chore(merge): 将 release/v1.0.0 同步到 main

This commit is contained in:
Zhou Weidong committed 2026-10-23 13:07:42 +08:00
commit 6abb09e5c2
265 files changed
+38022 -2667

No files matched your search

+10
View File
@@ -0,0 +1,10 @@
-- Author: fruit.com.cn
-- K85:按有效收藏关系回填短剧收藏数,仅由验收/运维手动执行一次。
UPDATE drama d
SET favorite_count = (
SELECT COUNT(*)
FROM user_favorite f
WHERE f.drama_id = d.id
AND f.deleted = 0
);
+29 -10
View File
@@ -39,7 +39,8 @@ ON CONFLICT (code) DO NOTHING;
INSERT INTO sys_permission (id, code, name, group_name, type, sort) VALUES
(1103, 'download:list', '查看下载授权', '用户管理', 'BUTTON', 103),
(1104, 'download:revoke', '吊销下载授权', '用户管理', 'BUTTON', 104)
(1104, 'download:revoke', '吊销下载授权', '用户管理', 'BUTTON', 104),
(1105, 'watch-history:list','查看观看记录', '用户管理', 'BUTTON', 105)
ON CONFLICT (code) DO NOTHING;
INSERT INTO sys_permission (id, code, name, group_name, type, sort) VALUES
@@ -80,6 +81,7 @@ 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',
'watch-history:list',
'comment:list', 'comment:audit', 'report:list', 'report:handle',
'sensitive-word:list', 'sensitive-word:update',
'order:list', 'order:update', 'entitlement:list', 'entitlement:update',
@@ -92,7 +94,7 @@ 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),
(17, 0, '创作者管理', '/creator', 'CreatorCenter', '#', '/creator/creators', 'material-symbols:movie-edit-rounded', '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,
@@ -129,8 +131,10 @@ WHERE NOT EXISTS (SELECT 1 FROM product WHERE code = 'coin_1200');
-- 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)
(15, 0, '用户管理', '/user', 'UserCenter', '#', '/user/app-users', 'material-symbols:group-rounded', 'app-user:list', 'CATALOG', 1, 0, 4),
(16, 15, 'App 用户', 'app-users', 'app-users', 'views/userManagement/AppUsersView', '', '', 'app-user:list', 'MENU', 0, 0, 1),
(34, 15, '观看记录', 'watch-history', 'watch-history',
'views/userManagement/WatchHistoryView', '', '', 'watch-history: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,
@@ -141,7 +145,7 @@ SELECT r.id * 1000000 + m.id, r.id, m.id
FROM sys_role r
CROSS JOIN sys_menu m
WHERE r.code = 'super_admin'
AND m.id IN (15, 16)
AND m.id IN (15, 16, 34)
ON CONFLICT DO NOTHING;
-- ---------- 菜单:内容治理 / 订单与权益 / 数据看板 ----------
@@ -150,11 +154,11 @@ ON CONFLICT DO NOTHING;
-- 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),
(20, 0, '内容治理', '/governance', 'Governance', '#', '/governance/content', 'material-symbols:policy-rounded', '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),
(22, 0, '订单与权益', '/commerce', 'Commerce', '#', '/commerce/orders', 'material-symbols:payments-rounded', '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),
(24, 0, '数据看板', '/board', 'BoardCenter', '#', '/board/overview', 'material-symbols:monitoring-rounded', '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,
@@ -253,7 +257,7 @@ INSERT INTO sys_menu (id, parent_id, title, route_path, route_name, component, r
permission_code, type, always_show, affix, sort, visible) VALUES
-- route_name 必须全局唯一:17 号菜单(创作者管理)已经叫 CreatorCenter,
-- 同名会让 Vue Router 后者覆盖前者、整个 /creator-center 子树注册不上(超管点进去就 404)
(26, 0, '创作者中心', '/creator-center', 'CreatorWorkspace', '#', '/creator-center/workspace', 'ep:film', 'creator-center:view', 'CATALOG', 1, 0, 3, 1),
(26, 0, '创作者中心', '/creator-center', 'CreatorWorkspace', '#', '/creator-center/workspace', 'material-symbols:video-camera-front-rounded', 'creator-center:view', 'CATALOG', 1, 0, 3, 1),
(27, 26, '我的作品', 'workspace', 'creator-workspace', 'views/creator-center/WorkspaceView', '', '', 'creator-center:view', 'MENU', 0, 0, 1, 1),
(28, 26, '作品编辑', 'dramas/:id', 'creator-drama-edit', 'views/creator-center/DramaEditView', '', '', 'creator-center:drama:edit', 'MENU', 0, 0, 2, 0),
(29, 26, '收费配置', 'prices', 'creator-prices', 'views/creator-center/PriceConfigView', '', '', 'creator-center:price:update', 'MENU', 0, 0, 3, 1),
@@ -310,7 +314,7 @@ ON CONFLICT DO NOTHING;
INSERT INTO sys_menu (id, parent_id, title, route_path, route_name, component, redirect, icon,
permission_code, type, always_show, affix, sort) VALUES
(31, 22, '商品配置', 'products', 'commerce-products', 'views/commerce/ProductManagementView', '', '', 'product:list', 'MENU', 0, 0, 2),
(32, 0, '运营管理', '/operation', 'OperationCenter', '#', '/operation/notices', 'ep:bell', 'notice:list', 'CATALOG', 1, 0, 9),
(32, 0, '运营管理', '/operation', 'OperationCenter', '#', '/operation/notices', 'material-symbols:campaign-rounded', 'notice:list', 'CATALOG', 1, 0, 9),
(33, 32, '系统公告', 'notices', 'operation-notices', 'views/operation/NoticeManagementView', '', '', 'notice: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,
@@ -333,3 +337,18 @@ INSERT INTO sys_config (id, config_key, config_value, remark) VALUES
(3, 'app.register.max-per-ip-per-day', '0', '0=不限制;生产建议 5'),
(4, 'app.register.max-per-device-per-day', '0', '0=不限制;生产建议 3')
ON CONFLICT (config_key) DO NOTHING;
INSERT INTO sys_config (id, config_key, config_value, remark) VALUES
(2026102201,
'media.transcode.profile',
'{"enabled":true,"segmentSeconds":6,"ladder":[' ||
'{"quality":"360p","width":640,"height":360,"videoBitrateKbps":400,"audioBitrateKbps":64,"enabled":true},' ||
'{"quality":"480p","width":854,"height":480,"videoBitrateKbps":800,"audioBitrateKbps":64,"enabled":true},' ||
'{"quality":"720p","width":1280,"height":720,"videoBitrateKbps":1600,"audioBitrateKbps":96,"enabled":true},' ||
'{"quality":"1080p","width":1920,"height":1080,"videoBitrateKbps":3200,"audioBitrateKbps":128,"enabled":true}],' ||
'"sprite":{"enabled":true,"intervalSeconds":1,"columns":10,"thumbWidth":160}}',
'转码档位与缩略图轴配置')
ON CONFLICT (config_key) DO NOTHING;
-- K23:二级菜单统一只显示文字,历史图标值也一并清空。
UPDATE sys_menu SET icon = '' WHERE type = 'MENU';
+18 -5
View File
@@ -50,14 +50,16 @@ ON CONFLICT (id) DO UPDATE SET code = EXCLUDED.code, name = EXCLUDED.name,
-- ---------- 菜单 ----------
INSERT INTO sys_menu (id, parent_id, title, route_path, route_name, component, redirect, icon,
permission_code, type, always_show, affix, sort) VALUES
(1, 0, '工作台', '/dashboard', 'Dashboard', '#', '/dashboard/index', 'ant-design:dashboard-filled', 'drama:list', 'CATALOG', 0, 0, 1),
(2, 1, '工作台', 'index', 'dashboard', 'views/common/DashboardView', '', 'ant-design:dashboard-filled', 'drama:list', 'MENU', 0, 1, 1),
(3, 0, '内容管理', '/content', 'Content', '#', '/content/dramas', 'ep:video-camera', 'drama:list', 'CATALOG', 1, 0, 2),
(1, 0, '工作台', '/dashboard', 'Dashboard', '#', '/dashboard/index', 'material-symbols:dashboard-rounded', 'drama:list', 'CATALOG', 0, 0, 1),
(2, 1, '工作台', 'index', 'dashboard', 'views/common/DashboardView', '', '', 'drama:list', 'MENU', 0, 1, 1),
(3, 0, '内容管理', '/content', 'Content', '#', '/content/dramas', 'material-symbols:video-library-rounded', 'drama:list', 'CATALOG', 1, 0, 2),
(4, 3, '短剧管理', 'dramas', 'dramas', 'views/contentManagement/DramaManagementView', '', '', 'drama:list', 'MENU', 0, 0, 1),
(5, 3, '剧集管理', 'episodes', 'episodes', 'views/contentManagement/EpisodeManagementView', '', '', 'episode:list', 'MENU', 0, 0, 2),
(12, 3, '轮播图管理', 'banners', 'banners', 'views/contentManagement/BannerManagementView', '', '', 'banner:list', 'MENU', 0, 0, 3),
(13, 3, '类型管理', 'categories', 'categories', 'views/contentManagement/CategoryManagementView','', '', 'drama:list', 'MENU', 0, 0, 4),
(6, 0, '后台管理', '/system', 'System', '#', '/system/access', 'ep:setting', 'system:role', 'CATALOG', 1, 0, 3),
(36, 3, '分类管理', 'category-dramas','category-dramas','views/contentManagement/CategoryDramaView', '', '', 'drama:list', 'MENU', 0, 0, 5),
(37, 3, '剧单管理', 'drama-playlists','drama-playlists','views/contentManagement/DramaPlaylistView', '', '', 'drama:list', 'MENU', 0, 0, 6),
(6, 0, '后台管理', '/system', 'System', '#', '/system/access', 'material-symbols:settings-rounded', 'system:role', 'CATALOG', 1, 0, 3),
(7, 6, '角色权限配置', 'access', 'access', 'views/permission/RoleManagementView', '', '', 'system:role', 'MENU', 0, 0, 1),
(8, 6, '管理员用户列表','admin-users','admin-users', 'views/userManagement/AdminUsersView', '', '', 'system:admin-user','MENU', 0, 0, 2),
(9, 6, '菜单管理', 'menus', 'menus', 'views/permission/MenuManagementView', '', '', 'system:menu', 'MENU', 0, 0, 3),
@@ -77,6 +79,17 @@ ON CONFLICT (id) DO UPDATE SET parent_id = EXCLUDED.parent_id, title = EXCLUDED.
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_menu (id, parent_id, title, route_path, route_name, component, redirect, icon,
permission_code, type, always_show, affix, sort) VALUES
(35, 6, '转码设置', 'transcode-settings', 'transcode-settings', 'views/systemManagement/TranscodeSettingsView', '', '', 'episode:upload', 'MENU', 0, 0, 7)
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;
-- K23:二级菜单统一只显示文字,历史图标值也一并清空。
UPDATE sys_menu SET icon = '' WHERE type = 'MENU';
-- ---------- 角色-权限 ----------
INSERT INTO sys_role_permission (id, role_id, permission_id)
SELECT r.id * 1000000 + p.id, r.id, p.id FROM sys_role r CROSS JOIN sys_permission p WHERE r.code = 'super_admin'
@@ -109,7 +122,7 @@ ON CONFLICT DO NOTHING;
INSERT INTO sys_role_menu (id, role_id, menu_id)
SELECT r.id * 1000000 + m.id, r.id, m.id FROM sys_role r CROSS JOIN sys_menu m
WHERE r.code IN ('content_operator','content_reviewer','data_analyst') AND m.id IN (1,2,3,4,5,12,13)
WHERE r.code IN ('content_operator','content_reviewer','data_analyst') AND m.id IN (1,2,3,4,5,12,13,36,37)
ON CONFLICT DO NOTHING;
-- ---------- 管理员(密码均为 admin123) ----------
+2
View File
@@ -0,0 +1,2 @@
ALTER TABLE drama ADD COLUMN IF NOT EXISTS drama_type VARCHAR(16) NOT NULL DEFAULT 'LIVE';
COMMENT ON COLUMN drama.drama_type IS '内容类型:ANIME=漫剧,LIVE=真人剧';
+2
View File
@@ -0,0 +1,2 @@
ALTER TABLE drama_episode ADD COLUMN IF NOT EXISTS like_count BIGINT NOT NULL DEFAULT 0;
COMMENT ON COLUMN drama_episode.like_count IS '本集点赞数(点赞目标为 EPISODE)';
+34
View File
@@ -0,0 +1,34 @@
-- Author: fruit.com.cn
-- K91 后台观看记录独立菜单与权限点(幂等,仅提交文件,由发布流程执行)
INSERT INTO sys_permission (id, code, name, group_name, type, sort) VALUES
(1105, 'watch-history:list', '查看观看记录', '用户管理', 'BUTTON', 105)
ON CONFLICT (code) DO NOTHING;
INSERT INTO sys_role_permission (id, role_id, permission_id)
SELECT r.id * 1000000 + p.id, r.id, p.id
FROM sys_role r
CROSS JOIN sys_permission p
WHERE r.code = 'super_admin' AND p.code = 'watch-history:list'
ON CONFLICT DO NOTHING;
-- 任务书建议使用菜单 id 26,但现有“创作者中心”已使用 26,27-30 为其子菜单。
-- 为避免覆盖已有菜单树,这里使用下一个空闲 id 34。
INSERT INTO sys_menu (id, parent_id, title, route_path, route_name, component, redirect, icon,
permission_code, type, always_show, affix, sort) VALUES
(34, 15, '观看记录', 'watch-history', 'watch-history',
'views/userManagement/WatchHistoryView', '', '',
'watch-history: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 (id, role_id, menu_id)
SELECT r.id * 1000000 + m.id, r.id, m.id
FROM sys_role r
CROSS JOIN sys_menu m
WHERE r.code = 'super_admin' AND m.id = 34
ON CONFLICT DO NOTHING;
+16
View File
@@ -0,0 +1,16 @@
-- Author: fruit.com.cn
-- K93 短剧分类与内容类型多选(幂等,仅提交文件,由发布流程执行)
ALTER TABLE drama ADD COLUMN IF NOT EXISTS drama_types VARCHAR(32) NOT NULL DEFAULT '';
COMMENT ON COLUMN drama.drama_types IS '内容类型多选,逗号分隔(ANIME/LIVE),drama_type 保留第一个';
ALTER TABLE drama ADD COLUMN IF NOT EXISTS category_ids VARCHAR(255) NOT NULL DEFAULT '';
COMMENT ON COLUMN drama.category_ids IS
'短剧分类多选,逗号分隔的 category_id,category_id 保留第一个';
UPDATE drama SET drama_types = drama_type
WHERE (drama_types IS NULL OR drama_types = '') AND drama_type IS NOT NULL AND drama_type <> '';
UPDATE drama SET category_ids = category_id::text
WHERE (category_ids IS NULL OR category_ids = '') AND category_id IS NOT NULL AND category_id > 0;
@@ -0,0 +1,26 @@
-- Author: fruit.com.cn
-- 将已有零绑定转码任务按分集视频 URL 回填(幂等,仅处理未完成任务)
BEGIN;
UPDATE transcode_task t
SET drama_id = e.drama_id,
episode_id = e.id
FROM drama_episode e
WHERE t.deleted = 0
AND e.deleted = 0
AND t.status IN ('QUEUED', 'RUNNING')
AND t.episode_id = 0
AND e.drama_id > 0
AND split_part(e.video_url, '?', 1) = split_part(t.source_url, '?', 1);
UPDATE drama_episode e
SET video_asset_id = t.media_asset_id
FROM transcode_task t
WHERE t.deleted = 0
AND t.episode_id = e.id
AND t.media_asset_id > 0
AND e.video_asset_id = 0
AND split_part(e.video_url, '?', 1) = split_part(t.source_url, '?', 1);
COMMIT;
@@ -0,0 +1,21 @@
-- Author: fruit.com.cn
-- 后台「分类管理」菜单与分类-短剧关联页(幂等,仅提交文件,由发布流程执行)
INSERT INTO sys_menu (id, parent_id, title, route_path, route_name, component, redirect, icon,
permission_code, type, always_show, affix, sort) VALUES
(36, 3, '分类管理', 'category-dramas', 'category-dramas',
'views/contentManagement/CategoryDramaView', '', '',
'drama:list', 'MENU', 0, 0, 5)
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 (id, role_id, menu_id)
SELECT r.id * 1000000 + m.id, r.id, m.id
FROM sys_role r
CROSS JOIN sys_menu m
WHERE r.code IN ('super_admin', 'content_operator', 'content_reviewer', 'data_analyst')
AND m.id = 36
ON CONFLICT DO NOTHING;
@@ -0,0 +1,31 @@
-- Author: fruit.com.cn
-- 运营分类(与「类型」drama_category 是两个概念):分类可自定义增删,并关联多部短剧
-- 幂等,仅提交文件,由发布流程执行
CREATE TABLE IF NOT EXISTS drama_classification (
id BIGINT PRIMARY KEY,
name VARCHAR(64) NOT NULL,
sort INTEGER NOT NULL DEFAULT 0,
status SMALLINT NOT NULL DEFAULT 1,
created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX IF NOT EXISTS uk_drama_classification_name ON drama_classification (name);
COMMENT ON TABLE drama_classification IS '运营分类;与短剧类型(drama_category)相互独立';
CREATE TABLE IF NOT EXISTS drama_classification_drama (
id BIGINT PRIMARY KEY,
classification_id BIGINT NOT NULL,
drama_id BIGINT NOT NULL,
created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX IF NOT EXISTS uk_classification_drama
ON drama_classification_drama (classification_id, drama_id);
CREATE INDEX IF NOT EXISTS idx_classification_drama_drama
ON drama_classification_drama (drama_id);
COMMENT ON TABLE drama_classification_drama IS '分类与短剧的关联关系';
DROP TRIGGER IF EXISTS trg_drama_classification_updated_at ON drama_classification;
CREATE TRIGGER trg_drama_classification_updated_at
BEFORE UPDATE ON drama_classification
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
@@ -0,0 +1,21 @@
-- Author: fruit.com.cn
-- 后台「剧单管理」菜单(幂等,仅提交文件,由发布流程执行)
INSERT INTO sys_menu (id, parent_id, title, route_path, route_name, component, redirect, icon,
permission_code, type, always_show, affix, sort) VALUES
(37, 3, '剧单管理', 'drama-playlists', 'drama-playlists',
'views/contentManagement/DramaPlaylistView', '', '',
'drama:list', 'MENU', 0, 0, 6)
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 (id, role_id, menu_id)
SELECT r.id * 1000000 + m.id, r.id, m.id
FROM sys_role r
CROSS JOIN sys_menu m
WHERE r.code IN ('super_admin', 'content_operator', 'content_reviewer', 'data_analyst')
AND m.id = 37
ON CONFLICT DO NOTHING;
+31
View File
@@ -0,0 +1,31 @@
-- Author: fruit.com.cn
-- 剧单:运营编排的短剧集合,归属某个分类,并可关联多部短剧
-- 幂等,仅提交文件,由发布流程执行
CREATE TABLE IF NOT EXISTS drama_playlist (
id BIGINT PRIMARY KEY,
classification_id BIGINT NOT NULL DEFAULT 0,
name VARCHAR(64) NOT NULL,
sort INTEGER NOT NULL DEFAULT 0,
status SMALLINT NOT NULL DEFAULT 1,
created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX IF NOT EXISTS uk_drama_playlist_name ON drama_playlist (name);
CREATE INDEX IF NOT EXISTS idx_drama_playlist_classification ON drama_playlist (classification_id);
COMMENT ON TABLE drama_playlist IS '剧单;归属分类,可关联多部短剧';
CREATE TABLE IF NOT EXISTS drama_playlist_drama (
id BIGINT PRIMARY KEY,
playlist_id BIGINT NOT NULL,
drama_id BIGINT NOT NULL,
created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX IF NOT EXISTS uk_playlist_drama ON drama_playlist_drama (playlist_id, drama_id);
CREATE INDEX IF NOT EXISTS idx_playlist_drama_drama ON drama_playlist_drama (drama_id);
COMMENT ON TABLE drama_playlist_drama IS '剧单与短剧的关联关系';
DROP TRIGGER IF EXISTS trg_drama_playlist_updated_at ON drama_playlist;
CREATE TRIGGER trg_drama_playlist_updated_at
BEFORE UPDATE ON drama_playlist
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
+45
View File
@@ -0,0 +1,45 @@
-- Author: fruit.com.cn
-- 转码缩略图轴:默认档位配置 + 单集雪碧图/VTT 元数据(幂等)
CREATE TABLE IF NOT EXISTS media_thumbnail (
id BIGINT PRIMARY KEY,
episode_id BIGINT NOT NULL,
drama_id BIGINT NOT NULL DEFAULT 0,
vtt_object_key VARCHAR(512) NOT NULL DEFAULT '',
sprite_prefix VARCHAR(512) NOT NULL DEFAULT '',
interval_sec INT NOT NULL DEFAULT 1,
columns INT NOT NULL DEFAULT 10,
rows INT NOT NULL DEFAULT 1,
thumb_width INT NOT NULL DEFAULT 160,
thumb_height INT NOT NULL DEFAULT 0,
frame_count INT NOT NULL DEFAULT 0,
duration_sec INT NOT NULL DEFAULT 0,
size_bytes BIGINT NOT NULL DEFAULT 0,
status VARCHAR(16) NOT NULL DEFAULT 'FAILED',
error_msg VARCHAR(500) NOT NULL DEFAULT '',
created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted SMALLINT NOT NULL DEFAULT 0
);
CREATE UNIQUE INDEX IF NOT EXISTS uk_media_thumbnail_episode
ON media_thumbnail (episode_id);
CREATE INDEX IF NOT EXISTS idx_media_thumbnail_drama
ON media_thumbnail (drama_id);
COMMENT ON TABLE media_thumbnail IS '单集缩略图雪碧图与 VTT 时间轴';
DROP TRIGGER IF EXISTS trg_media_thumbnail_updated_at ON media_thumbnail;
CREATE TRIGGER trg_media_thumbnail_updated_at
BEFORE UPDATE ON media_thumbnail
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
INSERT INTO sys_config (id, config_key, config_value, remark) VALUES
(2026102201,
'media.transcode.profile',
'{"enabled":true,"segmentSeconds":6,"ladder":[' ||
'{"quality":"360p","width":640,"height":360,"videoBitrateKbps":400,"audioBitrateKbps":64,"enabled":true},' ||
'{"quality":"480p","width":854,"height":480,"videoBitrateKbps":800,"audioBitrateKbps":64,"enabled":true},' ||
'{"quality":"720p","width":1280,"height":720,"videoBitrateKbps":1600,"audioBitrateKbps":96,"enabled":true},' ||
'{"quality":"1080p","width":1920,"height":1080,"videoBitrateKbps":3200,"audioBitrateKbps":128,"enabled":true}],' ||
'"sprite":{"enabled":true,"intervalSeconds":1,"columns":10,"thumbWidth":160}}',
'转码档位与缩略图轴配置')
ON CONFLICT (config_key) DO NOTHING;
@@ -0,0 +1,18 @@
-- Author: fruit.com.cn
-- 剧单分类直接关联短剧(不再有「剧单」这一层)
-- 幂等,仅提交文件,由发布流程执行
CREATE TABLE IF NOT EXISTS drama_playlist_category_drama (
id BIGINT PRIMARY KEY,
category_id BIGINT NOT NULL,
drama_id BIGINT NOT NULL,
created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX IF NOT EXISTS uk_playlist_category_drama
ON drama_playlist_category_drama (category_id, drama_id);
CREATE INDEX IF NOT EXISTS idx_playlist_category_drama_drama
ON drama_playlist_category_drama (drama_id);
COMMENT ON TABLE drama_playlist_category_drama IS '剧单分类与短剧的关联关系';
DROP TABLE IF EXISTS drama_playlist_drama;
DROP TABLE IF EXISTS drama_playlist;
@@ -0,0 +1,31 @@
-- Author: fruit.com.cn
-- 剧单专属分类(与「分类管理」的运营分类无关),并调整剧单归属字段
-- 幂等,仅提交文件,由发布流程执行
CREATE TABLE IF NOT EXISTS drama_playlist_category (
id BIGINT PRIMARY KEY,
name VARCHAR(64) NOT NULL,
sort INTEGER NOT NULL DEFAULT 0,
status SMALLINT NOT NULL DEFAULT 1,
created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX IF NOT EXISTS uk_drama_playlist_category_name
ON drama_playlist_category (name);
COMMENT ON TABLE drama_playlist_category IS '剧单专属分类;与运营分类(drama_classification)相互独立';
ALTER TABLE drama_playlist DROP COLUMN IF EXISTS classification_id;
ALTER TABLE drama_playlist ADD COLUMN IF NOT EXISTS playlist_category_id BIGINT NOT NULL DEFAULT 0;
CREATE INDEX IF NOT EXISTS idx_drama_playlist_category
ON drama_playlist (playlist_category_id);
COMMENT ON COLUMN drama_playlist.playlist_category_id IS '剧单分类;0 表示未分类';
DROP TRIGGER IF EXISTS trg_drama_playlist_category_updated_at ON drama_playlist_category;
CREATE TRIGGER trg_drama_playlist_category_updated_at
BEFORE UPDATE ON drama_playlist_category
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
-- Author: fruit.com.cn
-- 剧单分类增加描述字段(幂等)
ALTER TABLE drama_playlist_category ADD COLUMN IF NOT EXISTS description VARCHAR(255) NOT NULL DEFAULT '';
COMMENT ON COLUMN drama_playlist_category.description IS '分类描述';
@@ -0,0 +1,12 @@
-- Author: fruit.com.cn
-- 扩展转码错误信息列,允许保留 ffmpeg / ffprobe 关键错误上下文(可重复执行)
BEGIN;
ALTER TABLE IF EXISTS transcode_task
ALTER COLUMN error_msg TYPE TEXT USING error_msg::TEXT;
ALTER TABLE IF EXISTS media_thumbnail
ALTER COLUMN error_msg TYPE TEXT USING error_msg::TEXT;
COMMIT;
@@ -0,0 +1,20 @@
-- Author: fruit.com.cn
-- 后台「转码设置」独立菜单(幂等,仅提交文件,由发布流程执行)
INSERT INTO sys_menu (id, parent_id, title, route_path, route_name, component, redirect, icon,
permission_code, type, always_show, affix, sort) VALUES
(35, 6, '转码设置', 'transcode-settings', 'transcode-settings',
'views/systemManagement/TranscodeSettingsView', '', '',
'episode:upload', 'MENU', 0, 0, 7)
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 (id, role_id, menu_id)
SELECT r.id * 1000000 + m.id, r.id, m.id
FROM sys_role r
CROSS JOIN sys_menu m
WHERE r.code = 'super_admin' AND m.id = 35
ON CONFLICT DO NOTHING;
@@ -0,0 +1,22 @@
-- Author: fruit.com.cn
-- 收口未绑定分集或媒资不存在的僵尸转码任务(可重复执行)
BEGIN;
UPDATE transcode_task t
SET status = 'FAILED',
error_msg = '历史任务无效:episode_id=0 或 media_asset_id 指向不存在的媒资,请从有视频的分集重新转码',
finished_at = CURRENT_TIMESTAMP
WHERE t.deleted = 0
AND t.status IN ('QUEUED', 'RUNNING')
AND (
t.episode_id = 0
OR NOT EXISTS (
SELECT 1
FROM media_asset a
WHERE a.id = t.media_asset_id
AND a.deleted = 0
)
);
COMMIT;
+40
View File
@@ -0,0 +1,40 @@
-- Author: fruit.com.cn
-- 服务条款与隐私协议:三语正文 + 后台菜单
CREATE TABLE IF NOT EXISTS legal_document (
id BIGINT PRIMARY KEY,
doc_code VARCHAR(16) NOT NULL,
lang VARCHAR(8) NOT NULL,
title VARCHAR(128) NOT NULL DEFAULT '',
content TEXT NOT NULL DEFAULT '',
updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX IF NOT EXISTS uk_legal_document_code_lang ON legal_document (doc_code, lang);
COMMENT ON TABLE legal_document IS '服务条款与隐私协议';
INSERT INTO legal_document (id, doc_code, lang, title, content) VALUES
(910001, 'terms', 'zh', '', '本页由水果短剧发布,可在管理后台用 Markdown 修改。'),
(910002, 'terms', 'en', '', 'This page is published by FruitShorts and can be edited as Markdown in the admin console.'),
(910003, 'terms', 'id', '', 'Halaman ini dipublikasikan oleh FruitShorts dan dapat diubah sebagai Markdown di konsol admin.'),
(910004, 'privacy', 'zh', '', '本页由水果短剧发布,可在管理后台用 Markdown 修改。'),
(910005, 'privacy', 'en', '', 'This page is published by FruitShorts and can be edited as Markdown in the admin console.'),
(910006, 'privacy', 'id', '', 'Halaman ini dipublikasikan oleh FruitShorts dan dapat diubah sebagai Markdown di konsol admin.')
ON CONFLICT (doc_code, lang) DO NOTHING;
INSERT INTO sys_menu (id, parent_id, title, route_path, route_name, component, redirect, icon,
permission_code, type, always_show, affix, sort) VALUES
(38, 6, '协议设置', 'legal-documents', 'legal-documents',
'views/systemManagement/LegalDocumentView', '', '',
'system:role', 'MENU', 0, 0, 8)
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 (id, role_id, menu_id)
SELECT r.id * 1000000 + m.id, r.id, m.id
FROM sys_role r
CROSS JOIN sys_menu m
WHERE r.code = 'super_admin' AND m.id = 38
ON CONFLICT DO NOTHING;
+107 -2
View File
@@ -44,6 +44,7 @@ ALTER TABLE drama_episode ADD COLUMN IF NOT EXISTS preview_seconds INT
ALTER TABLE drama_episode ADD COLUMN IF NOT EXISTS subtitle_url VARCHAR(512) NOT NULL DEFAULT '';
ALTER TABLE drama_episode ADD COLUMN IF NOT EXISTS subtitle_lang VARCHAR(16) NOT NULL DEFAULT '';
ALTER TABLE drama_episode ADD COLUMN IF NOT EXISTS is_vip_only SMALLINT NOT NULL DEFAULT 0; -- 预留:会员专属(第二阶段)
ALTER TABLE drama_episode ADD COLUMN IF NOT EXISTS like_count BIGINT NOT NULL DEFAULT 0; -- 本集点赞数
-- 媒资:CDN 地址与转码状态
ALTER TABLE media_asset ADD COLUMN IF NOT EXISTS cdn_url VARCHAR(512) NOT NULL DEFAULT '';
@@ -784,6 +785,32 @@ CREATE UNIQUE INDEX IF NOT EXISTS uk_rendition ON media_rendition (media_asset_i
CREATE INDEX IF NOT EXISTS idx_rendition_episode ON media_rendition (episode_id);
COMMENT ON TABLE media_rendition IS '多码率产物;播放票据按此生成 master playlist';
CREATE TABLE IF NOT EXISTS media_thumbnail (
id BIGINT PRIMARY KEY,
episode_id BIGINT NOT NULL,
drama_id BIGINT NOT NULL DEFAULT 0,
vtt_object_key VARCHAR(512) NOT NULL DEFAULT '',
sprite_prefix VARCHAR(512) NOT NULL DEFAULT '',
interval_sec INT NOT NULL DEFAULT 1,
columns INT NOT NULL DEFAULT 10,
rows INT NOT NULL DEFAULT 1,
thumb_width INT NOT NULL DEFAULT 160,
thumb_height INT NOT NULL DEFAULT 0,
frame_count INT NOT NULL DEFAULT 0,
duration_sec INT NOT NULL DEFAULT 0,
size_bytes BIGINT NOT NULL DEFAULT 0,
status VARCHAR(16) NOT NULL DEFAULT 'FAILED',
error_msg VARCHAR(500) NOT NULL DEFAULT '',
created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted SMALLINT NOT NULL DEFAULT 0
);
CREATE UNIQUE INDEX IF NOT EXISTS uk_media_thumbnail_episode
ON media_thumbnail (episode_id);
CREATE INDEX IF NOT EXISTS idx_media_thumbnail_drama
ON media_thumbnail (drama_id);
COMMENT ON TABLE media_thumbnail IS '单集缩略图雪碧图与 VTT 时间轴';
-- ============================================================
-- 八、运营补充(PRD 08 平台运营后台 / 10 上线)
-- ============================================================
@@ -842,9 +869,64 @@ CREATE INDEX IF NOT EXISTS idx_audit_log_biz ON audit_log (biz_type, biz_id, cre
COMMENT ON TABLE audit_log IS '业务对象变更审计(支付、权益、定价等敏感操作)';
-- ============================================================
-- 九、updated_at 触发器(与已有表保持一致)
-- 八之二、运营分类(与短剧类型 drama_category 相互独立)
-- ============================================================
CREATE TABLE IF NOT EXISTS drama_classification (
id BIGINT PRIMARY KEY,
name VARCHAR(64) NOT NULL,
sort INTEGER NOT NULL DEFAULT 0,
status SMALLINT NOT NULL DEFAULT 1,
created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX IF NOT EXISTS uk_drama_classification_name ON drama_classification (name);
COMMENT ON TABLE drama_classification IS '运营分类;与短剧类型(drama_category)相互独立';
CREATE TABLE IF NOT EXISTS drama_classification_drama (
id BIGINT PRIMARY KEY,
classification_id BIGINT NOT NULL,
drama_id BIGINT NOT NULL,
created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX IF NOT EXISTS uk_classification_drama
ON drama_classification_drama (classification_id, drama_id);
CREATE INDEX IF NOT EXISTS idx_classification_drama_drama
ON drama_classification_drama (drama_id);
COMMENT ON TABLE drama_classification_drama IS '分类与短剧的关联关系';
-- ============================================================
-- 八之三、剧单(剧单有自己的一套分类,与运营分类无关)
-- ============================================================
CREATE TABLE IF NOT EXISTS drama_playlist_category (
id BIGINT PRIMARY KEY,
name VARCHAR(64) NOT NULL,
description VARCHAR(255) NOT NULL DEFAULT '',
sort INTEGER NOT NULL DEFAULT 0,
status SMALLINT NOT NULL DEFAULT 1,
created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX IF NOT EXISTS uk_drama_playlist_category_name
ON drama_playlist_category (name);
COMMENT ON TABLE drama_playlist_category IS '剧单专属分类;与运营分类(drama_classification)相互独立';
CREATE TABLE IF NOT EXISTS drama_playlist_category_drama (
id BIGINT PRIMARY KEY,
category_id BIGINT NOT NULL,
drama_id BIGINT NOT NULL,
created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX IF NOT EXISTS uk_playlist_category_drama
ON drama_playlist_category_drama (category_id, drama_id);
CREATE INDEX IF NOT EXISTS idx_playlist_category_drama_drama
ON drama_playlist_category_drama (drama_id);
COMMENT ON TABLE drama_playlist_category_drama IS '剧单分类与短剧的关联关系';
-- ============================================================
-- 九、updated_at 触发器(与已有表保持一致)
-- ============================================================
DO $$
DECLARE
t TEXT;
@@ -857,7 +939,9 @@ BEGIN
'wallet', 'product', 'orders', 'store_receipt', 'entitlement', 'refund_record',
'reconcile_task', 'creator', 'creator_document', 'content_submission',
'creator_stat_daily', 'creator_settlement',
'transcode_task', 'media_rendition',
'transcode_task', 'media_rendition', 'media_thumbnail',
'drama_classification',
'drama_playlist_category',
'ops_notice', 'ops_daily_stat'
]
LOOP
@@ -933,3 +1017,24 @@ COMMENT ON COLUMN sys_admin_user.must_change_password IS '1 = 首登强制改密
-- 默认 1(超管照旧看到),置 0 表示"不给超管显示"。
ALTER TABLE sys_menu ADD COLUMN IF NOT EXISTS super_admin_visible SMALLINT NOT NULL DEFAULT 1;
COMMENT ON COLUMN sys_menu.super_admin_visible IS '0 = 不给超管显示(角色专属菜单用;超管的菜单是全量兜底,不走 sys_role_menu)';
-- ============================================================
-- 十、C3 埋点事件落库(/app/events 匿名上报,供分析漏斗用)
-- ============================================================
CREATE TABLE IF NOT EXISTS app_event_log (
id BIGINT PRIMARY KEY,
event_name VARCHAR(64) NOT NULL,
event_time TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
user_id BIGINT,
device_id VARCHAR(64),
session_id VARCHAR(64),
page VARCHAR(128),
properties TEXT,
client_ip VARCHAR(64),
created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_app_event_log_time ON app_event_log (event_time DESC);
CREATE INDEX IF NOT EXISTS idx_app_event_log_user ON app_event_log (user_id);
CREATE INDEX IF NOT EXISTS idx_app_event_log_name_time ON app_event_log (event_name, event_time DESC);
COMMENT ON TABLE app_event_log IS '客户端埋点事件原始落库(匿名上报,供后续分析与漏斗)';
+14
View File
@@ -127,6 +127,17 @@ CREATE TABLE IF NOT EXISTS sys_config (
CREATE UNIQUE INDEX IF NOT EXISTS uk_sys_config_key ON sys_config (config_key);
COMMENT ON TABLE sys_config IS '系统配置';
CREATE TABLE IF NOT EXISTS legal_document (
id BIGINT PRIMARY KEY,
doc_code VARCHAR(16) NOT NULL, -- terms / privacy
lang VARCHAR(8) NOT NULL, -- zh / en / id
title VARCHAR(128) NOT NULL DEFAULT '',
content TEXT NOT NULL DEFAULT '',
updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX IF NOT EXISTS uk_legal_document_code_lang ON legal_document (doc_code, lang);
COMMENT ON TABLE legal_document IS '服务条款与隐私协议';
CREATE TABLE IF NOT EXISTS sys_operation_log (
id BIGINT PRIMARY KEY,
admin_user_id BIGINT NOT NULL DEFAULT 0,
@@ -164,11 +175,14 @@ CREATE TABLE IF NOT EXISTS drama (
title VARCHAR(128) NOT NULL,
subtitle VARCHAR(128) NOT NULL DEFAULT '',
category_id BIGINT NOT NULL DEFAULT 0,
category_ids VARCHAR(255) NOT NULL DEFAULT '',
genre VARCHAR(64) NOT NULL DEFAULT '',
synopsis VARCHAR(1000) NOT NULL DEFAULT '',
cover_url VARCHAR(512) NOT NULL DEFAULT '',
horizontal_cover_url VARCHAR(512) NOT NULL DEFAULT '',
language VARCHAR(16) NOT NULL DEFAULT 'zh-CN',
drama_type VARCHAR(16) NOT NULL DEFAULT 'LIVE',
drama_types VARCHAR(32) NOT NULL DEFAULT '',
total_episodes INT NOT NULL DEFAULT 0,
free_episodes INT NOT NULL DEFAULT 3,
unlock_coin INT NOT NULL DEFAULT 0,