Files
guoju0808/_self/manager_meetings.md
T
郭庆泰 c3eb8ed9c3 feat: OCR 服务 + 会议材料模块
ry-ocr/ (新)
  本地发票识别微服务 (PaddleOCR 3.x + FastAPI, 8801)
  - QR 优先: 扫到二维码即取开票时间/发票号/金额; 没扫到/格式不合法直接判非发票, 不跑 OCR
  - 配置 QR_FULL_OCR 控制快路径(false, 0.2s)还是全字段(true, 4.5s)
  - /recognize/invoice (multipart) + /recognize/invoice/by-path (本地路径, 白名单) + /recognize/text
  - is_invoice / from_qr / qr_raw / qr_error / error_code 字段
  - 12 字段发票抽取 (regex + 启发式, 左右主体识别)
  - 超时保护 (15s 单页 / 60s 总流程) + PaddleOCR 单例 + ThreadPoolExecutor

ry-api/ruoyi-business/
  - pom.xml: 加 hutool-http/json/core 5.8.27, lombok 1.18.30 (OcrClient @Slf4j 所需)
  - ocr/: OcrClient + InvoiceResult/Fields/Line + ZipExtractor + InvoiceOcrScheduler
  - oss/: OssUploader + OssConfMeta (OCR 识别后重传 OSS)
  - config/: OcrConfig + OcrExecutorConfig (后台线程池)
  - service/impl/InvoiceOcrService: 后台提交 OCR, ZIP 路径解压识别, 替换场景先清旧
  - 会议材料 CRUD 全套 (BizMeetingAuditLog/Executor/Invoice/Material/Supervisor):
    controller + service + mapper + domain + xml

ry-vue3/
  - MeetingDetail.vue (新建): 会议详情页 (含评分维度章节, 改只读)
  - Meetings.vue / OssFileUploader.vue / router / Login.vue: 适配新字段

ry-api/ruoyi-admin/
  - RuoYiApplication.java + application.yml: 启用 @Async 异步支持

_self/
  - manager_meetings.md / manager_meeting_detail.md: 文档
2026-08-22 00:23:22 +08:00

28 KiB
Raw Blame History

manager/meetings — 端到端技术审查

审查时间: 2026-08-21 (v3) 触发场景: 用户访问 /manager/meetings (manager 角色), 修复 label/期数/placeholder + 后端 long→int + 查看按钮跳页面 审查范围: ry-vue3/src/views/manager/Meetings.vue (会议管理列表页) + MeetingDetail.vue (新) + 后端 BizMeeting 全链路 + DB 实测 对比原型: proto/html/components/meeting-manage.html (manager.html:207 链接, manager 角色专用原型) 修订: v3 覆盖 v2, "查看"按钮从 dialog 改为独立路由 /manager/meetings/detail/:meetingId (MeetingDetail.vue)


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

文件:行 内容
① 角色菜单 ry-vue3/src/layout/AdminLayout.vue:97 path: '/manager/meetings', title: '会议管理'
② 路由 ry-vue3/src/router/index.js:65-66 name: 'manager-meetings' → @/views/manager/Meetings.vue + name: 'manager-meetings-new' → MeetingNew.vue
③ 组件 ry-vue3/src/views/manager/Meetings.vue (256 行) 列表 + 筛选 + 批量提交 + 查看/修改/提交/复制
④ 原型 proto/html/components/meeting-manage.html (618 行, manager.html:207 data-page="components/meeting-manage.html") 12 列表格 + 8 项筛选 + 批量提交按钮

修订: v1 误把原型记为 meetings.html (doctor 端 "我参与的会议"). 实测 manager.html:207 的 data-page 指向 meeting-manage.html, 才是 manager 角色的真正原型. 实体筛选/列名以 meeting-manage.html 为准.


1. 主要功能 + 可见性

1.1 主要功能

功能 前端入口 后端接口 数据表
筛选 + 分页列表 Meetings.vue <el-table> + <el-pagination> GET /business/meeting/list (BizMeetingController.java:26-37) biz_meeting
查看详情 (弹窗) onView(row)el-dialog + el-descriptions 只读 复用列表 row, 无额外请求 biz_meeting
修改会议 (跳独立页) onEdit(row) → router.push → MeetingNew.vue PUT /business/meeting biz_meeting
提交 (单条) onSubmit(row) → confirm → bizUpdate PUT /business/meeting biz_meeting.current_stage
复制 (单条) onCopy(row) → router.push MeetingNew ?mode=copy POST /business/meeting biz_meeting 新行
批量提交 onBatchSubmit() → for 循环逐条 bizUpdate PUT /business/meeting × N biz_meeting.current_stage

1.2 可见性 (三层过滤)

来源 校验字段
前端菜单 AdminLayout.vue:97 角色 = manager
路由守卫 router/index.js:65-66 meta.title (无 role 字段, 由 menu 拦截)
后端 SQL BizMeetingMapper.xml:37 selectList 无任何过滤 — 后端全量返回 (manager/doctor/expert 都共用同一接口, doctor/expert 走 setUserId 走 attendee 中间表过滤, manager 不隔离)

数据隔离: 缺失 — manager 端没有 @DataScopelead_user_id 过滤。当前 DB 9 行测试数据无风险, 生产环境会暴露全部会议 (见 §10 #1)。

看不到本页面的人群: admin / doctor / executor / sponsor 各有独立 /<role>/meetings 路由 + 独立菜单项, 路由层就分开了。


2. 筛选项 (filter-form)

UI label 控件 绑定字段 后端 <if> 命中表.字段 选项来源 原型对照
项目编号 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 (文本, 今日改) 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 项 (未执行/执行中/已执行/已完结) ⚠️ 原型有 (但原型是 6 项含 待审核/待结算/冻结中)
备注 el-input (模糊) q.remark 缺失biz_meetingremark (无字段) 原型无

完整 SQL 块 (BizMeetingMapper.xml:37-52):

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 <=]
      [AND userId EXISTS attendee] (doctor/expert )
order by meeting_id desc

8 项 filter 中 7 项生效; remark filter 是死路 — 实体/表/INSERT 都没有此字段 (见 §6.3, §9 #3)。


3. 工具栏 (filter-form / batch-bar)

按钮 功能 接口 涉及表 原型对照
查找 触发 load() → bizList GET /business/meeting/list?... biz_meeting 查找
重置 清空 q → load 同上 原型无
批量提交 onBatchSubmit() 逐条 update currentStage='执行中' PUT /business/meeting × N biz_meeting.current_stage 原型有 ("批量提交:后端待对接")

提示行: <span v-if="selectedIds.length" class="filter-tip">已选 N 条</span> — 推到 batch-bar 最右。


4. 表格 (el-table)

4.1 数据来源

见 §2 完整 SQL 块。

4.2 列映射

列名 row.* DB 表.字段 原型对照
多选框 (selection) 原型有 checkbox 列
项目编号 row.projectNo biz_meeting.project_no 项目编号
会议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 (永远空, 见 §9 #3) (无) 备注 (原型有)
操作 查看/修改/提交/复制 原型有 提交/查看/修改/复制

新增列 (原型无, 实现增) 改进: 无。

遗漏列 (DB 有, 列表未显示):

  • org_name (公司名称) — 列表可加
  • create_time / update_time — 审计可用
  • labor_signed (0/1) — 原型无, 实体有
  • invitation_url / schedule_url — 列表可加链接

5. 行内操作按钮

按钮 触发函数 接口 后端动作 涉及表.字段 跳转形式 原型对照
查看 viewDetail(row) GET /business/meeting/{meetingId} (在 MeetingDetail.vue) router.push → MeetingDetail.vue 独立页加载详情 biz_meeting 全字段 page 查看
修改 onEdit(row) → router.push manager-meetings-new?meetingId=...&projectId=... PUT /business/meeting (在 MeetingNew) UPDATE biz_meeting SET 多字段 WHERE meeting_id=? biz_meeting page 修改
提交 onSubmit(row) PUT /business/meeting UPDATE biz_meeting SET current_stage='执行中' WHERE meeting_id=? biz_meeting.current_stage page (改 DB) 提交
复制 onCopy(row) → router.push manager-meetings-new?...&mode=copy POST /business/meeting (在 MeetingNew) INSERT biz_meeting (...); meetingId AUTO_INCREMENT, businessId 兜底雪花 ID biz_meeting (新行) page 复制

真实落点:

  • "提交": 直接 UPDATE current_stage = '执行中', 无业务校验 (任何状态都能转, 包括"已完结"→"执行中" 状态回滚)。不写日志 (biz_meeting_log 表不存在)。
  • "修改" / "复制": 跳 MeetingNew.vue 独立页处理 (Meetings.vue:106 注释明确说明), form 含 9 字段, 见 manager_meeting_new.md。

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

6.1 biz_meeting DDL (实测 2026-08-21)

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 '公司名称(冗余)',
  `address` varchar(500) 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=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='会议表';

实测数据: 9 行 (今日) / 7 行 (08-18) / AUTO_INCREMENT=12 (说明中间有删除)

6.2 关联表

  • biz_project — 见 manager_projects.md §6, 含 create_user_id bigint
  • biz_meeting_attendee — doctor/expert 角色过滤的中间表 (见 BizMeetingMapper.xml:49 exists)

6.3 Entity ↔ 表字段对照表

实体字段 中文列名 (DB COMMENT) 实体类型 表字段 表类型 一致?
meetingId 会议ID Long meeting_id bigint
businessId 业务会议ID 5643145673 String business_id varchar(50)
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 ⚠️ 类型不一致 (MyBatis 自动转 OK)
totalPeriods 总期数 Long total_periods int ⚠️ 类型不一致 (同上)
projectForm 项目形式 String project_form varchar(20)
startTime 会议开始时间 Date start_time datetime (有 @JsonFormat + @DateTimeFormat)
endTime 会议结束时间 Date end_time datetime
orgName 公司名称(冗余) String org_name varchar(200)
address 会议地址 String address varchar(500) (实体/表都有, 但 selectFields/insert/update/selectList 全部漏列 — 详见 §9 #6)
currentStage 当前阶段 String current_stage varchar(20)
supervisionOpinion 监察意见 String supervision_opinion varchar(500)
supervisionBy 监察人 String supervision_by varchar(64)
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)
createTime 创建时间 Date create_time datetime
updateBy 更新人 String update_by varchar(64)
updateTime 更新时间 Date update_time datetime
(无 remark 字段) (无 remark 列) 实体缺 remark (见 §9 #3)

修订: v1 漏报 address 字段 — 实测 DB 有 address varchar(500) 列 + COMMENT '会议地址', 实体也有 private String address, 但 mapper 全套 (selectFields / insert / updateByPrimaryKey) 都没碰这个字段。新发现: 见 §9 #6。


7. 索引检查

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 =

缺失但暂可接受 (按 §2 筛选启用后):

  • idx_project_noLIKE '%xxx%' 模糊匹配无法走索引 (见 §10 #6)
  • idx_meeting_name — 同上
  • 复合 (project_id, meeting_id) — JOIN 用, 当前单 project_id 索引够

8. 与原型差异 (proto/html/components/meeting-manage.html)

8.1 实现新增 (原型没有) — 改进

原型 实现 评估
筛选 "备注" 4 项 (项目编号/会议名称/项目形式/当前阶段) 8 项 (多 会议ID/第?期/会议时间/备注) ⚠️ 备注 filter 死路 (见 §9 #3), 第?期无 placeholder 限制
弹窗 (查看/修改) 跳转 detail 页 el-dialog 紧凑 manager 端更高效
行内 "复制" → 跳独立页 原型 onclick="copyMeeting(this)" URL 传参 MeetingNew.vue?mode=copy 模式更清晰

8.2 原型有但实现缺失 — 回退

原型 实现 差距
9 条红字提示 (执行方只能在项目列表建会 / 状态定义 / 提交审核后 OA 流程 / 复制 → 新建会议 / 总期数可点击筛选 / 提交后 3 秒消失 / 7 种状态统一解释 / 冻结中提交置灰 / 到期前 24h 每 4h 短信催促) 整段红字提示缺失 (manager 端 UX 参考)
meeting-detail-executor.html 详情页 弹 dialog ⚠️ 弹窗缺字段 (见 §10 #11)

8.3 文字 / 标签差异

原型 实现 评估
面包屑 首页 > 我参与的会议 首页 / 会议管理 角色匹配
当前阶段 select 6 项 (未执行/执行中/待审核/待结算/已完结/冻结中) 4 项 (未执行/执行中/已执行/已完结) ⚠️ 缺 待审核/待结算/冻结中 3 项 (但跟 DB COMMENT 一致, 见 §9 #1)
期数筛选项 "第 [____] 期" 三段式 (label/input/label) "期数(第几期)" 单 label ⚠️ 排版略不同 (今日改 label 文案)
颜色 #1890ff (浅蓝) var(--brand-primary) (深海军蓝) 项目色

8.4 总结

整体方向: 对齐 — 实装与原型字段基本一致 (12 列 vs 12 列, 8 项 filter vs 8 项 filter); 差距在 "红字提示" 整段缺失 + 当前阶段 select 选项数不一致。


9. 设计问题

9.1 当前阶段 select 与 DB 实际数据不一致

DDL 注释列了 7 种 (未执行/待监管/监管通过/待整改/待结算/已结算/已结题), 实装 select 4 项 (未执行/执行中/已执行/已完结)。两者有交集但不一致, filter 启用后用户选"未执行"也筛不到任何数据 (DB 实际可能是 待监管/已结算 等)。

9.2 calcRemain 读不存在的字段

Meetings.vue:162row.submitDeadlineDays, 但 BizMeeting 实体无此字段 (BizProject 才有)。当前永远 fallback 到 30 天, 是个静默 bug。

9.3 实体无 remark 字段

前端 3 处使用 (Meetings.vue:32 q.remark, :67 row.remark, :32 filter), 但 BizMeeting 实体无 remark, 表也无 remark 列。后果:

  • filter "备注" 永远无效
  • 列表"备注"列永远空
  • 详情 dialog"备注"行永远 -

9.4 数据隔离缺失 (manager 端)

BizMeetingMapper.xml:37 selectList@DataScopelead_user_id 过滤。当前测试数据无风险, 生产必修。

9.5 状态回滚无校验

"提交" 操作任何 stage 都能转 "执行中", 包括 "已完结" → "执行中" (状态回滚)。应加前置校验。

9.6 新发现: address 字段 mapper 全套遗漏

DB 有 address varchar(500) COMMENT '会议地址', 实体也有 private String address + getter/setter (BizMeeting.java:117-119), 但 BizMeetingMapper.xml:

  • selectFields (line 29-32) — 漏列
  • selectByPrimaryKey (line 33-36) — 通过 selectFields 漏列
  • selectList (line 37-52) — 通过 selectFields 漏列
  • insert (line 53-97) — <if> 块无 address
  • updateByPrimaryKey (line 98-121) — <if> 块无 address

后果: 即使前端表单填了 address, 写入 DB 时会被静默丢弃; 即使 DB 已有 address, 列表也读不出来。


10. 待修复列表 (严格只列未修)

# 问题 文件 修复建议 严重度
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 calcRemainrow.submitDeadlineDays (BizMeeting 无此字段) Meetings.vue:162 改成读 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> + DDL ALTER TABLE biz_meeting ADD COLUMN remark text; 路径 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:205-212 onSubmit + :215-226 onBatchSubmit if (currentStage === '未执行') 才能提交, 否则 ElMessageBox 提示 P2
6 address 字段 mapper 全套遗漏 (DB 有, 实体有, mapper 全套没碰) BizMeetingMapper.xml selectFields/insert/update 全部加 address 字段 + <if test="address != null and address != ''"> P1
7 筛选后端需补索引 (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
8 实体 periodNo/totalPeriods Long vs int BizMeeting.java 改 int, MyBatis INSERT 不需 Long 转换 P3
9 当前阶段 select 选项跟 DB 实际数据不一致 (见 §9 #1) Meetings.vue:25-31 改成 7 项 (跟 DB COMMENT 一致: 未执行/待监管/监管通过/待整改/待结算/已结算/已结题) P1
10 filter 8 项挤一行 (屏幕窄乱) Meetings.vue:6-37 拆 2 行, 或 grid-template-columns: repeat(4, 1fr) P2
11 批量提交无事务/无批量 endpoint Meetings.vue:215-226 后端加 PUT /business/meeting/batch?ids=... + @Transactional; 前端 for 循环改单次调用 P2
12 详情页字段映射完整 (14 字段 + 邀请函 + 日程 + 返回, 详见 §5 跳转形式列) MeetingDetail.vue (新) 已修 (A.7) — 跳独立页, 参照原型 meeting-detail.html 1:1 实现 已修
13 totalPeriods 永远 1 (MeetingNew.vue 没让填) MeetingNew.vue 加"总期数"字段 (用户填, INSERT 时一起写) P1
14 9 条红字提示整体缺失 (原型 meeting-manage.html:533-543) Meetings.vue 顶部加 .hint-list 块 (manager 端 UX 参考, 不强制与 executor 端一致) P2
15 截止前 24h 短信催促 (原型第 9 条提示) 后端 scheduler + sys_sms 表 加定时任务扫描 end_time + submit_deadline_days, 距截止 24h 起每 4h 触发 P3

11. 引用清单

前端

  • ry-vue3/src/views/manager/Meetings.vue:256 — 本审查目标 (今日改动: 7/10/60/100/32)
  • ry-vue3/src/views/manager/MeetingNew.vue — 新建/修改/复制会议独立页
  • ry-vue3/src/layout/AdminLayout.vue:97 — manager 菜单项
  • ry-vue3/src/router/index.js:65-66 — 路由
  • ry-vue3/src/utils/request.js:15-30 — axios 拦截器 (__silentError 跳过 toast)
  • ry-vue3/src/api/public.js:32, 90-93bizList / bizGet / bizUpdate / bizAdd

后端 (Java)

  • ry-api/ruoyi-business/.../controller/BizMeetingController.java:26-75 — 5 endpoints
  • ry-api/ruoyi-business/.../domain/BizMeeting.java:11-136 — 25 字段, 缺 remark, address 在 mapper 全套遗漏
  • ry-api/ruoyi-business/.../service/impl/BizMeetingServiceImpl.java:24-31 — insert 调 SnowflakeId 兜底 businessId
  • ry-api/ruoyi-business/.../mapper/BizMeetingMapper.java — mapper 接口

Mapper XML

  • ry-api/ruoyi-business/src/main/resources/mapper/business/BizMeetingMapper.xml:131 — selectList 7 个 <if> 已生效; address 全套漏 (见 §9 #6)

配置 / 工具

  • 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/IdGenerator.java — 雪花 ID 生成器
  • ry-api/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java:27 — getUserId()

原型

  • proto/html/manager.html:207 — 链接到 components/meeting-manage.html
  • proto/html/components/meeting-manage.html:618 — manager 会议管理原型 (12 列 + 8 filter + 9 红字提示)
  • proto/html/components/meeting-manage-1.html — 原型变体 (期数 input 拆成 第/数字/期 三段), 暂未用

数据库 (实测 2026-08-21)

  • biz_meeting — 9 行 (08-21) / 7 行 (08-18), AUTO_INCREMENT=12, 4 索引 (PK + UNIQUE + 2 普通), 24 列
  • biz_project — 12 行, 含 create_user_id bigint
  • biz_meeting_attendee — doctor/expert 角色过滤的中间表

附录: 修复记录 (按 commit 时间倒序)

A.7 commit (未 commit, 2026-08-21 session 改动) — 查看按钮跳页面

背景: 用户硬要求 "跳页面变成打开 dialog 是完全不能接受的", 同时让 page-tech-review skill 能自动抓这类反模式

A.7.1 新建 MeetingDetail.vue (ry-vue3/src/views/manager/MeetingDetail.vue, 290 行)

  • 1:1 参照 ManagerProjectDetail.vue 的 page-card + breadcrumb + new-card-title 结构
  • 字段映射: 14 项基本信息 (项目编号/会议ID/会议名称/项目名称/项目形式/总期数/期数/起止时间/当前阶段/签署劳务/支持单位/创建人员/创建时间/备注) + 监察段 (条件渲染) + 邀请函/日程 (有 URL 渲染预览+下载, 无 URL 显示空态) + 返回
  • 字段对照 biz_meeting DB 实测 (见 §6.3); supervision_* 任意一项存在就整段显示, 避免空占位
  • 已知死字段: 备注 永远 - (实体/表都没, 见 §9 #3); address mapper 全套漏 (见 §9 #6), 暂不显示此字段避免误导
  • URL 参数: route.params.meetingId (path param, 跟 ManagerProjectDetail 一致)

A.7.2 router 加路由 (ry-vue3/src/router/index.js:66)

{ path: 'meetings/detail/:meetingId', name: 'manager-meetings-detail',
  component: () => import('@/views/manager/MeetingDetail.vue'),
  meta: { title: '会议详情' } },

参照 manager-projects-detail (line 63) 命名

A.7.3 Meetings.vue 删 dialog 改跳页面 (367 行 → 220 行)

  • onView(row)viewDetail(row), 内部 router.push(/manager/meetings/detail/${row.meetingId})
  • 删除: <el-dialog> 整块 (89-156 行), detailOpen/currentRow ref, onView/calcRemain/laborSignedLabel 函数, .meeting-detail-dialog 系列样式, 3 个 icon imports (Document/Calendar/Picture)
  • 保留: fmtTime (表格列用), stageClass (表格列用), .stage-tag 系列样式

A.7.4 page-tech-review skill 加规则 (SKILL.md)

  • §5 加 2 处: (1) 列说明加 "跳转形式 (page= / dialog=)"; (2) 新 bullet 强调 "查看" 必须跳独立页面, 给反例 (本次修复前 Meetings.vue) 和参考模式 (Projects.vue:424)
  • §10 铁律加第 10 条 : "查看" 不能用 dialog; 审查时 §5 必须标 "跳转形式", dialog 即 P0

A.6 commit (未 commit, 2026-08-21 session 改动) — label/期数/placeholder 修复

改动范围: Meetings.vue (前端) + BizProjectController.java (后端, 顺带修)

A.6.1 后端 BizProjectController.java:223

  • : int s = safeLong(...) + safeLong(...) + ... — long 累加赋给 int, Java 报"可能会有损失"
  • : int slong s
  • 影响: rate() 接口里 compliance 角色聚合评分那行, 不影响 meeting 页面本身

A.6.2 前端 Meetings.vue:10 筛选项 "第?期"

  • 问题: :min="0" 让 el-input-number 在空值时强制 0 → 后端 period_no = 0 过滤掉全部数据; label 文案 "第?期" 不直观
  • :
    • label: 第?期期数(第几期)
    • 控件: <el-input-number :min="0" :precision="0" controls-position="right"><el-input placeholder="请输入期数" clearable>
    • 原因: Element Plus 2.4 无 value-on-clear prop, :min="1" 仍会让 blur 时 snap 到 1; 改用普通 <el-input> 让空值保持空串, 由 mapper <if test="periodNo != null"> 跳过
  • 验证: 缺值 → 不影响其他筛选; periodNo=1 → 1 行

A.6.3 前端 Meetings.vue:60, 100 期数显示

  • 问题: 第 {{ row.periodNo || 0 }} 期 在 periodNo 为 null/空时强行显示 "第 0 期"
  • : {{ row.periodNo ? '第 ' + row.periodNo + ' 期' : '-' }}
  • 影响: 表格列 + 详情 dialog 同步去掉 || 0 兜底

A.6.4 前端 Meetings.vue:7-32 placeholder 补齐

  • 问题: 5 个文本输入 + 2 个日期选择器缺 placeholder
  • :
    • 项目编号 → 请输入项目编号
    • 会议ID → 请输入会议ID
    • 会议名称 → 请输入会议名称
    • 期数(第几期) → 请输入期数
    • 会议时间 → 开始时间 / 结束时间
    • 备注 → 请输入备注
    • 项目形式 / 当前阶段 → 已经有 请选择

A.5 commit bae9fa6 (2026-08-18) — 恢复会议ID + 第?期 filter (第五轮续)

  • 背景: 第四轮前后曾误删 会议ID / 第?期 filter, 用户澄清两个字段原型中都有
  • 修改: Meetings.vue:8 加回 <el-form-item label="会议ID">; Meetings.vue:10 第?期 el-input-number; q reactive + reset() 加回 meetingId
  • 验证: q.meetingId=14 → 1 行; q.periodNo=1 → 1 行

A.4 commit 14757f3 (2026-08-18) — mapper selectList 加 7 个筛选 if + @DateTimeFormat

  • 解决: 全部筛选不生效 (<where> 空)
  • 修改: BizMeetingMapper.xml:37-52 加 8 个 <if>; BizMeeting.java:30-33 startTime/endTime 加 @DateTimeFormat

A.3-A.1 (略, 见 v1 报告)