为什么: 1) 前面几块把用户、内容、播放、交易、媒资的数据都落库了,运营需要一个地方一次看完, 否则每个指标都要去查库或翻后台列表。 2) 看板最容易出的问题是"数字看起来对但口径不清",所以每个指标都在代码注释和 docs/api-phase1.md 里写死口径(时间范围、统计维度),前端 tooltip 直接复用。 3) 取不到数据源的指标(DAU、CDN 流量成本、商店订单金额)一律返回 null 并在 notes 里 说明缺什么、怎么补 —— 不用 0 冒充,避免运营拿假数字做判断。 4) 站在接入层做只读聚合而不是新建模块:它跨六个域取数,建模块只会把依赖再摊开一层, 而它只读不写,放在 admin-api 改动面最小。
141 lines
7.9 KiB
SQL
141 lines
7.9 KiB
SQL
-- FruitShorts 短剧服务 · 第一阶段增量数据(PostgreSQL 18)
|
||
--
|
||
-- 只放「代码已经实现、需要权限点才能调通」的数据。
|
||
-- 菜单(sys_menu)暂时不加:前端页面还没做,加了会出现指向不存在组件的动态路由,
|
||
-- 等 fruitshorts-web 的 App 用户管理页落地后再补菜单与角色菜单绑定。
|
||
--
|
||
-- 幂等:可重复执行。
|
||
|
||
-- 先对齐 IDENTITY 序列:历史种子数据用了显式 ID,序列没有前移,
|
||
-- 不对齐的话下面的插入会从 1 开始而撞主键。
|
||
DO $$
|
||
DECLARE
|
||
t text;
|
||
seq text;
|
||
maxid bigint;
|
||
BEGIN
|
||
FOREACH t IN ARRAY ARRAY['sys_permission','sys_menu','sys_role_permission','sys_role_menu',
|
||
'product','app_user','app_user_credential','orders','wallet'] LOOP
|
||
seq := pg_get_serial_sequence(t, 'id');
|
||
IF seq IS NULL THEN
|
||
CONTINUE;
|
||
END IF;
|
||
EXECUTE format('SELECT COALESCE(MAX(id), 0) FROM %I', t) INTO maxid;
|
||
IF maxid > 0 THEN
|
||
PERFORM setval(seq, maxid);
|
||
END IF;
|
||
END LOOP;
|
||
END $$;
|
||
|
||
INSERT INTO sys_permission (code, name, group_name, type, sort) VALUES
|
||
('app-user:list', '查看 App 用户', '用户管理', 'BUTTON', 101),
|
||
('app-user:update', '处置 App 用户', '用户管理', 'BUTTON', 102)
|
||
ON CONFLICT (code) DO NOTHING;
|
||
|
||
INSERT INTO sys_permission (code, name, group_name, type, sort) VALUES
|
||
('download:list', '查看下载授权', '用户管理', 'BUTTON', 103),
|
||
('download:revoke', '吊销下载授权', '用户管理', 'BUTTON', 104)
|
||
ON CONFLICT (code) DO NOTHING;
|
||
|
||
INSERT INTO sys_permission (code, name, group_name, type, sort) VALUES
|
||
('comment:list', '查看评论', '内容治理', 'BUTTON', 111),
|
||
('comment:audit', '审核评论', '内容治理', 'BUTTON', 112),
|
||
('report:list', '查看举报', '内容治理', 'BUTTON', 113),
|
||
('report:handle', '处理举报', '内容治理', 'BUTTON', 114),
|
||
('sensitive-word:list', '查看敏感词', '内容治理', 'BUTTON', 115),
|
||
('sensitive-word:update','维护敏感词', '内容治理', 'BUTTON', 116)
|
||
ON CONFLICT (code) DO NOTHING;
|
||
|
||
INSERT INTO sys_permission (code, name, group_name, type, sort) VALUES
|
||
('order:list', '查看订单', '订单与权益', 'BUTTON', 121),
|
||
('order:update', '补发/退款', '订单与权益', 'BUTTON', 122),
|
||
('entitlement:list', '查看权益', '订单与权益', 'BUTTON', 123),
|
||
('entitlement:update', '补发/回收权益', '订单与权益', 'BUTTON', 124),
|
||
('wallet:update', '人工补币', '订单与权益', 'BUTTON', 125),
|
||
('reconcile:run', '手动对账', '订单与权益', 'BUTTON', 126)
|
||
ON CONFLICT (code) DO NOTHING;
|
||
|
||
INSERT INTO sys_permission (code, name, group_name, type, sort) VALUES
|
||
('creator:list', '查看创作者', '创作者管理', 'BUTTON', 131),
|
||
('creator:audit', '创作者入驻审核','创作者管理', 'BUTTON', 132),
|
||
('submission:list', '查看内容提交', '创作者管理', 'BUTTON', 133),
|
||
('submission:audit', '内容提交审核', '创作者管理', 'BUTTON', 134),
|
||
('price:update', '配置分集价格', '内容管理', 'BUTTON', 135)
|
||
ON CONFLICT (code) DO NOTHING;
|
||
|
||
-- 看板权限:菜单在 3-4 补页面时一起加,避免菜单指向不存在的组件
|
||
INSERT INTO sys_permission (code, name, group_name, type, sort) VALUES
|
||
('dashboard:view', '查看运营大盘', '数据看板', 'BUTTON', 141)
|
||
ON CONFLICT (code) DO NOTHING;
|
||
|
||
-- 超管默认拥有全部权限点
|
||
INSERT INTO sys_role_permission (role_id, permission_id)
|
||
SELECT r.id, p.id
|
||
FROM sys_role r
|
||
CROSS JOIN sys_permission p
|
||
WHERE r.code = 'super_admin'
|
||
AND p.code IN ('app-user:list', 'app-user:update', 'download:list', 'download:revoke',
|
||
'comment:list', 'comment:audit', 'report:list', 'report:handle',
|
||
'sensitive-word:list', 'sensitive-word:update',
|
||
'order:list', 'order:update', 'entitlement:list', 'entitlement:update',
|
||
'wallet:update', 'reconcile:run',
|
||
'creator:list', 'creator:audit', 'submission:list', 'submission:audit',
|
||
'price:update', 'dashboard:view')
|
||
ON CONFLICT DO NOTHING;
|
||
|
||
-- ---------- 菜单:创作者管理 ----------
|
||
-- component 指向 src/views/creator/ 下的页面,前端按这个字符串动态加载。
|
||
INSERT INTO sys_menu (id, parent_id, title, route_path, route_name, component, redirect, icon,
|
||
permission_code, type, always_show, affix, sort) VALUES
|
||
(17, 0, '创作者管理', '/creator', 'CreatorCenter', '#', '/creator/creators', 'ep:user-filled', 'creator:list', 'CATALOG', 1, 0, 5),
|
||
(18, 17, '创作者入驻', 'creators', 'creators', 'views/creator/CreatorAuditView', '', '', 'creator:list', 'MENU', 0, 0, 1),
|
||
(19, 17, '内容审核', 'submissions', 'submissions', 'views/creator/SubmissionAuditView', '', '', 'submission:list', 'MENU', 0, 0, 2)
|
||
ON CONFLICT (id) DO UPDATE SET parent_id = EXCLUDED.parent_id, title = EXCLUDED.title,
|
||
route_path = EXCLUDED.route_path, route_name = EXCLUDED.route_name, component = EXCLUDED.component,
|
||
redirect = EXCLUDED.redirect, icon = EXCLUDED.icon, permission_code = EXCLUDED.permission_code,
|
||
type = EXCLUDED.type, always_show = EXCLUDED.always_show, affix = EXCLUDED.affix, sort = EXCLUDED.sort;
|
||
|
||
INSERT INTO sys_role_menu (role_id, menu_id)
|
||
SELECT r.id, m.id
|
||
FROM sys_role r
|
||
CROSS JOIN sys_menu m
|
||
WHERE r.code = 'super_admin'
|
||
AND m.id IN (17, 18, 19)
|
||
ON CONFLICT DO NOTHING;
|
||
|
||
-- 第一阶段新增的白名单数据(当前阶段都是免费内容,先把演示商品占位好)
|
||
INSERT INTO product (code, name, type, platform, store_product_id, coin_amount, bonus_coin,
|
||
price_amount, currency, region_codes, sort, status)
|
||
SELECT 'coin_100', '100 金币', 'COIN_PACK', 'ALL', '', 100, 0, 0.99, 'USD', 'ID', 1, 1
|
||
WHERE NOT EXISTS (SELECT 1 FROM product WHERE code = 'coin_100');
|
||
|
||
INSERT INTO product (code, name, type, platform, store_product_id, coin_amount, bonus_coin,
|
||
price_amount, currency, region_codes, sort, status)
|
||
SELECT 'coin_550', '550 金币', 'COIN_PACK', 'ALL', '', 500, 50, 4.99, 'USD', 'ID', 2, 1
|
||
WHERE NOT EXISTS (SELECT 1 FROM product WHERE code = 'coin_550');
|
||
|
||
INSERT INTO product (code, name, type, platform, store_product_id, coin_amount, bonus_coin,
|
||
price_amount, currency, region_codes, sort, status)
|
||
SELECT 'coin_1200', '1200 金币', 'COIN_PACK', 'ALL', '', 1000, 200, 9.99, 'USD', 'ID', 3, 1
|
||
WHERE NOT EXISTS (SELECT 1 FROM product WHERE code = 'coin_1200');
|
||
|
||
-- ---------- 菜单:用户管理 ----------
|
||
-- C 端用户与后台管理员是两套账号体系,单独挂一个一级目录,避免和管理员列表混淆。
|
||
-- component 指向 src/views/userManagement/AppUsersView.vue,前端按这个字符串动态加载。
|
||
INSERT INTO sys_menu (id, parent_id, title, route_path, route_name, component, redirect, icon,
|
||
permission_code, type, always_show, affix, sort) VALUES
|
||
(15, 0, '用户管理', '/user', 'UserCenter', '#', '/user/app-users', 'ep:user', 'app-user:list', 'CATALOG', 1, 0, 4),
|
||
(16, 15, 'App 用户', 'app-users', 'app-users', 'views/userManagement/AppUsersView', '', '', 'app-user:list', 'MENU', 0, 0, 1)
|
||
ON CONFLICT (id) DO UPDATE SET parent_id = EXCLUDED.parent_id, title = EXCLUDED.title,
|
||
route_path = EXCLUDED.route_path, route_name = EXCLUDED.route_name, component = EXCLUDED.component,
|
||
redirect = EXCLUDED.redirect, icon = EXCLUDED.icon, permission_code = EXCLUDED.permission_code,
|
||
type = EXCLUDED.type, always_show = EXCLUDED.always_show, affix = EXCLUDED.affix, sort = EXCLUDED.sort;
|
||
|
||
INSERT INTO sys_role_menu (role_id, menu_id)
|
||
SELECT r.id, m.id
|
||
FROM sys_role r
|
||
CROSS JOIN sys_menu m
|
||
WHERE r.code = 'super_admin'
|
||
AND m.id IN (15, 16)
|
||
ON CONFLICT DO NOTHING;
|