mall数据库文件

This commit is contained in:
comlibmb
2026-01-30 16:17:13 +08:00
parent cfec4a16c0
commit 8f181b2b6a
42 changed files with 12758 additions and 2 deletions

View File

@@ -0,0 +1,405 @@
-- ============================================
-- 07_custom_report_rpcs.sql
-- 自定义报表创建与管理 RPC 定义
-- ============================================
-- 目标:
-- 1) 为 `pages/mall/analytics/custom-report.uvue` 提供安全的数据服务
-- 2) 确保用户记录存在,解决外键约束问题
-- 3) 创建自定义报表并生成初始数据metrics + rows
--
-- 依赖前置脚本:
-- - 01_create_tables.sqlusers 表)
-- - ANALYTICS_DB_SCHEMA.sqlanalytics_reports / analytics_report_metrics / analytics_report_rows
--
-- 使用说明:
-- - 前端通过 supabase-js / UTS 调用 `rpc()` 访问本文件中的函数
-- - 所有函数仅对 `authenticated` 角色开放执行权限
-- ============================================
-- --------------------------------------------
-- 1. 确保用户记录存在Upsert User
-- --------------------------------------------
-- 说明:
-- - 如果 users 表中不存在当前用户记录,则插入
-- - 如果已存在,则更新最后登录时间等信息
-- - 解决 analytics_reports.owner_user_id 外键约束问题
CREATE OR REPLACE FUNCTION public.rpc_ensure_user_record(
p_user_id uuid,
p_email text DEFAULT NULL,
p_phone text DEFAULT NULL,
p_nickname text DEFAULT NULL
)
RETURNS uuid
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
v_user_id uuid;
BEGIN
-- 检查用户是否存在
SELECT id INTO v_user_id
FROM public.users
WHERE id = p_user_id;
IF v_user_id IS NULL THEN
-- 用户不存在,插入新记录
INSERT INTO public.users (
id,
email,
phone,
nickname,
last_login_at,
created_at,
updated_at
) VALUES (
p_user_id,
p_email,
p_phone,
COALESCE(p_nickname, COALESCE(split_part(p_email, '@', 1), '用户')),
NOW(),
NOW(),
NOW()
)
RETURNING id INTO v_user_id;
ELSE
-- 用户已存在,更新信息
UPDATE public.users
SET
email = COALESCE(p_email, email),
phone = COALESCE(p_phone, phone),
nickname = COALESCE(p_nickname, nickname),
last_login_at = NOW(),
updated_at = NOW()
WHERE id = p_user_id;
v_user_id := p_user_id;
END IF;
RETURN v_user_id;
END;
$$;
REVOKE ALL ON FUNCTION public.rpc_ensure_user_record(uuid,text,text,text) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.rpc_ensure_user_record(uuid,text,text,text) TO authenticated;
-- --------------------------------------------
-- 2. 创建自定义报表(含初始数据生成)
-- --------------------------------------------
-- 说明:
-- - 创建 analytics_reports 记录
-- - 根据 period 和选中的指标,生成 analytics_report_metrics
-- - 根据 period 聚合 orders 数据,生成 analytics_report_rows
CREATE OR REPLACE FUNCTION public.rpc_create_custom_report(
p_title text,
p_description text DEFAULT '',
p_period text DEFAULT '30d', -- 7d/30d/90d/1y
p_metrics text[] DEFAULT ARRAY['gmv', 'orders', 'users'], -- 选中的指标列表
p_chart_type text DEFAULT 'line' -- 图表类型(暂不存储,仅用于后续扩展)
)
RETURNS uuid
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
v_user_id uuid;
v_report_id uuid;
v_start_date date;
v_end_date date;
v_metric_key text;
v_metric_label text;
v_metric_value numeric;
v_total_gmv numeric := 0;
v_total_orders integer := 0;
v_total_users integer := 0;
v_avg_order_amount numeric := 0;
BEGIN
-- 1. 获取当前用户 ID
v_user_id := auth.uid();
IF v_user_id IS NULL THEN
RAISE EXCEPTION '用户未登录';
END IF;
-- 2. 确保用户记录存在
PERFORM public.rpc_ensure_user_record(
v_user_id,
NULL, -- email 从 auth.users 获取,这里不传
NULL, -- phone 从 auth.users 获取,这里不传
NULL -- nickname 从 auth.users 获取,这里不传
);
-- 3. 计算时间范围
v_end_date := CURRENT_DATE;
CASE p_period
WHEN '7d' THEN v_start_date := v_end_date - INTERVAL '7 days';
WHEN '30d' THEN v_start_date := v_end_date - INTERVAL '30 days';
WHEN '90d' THEN v_start_date := v_end_date - INTERVAL '90 days';
WHEN '1y' THEN v_start_date := v_end_date - INTERVAL '1 year';
ELSE v_start_date := v_end_date - INTERVAL '30 days'; -- 默认 30 天
END CASE;
-- 4. 创建报表记录
INSERT INTO public.analytics_reports (
owner_user_id,
title,
description,
type,
period,
date_start,
date_end,
status,
generated_at,
created_at,
updated_at
) VALUES (
v_user_id,
p_title,
p_description,
'custom',
p_period,
v_start_date,
v_end_date,
'ready',
NOW(),
NOW(),
NOW()
)
RETURNING id INTO v_report_id;
-- 5. 聚合订单数据,计算总指标
SELECT
COALESCE(SUM(o.total_amount), 0),
COUNT(DISTINCT o.id),
COUNT(DISTINCT o.user_id),
CASE
WHEN COUNT(DISTINCT o.id) > 0
THEN COALESCE(SUM(o.total_amount), 0) / COUNT(DISTINCT o.id)
ELSE 0
END
INTO v_total_gmv, v_total_orders, v_total_users, v_avg_order_amount
FROM public.orders o
WHERE o.created_at >= v_start_date
AND o.created_at <= v_end_date
AND o.status = 2; -- 已完成订单
-- 6. 生成核心指标analytics_report_metrics
-- GMV
IF 'gmv' = ANY(p_metrics) THEN
INSERT INTO public.analytics_report_metrics (
report_id,
metric_key,
metric_label,
metric_value_num,
format,
icon,
color
) VALUES (
v_report_id,
'gmv_total',
'总GMV',
v_total_gmv,
'currency',
'💰',
'#4caf50'
);
END IF;
-- 订单数
IF 'orders' = ANY(p_metrics) THEN
INSERT INTO public.analytics_report_metrics (
report_id,
metric_key,
metric_label,
metric_value_num,
format,
icon,
color
) VALUES (
v_report_id,
'orders_total',
'总订单数',
v_total_orders,
'number',
'📦',
'#2196f3'
);
END IF;
-- 用户数
IF 'users' = ANY(p_metrics) THEN
INSERT INTO public.analytics_report_metrics (
report_id,
metric_key,
metric_label,
metric_value_num,
format,
icon,
color
) VALUES (
v_report_id,
'users_total',
'下单用户数',
v_total_users,
'number',
'👥',
'#ff9800'
);
END IF;
-- 客单价
IF 'avg_order' = ANY(p_metrics) THEN
INSERT INTO public.analytics_report_metrics (
report_id,
metric_key,
metric_label,
metric_value_num,
format,
icon,
color
) VALUES (
v_report_id,
'avg_order_amount',
'客单价',
v_avg_order_amount,
'currency',
'💵',
'#9c27b0'
);
END IF;
-- 7. 生成明细行analytics_report_rows- 按天聚合
INSERT INTO public.analytics_report_rows (
report_id,
row_date,
gmv,
orders,
users,
avg_order_amount
)
SELECT
v_report_id,
o.created_at::date AS row_date,
COALESCE(SUM(o.total_amount), 0) AS gmv,
COUNT(DISTINCT o.id) AS orders,
COUNT(DISTINCT o.user_id) AS users,
CASE
WHEN COUNT(DISTINCT o.id) > 0
THEN COALESCE(SUM(o.total_amount), 0) / COUNT(DISTINCT o.id)
ELSE 0
END AS avg_order_amount
FROM public.orders o
WHERE o.created_at >= v_start_date
AND o.created_at <= v_end_date
AND o.status = 2
GROUP BY o.created_at::date
ORDER BY o.created_at::date;
RETURN v_report_id;
END;
$$;
REVOKE ALL ON FUNCTION public.rpc_create_custom_report(text,text,text,text[],text) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.rpc_create_custom_report(text,text,text,text[],text) TO authenticated;
-- --------------------------------------------
-- 3. 更新自定义报表(仅更新基本信息)
-- --------------------------------------------
-- 说明:
-- - 更新报表的标题、描述、周期
-- - 不重新生成数据(如需重新生成,删除后重建)
CREATE OR REPLACE FUNCTION public.rpc_update_custom_report(
p_report_id uuid,
p_title text,
p_description text DEFAULT NULL,
p_period text DEFAULT NULL
)
RETURNS boolean
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
v_user_id uuid;
BEGIN
-- 1. 获取当前用户 ID
v_user_id := auth.uid();
IF v_user_id IS NULL THEN
RAISE EXCEPTION '用户未登录';
END IF;
-- 2. 更新报表(仅限所有者)
UPDATE public.analytics_reports
SET
title = p_title,
description = COALESCE(p_description, description),
period = COALESCE(p_period, period),
updated_at = NOW()
WHERE id = p_report_id
AND owner_user_id = v_user_id;
-- FOUND 是 PostgreSQL 的特殊变量UPDATE 后自动设置
IF NOT FOUND THEN
RAISE EXCEPTION '报表不存在或无权限修改';
END IF;
RETURN true;
END;
$$;
REVOKE ALL ON FUNCTION public.rpc_update_custom_report(uuid,text,text,text) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.rpc_update_custom_report(uuid,text,text,text) TO authenticated;
-- --------------------------------------------
-- 4. 删除自定义报表(级联删除相关数据)
-- --------------------------------------------
-- 说明:
-- - 删除报表记录CASCADE 会自动删除 metrics 和 rows
-- - 仅允许所有者删除
CREATE OR REPLACE FUNCTION public.rpc_delete_custom_report(
p_report_id uuid
)
RETURNS boolean
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
v_user_id uuid;
BEGIN
-- 1. 获取当前用户 ID
v_user_id := auth.uid();
IF v_user_id IS NULL THEN
RAISE EXCEPTION '用户未登录';
END IF;
-- 2. 删除报表仅限所有者CASCADE 会自动删除 metrics 和 rows
DELETE FROM public.analytics_reports
WHERE id = p_report_id
AND owner_user_id = v_user_id
AND type = 'custom';
-- FOUND 是 PostgreSQL 的特殊变量DELETE 后自动设置
IF NOT FOUND THEN
RAISE EXCEPTION '报表不存在或无权限删除';
END IF;
RETURN true;
END;
$$;
REVOKE ALL ON FUNCTION public.rpc_delete_custom_report(uuid) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.rpc_delete_custom_report(uuid) TO authenticated;
-- ============================================
-- 完成提示
-- ============================================
DO $$
BEGIN
RAISE NOTICE 'Custom report RPCs created successfully.';
RAISE NOTICE 'Functions:';
RAISE NOTICE ' - rpc_ensure_user_record(uuid, text, text, text)';
RAISE NOTICE ' - rpc_create_custom_report(text, text, text, text[], text)';
RAISE NOTICE ' - rpc_update_custom_report(uuid, text, text, text)';
RAISE NOTICE ' - rpc_delete_custom_report(uuid)';
END $$;