-- ============================================ -- DATA_DETAIL_RPCS.sql -- 数据分析详情页专用 RPC 定义 -- ============================================ -- 目标: -- 1) 为 `pages/mall/analytics/data-detail.uvue` 提供统一的数据服务 -- 2) 仅复用现有 analytics_* 表与业务表,不新增物理表 -- 3) 权限完全依赖各表自身的 RLS 策略,本文件只负责函数与 GRANT -- -- 依赖前置脚本: -- - 01_create_tables.sql -- - ../../user/test/USER_AUTH_SCHEMA.sql -- - ../../user/test/USER_AUTH_TRIGGER.sql -- - ANALYTICS_DB_SCHEMA.sql -- -- 使用说明: -- - 前端通过 supabase-js / UTS 调用 `rpc()` 访问本文件中的函数 -- - 所有函数仅对 `authenticated` 角色开放执行权限 -- ============================================ -- -------------------------------------------- -- 1. 报表基础信息(用于初始化筛选器) -- -------------------------------------------- -- 根据报表 ID 返回基础配置,包含标题、类型、时间范围等 CREATE OR REPLACE FUNCTION public.rpc_data_detail_report_info( p_report_id uuid ) RETURNS TABLE ( id uuid, title text, type text, period text, date_start date, date_end date, status text, merchant_id uuid ) LANGUAGE sql AS $$ SELECT r.id, r.title, r.type, r.period, r.date_start, r.date_end, r.status, r.merchant_id FROM public.analytics_reports r WHERE r.id = p_report_id $$; REVOKE ALL ON FUNCTION public.rpc_data_detail_report_info(uuid) FROM PUBLIC; GRANT EXECUTE ON FUNCTION public.rpc_data_detail_report_info(uuid) TO authenticated; -- -------------------------------------------- -- 2. 报表明细行(表格数据) -- -------------------------------------------- -- 说明: -- - 以 analytics_report_rows 作为数据源 -- - 可按日期 / GMV / 订单数 / 用户数排序 -- - 维度信息通过 extra(JSONB) 透出,前端可自由解析 CREATE OR REPLACE FUNCTION public.rpc_data_detail_rows( p_report_id uuid, p_sort_by text DEFAULT 'row_date', -- row_date | gmv | orders | users p_sort_dir text DEFAULT 'asc', -- asc | desc p_limit integer DEFAULT 200, p_offset integer DEFAULT 0 ) RETURNS TABLE ( row_date date, gmv numeric, orders integer, users integer, conversion numeric, avg_order_amount numeric, extra jsonb ) LANGUAGE plpgsql AS $$ BEGIN -- 统一的 LIMIT / OFFSET 处理 IF lower(p_sort_by) = 'gmv' THEN IF lower(p_sort_dir) = 'desc' THEN RETURN QUERY SELECT r.row_date, r.gmv, r.orders, r.users, r.conversion, r.avg_order_amount, r.extra FROM public.analytics_report_rows r WHERE r.report_id = p_report_id ORDER BY r.gmv DESC, r.row_date DESC LIMIT GREATEST(p_limit, 0) OFFSET GREATEST(p_offset, 0); ELSE RETURN QUERY SELECT r.row_date, r.gmv, r.orders, r.users, r.conversion, r.avg_order_amount, r.extra FROM public.analytics_report_rows r WHERE r.report_id = p_report_id ORDER BY r.gmv ASC, r.row_date ASC LIMIT GREATEST(p_limit, 0) OFFSET GREATEST(p_offset, 0); END IF; ELSIF lower(p_sort_by) = 'orders' THEN IF lower(p_sort_dir) = 'desc' THEN RETURN QUERY SELECT r.row_date, r.gmv, r.orders, r.users, r.conversion, r.avg_order_amount, r.extra FROM public.analytics_report_rows r WHERE r.report_id = p_report_id ORDER BY r.orders DESC, r.row_date DESC LIMIT GREATEST(p_limit, 0) OFFSET GREATEST(p_offset, 0); ELSE RETURN QUERY SELECT r.row_date, r.gmv, r.orders, r.users, r.conversion, r.avg_order_amount, r.extra FROM public.analytics_report_rows r WHERE r.report_id = p_report_id ORDER BY r.orders ASC, r.row_date ASC LIMIT GREATEST(p_limit, 0) OFFSET GREATEST(p_offset, 0); END IF; ELSIF lower(p_sort_by) = 'users' THEN IF lower(p_sort_dir) = 'desc' THEN RETURN QUERY SELECT r.row_date, r.gmv, r.orders, r.users, r.conversion, r.avg_order_amount, r.extra FROM public.analytics_report_rows r WHERE r.report_id = p_report_id ORDER BY r.users DESC, r.row_date DESC LIMIT GREATEST(p_limit, 0) OFFSET GREATEST(p_offset, 0); ELSE RETURN QUERY SELECT r.row_date, r.gmv, r.orders, r.users, r.conversion, r.avg_order_amount, r.extra FROM public.analytics_report_rows r WHERE r.report_id = p_report_id ORDER BY r.users ASC, r.row_date ASC LIMIT GREATEST(p_limit, 0) OFFSET GREATEST(p_offset, 0); END IF; ELSE -- 默认按日期排序 IF lower(p_sort_dir) = 'desc' THEN RETURN QUERY SELECT r.row_date, r.gmv, r.orders, r.users, r.conversion, r.avg_order_amount, r.extra FROM public.analytics_report_rows r WHERE r.report_id = p_report_id ORDER BY r.row_date DESC LIMIT GREATEST(p_limit, 0) OFFSET GREATEST(p_offset, 0); ELSE RETURN QUERY SELECT r.row_date, r.gmv, r.orders, r.users, r.conversion, r.avg_order_amount, r.extra FROM public.analytics_report_rows r WHERE r.report_id = p_report_id ORDER BY r.row_date ASC LIMIT GREATEST(p_limit, 0) OFFSET GREATEST(p_offset, 0); END IF; END IF; END; $$; REVOKE ALL ON FUNCTION public.rpc_data_detail_rows(uuid,text,text,integer,integer) FROM PUBLIC; GRANT EXECUTE ON FUNCTION public.rpc_data_detail_rows(uuid,text,text,integer,integer) TO authenticated; -- -------------------------------------------- -- 3. 钻取指标列表(KPI / 汇总卡片) -- -------------------------------------------- -- 说明: -- - 直接从 analytics_report_metrics 读取 -- - 前端可根据 format 字段决定展示方式(数字 / 金额 / 百分比) CREATE OR REPLACE FUNCTION public.rpc_data_detail_drill_items( p_report_id uuid ) RETURNS TABLE ( metric_key text, metric_label text, metric_value_num numeric, metric_value_text text, format text, change_pct numeric, icon text, color text ) LANGUAGE sql AS $$ SELECT m.metric_key, m.metric_label, m.metric_value_num, m.metric_value_text, m.format, m.change_pct, m.icon, m.color FROM public.analytics_report_metrics m WHERE m.report_id = p_report_id ORDER BY m.metric_key $$; REVOKE ALL ON FUNCTION public.rpc_data_detail_drill_items(uuid) FROM PUBLIC; GRANT EXECUTE ON FUNCTION public.rpc_data_detail_drill_items(uuid) TO authenticated; -- -------------------------------------------- -- 4. GMV 对比数据(当前周期 vs 对比周期) -- -------------------------------------------- -- 说明: -- - 当前周期 = analytics_reports.period / date_start/date_end 所定义的范围 -- - 对比周期 = 与当前周期长度相同的上一段时间 -- - 聚合来源:orders CREATE OR REPLACE FUNCTION public.rpc_data_detail_compare_gmv( p_report_id uuid ) RETURNS TABLE ( day date, gmv_current numeric, gmv_previous numeric ) LANGUAGE plpgsql AS $$ DECLARE v_date_start date; v_date_end date; v_period_len integer; BEGIN SELECT COALESCE(r.date_start, (now() - INTERVAL '7 days')::date), COALESCE(r.date_end, now()::date) INTO v_date_start, v_date_end FROM public.analytics_reports r WHERE r.id = p_report_id; IF v_date_start IS NULL OR v_date_end IS NULL THEN RETURN; END IF; v_period_len := (v_date_end - v_date_start) + 1; RETURN QUERY WITH cur AS ( SELECT o.created_at::date AS day, SUM(o.total_amount) AS gmv FROM public.orders o WHERE o.created_at::date BETWEEN v_date_start AND v_date_end AND o.status = 2 GROUP BY o.created_at::date ), prev_range AS ( SELECT (v_date_start - v_period_len) AS start_date, (v_date_start - 1) AS end_date ), prev AS ( SELECT o.created_at::date AS day, SUM(o.total_amount) AS gmv FROM public.orders o, prev_range pr WHERE o.created_at::date BETWEEN pr.start_date AND pr.end_date AND o.status = 2 GROUP BY o.created_at::date ), series AS ( SELECT generate_series(v_date_start, v_date_end, INTERVAL '1 day')::date AS day ) SELECT s.day, COALESCE(c.gmv, 0) AS gmv_current, COALESCE(p.gmv, 0) AS gmv_previous FROM series s LEFT JOIN cur c ON c.day = s.day LEFT JOIN prev p ON p.day = (s.day - v_period_len); END; $$; REVOKE ALL ON FUNCTION public.rpc_data_detail_compare_gmv(uuid) FROM PUBLIC; GRANT EXECUTE ON FUNCTION public.rpc_data_detail_compare_gmv(uuid) TO authenticated; -- ============================================ -- 文件结束 -- ============================================