-- 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; -- ---------- 菜单:内容治理 / 订单与权益 / 数据看板 ---------- -- 这三条菜单拖到 3-4 页面做出来才加:菜单先落库而组件不存在的话, -- 前端动态路由会指向空组件、侧边栏直接报错(3-3 时就是这么刻意留空的)。 -- component 指向 src/views/governance|commerce|dashboard/ 下的页面,前端按字符串动态加载。 INSERT INTO sys_menu (id, parent_id, title, route_path, route_name, component, redirect, icon, permission_code, type, always_show, affix, sort) VALUES (20, 0, '内容治理', '/governance', 'Governance', '#', '/governance/content', 'ep:chat-dot-round', 'comment:list', 'CATALOG', 1, 0, 6), (21, 20, '评论与举报', 'content', 'governance-content', 'views/governance/ContentGovernanceView', '', '', 'comment:list', 'MENU', 0, 0, 1), (22, 0, '订单与权益', '/commerce', 'Commerce', '#', '/commerce/orders', 'ep:coin', 'order:list', 'CATALOG', 1, 0, 7), (23, 22, '订单管理', 'orders', 'commerce-orders', 'views/commerce/OrderManagementView', '', '', 'order:list', 'MENU', 0, 0, 1), (24, 0, '数据看板', '/board', 'BoardCenter', '#', '/board/overview', 'ep:data-line', 'dashboard:view', 'CATALOG', 1, 0, 8), (25, 24, '运营大盘', 'overview', 'board-overview', 'views/dashboard/BusinessDashboardView', '', '', 'dashboard:view', '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 (20, 21, 22, 23, 24, 25) ON CONFLICT DO NOTHING; -- ---------- 07 创作者中心:角色、权限点、授权 ---------- -- 创作者第一阶段直接登后台(复用 sys_admin_user + sys_role + sys_menu), -- 这里只落"身份与权限";菜单等页面做出来再挂 —— 菜单先入库会让前端动态路由指向不存在的组件。 INSERT INTO sys_role_category (id, name, description, sort) VALUES (4, '创作者', '外部内容创作者,只能管理自己的作品与数据', 4) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, description = EXCLUDED.description, sort = EXCLUDED.sort; INSERT INTO sys_role (id, name, code, category_id, level, description, status, is_builtin) VALUES (5, '创作者', 'creator', 4, 5, '只能查看与编辑自己的作品与数据', 1, 0) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, code = EXCLUDED.code, description = EXCLUDED.description, category_id = EXCLUDED.category_id, level = EXCLUDED.level; -- 权限点按批补:批 1 只有「进创作者中心」这一个,后面各批用到什么再幂等追加 INSERT INTO sys_permission (code, name, group_name, type, sort) VALUES ('creator-center:view', '访问创作者中心', '创作者中心', 'BUTTON', 150), ('creator-center:drama:edit', '创作者中心-编辑作品', '创作者中心', 'BUTTON', 151), ('creator-center:upload', '创作者中心-上传与挂载', '创作者中心', 'BUTTON', 152), ('creator-center:price:update', '创作者中心-配置分集价格', '创作者中心', 'BUTTON', 153) 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 = 'creator' AND p.code IN ('creator-center:view', 'creator-center:drama:edit', 'creator-center:upload', 'creator-center:price:update') ON CONFLICT DO NOTHING; -- 超管也留一份,方便排查创作者视角的问题(超管没有绑定创作者主体,进 creator-center 仍会被挡) 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 ('creator-center:view', 'creator-center:drama:edit', 'creator-center:upload', 'creator-center:price:update') ON CONFLICT DO NOTHING; -- 媒资分片上传是复用后台已有的 /admin/media/upload/*,所以创作者角色要用现成的上传权限点, -- 不再造一套 creator-center 的上传接口(上传会话归属与产物归属另在服务层校验)。 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 = 'creator' AND p.code IN ('cover:upload', 'episode:upload') ON CONFLICT DO NOTHING;