Files
medical-mall/pages/mall/analytics/test/DATA_DETAIL_RPCS.sql
2026-01-30 16:17:13 +08:00

343 lines
8.9 KiB
PL/PgSQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- ============================================
-- 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;
-- ============================================
-- 文件结束
-- ============================================