Files
guoju0808/_self/doctor_home.md
T
郭庆泰andClaude e496f34393 feat: 多处页面改造 + 新增劳务协议模板配置
主要改动:
- biz_meeting_attendee 中间表 + doctor/expert 角色数据隔离
- biz_meeting_attendee 加 handsign/labor_protocol 字段 (劳务协议改造)
- biz_labor_protocol_template 配置表 + admin 页面 (从 HeguiConstants 迁移)
- biz_expert.expertId 改 Long + IdGenerator 生成 (去自增)
- Login.vue / PublicityDetail.vue / Home.vue 等多处 bug 修复 + UI 改进
- 新增 page-tech-review 报告 3 篇 (_self/*.md)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-19 21:06:49 +08:00

16 KiB

/doctor/home 页面端到端审查 (v3)

审查日期: 2026-08-19 (v3 含修复) 审查范围: 前端 → 后端 → DB → 原型 审查者: Claude Code (page-tech-review skill)

修订 (v1 → v2):

  • P1 数据隔离: biz_meeting_attendee 中间表 + mapper EXISTS + controller 注入 (doctor/expert 角色)
  • 欢迎栏显示真实姓名 (biz_expert.name → fallback 到 nickName/userName)

修订 (v2 → v3):

  • "待签署协议" 数据源从 biz_project_plan 改到 biz_meeting_attendee (按 user_id + 任一未签)
  • biz_meeting_attendee 表加 2 字段: handsign longtext (Base64 手写签名) + labor_protocol varchar(500) (劳务协议 URL)
  • 新建后端 controller + service + mapper + 前端 API
  • 签署 dialog + 手写板 UI 未做 (v3 待修)
  • 新建会议自动写 attendee 中间表 (BizMeetingController.add) 未做

0. 组件定位 (四跳链)

命中
① 角色菜单 AdminLayout.vue:90 MENU.doctor{ path: '/doctor/home', title: '首页' }
② 路由 router/index.js:90name: 'doctor-home', component: () => import('@/views/doctor/Home.vue')
③ 组件 ry-vue3/src/views/doctor/Home.vue
④ 原型 proto/html/doctor.html:204 data-page="components/home.html"proto/html/components/home.html

1. 主要功能 + 可见性

1.1 主要功能

页面是 dashboard 工作台,4 块内容:

功能 前端入口 后端接口 数据表
欢迎栏 (实时时钟 + 专家姓名) Home.vue:6-15 GET /business/expert/profile biz_expert
待参加的会议 Home.vue:114 bizList('meeting', {pageSize: 5}) GET /business/meeting/list biz_meeting + biz_meeting_attendee
待签署的协议 (v3 改) Home.vue:126 listUnsignedMeetingProtocols() GET /business/meetingAttendee/unsigned biz_meeting_attendee (handsign 或 labor_protocol 为空)
通知消息 Home.vue listMyMessages({limit: 5}) GET /business/message/my biz_message

页面无 CRUD 操作,纯展示 (v3 计划加签署 dialog 但未做)。

1.2 可见性 (三层过滤)

来源 校验字段
前端菜单 AdminLayout.vue:90 MENU.doctor doctor 角色可见
路由守卫 router/index.js:88 meta: { role: 'doctor' } + permission.js token 角色
后端 各 controller 注入 + mapper <if> 过滤 详见 §1.1

数据隔离现状 (v3):

数据块 隔离机制
欢迎栏 biz_expert 按 token userId
待参加会议 biz_meeting_attendee (EXISTS) — controller 注入 userId for doctor/expert
待签署协议 (v3) biz_meeting_attendee.user_id = current user (controller SecurityUtils.getUserId())
通知消息 biz_message.user_id = current user

2. 筛选项 (filter-form)

本页面无 filter-form,跳过。


3. 工具栏按钮 (toolbar)

本页面无 toolbar,只有 3 个"更多"链接 (Home.vue:22, 37, 57)。


4. 表格 (el-table)

本页面无表格,使用 ul/li 自定义列表。


5. UI 元素映射

5.1 欢迎栏 (Home.vue:6-15)

UI 绑定 来源
用户名 (左) displayName (computed) 优先级: biz_expert.namenickNameuserName → '专家'
当前时间 nowTime (setInterval) 前端 Date
当前日期 nowDate (setInterval) 前端 Date

5.2 待参加会议列表 (Home.vue:24-32)

UI label 绑定字段 后端 SQL 命中表.字段 原型对照
会议名 m.meetingName selectList + EXISTS biz_meeting_attendee biz_meeting.meeting_name
状态/时间 formatTime(m.startTime) selectList biz_meeting.start_time

5.3 待签署协议列表 (Home.vue:39-49) — v3 重大改动

UI label 绑定字段 后端 SQL 命中表.字段 原型对照
协议名 s.meetingName selectUnsignedByUserId JOIN biz_meeting biz_meeting.meeting_name (via JOIN) ⚠️ 原型写"协议/意见书",实际显示会议名
状态 固定 "待签署" ⚠️ 实现只显示"待签署",原型有"已完成"

v2 → v3 数据流变化:

  • v2 (错误): GET /business/projectPlan/list → 按 submitter_id 过滤 (这是"投稿方案"语义, 不是劳务协议)
  • v3 (正确): GET /business/meetingAttendee/unsigned → 当前用户 + 任一未签 → JOIN biz_meeting 取会议名

API (ry-vue3/src/api/business/meetingAttendee.js):

export function listUnsignedMeetingProtocols() {
  return request({ url: '/business/meetingAttendee/unsigned', method: 'get' })
}
export function updateHandsign(id, handsign) { ... }
export function updateLaborProtocol(id, laborProtocol) { ... }

后端 mapper SQL (核心):

select a.id, a.meeting_id, a.user_id, a.handsign, a.labor_protocol,
       m.meeting_name as meetingName, m.start_time as startTime,
       m.end_time as endTime, m.project_name as projectName, m.project_no as projectNo
from biz_meeting_attendee a
inner join biz_meeting m on m.meeting_id = a.meeting_id
where a.user_id = #{userId}
  and (a.handsign is null or a.handsign = ''
    or a.labor_protocol is null or a.labor_protocol = '')
order by m.start_time asc

判定逻辑 (决策 A1): 任一未签即"待签署"。两条都有值就排除。

5.4 通知消息列表 (Home.vue:59-69)

略,同 v2 报告。


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

6.1 biz_meeting_attendee (v3 实测, 2026-08-19)

CREATE TABLE biz_meeting_attendee (
  id bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
  meeting_id bigint NOT NULL COMMENT '会议ID (FK biz_meeting.meeting_id)',
  user_id bigint NOT NULL COMMENT '参会人 user_id (FK sys_user.user_id)',
  handsign longtext COMMENT '手写签名 Base64',
  labor_protocol varchar(500) DEFAULT NULL COMMENT '劳务协议 URL (OSS)',
  create_by varchar(64) DEFAULT '' COMMENT '添加人',
  create_time datetime DEFAULT NULL COMMENT '添加时间',
  PRIMARY KEY (id),
  UNIQUE KEY uk_meeting_user (meeting_id, user_id),
  KEY idx_user_id (user_id)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='会议参会人';

6.2 BizMeetingAttendee Entity ↔ DB 字段对照

实体字段 中文列名 Java 类型 表字段 DB 类型 一致?
id 主键 Long id bigint AUTO_INCREMENT
meetingId 会议ID Long meeting_id bigint
userId 参会人 user_id Long user_id bigint
handsign 手写签名 Base64 String handsign longtext (v3 新增)
laborProtocol 劳务协议 URL (OSS) String labor_protocol varchar(500) (v3 新增)
createBy (BaseEntity) 添加人 String create_by varchar(64)
createTime 添加时间 Date create_time datetime
meetingName (transient) String JOIN m.meeting_name (联表字段)
startTime (transient) Date JOIN m.start_time
endTime (transient) Date JOIN m.end_time
projectName (transient) String JOIN m.project_name
projectNo (transient) String JOIN m.project_no

5 个 transient 联表字段 接收 selectUnsignedByUserId 的 JOIN 输出, 给前端用。


7. 索引检查

7.1 biz_meeting_attendee

Key 用途覆盖
PRIMARY id
uk_meeting_user meeting_id, user_id (UNIQUE) 防重复 + 精确查
idx_user_id user_id selectUnsignedByUserId WHERE user_id = ? 走这个索引

评价: 复合查询 (WHERE user_id = X AND (handsign IS NULL OR labor_protocol IS NULL)) 走 idx_user_id,然后行过滤。10k 行内完全 OK。

7.2 缺什么?

  • idx_user_status: 如果会议量大且空记录占比小, 想加速"待签署"查询, 可以加 (user_id, handsign IS NULL, labor_protocol IS NULL) 函数索引。但目前数据少, 暂不需要。
  • idx_meeting_status: WHERE meeting_id = X AND handsign IS NULL 场景目前不存在 (管理端"看哪些医生没签"的视图未做), 暂不需要。

8. 与原型差异

8.1 实现新增 (超出原型)

实现 原型
实时时钟 静态
通知标记已读
"更多"链接跳 Vue 路由 静态 HTML
空状态文案
欢迎栏显示真实姓名 (v2) 静态写死
数据源按 user 隔离 (v2 加中间表)
劳务协议按会议关联 (v3 改 biz_meeting_attendee)

8.2 原型有但实现缺失

原型 实现 严重度
item-icon 图标 (📅 📄) P2
section-title 左侧蓝条 P2
欢迎栏渐变背景 ⚠️ 单色 P3
"已完成" 状态显示 (signed status) item-status.done 实现永远显示"待签署" P1
签署交互 (点列表 → 弹 dialog → 上传 handsign + labor_protocol) 原型点击 alert 无 dialog, 点列表没反应 P1

8.3 文字 / 标签差异

原型 实现
协议状态文案 "待签署 / 已完成" "待签署" (永远)
协议名显示 "《方案名》专家意见书" "会议名" (会议关联, 语义不同)

8.4 总结

v3 整体方向: 数据语义修正 (劳务协议按会议关联 ), 视觉 + 交互仍待补。


9. 字段冗余 / 设计问题

9.1 biz_meeting_attendee 设计合理 (v3 验证)

  • handsign longtext 存 Base64 是合理的: 不依赖 OSS, 数据完整性内嵌 DB, 简单
  • labor_protocol varchar(500) 存 OSS URL 是合理的: 大文件走 OSS, DB 只存引用

9.2 缺管理端点 ⚠️ P1

BizMeetingAttendeeController 目前只有 doctor 用的 3 接口。新建会议时, 没有 API 自动把参会人写入中间表

  • 影响: 现有数据需要手动 INSERT (像之前那样用 SQL), 业务没法在线给会议加参会人
  • 修复: BizMeetingController.add 接受 attendeeUserIds: Long[], 批量 insert 中间表

9.3 缺管理列表 (P3)

没有"看某会议的所有参会人 + 签署状态"的后台接口 (manager 端要用)。

  • 影响小 (低优先级), 当前 P1 先修

9.4 biz_project_plan 完全废弃? ⚠️

v3 把"待签署协议"从 biz_project_plan 改走中间表, 但 biz_project_plan 表和 BizProjectPlan entity 还在。

  • 投稿方案业务 (manager 审稿) 仍存在, 这是独立的 "项目策划方案投稿" 业务
  • 与劳务协议是两回事, 不应混淆

9.5 biz_meeting.status 缺失 (沿 v2 待修)

业务希望"待签署协议"按 meeting.status 过滤 (会议取消/已结束的不再显示待签), 但 biz_meeting 无 status 字段, 需要 ALTER。


10. 待修复列表 (v3)

# 问题 文件 修复建议 严重度 状态
1 biz_meeting 无 user 隔离 Controller + mapper 中间表 EXISTS P1 v2 修
2 欢迎栏显示数字 userName Home.vue displayName computed 优先级链 P2 v2 修
3 劳务协议数据源错 (biz_project_plan) Home.vue + BizProjectPlanController 改走 biz_meeting_attendee P0 v3 修
4 表无 handsign/labor_protocol biz_meeting_attendee ALTER 加 2 列 + 后端全套接口 P0 v3 修
6 签署 dialog 未做: 点"待签署"列表项无反应 Home.vue 弹 dialog: handsign 用 textarea 输入 Base64 (临时), labor_protocol 用 OssImageUploader, 提交分别 PUT P1 待修
7 手写板 canvas 组件未做: handsign 暂用 textarea 输入 Base64, 用户体验差 新建 SignaturePad.vue vue-signature-pad 库 或 自写 canvas + toDataURL() P2 待修
8 item-icon 图标缺失 (📅 📄) Home.vue .item-icon 样式 + 模板 P2 待修 (v1 提的)
9 section-title 左侧蓝条缺失 Home.vue:151 border-left + padding-left P2 待修 (v1 提的)
10 欢迎栏渐变背景降级为单色 Home.vue:145 还原 gradient P3 待修 (v1 提的)
11 biz_project_plan.status 注释缺失 DB ALTER COMMENT P3 待修
12 biz_meeting.status 不存在 (无法过滤"已结束"会议) DB + mapper ALTER 加 status 字段 P3 待修
13 Home.vue:131 read: a.read || i >= 2 强制第3条后标已读 Home.vue 改为纯 read: a.read P3 待修
14 新建会议自动写 attendee 中间表: BizMeetingController.add 不支持传 attendeeUserIds BizMeetingController.java + service add 接受 attendeeUserIds: Long[], 批量 insert 中间表 P1 待修
15 缺管理端"看参会人列表 + 签署状态"接口 新建 BizMeetingAttendeeController 管理端点 GET /business/meetingAttendee/byMeeting/{meetingId} P3 待修

11. 引用清单

v3 新增/改的文件

文件 行号 说明
DB biz_meeting_attendee ALTER 加 handsign longtext + labor_protocol varchar(500)
ry-api/.../controller/BizMeetingAttendeeController.java 全文 v3 新建
ry-api/.../service/IBizMeetingAttendeeService.java 全文 v3 新建
ry-api/.../service/impl/BizMeetingAttendeeServiceImpl.java 全文 v3 新建
ry-api/.../domain/BizMeetingAttendee.java 全文 v3 加 handsign + laborProtocol + 5 个 transient 联表字段
ry-api/.../mapper/BizMeetingAttendeeMapper.java 全文 v3 加 updateHandsign + updateLaborProtocol + selectUnsignedByUserId
ry-api/.../mapper/business/BizMeetingAttendeeMapper.xml 全文 v3 加 resultMap 字段 + 2 update + selectUnsignedByUserId 联表 SQL
ry-vue3/src/api/business/meetingAttendee.js 全文 v3 新建: 3 API helpers
ry-vue3/src/views/doctor/Home.vue 39-49, 124-134 v3 改 "待签署协议" 数据源

未改的文件 (沿 v2)

文件 行号 说明
ry-vue3/src/layout/AdminLayout.vue 90 MENU.doctor 第 1 项
ry-vue3/src/router/index.js 88-99 /doctor 父路由
proto/html/doctor.html 204 原型菜单
proto/html/components/home.html 全文 原型基准
ry-vue3/src/api/public.js listMyMessages / bizList
ry-vue3/src/api/business/expert.js 全文 v2 新建: getMyExpertProfile
ry-api/.../controller/BizMeetingController.java 23-33 v2 改: 加 userId 注入
ry-api/.../controller/BizProjectPlanController.java 不再被"待签署协议"调用, 投稿方案独立业务
ry-api/.../controller/BizExpertController.java 46-50 欢迎栏取名
MySQL guoju0808.biz_meeting v2 无改动
MySQL guoju0808.biz_meeting_attendee v3 加 2 列
MySQL guoju0808.biz_message 通知
MySQL guoju0808.biz_expert (user_id=142) name='dct07'

v3 总结

修复 2 项 (跨 v2 → v3):

  1. 数据语义修正: "待签署协议" 从 biz_project_plan 改到 biz_meeting_attendee (语义正确: 劳务协议按会议关联, 不按投稿方案)
  2. 新字段 + 后端: handsign longtext + labor_protocol varchar(500) + 完整后端 CRUD 接口 + 前端 API

还剩 11 项待修复,按严重度:

  • P1 (2 项): 签署 dialog 缺失 (点列表没反应); 新建会议没自动写 attendee
  • P2 (3 项): 手写板 UI; item-icon; section-title 边框
  • P3 (6 项): 字段注释 + status 字段 + 索引 + 前端兜底 + 管理端点

SQL 实测验证 (user_id=142 当前状态):

待签署会议: 3 个 (id=1,2,3 全部 handsign=NULL labor_protocol=NULL)
会议名: 整合医学学会项目评审会 / 基层医疗改革试点中期评估会 / 数字化医疗转型方案评审会
按 start_time 升序 ✓