会议纪要功能修复与改进

后端:
- 待办同步改走 ISysOaTaskService.insertByBo/updateByBo,新任务带操作日志和IM通知
- 任务状态映射修正:done→2执行完成,其余→0执行中(原 progress→1 会显示成"等待验收")
- 无负责人/无内容的待办仅作纪要记录,不再生成无主任务
- 更新时可清空字段改用显式 set(原来解绑项目、清空内容不生效)
- 新增接口返回纪要ID,前端据此进入编辑态,避免重复保存生成多条
- 会议编号加3位随机数防同秒撞唯一键;异常改 ServiceException;同步失败记日志
- enrich 为待办条目注入 assigneeName,列表/详情/导出可显示负责人姓名
- SysOaTaskServiceImpl.insertByBo 回填 taskId 供调用方关联

前端:
- 主持人/待办负责人改用人员单选弹窗(原多选组件取首位的方式易误操作)
- 会议类型、待办状态接入 sys_dict 字典(oa_meeting_type / oa_meeting_task_status)
- 新建保存后切换为编辑态;默认日期用本地时区(原 UTC 凌晨会差一天)
- 导出/打印带主持人、参会人、待办负责人姓名(原来只有用户ID)
- 删除已同步待办时提示任务不会被删除

SQL(已直接应用到生产库):
- 字典数据补全并修复 dict_id=0 脏数据(sys_dict_* 主键为雪花ID须显式指定)
- 菜单 2063809716454174722 icon 修为 documentation,授权10个角色
- 脚本改为幂等,去掉 DROP TABLE,del_flag 注释修正为逻辑删除值2

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 10:12:48 +08:00
parent e5bfa0c78c
commit a9c9b8a5ea
5 changed files with 330 additions and 174 deletions

View File

@@ -1,21 +1,19 @@
-- =====================================================
-- 智能会议纪要 (Smart Meeting Minutes)
-- - 弃用 oa_meeting_project改为绑定 sys_oa_project.project_id
-- - 会议可绑定 sys_oa_project.project_id,也可不绑定(非项目会议)
-- - 主持人/参会/待办负责人 统一存 user_id
-- - 待办在保存时可同步生成 sys_oa_task
-- - 待办在保存时可同步生成 sys_oa_task(带操作日志和 IM 通知)
-- 本脚本可重复执行(幂等)。
-- 注意sys_dict_type/sys_dict_data/sys_menu 主键为雪花ID非自增必须显式指定。
-- =====================================================
-- 清理上一版(如有)
DROP TABLE IF EXISTS `oa_meeting_project`;
-- ---------------- 会议纪要 ----------------
DROP TABLE IF EXISTS `oa_meeting_minutes`;
CREATE TABLE `oa_meeting_minutes` (
-- ---------------- 会议纪要表 ----------------
CREATE TABLE IF NOT EXISTS `oa_meeting_minutes` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`meeting_code` varchar(32) NOT NULL COMMENT '会议编号 MT-yyyyMMddHHmmss',
`meeting_code` varchar(32) NOT NULL COMMENT '会议编号 MT-yyyyMMddHHmmss+3位随机',
`meeting_date` date NOT NULL COMMENT '会议日期',
`project_id` bigint(20) DEFAULT NULL COMMENT '关联 sys_oa_project.project_id',
`meeting_type` varchar(20) DEFAULT 'other' COMMENT '类型 tech/project/client/weekly/other',
`project_id` bigint(20) DEFAULT NULL COMMENT '关联 sys_oa_project.project_id(可空=非项目会议)',
`meeting_type` varchar(20) DEFAULT 'other' COMMENT '类型 字典 oa_meeting_type',
`subject` varchar(500) NOT NULL COMMENT '会议主题',
`location` varchar(255) DEFAULT NULL COMMENT '会议地点',
`host_user_id` bigint(20) DEFAULT NULL COMMENT '主持人 sys_user.user_id',
@@ -23,13 +21,13 @@ CREATE TABLE `oa_meeting_minutes` (
`topic` text COMMENT '会议议题',
`discussion` text COMMENT '讨论内容',
`decision` text COMMENT '决议事项',
`tasks_json` text COMMENT '待办 JSON[{assigneeUserId,content,deadline,status,taskId}]',
`tasks_json` text COMMENT '待办 JSON[{assigneeUserId,assigneeName,content,deadline,status,taskId}]',
`sync_task` tinyint(1) DEFAULT 1 COMMENT '是否将待办同步为 OA 任务',
`create_by` varchar(64) DEFAULT NULL,
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_by` varchar(64) DEFAULT NULL,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志0正常 1删除',
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志0正常 2删除mybatis-plus logicDeleteValue=2',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_meeting_code` (`meeting_code`, `del_flag`),
KEY `idx_date` (`meeting_date`),
@@ -37,26 +35,60 @@ CREATE TABLE `oa_meeting_minutes` (
KEY `idx_type` (`meeting_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会议纪要';
-- ---------------- 清理早期错误数据dict_id/dict_code 误插为 0 ----------------
DELETE FROM `sys_dict_type` WHERE `dict_id` = 0 AND `dict_type` IN ('oa_meeting_type', 'oa_meeting_task_status');
DELETE FROM `sys_dict_data` WHERE `dict_code` = 0 AND `dict_type` IN ('oa_meeting_type', 'oa_meeting_task_status');
-- ---------------- 字典:会议类型 ----------------
INSERT IGNORE INTO `sys_dict_type` (`dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `remark`)
VALUES ('会议类型', 'oa_meeting_type', '0', 'admin', NOW(), '智能会议纪要-会议类型');
INSERT IGNORE INTO `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `remark`)
VALUES (2063900000000000001, '会议类型', 'oa_meeting_type', '0', 'admin', NOW(), '智能会议纪要-会议类型');
INSERT IGNORE INTO `sys_dict_data`
(`dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `remark`)
(`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `remark`)
VALUES
(1, '技术评审', 'tech', 'oa_meeting_type', '', 'info', 'N', '0', 'admin', NOW(), ''),
(2, '项目推进', 'project', 'oa_meeting_type', '', 'primary', 'N', '0', 'admin', NOW(), ''),
(3, '客户沟通', 'client', 'oa_meeting_type', '', 'warning', 'N', '0', 'admin', NOW(), ''),
(4, '周例会', 'weekly', 'oa_meeting_type', '', 'success', 'N', '0', 'admin', NOW(), ''),
(5, '其他', 'other', 'oa_meeting_type', '', '', 'Y', '0', 'admin', NOW(), '');
(2063900000000000011, 1, '技术评审', 'tech', 'oa_meeting_type', '', 'info', 'N', '0', 'admin', NOW(), ''),
(2063900000000000012, 2, '项目推进', 'project', 'oa_meeting_type', '', 'primary', 'N', '0', 'admin', NOW(), ''),
(2063900000000000013, 3, '客户沟通', 'client', 'oa_meeting_type', '', 'warning', 'N', '0', 'admin', NOW(), ''),
(2063900000000000014, 4, '周例会', 'weekly', 'oa_meeting_type', '', 'success', 'N', '0', 'admin', NOW(), ''),
(2063900000000000015, 5, '其他', 'other', 'oa_meeting_type', '', 'default', 'Y', '0', 'admin', NOW(), '');
-- ---------------- 字典:待办状态 ----------------
INSERT IGNORE INTO `sys_dict_type` (`dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `remark`)
VALUES ('会议待办状态', 'oa_meeting_task_status', '0', 'admin', NOW(), '智能会议纪要-待办状态');
INSERT IGNORE INTO `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `remark`)
VALUES (2063900000000000002, '会议待办状态', 'oa_meeting_task_status', '0', 'admin', NOW(), '智能会议纪要-待办状态');
INSERT IGNORE INTO `sys_dict_data`
(`dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `remark`)
(`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `remark`)
VALUES
(1, '待办', 'pending', 'oa_meeting_task_status', '', 'info', 'Y', '0', 'admin', NOW(), ''),
(2, '进行中', 'progress', 'oa_meeting_task_status', '', 'primary', 'N', '0', 'admin', NOW(), ''),
(3, '已完成', 'done', 'oa_meeting_task_status', '', 'success', 'N', '0', 'admin', NOW(), '');
(2063900000000000021, 1, '待办', 'pending', 'oa_meeting_task_status', '', 'info', 'Y', '0', 'admin', NOW(), ''),
(2063900000000000022, 2, '进行中', 'progress', 'oa_meeting_task_status', '', 'primary', 'N', '0', 'admin', NOW(), ''),
(2063900000000000023, 3, '已完成', 'done', 'oa_meeting_task_status', '', 'success', 'N', '0', 'admin', NOW(), '');
-- ---------------- 菜单:信息 > 会议纪要 ----------------
-- 父菜单 1774989374680858626 = 「信息」
INSERT IGNORE INTO `sys_menu`
(`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`)
VALUES
(2063809716454174722, '会议纪要', 1774989374680858626, 3,
'meeting', 'oa/meeting/index', 'C', '0', '0',
NULL, 'documentation', 'admin', NOW());
UPDATE `sys_menu` SET `icon` = 'documentation' WHERE `menu_id` = 2063809716454174722 AND (`icon` = '#' OR `icon` IS NULL);
-- ---------------- 角色授权(与「信息」下兄弟菜单一致的角色集) ----------------
INSERT IGNORE INTO `sys_role_menu` (`role_id`, `menu_id`)
VALUES
(1743186990678077442, 2063809716454174722), -- 总经理
(1743204526291349506, 2063809716454174722), -- 技术总监
(1743205028123045890, 2063809716454174722), -- 信息化部
(1852970465740505090, 2063809716454174722), -- 普通员工
(1859257980152692738, 2063809716454174722), -- 职工
(1859548445766717441, 2063809716454174722), -- 后勤
(1893987128812761089, 2063809716454174722), -- 新员工临时身份
(1914212623781187585, 2063809716454174722), -- 技术总工
(1914213026883162113, 2063809716454174722), -- 设计主任
(1925062159919448065, 2063809716454174722); -- 外贸专责
-- ---------------- 校验 ----------------
SELECT menu_id, menu_name, path, component, icon FROM sys_menu WHERE menu_id = 2063809716454174722;
SELECT dict_type, dict_label, dict_value FROM sys_dict_data
WHERE dict_type IN ('oa_meeting_type', 'oa_meeting_task_status') ORDER BY dict_type, dict_sort;