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 - - - - - -``` - -## 落地约束 - -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` 对齐 -- 本次升级为“结构对齐 + 必要配置数据迁移”,未删除旧业务数据