27 KiB
manager/meetings — 端到端技术审查
审查时间: 2026-08-18 触发场景: 用户访问
/manager/meetings(manager 角色) 审查范围:ry-vue3/src/views/manager/Meetings.vue(会议管理列表页) + 后端 BizMeeting 全链路 + DB 实测 对比原型:proto/html/components/meetings.html(我参与的会议 / doctor 端原型, 实装 manager 重用) 特别说明: 本页是 manager 端"会议管理"列表, 跟原型"我参与的会议"(doctor 端) 功能相近但角色不同 — 复用原型 UI 是合理的
修复记录 (2026-08-18 落实)
第一轮: 数据库正确性 (同 manager_meeting_new.md, 已 push)
(略 — 见 _self/manager_meeting_new.md §修复记录 第一轮; 共享 BizMeeting 实体/mapper/service)
第二轮: onCopy 改走 bizAdd + 三处双 toast (commit 08d81e9)
| 问题 | 修复 |
|---|---|
P0#3 onCopy bug — meetingId='' 走 bizUpdate → UPDATE 影响 0 行 + 误报"修改成功", 实际未创建副本 |
Meetings.vue:254-263 onCopy 加 editMode='copy' 标志; submitEdit() 按 mode 分支: copy 走 bizAdd('meeting', payload, { __silentError: true }) (删 meetingId, 走 AUTO_INCREMENT), edit 走 bizUpdate; Dialog title 动态 '复制会议' vs '修改会议'; Toast 文案动态 '复制成功' vs '修改成功' |
P0#4 双 toast (3 处) — submitEdit / onSubmit / onBatchSubmit 缺 __silentError, 拦截器+catch 双 toast |
三处 bizUpdate 都加 { __silentError: true }; catch 统一 `ElMessage.error(e?.msg |
附带: editForm 补 projectId / projectNo / projectName / currentStage (复制需要) |
Meetings.vue:222-231 加 4 字段; onEdit/onCopy 都从 row 回填 |
| 后端核对 | POST /business/meeting 已存在 (BizMeetingController.add:36-40); Mapper INSERT (BizMeetingMapper.xml:43-87) 已覆盖所有字段; Spring Boot 默认 fail-on-unknown=false, 前端发的 remark 字段被静默忽略, 不报错; meetingId 走 AUTO_INCREMENT; create_by/create_time/update_by/update_time 由 MyBatis-Plus MetaObjectHandler 自动填充; 后端零改动 ✅ |
0. 4 跳定位 (铁律: 不按名字猜)
| 跳 | 文件:行 | 结果 |
|---|---|---|
| ① 角色菜单 | ry-vue3/src/layout/AdminLayout.vue:99 |
path: '/manager/meetings', title: '会议管理' ✓ |
| ② 路由 | ry-vue3/src/router/index.js:69-70 |
name: 'manager-meetings', component: () => import('@/views/manager/Meetings.vue') ✓ |
| ③ 组件 | ry-vue3/src/views/manager/Meetings.vue (306 行) |
列表 + 筛选 + 批量提交 + 查看/修改/提交/复制 |
| ④ 原型 | proto/html/components/meetings.html |
"我参与的会议" 7 列表格 + 4 项筛选 (项目编号/会议名称/当前阶段/签署状态) |
1. 主要功能 + 可见性
1.1 主要功能
| 功能 | 前端入口 | 后端接口 | 数据表 |
|---|---|---|---|
| 筛选+分页列表 | Meetings.vue <el-table> + <el-pagination> |
GET /business/meeting/list (BizMeetingController:24-29) |
biz_meeting |
| 查看详情 (弹窗) | onView(row) → el-dialog (只读 el-descriptions) |
复用列表返回的 row, 不额外请求 | biz_meeting |
| 修改会议 (弹窗) | onEdit(row) → submitEdit() |
PUT /business/meeting (BizMeetingController:42-46) |
biz_meeting |
| 提交 (单条) | onSubmit(row) → 弹 confirm → bizUpdate |
PUT /business/meeting (BizMeetingController:42-46) |
biz_meeting (current_stage 改 "执行中") |
| 复制 (单条) | onCopy(row) → 打开 editForm (meetingId='') → submitEdit |
PUT /business/meeting ❌ 应 POST /business/meeting |
biz_meeting |
| 批量提交 (逐条) | onBatchSubmit() → for 循环 bizUpdate |
同上 × N 次 | biz_meeting |
1.2 可见性 (三层隔离)
| 层 | 来源 | 校验字段 |
|---|---|---|
| 前端菜单 | AdminLayout.vue:99 path: '/manager/meetings' |
角色 = manager |
| 路由守卫 | router/index.js:69-70 meta: { title: '会议管理' } (无 role 字段, 由 menu 拦截) |
role |
| 后端 SQL | BizMeetingMapper.xml:37-42 selectList 无任何过滤 ❌ |
无 (数据全量返回, 无 unit_type 隔离) |
严重问题: selectList 后端无任何条件, manager 端能 SELECT 出所有会议 (无 sponsor / executor / doctor 隔离)。当前 DB 7 行全测数据, 无用户敏感数据, 不算 leak, 但生产环境会有问题。
看不到本页面的人群:
- admin: 有独立
/admin/meetings(AdminLayout.vue:74) - leader: 有独立
/leader/meetings(AdminLayout.vue:92) - doctor: 有独立
/doctor/meetings(AdminLayout.vue:109) - executor: 有独立
/executor/meetings(AdminLayout.vue:117) - sponsor: 有独立
/sponsor/meetings(AdminLayout.vue:126)
数据隔离机制: ❌ 缺失 — manager 端没有按 lead_user_id = 当前 user_id 过滤, 也没用 @DataScope 注解。后端直接返回全表。
2. 筛选项 (filter-form)
| UI label | 控件 | 绑定字段 | 后端 SQL <if> |
命中表.字段 | 选项来源 | 原型对照 |
|---|---|---|---|---|---|---|
| 项目编号 | el-input (模糊) | q.projectNo |
❌ 缺失 | (无 WHERE) | — | ✅ 项目编号 (原型有) |
| 会议ID | el-input (精确) | q.meetingId |
❌ 缺失 | (无 WHERE) | — | ❌ 原型无此字段 (用户增, 但暴露 PK 是错的) |
| 会议名称 | el-input (模糊) | q.meetingName |
❌ 缺失 | biz_meeting.meeting_name |
— | ✅ 会议名称 (原型有) |
| 第?期 | el-input-number? (实际 el-input) | q.periodNo |
❌ 缺失 | biz_meeting.period_no |
— | ❌ 原型无 (实装增, 但 type=el-input 应该是 el-input-number) |
| 会议时间 (start~end) | el-date-picker × 2 | q.startTime, q.endTime |
❌ 缺失 | biz_meeting.start_time/end_time |
— | ❌ 原型无 (实装增, 但后端不接) |
| 项目形式 | el-select | q.projectForm |
❌ 缺失 | biz_meeting.project_form |
写死 4 项 (线上/线下/线上+线下/其他) | ❌ 原型无 |
| 当前阶段 | el-select | q.currentStage |
❌ 缺失 | biz_meeting.current_stage |
写死 4 项 (未执行/执行中/已执行/已完结) ❌ DDL 注释 7 项 | ✅ 当前阶段 (原型有, 但原型 2 项 "未开始/已结束") |
| 备注 | el-input (模糊) | q.remark |
❌ 缺失 | (无字段, biz_meeting 无 remark 列 ❌) | — | ❌ 原型无 |
汇总: 7 个 el-input/el-select 全部无效, 后端 mapper <where> 是空的 (BizMeetingMapper.xml:39-40):
<select id="selectList" resultMap="BizMeetingResult" parameterType="BizMeeting">
<include refid="selectFields"/>
<where>
</where>
order by meeting_id desc
</select>
核心 bug: 筛选功能全部失灵 — 点了"查找"也只按 meeting_id desc 排序返回全表。
3. 工具栏按钮 (toolbar)
| 按钮 | 功能 | 接口 (HTTP method + URL) | 涉及表 | 原型对照 |
|---|---|---|---|---|
| 查找 | 触发 load() → bizList |
GET /business/meeting/list?... |
biz_meeting |
✅ 查找 (原型有) |
| 重置 | 清空 q → load | 同上 | — | ❌ 原型无 |
| 批量提交 | onBatchSubmit() 逐条 update currentStage='执行中' |
PUT /business/meeting × N |
biz_meeting |
❌ 原型无 (manager 专属) |
提示行: <span v-if="selectedIds.length" class="filter-tip">已选 {{ selectedIds.length }} 条</span> — 跟 People.vue 的 <div class="filter-tip"> 一致 ✅
4. 表格 (el-table)
4.1 数据来源 (SQL 块)
完整 SQL (从 BizMeetingMapper.xml:29-32 selectFields):
select meeting_id, business_id, project_id, project_no, project_name, meeting_name, period_no, total_periods, project_form, start_time, end_time, org_name, current_stage, supervision_opinion, supervision_by, supervision_time, invitation_url, schedule_url, labor_signed, create_by, create_time, update_by, update_time
from biz_meeting
[WHERE] -- 全部条件都缺失, 见 §2
order by meeting_id desc
4.2 列映射
| 列名 | row.* | DB 表.字段 | 原型对照 |
|---|---|---|---|
| 多选框 | (selection) | — | ❌ 原型无 |
| 项目编号 | row.projectNo |
biz_meeting.project_no |
✅ 项目编号 |
| 会议ID | row.meetingId ❌ 暴露 PK |
biz_meeting.meeting_id |
❌ 原型无 (实装增, 应删) |
| 项目形式 | row.projectForm |
biz_meeting.project_form |
❌ 原型无 |
| 会议名称 | row.meetingName |
biz_meeting.meeting_name |
✅ 会议名称 |
| 会议开始时间 | row.startTime (fmtTime) |
biz_meeting.start_time |
❌ 原型无 |
| 会议结束时间 | row.endTime (fmtTime) |
biz_meeting.end_time |
❌ 原型无 |
| 总期数 | row.totalPeriods |
biz_meeting.total_periods |
❌ 原型无 |
| 期数 | row.periodNo ("第 X 期") |
biz_meeting.period_no |
❌ 原型无 |
| 当前阶段 | row.currentStage (stage-tag) |
biz_meeting.current_stage |
✅ 当前阶段 |
| 备注 | row.remark ❌ DB 无此字段, 永远空 |
(无) | ❌ 原型无 |
| 操作 | 查看/修改/提交/复制 (4 按钮) | — | ✅ 操作 (原型只有 1 个"签署劳务/查看劳务"按钮) |
新增列 (原型无, 实现增) ✅ 是改进:
- 项目形式, 会议开始/结束时间, 总期数, 期数 — 业务上必要
- 多选框 (用于批量提交) — manager 专属
- 操作列 4 按钮 — manager 端管理需要
遗漏列 (DB 有, 当前未显示):
org_name(公司名称, 冗余) — 列表可加create_time/update_time— 列表可加 (审计)supervision_opinion/supervision_by/supervision_time— 详情 dialog 有但列表无labor_signed(0/1) — 详情 dialog 有但列表无
5. 行内操作按钮
| 按钮 | 触发函数 | 接口 | 后端动作 | 涉及表.字段 | 原型对照 |
|---|---|---|---|---|---|
| 查看 | onView(row) |
(无, 用列表 row 数据) | 弹 detailOpen dialog | — | ❌ 原型无 (原型点会议名跳转 meeting-detail.html) |
| 修改 | onEdit(row) → submitEdit() |
PUT /business/meeting |
UPDATE biz_meeting SET meeting_name?, project_form?, start_time?, end_time?, total_periods?, remark? WHERE meeting_id=? | biz_meeting (6 字段) |
❌ 原型无 |
| 提交 | onSubmit(row) |
PUT /business/meeting |
UPDATE biz_meeting SET current_stage='执行中' WHERE meeting_id=? | biz_meeting.current_stage |
❌ 原型无 |
| 复制 | onCopy(row) → submitEdit() |
PUT /business/meeting ❌ 应 POST |
UPDATE WHERE meeting_id='' ❌ 0 rows affected | (无变化) | ❌ 原型无 |
真实落点:
- "提交": 直接改
current_stage = '执行中', 没有任何业务校验 (例如只能从未执行→执行中). 也不写日志 (biz_meeting_log等不存在). - "修改": 改 6 字段, 但 start_time/end_time/total_periods 没校验 (MeetingNew 的校验规则未共享).
核心 bug #2 (onCopy): Meetings.vue:254-263
function onCopy(row) {
Object.assign(editForm, {
meetingId: '', // ← 空字符串
meetingName: (row.meetingName || '') + ' 副本',
...
})
editOpen.value = true
}
submitEdit() 内部 await bizUpdate('meeting', { ...editForm }) → PUT /business/meeting 带 meetingId='' → UPDATE WHERE meeting_id='' → 0 行受影响 → 返回 toAjax(0) → 200 OK, 前端弹 "修改成功" → 实际未创建副本。
6. Java Entity ↔ 数据库表 一致性
6.1 biz_meeting 主表 DDL (实测, 2026-08-18)
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=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='会议表';
6.2 关联表 DDL (引用)
biz_project— 见manager_projects.md§6 + 最近ALTER TABLE加create_user_id(commitffda9c6)biz_person— 主键 person_id bigint, 唯一键 uk_person_user_id (user_id)
6.3 Entity ↔ 表字段对照表
| 实体字段 | 中文列名 (DB COMMENT) | 实体类型 | 表字段 | 表类型 | 一致? |
|---|---|---|---|---|---|
| meetingId | 会议ID | Long | meeting_id | bigint | ✅ (前轮修过 String→Long) |
| businessId | 业务编号ID | String | business_id | varchar(50) | ✅ |
| projectId | 关联项目ID | Long | project_id | bigint | ✅ (前轮修过 String→Long) |
| projectNo | 项目编号 | String | project_no | varchar(50) | ✅ |
| projectName | 项目名称 | String | project_name | varchar(200) | ✅ |
| meetingName | 会议名称 | String | meeting_name | varchar(200) | ✅ |
| periodNo | 期数 | Long | period_no | int | ⚠️ 类型不一致 (Long vs int) — 列表显示无问题, 但 editForm 初始化 `periodNo |
| totalPeriods | 总期数 | Long | total_periods | int | ⚠️ 类型不一致 (同 periodNo) |
| projectForm | 项目形式 | String | project_form | varchar(20) | ✅ |
| startTime | 会议开始时间 | Date | start_time | datetime | ✅ (前轮修过 String→Date + @JsonFormat) |
| 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 | 监察时间 | Date | supervision_time | datetime | ✅ (前轮修过 String→Date) |
| invitationUrl | 邀请函URL | String | invitation_url | varchar(500) | ✅ |
| scheduleUrl | 日程海报URL | String | schedule_url | varchar(500) | ✅ |
| laborSigned | 签署劳务 | String | labor_signed | char(1) | ✅ |
| createBy | 创建人 | String | create_by | varchar(64) | ✅ (BaseEntity 字段, 由 MetaObjectHandler 自动填) |
| createTime | 创建时间 | Date | create_time | datetime | ✅ |
| updateBy | 修改人 | String | update_by | varchar(64) | ✅ |
| updateTime | 修改时间 | Date | update_time | datetime | ✅ |
重大问题: 实体无 remark 字段, 但前端 Meetings.vue:32, 67, 125 都在用 q.remark / row.remark / editForm.remark ❌ 永远 null:
- 列表"备注"列永远空
- 详情 dialog"备注"行永远
-(Meetings.vue:102) - 修改 dialog 有"备注"输入框 (但写入 mapper
<if test="remark != null">也会失败 — MyBatis 找不到 setter)
BizMeetingMapper.xml:108 updateByPrimaryKey 也无 remark = #{remark} 的 if 块。
修订标记
- 第一轮: meetingId String→Long, supervisionTime String→Date, INSERT/UPDATE/selectFields 补漏, businessId 兜底生成 (已在 manager_meeting_new.md 第一轮完成)
7. 索引检查
7.1 biz_meeting 索引 (实测, 2026-08-18)
| Key | 列 | 用途覆盖 |
|---|---|---|
| PRIMARY | meeting_id |
✅ 默认 ORDER BY |
| uk_business_id | business_id (UNIQUE) |
✅ 雪花 ID 兜底生成防冲突 |
| idx_meeting_project | project_id |
✅ WHERE project_id = ? (项目侧查会议) |
| idx_meeting_stage | current_stage |
✅ WHERE current_stage = ? (filter 启用后生效) |
预期但缺失 (按 §2 筛选修复后需要):
idx_project_no(project_no varchar(50)) — filter "项目编号" 用LIKE模糊匹配, 小数据量可接受, 但生产 10k+ 项目需要idx_meeting_name(meeting_name varchar(200)) — filter "会议名称" 用LIKE模糊, 同上- 复合索引
(project_id, meeting_id)— JOIN 用, 当前单project_id够用
判定: 当前 7 行数据, 索引缺失影响可接受; 若按 §2 加全筛选, 需补 idx_project_no + idx_meeting_name。
8. 与原型差异 (实现偏离)
8.1 实现新增 (原型没有) — 改进
| 项 | 原型 | 实现 |
|---|---|---|
| 4 个 el-select 筛选 (会议ID/会议时间/项目形式/备注) | 无 | ✅ 是 manager 端管理需要 |
| 表格多选 + 批量提交 | 无 | ✅ manager 专属 |
| 操作列 4 按钮 (查看/修改/提交/复制) | 1 个 "签署劳务/查看劳务" | ✅ 是 (角色不同) |
| 分页 | 无 | ✅ 必要 |
| 弹窗 (查看/修改) | 跳转 meeting-detail.html | ✅ 弹窗更紧凑 |
| 详情 dialog 显示 submitDeadlineDays | 无 | ✅ 派生字段 |
8.2 原型有但实现缺失 — 回退
| 原型 | 实现 | 差距 |
|---|---|---|
| 项目编号/会议名称/当前阶段/签署状态 — 4 项筛选 | 8 项 | 原型"签署状态" → labor_signed 缺失 |
| 表格列: 项目编号/会议名称/当前阶段/日程/邀请函/签署状态/操作 (7 列) | 11 列 | 原型"日程"/"邀请函"/"签署状态"列未直接显示, 但有 schedule_url / invitation_url / labor_signed 字段, 可点操作查看 |
| 弹框 邀请函 + 日程 (原型 u11685/u11690 动态面板) | 无 | ❌ 原型专门有, 实现未做 |
| 红字提示 (*邀请函根据执行方上传…) (原型 u11590) | 无 | ❌ 原型顶部红字, 实现无 |
| 底部红字提示 (*未签署时显示…) (原型 u11592/u11594/u11681/u11683) | 无 | ❌ 同上 |
8.3 文字 / 标签差异
| 项 | 原型 | 实现 | 评估 |
|---|---|---|---|
| 面包屑 | 首页 > 我参与的会议 | 首页 / 会议管理 | ✅ 跟角色匹配 |
| 当前阶段 select | 未开始 / 已结束 | 未执行 / 执行中 / 已执行 / 已完结 | ⚠️ 命名风格不同, 实装更细 |
| 颜色 | #1890ff (浅蓝) |
var(--brand-primary) (深海军蓝) |
✅ 跟项目色系统一 |
8.4 总结
整体方向: 扩展 — 实现远超原型 (manager 端多 7 列 + 批量提交 + 修改 dialog); 原型的"邀请函/日程弹框"和"红字提示"未移植 (manager 角色下这些提示不太需要, 但建议加); 原型"签署状态"列未加 (manager 端不关注劳务签署)。
9. 表字段冗余 / 设计问题
9.1 实体 vs 表不一致 (详见 §6.3)
- ⚠️ 实体无
remark字段 — 前端 3 处使用, 全部 silent fail - ⚠️ periodNo/totalPeriods 类型不一致 — Long vs int, MyBatis 自动转换, 暂不修
9.2 selectList 无 WHERE 条件 (详见 §2)
- 全部筛选条件 mapper 不接, 用户体验: 选了筛选项 + 点查找 = 返回全表 ❌
9.3 业务闭环检查
onCopy实际是 INSERT (新建副本), 但走 bizUpdate → 0 行受影响 + 误报"修改成功"- 提交/批量提交无业务校验 (任何状态都能转 "执行中", 包括"已完结" → "执行中" 的状态回滚)
- 修改 dialog 无任何校验 (start_time > end_time 不报, meetingName 空不报)
- 修改 dialog 改 6 字段, 但 mapper UPDATE 只 6 个
<if>(跟前端一致 ✅), 但 缺remark<if>(实体无此字段)
9.4 双 toast bug (跨页面通用)
submitEdit/onSubmit/onBatchSubmit都未传{ __silentError: true }❌- 跟
MeetingNew.vue之前同款 bug (修过)
9.5 数据隔离缺失
BizMeetingMapper.xml:37-42 selectList无@DataScope或 manager 端限制- 当前 7 行数据无风险, 但生产环境 manager 应该只看自己 lead_user_id 的项目关联的会议 (应通过
biz_project.lead_user_id过滤)
10. 待修复列表 (按优先级)
| # | 问题 | 文件 | 修复建议 | 严重度 |
|---|---|---|---|---|
| 1 | 所有筛选不生效 (7 项) — mapper <where> 空 |
BizMeetingMapper.xml:39-40 |
加 8 个 <if> 条件: project_no LIKE, meeting_name LIKE, period_no =, project_form =, current_stage =, start_time >=, end_time <=, business_id = (如果还用 meetingId filter, 应改成业务字段) |
P0 |
| 2 | meetingId 列让用户看/筛 PK |
Meetings.vue:8, 49 |
删 filter (q.meetingId + 字段) + 删 el-table-column | P0 |
| 3 | onCopy bug — PUT 0 行 + 误报成功 |
Meetings.vue:254-263 + submitEdit() |
onCopy 改走 bizAdd('meeting', { ...不带 meetingId }); submitEdit 改成 if (editForm.meetingId) bizUpdate else bizAdd, 或拆成两个 dialog |
P0 ✅ 第二轮修 |
| 4 | 3 处缺 __silentError (双 toast) |
Meetings.vue:235, 247, 272 |
bizUpdate 调用加 { __silentError: true }, catch 里手动 ElMessage.error(e?.msg || '...') |
P0 ✅ 第二轮同commit修 |
| 5 | 实体无 remark 字段 — 前端 3 处 silent fail |
BizMeeting.java + BizMeetingMapper.xml UPDATE |
加 private String remark + getter/setter + mapper UPDATE 加 <if test="remark != null">remark = #{remark},</if> + INSERT 加 <if test="remark != null and remark != ''">remark,</if>; 或前端 3 处全删 (业务可能不需要) |
P0 |
| 6 | calcRemain 读 row.submitDeadlineDays (BizMeeting 无此字段) |
Meetings.vue:186 |
改成读 row.project?.submitDeadlineDays (需后端 JOIN biz_project); 或去掉此列 (manager 不太需要此字段) |
P1 |
| 7 | 当前阶段 select 只 4 项, DDL 列了 7 项 (未执行/执行中/监管通过/待整改/待结算/已结算/已结题) | Meetings.vue:25-31 + :62-66 (column) |
补 3 个 option + stageClass 已支持, OK | P1 |
| 8 | 详情 dialog 缺字段 (create_time / org_name / supervision_* / labor_signed / invitation_url / schedule_url) | Meetings.vue:91-103 |
el-descriptions 加 5-8 行; URL 字段加 <a :href> 链接 |
P1 |
| 9 | totalPeriods 永远 1 — MeetingNew.vue 没让填 |
MeetingNew.vue (新建表单) |
MeetingNew.vue 加"总期数"字段 (用户填, INSERT 时一起写); 列表列保留 | P1 |
| 10 | 批量提交无事务/无批量 endpoint | Meetings.vue:271-273 |
后端加 PUT /business/meeting/batch?ids=... + @Transactional; 前端 for 循环改成单次调用 |
P2 |
| 11 | filter 第?期 type=el-input 应是 el-input-number | Meetings.vue:10 |
改 <el-input-number v-model="q.periodNo" :min="1" /> |
P2 |
| 12 | filter 8 项挤一行 (屏幕窄乱) | Meetings.vue:6-37 |
拆 2 行, 或 grid-template-columns: repeat(4, 1fr) | P2 |
| 13 | 状态回滚无校验 (任何 stage → "执行中") | Meetings.vue:244-251 |
加 if (currentStage === '未执行') 才能提交, 否则 ElMessageBox 提示 | P2 |
| 14 | 数据隔离缺失 (selectList 无 lead_user_id 过滤) | BizMeetingMapper.xml:37-42 |
加 <if test="params.leadUserId != null">and project_id in (select project_id from biz_project where lead_user_id = #{params.leadUserId})</if> (需要后端传入当前 user_id) |
P2 (生产前必修) |
| 15 | filter 缺"签署状态" (原型有, 实体有 labor_signed) | Meetings.vue filter 加 |
加 <el-select v-model="q.laborSigned"> 2 option |
P2 |
| 16 | 筛选后端需补索引 (idx_project_no + idx_meeting_name) | biz_meeting table |
ALTER TABLE biz_meeting ADD KEY idx_project_no (project_no), ADD KEY idx_meeting_name (meeting_name); |
P3 (小数据量暂可) |
| 17 | 实体 periodNo/totalPeriods Long vs int | BizMeeting.java |
改 int, MyBatis INSERT 不需要 Long 转换 | P3 |
11. 引用清单
前端
ry-vue3/src/views/manager/Meetings.vue(306 行) — 本审查目标ry-vue3/src/views/manager/MeetingNew.vue— 新建会议独立页 (共享 BizMeeting)ry-vue3/src/layout/AdminLayout.vue:99— manager 菜单项 "会议管理"ry-vue3/src/router/index.js:69-70—/manager/meetings路由ry-vue3/src/utils/request.js:15-30— 响应拦截器 (code=200 直接放行 data, 错误触发__silentError跳过)ry-vue3/src/api/public.js:32, 92-93—bizList/bizUpdate/bizAdd
后端 (Java)
ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizMeetingController.java(54 行) — 5 个 endpoint (list/getInfo/add/edit/remove)ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizMeeting.java(104 行) — 实体 (24 字段, 缺 remark 字段; meetingId/supervisionTime 已修)ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizMeetingServiceImpl.java(34 行) — service 实现 (insert 调 SnowflakeId 兜底 businessId)ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizMeetingService.java— service 接口ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizMeetingMapper.java— mapper 接口
Mapper XML
ry-api/ruoyi-business/src/main/resources/mapper/business/BizMeetingMapper.xml(121 行) — selectList<where>是空的 (P0#1)
配置 / 工具
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:24 调 generateId)ry-api/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java:27— getUserId() (manager 端过滤可能用)
原型
proto/html/components/meetings.html(546 行) — "我参与的会议" 原型 (doctor 端)proto/html/components/meeting-detail.html— 会议详情页 (查看操作可跳转, 现用 el-dialog 替代)
数据库 (实测, 2026-08-18)
biz_meeting— 7 行, 4 索引 (PK + UNIQUE + 2 普通), 23 列 (含 meeting_id/business_id/project_id/project_no/project_name/meeting_name/period_no/total_periods/project_form/start_time/end_time/org_name/current_stage/supervision_opinion/supervision_by/supervision_time/invitation_url/schedule_url/labor_signed/create_by/create_time/update_by/update_time)biz_project— 12 行 (含最近ALTER TABLE ADD COLUMN create_user_id bigint, commitffda9c6)biz_person— JOIN 取姓名 (create_user_id → biz_person.user_id → biz_person.name)
历史修复 (跨 session)
- 第一轮 (manager_meeting_new.md commit
66a928a): 13 项 DB + 类型修复 - 第二轮 (manager_meeting_new.md commit
4fbfcbf+8f62f65+518da05+29a4b02+379cf22+ac31387): MeetingNew.vue 原型 1:1 重写 + 风格统一 + 双 toast 修复 - 第三轮 (commit
ffda9c6): biz_project 加 create_user_id - 第四轮 (commit
a081da8): MeetingNew.vue "期数" 文案改 "请填写第几期"