diff --git a/.gitignore b/.gitignore
index 45797b6..70f3274 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,7 +29,11 @@ backend/uploads/
backend/logs/
backend/venv/
backend/test/
-backend/sql/
+# Only keep the latest full-deploy SQL entrypoints in repo
+backend/sql/*
+!backend/sql/imeeting-schema-latest.sql
+!backend/sql/imeeting-seed-latest.sql
+backend/sql/migrations/
backend/scripts/
资料/
@@ -150,4 +154,3 @@ lerna-debug.log*
.pnp.*
pids/
logs/
-
diff --git a/backend/sql/imeeting-schema-latest.sql b/backend/sql/imeeting-schema-latest.sql
new file mode 100644
index 0000000..54f3e3d
--- /dev/null
+++ b/backend/sql/imeeting-schema-latest.sql
@@ -0,0 +1,643 @@
+-- iMeeting latest schema initialization script
+-- 用途:
+-- 1. 面向当前最新代码结构的全新部署
+-- 2. 不再兼容或保留旧 users / roles / menus 等历史结构
+-- 3. 仅负责建表,不写入基础角色/用户/菜单/参数等种子数据
+-- 4. 本文件即为全量建表入口,无需执行历史 migrations 目录脚本
+--
+-- 执行顺序:
+-- 1. 先执行本文件
+-- 2. 再执行 imeeting-seed-latest.sql
+
+SET NAMES utf8mb4;
+
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- 兼容旧迁移中创建的 legacy views
+DROP VIEW IF EXISTS `users`;
+DROP VIEW IF EXISTS `roles`;
+DROP VIEW IF EXISTS `menus`;
+DROP VIEW IF EXISTS `role_menu_permissions`;
+DROP VIEW IF EXISTS `dict_data`;
+DROP VIEW IF EXISTS `system_parameters`;
+
+-- 清理旧结构与当前结构
+DROP TABLE IF EXISTS `sys_role_menu_permissions`;
+DROP TABLE IF EXISTS `prompt_config`;
+DROP TABLE IF EXISTS `sys_user_mcp`;
+DROP TABLE IF EXISTS `user_logs`;
+DROP TABLE IF EXISTS `user_voiceprint`;
+DROP TABLE IF EXISTS `client_downloads`;
+DROP TABLE IF EXISTS `external_apps`;
+DROP TABLE IF EXISTS `terminals`;
+DROP TABLE IF EXISTS `knowledge_base_tasks`;
+DROP TABLE IF EXISTS `knowledge_bases`;
+DROP TABLE IF EXISTS `llm_tasks`;
+DROP TABLE IF EXISTS `transcript_segments`;
+DROP TABLE IF EXISTS `transcript_tasks`;
+DROP TABLE IF EXISTS `audio_files`;
+DROP TABLE IF EXISTS `attachments`;
+DROP TABLE IF EXISTS `attendees`;
+DROP TABLE IF EXISTS `meetings`;
+DROP TABLE IF EXISTS `tags`;
+DROP TABLE IF EXISTS `prompts`;
+DROP TABLE IF EXISTS `audio_model_config`;
+DROP TABLE IF EXISTS `llm_model_config`;
+DROP TABLE IF EXISTS `hot_word_item`;
+DROP TABLE IF EXISTS `hot_word_group`;
+DROP TABLE IF EXISTS `sys_system_parameters`;
+DROP TABLE IF EXISTS `sys_dict_data`;
+DROP TABLE IF EXISTS `sys_menus`;
+DROP TABLE IF EXISTS `sys_users`;
+DROP TABLE IF EXISTS `sys_roles`;
+
+-- 历史阶段遗留表,一并清理
+DROP TABLE IF EXISTS `meeting_summaries`;
+DROP TABLE IF EXISTS `sys_user_prompt_config`;
+DROP TABLE IF EXISTS `ai_model_configs`;
+DROP TABLE IF EXISTS `ai_model_config`;
+DROP TABLE IF EXISTS `llm_model_configs`;
+DROP TABLE IF EXISTS `audio_model_configs`;
+DROP TABLE IF EXISTS `hot_words`;
+DROP TABLE IF EXISTS `system_parameters`;
+DROP TABLE IF EXISTS `dict_data`;
+DROP TABLE IF EXISTS `role_menu_permissions`;
+DROP TABLE IF EXISTS `menus`;
+DROP TABLE IF EXISTS `users`;
+DROP TABLE IF EXISTS `roles`;
+
+SET FOREIGN_KEY_CHECKS = 1;
+
+-- =====================================================================
+-- 1. 基础系统表
+-- =====================================================================
+CREATE TABLE `sys_roles` (
+ `role_id` INT NOT NULL AUTO_INCREMENT,
+ `role_name` VARCHAR(50) NOT NULL COMMENT '角色名称',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ PRIMARY KEY (`role_id`),
+ UNIQUE KEY `uk_sys_roles_name` (`role_name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统角色表';
+
+CREATE TABLE `sys_users` (
+ `user_id` INT NOT NULL AUTO_INCREMENT,
+ `username` VARCHAR(50) NOT NULL COMMENT '登录账号',
+ `caption` VARCHAR(50) NOT NULL COMMENT '显示名称',
+ `email` VARCHAR(100) DEFAULT NULL COMMENT '邮箱,可为空',
+ `avatar_url` VARCHAR(255) DEFAULT NULL COMMENT '头像地址',
+ `password_hash` VARCHAR(255) NOT NULL COMMENT '密码哈希',
+ `role_id` INT NOT NULL DEFAULT 2 COMMENT '角色ID',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ PRIMARY KEY (`user_id`),
+ UNIQUE KEY `uk_sys_users_username` (`username`),
+ UNIQUE KEY `uk_sys_users_email` (`email`),
+ KEY `idx_sys_users_role_id` (`role_id`),
+ KEY `idx_sys_users_created_at` (`created_at`),
+ CONSTRAINT `fk_sys_users_role_id`
+ FOREIGN KEY (`role_id`) REFERENCES `sys_roles` (`role_id`)
+ ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统用户表';
+
+CREATE TABLE `sys_menus` (
+ `menu_id` INT NOT NULL AUTO_INCREMENT,
+ `menu_code` VARCHAR(50) NOT NULL COMMENT '菜单编码',
+ `menu_name` VARCHAR(100) NOT NULL COMMENT '菜单名称',
+ `menu_icon` VARCHAR(100) DEFAULT NULL COMMENT '菜单图标',
+ `menu_url` VARCHAR(255) DEFAULT NULL COMMENT '前端路由',
+ `menu_type` ENUM('action', 'link', 'divider') NOT NULL DEFAULT 'link' COMMENT '菜单类型',
+ `parent_id` INT DEFAULT NULL COMMENT '父菜单ID',
+ `menu_level` TINYINT NOT NULL DEFAULT 1 COMMENT '菜单层级(根节点为1)',
+ `tree_path` VARCHAR(255) DEFAULT NULL COMMENT '树路径(如 /1/5)',
+ `sort_order` INT NOT NULL DEFAULT 0 COMMENT '排序号',
+ `is_active` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+ `is_visible` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否在侧边栏显示',
+ `description` VARCHAR(255) DEFAULT NULL COMMENT '菜单说明',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ PRIMARY KEY (`menu_id`),
+ UNIQUE KEY `uk_sys_menus_code` (`menu_code`),
+ KEY `idx_sys_menus_parent_id` (`parent_id`),
+ KEY `idx_sys_menus_menu_level` (`menu_level`),
+ KEY `idx_sys_menus_tree_path` (`tree_path`),
+ KEY `idx_sys_menus_is_active` (`is_active`),
+ KEY `idx_sys_menus_is_visible` (`is_visible`),
+ CONSTRAINT `fk_sys_menus_parent_id`
+ FOREIGN KEY (`parent_id`) REFERENCES `sys_menus` (`menu_id`)
+ ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统菜单表';
+
+CREATE TABLE `sys_dict_data` (
+ `id` BIGINT NOT NULL AUTO_INCREMENT,
+ `dict_type` VARCHAR(64) NOT NULL DEFAULT 'client_platform' COMMENT '字典类型',
+ `dict_code` VARCHAR(64) NOT NULL COMMENT '业务编码',
+ `parent_code` VARCHAR(64) NOT NULL DEFAULT 'ROOT' COMMENT '父级编码',
+ `tree_path` VARCHAR(255) DEFAULT NULL COMMENT '树路径',
+ `label_cn` VARCHAR(128) NOT NULL COMMENT '中文名称',
+ `label_en` VARCHAR(128) DEFAULT NULL COMMENT '英文名称',
+ `sort_order` INT NOT NULL DEFAULT 0 COMMENT '排序',
+ `extension_attr` LONGTEXT DEFAULT NULL COMMENT '扩展属性(JSON字符串)',
+ `is_default` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否默认',
+ `status` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '状态',
+ `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_sys_dict_data_type_code` (`dict_type`, `dict_code`),
+ KEY `idx_sys_dict_data_type_parent` (`dict_type`, `parent_code`),
+ KEY `idx_sys_dict_data_status` (`status`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统字典数据表';
+
+CREATE TABLE `sys_system_parameters` (
+ `param_id` BIGINT NOT NULL AUTO_INCREMENT,
+ `param_key` VARCHAR(128) NOT NULL COMMENT '参数键',
+ `param_name` VARCHAR(255) NOT NULL COMMENT '参数名称',
+ `param_value` TEXT DEFAULT NULL COMMENT '参数值',
+ `value_type` VARCHAR(32) NOT NULL DEFAULT 'string' COMMENT '值类型',
+ `category` VARCHAR(64) NOT NULL DEFAULT 'system' COMMENT '参数分类',
+ `description` VARCHAR(500) DEFAULT NULL COMMENT '参数说明',
+ `is_active` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ PRIMARY KEY (`param_id`),
+ UNIQUE KEY `uk_sys_system_parameters_key` (`param_key`),
+ KEY `idx_sys_system_parameters_category` (`category`),
+ KEY `idx_sys_system_parameters_active` (`is_active`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统参数表';
+
+CREATE TABLE `hot_word_group` (
+ `id` INT NOT NULL AUTO_INCREMENT,
+ `name` VARCHAR(100) NOT NULL COMMENT '热词组名称',
+ `description` VARCHAR(500) DEFAULT NULL COMMENT '描述',
+ `vocabulary_id` VARCHAR(255) DEFAULT NULL COMMENT '阿里云词表ID',
+ `last_sync_time` DATETIME DEFAULT NULL COMMENT '最后同步时间',
+ `status` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '状态',
+ `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_hot_word_group_name` (`name`),
+ KEY `idx_hot_word_group_status` (`status`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='热词组主表';
+
+CREATE TABLE `llm_model_config` (
+ `config_id` BIGINT NOT NULL AUTO_INCREMENT,
+ `model_code` VARCHAR(128) NOT NULL COMMENT '模型编码',
+ `model_name` VARCHAR(255) NOT NULL COMMENT '模型名称',
+ `provider` VARCHAR(64) DEFAULT NULL COMMENT '供应商',
+ `endpoint_url` VARCHAR(512) DEFAULT NULL COMMENT '模型接口地址',
+ `api_key` VARCHAR(512) DEFAULT NULL COMMENT '接口密钥',
+ `llm_model_name` VARCHAR(128) NOT NULL COMMENT '供应商模型名',
+ `llm_timeout` INT NOT NULL DEFAULT 120 COMMENT '超时时间(秒)',
+ `llm_temperature` DECIMAL(5,2) NOT NULL DEFAULT 0.70 COMMENT 'temperature',
+ `llm_top_p` DECIMAL(5,2) NOT NULL DEFAULT 0.90 COMMENT 'top_p',
+ `llm_max_tokens` INT NOT NULL DEFAULT 2048 COMMENT '最大token数',
+ `llm_system_prompt` TEXT DEFAULT NULL COMMENT '系统提示词',
+ `description` VARCHAR(500) DEFAULT NULL COMMENT '说明',
+ `is_active` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+ `is_default` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否默认',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ PRIMARY KEY (`config_id`),
+ UNIQUE KEY `uk_llm_model_config_code` (`model_code`),
+ KEY `idx_llm_model_config_active` (`is_active`),
+ KEY `idx_llm_model_config_default` (`is_default`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='LLM模型配置表';
+
+CREATE TABLE `audio_model_config` (
+ `config_id` BIGINT NOT NULL AUTO_INCREMENT,
+ `model_code` VARCHAR(128) NOT NULL COMMENT '模型编码',
+ `model_name` VARCHAR(255) NOT NULL COMMENT '模型名称',
+ `audio_scene` VARCHAR(32) NOT NULL COMMENT 'asr / voiceprint',
+ `provider` VARCHAR(64) DEFAULT NULL COMMENT '供应商',
+ `endpoint_url` VARCHAR(512) DEFAULT NULL COMMENT '接口地址',
+ `api_key` VARCHAR(512) DEFAULT NULL COMMENT '接口密钥',
+ `request_timeout_seconds` INT NOT NULL DEFAULT 300 COMMENT '请求超时(秒)',
+ `hot_word_group_id` INT DEFAULT NULL COMMENT '关联热词组',
+ `extra_config` JSON DEFAULT NULL COMMENT '音频模型差异化配置',
+ `description` VARCHAR(500) DEFAULT NULL COMMENT '说明',
+ `is_active` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+ `is_default` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否默认',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ PRIMARY KEY (`config_id`),
+ UNIQUE KEY `uk_audio_model_config_code` (`model_code`),
+ KEY `idx_audio_model_config_scene` (`audio_scene`),
+ KEY `idx_audio_model_config_active` (`is_active`),
+ KEY `idx_audio_model_config_default` (`is_default`),
+ KEY `idx_audio_model_config_hot_word_group_id` (`hot_word_group_id`),
+ CONSTRAINT `fk_audio_model_config_hot_word_group_id`
+ FOREIGN KEY (`hot_word_group_id`) REFERENCES `hot_word_group` (`id`)
+ ON DELETE SET NULL ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='音频模型配置表';
+
+CREATE TABLE `hot_word_item` (
+ `id` INT NOT NULL AUTO_INCREMENT,
+ `group_id` INT NOT NULL COMMENT '热词组ID',
+ `text` VARCHAR(255) NOT NULL COMMENT '热词内容',
+ `weight` INT NOT NULL DEFAULT 4 COMMENT '权重',
+ `lang` VARCHAR(20) NOT NULL DEFAULT 'zh' COMMENT '语言',
+ `status` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '状态',
+ `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_hot_word_item_group_text` (`group_id`, `text`),
+ KEY `idx_hot_word_item_group_id` (`group_id`),
+ KEY `idx_hot_word_item_status` (`status`),
+ CONSTRAINT `fk_hot_word_item_group_id`
+ FOREIGN KEY (`group_id`) REFERENCES `hot_word_group` (`id`)
+ ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='热词条目表';
+
+CREATE TABLE `prompts` (
+ `id` INT NOT NULL AUTO_INCREMENT,
+ `name` VARCHAR(255) NOT NULL COMMENT '提示词名称',
+ `task_type` ENUM('MEETING_TASK', 'KNOWLEDGE_TASK') NOT NULL COMMENT '任务类型',
+ `content` LONGTEXT NOT NULL COMMENT '提示词内容',
+ `desc` VARCHAR(500) DEFAULT NULL COMMENT '模版简介',
+ `is_default` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否默认',
+ `is_active` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+ `creator_id` INT NOT NULL COMMENT '创建者',
+ `is_system` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否系统模版',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ PRIMARY KEY (`id`),
+ KEY `idx_prompts_creator_id` (`creator_id`),
+ KEY `idx_prompts_task_scope_active` (`task_type`, `is_system`, `creator_id`, `is_active`, `is_default`),
+ CONSTRAINT `fk_prompts_creator_id`
+ FOREIGN KEY (`creator_id`) REFERENCES `sys_users` (`user_id`)
+ ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='提示词模版表';
+
+CREATE TABLE `prompt_config` (
+ `config_id` BIGINT NOT NULL AUTO_INCREMENT,
+ `user_id` INT NOT NULL COMMENT '用户ID',
+ `task_type` ENUM('MEETING_TASK', 'KNOWLEDGE_TASK') NOT NULL COMMENT '任务类型',
+ `prompt_id` INT NOT NULL COMMENT '模版ID',
+ `is_enabled` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+ `sort_order` INT NOT NULL DEFAULT 0 COMMENT '排序',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ PRIMARY KEY (`config_id`),
+ UNIQUE KEY `uk_prompt_config_user_task_prompt` (`user_id`, `task_type`, `prompt_id`),
+ KEY `idx_prompt_config_user_task_order` (`user_id`, `task_type`, `sort_order`),
+ KEY `idx_prompt_config_prompt_id` (`prompt_id`),
+ CONSTRAINT `fk_prompt_config_user_id`
+ FOREIGN KEY (`user_id`) REFERENCES `sys_users` (`user_id`)
+ ON DELETE CASCADE ON UPDATE RESTRICT,
+ CONSTRAINT `fk_prompt_config_prompt_id`
+ FOREIGN KEY (`prompt_id`) REFERENCES `prompts` (`id`)
+ ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户提示词配置表';
+
+CREATE TABLE `sys_role_menu_permissions` (
+ `id` BIGINT NOT NULL AUTO_INCREMENT,
+ `role_id` INT NOT NULL COMMENT '角色ID',
+ `menu_id` INT NOT NULL COMMENT '菜单ID',
+ `granted_by` INT DEFAULT NULL COMMENT '授权人ID',
+ `granted_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '授权时间',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_sys_role_menu_permissions_role_menu` (`role_id`, `menu_id`),
+ KEY `idx_sys_role_menu_permissions_role_id` (`role_id`),
+ KEY `idx_sys_role_menu_permissions_menu_id` (`menu_id`),
+ KEY `idx_sys_role_menu_permissions_granted_by` (`granted_by`),
+ KEY `idx_sys_role_menu_permissions_granted_at` (`granted_at`),
+ CONSTRAINT `fk_sys_role_menu_permissions_role_id`
+ FOREIGN KEY (`role_id`) REFERENCES `sys_roles` (`role_id`)
+ ON DELETE CASCADE ON UPDATE RESTRICT,
+ CONSTRAINT `fk_sys_role_menu_permissions_menu_id`
+ FOREIGN KEY (`menu_id`) REFERENCES `sys_menus` (`menu_id`)
+ ON DELETE CASCADE ON UPDATE RESTRICT,
+ CONSTRAINT `fk_sys_role_menu_permissions_granted_by`
+ FOREIGN KEY (`granted_by`) REFERENCES `sys_users` (`user_id`)
+ ON DELETE SET NULL ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='角色菜单授权表';
+
+CREATE TABLE `sys_user_mcp` (
+ `id` INT NOT NULL AUTO_INCREMENT,
+ `user_id` INT NOT NULL COMMENT '用户ID',
+ `bot_id` VARCHAR(64) NOT NULL COMMENT '机器人ID',
+ `bot_secret` VARCHAR(128) NOT NULL COMMENT '机器人密钥',
+ `status` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '状态',
+ `last_used_at` DATETIME DEFAULT NULL COMMENT '最后使用时间',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_sys_user_mcp_user_id` (`user_id`),
+ UNIQUE KEY `uk_sys_user_mcp_bot_id` (`bot_id`),
+ KEY `idx_sys_user_mcp_status` (`status`),
+ CONSTRAINT `fk_sys_user_mcp_user_id`
+ FOREIGN KEY (`user_id`) REFERENCES `sys_users` (`user_id`)
+ ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户MCP接入凭证表';
+
+-- =====================================================================
+-- 2. 业务表
+-- =====================================================================
+CREATE TABLE `tags` (
+ `id` INT NOT NULL AUTO_INCREMENT,
+ `name` VARCHAR(255) NOT NULL COMMENT '标签名称',
+ `color` VARCHAR(7) NOT NULL DEFAULT '#409EFF' COMMENT '标签颜色',
+ `creator_id` INT DEFAULT NULL COMMENT '创建人',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_tags_name` (`name`),
+ KEY `idx_tags_creator_id` (`creator_id`),
+ CONSTRAINT `fk_tags_creator_id`
+ FOREIGN KEY (`creator_id`) REFERENCES `sys_users` (`user_id`)
+ ON DELETE SET NULL ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='标签表';
+
+CREATE TABLE `meetings` (
+ `meeting_id` INT NOT NULL AUTO_INCREMENT,
+ `user_id` INT NOT NULL COMMENT '创建人',
+ `title` VARCHAR(255) NOT NULL COMMENT '会议标题',
+ `tags` VARCHAR(255) DEFAULT NULL COMMENT '逗号分隔标签',
+ `meeting_time` DATETIME DEFAULT NULL COMMENT '会议时间',
+ `access_password` VARCHAR(32) DEFAULT NULL COMMENT '访问密码',
+ `prompt_id` INT DEFAULT 0 COMMENT '选用提示词ID,0表示未指定',
+ `user_prompt` TEXT DEFAULT NULL COMMENT '用户额外提示',
+ `summary` LONGTEXT DEFAULT NULL COMMENT '会议总结',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ PRIMARY KEY (`meeting_id`),
+ KEY `idx_meetings_user_id` (`user_id`),
+ KEY `idx_meetings_meeting_time` (`meeting_time`),
+ KEY `idx_meetings_created_at` (`created_at`),
+ KEY `idx_meetings_prompt_id` (`prompt_id`),
+ CONSTRAINT `fk_meetings_user_id`
+ FOREIGN KEY (`user_id`) REFERENCES `sys_users` (`user_id`)
+ ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='会议表';
+
+CREATE TABLE `attendees` (
+ `attendee_id` INT NOT NULL AUTO_INCREMENT,
+ `meeting_id` INT NOT NULL COMMENT '会议ID',
+ `user_id` INT NOT NULL COMMENT '参会用户ID',
+ PRIMARY KEY (`attendee_id`),
+ UNIQUE KEY `uk_attendees_meeting_user` (`meeting_id`, `user_id`),
+ KEY `idx_attendees_meeting_id` (`meeting_id`),
+ KEY `idx_attendees_user_id` (`user_id`),
+ CONSTRAINT `fk_attendees_meeting_id`
+ FOREIGN KEY (`meeting_id`) REFERENCES `meetings` (`meeting_id`)
+ ON DELETE CASCADE ON UPDATE RESTRICT,
+ CONSTRAINT `fk_attendees_user_id`
+ FOREIGN KEY (`user_id`) REFERENCES `sys_users` (`user_id`)
+ ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='会议参会人表';
+
+CREATE TABLE `attachments` (
+ `attachment_id` INT NOT NULL AUTO_INCREMENT,
+ `meeting_id` INT NOT NULL COMMENT '会议ID',
+ `file_name` VARCHAR(255) NOT NULL COMMENT '文件名',
+ `file_path` VARCHAR(512) NOT NULL COMMENT '文件路径',
+ `file_type` VARCHAR(100) DEFAULT NULL COMMENT '文件类型',
+ `uploaded_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '上传时间',
+ PRIMARY KEY (`attachment_id`),
+ KEY `idx_attachments_meeting_id` (`meeting_id`),
+ CONSTRAINT `fk_attachments_meeting_id`
+ FOREIGN KEY (`meeting_id`) REFERENCES `meetings` (`meeting_id`)
+ ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='会议附件表';
+
+CREATE TABLE `audio_files` (
+ `audio_id` INT NOT NULL AUTO_INCREMENT,
+ `meeting_id` INT NOT NULL COMMENT '会议ID',
+ `file_path` VARCHAR(512) NOT NULL COMMENT '音频相对路径',
+ `file_name` VARCHAR(255) DEFAULT NULL COMMENT '原始文件名',
+ `file_size` BIGINT DEFAULT NULL COMMENT '文件大小(字节)',
+ `duration` DECIMAL(10,2) DEFAULT NULL COMMENT '音频时长(秒)',
+ `upload_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '上传时间',
+ `processing_status` VARCHAR(20) NOT NULL DEFAULT 'uploaded' COMMENT '处理状态',
+ `error_message` TEXT DEFAULT NULL COMMENT '错误信息',
+ `task_id` VARCHAR(255) DEFAULT NULL COMMENT '最新转写任务ID',
+ PRIMARY KEY (`audio_id`),
+ UNIQUE KEY `uk_audio_files_meeting_id` (`meeting_id`),
+ KEY `idx_audio_files_task_id` (`task_id`),
+ KEY `idx_audio_files_processing_status` (`processing_status`),
+ CONSTRAINT `fk_audio_files_meeting_id`
+ FOREIGN KEY (`meeting_id`) REFERENCES `meetings` (`meeting_id`)
+ ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='会议音频表';
+
+CREATE TABLE `transcript_tasks` (
+ `task_id` VARCHAR(100) NOT NULL COMMENT '业务任务ID',
+ `paraformer_task_id` VARCHAR(100) DEFAULT NULL COMMENT '云端任务ID',
+ `meeting_id` INT NOT NULL COMMENT '会议ID',
+ `status` ENUM('pending', 'processing', 'completed', 'failed') NOT NULL DEFAULT 'pending' COMMENT '任务状态',
+ `progress` INT NOT NULL DEFAULT 0 COMMENT '任务进度',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `completed_at` DATETIME DEFAULT NULL COMMENT '完成时间',
+ `error_message` TEXT DEFAULT NULL COMMENT '错误信息',
+ PRIMARY KEY (`task_id`),
+ KEY `idx_transcript_tasks_meeting_id` (`meeting_id`),
+ KEY `idx_transcript_tasks_status` (`status`),
+ KEY `idx_transcript_tasks_created_at` (`created_at`),
+ KEY `idx_transcript_tasks_paraformer_task_id` (`paraformer_task_id`),
+ CONSTRAINT `fk_transcript_tasks_meeting_id`
+ FOREIGN KEY (`meeting_id`) REFERENCES `meetings` (`meeting_id`)
+ ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='转写任务表';
+
+CREATE TABLE `transcript_segments` (
+ `segment_id` BIGINT NOT NULL AUTO_INCREMENT,
+ `meeting_id` INT NOT NULL COMMENT '会议ID',
+ `speaker_id` INT NOT NULL DEFAULT 0 COMMENT '说话人编号',
+ `speaker_tag` VARCHAR(50) DEFAULT NULL COMMENT '说话人标签',
+ `start_time_ms` INT NOT NULL COMMENT '开始时间(毫秒)',
+ `end_time_ms` INT NOT NULL COMMENT '结束时间(毫秒)',
+ `text_content` LONGTEXT NOT NULL COMMENT '转写文本',
+ PRIMARY KEY (`segment_id`),
+ KEY `idx_transcript_segments_meeting_id` (`meeting_id`),
+ KEY `idx_transcript_segments_speaker_id` (`speaker_id`),
+ KEY `idx_transcript_segments_start_time_ms` (`start_time_ms`),
+ CONSTRAINT `fk_transcript_segments_meeting_id`
+ FOREIGN KEY (`meeting_id`) REFERENCES `meetings` (`meeting_id`)
+ ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='转写分段表';
+
+CREATE TABLE `llm_tasks` (
+ `task_id` VARCHAR(100) NOT NULL COMMENT '总结任务ID',
+ `meeting_id` INT NOT NULL COMMENT '会议ID',
+ `user_prompt` TEXT DEFAULT NULL COMMENT '用户额外提示',
+ `prompt_id` INT DEFAULT NULL COMMENT '使用的模版ID',
+ `model_code` VARCHAR(128) DEFAULT NULL COMMENT '使用的模型编码',
+ `status` ENUM('pending', 'processing', 'completed', 'failed') NOT NULL DEFAULT 'pending' COMMENT '任务状态',
+ `progress` INT NOT NULL DEFAULT 0 COMMENT '任务进度',
+ `result` LONGTEXT DEFAULT NULL COMMENT '总结结果',
+ `error_message` TEXT DEFAULT NULL COMMENT '错误信息',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `completed_at` DATETIME DEFAULT NULL COMMENT '完成时间',
+ PRIMARY KEY (`task_id`),
+ KEY `idx_llm_tasks_meeting_id` (`meeting_id`),
+ KEY `idx_llm_tasks_status` (`status`),
+ KEY `idx_llm_tasks_created_at` (`created_at`),
+ KEY `idx_llm_tasks_prompt_id` (`prompt_id`),
+ KEY `idx_llm_tasks_model_code` (`model_code`),
+ CONSTRAINT `fk_llm_tasks_meeting_id`
+ FOREIGN KEY (`meeting_id`) REFERENCES `meetings` (`meeting_id`)
+ ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='会议总结任务表';
+
+CREATE TABLE `knowledge_bases` (
+ `kb_id` INT NOT NULL AUTO_INCREMENT,
+ `title` VARCHAR(255) NOT NULL COMMENT '知识标题',
+ `prompt_id` INT DEFAULT 0 COMMENT '使用的模版ID',
+ `user_prompt` TEXT DEFAULT NULL COMMENT '用户额外提示',
+ `content` LONGTEXT DEFAULT NULL COMMENT '知识内容',
+ `creator_id` INT NOT NULL COMMENT '创建人',
+ `is_shared` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否共享',
+ `source_meeting_ids` VARCHAR(255) DEFAULT NULL COMMENT '来源会议ID列表',
+ `tags` VARCHAR(255) DEFAULT NULL COMMENT '标签',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ PRIMARY KEY (`kb_id`),
+ KEY `idx_knowledge_bases_creator_id` (`creator_id`),
+ KEY `idx_knowledge_bases_prompt_id` (`prompt_id`),
+ KEY `idx_knowledge_bases_updated_at` (`updated_at`),
+ KEY `idx_knowledge_bases_is_shared` (`is_shared`),
+ CONSTRAINT `fk_knowledge_bases_creator_id`
+ FOREIGN KEY (`creator_id`) REFERENCES `sys_users` (`user_id`)
+ ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='知识库表';
+
+CREATE TABLE `knowledge_base_tasks` (
+ `task_id` VARCHAR(100) NOT NULL COMMENT '知识库任务ID',
+ `user_id` INT NOT NULL COMMENT '发起人',
+ `kb_id` INT NOT NULL COMMENT '知识库ID',
+ `prompt_id` INT DEFAULT NULL COMMENT '使用的模版ID',
+ `user_prompt` TEXT DEFAULT NULL COMMENT '用户额外提示',
+ `status` ENUM('pending', 'processing', 'completed', 'failed') NOT NULL DEFAULT 'pending' COMMENT '任务状态',
+ `progress` INT NOT NULL DEFAULT 0 COMMENT '任务进度',
+ `error_message` TEXT DEFAULT NULL COMMENT '错误信息',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `completed_at` DATETIME DEFAULT NULL COMMENT '完成时间',
+ PRIMARY KEY (`task_id`),
+ KEY `idx_knowledge_base_tasks_user_id` (`user_id`),
+ KEY `idx_knowledge_base_tasks_kb_id` (`kb_id`),
+ KEY `idx_knowledge_base_tasks_status` (`status`),
+ KEY `idx_knowledge_base_tasks_created_at` (`created_at`),
+ CONSTRAINT `fk_knowledge_base_tasks_user_id`
+ FOREIGN KEY (`user_id`) REFERENCES `sys_users` (`user_id`)
+ ON DELETE CASCADE ON UPDATE RESTRICT,
+ CONSTRAINT `fk_knowledge_base_tasks_kb_id`
+ FOREIGN KEY (`kb_id`) REFERENCES `knowledge_bases` (`kb_id`)
+ ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='知识库生成任务表';
+
+CREATE TABLE `client_downloads` (
+ `id` BIGINT NOT NULL AUTO_INCREMENT,
+ `platform_type` VARCHAR(50) DEFAULT NULL COMMENT '平台类型(兼容字段)',
+ `platform_name` VARCHAR(50) DEFAULT NULL COMMENT '平台名称(兼容字段)',
+ `platform_code` VARCHAR(64) NOT NULL COMMENT '平台编码',
+ `version` VARCHAR(50) NOT NULL COMMENT '版本号',
+ `version_code` INT NOT NULL COMMENT '版本序号',
+ `download_url` VARCHAR(512) NOT NULL COMMENT '下载地址',
+ `file_size` BIGINT DEFAULT NULL COMMENT '文件大小',
+ `release_notes` TEXT DEFAULT NULL COMMENT '更新说明',
+ `is_active` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+ `is_latest` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否最新',
+ `min_system_version` VARCHAR(50) DEFAULT NULL COMMENT '最低系统版本',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `created_by` INT DEFAULT NULL COMMENT '创建人',
+ PRIMARY KEY (`id`),
+ KEY `idx_client_downloads_platform_code` (`platform_code`),
+ KEY `idx_client_downloads_platform_type_name` (`platform_type`, `platform_name`),
+ KEY `idx_client_downloads_is_latest` (`is_latest`),
+ KEY `idx_client_downloads_is_active` (`is_active`),
+ KEY `idx_client_downloads_platform_code_version` (`platform_code`, `version_code`),
+ CONSTRAINT `fk_client_downloads_created_by`
+ FOREIGN KEY (`created_by`) REFERENCES `sys_users` (`user_id`)
+ ON DELETE SET NULL ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='客户端下载管理表';
+
+CREATE TABLE `external_apps` (
+ `id` INT NOT NULL AUTO_INCREMENT,
+ `app_name` VARCHAR(100) NOT NULL COMMENT '应用名称',
+ `app_type` ENUM('native', 'web') NOT NULL COMMENT '应用类型',
+ `app_info` TEXT DEFAULT NULL COMMENT '应用信息(JSON字符串)',
+ `icon_url` TEXT DEFAULT NULL COMMENT '图标地址',
+ `description` TEXT DEFAULT NULL COMMENT '应用说明',
+ `sort_order` INT NOT NULL DEFAULT 0 COMMENT '排序',
+ `is_active` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `created_by` INT DEFAULT NULL COMMENT '创建人',
+ PRIMARY KEY (`id`),
+ KEY `idx_external_apps_type` (`app_type`),
+ KEY `idx_external_apps_active` (`is_active`),
+ KEY `idx_external_apps_sort_order` (`sort_order`),
+ KEY `idx_external_apps_type_active` (`app_type`, `is_active`),
+ CONSTRAINT `fk_external_apps_created_by`
+ FOREIGN KEY (`created_by`) REFERENCES `sys_users` (`user_id`)
+ ON DELETE SET NULL ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='外部应用管理表';
+
+CREATE TABLE `terminals` (
+ `id` INT NOT NULL AUTO_INCREMENT,
+ `imei` VARCHAR(64) NOT NULL COMMENT '终端唯一标识',
+ `terminal_name` VARCHAR(100) DEFAULT NULL COMMENT '终端名称',
+ `terminal_type` VARCHAR(50) NOT NULL COMMENT '终端类型编码',
+ `description` VARCHAR(500) DEFAULT NULL COMMENT '说明',
+ `status` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '启用状态',
+ `is_activated` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '激活状态',
+ `activated_at` DATETIME DEFAULT NULL COMMENT '激活时间',
+ `firmware_version` VARCHAR(50) DEFAULT NULL COMMENT '固件版本',
+ `last_online_at` DATETIME DEFAULT NULL COMMENT '最后在线时间',
+ `ip_address` VARCHAR(50) DEFAULT NULL COMMENT '最近在线IP',
+ `mac_address` VARCHAR(64) DEFAULT NULL COMMENT 'MAC地址',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `created_by` INT DEFAULT NULL COMMENT '创建人',
+ `current_user_id` INT DEFAULT NULL COMMENT '当前绑定用户',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_terminals_imei` (`imei`),
+ KEY `idx_terminals_terminal_type` (`terminal_type`),
+ KEY `idx_terminals_status` (`status`),
+ KEY `idx_terminals_created_by` (`created_by`),
+ KEY `idx_terminals_current_user_id` (`current_user_id`),
+ KEY `idx_terminals_last_online_at` (`last_online_at`),
+ CONSTRAINT `fk_terminals_created_by`
+ FOREIGN KEY (`created_by`) REFERENCES `sys_users` (`user_id`)
+ ON DELETE SET NULL ON UPDATE RESTRICT,
+ CONSTRAINT `fk_terminals_current_user_id`
+ FOREIGN KEY (`current_user_id`) REFERENCES `sys_users` (`user_id`)
+ ON DELETE SET NULL ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='专用终端设备表';
+
+CREATE TABLE `user_logs` (
+ `log_id` BIGINT NOT NULL AUTO_INCREMENT,
+ `user_id` INT NOT NULL COMMENT '用户ID',
+ `action_type` VARCHAR(50) NOT NULL COMMENT '行为类型',
+ `ip_address` VARCHAR(50) DEFAULT NULL COMMENT 'IP地址',
+ `user_agent` TEXT DEFAULT NULL COMMENT 'User-Agent',
+ `metadata` LONGTEXT DEFAULT NULL COMMENT '扩展元数据(JSON字符串)',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ PRIMARY KEY (`log_id`),
+ KEY `idx_user_logs_user_id` (`user_id`),
+ KEY `idx_user_logs_action_type` (`action_type`),
+ KEY `idx_user_logs_created_at` (`created_at`),
+ KEY `idx_user_logs_user_action` (`user_id`, `action_type`),
+ CONSTRAINT `fk_user_logs_user_id`
+ FOREIGN KEY (`user_id`) REFERENCES `sys_users` (`user_id`)
+ ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户行为日志表';
+
+CREATE TABLE `user_voiceprint` (
+ `vp_id` INT NOT NULL AUTO_INCREMENT,
+ `user_id` INT NOT NULL COMMENT '用户ID',
+ `file_path` VARCHAR(255) NOT NULL COMMENT '声纹文件路径',
+ `file_size` BIGINT DEFAULT NULL COMMENT '文件大小',
+ `duration_seconds` DECIMAL(5,2) DEFAULT 10.00 COMMENT '音频时长',
+ `vector_data` LONGTEXT DEFAULT NULL COMMENT '声纹向量(JSON字符串)',
+ `collected_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '采集时间',
+ `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ PRIMARY KEY (`vp_id`),
+ UNIQUE KEY `uk_user_voiceprint_user_id` (`user_id`),
+ KEY `idx_user_voiceprint_collected_at` (`collected_at`),
+ CONSTRAINT `fk_user_voiceprint_user_id`
+ FOREIGN KEY (`user_id`) REFERENCES `sys_users` (`user_id`)
+ ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户声纹表';
+
+SELECT 'imeeting-schema-latest.sql executed successfully' AS `message`;
diff --git a/backend/sql/imeeting-seed-latest.sql b/backend/sql/imeeting-seed-latest.sql
new file mode 100644
index 0000000..54a4889
--- /dev/null
+++ b/backend/sql/imeeting-seed-latest.sql
@@ -0,0 +1,800 @@
+-- iMeeting latest seed initialization script
+-- 用途:
+-- 1. 面向“已执行最新全量建表脚本”的全新部署
+-- 2. 仅初始化系统基础数据,不包含历史会议、附件、任务、知识库等业务数据
+-- 3. 尽量支持重复执行(幂等),便于新库初始化或回放
+--
+-- 重要前提:
+-- 1. 已先执行 imeeting-schema-latest.sql
+-- 2. 当前库已存在以下最新结构:
+-- sys_roles / sys_users / sys_menus / sys_role_menu_permissions
+-- prompts(desc,is_system) / prompt_config
+-- sys_system_parameters / llm_model_config / audio_model_config
+-- hot_word_group / hot_word_item / sys_dict_data
+--
+-- 默认账号:
+-- admin / admin123
+-- demo / 123456
+--
+-- 说明:
+-- 1. 模型 API Key 默认留空,优先走环境变量配置
+-- 2. ASR 默认绑定“默认热词组”,首次执行后仍可在后台继续同步词表
+
+SET NAMES utf8mb4;
+
+START TRANSACTION;
+
+-- =====================================================================
+-- 1. 基础角色
+-- =====================================================================
+INSERT INTO `sys_roles` (`role_id`, `role_name`, `created_at`)
+VALUES
+ (1, '平台管理员', NOW()),
+ (2, '普通用户', NOW())
+ON DUPLICATE KEY UPDATE
+ `role_name` = VALUES(`role_name`);
+
+-- =====================================================================
+-- 2. 基础用户
+-- 密码说明:
+-- admin -> admin123
+-- demo -> 123456
+-- =====================================================================
+INSERT INTO `sys_users`
+(`user_id`, `username`, `caption`, `email`, `avatar_url`, `password_hash`, `role_id`, `created_at`)
+VALUES
+ (1, 'admin', '系统管理员', 'admin@imeeting.local', NULL, '240be518fabd2724ddb6f04eeb1da5967448d7e831c08c8fa822809f74c720a9', 1, NOW()),
+ (2, 'demo', '演示用户', 'demo@imeeting.local', NULL, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', 2, NOW())
+ON DUPLICATE KEY UPDATE
+ `username` = VALUES(`username`),
+ `caption` = VALUES(`caption`),
+ `email` = VALUES(`email`),
+ `avatar_url` = VALUES(`avatar_url`),
+ `password_hash` = VALUES(`password_hash`),
+ `role_id` = VALUES(`role_id`);
+
+-- =====================================================================
+-- 3. 系统默认提示词模版
+-- =====================================================================
+INSERT INTO `prompts`
+(`id`, `name`, `task_type`, `content`, `desc`, `is_default`, `is_active`, `creator_id`, `is_system`, `created_at`)
+VALUES
+ (
+ 1,
+ '系统默认会议总结',
+ 'MEETING_TASK',
+ '你是一名专业的会议纪要助手。请基于会议转写内容输出结构化 Markdown,总结以下内容:
+
+## 会议概览
+- 说明会议主题、时间、参与方、目标
+
+## 核心讨论
+- 按议题归纳讨论重点,不按逐句流水账整理
+
+## 决策事项
+- 明确已经形成共识的决定、口径与结论
+
+## 待办事项
+- 使用表格列出事项、责任人、时间要求、当前状态
+
+## 风险与建议
+- 提醒未决问题、依赖项、潜在风险,并给出后续建议
+
+输出要求:
+1. 仅基于原文,不臆测未提及内容
+2. 信息缺失时明确标注“未提及”
+3. 语言简洁、可直接归档共享',
+ '会议转写默认总结模板',
+ 1,
+ 1,
+ 1,
+ 1,
+ NOW()
+ ),
+ (
+ 2,
+ '系统默认知识整理',
+ 'KNOWLEDGE_TASK',
+ '你是一名专业的知识整理助手。请基于输入材料生成一篇适合归档到知识库的 Markdown 文档,包含以下部分:
+
+## 标题
+- 产出准确、可检索的标题
+
+## 摘要
+- 用 3 至 5 句话概括核心内容
+
+## 关键事实
+- 提炼重要信息、规则、约束和背景
+
+## 操作步骤或处理方案
+- 如果材料中包含流程或做法,请按步骤梳理
+
+## 风险与注意事项
+- 标记边界条件、限制项和容易出错的点
+
+## 相关名词与标签
+- 提炼适合检索和分类的关键词
+
+输出要求:
+1. 保持事实准确,避免编造
+2. 优先结构化、可复用、可沉淀
+3. 文风专业、简洁、便于知识检索',
+ '知识库整理默认模板',
+ 1,
+ 1,
+ 1,
+ 1,
+ NOW()
+ )
+ON DUPLICATE KEY UPDATE
+ `name` = VALUES(`name`),
+ `task_type` = VALUES(`task_type`),
+ `content` = VALUES(`content`),
+ `desc` = VALUES(`desc`),
+ `is_default` = VALUES(`is_default`),
+ `is_active` = VALUES(`is_active`),
+ `creator_id` = VALUES(`creator_id`),
+ `is_system` = VALUES(`is_system`);
+
+-- 为初始化账号补充默认模版启用配置
+INSERT INTO `prompt_config`
+(`user_id`, `task_type`, `prompt_id`, `is_enabled`, `sort_order`, `created_at`, `updated_at`)
+VALUES
+ (1, 'MEETING_TASK', 1, 1, 1, NOW(), NOW()),
+ (1, 'KNOWLEDGE_TASK', 2, 1, 1, NOW(), NOW()),
+ (2, 'MEETING_TASK', 1, 1, 1, NOW(), NOW()),
+ (2, 'KNOWLEDGE_TASK', 2, 1, 1, NOW(), NOW())
+ON DUPLICATE KEY UPDATE
+ `is_enabled` = VALUES(`is_enabled`),
+ `sort_order` = VALUES(`sort_order`),
+ `updated_at` = VALUES(`updated_at`);
+
+-- =====================================================================
+-- 4. 系统参数
+-- =====================================================================
+INSERT INTO `sys_system_parameters`
+(`param_key`, `param_name`, `param_value`, `value_type`, `category`, `description`, `is_active`, `created_at`, `updated_at`)
+VALUES
+ ('token_expire_days', 'Token过期时间', '7', 'number', 'system', '控制登录 token 的过期时间,单位:天。', 1, NOW(), NOW()),
+ ('default_reset_password', '默认重置密码', '123456', 'string', 'system', '管理员重置用户密码时使用的默认密码。', 1, NOW(), NOW()),
+ ('page_size', '系统分页大小', '10', 'number', 'public', '系统通用分页数量。', 1, NOW(), NOW()),
+ ('max_audio_size', '音频上传大小限制', '100', 'number', 'public', '音频上传大小限制,单位:MB。', 1, NOW(), NOW()),
+ ('max_image_size', '图片上传大小限制', '10', 'number', 'public', '图片上传大小限制,单位:MB。', 1, NOW(), NOW()),
+ ('app_name', '系统名称', 'iMeeting', 'string', 'public', '前端应用标题。', 1, NOW(), NOW()),
+ ('console_subtitle', '控制台副标题', '智能会议协作平台', 'string', 'public', '登录后控制台副标题。', 1, NOW(), NOW()),
+ ('preview_title', '会议预览标题', '会议预览', 'string', 'public', '会议预览页标题。', 1, NOW(), NOW()),
+ ('login_welcome', '登录欢迎语', '欢迎登录 iMeeting,请输入您的账号信息。', 'string', 'public', '登录页欢迎语。', 1, NOW(), NOW()),
+ ('footer_text', '页脚文案', '©2026 iMeeting', 'string', 'public', '系统页脚文案。', 1, NOW(), NOW())
+ON DUPLICATE KEY UPDATE
+ `param_name` = VALUES(`param_name`),
+ `param_value` = VALUES(`param_value`),
+ `value_type` = VALUES(`value_type`),
+ `category` = VALUES(`category`),
+ `description` = VALUES(`description`),
+ `is_active` = VALUES(`is_active`),
+ `updated_at` = VALUES(`updated_at`);
+
+-- =====================================================================
+-- 5. 默认热词组与热词
+-- =====================================================================
+INSERT INTO `hot_word_group` (`name`, `description`, `status`, `create_time`, `update_time`)
+SELECT '默认热词组', '系统初始化热词组,供默认 ASR 模型绑定使用。', 1, NOW(), NOW()
+FROM DUAL
+WHERE NOT EXISTS (
+ SELECT 1 FROM `hot_word_group` WHERE `name` = '默认热词组'
+);
+
+UPDATE `hot_word_group`
+SET
+ `description` = '系统初始化热词组,供默认 ASR 模型绑定使用。',
+ `status` = 1,
+ `update_time` = NOW()
+WHERE `name` = '默认热词组';
+
+SET @default_hot_word_group_id := (
+ SELECT `id`
+ FROM `hot_word_group`
+ WHERE `name` = '默认热词组'
+ ORDER BY `id`
+ LIMIT 1
+);
+
+INSERT INTO `hot_word_item`
+(`group_id`, `text`, `weight`, `lang`, `status`, `create_time`, `update_time`)
+SELECT @default_hot_word_group_id, 'iMeeting', 8, 'zh', 1, NOW(), NOW()
+FROM DUAL
+WHERE @default_hot_word_group_id IS NOT NULL
+ON DUPLICATE KEY UPDATE
+ `weight` = VALUES(`weight`),
+ `lang` = VALUES(`lang`),
+ `status` = VALUES(`status`),
+ `update_time` = VALUES(`update_time`);
+
+INSERT INTO `hot_word_item`
+(`group_id`, `text`, `weight`, `lang`, `status`, `create_time`, `update_time`)
+SELECT @default_hot_word_group_id, '会议纪要', 7, 'zh', 1, NOW(), NOW()
+FROM DUAL
+WHERE @default_hot_word_group_id IS NOT NULL
+ON DUPLICATE KEY UPDATE
+ `weight` = VALUES(`weight`),
+ `lang` = VALUES(`lang`),
+ `status` = VALUES(`status`),
+ `update_time` = VALUES(`update_time`);
+
+INSERT INTO `hot_word_item`
+(`group_id`, `text`, `weight`, `lang`, `status`, `create_time`, `update_time`)
+SELECT @default_hot_word_group_id, '语音转写', 6, 'zh', 1, NOW(), NOW()
+FROM DUAL
+WHERE @default_hot_word_group_id IS NOT NULL
+ON DUPLICATE KEY UPDATE
+ `weight` = VALUES(`weight`),
+ `lang` = VALUES(`lang`),
+ `status` = VALUES(`status`),
+ `update_time` = VALUES(`update_time`);
+
+-- =====================================================================
+-- 6. 默认模型配置
+-- =====================================================================
+INSERT INTO `llm_model_config`
+(`model_code`, `model_name`, `provider`, `endpoint_url`, `api_key`, `llm_model_name`,
+ `llm_timeout`, `llm_temperature`, `llm_top_p`, `llm_max_tokens`, `llm_system_prompt`,
+ `description`, `is_active`, `is_default`, `created_at`, `updated_at`)
+VALUES
+ (
+ 'llm_model',
+ '默认文本模型',
+ 'dashscope',
+ 'https://dashscope.aliyuncs.com/compatible-mode/v1',
+ NULL,
+ 'qwen-plus',
+ 120,
+ 0.70,
+ 0.90,
+ 2048,
+ '你是一名专业的会议与知识整理助手,请基于输入内容给出准确、结构化、可复用的输出。',
+ '系统初始化的默认 LLM 模型配置,API Key 优先使用环境变量。',
+ 1,
+ 1,
+ NOW(),
+ NOW()
+ )
+ON DUPLICATE KEY UPDATE
+ `model_name` = VALUES(`model_name`),
+ `provider` = VALUES(`provider`),
+ `endpoint_url` = VALUES(`endpoint_url`),
+ `api_key` = VALUES(`api_key`),
+ `llm_model_name` = VALUES(`llm_model_name`),
+ `llm_timeout` = VALUES(`llm_timeout`),
+ `llm_temperature` = VALUES(`llm_temperature`),
+ `llm_top_p` = VALUES(`llm_top_p`),
+ `llm_max_tokens` = VALUES(`llm_max_tokens`),
+ `llm_system_prompt` = VALUES(`llm_system_prompt`),
+ `description` = VALUES(`description`),
+ `is_active` = VALUES(`is_active`),
+ `is_default` = VALUES(`is_default`),
+ `updated_at` = VALUES(`updated_at`);
+
+INSERT INTO `audio_model_config`
+(`model_code`, `model_name`, `audio_scene`, `provider`, `endpoint_url`, `api_key`,
+ `request_timeout_seconds`, `hot_word_group_id`, `extra_config`, `description`,
+ `is_active`, `is_default`, `created_at`, `updated_at`)
+SELECT
+ 'audio_model',
+ '默认语音识别模型',
+ 'asr',
+ 'dashscope',
+ 'https://dashscope.aliyuncs.com',
+ NULL,
+ 300,
+ g.`id`,
+ JSON_OBJECT(
+ 'model', 'paraformer-v2',
+ 'vocabulary_id', g.`vocabulary_id`,
+ 'speaker_count', 10,
+ 'language_hints', JSON_ARRAY('zh', 'en'),
+ 'disfluency_removal_enabled', TRUE,
+ 'diarization_enabled', TRUE
+ ),
+ '系统初始化的默认 ASR 模型配置。',
+ 1,
+ 1,
+ NOW(),
+ NOW()
+FROM `hot_word_group` g
+WHERE g.`id` = @default_hot_word_group_id
+ON DUPLICATE KEY UPDATE
+ `model_name` = VALUES(`model_name`),
+ `audio_scene` = VALUES(`audio_scene`),
+ `provider` = VALUES(`provider`),
+ `endpoint_url` = VALUES(`endpoint_url`),
+ `api_key` = VALUES(`api_key`),
+ `request_timeout_seconds` = VALUES(`request_timeout_seconds`),
+ `hot_word_group_id` = VALUES(`hot_word_group_id`),
+ `extra_config` = VALUES(`extra_config`),
+ `description` = VALUES(`description`),
+ `is_active` = VALUES(`is_active`),
+ `is_default` = VALUES(`is_default`),
+ `updated_at` = VALUES(`updated_at`);
+
+INSERT INTO `audio_model_config`
+(`model_code`, `model_name`, `audio_scene`, `provider`, `endpoint_url`, `api_key`,
+ `request_timeout_seconds`, `hot_word_group_id`, `extra_config`, `description`,
+ `is_active`, `is_default`, `created_at`, `updated_at`)
+VALUES
+ (
+ 'voiceprint_model',
+ '默认声纹配置',
+ 'voiceprint',
+ 'funasr',
+ NULL,
+ NULL,
+ 120,
+ NULL,
+ JSON_OBJECT(
+ 'template_text', '我正在进行声纹采集,这段语音将用于身份识别和验证。声纹技术能够准确识别每个人独特的声音特征。',
+ 'duration_seconds', 12,
+ 'sample_rate', 16000,
+ 'channels', 1,
+ 'max_size_bytes', 5242880
+ ),
+ '系统初始化的默认声纹采集配置。',
+ 1,
+ 1,
+ NOW(),
+ NOW()
+ )
+ON DUPLICATE KEY UPDATE
+ `model_name` = VALUES(`model_name`),
+ `audio_scene` = VALUES(`audio_scene`),
+ `provider` = VALUES(`provider`),
+ `endpoint_url` = VALUES(`endpoint_url`),
+ `api_key` = VALUES(`api_key`),
+ `request_timeout_seconds` = VALUES(`request_timeout_seconds`),
+ `hot_word_group_id` = VALUES(`hot_word_group_id`),
+ `extra_config` = VALUES(`extra_config`),
+ `description` = VALUES(`description`),
+ `is_active` = VALUES(`is_active`),
+ `is_default` = VALUES(`is_default`),
+ `updated_at` = VALUES(`updated_at`);
+
+-- =====================================================================
+-- 7. 基础字典数据
+-- =====================================================================
+INSERT INTO `sys_dict_data`
+(`dict_type`, `dict_code`, `parent_code`, `tree_path`, `label_cn`, `label_en`, `sort_order`,
+ `extension_attr`, `is_default`, `status`, `create_time`, `update_time`)
+VALUES
+ ('client_platform', 'DESKTOP', 'ROOT', NULL, '桌面端', 'Desktop', 1, JSON_OBJECT('icon', 'monitor'), 0, 1, NOW(), NOW()),
+ ('client_platform', 'MOBILE', 'ROOT', NULL, '移动端', 'Mobile', 2, JSON_OBJECT('icon', 'phone'), 0, 1, NOW(), NOW()),
+ ('client_platform', 'TERMINAL', 'ROOT', NULL, '专用终端', 'Terminal', 3, JSON_OBJECT('icon', 'router'), 0, 1, NOW(), NOW()),
+ ('client_platform', 'WIN', 'DESKTOP', NULL, 'Windows', 'Windows', 1, JSON_OBJECT('suffix', '.exe', 'arch_support', JSON_ARRAY('x86', 'x64')), 0, 1, NOW(), NOW()),
+ ('client_platform', 'MAC', 'DESKTOP', NULL, 'macOS', 'macOS', 2, JSON_OBJECT('suffix', '.dmg', 'arch_support', JSON_ARRAY('x64', 'arm64')), 0, 1, NOW(), NOW()),
+ ('client_platform', 'LINUX', 'DESKTOP', NULL, 'Linux', 'Linux', 3, JSON_OBJECT('suffix', '.deb', 'arch_support', JSON_ARRAY('x64', 'arm64')), 0, 1, NOW(), NOW()),
+ ('client_platform', 'IOS', 'MOBILE', NULL, '苹果iOS', 'iOS', 1, JSON_OBJECT('suffix', '.ipa', 'store_link', TRUE), 0, 1, NOW(), NOW()),
+ ('client_platform', 'ANDROID', 'MOBILE', NULL, '安卓', 'Android', 2, JSON_OBJECT('suffix', '.apk'), 0, 1, NOW(), NOW()),
+ ('client_platform', 'TERM_STD', 'TERMINAL', NULL, '通用终端', 'Standard Terminal', 1, JSON_OBJECT('vendor', 'Generic', 'os', 'Android'), 1, 1, NOW(), NOW()),
+ ('client_platform', 'TERM_S100','TERMINAL', NULL, '中兴 S100', 'ZTE S100', 2, JSON_OBJECT('vendor', 'ZTE', 'os', 'Android'), 0, 1, NOW(), NOW()),
+ ('client_platform', 'TERM_A133','TERMINAL', NULL, '全志 A133', 'Allwinner A133', 3, JSON_OBJECT('vendor', 'Allwinner', 'os', 'Android'), 0, 1, NOW(), NOW()),
+
+ ('terminal_type', 'TERM_STD', 'ROOT', NULL, '通用终端', 'Standard Terminal', 1, NULL, 1, 1, NOW(), NOW()),
+ ('terminal_type', 'TERM_S100','ROOT', NULL, '中兴 S100', 'ZTE S100', 2, NULL, 0, 1, NOW(), NOW()),
+ ('terminal_type', 'TERM_A133','ROOT', NULL, '全志 A133', 'Allwinner A133', 3, NULL, 0, 1, NOW(), NOW()),
+
+ ('task_type', 'MEETING_TASK', 'ROOT', NULL, '会议任务', 'Meeting Task', 1, NULL, 0, 1, NOW(), NOW()),
+ ('task_type', 'KNOWLEDGE_TASK', 'ROOT', NULL, '知识库任务', 'Knowledge Task', 2, NULL, 0, 1, NOW(), NOW()),
+
+ ('external_apps', 'NATIVE', 'ROOT', NULL, '原生应用', 'Native App', 1, JSON_OBJECT('protocol', 'apk'), 0, 1, NOW(), NOW()),
+ ('external_apps', 'WEB', 'ROOT', NULL, 'Web应用', 'Web App', 2, JSON_OBJECT('protocol', 'https'), 0, 1, NOW(), NOW())
+ON DUPLICATE KEY UPDATE
+ `parent_code` = VALUES(`parent_code`),
+ `tree_path` = VALUES(`tree_path`),
+ `label_cn` = VALUES(`label_cn`),
+ `label_en` = VALUES(`label_en`),
+ `sort_order` = VALUES(`sort_order`),
+ `extension_attr` = VALUES(`extension_attr`),
+ `is_default` = VALUES(`is_default`),
+ `status` = VALUES(`status`),
+ `update_time` = VALUES(`update_time`);
+
+-- =====================================================================
+-- 8. 菜单定义
+-- 最终菜单树:
+-- dashboard
+-- desktop
+-- meeting_manage
+-- ├─ meeting_center
+-- └─ prompt_config
+-- platform_admin
+-- ├─ hot_word_management
+-- ├─ model_management
+-- ├─ prompt_management
+-- ├─ client_management
+-- ├─ external_app_management
+-- └─ terminal_management
+-- system_management
+-- ├─ user_management
+-- ├─ permission_management
+-- │ └─ permission_menu_tree (隐藏)
+-- ├─ dict_management
+-- └─ parameter_management
+-- =====================================================================
+INSERT INTO `sys_menus`
+(`menu_code`, `menu_name`, `menu_icon`, `menu_url`, `menu_type`, `parent_id`, `menu_level`, `tree_path`,
+ `sort_order`, `is_active`, `is_visible`, `description`, `created_at`, `updated_at`)
+VALUES
+ ('dashboard', 'Dashboard', 'DashboardOutlined', '/dashboard', 'link', NULL, 1, NULL, 1, 1, 1, '管理员桌面', NOW(), NOW()),
+ ('desktop', 'Desktop', 'DesktopOutlined', '/dashboard', 'link', NULL, 1, NULL, 2, 1, 1, '普通用户桌面', NOW(), NOW()),
+ ('meeting_manage', '会议管理', 'CalendarOutlined', '/meetings/center', 'link', NULL, 1, NULL, 3, 1, 1, '普通用户会议功能入口', NOW(), NOW()),
+ ('platform_admin', '平台管理', 'Shield', '/admin/management/hot-word-management', 'link', NULL, 1, NULL, 4, 1, 1, '平台能力配置入口', NOW(), NOW()),
+ ('system_management', '系统管理', 'Setting', '/admin/management/system-overview', 'link', NULL, 1, NULL, 5, 1, 1, '系统治理入口', NOW(), NOW())
+ON DUPLICATE KEY UPDATE
+ `menu_name` = VALUES(`menu_name`),
+ `menu_icon` = VALUES(`menu_icon`),
+ `menu_url` = VALUES(`menu_url`),
+ `menu_type` = VALUES(`menu_type`),
+ `parent_id` = VALUES(`parent_id`),
+ `menu_level` = VALUES(`menu_level`),
+ `sort_order` = VALUES(`sort_order`),
+ `is_active` = VALUES(`is_active`),
+ `is_visible` = VALUES(`is_visible`),
+ `description` = VALUES(`description`),
+ `updated_at` = VALUES(`updated_at`);
+
+SET @meeting_manage_id := (SELECT `menu_id` FROM `sys_menus` WHERE `menu_code` = 'meeting_manage' LIMIT 1);
+SET @platform_admin_id := (SELECT `menu_id` FROM `sys_menus` WHERE `menu_code` = 'platform_admin' LIMIT 1);
+SET @system_management_id := (SELECT `menu_id` FROM `sys_menus` WHERE `menu_code` = 'system_management' LIMIT 1);
+
+INSERT INTO `sys_menus`
+(`menu_code`, `menu_name`, `menu_icon`, `menu_url`, `menu_type`, `parent_id`, `menu_level`, `tree_path`,
+ `sort_order`, `is_active`, `is_visible`, `description`, `created_at`, `updated_at`)
+SELECT
+ 'meeting_center', '会议中心', 'CalendarOutlined', '/meetings/center', 'link',
+ @meeting_manage_id, 2, NULL, 1, 1, 1, '普通用户会议中心', NOW(), NOW()
+FROM DUAL
+WHERE @meeting_manage_id IS NOT NULL
+ON DUPLICATE KEY UPDATE
+ `menu_name` = VALUES(`menu_name`),
+ `menu_icon` = VALUES(`menu_icon`),
+ `menu_url` = VALUES(`menu_url`),
+ `menu_type` = VALUES(`menu_type`),
+ `parent_id` = VALUES(`parent_id`),
+ `menu_level` = VALUES(`menu_level`),
+ `sort_order` = VALUES(`sort_order`),
+ `is_active` = VALUES(`is_active`),
+ `is_visible` = VALUES(`is_visible`),
+ `description` = VALUES(`description`),
+ `updated_at` = VALUES(`updated_at`);
+
+INSERT INTO `sys_menus`
+(`menu_code`, `menu_name`, `menu_icon`, `menu_url`, `menu_type`, `parent_id`, `menu_level`, `tree_path`,
+ `sort_order`, `is_active`, `is_visible`, `description`, `created_at`, `updated_at`)
+SELECT
+ 'prompt_config', '提示词配置', 'Book', '/prompt-config', 'link',
+ @meeting_manage_id, 2, NULL, 2, 1, 1, '用户提示词启用与排序配置', NOW(), NOW()
+FROM DUAL
+WHERE @meeting_manage_id IS NOT NULL
+ON DUPLICATE KEY UPDATE
+ `menu_name` = VALUES(`menu_name`),
+ `menu_icon` = VALUES(`menu_icon`),
+ `menu_url` = VALUES(`menu_url`),
+ `menu_type` = VALUES(`menu_type`),
+ `parent_id` = VALUES(`parent_id`),
+ `menu_level` = VALUES(`menu_level`),
+ `sort_order` = VALUES(`sort_order`),
+ `is_active` = VALUES(`is_active`),
+ `is_visible` = VALUES(`is_visible`),
+ `description` = VALUES(`description`),
+ `updated_at` = VALUES(`updated_at`);
+
+INSERT INTO `sys_menus`
+(`menu_code`, `menu_name`, `menu_icon`, `menu_url`, `menu_type`, `parent_id`, `menu_level`, `tree_path`,
+ `sort_order`, `is_active`, `is_visible`, `description`, `created_at`, `updated_at`)
+SELECT
+ 'hot_word_management', '热词管理', 'Text', '/admin/management/hot-word-management', 'link',
+ @platform_admin_id, 2, NULL, 1, 1, 1, 'ASR 热词管理与同步', NOW(), NOW()
+FROM DUAL
+WHERE @platform_admin_id IS NOT NULL
+ON DUPLICATE KEY UPDATE
+ `menu_name` = VALUES(`menu_name`),
+ `menu_icon` = VALUES(`menu_icon`),
+ `menu_url` = VALUES(`menu_url`),
+ `menu_type` = VALUES(`menu_type`),
+ `parent_id` = VALUES(`parent_id`),
+ `menu_level` = VALUES(`menu_level`),
+ `sort_order` = VALUES(`sort_order`),
+ `is_active` = VALUES(`is_active`),
+ `is_visible` = VALUES(`is_visible`),
+ `description` = VALUES(`description`),
+ `updated_at` = VALUES(`updated_at`);
+
+INSERT INTO `sys_menus`
+(`menu_code`, `menu_name`, `menu_icon`, `menu_url`, `menu_type`, `parent_id`, `menu_level`, `tree_path`,
+ `sort_order`, `is_active`, `is_visible`, `description`, `created_at`, `updated_at`)
+SELECT
+ 'model_management', '模型管理', 'Appstore', '/admin/management/model-management', 'link',
+ @platform_admin_id, 2, NULL, 2, 1, 1, '音频模型与 LLM 模型配置', NOW(), NOW()
+FROM DUAL
+WHERE @platform_admin_id IS NOT NULL
+ON DUPLICATE KEY UPDATE
+ `menu_name` = VALUES(`menu_name`),
+ `menu_icon` = VALUES(`menu_icon`),
+ `menu_url` = VALUES(`menu_url`),
+ `menu_type` = VALUES(`menu_type`),
+ `parent_id` = VALUES(`parent_id`),
+ `menu_level` = VALUES(`menu_level`),
+ `sort_order` = VALUES(`sort_order`),
+ `is_active` = VALUES(`is_active`),
+ `is_visible` = VALUES(`is_visible`),
+ `description` = VALUES(`description`),
+ `updated_at` = VALUES(`updated_at`);
+
+INSERT INTO `sys_menus`
+(`menu_code`, `menu_name`, `menu_icon`, `menu_url`, `menu_type`, `parent_id`, `menu_level`, `tree_path`,
+ `sort_order`, `is_active`, `is_visible`, `description`, `created_at`, `updated_at`)
+SELECT
+ 'prompt_management', '提示词库', 'BookText', '/prompt-management', 'link',
+ @platform_admin_id, 2, NULL, 3, 1, 1, '系统提示词库管理', NOW(), NOW()
+FROM DUAL
+WHERE @platform_admin_id IS NOT NULL
+ON DUPLICATE KEY UPDATE
+ `menu_name` = VALUES(`menu_name`),
+ `menu_icon` = VALUES(`menu_icon`),
+ `menu_url` = VALUES(`menu_url`),
+ `menu_type` = VALUES(`menu_type`),
+ `parent_id` = VALUES(`parent_id`),
+ `menu_level` = VALUES(`menu_level`),
+ `sort_order` = VALUES(`sort_order`),
+ `is_active` = VALUES(`is_active`),
+ `is_visible` = VALUES(`is_visible`),
+ `description` = VALUES(`description`),
+ `updated_at` = VALUES(`updated_at`);
+
+INSERT INTO `sys_menus`
+(`menu_code`, `menu_name`, `menu_icon`, `menu_url`, `menu_type`, `parent_id`, `menu_level`, `tree_path`,
+ `sort_order`, `is_active`, `is_visible`, `description`, `created_at`, `updated_at`)
+SELECT
+ 'client_management', '客户端管理', 'Smartphone', '/admin/management/client-management', 'link',
+ @platform_admin_id, 2, NULL, 4, 1, 1, '客户端下载与版本管理', NOW(), NOW()
+FROM DUAL
+WHERE @platform_admin_id IS NOT NULL
+ON DUPLICATE KEY UPDATE
+ `menu_name` = VALUES(`menu_name`),
+ `menu_icon` = VALUES(`menu_icon`),
+ `menu_url` = VALUES(`menu_url`),
+ `menu_type` = VALUES(`menu_type`),
+ `parent_id` = VALUES(`parent_id`),
+ `menu_level` = VALUES(`menu_level`),
+ `sort_order` = VALUES(`sort_order`),
+ `is_active` = VALUES(`is_active`),
+ `is_visible` = VALUES(`is_visible`),
+ `description` = VALUES(`description`),
+ `updated_at` = VALUES(`updated_at`);
+
+INSERT INTO `sys_menus`
+(`menu_code`, `menu_name`, `menu_icon`, `menu_url`, `menu_type`, `parent_id`, `menu_level`, `tree_path`,
+ `sort_order`, `is_active`, `is_visible`, `description`, `created_at`, `updated_at`)
+SELECT
+ 'external_app_management', '外部应用管理', 'AppWindow', '/admin/management/external-app-management', 'link',
+ @platform_admin_id, 2, NULL, 5, 1, 1, '外部系统入口管理', NOW(), NOW()
+FROM DUAL
+WHERE @platform_admin_id IS NOT NULL
+ON DUPLICATE KEY UPDATE
+ `menu_name` = VALUES(`menu_name`),
+ `menu_icon` = VALUES(`menu_icon`),
+ `menu_url` = VALUES(`menu_url`),
+ `menu_type` = VALUES(`menu_type`),
+ `parent_id` = VALUES(`parent_id`),
+ `menu_level` = VALUES(`menu_level`),
+ `sort_order` = VALUES(`sort_order`),
+ `is_active` = VALUES(`is_active`),
+ `is_visible` = VALUES(`is_visible`),
+ `description` = VALUES(`description`),
+ `updated_at` = VALUES(`updated_at`);
+
+INSERT INTO `sys_menus`
+(`menu_code`, `menu_name`, `menu_icon`, `menu_url`, `menu_type`, `parent_id`, `menu_level`, `tree_path`,
+ `sort_order`, `is_active`, `is_visible`, `description`, `created_at`, `updated_at`)
+SELECT
+ 'terminal_management', '终端管理', 'Monitor', '/admin/management/terminal-management', 'link',
+ @platform_admin_id, 2, NULL, 6, 1, 1, '专用终端管理', NOW(), NOW()
+FROM DUAL
+WHERE @platform_admin_id IS NOT NULL
+ON DUPLICATE KEY UPDATE
+ `menu_name` = VALUES(`menu_name`),
+ `menu_icon` = VALUES(`menu_icon`),
+ `menu_url` = VALUES(`menu_url`),
+ `menu_type` = VALUES(`menu_type`),
+ `parent_id` = VALUES(`parent_id`),
+ `menu_level` = VALUES(`menu_level`),
+ `sort_order` = VALUES(`sort_order`),
+ `is_active` = VALUES(`is_active`),
+ `is_visible` = VALUES(`is_visible`),
+ `description` = VALUES(`description`),
+ `updated_at` = VALUES(`updated_at`);
+
+INSERT INTO `sys_menus`
+(`menu_code`, `menu_name`, `menu_icon`, `menu_url`, `menu_type`, `parent_id`, `menu_level`, `tree_path`,
+ `sort_order`, `is_active`, `is_visible`, `description`, `created_at`, `updated_at`)
+SELECT
+ 'user_management', '用户管理', 'Users', '/admin/management/user-management', 'link',
+ @system_management_id, 2, NULL, 1, 1, 1, '账号、角色、密码管理', NOW(), NOW()
+FROM DUAL
+WHERE @system_management_id IS NOT NULL
+ON DUPLICATE KEY UPDATE
+ `menu_name` = VALUES(`menu_name`),
+ `menu_icon` = VALUES(`menu_icon`),
+ `menu_url` = VALUES(`menu_url`),
+ `menu_type` = VALUES(`menu_type`),
+ `parent_id` = VALUES(`parent_id`),
+ `menu_level` = VALUES(`menu_level`),
+ `sort_order` = VALUES(`sort_order`),
+ `is_active` = VALUES(`is_active`),
+ `is_visible` = VALUES(`is_visible`),
+ `description` = VALUES(`description`),
+ `updated_at` = VALUES(`updated_at`);
+
+INSERT INTO `sys_menus`
+(`menu_code`, `menu_name`, `menu_icon`, `menu_url`, `menu_type`, `parent_id`, `menu_level`, `tree_path`,
+ `sort_order`, `is_active`, `is_visible`, `description`, `created_at`, `updated_at`)
+SELECT
+ 'permission_management', '权限管理', 'KeyRound', '/admin/management/permission-management', 'link',
+ @system_management_id, 2, NULL, 2, 1, 1, '菜单与角色授权管理', NOW(), NOW()
+FROM DUAL
+WHERE @system_management_id IS NOT NULL
+ON DUPLICATE KEY UPDATE
+ `menu_name` = VALUES(`menu_name`),
+ `menu_icon` = VALUES(`menu_icon`),
+ `menu_url` = VALUES(`menu_url`),
+ `menu_type` = VALUES(`menu_type`),
+ `parent_id` = VALUES(`parent_id`),
+ `menu_level` = VALUES(`menu_level`),
+ `sort_order` = VALUES(`sort_order`),
+ `is_active` = VALUES(`is_active`),
+ `is_visible` = VALUES(`is_visible`),
+ `description` = VALUES(`description`),
+ `updated_at` = VALUES(`updated_at`);
+
+INSERT INTO `sys_menus`
+(`menu_code`, `menu_name`, `menu_icon`, `menu_url`, `menu_type`, `parent_id`, `menu_level`, `tree_path`,
+ `sort_order`, `is_active`, `is_visible`, `description`, `created_at`, `updated_at`)
+SELECT
+ 'dict_management', '字典管理', 'BookMarked', '/admin/management/dict-management', 'link',
+ @system_management_id, 2, NULL, 3, 1, 1, '平台字典与码表管理', NOW(), NOW()
+FROM DUAL
+WHERE @system_management_id IS NOT NULL
+ON DUPLICATE KEY UPDATE
+ `menu_name` = VALUES(`menu_name`),
+ `menu_icon` = VALUES(`menu_icon`),
+ `menu_url` = VALUES(`menu_url`),
+ `menu_type` = VALUES(`menu_type`),
+ `parent_id` = VALUES(`parent_id`),
+ `menu_level` = VALUES(`menu_level`),
+ `sort_order` = VALUES(`sort_order`),
+ `is_active` = VALUES(`is_active`),
+ `is_visible` = VALUES(`is_visible`),
+ `description` = VALUES(`description`),
+ `updated_at` = VALUES(`updated_at`);
+
+INSERT INTO `sys_menus`
+(`menu_code`, `menu_name`, `menu_icon`, `menu_url`, `menu_type`, `parent_id`, `menu_level`, `tree_path`,
+ `sort_order`, `is_active`, `is_visible`, `description`, `created_at`, `updated_at`)
+SELECT
+ 'parameter_management', '参数管理', 'Setting', '/admin/management/parameter-management', 'link',
+ @system_management_id, 2, NULL, 4, 1, 1, '系统参数管理', NOW(), NOW()
+FROM DUAL
+WHERE @system_management_id IS NOT NULL
+ON DUPLICATE KEY UPDATE
+ `menu_name` = VALUES(`menu_name`),
+ `menu_icon` = VALUES(`menu_icon`),
+ `menu_url` = VALUES(`menu_url`),
+ `menu_type` = VALUES(`menu_type`),
+ `parent_id` = VALUES(`parent_id`),
+ `menu_level` = VALUES(`menu_level`),
+ `sort_order` = VALUES(`sort_order`),
+ `is_active` = VALUES(`is_active`),
+ `is_visible` = VALUES(`is_visible`),
+ `description` = VALUES(`description`),
+ `updated_at` = VALUES(`updated_at`);
+
+SET @permission_management_id := (
+ SELECT `menu_id`
+ FROM `sys_menus`
+ WHERE `menu_code` = 'permission_management'
+ LIMIT 1
+);
+
+INSERT INTO `sys_menus`
+(`menu_code`, `menu_name`, `menu_icon`, `menu_url`, `menu_type`, `parent_id`, `menu_level`, `tree_path`,
+ `sort_order`, `is_active`, `is_visible`, `description`, `created_at`, `updated_at`)
+SELECT
+ 'permission_menu_tree', '菜单树维护', 'AppstoreAdd', '/admin/management/permission-management', 'link',
+ @permission_management_id, 3, NULL, 20, 1, 0, '权限管理中的隐藏入口,用于菜单树维护。', NOW(), NOW()
+FROM DUAL
+WHERE @permission_management_id IS NOT NULL
+ON DUPLICATE KEY UPDATE
+ `menu_name` = VALUES(`menu_name`),
+ `menu_icon` = VALUES(`menu_icon`),
+ `menu_url` = VALUES(`menu_url`),
+ `menu_type` = VALUES(`menu_type`),
+ `parent_id` = VALUES(`parent_id`),
+ `menu_level` = VALUES(`menu_level`),
+ `sort_order` = VALUES(`sort_order`),
+ `is_active` = VALUES(`is_active`),
+ `is_visible` = VALUES(`is_visible`),
+ `description` = VALUES(`description`),
+ `updated_at` = VALUES(`updated_at`);
+
+-- 回填本次初始化菜单的树结构
+UPDATE `sys_menus`
+SET
+ `menu_level` = 1,
+ `tree_path` = CONCAT('/', `menu_id`)
+WHERE `menu_code` IN ('dashboard', 'desktop', 'meeting_manage', 'platform_admin', 'system_management');
+
+UPDATE `sys_menus` c
+JOIN `sys_menus` p ON c.`parent_id` = p.`menu_id`
+SET
+ c.`menu_level` = p.`menu_level` + 1,
+ c.`tree_path` = CONCAT(p.`tree_path`, '/', c.`menu_id`)
+WHERE c.`menu_code` IN (
+ 'meeting_center',
+ 'prompt_config',
+ 'hot_word_management',
+ 'model_management',
+ 'prompt_management',
+ 'client_management',
+ 'external_app_management',
+ 'terminal_management',
+ 'user_management',
+ 'permission_management',
+ 'dict_management',
+ 'parameter_management'
+);
+
+UPDATE `sys_menus` c
+JOIN `sys_menus` p ON c.`parent_id` = p.`menu_id`
+SET
+ c.`menu_level` = p.`menu_level` + 1,
+ c.`tree_path` = CONCAT(p.`tree_path`, '/', c.`menu_id`)
+WHERE c.`menu_code` IN ('permission_menu_tree');
+
+-- =====================================================================
+-- 9. 角色授权
+-- 管理员: 所有启用菜单
+-- 普通用户: dashboard / desktop / meeting_manage / meeting_center / prompt_config
+-- =====================================================================
+INSERT INTO `sys_role_menu_permissions`
+(`role_id`, `menu_id`, `granted_by`, `granted_at`)
+SELECT
+ 1,
+ m.`menu_id`,
+ 1,
+ NOW()
+FROM `sys_menus` m
+WHERE m.`is_active` = 1
+ON DUPLICATE KEY UPDATE
+ `granted_by` = VALUES(`granted_by`),
+ `granted_at` = VALUES(`granted_at`);
+
+INSERT INTO `sys_role_menu_permissions`
+(`role_id`, `menu_id`, `granted_by`, `granted_at`)
+SELECT
+ 2,
+ m.`menu_id`,
+ 1,
+ NOW()
+FROM `sys_menus` m
+WHERE m.`is_active` = 1
+ AND m.`menu_code` IN ('dashboard', 'desktop', 'meeting_manage', 'meeting_center', 'prompt_config')
+ON DUPLICATE KEY UPDATE
+ `granted_by` = VALUES(`granted_by`),
+ `granted_at` = VALUES(`granted_at`);
+
+-- =====================================================================
+-- 10. 自增游标兜底
+-- =====================================================================
+COMMIT;
+
+ALTER TABLE `sys_roles` AUTO_INCREMENT = 3;
+ALTER TABLE `sys_users` AUTO_INCREMENT = 3;
+ALTER TABLE `prompts` AUTO_INCREMENT = 3;
diff --git a/design/button-system-guidelines.md b/design/button-system-guidelines.md
deleted file mode 100644
index 00952da..0000000
--- a/design/button-system-guidelines.md
+++ /dev/null
@@ -1,222 +0,0 @@
-# iMeeting 按钮统一规范
-
-## 目标
-
-统一平台内业务操作按钮的视觉语言、尺寸层级和使用方式,避免同一场景中出现不同形态的编辑、删除、查看、复制等操作按钮。
-
-当前平台按钮分为两套标准:
-
-1. 业务操作按钮:统一通过 [ActionButton](/Users/jiliu/工作/projects/imeeting/frontend/src/components/ActionButton.jsx) 承载。
-2. 表单操作条按钮:统一使用 Ant Design `Button` 家族,不与 `ActionButton` 混用。
-
-## 设计原则
-
-1. 语义和尺寸分离。
-语义只表达动作类型,例如查看、编辑、删除;尺寸只表达场景层级,例如列表操作、面板次级操作。
-
-2. 同一场景只选一种尺寸档。
-不要在同一条记录、同一个卡片头部、同一个面板操作区里混用大图标、小图标、大文字、小文字。
-
-3. 删除按钮只保留颜色差异。
-删除按钮和其它按钮使用同一套圆角、边框、阴影和尺寸,不再使用额外的危险态造型。
-
-4. 业务操作、表单操作、功能控件分开。
-- 业务操作统一走 `ActionButton`
-- 表单操作条统一走标准 `Button`
-- 编辑器工具栏、播放器控制等功能控件不强行复用这套规范
-
-5. 同一操作条内外框语言必须一致。
-如果一组按钮里已经采用普通 `Button`,就不要混入胶囊式 `ActionButton`;如果一组按钮采用 `ActionButton`,就不要再塞入默认 `Button`。
-
-## 标准尺寸
-
-### 1. 带文字(大)
-
-- 组件参数:`variant="textLg"`
-- 典型场景:面板内次级操作、详情弹窗中的补充动作、信息面板中的“下载结果 / 复制链接 / 编辑当前菜单”
-- 示例:`编辑`、`删除`、`下载转录结果 (JSON)`、`复制链接`
-
-### 2. 带文字(小)
-
-- 组件参数:`variant="textSm"`
-- 典型场景:卡片头部轻量动作、模块内局部切换动作
-- 示例:`标签`、`编辑`、`查看详情`、`清空已选`
-
-### 3. 仅图标(大)
-
-- 组件参数:`variant="iconLg"`
-- 典型场景:输入框组合控件右侧操作、需要更高点击面的紧凑操作
-- 示例:分享密码区的 `复制 / 保存`
-
-### 4. 仅图标(小)
-
-- 组件参数:`variant="iconSm"`
-- 典型场景:列表行操作、卡片角落操作、悬浮于内容边缘的轻量动作
-- 示例:`编辑 / 删除 / 查看 / 同步 / 更多`
-
-## 标准语义
-
-### `tone="view"`
-
-- 用于查看、打开、复制、下载、预览
-- 颜色语义:蓝色系
-
-### `tone="neutral"`
-
-- 用于更多、清空、重置筛选、非强调型辅助动作
-- 颜色语义:中性色
-
-### `tone="edit"`
-
-- 用于编辑、设置、修改
-- 颜色语义:蓝色系,与查看同体系但文义偏编辑
-
-### `tone="accent"`
-
-- 用于需要强调但非危险的特殊动作
-- 颜色语义:强调色
-- 当前典型场景:`重置密码`
-
-### `tone="delete"`
-
-- 用于删除、移除、关闭会话等不可逆动作
-- 颜色语义:红色系
-
-## 场景映射
-
-### 列表行操作
-
-- 一律使用 `iconSm`
-- 常见组合:`编辑 / 删除`、`查看 / 编辑 / 删除`
-- 示例页面:
- - 热词管理
- - 用户管理
- - 参数管理
- - 模型管理
- - 客户端管理
- - 外部应用管理
-
-### 卡片角落操作
-
-- 一律使用 `iconSm`
-- 常见组合:`编辑 / 删除`、`更多`
-- 示例页面:
- - 会议中心卡片
- - 时间线卡片
- - 知识库左侧列表
-
-### 卡片或模块头部的轻量动作
-
-- 一律使用 `textSm`
-- 常见组合:`标签`、`编辑`、`查看详情`
-
-### 面板或 Drawer 的次级操作
-
-- 一律使用 `textLg`
-- 常见组合:`编辑`、`删除`、`复制链接`、`下载转录结果`
-
-### 表单操作条
-
-- 一律使用标准 `Button`
-- 常见组合:`删除 / 取消 / 保存`
-- 视觉规范:
- - `删除`:`className="btn-soft-red"`
- - `取消`:默认 `Button`
- - `保存`:`type="primary"`
-- 说明:
- - 这类按钮属于提交与撤销控制,不使用 `ActionButton`
- - 同一条内不要出现 `ActionButton tone="delete"` 与普通 `Button` 并排
-
-### 输入框附属操作
-
-- 一律使用 `iconLg`
-- 常见组合:输入框后缀的 `复制 / 保存`
-
-## 禁止项
-
-1. 不要在业务操作中直接裸用 `EditOutlined`、`DeleteOutlined` 作为可点击入口。
-
-2. 不要在同一场景混用:
-- `shape="circle"` 图标按钮
-- 旧的 `btn-icon-soft-*`
-- 默认 `danger` 样式按钮
-- 新的 `ActionButton`
-- 普通 `Button` 和 `ActionButton` 的不同外框语言
-
-3. 不要为了“删除更危险”单独给删除按钮换不同形状、尺寸或阴影。
-
-4. 不要在业务操作中继续手写 `Tooltip + Button + btn-text-* + btn-action-*`。
-优先使用 `ActionButton`。
-
-## 推荐写法
-
-```jsx
-import ActionButton from '../components/ActionButton';
-
-}
- onClick={handleEdit}
-/>
-```
-
-```jsx
-}
- onClick={handleDelete}
->
- 删除
-
-```
-
-```jsx
-}
- onClick={handleCopy}
-/>
-```
-
-```jsx
-
- } onClick={handleDelete}>
- 删除
-
- } onClick={handleCancel}>
- 取消
-
- } onClick={handleSave}>
- 保存
-
-
-```
-
-## 落地约束
-
-1. 新增按钮时,先判断是不是业务动作还是表单提交动作。
-- 业务动作优先使用 `ActionButton`
-- 表单操作条优先使用标准 `Button`
-
-2. 新页面开发时,先确定场景,再选尺寸档。
-不要先凭感觉挑样式。
-
-3. 旧页面调整时,如果涉及编辑、删除、查看、更多、复制、下载等业务动作,顺手迁移到 `ActionButton`。
-
-4. 如果删除按钮和取消、保存并排出现,优先按表单操作条处理,不要单独给删除套胶囊业务按钮。
-
-## 现状说明
-
-当前平台中的主要业务操作按钮已基本迁移到 `ActionButton`,主要表单操作条也开始统一为 `删除 / 取消 / 保存` 的标准按钮组合。
-
-未纳入本规范的主要是两类控件:
-
-- Markdown 编辑器工具栏按钮
-- 会议详情中的音频工具栏按钮
-
-这两类属于功能控件,不按业务操作按钮规范处理。
diff --git a/docs/CLIENT_DOWNLOADS_MODULE.md b/docs/CLIENT_DOWNLOADS_MODULE.md
deleted file mode 100644
index a449f2e..0000000
--- a/docs/CLIENT_DOWNLOADS_MODULE.md
+++ /dev/null
@@ -1,292 +0,0 @@
-# 客户端下载管理模块
-
-## 概述
-
-本模块实现了一个完整的客户端下载管理系统,支持移动端(iOS/Android)和桌面端(Windows/Mac/Linux)的版本管理和下载。
-
-## 功能特性
-
-### 1. 管理员功能
-- ✅ 创建/编辑/删除客户端版本
-- ✅ 管理版本号和版本代码
-- ✅ 设置最新版本标记
-- ✅ 启用/禁用特定版本
-- ✅ 添加更新说明和系统要求
-- ✅ 平台分类管理(移动端/桌面端)
-- ✅ 搜索和过滤功能
-
-### 2. 用户功能
-- ✅ 查看所有平台的最新客户端
-- ✅ 按平台分类展示
-- ✅ 显示版本信息和文件大小
-- ✅ 一键下载
-
-### 3. API功能
-- ✅ 获取所有客户端列表(支持分页和过滤)
-- ✅ 获取最新版本客户端
-- ✅ 按平台获取最新版本(用于客户端版本检查)
-- ✅ CRUD操作(仅管理员)
-
-## 数据库设计
-
-### 表结构: `client_downloads`
-
-```sql
-CREATE TABLE client_downloads (
- id INT AUTO_INCREMENT PRIMARY KEY,
- platform_type ENUM('mobile', 'desktop') NOT NULL,
- platform_name VARCHAR(50) NOT NULL,
- version VARCHAR(50) NOT NULL,
- version_code INT NOT NULL DEFAULT 1,
- download_url TEXT NOT NULL,
- file_size BIGINT,
- release_notes TEXT,
- is_active BOOLEAN DEFAULT TRUE,
- is_latest BOOLEAN DEFAULT FALSE,
- min_system_version VARCHAR(50),
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
- created_by INT,
- FOREIGN KEY (created_by) REFERENCES users(user_id) ON DELETE SET NULL,
- INDEX idx_platform (platform_type, platform_name),
- INDEX idx_version (version_code),
- INDEX idx_active (is_active, is_latest)
-);
-```
-
-### 字段说明
-
-- `platform_type`: 平台类型(mobile/desktop)
-- `platform_name`: 具体平台(ios/android/windows/mac_intel/mac_m/linux)
-- `version`: 版本号字符串(如: 1.0.0)
-- `version_code`: 版本代码数字(用于版本比较,如: 1000)
-- `download_url`: 下载链接
-- `file_size`: 文件大小(字节)
-- `release_notes`: 更新说明
-- `is_active`: 是否启用
-- `is_latest`: 是否为最新版本
-- `min_system_version`: 最低系统版本要求
-
-## API接口
-
-### 公开接口(无需认证)
-
-#### 1. 获取客户端列表
-```
-GET /api/clients/downloads
-Query参数:
- - platform_type: mobile|desktop (可选)
- - platform_name: ios|android|windows|mac_intel|mac_m|linux (可选)
- - is_active: true|false (可选)
- - page: 页码 (默认1)
- - size: 每页数量 (默认50)
-```
-
-#### 2. 获取所有最新版本
-```
-GET /api/clients/downloads/latest
-返回: { mobile: [...], desktop: [...] }
-```
-
-#### 3. 获取指定平台最新版本
-```
-GET /api/clients/downloads/{platform_name}/latest
-示例: GET /api/clients/downloads/ios/latest
-```
-
-#### 4. 获取指定ID的客户端
-```
-GET /api/clients/downloads/{id}
-```
-
-### 管理员接口(需要管理员权限)
-
-#### 5. 创建客户端版本
-```
-POST /api/clients/downloads
-Body: {
- "platform_type": "mobile",
- "platform_name": "ios",
- "version": "1.0.0",
- "version_code": 1000,
- "download_url": "https://...",
- "file_size": 52428800,
- "release_notes": "初始版本...",
- "is_active": true,
- "is_latest": false,
- "min_system_version": "iOS 13.0"
-}
-```
-
-#### 6. 更新客户端版本
-```
-PUT /api/clients/downloads/{id}
-Body: {
- "version": "1.0.1",
- "version_code": 1001,
- "is_latest": true,
- ...
-}
-```
-
-#### 7. 删除客户端版本
-```
-DELETE /api/clients/downloads/{id}
-```
-
-## 前端组件
-
-### 1. ClientManagement (管理员页面)
-位置: `frontend/src/pages/ClientManagement.jsx`
-
-功能:
-- 客户端版本CRUD操作
-- 平台筛选和搜索
-- 版本状态管理
-- 响应式卡片布局
-
-### 2. ClientDownloads (用户下载组件)
-位置: `frontend/src/components/ClientDownloads.jsx`
-
-功能:
-- 展示最新客户端版本
-- 按平台分类
-- 一键下载
-- 可嵌入任何页面
-
-## 安装和部署
-
-### 1. 数据库初始化
-
-```bash
-# 执行SQL文件
-mysql -u your_user -p your_database < backend/sql/client_downloads.sql
-```
-
-### 2. 后端启动
-
-后端会自动加载新的路由,无需额外配置。
-
-### 3. 前端使用
-
-#### 在管理员页面添加客户端管理:
-
-```jsx
-import ClientManagement from './pages/ClientManagement';
-
-// 在管理员路由中添加
-} />
-```
-
-#### 在首页添加下载组件:
-
-```jsx
-import ClientDownloads from './components/ClientDownloads';
-
-// 在Dashboard或任何页面中添加
-
-```
-
-## 使用示例
-
-### 管理员创建新版本
-
-1. 访问管理后台的"客户端管理"页面
-2. 点击"新增客户端"按钮
-3. 填写版本信息:
- - 选择平台类型和具体平台
- - 输入版本号和版本代码
- - 填写下载链接
- - 添加更新说明
- - 勾选"设为最新版本"(如果是最新)
-4. 点击"创建"保存
-
-### 用户下载客户端
-
-1. 在首页查看"下载客户端"区域
-2. 选择对应平台
-3. 点击卡片即可下载
-
-### 客户端版本检查
-
-客户端可以调用API检查是否有新版本:
-
-```javascript
-// 检查iOS最新版本
-const response = await fetch('/api/clients/downloads/ios/latest');
-const latest = await response.json();
-
-if (latest.data.version_code > currentVersionCode) {
- // 提示用户更新
- showUpdateDialog(latest.data);
-}
-```
-
-## 版本号规范
-
-- **版本号**: 采用语义化版本(Semantic Versioning),格式: `主版本.次版本.修订号`
- - 例如: 1.0.0, 1.2.3, 2.0.0
-
-- **版本代码**: 纯数字,用于程序化比较
- - 推荐格式: 主版本(2位) + 次版本(2位) + 修订号(2位)
- - 例如: 1.0.0 -> 10000, 1.2.3 -> 10203, 2.0.0 -> 20000
-
-## 平台支持
-
-### 移动端
-- **iOS**: App Store链接或企业分发链接
-- **Android**: Google Play链接或APK直接下载
-
-### 桌面端
-- **Windows**: .exe安装包
-- **Mac (Intel)**: Intel架构的.dmg安装包
-- **Mac (M系列)**: Apple Silicon原生支持的.dmg安装包
-- **Linux**: .AppImage或.deb/.rpm包
-
-## 注意事项
-
-1. **下载链接**: 确保下载链接长期有效,建议使用CDN或对象存储
-2. **文件大小**: 建议填写准确的文件大小,方便用户了解下载时间
-3. **版本管理**:
- - 同一平台只能有一个"最新版本"
- - 设置新版本为最新时,会自动将旧版本的最新标记��除
-4. **权限控制**: CRUD操作仅管理员可执行,查询接口公开访问
-
-## 扩展建议
-
-1. **统计功能**: 添加下载次数统计
-2. **发布计划**: 支持定时发布新版本
-3. **灰度发布**: 按百分比或用户组逐步推送新版本
-4. **更新检查**: 提供SDK方便客户端集成版本检查
-5. **更新强制**: 支持强制更新标记
-
-## 文件清单
-
-### 后端
-- `backend/sql/client_downloads.sql` - 数据库表结构和初始数据
-- `backend/app/models/models.py` - Pydantic数据模型
-- `backend/app/api/endpoints/client_downloads.py` - API路由和业务逻辑
-- `backend/main.py` - 路由注册
-
-### 前端
-- `frontend/src/pages/ClientManagement.jsx` - 管理员管理页面
-- `frontend/src/pages/ClientManagement.css` - 管理页面样式
-- `frontend/src/components/ClientDownloads.jsx` - 用户下载组件
-- `frontend/src/components/ClientDownloads.css` - 下载组件样式
-- `frontend/src/config/api.js` - API配置
-
-## 技术栈
-
-### 后端
-- FastAPI
-- MySQL
-- Pydantic
-
-### 前端
-- React
-- Lucide React Icons
-- CSS3
-
-## 作者
-
-Generated with Claude Code
diff --git a/docs/MEETING_PROMPT_VARIABLES.md b/docs/MEETING_PROMPT_VARIABLES.md
deleted file mode 100644
index e055c61..0000000
--- a/docs/MEETING_PROMPT_VARIABLES.md
+++ /dev/null
@@ -1,121 +0,0 @@
-# 会议总结模板变量说明
-
-## 概述
-
-会议总结提示词模板支持使用变量占位符。只有在模板内容中显式写入变量时,系统才会替换对应值;未使用的变量不会自动追加到提示词中。
-
-当前会议总结链路的推荐组装方式如下:
-
-- `base_system_prompt`:放全局稳定规则,例如准确性要求、格式遵循、禁止编造;不要放会议业务指令
-- 会议模板(`MEETING_TASK`):放任务级总结模板,会作为会议总结专用的 `system` 指令
-- `user_prompt`:放本次用户的临时补充要求,例如侧重点、篇幅、风格
-- 会议转录:单独作为用户消息输入,作为总结事实来源
-
-这样可以把“规则”和“材料”分层,减少模型将转录内容误当成指令的概率。
-
-## 支持的变量
-
-### 1. 会议 ID
-
-```text
-{{meeting_id}}
-```
-
-输出当前会议的唯一 ID。
-
-### 2. 会议标题
-
-```text
-{{meeting_title}}
-```
-
-输出当前会议标题。
-
-### 3. 会议时间
-
-默认格式输出:
-
-```text
-{{meeting_time}}
-```
-
-默认格式示例:
-
-```text
-2026-04-07 14:30:00
-```
-
-自定义格式输出:
-
-```text
-{{meeting_time:%Y年%m月%d日 %H:%M}}
-```
-
-自定义格式示例:
-
-```text
-2026年04月07日 14:30
-```
-
-如果未设置自定义格式,则使用默认格式。若自定义格式无法解析,系统会回退到默认时间值。
-
-### 4. 会议创建人
-
-```text
-{{meeting_creator}}
-```
-
-输出会议创建人名称。
-
-### 5. 参会人员
-
-```text
-{{meeting_attendees}}
-```
-
-输出参会人员名称列表,多个名字使用 `、` 连接。
-
-## 可直接复制的变量列表
-
-```text
-{{meeting_id}}
-{{meeting_title}}
-{{meeting_time}}
-{{meeting_time:%Y年%m月%d日 %H:%M}}
-{{meeting_creator}}
-{{meeting_attendees}}
-```
-
-## 模板示例
-
-### 示例一:正式会议纪要
-
-```text
-请根据会议转录内容生成正式会议纪要。
-
-会议标题:{{meeting_title}}
-会议时间:{{meeting_time:%Y年%m月%d日 %H:%M}}
-创建人:{{meeting_creator}}
-参会人员:{{meeting_attendees}}
-
-请输出:
-1. 会议背景
-2. 核心讨论
-3. 决议事项
-4. 待办事项
-```
-
-### 示例二:简洁总结
-
-```text
-请用简洁风格总结本次会议。
-会议:{{meeting_title}}
-时间:{{meeting_time}}
-```
-
-## 使用规则
-
-- 变量必须使用双大括号包裹
-- 仅当模板中写入变量时,系统才会替换对应内容
-- `meeting_time` 支持自定义时间格式
-- 未填写的字段可能返回空字符串
diff --git a/docs/imeeting_qy_upgrade_report_20260403.md b/docs/imeeting_qy_upgrade_report_20260403.md
deleted file mode 100644
index fa11083..0000000
--- a/docs/imeeting_qy_upgrade_report_20260403.md
+++ /dev/null
@@ -1,129 +0,0 @@
-# iMeeting `imeeting_qy` 数据库升级报告
-
-## 1. 升级目标
-
-- 源旧库:`imeeting_qy`
-- 对标最新结构库:`imeeting`
-- 升级日期:`2026-04-03`
-- 执行方式:先在临时测试库 `imeeting_qy_upgrade_test` 演练,再正式执行到 `imeeting_qy`
-
-## 2. 备份信息
-
-- 正式升级前已创建完整备份库:`imeeting_qy_backup_20260403_004354`
-- 备份方式:同服务器整库复制全部 `BASE TABLE`
-
-## 3. 本次执行内容
-
-本次升级使用迁移脚本:
-
-- `backend/sql/migrations/upgrade_imeeting_qy_to_latest.sql`
-
-核心动作如下:
-
-1. 将旧系统表标准化为 `sys_*` 体系:
- - `users -> sys_users`
- - `roles -> sys_roles`
- - `menus -> sys_menus`
- - `role_menu_permissions -> sys_role_menu_permissions`
- - `dict_data -> sys_dict_data`
-
-2. 重建兼容视图:
- - `users`
- - `roles`
- - `menus`
- - `role_menu_permissions`
- - `dict_data`
- - `system_parameters`
-
-3. 对齐旧系统表字段与索引:
- - `sys_users` 补齐 `idx_role_id`
- - `sys_roles` 补齐 `uk_role_name`
- - `sys_menus` 补齐 `menu_level/tree_path/is_visible` 及相关索引
- - `sys_role_menu_permissions` 补齐 `granted_by/granted_at` 及相关索引
- - `prompts` 补齐 `is_system` 字段及组合索引
- - `terminals.current_user_id` 字段注释对齐到最新结构
-
-4. 新增并初始化最新配置表:
- - `sys_system_parameters`
- - `ai_model_configs`
- - `llm_model_config`
- - `audio_model_config`
- - `hot_word_group`
- - `hot_word_item`
- - `prompt_config`
- - `sys_user_mcp`
-
-5. 迁移旧配置数据:
- - 从 `sys_dict_data(dict_type='system_config')` 迁移系统参数到 `sys_system_parameters`
- - 迁移 LLM / ASR / 声纹配置到 `ai_model_configs`
- - 拆分生成 `llm_model_config`、`audio_model_config`
- - 从旧 `hot_words` 迁移到 `hot_word_group` / `hot_word_item`
-
-6. 重建最新菜单树与角色授权模型:
- - 新增 `dashboard`、`desktop`、`meeting_manage`、`system_management` 等最新菜单结构
- - 规范平台管理、系统管理、会议管理三套菜单层级
- - 管理员角色授予全部启用菜单
- - 普通用户保留 `desktop/meeting_manage/meeting_center/prompt_config`
-
-## 4. 升级结果
-
-升级后关键表数据如下:
-
-| 表名 | 行数 |
-|---|---:|
-| `sys_users` | 44 |
-| `sys_roles` | 2 |
-| `sys_menus` | 19 |
-| `sys_role_menu_permissions` | 22 |
-| `sys_system_parameters` | 4 |
-| `ai_model_configs` | 3 |
-| `llm_model_config` | 1 |
-| `audio_model_config` | 2 |
-| `hot_word_group` | 1 |
-| `hot_word_item` | 20 |
-| `prompt_config` | 0 |
-| `sys_user_mcp` | 0 |
-
-迁移后的系统参数:
-
-| 参数键 | 参数值 |
-|---|---|
-| `asr_vocabulary_id` | `vocab-imeeting-734e93f5bd8a4f3bb665dd526d584516` |
-| `default_reset_password` | `123456` |
-| `max_audio_size` | `500` |
-| `timeline_pagesize` | `20` |
-
-迁移后的模型配置:
-
-- `llm_model_config`:1 条默认模型,`model_code=llm_model`
-- `audio_model_config`:2 条配置
- - `audio_model` / `asr`
- - `voiceprint_model` / `voiceprint`
-
-迁移后的热词配置:
-
-- `hot_word_group`:1 个默认热词组
-- `hot_word_item`:20 条热词条目
-
-## 5. 角色菜单结果
-
-- 平台管理员:
- - `dashboard, hot_word_management, user_management, meeting_center, desktop, meeting_manage, model_management, permission_management, prompt_config, prompt_management, platform_admin, dict_management, system_management, client_management, external_app_management, terminal_management, parameter_management, permission_menu_tree`
-
-- 普通用户:
- - `meeting_center, desktop, meeting_manage, prompt_config`
-
-## 6. 结构校验结论
-
-对 `imeeting_qy` 与 `imeeting` 进行了 `information_schema.tables` + `information_schema.columns` 级别的最终校验,结果如下:
-
-- 缺失表:`0`
-- 多余表:`0`
-- 表类型差异:`0`
-- 字段差异:`0`
-
-结论:
-
-- `imeeting_qy` 已完成升级
-- 当前库结构已与 `imeeting` 对齐
-- 本次升级为“结构对齐 + 必要配置数据迁移”,未删除旧业务数据