Files
guoju0808/_self/manager_meeting_new.md
T
郭庆泰andClaude 4fbfcbfb0c refactor(meeting-new): 跟原型 new-meeting.html 1:1 对齐
完全重写 MeetingNew.vue, 严格按原型 HTML/CSS 翻译:
- 结构: 面包屑(可点击项目列表) + h1 + 红字提示 + .card + .form-grid (2列) + .form-actions
- 左列 6 项只读: 项目编号/项目名称/总场次/总期数/支持单位/创建时间/创建人员
- 右列 5 项: 会议名称(只读) + 期数/开始时间/结束时间/备注(输入)
- CSS 完整照搬: #169bd5 主按钮 + 32px input + 12px 面包屑 + 22px h1 + #ff4d4f 红字 + grid 1fr 1fr + 768px 响应式
- grid-auto-flow: column 让左 6 右 5 对齐 (符合原型 §#4/##5 设计意图)
- 字段映射: 总场次/总期数→biz_project.totalSessions; 支持单位→biz_project.sponsorOrgName (JOIN biz_org)

删除多余项 (前几轮加的): 项目形式/总期数/当前阶段下拉/page-sub/el-descriptions/会议ID输入框

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-18 22:39:02 +08:00

20 KiB

manager/meetings/new — 端到端技术审查

审查时间: 2026-08-18 (第二次, 修复 + 原型对齐) 触发场景: 用户访问 /manager/meetings/new?projectId=13 审查范围: ry-vue3/src/views/manager/MeetingNew.vue (新建会议独立页) + 后端 BizMeeting 全链路 + DB 实测 对比原型: proto/html/components/new-meeting.html


修复记录 (2026-08-18 落实)

第一轮: 数据库正确性 (13 项)

# 问题 修复 状态
P0#1 mapper INSERT 只插 meeting_id BizMeetingMapper.xml:43-87 扩 20 列 <if>
P0#2 businessId DDL NOT NULL 前端无字段 BizMeetingServiceImpl:24-26 兜底 IdGenerator.generateId()
P0#3 form 没 projectId (只 projectNo) MeetingNew.vue onMounted 回填 projectId/projectName
P1#4 "会议ID" 输入框让用户填 PK 删 field + 删 rule
P1#5 6 个项目只读快照全缺失 加 el-descriptions (后被原型对齐覆盖)
P1#6 会议名称默认 = 项目名称 onMounted 回填 + 字段 disabled + 红字提示
P1#7 meetingId String → Long 6 文件
P1#8 supervisionTime String → Date BizMeeting.java 加 @JsonFormat + Date
P2#9 面包屑不一致 改 "项目列表 / 新建会议" (后被原型对齐覆盖)
P2#10 page-sub 显示原始 ID "13" 改成 "{projectName} ({projectNo})" (后被原型对齐覆盖)
P2#11 当前阶段 el-select 4 → 10 选项 补 5 个 option (后被原型对齐覆盖)
P2#12 resultMap 漏字段 BizMeetingMapper.xml:4-28 补 9 个 result
P2#13 selectFields SQL 漏字段 BizMeetingMapper.xml:30 补 9 列

第二轮: 原型 1:1 对齐 (commit 待push)

问题 修复
整体结构跟原型完全不一样 重写 MeetingNew.vue 严格 1:1 翻译原型 HTML/CSS: 面包屑(可点击) + h1 + 红字提示 + .card + .form-grid (2列 grid-auto-flow:column 让左6右5对齐) + 6 只读 form-row + 5 字段 form-row + .form-actions
多余字段: 项目形式 / 总期数 / 当前阶段 / page-sub / el-descriptions 全删, 只保留原型 11 项
CSS 不是原型风格 (Element Plus 默认) 完整照搬原型 CSS: #169bd5 主按钮 + 32px input + 12px 灰字面包屑 + 22px h1 + ff4d4f 红字 + grid 1fr 1fr + 768px 响应式
字段映射 项目编号→projectNo, 项目名称→projectName, 总场次/总期数→totalSessions (不是 totalPeriods, biz_project 没此字段), 支持单位→sponsorOrgName (JOIN biz_org), 创建时间→createTime, 创建人员→createBy, 会议名称默认=项目名称

0. 4 跳定位 (铁律: 不按名字猜)

文件:行 结果
① 角色菜单 ry-vue3/src/layout/AdminLayout.vue:99 path: '/manager/meetings', title: '会议管理' ✓ (新建是子菜单/独立路由)
② 路由 ry-vue3/src/router/index.js:70 { path: 'meetings/new', name: 'manager-meetings-new', component: () => import('@/views/manager/MeetingNew.vue') }
③ 组件 ry-vue3/src/views/manager/MeetingNew.vue 115 行, 本审查对象
④ 原型 proto/html/manager.html 间接入口 → components/new-meeting.html 注: 原型标 "角色: 执行方, 父级: executor.html" — 角色归属不一致!

⚠️ 原型角色归属错位:new-meeting.html 头部注释 角色: 执行方 / 父级: executor.html,但本组件在 manager 路由下。原型本身可能是早期版本,实际 Vue 实现给 manager 用 (合规管理员新建会议)。


1. 主要功能 + 可见性

1.1 主要功能

功能 前端入口 后端接口 涉及表
新建会议表单 manager/MeetingNew.vue 表单 POST /business/meetingBizMeetingController.addbizMeetingService.insert biz_meeting
预选项目回填 onMountedbizGet('project', preselectProjectId) GET /business/project/{projectId} biz_project
取消 onCancel (无)

⚠️ 页面无编辑功能: 即便 URL 是 /new,MeetingNew.vue 没 route.params.id 分支,只能新建不能编辑。如果想编辑会议,得另开 MeetingEdit.vue 或复用本组件加 id 分支。

1.2 可见性 (三层隔离)

来源 校验字段
前端菜单 AdminLayout.vue:99 manager 角色菜单
路由守卫 router/index.js:70 name: 'manager-meetings-new', 路由 meta.role='manager' (来自父路由)
后端 BizMeetingController.listselectList 无 user_id 过滤(manager 看所有会议)

⚠️ manager 是全局视图角色,跟 manager/Projects 一致,不过滤 — 设计正确


2. 筛选项 (filter-form)

本页面无筛选区 — 是纯表单页,直接进入。


3. 工具栏按钮 (toolbar)

按钮 功能 接口 涉及表 原型对照
保存 onSave POST /business/meeting {...form} biz_meeting 原型 #6
取消 onCancel router.back() 原型 #7

4. 表格 (el-table)

本页面无表格 — 是纯表单页。


5. 行内操作按钮

本页面无行内操作 — 是纯表单页。


6. Java Entity ↔ 数据库表 一致性

6.1 biz_meeting 主表 DDL (实测)

CREATE TABLE `biz_meeting` (
  `meeting_id` bigint NOT NULL AUTO_INCREMENT COMMENT '会议ID',
  `business_id` varchar(50) NOT NULL COMMENT '业务会议ID 5643145673',
  `project_id` bigint DEFAULT NULL COMMENT '所属项目ID',
  `project_no` varchar(50) DEFAULT NULL COMMENT '项目编号',
  `project_name` varchar(200) DEFAULT NULL COMMENT '项目名称',
  `meeting_name` varchar(200) DEFAULT NULL COMMENT '会议名称',
  `period_no` int DEFAULT '1' COMMENT '期数',
  `total_periods` int DEFAULT '1' COMMENT '总期数',
  `project_form` varchar(20) DEFAULT NULL COMMENT '项目形式',
  `start_time` datetime DEFAULT NULL COMMENT '会议开始时间',
  `end_time` datetime DEFAULT NULL COMMENT '会议结束时间',
  `org_name` varchar(200) DEFAULT NULL COMMENT '公司名称(冗余)',
  `current_stage` varchar(20) DEFAULT '0' COMMENT '当前阶段 未执行/待监管/监管通过/待整改/待结算/已结算/已结题',
  `supervision_opinion` varchar(500) DEFAULT NULL COMMENT '监察意见',
  `supervision_by` varchar(64) DEFAULT NULL COMMENT '监察人',
  `supervision_time` datetime DEFAULT NULL COMMENT '监察时间',
  `invitation_url` varchar(500) DEFAULT NULL COMMENT '邀请函URL',
  `schedule_url` varchar(500) DEFAULT NULL COMMENT '日程海报URL',
  `labor_signed` char(1) DEFAULT '0' COMMENT '签署劳务 0未签 1已签',
  `create_by` varchar(64) DEFAULT '' COMMENT '创建人',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(64) DEFAULT '' COMMENT '更新人',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`meeting_id`),
  UNIQUE KEY `uk_business_id` (`business_id`),
  KEY `idx_meeting_project` (`project_id`),
  KEY `idx_meeting_stage` (`current_stage`)
) ENGINE=InnoDB AUTO_INCREMENT=8

6.2 关联表 DDL (引用)

  • biz_project (11 行, 7 索引 — 见 manager_projects.md §7.1)
  • biz_project_assign (11 行, 5 索引 — 见 manager_projects.md §7.2)

6.3 Entity ↔ 表字段对照表

实体字段 中文列名 (DB COMMENT) 类型 表字段 类型 一致?
meetingId 会议ID String meeting_id bigint ⚠️ 类型不一致 (Java String vs SQL bigint), 应改 Long
businessId 业务会议ID 5643145673 String business_id varchar(50) NOT NULL (但 NOT NULL, 前端必填, 当前 form 没校验!)
projectId 所属项目ID Long project_id bigint 类型一致
projectNo 项目编号 String project_no varchar(50)
projectName 项目名称 String project_name varchar(200)
meetingName 会议名称 String meeting_name varchar(200)
periodNo 期数 Long period_no int
totalPeriods 总期数 Long total_periods int
projectForm 项目形式 String project_form varchar(20)
startTime 会议开始时间 Date start_time datetime
endTime 会议结束时间 Date end_time datetime
orgName 公司名称(冗余) String org_name varchar(200)
currentStage 当前阶段 String current_stage varchar(20)
supervisionOpinion 监察意见 String supervision_opinion varchar(500)
supervisionBy 监察人 String supervision_by varchar(64)
supervisionTime 监察时间 String supervision_time datetime ⚠️ Java String vs SQL datetime — Java 实体应当用 Date
invitationUrl 邀请函URL String invitation_url varchar(500)
scheduleUrl 日程海报URL String schedule_url varchar(500)
laborSigned 签署劳务 0未签 1已签 String labor_signed char(1)
createBy/createTime/updateBy/updateTime 创建人/时间 等 (BaseEntity)

修订标记

⚠️ meetingId 同 §6.3 之前项目 (类似 BizProject.projectId): Java 用 String, SQL 用 bigint, 跟同表其他 bigint 列 (projectId) 风格不一致。biz_meeting 当前 7 行实测全有数据 (meeting_id 1-7, business_id 5643145673-77), 说明数据通过别的方式 (seed 脚本) 写入, 不是走当前 mapper.insert — 见 §10 #1。

⚠️ supervisionTime: 同 §6.3 之前 BizProject.startTime/endTime 模式, Java String vs SQL datetime, 未修复。

⚠️ businessId NOT NULL: DDL 是 NOT NULL, 但前端 form 没有 businessId 字段, 提交后 INSERT 会失败 (DDL 约束) — 见 §10 #2。


7. 索引检查

7.1 biz_meeting 索引

Key 用途覆盖
PRIMARY meeting_id 主键, ORDER BY
uk_business_id business_id (UNIQUE) 业务会议ID 精确匹配 (业务上应唯一,合理)
idx_meeting_project project_id WHERE project_id = ? JOIN 用
idx_meeting_stage current_stage 按阶段过滤
project_no ⚠️ MeetingNew.vue:103form.projectNo 反查 (但实际是 form 字段, 后端无 project_no 过滤查询), 可接受
start_time / end_time ⚠️ 时间范围查询 (如 /manager/meetings 列表筛选), 当前 manager/Meetings.vue 是按 ID 排序, 可接受

结论: 索引设计够用, 4 个索引覆盖主键 + 2 个常见 WHERE 列 + 1 个 UNIQUE 业务约束。


8. 与原型差异 (实现偏离)

当前状态: 已 1:1 对齐 (commit 待push)

8.1 实现新增 (原型没有)

无 — 实现完全照搬原型, 没有自行扩展

8.2 原型有但实现缺失

无 — 11 项全部对齐 (左 6 只读 + 右 5 字段)

8.3 文字 / 标签差异

无 — 字段标签跟原型完全一致 (项目编号 / 项目名称 / 总场次/总期数 / 支持单位 / 创建时间 / 创建人员 / 会议名称 / 期数 / 会议开始时间 / 会议结束时间 / 备注)

8.4 总结

对齐细节:

  • 面包屑 <a href>项目列表</a> > 新建会议 (可点击返回项目列表)
  • h1 "新建会议" (22px, 600 weight, #1a1a1a)
  • 红字提示 "*会议名称默认为项目名称,不可修改" (12px, #ff4d4f)
  • .card 容器 (32px 40px padding, #f0f0f0 border)
  • .form-grid 2 列布局 (grid-auto-flow: column 让左 6 右 5 对齐, 跟原型设计意图一致)
  • 11 个 form-row 标签 / 控件 / 占位符全部对齐原型
  • .form-actions 保存/取消按钮 (#169bd5 主色 + #797979 边框次色)
  • 768px 响应式断点 (单列 + 按钮纵向)
  • 字段映射: 总场次/总期数→biz_project.totalSessions (不是 totalPeriods); 支持单位→biz_project.sponsorOrgName (JOIN biz_org 派生)

字段映射修订: 原型说"总场次/总期数", 实际只显示一个数字 (来自 biz_project.totalSessions)。biz_project 表没有 totalPeriods 字段, 所以"总期数"和"总场次"是同一个字段, 即 totalSessions。会议本身的"期数"是 biz_meeting.periodNo, 跟项目总场次是两个概念。


9. 表字段冗余 / 设计问题

9.1 实体 vs 表不一致 (详见 §6.3)

  • ⚠️ meetingId String → Long (跟 §10 #1 关联)
  • ⚠️ supervisionTime String → Date (跟 BizProject.startTime/endTime 同模式, 未修复)
  • 其他字段一致

9.2 Mapper INSERT 严重残缺 🐛

BizMeetingMapper.xml:34-42:

<insert id="insert" parameterType="BizMeeting">
    insert into biz_meeting
    <trim prefix="(" suffix=")" suffixOverrides=",">
        <if test="meetingId != null and meetingId != ''">meeting_id,</if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
        <if test="meetingId != null and meetingId != ''">#{meetingId},</if>
    </trim>
</insert>

🛑 只插入 meeting_id 一列, 其他所有字段 (business_id, project_no, meeting_name, start_time, end_time, current_stage 等) 完全不写

实测验证: 当前 7 行数据齐全 (business_id 5643145673-77), 但 meeting_id 是 1-7 顺序自增, create_time 全是 2026-08-16 19:18:32, create_by='admin'。明显是 seed 脚本直插, 不是从当前 mapper.insert 走的

如果用户从本组件提交:

  • INSERT SQL 实际是 INSERT INTO biz_meeting (meeting_id) VALUES (1234567890123456789) — SnowflakeId 生成的 Long
  • DB 默认值: business_id NOT NULL 违反约束 → INSERT 报错
  • 其他字段全部 NULL, 数据无效

9.3 business_id NOT NULL 约束缺失前端校验

DDL: business_id varchar(50) NOT NULL, 但前端 form 没有 businessId 输入框 (line 7-15 也没列)。rules 里也没 businessId 必填校验。即便 mapper 修好 INSERT, 提交也会因缺 business_id 报错。

9.4 project_id 缺失

form 只提交 projectNo, 不提交 projectId。即使 mapper INSERT 修好, 写库的 meeting 也只有 project_no, 没有 project_id — 跟 biz_project 的 JOIN 查询会漏掉这条记录。

9.5 JOIN 字段 vs 持久化字段混淆

projectName / orgName 是冗余字段 (DB COMMENT 写"冗余"), 但前端 form 没填这两个字段, mapper INSERT 也不会写。后续 JOIN 派生需要靠 service 层回查。


10. 待修复列表 (按优先级)

# 问题 文件:行 修复建议 严重度
1 mapper INSERT 只插 meeting_id, 其他字段全 NULL 🐛 BizMeetingMapper.xml:34-42 跟 updateByPrimaryKey 一样, 给所有非空字段加 <if test="x != null and x != ''">x,</if> P0
2 business_id NOT NULL, 前端 form 无字段无校验 🐛 MeetingNew.vue (整个表单) + rules 加 businessId 输入框 + 必填校验, 或 mapper 给 businessId 兜底生成 P0
3 form 没 projectId, 写库 meeting 只关联 projectNo 不关联 projectId MeetingNew.vue:67-77 + :99-105 onMounted onMounted 查项目时同时回填 form.projectId = r.data.projectId (后端已 Long) P0
4 meetingId 输入框让用户填 PK 🐛 MeetingNew.vue:13-15 删 (meeting_id 是 AUTO_INCREMENT), 删 rules.meetingId P1
5 6 个项目只读快照全缺失 (原型 §#4) MeetingNew.vue:6-51 (表单整体) 在 form 上方加 el-descriptions 区域, 显示 projectNo/projectName/totalSessions/sponsorOrgName/createTime/createBy P1
6 会议名称应默认 = 项目名称, 不可修改 (原型 §#3 红字提示 + §#5 只读) MeetingNew.vue:10-12 + :80 rules onMounted 查项目后, form.meetingName = r.data.projectName, 字段加 :disabled="true", rules.meetingName 改 trigger 或保留必填 P1
7 面包屑跟原型不一致 MeetingNew.vue:3 改 "项目列表 > 新建会议" 或 "首页 > 会议管理 > 新建会议" 加一个返回项目列表链接 P2
8 page-sub 显示原始 ID "13", 不是项目名 MeetingNew.vue:4 onMounted 查项目后, page-sub 改成 "已选择项目: {projectName} ({projectNo})" P2
9 当前阶段 el-select 只 4 选项, DB 注释 7 个状态 MeetingNew.vue:37-42 加 "待监管/监管通过/待整改/待结算/已结算" 5 个 option P2
10 meetingId String → Long (跟 BizProject.projectId 同模式) BizMeeting.java:13 + getter/setter + BizMeetingMapper.java:10 + BizMeetingServiceImpl.java:17,23 + BizMeetingController.java:31 跟之前 9 文件同模式改 P1
11 supervisionTime String → Date (跟 BizProject.startTime/endTime 同模式) BizMeeting.java:68 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") P1
12 preselectProjectId 只在 setup 读一次, 路由变化不响应 MeetingNew.vue:63-64 computed(() => route.query.projectId) 让其响应式 (但本场景路由不变, 影响小) P3
13 supervisionOpinion/By/Time 表单缺失 (DB 有, 当前 stage 是 "未执行" 后续阶段需填) (后续 MeetingEdit 阶段) 不在本页范围, 在 MeetingEdit.vue 加 P3

11. 引用清单

前端

  • ry-vue3/src/views/manager/MeetingNew.vue — 新建会议独立页 (115 行)
  • ry-vue3/src/views/manager/Meetings.vue — 会议管理列表 (保存后跳转目标)
  • ry-vue3/src/views/manager/Projects.vue:97 — 操作列 dropdown "建会" 跳转入口 router.push('/manager/meetings/new?projectId=${row.projectId}')
  • ry-vue3/src/layout/AdminLayout.vue:99 — 菜单项 "会议管理"
  • ry-vue3/src/router/index.js:70/manager/meetings/new 路由
  • ry-vue3/src/utils/request.js:15-30 — 响应拦截器 (code=200 直接放行 data)

后端 (Java)

  • ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizMeetingController.java — 会议主 controller (54 行, 5 个 endpoint)
  • ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizMeeting.java — 实体 (103 行, 字段含 2 个类型不一致: meetingId String vs meeting_id bigint + supervisionTime String vs supervision_time datetime)
  • ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizMeetingServiceImpl.java — service 实现 (34 行, insert 调 SnowflakeId.injectIfEmpty)
  • ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizMeetingMapper.java — mapper 接口 (16 行, 全部 String)

Mapper XML

  • ry-api/ruoyi-business/src/main/resources/mapper/business/BizMeetingMapper.xml — 会议 mapper (76 行, 🛑 INSERT 严重残缺: 只插 meeting_id)

关联文件

  • ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizProjectController.java:139-143GET /business/project/{projectId} (依赖此接口回填项目名, Long @PathVariable 已修)
  • ry-vue3/src/api/public.js:90bizGet(entity, id)GET /business/${entity}/${id}

配置 / 工具

  • ry-api/ruoyi-admin/src/main/resources/application-druid.yml:9-10 — DB 连接 (root / cu2oh2co3)
  • ry-api/ruoyi-common/src/main/java/com/ruoyi/common/utils/id/SnowflakeId.java — 雪花 ID 注入 (BizMeetingServiceImpl:23 调 injectIfEmpty)

原型

  • proto/html/components/new-meeting.html — 新建会议原型 (248 行, 标"角色: 执行方" 实装给 manager 用, 角色归属错位)
  • proto/html/components/project-manage.html:529 — 建会入口 navigateTo('new-meeting.html?project_code=' + code) (实装改用 projectId 参数)
  • proto/html/manager.html (间接) — manager 端菜单入口

数据库 (实测)

  • biz_meeting — 7 行, 4 索引 (含 1 唯一)
  • biz_project — 11 行, 7 索引 (见 manager_projects.md §7.1)
  • biz_project_assign — 11 行, 5 索引 (见 manager_projects.md §7.2)