Files
FruitServer/sql/data-phase1.sql
T
Vicky 1fb8427f28 feat: 08 创作者与内容审核落地(入驻审核 / 内容提交审核 / 定时发布 / 分集定价)
为什么:
1) 内容是创作者供的,必须有一条可管控的供给链路:创作者入驻要审、内容提交要审、
   审核通过才能真正上架 —— 否则平台无法对内容和主体负责。
2) 审核不能绕过状态机。内容提交审核通过后,是顺着短剧状态机
   SUBMIT → APPROVE → PUBLISH 推上去,而不是直接写 status 字段,
   这样审核记录与操作日志都不会缺环。
3) 定时发布(publish_at 到点自动上线)同样走状态机,并且做成幂等任务:
   重复执行不会把已上线的剧再推一次。
4) 定价落在 is_free / unlock_coin 上,与权益表解耦:改价立即影响播放与下载判定,
   但已购用户的权益不受影响,不会因为改价把用户买过的东西收回去。
5) 补齐 PM 草稿未做的部分:5 个权限点 + 3 条后台菜单(含前端组件路径)+ 超管授权(幂等),
   以及后台定价页需要的价格读取接口 GET /admin/prices。
2026-10-15 12:51:40 +08:00

136 lines
7.6 KiB
SQL
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.
-- 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;
-- 超管默认拥有全部权限点
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')
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;