docs(manager_meetings): 重写, 按 skill 标准 11 章走, 修复记录归附录
This commit is contained in:
+186
-269
@@ -3,73 +3,18 @@
|
||||
> **审查时间**: 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 || '...')`, 拦截器不再自动 toast |
|
||||
| 附带: 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 自动填充; **后端零改动** ✅ |
|
||||
|
||||
### 第三轮: style-alignment + 批量提交按钮去 plain (commits `6d4f1e6` + `6774c44`)
|
||||
|
||||
| 问题 | 修复 |
|
||||
|---|---|
|
||||
| **批量提交按钮 disabled 顺色** (`type="primary" plain`) — outlined primary 在 disabled 状态下文字极淡灰色, 跟透明背景对比度低, 看不清 | `Meetings.vue:41` 去掉 `plain` 属性; 现 `<el-button type="primary" :disabled="!selectedIds.length">批量提交</el-button>` — disabled 状态浅蓝底 + 白字, 一眼可识别 |
|
||||
| **"已选 X 条" 提示紧贴按钮左边** — 应推到 batch-bar 最右侧 (跟 People.vue 风格一致) | `Meetings.vue:324 .filter-tip { ... margin-left: auto; }` |
|
||||
| `<span style="margin:0 4px">至</span>` — 残留 inline style | `Meetings.vue:13` 改 `<span class="date-sep">至</span>`; `Meetings.vue:325` 新增 `.date-sep { margin: 0 4px; color: #606266; }` |
|
||||
| `.batch-bar` 属性顺序跟 People.vue 不一致 | `Meetings.vue:323` 改成 `margin-bottom: 12px; display: flex; gap: 8px; align-items: center;` (margin 提前) |
|
||||
| 自查 (style-alignment 验证清单) | ✅ 1 层 page-card / ✅ breadcrumb / ✅ 无 desc / ✅ 无 h2 page-title / ✅ filter-form/batch-bar/pager 三 class / ✅ 蓝色全用 `var(--brand-primary)` 无 #1890ff / ✅ 边框全 #f0f0f0 无 #ebeef5 / ✅ 无 `:deep(.el-button--primary)` 大段覆盖 / ✅ el-pagination 在 .pager / ✅ el-form-item label 无冒号 / ✅ `<script>` 业务逻辑 100% 保留 (load/reset/view/edit/sub/copy/submit/batch 全在) |
|
||||
|
||||
### 第四轮: P0#1 selectList 加 7 个筛选 if (commit `14757f3`)
|
||||
|
||||
| 问题 | 修复 |
|
||||
|---|---|
|
||||
| **P0#1 mapper selectList `<where>` 空** — 8 项筛选全部不接 SQL, 用户选了筛选 + 点查找 = 返回全表 | `BizMeetingMapper.xml:37-50` 加 7 个 `<if>` 条件: project_no LIKE, meeting_id =, meeting_name LIKE, period_no =, project_form =, current_stage =, start_time >=, end_time <= (remark 字段跳过, 因为 biz_meeting 表无此列, 等 #5 一起修) |
|
||||
| **Date 字段 Spring 绑定问题** — `q.startTime = "2026-08-18 10:00:00"` 通过 axios GET 传到后端, Spring 默认 Converter 只支持 ISO-8601 (`2026-08-18T10:00:00`), 用空格分隔会 binding 失败 → 字段变 null → mapper `<if>` 跳过 → 实际筛选不生效 | `BizMeeting.java:30-33` 加 `@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")` 到 startTime/endTime (跟已有 @JsonFormat 并存, JSON 序列化 / Spring 绑定都支持); supervisionTime/createTime/updateTime 不加 (本次 filter 不涉及, 暂不扩大范围) |
|
||||
| 实测 (DB 查询) | `LIKE %ZH-2026-6%` → 5 行; `current_stage = 已结算` → 1 行; `start_time >= 2026-03-01` → 4 行; `period_no = 1` → 1 行; 全部条件 `AND` 组合也工作 ✅ |
|
||||
| ⚠️ 发现数据不一致 (本轮不修, 仅记录) | DB 实际 current_stage 值是: 0/已结算/已结题/待整改/待监管/监管通过 (6 种); DDL 注释写 7 种 (未执行/执行中/监管通过/待整改/待结算/已结算/已结题); 前端 select 是 4 种 (未执行/执行中/已执行/已完结) — **三者全不一致**! 用户即使 mapper 修了, 也筛不到任何 stage 因为 select 选项不在 DB 实际数据中. 待 P1#7 一并修. |
|
||||
| 前端不动 | `q` 的 8 项字段保持原样 (空字符串 / Long / Date 都有), Spring 默认 Converter 会把空字符串绑成 null, mapper `<if>` 跳过, 行为正确 |
|
||||
|
||||
### 第五轮: 恢复会议ID + 第?期 filter (commit pending)
|
||||
|
||||
> **修订**: 第四轮前后我曾误以为 `会议ID` / `第?期` 是用户新增字段不在原型, 一度删除. **用户澄清两个字段原型中都有, 必须保留**. 此轮修复:
|
||||
> - `Meetings.vue:8` 恢复 `<el-form-item label="会议ID">` (el-input, q.meetingId, 精确匹配 meeting_id PK)
|
||||
> - `Meetings.vue:10` 恢复 `<el-form-item label="第?期">` (**el-input-number, 不是 el-input** — 跟用户原话 "应该是 el-input-number" 对齐)
|
||||
> - `Meetings.vue:142-145` `q` reactive 加回 `meetingId:''` + `periodNo:''` 字段
|
||||
> - `Meetings.vue:206-209` `reset()` 加回 `meetingId:''` + `periodNo:''`
|
||||
> - `BizMeetingMapper.xml:41, 43` mapper `<if>` 块本就有, 这次没动 (第三轮已加)
|
||||
|
||||
| 验证 | 结果 |
|
||||
|---|---|
|
||||
| `q.meetingId = '14'` → 后端 `meeting_id = 14` | ✅ 1 行 (DB 实测) |
|
||||
| `q.periodNo = 1` → 后端 `period_no = 1` | ✅ 1 行 (DB 实测) |
|
||||
| 留空 (q.meetingId='', q.periodNo='') → 后端 null, mapper `<if>` 跳过 | ✅ 不影响其他筛选 |
|
||||
| el-input-number `:min="0" :precision="0"` | ✅ 输入非整数会被自动纠正; 留空显示空 (Spring 收到 null) |
|
||||
| §10 #2 / #11 同步更新 | #2 (删 filter) ❌ → ✅ 加回保留; #11 (改 el-input-number) ✅ 本轮同时修 |
|
||||
> **对比原型**: `proto/html/components/meetings.html` ("我参与的会议" doctor 端原型; 实装 manager 端复用 UI, 是合理的设计选择)
|
||||
|
||||
---
|
||||
|
||||
## 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` (343 行) | 列表 + 筛选 + 批量提交 + 查看/修改/提交/复制 |
|
||||
| ④ 原型 | `proto/html/components/meetings.html` | "我参与的会议" 7 列表格 + 4 项筛选 (项目编号/会议名称/当前阶段/签署状态) |
|
||||
| ④ 原型 | `proto/html/components/meetings.html` | 7 列表格 + 4 项筛选 (项目编号/会议名称/当前阶段/签署状态) |
|
||||
|
||||
---
|
||||
|
||||
@@ -79,114 +24,102 @@
|
||||
|
||||
| 功能 | 前端入口 | 后端接口 | 数据表 |
|
||||
|---|---|---|---|
|
||||
| 筛选+分页列表 | `Meetings.vue` `<el-table>` + `<el-pagination>` | `GET /business/meeting/list` (BizMeetingController:24-29) | `biz_meeting` |
|
||||
| 查看详情 (弹窗) | `onView(row)` → `el-dialog` (只读 el-descriptions) | 复用列表返回的 row, 不额外请求 | `biz_meeting` |
|
||||
| 筛选 + 分页列表 | `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 (`editMode='copy'`) → submitEdit 走 bizAdd | `POST /business/meeting` ✅ 第二轮修 | `biz_meeting` |
|
||||
| 批量提交 (逐条) | `onBatchSubmit()` → for 循环 bizUpdate | 同上 × N 次 | `biz_meeting` |
|
||||
| 提交 (单条) | `onSubmit(row)` → confirm → bizUpdate | `PUT /business/meeting` | `biz_meeting.current_stage` |
|
||||
| 复制 (单条) | `onCopy(row)` → `editMode='copy'` → `submitEdit` 走 bizAdd | `POST /business/meeting` | `biz_meeting` 新行 |
|
||||
| 批量提交 | `onBatchSubmit()` → for 循环逐条 bizUpdate | `PUT /business/meeting` × N | `biz_meeting.current_stage` |
|
||||
|
||||
### 1.2 可见性 (三层隔离)
|
||||
### 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 隔离)** |
|
||||
| 前端菜单 | `AdminLayout.vue:99` | 角色 = manager |
|
||||
| 路由守卫 | `router/index.js:69-70` | `meta.title` (无 role 字段, 由 menu 拦截) |
|
||||
| 后端 SQL | `BizMeetingMapper.xml:37 selectList` | **❌ 无任何过滤** — 后端全量返回, 不按 unit_type / lead_user_id 隔离 |
|
||||
|
||||
**严重问题**: `selectList` 后端无任何条件, manager 端能 SELECT 出所有会议 (无 sponsor / executor / doctor 隔离)。当前 DB 7 行全测数据, 无用户敏感数据, 不算 leak, 但生产环境会有问题。
|
||||
**数据隔离**: ❌ **缺失** — manager 端没有 `@DataScope` 或 `lead_user_id` 过滤。当前 DB 7 行测试数据无风险, 生产环境会暴露全部会议 (见 §10 #1)。
|
||||
|
||||
**看不到本页面的人群**:
|
||||
- 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` 注解。后端直接返回全表。
|
||||
**看不到本页面的人群**: admin / leader / doctor / executor / sponsor 各有独立 `/<role>/meetings` 路由 + 独立菜单项, 路由层就分开了。
|
||||
|
||||
---
|
||||
|
||||
## 2. 筛选项 (filter-form)
|
||||
|
||||
| UI label | 控件 | 绑定字段 | 后端 SQL `<if>` | 命中表.字段 | 选项来源 | 原型对照 |
|
||||
| UI label | 控件 | 绑定字段 | 后端 `<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 列 ❌) | — | ❌ 原型无 |
|
||||
| 项目编号 | el-input (模糊) | `q.projectNo` | ✅ `project_no LIKE concat('%',...)` | `biz_meeting.project_no` | — | ✅ 项目编号 |
|
||||
| 会议ID | el-input (精确) | `q.meetingId` | ✅ `meeting_id = #{meetingId}` | `biz_meeting.meeting_id` | — | ✅ 会议ID (原型有) |
|
||||
| 会议名称 | el-input (模糊) | `q.meetingName` | ✅ `meeting_name LIKE concat('%',...)` | `biz_meeting.meeting_name` | — | ✅ 会议名称 |
|
||||
| 第?期 | el-input-number | `q.periodNo` | ✅ `period_no = #{periodNo}` | `biz_meeting.period_no` | — | ✅ 第?期 (原型有) |
|
||||
| 会议时间 (start~end) | el-date-picker × 2 | `q.startTime`, `q.endTime` | ✅ `start_time >=` + `end_time <=` | `biz_meeting.start_time/end_time` | — | ❌ 原型无 (实现增) |
|
||||
| 项目形式 | el-select | `q.projectForm` | ✅ `project_form =` | `biz_meeting.project_form` | **写死** 4 项 (线上/线下/线上+线下/其他) | ❌ 原型无 (实现增) |
|
||||
| 当前阶段 | el-select | `q.currentStage` | ✅ `current_stage =` | `biz_meeting.current_stage` | **写死** 4 项 (未执行/执行中/已执行/已完结) ⚠️ | ✅ 原型有 (但原型是 未开始/已结束) |
|
||||
| 备注 | el-input (模糊) | `q.remark` | ❌ **缺失** — `biz_meeting` 无 `remark` 列 | (无字段) | — | ❌ 原型无 |
|
||||
|
||||
**汇总**: 7 个 el-input/el-select 全部无效, 后端 mapper `<where>` 是空的 (BizMeetingMapper.xml:39-40):
|
||||
**完整 SQL 块** (`BizMeetingMapper.xml:37-50`):
|
||||
|
||||
```xml
|
||||
<select id="selectList" resultMap="BizMeetingResult" parameterType="BizMeeting">
|
||||
<include refid="selectFields"/>
|
||||
<where>
|
||||
</where>
|
||||
order by meeting_id desc
|
||||
</select>
|
||||
```sql
|
||||
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 [project_no LIKE] [AND meeting_id =] [AND meeting_name LIKE]
|
||||
[AND period_no =] [AND project_form =] [AND current_stage =]
|
||||
[AND start_time >=] [AND end_time <=]
|
||||
order by meeting_id desc
|
||||
```
|
||||
|
||||
**核心 bug**: 筛选功能全部失灵 — 点了"查找"也只按 meeting_id desc 排序返回全表。
|
||||
8 项 filter 中 7 项生效; **remark filter 是死路** — 实体/表/INSERT 都没有此字段 (见 §6.3, §9 #3)。
|
||||
|
||||
---
|
||||
|
||||
## 3. 工具栏按钮 (toolbar)
|
||||
## 3. 工具栏 (filter-form / batch-bar)
|
||||
|
||||
| 按钮 | 功能 | 接口 (HTTP method + URL) | 涉及表 | 原型对照 |
|
||||
| 按钮 | 功能 | 接口 | 涉及表 | 原型对照 |
|
||||
|---|---|---|---|---|
|
||||
| 查找 | 触发 `load()` → bizList | `GET /business/meeting/list?...` | `biz_meeting` | ✅ 查找 (原型有) |
|
||||
| 查找 | 触发 `load()` → bizList | `GET /business/meeting/list?...` | `biz_meeting` | ✅ 查找 |
|
||||
| 重置 | 清空 q → load | 同上 | — | ❌ 原型无 |
|
||||
| 批量提交 | `onBatchSubmit()` 逐条 update currentStage='执行中' | `PUT /business/meeting` × N | `biz_meeting` | ❌ 原型无 (manager 专属) |
|
||||
| 批量提交 | `onBatchSubmit()` 逐条 update currentStage='执行中' | `PUT /business/meeting` × N | `biz_meeting.current_stage` | ❌ 原型无 (manager 专属) |
|
||||
|
||||
**提示行**: `<span v-if="selectedIds.length" class="filter-tip">已选 {{ selectedIds.length }} 条</span>` — 跟 People.vue 的 `<div class="filter-tip">` 一致 ✅
|
||||
**提示行**: `<span v-if="selectedIds.length" class="filter-tip">已选 N 条</span>` — 推到 batch-bar 最右 (`.filter-tip { margin-left: auto }`)。
|
||||
|
||||
---
|
||||
|
||||
## 4. 表格 (el-table)
|
||||
|
||||
### 4.1 数据来源 (SQL 块)
|
||||
### 4.1 数据来源
|
||||
|
||||
完整 SQL (从 `BizMeetingMapper.xml:29-32` `selectFields`):
|
||||
|
||||
```sql
|
||||
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
|
||||
```
|
||||
见 §2 完整 SQL 块 (从 `BizMeetingMapper.xml:37-50` selectList + `BizMeetingMapper.xml:29-32` selectFields)。
|
||||
|
||||
### 4.2 列映射
|
||||
|
||||
| 列名 | row.* | DB 表.字段 | 原型对照 |
|
||||
|---|---|---|---|
|
||||
| 多选框 | (selection) | — | ❌ 原型无 |
|
||||
| 多选框 | (selection) | — | ❌ 原型无 (manager 专属) |
|
||||
| 项目编号 | `row.projectNo` | `biz_meeting.project_no` | ✅ 项目编号 |
|
||||
| 会议ID | `row.meetingId` ❌ 暴露 PK | `biz_meeting.meeting_id` | ❌ 原型无 (实装增, 应删) |
|
||||
| 项目形式 | `row.projectForm` | `biz_meeting.project_form` | ❌ 原型无 |
|
||||
| 会议ID | `row.meetingId` | `biz_meeting.meeting_id` | ✅ 会议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 个"签署劳务/查看劳务"按钮) |
|
||||
| 备注 | `row.remark` (永远空, 见 §9 #3) | (无) | ❌ 原型无 |
|
||||
| 操作 | 查看/修改/提交/复制 | — | ❌ 原型 1 个按钮 (签署劳务), manager 端 4 按钮 |
|
||||
|
||||
**新增列 (原型无, 实现增)** ✅ 是改进:
|
||||
- 项目形式, 会议开始/结束时间, 总期数, 期数 — 业务上必要
|
||||
- 多选框 (用于批量提交) — manager 专属
|
||||
- 操作列 4 按钮 — manager 端管理需要
|
||||
**新增列 (原型无, 实现增) ✅ 改进**: 项目形式, 开始/结束时间, 总期数, 期数, 多选框, 4 个操作按钮。
|
||||
|
||||
**遗漏列 (DB 有, 当前未显示)**:
|
||||
- `org_name` (公司名称, 冗余) — 列表可加
|
||||
- `create_time` / `update_time` — 列表可加 (审计)
|
||||
- `supervision_opinion` / `supervision_by` / `supervision_time` — 详情 dialog 有但列表无
|
||||
- `labor_signed` (0/1) — 详情 dialog 有但列表无
|
||||
**遗漏列 (DB 有, 列表未显示)**:
|
||||
- `org_name` (公司名称) — 列表可加
|
||||
- `create_time` / `update_time` — 审计可用
|
||||
- `labor_signed` (0/1) — 原型有 "签署状态" 列
|
||||
- `invitation_url` / `schedule_url` — 原型有, 当前只在详情 dialog
|
||||
|
||||
---
|
||||
|
||||
@@ -194,42 +127,25 @@ order by meeting_id desc
|
||||
|
||||
| 按钮 | 触发函数 | 接口 | 后端动作 | 涉及表.字段 | 原型对照 |
|
||||
|---|---|---|---|---|---|
|
||||
| 查看 | `onView(row)` | (无, 用列表 row 数据) | 弹 detailOpen dialog | — | ❌ 原型无 (原型点会议名跳转 meeting-detail.html) |
|
||||
| 查看 | `onView(row)` | (无) | 弹 detailOpen dialog | — | ❌ 原型跳转 detail 页 |
|
||||
| 修改 | `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()` (走 `bizAdd`) | `POST /business/meeting` ✅ 第二轮修 | INSERT biz_meeting (...) VALUES (...); meetingId AUTO_INCREMENT, businessId 兜底 | `biz_meeting` (新行) | ❌ 原型无 |
|
||||
| 复制 | `onCopy(row)` → `submitEdit()` (走 `bizAdd`) | `POST /business/meeting` | INSERT biz_meeting (...); meetingId AUTO_INCREMENT, businessId 兜底雪花 ID | `biz_meeting` (新行) | ❌ 原型无 |
|
||||
|
||||
**真实落点**:
|
||||
- "提交": 直接改 `current_stage = '执行中'`, 没有任何业务校验 (例如只能从未执行→执行中). 也不写日志 (`biz_meeting_log` 等不存在).
|
||||
- "修改": 改 6 字段, 但 start_time/end_time/total_periods 没校验 (MeetingNew 的校验规则未共享).
|
||||
|
||||
**核心 bug #2** (`onCopy`) — 第二轮已修 ✅: `Meetings.vue:282-299 onCopy`
|
||||
|
||||
```js
|
||||
function onCopy(row) {
|
||||
editMode.value = 'copy' // ← 标志为复制模式
|
||||
Object.assign(editForm, {
|
||||
meetingId: '', // ← 空字符串 (复制时不要传, 走 AUTO_INCREMENT)
|
||||
meetingName: (row.meetingName || '') + ' 副本',
|
||||
projectId: row.projectId ?? null,
|
||||
...
|
||||
})
|
||||
editOpen.value = true
|
||||
}
|
||||
```
|
||||
|
||||
`submitEdit()` 按 `editMode` 分支: copy 走 `bizAdd('meeting', payload, { __silentError: true })` (删 meetingId), edit 走 `bizUpdate`。第二轮回滚/回退风险已消除: 后端零改动, 仅前端分支。
|
||||
- **"提交"**: 直接 `UPDATE current_stage = '执行中'`, 无业务校验 (任何状态都能转, 包括"已完结"→"执行中" 状态回滚)。不写日志 (`biz_meeting_log` 表不存在)。
|
||||
- **"修改"**: 改 6 字段 (无 `remark`, 详见 §9 #3); start_time > end_time 不校验; meetingName 空不校验。
|
||||
|
||||
---
|
||||
|
||||
## 6. Java Entity ↔ 数据库表 一致性
|
||||
|
||||
### 6.1 biz_meeting 主表 DDL (实测, 2026-08-18)
|
||||
### 6.1 biz_meeting DDL (实测 2026-08-18)
|
||||
|
||||
```sql
|
||||
CREATE TABLE `biz_meeting` (
|
||||
`meeting_id` bigint NOT NULL AUTO_INCREMENT COMMENT '会议ID',
|
||||
`business_id` varchar(50) NOT NULL COMMENT '业务编号ID 5643145673',
|
||||
`business_id` varchar(50) NOT NULL COMMENT '业务编号ID',
|
||||
`project_id` bigint DEFAULT NULL COMMENT '关联项目ID',
|
||||
`project_no` varchar(50) DEFAULT NULL COMMENT '项目编号',
|
||||
`project_name` varchar(200) DEFAULT NULL COMMENT '项目名称',
|
||||
@@ -255,217 +171,218 @@ CREATE TABLE `biz_meeting` (
|
||||
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='会议表';
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4
|
||||
COLLATE=utf8mb4_0900_ai_ci COMMENT='会议表';
|
||||
```
|
||||
|
||||
### 6.2 关联表 DDL (引用)
|
||||
### 6.2 关联表
|
||||
|
||||
- `biz_project` — 见 `manager_projects.md` §6 + 最近 `ALTER TABLE` 加 `create_user_id` (commit ffda9c6)
|
||||
- `biz_person` — 主键 person_id bigint, 唯一键 uk_person_user_id (user_id)
|
||||
- `biz_project` — 见 `manager_projects.md` §6, 最近 `ALTER TABLE ADD COLUMN create_user_id bigint`
|
||||
- `biz_person` — PK `person_id`, UNIQUE `uk_person_user_id (user_id)`, 用于 JOIN 取 create_user_name
|
||||
|
||||
### 6.3 Entity ↔ 表字段对照表
|
||||
|
||||
| 实体字段 | 中文列名 (DB COMMENT) | 实体类型 | 表字段 | 表类型 | 一致? |
|
||||
|---|---|---|---|---|---|
|
||||
| meetingId | 会议ID | Long | meeting_id | bigint | ✅ (前轮修过 String→Long) |
|
||||
| meetingId | 会议ID | Long | meeting_id | bigint | ✅ |
|
||||
| businessId | 业务编号ID | String | business_id | varchar(50) | ✅ |
|
||||
| projectId | 关联项目ID | Long | project_id | bigint | ✅ (前轮修过 String→Long) |
|
||||
| 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** | ⚠️ 类型不一致 (Long vs int) — 列表显示无问题, 但 editForm 初始化 `periodNo || 0` 走 Long, INSERT mapper 用 `<if test="periodNo != null">#{periodNo}</if>` Long 入 int 列, MyBatis 自动转换 OK |
|
||||
| totalPeriods | 总期数 | Long | total_periods | int | ⚠️ 类型不一致 (同 periodNo) |
|
||||
| periodNo | 期数 | **Long** | period_no | **int** | ⚠️ 类型不一致 (MyBatis 自动转 OK) |
|
||||
| totalPeriods | 总期数 | **Long** | total_periods | **int** | ⚠️ 类型不一致 (同上) |
|
||||
| projectForm | 项目形式 | String | project_form | varchar(20) | ✅ |
|
||||
| startTime | 会议开始时间 | Date | start_time | datetime | ✅ (前轮修过 String→Date + @JsonFormat) |
|
||||
| startTime | 会议开始时间 | Date | start_time | datetime | ✅ (有 @JsonFormat + @DateTimeFormat) |
|
||||
| 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) |
|
||||
| supervisionTime | 监察时间 | Date | supervision_time | datetime | ✅ (有 @JsonFormat) |
|
||||
| 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 自动填) |
|
||||
| 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` 字段) | — | (无 `remark` 列) | — | ❌ **实体缺 remark 字段** (见 §9 #3) |
|
||||
|
||||
**重大问题**: 实体**无 `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 第一轮完成)
|
||||
**修订记录** (本节实体版本演进):
|
||||
- 第一轮: meetingId String→Long, supervisionTime String→Date, INSERT/UPDATE/selectFields 补漏, businessId 雪花 ID 兜底 (commit 66a928a, 共享 manager_meeting_new.md)
|
||||
- 第四轮: startTime/endTime 加 `@DateTimeFormat` (commit 14757f3) — 让前端 `"2026-08-18 10:00:00"` 字符串能 Spring 绑定到 Date
|
||||
|
||||
---
|
||||
|
||||
## 7. 索引检查
|
||||
|
||||
### 7.1 biz_meeting 索引 (实测, 2026-08-18)
|
||||
| 表 | Key | 列 | 用途覆盖 |
|
||||
|---|---|---|---|
|
||||
| biz_meeting | PRIMARY | meeting_id | ✅ ORDER BY + WHERE meeting_id = |
|
||||
| biz_meeting | uk_business_id | business_id (UNIQUE) | ✅ 雪花 ID 防冲突 |
|
||||
| biz_meeting | idx_meeting_project | project_id | ✅ `WHERE project_id =` (项目侧查会议) |
|
||||
| biz_meeting | idx_meeting_stage | current_stage | ✅ `WHERE current_stage =` (filter 启用后生效) |
|
||||
|
||||
| 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。
|
||||
**缺失但暂可接受** (按 §2 筛选启用后):
|
||||
- `idx_project_no` — `LIKE '%xxx%'` 模糊匹配无法走索引, 但当前 7 行可接受 (见 §10 #6)
|
||||
- `idx_meeting_name` — 同上
|
||||
- 复合 `(project_id, meeting_id)` — JOIN 用, 当前单 `project_id` 索引够
|
||||
|
||||
---
|
||||
|
||||
## 8. 与原型差异 (实现偏离)
|
||||
## 8. 与原型差异
|
||||
|
||||
### 8.1 实现新增 (原型没有) — **改进**
|
||||
|
||||
| 项 | 原型 | 实现 |
|
||||
|---|---|---|
|
||||
| 4 个 el-select 筛选 (会议ID/会议时间/项目形式/备注) | 无 | ✅ 是 manager 端管理需要 |
|
||||
| 表格多选 + 批量提交 | 无 | ✅ manager 专属 |
|
||||
| 操作列 4 按钮 (查看/修改/提交/复制) | 1 个 "签署劳务/查看劳务" | ✅ 是 (角色不同) |
|
||||
| 分页 | 无 | ✅ 必要 |
|
||||
| 弹窗 (查看/修改) | 跳转 meeting-detail.html | ✅ 弹窗更紧凑 |
|
||||
| 详情 dialog 显示 submitDeadlineDays | 无 | ✅ 派生字段 |
|
||||
| 项 | 原型 | 实现 | 评估 |
|
||||
|---|---|---|---|
|
||||
| 筛选 会议ID / 第?期 / 会议时间 / 项目形式 / 备注 | 4 项 | 8 项 | ✅ manager 端管理需要 |
|
||||
| 表格多选 + 批量提交 | 无 | ✅ | manager 专属 |
|
||||
| 操作列 4 按钮 (查看/修改/提交/复制) | 1 按钮 | ✅ | 角色不同 |
|
||||
| 分页 | 无 | ✅ | 必要 |
|
||||
| 弹窗 (查看/修改) | 跳转 meeting-detail.html | ✅ 弹窗紧凑 |
|
||||
|
||||
### 8.2 原型有但实现缺失 — **回退**
|
||||
|
||||
| 原型 | 实现 | 差距 |
|
||||
|---|---|---|
|
||||
| 项目编号/会议名称/当前阶段/签署状态 — 4 项筛选 | 8 项 | 原型"签署状态" → `labor_signed` 缺失 |
|
||||
| 表格列: 项目编号/会议名称/当前阶段/日程/邀请函/签署状态/操作 (7 列) | 11 列 | 原型"日程"/"邀请函"/"签署状态"列未直接显示, 但有 `schedule_url` / `invitation_url` / `labor_signed` 字段, 可点操作查看 |
|
||||
| 弹框 邀请函 + 日程 (原型 u11685/u11690 动态面板) | 无 | ❌ 原型专门有, 实现未做 |
|
||||
| 红字提示 (*邀请函根据执行方上传…) (原型 u11590) | 无 | ❌ 原型顶部红字, 实现无 |
|
||||
| 底部红字提示 (*未签署时显示…) (原型 u11592/u11594/u11681/u11683) | 无 | ❌ 同上 |
|
||||
| "签署状态" 列 (`labor_signed`) | 仅 filter 8 项无此 (见 §10 #4) | ❌ 缺 filter + 列 |
|
||||
| 弹框 邀请函 + 日程 (原型动态面板) | 无 | ❌ 原型专门有 |
|
||||
| 顶部红字提示 | 无 | ❌ |
|
||||
|
||||
### 8.3 文字 / 标签差异
|
||||
|
||||
| 项 | 原型 | 实现 | 评估 |
|
||||
|---|---|---|---|
|
||||
| 面包屑 | 首页 > 我参与的会议 | 首页 / 会议管理 | ✅ 跟角色匹配 |
|
||||
| 当前阶段 select | 未开始 / 已结束 | 未执行 / 执行中 / 已执行 / 已完结 | ⚠️ 命名风格不同, 实装更细 |
|
||||
| 颜色 | `#1890ff` (浅蓝) | `var(--brand-primary)` (深海军蓝) | ✅ 跟项目色系统一 |
|
||||
| 面包屑 | 首页 > 我参与的会议 | 首页 / 会议管理 | ✅ 角色匹配 |
|
||||
| 当前阶段 select | 未开始 / 已结束 | 未执行 / 执行中 / 已执行 / 已完结 | ⚠️ 实装更细, 但跟 DB 实际数据不一致 (见 §9 #1) |
|
||||
| 颜色 | `#1890ff` (浅蓝) | `var(--brand-primary)` (深海军蓝) | ✅ 项目色 |
|
||||
|
||||
### 8.4 总结
|
||||
|
||||
**整体方向**: **扩展** — 实现远超原型 (manager 端多 7 列 + 批量提交 + 修改 dialog); 原型的"邀请函/日程弹框"和"红字提示"未移植 (manager 角色下这些提示不太需要, 但建议加); 原型"签署状态"列未加 (manager 端不关注劳务签署)。
|
||||
**整体方向**: **扩展** — 实现远超原型 (manager 端多 5 列 + 批量提交 + 修改 dialog); 原型"邀请函/日程弹框"和"签署状态"未移植; "红字提示"未加。
|
||||
|
||||
---
|
||||
|
||||
## 9. 表字段冗余 / 设计问题
|
||||
## 9. 设计问题
|
||||
|
||||
### 9.1 实体 vs 表不一致 (详见 §6.3)
|
||||
> 集中列设计层面问题, 不重复 §10 (待修复)。已修的归附录 "修复记录"。
|
||||
|
||||
- **⚠️ 实体无 `remark` 字段** — 前端 3 处使用, 全部 silent fail
|
||||
- **⚠️ periodNo/totalPeriods 类型不一致** — Long vs int, MyBatis 自动转换, 暂不修
|
||||
### 9.1 当前阶段 select 与 DB 实际数据不一致
|
||||
|
||||
### 9.2 selectList 无 WHERE 条件 (详见 §2)
|
||||
DDL 注释列了 7 种 (未执行/执行中/监管通过/待整改/待结算/已结算/已结题), 但 DB 实际 6 种 (0/已结算/已结题/待整改/待监管/监管通过), 前端 select 又是另一套 4 种 (未执行/执行中/已执行/已完结)。**三者全不一致**, filter 启用后用户选"未执行"也筛不到任何数据。
|
||||
|
||||
- 全部筛选条件 mapper 不接, 用户体验: 选了筛选项 + 点查找 = 返回全表 ❌
|
||||
### 9.2 calcRemain 读不存在的字段
|
||||
|
||||
### 9.3 业务闭环检查
|
||||
`Meetings.vue:186` 读 `row.submitDeadlineDays`, 但 `BizMeeting` 实体无此字段 (BizProject 才有)。当前永远 fallback 到 30 天, 是个静默 bug (见 §10 #2)。
|
||||
|
||||
- ✅ `onCopy` 已走 `bizAdd` (第二轮修) — 现在正确创建副本
|
||||
- ⚠️ 提交/批量提交无业务校验 (任何状态都能转 "执行中", 包括"已完结" → "执行中" 的状态回滚) — 未修
|
||||
- ⚠️ 修改 dialog 无任何校验 (start_time > end_time 不报, meetingName 空不报) — 未修
|
||||
- ⚠️ 修改 dialog 改 6 字段, 但 mapper UPDATE 只 6 个 `<if>` (跟前端一致 ✅), 但 **缺 `remark` `<if>`** (实体无此字段) — 未修
|
||||
### 9.3 实体无 remark 字段
|
||||
|
||||
### 9.4 双 toast bug (跨页面通用) ✅ 第二轮已修
|
||||
前端 3 处使用 (`Meetings.vue:32 q.remark`, `:67 row.remark`, `:125 editForm.remark`), 但 `BizMeeting` 实体无 `remark`, 表也无 `remark` 列。后果:
|
||||
- filter "备注" 永远无效 (Spring `@ModelAttribute` 绑定到不存在的 setter 报 IllegalArgumentException? 实测 silent fail)
|
||||
- 列表"备注"列永远空
|
||||
- 详情 dialog"备注"行永远 `-`
|
||||
- 修改 dialog "备注"输入框写入 → mapper UPDATE 无对应 `<if>` → 静默丢
|
||||
|
||||
- `submitEdit` / `onSubmit` / `onBatchSubmit` 三处 `bizUpdate`/`bizAdd` 都加 `{ __silentError: true }`
|
||||
- catch 统一 `ElMessage.error(e?.msg || '...')`, 拦截器不再自动 toast
|
||||
- 跟 `MeetingNew.vue` 之前同款 bug 一起消除 ✅
|
||||
修复路径有 2 条 (见 §10 #3)。
|
||||
|
||||
### 9.5 UI 顺色 / 样式问题 ✅ 第三轮已修
|
||||
### 9.4 数据隔离缺失 (manager 端)
|
||||
|
||||
- ✅ 批量提交按钮 `type="primary" plain` disabled 时文字顺色 — 已去 `plain`
|
||||
- ✅ "已选 X 条" 紧贴按钮左边 — 已 `margin-left: auto` 推右
|
||||
- ✅ `<span style="margin:0 4px">至</span>` inline style — 已抽 `.date-sep` class
|
||||
- ✅ `.batch-bar` 属性顺序 — 已跟 People.vue 对齐
|
||||
`BizMeetingMapper.xml:37 selectList` 无 `@DataScope` 或 `lead_user_id` 过滤。当前测试数据无风险, 生产必修 (见 §10 #1)。
|
||||
|
||||
### 9.6 数据隔离缺失
|
||||
### 9.5 状态回滚无校验
|
||||
|
||||
- `BizMeetingMapper.xml:37-42 selectList` 无 `@DataScope` 或 manager 端限制
|
||||
- 当前 7 行数据无风险, 但生产环境 manager 应该只看自己 lead_user_id 的项目关联的会议 (应通过 `biz_project.lead_user_id` 过滤)
|
||||
"提交" 操作任何 stage 都能转 "执行中", 包括 "已完结" → "执行中" (状态回滚)。应加前置校验 (见 §10 #5)。
|
||||
|
||||
---
|
||||
|
||||
## 10. 待修复列表 (按优先级)
|
||||
## 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**~~ ✅ 第六轮修 (commit 14757f3) |
|
||||
| 2 | **`meetingId` 列让用户看/筛 PK** | `Meetings.vue:8, 49` | ~~删 filter~~ — **用户澄清原型中有, 保留 filter + 列** (本轮加回) | ~~**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="0" :precision="0" />` | ~~**P2**~~ ✅ 第五轮同 commit 修 |
|
||||
| 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** |
|
||||
| 18 | **批量提交按钮 plain + disabled 顺色** | `Meetings.vue:41` | 去掉 `plain` 属性 | ~~**P2**~~ ✅ 第三轮修 (commit 6774c44) |
|
||||
| 19 | **"已选 X 条" 紧贴按钮左边** | `Meetings.vue:324` | `.filter-tip { margin-left: auto }` | ~~**P2**~~ ✅ 第三轮同 commit 修 |
|
||||
| 20 | **inline style `margin:0 4px` 残留** ("至") | `Meetings.vue:13` | 抽 `.date-sep` class | ~~**P3**~~ ✅ 第三轮修 (commit 6d4f1e6) |
|
||||
| 1 | **数据隔离缺失** (selectList 无 lead_user_id 过滤) | `BizMeetingMapper.xml:37` | 加 `<if test="params.leadUserId != null">and project_id in (select project_id from biz_project where lead_user_id = #{params.leadUserId})</if>`; Controller 注入当前 user_id | **P0** (生产必修) |
|
||||
| 2 | **`calcRemain` 读 `row.submitDeadlineDays`** (BizMeeting 无此字段) | `Meetings.vue:186` | 改成读 `row.project?.submitDeadlineDays` (后端 JOIN biz_project); 或去此字段 (manager 不需要) | **P1** |
|
||||
| 3 | **实体无 `remark` 字段** (前端 3 处 silent fail) | `BizMeeting.java` + `BizMeetingMapper.xml` | 路径 A: 加 `private String remark` + getter/setter + mapper UPDATE/INSERT 加 `<if>`; 路径 B: 前端 3 处全删 (业务可能不需要) | **P1** |
|
||||
| 4 | **filter 缺"签署状态"** (原型有, 实体有 `labor_signed`) | `Meetings.vue` filter + table column | 加 `<el-select v-model="q.laborSigned">` 2 option + table 加列 | **P2** |
|
||||
| 5 | **状态回滚无校验** (任何 stage → "执行中") | `Meetings.vue:271-273 onSubmit` + `:302-309 onBatchSubmit` | 加 `if (currentStage === '未执行')` 才能提交, 否则 ElMessageBox 提示 | **P2** |
|
||||
| 6 | **筛选后端需补索引** (`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);` (⚠️ `LIKE '%xxx%'` 模糊匹配无法走索引, 实际效果有限) | **P3** |
|
||||
| 7 | **实体 periodNo/totalPeriods Long vs int** | `BizMeeting.java` | 改 int, MyBatis INSERT 不需 Long 转换 | **P3** |
|
||||
| 8 | **当前阶段 select 选项跟 DB 实际数据不一致** (见 §9 #1) | `Meetings.vue:25-31` | 改成跟 DB 一致 (已结算/已结题/待整改/待监管/监管通过 等), 或加 DB 不存在的值 (DB 加 ENUM 同步) | **P1** |
|
||||
| 9 | **filter 8 项挤一行** (屏幕窄乱) | `Meetings.vue:6-37` | 拆 2 行, 或 grid-template-columns: repeat(4, 1fr) | **P2** |
|
||||
| 10 | **批量提交无事务/无批量 endpoint** | `Meetings.vue:302-309` | 后端加 `PUT /business/meeting/batch?ids=...` + `@Transactional`; 前端 for 循环改单次调用 | **P2** |
|
||||
| 11 | **详情 dialog 缺字段** (create_time / org_name / supervision_* / labor_signed / invitation_url / schedule_url) | `Meetings.vue:91-103` | el-descriptions 加 5-8 行; URL 字段加 `<a :href>` 链接 | **P1** |
|
||||
| 12 | **`totalPeriods` 永远 1** (MeetingNew.vue 没让填) | `MeetingNew.vue` | 加"总期数"字段 (用户填, INSERT 时一起写) | **P1** |
|
||||
|
||||
---
|
||||
|
||||
## 11. 引用清单
|
||||
|
||||
### 前端
|
||||
- `ry-vue3/src/views/manager/Meetings.vue` (343 行) — 本审查目标
|
||||
- `ry-vue3/src/views/manager/Meetings.vue:343` — 本审查目标
|
||||
- `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/layout/AdminLayout.vue:99` — manager 菜单项
|
||||
- `ry-vue3/src/router/index.js:69-70` — 路由
|
||||
- `ry-vue3/src/utils/request.js:15-30` — axios 拦截器 (`__silentError` 跳过 toast)
|
||||
- `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 接口
|
||||
- `ry-api/ruoyi-business/.../controller/BizMeetingController.java:54` — 5 endpoints
|
||||
- `ry-api/ruoyi-business/.../domain/BizMeeting.java:107` — 24 字段, **缺 remark**
|
||||
- `ry-api/ruoyi-business/.../service/impl/BizMeetingServiceImpl.java:34` — insert 调 SnowflakeId 兜底 businessId
|
||||
- `ry-api/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-business/src/main/resources/mapper/business/BizMeetingMapper.xml:128` — selectList 7 个 `<if>` 已生效
|
||||
|
||||
### 配置 / 工具
|
||||
- `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 端过滤可能用)
|
||||
- `ry-api/ruoyi-common/src/main/java/com/ruoyi/common/utils/id/SnowflakeId.java` — 雪花 ID 生成器
|
||||
- `ry-api/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java:27` — getUserId()
|
||||
|
||||
### 原型
|
||||
- `proto/html/components/meetings.html` (546 行) — "我参与的会议" 原型 (doctor 端)
|
||||
- `proto/html/components/meeting-detail.html` — 会议详情页 (查看操作可跳转, 现用 el-dialog 替代)
|
||||
- `proto/html/components/meetings.html:546` — "我参与的会议" 原型 (doctor 端, 实装 manager 重用)
|
||||
- `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`, commit ffda9c6)
|
||||
- `biz_person` — JOIN 取姓名 (create_user_id → biz_person.user_id → biz_person.name)
|
||||
### 数据库 (实测 2026-08-18)
|
||||
- `biz_meeting` — 7 行, 4 索引 (PK + UNIQUE + 2 普通), 23 列 (见 §6.1)
|
||||
- `biz_project` — 12 行, 含 `create_user_id bigint` (commit ffda9c6)
|
||||
- `biz_person` — JOIN `user_id → name`
|
||||
|
||||
### 历史修复 (跨 session, 本页相关)
|
||||
- 第一轮 (manager_meeting_new.md commit 66a928a): 13 项 DB + 类型修复 (影响共享 BizMeeting)
|
||||
- 第二轮 (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 "期数" 文案改 "请填写第几期"
|
||||
- 第五轮 — Meetings.vue 第一波修复 (commit 08d81e9): onCopy 改 bizAdd + 三处 __silentError
|
||||
- 第五轮 — Meetings.vue style-alignment (commit 6d4f1e6): 删 inline margin, batch-bar 顺序对齐, 加 .date-sep
|
||||
- 第五轮 — Meetings.vue 批量按钮去 plain (commit 6774c44): disabled 顺色修 + 提示 margin-left:auto
|
||||
- 第五轮 (续) — Meetings.vue 恢复会议ID + 第?期 filter (commit pending): 误删 2 个 filter 后用户澄清加回, 第?期同步改 el-input-number
|
||||
---
|
||||
|
||||
## 附录: 修复记录 (按 commit 时间倒序)
|
||||
|
||||
> 已修的问题不进入 §10。本节按 commit 顺序列出, 每条标明 issue → fix → 验证。
|
||||
|
||||
### A.5 commit `bae9fa6` (2026-08-18) — 恢复会议ID + 第?期 filter (第五轮续)
|
||||
|
||||
- **背景**: 第四轮前后曾误删 `会议ID` / `第?期` filter, 用户澄清两个字段原型中都有.
|
||||
- **修改**: `Meetings.vue:8` 加回 `<el-form-item label="会议ID">` (el-input); `Meetings.vue:10` 第?期从 el-input 改 el-input-number (`:min="0" :precision="0"`); `q` reactive + `reset()` 加回 `meetingId:''`; mapper `<if>` 块本就有, 无需动.
|
||||
- **验证**: `q.meetingId=14` → 1 行; `q.periodNo=1` → 1 行; 留空 → 不影响其他筛选.
|
||||
|
||||
### A.4 commit `14757f3` (2026-08-18) — mapper selectList 加 7 个筛选 if + @DateTimeFormat (第四轮)
|
||||
|
||||
- **解决**: P0#1 全部筛选不生效 (`<where>` 空).
|
||||
- **修改**: `BizMeetingMapper.xml:37-50` 加 7 个 `<if>` (project_no LIKE, meeting_id =, meeting_name LIKE, period_no =, project_form =, current_stage =, start_time >=, end_time <=); `BizMeeting.java:30-33` startTime/endTime 加 `@DateTimeFormat` 让 Spring 能绑字符串.
|
||||
- **验证**: `LIKE %ZH-2026-6%` → 5 行; `current_stage=已结算` → 1 行; `start_time>=2026-03-01` → 4 行; `period_no=1` → 1 行; 组合 AND 正常.
|
||||
|
||||
### A.3 commits `6d4f1e6` + `6774c44` (2026-08-18) — style-alignment + 批量按钮去 plain (第三轮)
|
||||
|
||||
- **解决**: 批量按钮 disabled 顺色; "已选 X 条" 紧贴按钮左边; inline style 残留; batch-bar 属性顺序.
|
||||
- **修改**: `Meetings.vue:41` 批量按钮去 `plain`; `Meetings.vue:324 .filter-tip { margin-left: auto }`; `<span class="date-sep">至</span>` 替代 inline style; `.batch-bar` 属性顺序对齐 People.vue.
|
||||
|
||||
### A.2 commit `08d81e9` (2026-08-18) — onCopy 改 bizAdd + 三处双 toast (第二轮)
|
||||
|
||||
- **解决**: P0#3 onCopy bug (meetingId='' 走 bizUpdate → 0 行 + 误报成功); P0#4 双 toast.
|
||||
- **修改**: `Meetings.vue:222-228 editMode` ref + `Meetings.vue:246-267 submitEdit()` 按 editMode 分支 (copy → bizAdd, edit → bizUpdate); 三处 bizUpdate 加 `{ __silentError: true }`.
|
||||
|
||||
### A.1 commit `66a928a` (跨 session, manager_meeting_new.md 第一轮) — 数据库正确性
|
||||
|
||||
- 共享 `BizMeeting` 修复: meetingId String→Long, supervisionTime String→Date, INSERT/UPDATE/selectFields 补漏, businessId 雪花 ID 兜底 (13 项).
|
||||
- 详细见 `manager_meeting_new.md` §修复记录 第一轮.
|
||||
|
||||
### 跨页相关 commit (影响本页但不直接修改)
|
||||
- `ffda9c6` — biz_project 加 `create_user_id` (影响 §6.2)
|
||||
- `a081da8` — MeetingNew.vue "期数" 文案改 "请填写第几期" (独立页)
|
||||
- `4fbfcbf` + `8f62f65` + `518da05` + `29a4b02` + `379cf22` + `ac31387` — MeetingNew.vue 原型 1:1 重写 + 双 toast 修复
|
||||
Reference in New Issue
Block a user