Files
xuetang/app/research/diagnosis_detail_visual_spec.md
2026-09-08 11:40:15 +08:00

566 lines
42 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 诊单详情 / 编辑 / 预约视觉规格(后台源码基准)
## 1. 范围与判读原则
本规格只以 `D:/web/zyt/admin` 当前源码为事实源,覆盖:
- 三个主视图:`src/views/tcm/diagnosis/edit.vue``readonly.vue``appointment.vue`
- 三个主视图直接渲染的诊单组件:患者摘要、病例、日常记录、医生备注、处方/病例记录、业务订单、视频、聊天、医助指派历史、挂号历史、待办。
- 备注视图直接引用的 `src/views/patient/reception/components/NoteTimeline.vue`
- 直接生效的全局样式入口、Element Plus 变量和 Tailwind 尺寸映射。
颜色、尺寸若由当前文件明确声明,标为“显式”;若控件仅沿用 Element Plus,则标为“继承”。项目使用 Element Plus `^2.9.4` 与 Tailwind CSS `^3.4.17``package.json:27,64`)。全局样式入口为 `main.ts:1-3`,依次加载 `element.scss``dark.css``var.css``tailwind.css``public.scss``src/styles/index.scss:1-5`)。因此不能把浏览器/Element 默认值误写成某个业务组件的局部规格。
> 关键结论:系统实际上有两种“只读详情”。`readonly.vue` 是独立、卡片化、纵向详情页;`edit.vue` 在 `viewOnly` 模式下则仍是右侧抽屉和 Tab 结构,只禁用编辑控件。两者不能用同一个线框替代。
---
## 2. 全局视觉基础
### 2.1 字体与字号
字体栈由 Tailwind 配置明确为 `PingFang SC, Arial, Hiragino Sans GB, Microsoft YaHei, sans-serif``tailwind.config.js:79-80`),并赋给 `--el-font-family``src/styles/var.css:1-3`)。基础字号如下(`src/styles/var.css:11-18`):
| 语义 | 实际字号 |
|---|---:|
| extra large | 18 px |
| large | 16 px |
| medium | 15 px |
| base | 14 px |
| small | 13 px |
| extra small | 12 px |
业务层进一步压缩:编辑抽屉根节点和表单文字为 12 px(`edit.vue:1476-1504,1532-1556`);只读病例键值为 12.5 px`components/PatientCaseCard.vue:307-341`);聊天气泡为 14 px`components/ImChatRecordPanel.vue:260-286`)。
### 2.2 全局颜色与表面
以下均为项目显式变量(`src/styles/var.css:20-40`):
| 用途 | 色值 |
|---|---|
| 页面底 | `#f6f6f6` |
| 普通/浮层底 | `#ffffff` |
| 主文字 | `#333333` |
| 常规文字 | `#666666` |
| 次要文字 | `#999999` |
| placeholder | `#a8abb2` |
| disabled | `#c0c4cc` |
| border / light / lighter | `#dcdfe6` / `#e4e7ed` / `#ebeef5` |
| extra-light border | `#f2f2f2` |
| fill / light / lighter | `#f0f2f5` / `#f8f8f8` / `#fafafa` |
| extra-light fill | `#fafcff` |
Element 语义主色未在这些诊单文件中改写,局部引用 `var(--el-color-primary)` 或显式 `#409eff`。继承的 Element Plus 2.9.4 常规控件高度为 32 pxsmall 24 px、large 40 px);但编辑抽屉底部按钮被局部覆盖为最小 40 px,移动端最小 44 px(`edit.vue:1732-1740,1905-1913`)。
### 2.3 间距基线和全局行为
Tailwind 间距映射是 4 px 基线:`1=4``2=8``2.5=10``3=12``3.5=14``4=16``5=20``6=24``tailwind.config.js:103-125`)。业务文件里的 8/10/12/14/16/18/20/24 px 与该节奏一致。
直接影响这些页面的全局规则:
- Dialog 居中,最大宽 `calc(100vw - 30px)`,圆角 5 px`src/styles/element.scss:11-27`)。
- 全局 Drawer 主内边距变量为 16 pxHeader 内边距 `13px 16px`、下边框 1 px lighter;预约 Drawer 没有重写这些值,编辑 Drawer 则只额外重写背景与边框(`src/styles/element.scss:46-56`)。
- 全局表格字号 14 px、表头主文字色、表头字重 400、表头底 `#f8f8f8``src/styles/element.scss:58-68`; `src/styles/var.css:10`)。因此编辑根节点的 12 px 不应错误地传成所有表格单元字号。
- Input、Select、Textarea 聚焦时出现 2 px primary-light 外环,radio/checkbox active 也有 2 px 外环;校验错误时切换 danger-light 外环(`src/styles/element.scss:140-175`)。
- Tabs 底线全局压至 1 px`src/styles/element.scss:131-133`)。
- 消息与通知层级为 9999`src/styles/element.scss:1-9`)。
- 小于等于 768 px 时分页隐藏页码跳转与 page-size 选择器(`src/styles/element.scss:177-183`)。
- Tailwind 会导入 base/components/utilities`src/styles/tailwind.css:1-3`),但 Element 按钮背景、focus、hover 被重新还原为 Element 变量,避免被 Tailwind reset 覆盖(`src/styles/element.scss:186-200`)。
- `body` 为 14 px 主文字、`overflow:hidden`、最小宽 375 px;页面/Drawer 自己承担滚动(`src/styles/public.scss:1-3`)。全局 `.form-tips` 为 12 px secondary、行高 24 px、上间距 4 px`src/styles/public.scss:4-6`)。
暗色主题另有一套直接全局变量:页面/表面为 `#0a0a0a / #1d2124 / #1d1e1f`,主/常规/次要文字为 `#e5eaf3 / #cfd3dc / #a3a6ad`,边框从 `#636466``#2b2b2c`,遮罩为 `rgba(0,0,0,.8)``src/styles/dark.css:1-31`)。不过三个诊单主视图及卡片大量显式写入白底、浅蓝渐变和 slate 色,不能完整随暗色变量切换;本规格后续均按源码默认浅色态记录,暗色不能视为已完整适配。
---
## 3. 独立只读详情页 `readonly.vue`
### 3.1 页面骨架
源码结构是单列滚动页,不使用 Tabs(`readonly.vue:1-149`):
```text
┌─────────────────────────────────────────────────────────────────────┐
│ ← 返回 诊单只读详情 张三 男 · 42岁 [未服务 3天] │
├─────────────────────────────────────────────────────────────────────┤
│ [患者信息摘要 PatientInfoCard] │
├─────────────────────────────────────────────────────────────────────┤
│ [患者病例 PatientCaseCard] │
├─────────────────────────────────────────────────────────────────────┤
│ [日常记录 DailyMatrix] 按权限可见 │
├─────────────────────────────────────────────────────────────────────┤
│ [医生备注/舌象/报告 NoteTimeline] │
├─────────────────────────────────────────────────────────────────────┤
│ [业务订单 PatientOrderList] 按权限可见 │
├─────────────────────────────────────────────────────────────────────┤
│ [视频录制回放 CallRecordPanel] 按权限可见 │
├─────────────────────────────────────────────────────────────────────┤
│ [聊天 ImChatRecordPanel] 按权限可见 │
├─────────────────────────────────────────────────────────────────────┤
│ [指派医助记录 AssignLogPanel] 按权限可见 │
├─────────────────────────────────────────────────────────────────────┤
│ [挂号记录 AppointmentRecordPanel] 按权限可见 │
└─────────────────────────────────────────────────────────────────────┘
```
渲染顺序严格来自 `readonly.vue:39-146`;异常时在 hero 下方显示错误空态(`readonly.vue:31-36`)。页面根容器垂直间距 16 px、内边距 16 px(`readonly.vue:269-273`)。
### 3.2 顶部 Hero
Hero 是可换行的左右布局:`display:flex; justify-content:space-between; flex-wrap:wrap; gap:12px`,内边距 `12px 16px`,圆角 12 px,边框 `#dde7ff`,背景为 `#f5f8ff → #eef3ff` 的浅蓝渐变(`readonly.vue:275-285`)。
- 页面标题:16 px / 700`readonly.vue:286-303`)。
- 患者姓名:18 px / 700;性别年龄 13 px`readonly.vue:305-320`)。
- 未服务状态胶囊:12 px / 600,内边距 `4px 10px`999 px 全圆角(`readonly.vue:323-330`)。
- 状态色:正常绿 `#16a34a` / 边框 `#bbf7d0`;提醒橙 `#ea580c` / `#fed7aa`;严重红 `#dc2626` / `#fecaca``readonly.vue:332-355`)。从未记录时使用 Element placeholder 灰。
### 3.3 卡片规格
通用详情卡为白底、1 px `#e6ebf2` 边框、14 px 圆角、18 px 内边距、14 px 内部纵向间距和轻阴影(`readonly.vue:364-373`)。卡片标题 15 px / 700,标题前为 `3 × 16 px` 蓝色标记(`readonly.vue:375-396`)。DailyMatrix 外层额外 16 px 内边距以对齐矩阵(`readonly.vue:398-405`)。错误空态卡保持 14 px 圆角并有 40 px 纵向内边距(`readonly.vue:357-362`)。
患者摘要内部是浅蓝 Hero 卡:圆角 12 px,内边距 `16px 18px`,行距 6 px;患者名 22 px / 700,其余信息 13 px、行高 1.7(`components/PatientInfoCard.vue:78-123`)。字段顺序是:
1. 姓名。
2. 脱敏手机 · 性别 · 年龄。
3. 身高 / 体重 · 地区。
4. 预约日期时间 · 时段。
5. 医生 / 医助。
6. 预约状态 · 是否已开方。
7. 备注(有值才显示)。
顺序由 `components/PatientInfoCard.vue:6-25` 确定。
### 3.4 病例字段顺序与网格
病例卡以分组标题 + 网格键值展示;组间 `gap:10px`,除首组外顶部 12 px 内边距并有 dashed 分隔线(`components/PatientCaseCard.vue:258-269`)。分组标题 13 px / 600、蓝色,前有 4 px 圆点(`components/PatientCaseCard.vue:271-287`)。网格横向间距 16 px、纵向 8 px,并提供 1/2/3/4 等分列(`components/PatientCaseCard.vue:289-305`)。键值字号 12.5 px、行高 1.55label 最小宽 58 pxlabel 为 `#6b7280`value 为 `#1f2937` / 500,空值为 `#c0c4cc``components/PatientCaseCard.vue:307-341`)。
只读病例的真实字段顺序(`components/PatientCaseCard.vue:8-124`):
| 分组 | 列数 | 顺序 |
|---|---:|---|
| 基本信息 | 4 | 诊单ID、姓名、身份证、手机、性别、年龄、婚姻、地区 |
| 生命体征 | 4 | 身高、体重、高压、低压、诊断类型、空腹血糖、在用药物(多行) |
| 主诉 | 4 | 当地诊断日期、糖尿病病史、当地医院、当地医院诊断结果 |
| 现病史 | 3 | 口腔、饮水、体重变化、脂肪肝、饮食(跨2列)、肢体、睡眠、眼、头、出汗、皮肤、小便、大便、腰肾、其他补充(跨3列、多行) |
| 既往史 | 1 | 既往史(整行) |
| 其他病史 | 混合 | 外伤、手术、过敏、家族、妊娠 |
| 补充与意见 | 1 | 病史补充(有值才显示)、处方意见 |
超标指标采用 `#dc2626`、700 字重并带上箭头(`components/PatientCaseCard.vue:343-358`)。处方意见为 13 px、`12px 14px` 内边距、8 px 圆角、左侧 3 px 蓝条(`components/PatientCaseCard.vue:360-368`)。
### 3.5 响应式事实
`readonly.vue` 自身没有 media queryHero 仅通过 `flex-wrap` 避免左右信息互相挤压。`PatientCaseCard.vue` 也没有窄屏降列规则,所以 4 列病例网格不会自动变成 1 列。实现 PySide 时不能把“可换行 Hero”误判为整页已经完整响应式。
---
## 4. 编辑 / 抽屉只读 `edit.vue`
### 4.1 框架与模式
右侧 Drawer 宽度固定为视口的 60%,方向 RTL;只读时 z-index 4000,编辑/新增时 1500`edit.vue:2-10`)。抽屉有三种标识:只读 `info`、新建 `success`、编辑 `warning`,标题下显示“患者名 · 诊单ID”(`edit.vue:11-54,859-863`)。
```text
桌面(右侧 60% Drawer
┌───────────────────────────────────────────────────────────────┐
│ 编辑诊单 [编辑] 患者名 · #123 │ Header
├───────────────────────────────────────────────────────────────┤
│ 病历 │ 医生备注 │ 日常记录 │ 处方 │ 业务订单 │ 视频 │ ... → │ Tabs
├───────────────────────────────────────────────────────────────┤
│ │
│ [锁定提示 / 隐私提示,按条件] │
│ 诊单ID [_____________________________] │
│ 姓名 [____________] 身份证 [____________] │
│ │
│ ──────────────── 生命体征 ──────────────── │
│ 婚姻 [____] 身高 [____] 体重 [____] │ Scroll body
│ ... │
│ ──────────────── 现病史 ───────────────── │
│ [可换行 radio / checkbox 组] │
│ │
├───────────────────────────────────────────────────────────────┤
│ [取消/关闭] [保存] │ Footer slot
└───────────────────────────────────────────────────────────────┘
```
`viewOnly` 模式没有切换到独立详情卡,而是给病历 `fieldset` 禁用输入,并隐藏保存;锁定患者信息时显示 warning alert`edit.vue:57-84,766-781`)。
### 4.2 Header、Tabs、Footer
- Header 背景 `#fff → #f8fafc`,底边 1 px `#e2e8f0``edit.vue:1776-1785`)。标题 18 px / 600 / `#0f172a`,行高 1.3;副标题 13 px`edit.vue:1670-1717`)。
- Body 背景 `#f8fafc``edit.vue:1787-1790`)。
- Tabs 横向滚动,滚动条 4 px;nav 使用 `max-content` 且最小宽 100%,tab 水平内边距 14 px,常态 `#64748b` / 500,激活态为 Element primary / 600,激活条 3 px`edit.vue:1798-1858`)。
- Footer 最终生效样式为白底、上边框 1 px `#e2e8f0`,内容右对齐、gap 12 px、内边距 `14px 20px 18px``edit.vue:1719-1730,1860-1864`)。按钮最小高 40 px、水平内边距 20 px、600 字重、圆角 10 px`edit.vue:1732-1740`)。
这里没有 CSS `position: sticky`。底部操作之所以视觉上固定,是因为它使用 Element Drawer 的独立 footer slot,位于可滚动 body 之外(模板 `edit.vue:766-781`;结构样式 `edit.vue:1792-1796`)。PySide 应以固定底栏实现,而不是在滚动内容末尾放按钮。
### 4.3 Tab 顺序、权限与内容
Tab 的准确顺序和门槛(`edit.vue:55-759`):
| 序号 | Tab | 条件 | 内容组件 |
|---:|---|---|---|
| 1 | 病历 | 始终 | 内联表单 |
| 2 | 医生备注 | 始终 | `NoteTimeline` |
| — | 跟踪备注 | **已注释,不渲染** | 原拟 `TrackingNoteTimeline``edit.vue:644-654` |
| 3 | 日常记录 | `tcm.diagnosis/dailyRecord` | `DailyMatrix` |
| 4 | 处方 | `tcm.diagnosis/chufang` | `CaseRecordList` |
| 5 | 业务订单 | `tcm.diagnosis/patientOrders` | `PatientOrderList` |
| 6 | 视频录制回放 | `tcm.diagnosis/huifang` | `CallRecordPanel` |
| 7 | 聊天 | `tcm.diagnosis/chat` | `ImChatRecordPanel` |
| 8 | 指派医助记录 | `tcm.diagnosis/assign``tcm.diagnosis/detail` | `AssignLogPanel` |
| 9 | 挂号记录 | `doctor.appointment/lists` | `AppointmentRecordPanel` |
权限变化后若当前 Tab 失权,代码会主动回到 `basic``edit.vue:883-913`)。除病历外的大部分 Tab 为 lazy 内容,首次选中才加载。
### 4.4 病历表单布局、标签和控件
桌面表单 label width 为 160 px`edit.vue:61-63`)。根字号、label、输入/textarea/radio/checkbox/button 均显式为 12 pxlabel 为 500 / `#606266``edit.vue:1476-1504,1532-1556`)。表单项底部间距 18 px`edit.vue:1528-1530`)。输入、选择、日期、数字框圆角 10 px(`edit.vue:1645-1667`);普通输入高度沿用 Element 32 px。
分组标题的上/下外边距为 28/22 px;中间文字 14 px / 600 / `#0f172a``7px 16px` 内边距、999 px 胶囊圆角,两侧 1 px `#e2e8f0` 横线(`edit.vue:1506-1525`)。单选紧凑组换行、gap 12 px;复选组 gap `12px 16px`;普通 radio/checkbox 右、下间距分别 16/8 px`edit.vue:1558-1604`)。帮助文本 12 px、`#909399`、行高 1.5、顶部 4 px`edit.vue:1606-1611`)。
### 4.5 编辑表单的真实字段顺序
以下只列实际渲染字段,不把 `formData` 中未渲染的属性当作 UI(模板 `edit.vue:57-632`):
| 区段 | 栅格 | 字段顺序与控件 |
|---|---|---|
| 顶部 | 24 | 诊单ID(只读) |
| 基本身份 | 12 + 12 | 姓名;身份证 |
| 联系信息 | 12 + 12 | 手机;性别 |
| 年龄 | 12 | 年龄 |
| **生命体征** | 8 + 8 + 8 | 婚姻;身高;体重 |
| | 8 + 8 + 8 | 地区;高压;低压 |
| | 8 | 空腹血糖 |
| | 12 | 诊断类型 |
| | 12 + 12 | 状态;渠道 |
| | 12 | 统计端就诊卡 |
| | 12 | 在用药物,textarea3 行,maxlength 2000 |
| **主诉** | 12 + 12 | 当地诊断日期;糖尿病病史 |
| | 24 | 当地医院诊断结果(check buttons |
| | 24 | 当地医院名称 |
| **现病史** | 24 | 口腔感觉(check buttons |
| | 24 | 每日饮水量(radio buttons |
| | 24 | 近月体重变化(radio buttons |
| | 24 | 脂肪肝(radio buttons |
| | 24 | 饮食(check buttons |
| | 24 × 9 | 肢体、睡眠、眼睛、头部、出汗、皮肤、小便、大便、腰肾 |
| | 24 | 其他补充,textarea3 行 |
| **既往史** | 24 | 既往史(check buttons |
| **其他病史** | 8 + 8 + 8 | 外伤;手术;过敏 |
| | 12 + 12 | 家族;妊娠 |
| **诊断信息** | 24 | 病史补充,textarea2 行 |
具体模板行:顶部/身份 `edit.vue:86-194`;生命体征 `edit.vue:199-368`;主诉 `edit.vue:369-412`;现病史 `edit.vue:414-549`;既往史 `edit.vue:552-564`;其他病史 `edit.vue:567-613`;诊断信息 `edit.vue:616-629`
当前模板没有显示 `syndrome_type``diabetes_type`、舌象、脉象、治则、医嘱等字段,即便脚本模型中存在,也不应擅自加入视觉复刻。
### 4.6 移动端
小于等于 768 px 时(`edit.vue:1876-2004`):
- Drawer 变为 100vwheader `12px 14px`body `10px 12px`
- Footer 改为纵向、按钮全宽,gap 10 px,内边距 `12px 14px + safe-area`,按钮最小 44 px。
- 标题 17 pxTab 高/行高 44 px、字号 13 px、水平内边距 12 px。
- label 改到控件上方:100% 宽、左对齐、下间距 6 px;表单项底部 14 px。
- 所有 `el-col` 强制 100%,数字框 100%radio gap `8px 16px`checkbox `8px 10px`
- 分组标题外边距 18/14 px,文字 13 px、水平内边距 10 px。
```text
移动端(<=768
┌──────────────────────┐
│ 标题 [状态] × │
│ 患者 · 诊单ID │
├──────────────────────┤
│ ← 可横向滚动 Tabs → │
├──────────────────────┤
│ 姓名 │
│ [__________________] │
│ 身份证 │
│ [__________________] │
│ ... 全部单列 ... │
├──────────────────────┤
│ [取消/关闭 全宽] │
│ [保存 全宽,44px+] │
└──────────────────────┘
```
---
## 5. 预约抽屉 `appointment.vue`
### 5.1 骨架与字段顺序
预约同样是 RTL 右侧 Drawer,宽 60%z-index 2000,且点击遮罩不能关闭(`appointment.vue:2-9`)。表单 label width 为 100 px`appointment.vue:19`)。
```text
┌───────────────────────────────────────────────────────────────┐
│ 预约面诊 × │
├───────────────────────────────────────────────────────────────┤
│ [今日重复预约警告 / 其他日期提示,条件显示] │
│ 上次面诊 2026-08-01 10:30 │
│ 预约方式 (●) 按时间预约 │
│ 预约类型 (●) 视频面诊 │
│ 预约患者 (●) 当前患者 │
│ 渠道来源 [请选择 ▼] │
│ 自媒体详情 [请选择 ▼] ← 仅自媒体渠道 │
│ 预约医生 ( ) 医生A ( ) 医生B ... │
│ 预约时间 [08月10日 周一] [08月11日 周二] ... │
│ ┌───────────────────────────────────────────┐ │
│ │ 可预约时段 [刷新] │ │
│ │ [09:00 可约] [09:30 已满] [10:00 可约] ...│ │
│ └───────────────────────────────────────────┘ │
│ 备注 [_________________________________________] │
├───────────────────────────────────────────────────────────────┤
│ [取消] [确认预约] │
└───────────────────────────────────────────────────────────────┘
```
字段顺序严格为(`appointment.vue:21-181`):
1. 上次面诊(文本)。
2. 预约方式(当前只呈现按时间预约)。
3. 预约类型(视频)。
4. 预约患者(当前患者)。
5. 渠道来源(必填 select)。
6. 自媒体详情(渠道命中自媒体白名单时必填)。
7. 预约医生(radio 列表)。
8. 预约时间:先日期按钮,后可预约时段矩阵。
9. 备注(textarea2 行)。
10. Footer:取消、确认预约。
### 5.2 尺寸、颜色与交互状态
- 渠道控件宽 100%、最大宽 360 px(`appointment.vue:741-750`)。
- 医生/单选组可换行,gap 12 px(`appointment.vue:752-765,911-921`)。
- 日期按钮 flex-wrap、gap 10 px、最小宽 130 px、高 40 px、字号 14 px、圆角 8 pxhover 上移 2 px并加阴影(`appointment.vue:771-789`)。
- 时段容器底 `#f8f9fa`、圆角 8 px、内边距 16 px;标题 15 px / 600 / `#303133``appointment.vue:791-808`)。
- 时段网格 `auto-fill minmax(110px,1fr)`、gap 10 px、最大高 450 px并滚动,滚动条宽 6 px(`appointment.vue:810-830`)。
- 时段卡白底,2 px `#e4e7ed` 边框、8 px 圆角、最小高 70 px、水平内边距 8 px;时间 15 px / 600 / `#303133`,状态 12 px / `#909399``appointment.vue:831-862`)。
- 可约 hover`#409eff` 边框、`#ecf5ff` 底、上移并加阴影(`appointment.vue:864-873`)。
- 不可约:`#f5f7fa` 底、opacity 0.6、文字 `#c0c4cc``appointment.vue:875-894`)。
- 选中:`#409eff → #66b1ff` 渐变、白字和阴影(`appointment.vue:896-909`)。
- Footer 右对齐、gap 12 px、上下内边距 12 px`appointment.vue:923-928`)。
状态逻辑是视觉的一部分:未选医生时显示“请先选择医生”,无排班显示空态;日期只来自当前及未来有效排班(`appointment.vue:299-326`);当天过去时段禁用(`appointment.vue:328-357`);当天已有预约显示 warning,其他日期重复信息为 info(`appointment.vue:359-375`)。提交按钮只有医生、日期、时间、渠道以及条件性渠道详情齐全,且不存在当天冲突时才可用(`appointment.vue:377-386`)。
### 5.3 响应式事实
`appointment.vue` 没有移动端 media query。内部医生、日期和 slot 网格会换行,但 Drawer 在窄屏仍保持 60% 视口宽。这是后台源码的真实缺口;PySide 若要求窗口缩小时可用,应保留桌面 60% 的视觉比例,同时设置合理最小内容宽并在不足时切到全宽/单列,而不声称这是 Vue 原实现已有行为。
---
## 6. 备注、日常记录、处方/订单与历史关联区
### 6.1 医生备注 / 舌象 / 报告
编辑 Drawer 和独立只读页均使用 `NoteTimeline``edit.vue:633-643`; `readonly.vue:56-72`)。编辑态顶部按权限显示“新增备注、选择舌象、选择报告”;只读态隐藏这些操作(`src/views/patient/reception/components/NoteTimeline.vue:1-123`)。
视觉规格(`NoteTimeline.vue:272-436`):
- 顶部动作行 gap 12 px、底部分隔线。
- 时间轴左内边距 22 px,轴线 2 px `#ebeef5`;节点 10 px、`#409eff`,外圈 `#ecf5ff`
- 日期 13 px / 600 / `#303133`,等宽数字;正文 12.5 px / `#606266` / 1.6 行高。
- 舌象缩略图 `64 × 64 px`、圆角 6 px、带边框;删除为红色动作。
- 报告文件 chip 为 `6px 10px`、圆角 6 px、12 px primary 字,最大宽 180 px。
- 上传格 `90 × 90 px`、1 px dashed `#dcdfe6`、圆角 6 px、12 pxhover 转 primary。
- 新增备注 Dialog 宽 480 pxtextarea 4 行、maxlength 500。
`TrackingNoteTimeline` 当前并未进入可见 Tab`edit.vue:644-654` 将整段注释。不能在复刻中把它当作现存“跟踪备注”页签。
### 6.2 日常记录、趋势与待办
DailyMatrix 顶部提供最近 7 天 / 30 天 / 自定义日期和日期范围;右侧有本人记录图例、编辑动作与血糖血压/饮食/运动/备注/刷新按钮,readonly 仅保留刷新(`components/DailyMatrix.vue:1-129`)。矩阵的指标顺序为:空腹、餐后2小时、其他血糖、血压、西药、胰岛素、早餐、午餐、晚餐、运动、跟踪备注(`components/DailyMatrix.vue:410-485`)。固定指标列 120 px,日期列最小 100 px。
- 根内边距 16 pxtoolbar 换行、gap 12 px、下间距 12 px`DailyMatrix.vue:1090-1105`)。
- 趋势卡上间距 16 px、内边距 `16px 18px`、圆角 10 px,图表高 280 px`DailyMatrix.vue:1124-1158`)。
- 超标红 `#dc2626` / 700;本人记录用紫色浅底,徽章 `#6d28d9 / #ede9fe / #ddd6fe``DailyMatrix.vue:1182-1225`)。
- <=768 px 时根内边距 12 px,图表内边距 12 px、高 240 px`DailyMatrix.vue:1240-1260`)。
待办区域位于 DailyMatrix 下方,标题 14 px / 600。表格字段依次为提醒时间、内容、状态、创建人、推送时间、错误信息、操作;toolbar 可筛全部/待推送/已推送/失败/已取消(`components/DiagnosisTodoList.vue:1-112`)。新增 Dialog 宽 520 px、label 100 px,字段顺序为提醒时间、内容(4 行/500 字)、提醒人;toolbar 换行、gap 8 px、下间距 12 px,分页右对齐(`DiagnosisTodoList.vue:291-319`)。
### 6.3 处方 / 病例历史
`CaseRecordList` 顶部编辑态显示小号 primary“开方”,只读时隐藏。表格字段顺序:就诊日期(120)、就诊编号(120)、诊断(min 160)、处方摘要(min 180)、医生(90)、状态(140)、操作(120 固定右侧);根内边距 20 px(`components/CaseRecordList.vue:1-39,103-106`)。
点击“开方”进入直接依赖的全局 `@/components/tcm-prescription/index.vue`,不是在诊单 Tab 内原地编辑:它另开 1200 px Drawer、禁止点遮罩关闭,表单 label 100 px`src/components/tcm-prescription/index.vue:1-10`)。编辑态顺序为:
1. 患者信息:姓名 / 性别 / 年龄三等分,电话 / 门诊号两等分。
2. 诊断信息:面象 / 舌象两等分,临床诊断整行 2 行 textarea;舌象详情和脉象详情在模板中被注释(`index.vue:11-76`)。
3. 中药处方 RP:药材总数与锁定提示;添加主方、添加辅方、处方库导入、粘贴导入;处方价格;主方卡片网格;辅方卡片网格(`index.vue:78-216`)。
4. 用法信息:处方类型、主方用法、条件性辅方用法、剂数、剂量单位、用法、服用时间、服用方式、忌口、其他说明、医师、是否共享、医师签名(`index.vue:217-531`)。
信息分区间距 20 px、内边距 16 px、底 `#f5f7fa`、圆角 6 px;标题 15 px / 600 / `#303133``index.vue:2500-2516`)。RP toolbar 可换行,gap `12px 20px`、内边距 `14px 16px`、圆角 10 px、lighter 边框;标题 16 px、说明/锁定文字 12 px。药材编辑区桌面固定 4 列、gap 12 px,卡片白底、10 px 内边距、6 px 圆角;仅在 <=960 px 时让操作按钮行占满,**没有**把 4 列药材网格降列(`index.vue:2522-2690`)。签名区最大宽 600 px、1 px `#dcdfe6`、圆角 4 px`index.vue:2694-2711`)。
保存后同一 Drawer 切换为处方预览:Tab 为“药房联 / 处方联”,上方工具条与作废/审核驳回状态,主体是 A4 `210 × 297 mm` 白纸,`8mm 10mm` 内边距、13 px 字号、28 px / 700 标题(`index.vue:536-754,2714-2782`)。患者信息是 4 列表格,药材是 2 列,底部医师/类型/天数/剂量为网格(`index.vue:2807-2966,2990-3035`)。未保存编辑态才提供 Drawer footer`index.vue:899-905`)。
### 6.4 业务订单
订单 Tab/卡片顶部先显示“全局就诊序号偏移”工具条:label、tooltip、020 数字框(宽 120 px)、保存按钮(`components/PatientOrderList.vue:7-42`)。工具条换行、`12px 14px` 内边距、1 px lighter 边框、8 px 圆角、light fill`PatientOrderList.vue:252-276`)。
订单表为 bordered + striped,字段顺序和列宽来自 `PatientOrderList.vue:44-106`
1. 订单号,min 200。
2. 全局就诊序号,96。
3. 数量统计,96Tag。
4. 金额,120,右对齐红字。
5. 医生,110。
6. 医助,110。
7. 履约状态,110Tag。
8. 创建时间,min 170。
9. 详情,100,固定右侧。
默认 page size 为 10,底部带分页,点击详情打开只读订单详情(`PatientOrderList.vue:108-148`)。
订单详情复用 `PrescriptionOrderDetailDrawer` 的 readonly 受限版,而不是订单页内展开(`PatientOrderList.vue:113-124`)。该共享 Drawer 宽 80%Header `16px 24px`,标题 18 px / 600,订单号与药房单号用圆角 Tag;加载态为 12 行 skeletonbody 水平内边距 24 px并独立纵向滚动(`src/views/consumer/prescription/components/PrescriptionOrderDetailDrawer.vue:13-50,1752-1757`)。内容顺序为:
1. 金额概览:总金额、已付总额、退款金额、需代收、已付笔数;响应式 2 / 3 / 5 列(`PrescriptionOrderDetailDrawer.vue:154-197`)。
2. 两栏主区:左侧处方详情,右侧未关联收款与关联收款;收款表顺序为 ID、单号、类型、金额、状态、方式(readonly 隐藏)、创建人、创建时间(`PrescriptionOrderDetailDrawer.vue:200-545`)。
3. 履约与收货信息:3 列 descriptionslabel 宽 120 px`PrescriptionOrderDetailDrawer.vue:551-680,1782-1785`)。
4. 物流轨迹与操作日志(有数据/开启附加加载时)(`PrescriptionOrderDetailDrawer.vue:683-824`)。
readonly 明确隐藏顶部告警、流程步骤、挂号关联、内部成本、药材明细、收款方式和外部物流更新等完整版内容,但金额概览、主辅方用量/服法和基础详情仍共享(`PrescriptionOrderDetailDrawer.vue:2-11`)。面板统一 8 px 圆角,Header `14px 16px`、Body 16 px`PrescriptionOrderDetailDrawer.vue:1759-1780`)。
### 6.5 视频、聊天与历史表
**视频录制回放。** CallRecordPanel 编辑态有上传 toolbar;字段为播放(min 320)、开始时间 170、结束时间 170、通话类型 100、房间 180、时长 110、状态 90、录制 100、上传 180(仅编辑)(`components/CallRecordPanel.vue:1-74`)。空态内边距 `28px 12px`,标题 14 px、说明 12 px / 1.6`CallRecordPanel.vue:188-214`)。内嵌视频最大高 180 px、圆角 4 px、黑底;播放覆盖层为 `rgba(0,0,0,.62)`、白色 12 px`components/RecordingVideoPlayer.vue:322-359`)。
**聊天。** 顶部 info alert + 同步/刷新 toolbar,消息区最大高 `min(60vh,520px)`、gap 16 px。单条最大宽 88%;患者消息靠左、灰底,医生消息靠右、primary 浅底;meta 12 px,气泡 14 px、1.5 行高、`10px 12px` 内边距、8 px 圆角;图片最大 `240 × 200 px``components/ImChatRecordPanel.vue:1-70,200-293`)。
**医助指派历史。** 字段依次为时间 175、原医助 min 120、新医助 min 120、继承 72 Tag、快照订单创建人 min 130、快照创建时间 190、操作人 110、账号 120、IP 130`components/AssignLogPanel.vue:1-43`)。
**挂号历史。** 字段依次为 ID 72、状态 100 Tag、患者 min 150(姓名+手机堆叠)、医生 110、医助 110、预约时间 min 130(日期+时段堆叠)、预约类型 100、渠道 110、确认 92、处方 80、备注 min 100、创建时间 165(`components/AppointmentRecordPanel.vue:1-75`)。堆叠单元垂直 gap 2 px、行高 1.35`AppointmentRecordPanel.vue:172-178`)。
### 6.6 `components/` 全目录的可达性边界
三主视图的实际 import 清单见 `edit.vue:787-805``readonly.vue:151-167`。为避免把目录中保留组件误认成当前详情功能,本次也核了其余文件:
| 组件 | 三主视图当前可达性 | 结论 |
|---|---|---|
| `PatientInfoCard``PatientCaseCard` | readonly 直接使用 | 当前只读摘要/病例 |
| `DailyMatrix``CaseRecordList``PatientOrderList``CallRecordPanel``ImChatRecordPanel``AssignLogPanel``AppointmentRecordPanel` | edit/readonly 直接使用(依页面和权限而异) | 当前主链 |
| `RecordingPlaybackBlock``RecordingVideoPlayer` | CallRecordPanel 间接使用 | 当前视频主链(`CallRecordPanel.vue:32,78`; `RecordingPlaybackBlock.vue:5,35` |
| `DiagnosisTodoList` | DailyMatrix 间接使用 | 当前日常记录主链 |
| `TrackingNoteTimeline` | edit 有 import,但模板区整段注释 | 当前不可见(`edit.vue:644-654,803` |
| `BloodRecordList` | 未被三主视图 import | 旧/独立颗粒列表;其能力已由 DailyMatrix 内置 600 px 血糖血压 Dialog 承接(`BloodRecordList.vue:1-170`; `DailyMatrix.vue:131-185` |
| `DietRecordList` | 未被三主视图 import | 旧/独立列表;当前 DailyMatrix 内置 800 px 饮食 Dialog`DietRecordList.vue:1-112`; `DailyMatrix.vue:187-227` |
| `ExerciseRecordList` | 未被三主视图 import | 旧/独立列表;当前 DailyMatrix 内置 600 px 运动 Dialog`ExerciseRecordList.vue:1-86`; `DailyMatrix.vue:229-260` |
| `TrackingMatrix` | 未被三主视图 import | 非当前矩阵;当前入口明确 import `DailyMatrix``edit.vue:796`; `readonly.vue:161` |
| `AssistantWatchCallDialog` | 未被三主视图 import | 旁路观看 Dialog,不属于诊单详情/编辑/预约;自身是 auto-fill、最小 280 px 的观看网格,gap 12 px`AssistantWatchCallDialog.vue:1-19,242-282` |
因此 PySide 对齐应以“当前可达主链”为实现范围,不能因为同目录存在旧颗粒列表而重复增加血糖、饮食、运动 Tab,也不能把观看 Dialog 或 TrackingMatrix 插入诊单详情。
---
## 7. 加载、空态、错误和权限状态
| 场景 | 后台表现 | 源码 |
|---|---|---|
| 独立详情加载 | 页面级 loading | `readonly.vue:1-2` |
| 独立详情失败 | Hero 下方错误空态卡 | `readonly.vue:31-36` |
| 无未服务记录 | Hero 灰色“从未记录”状态 | `readonly.vue:323-355` |
| 抽屉只读 | 状态 badge + disabled fieldset + 无保存 | `edit.vue:11-54,57-84,766-781` |
| 患者隐私锁定 | warning Alert,身份字段不可改 | `edit.vue:71-84` |
| Tab 失权 | 隐藏 Tab;当前失权时回 basic | `edit.vue:655-759,883-913` |
| 预约未选医生 | 时间区提示先选医生 | `appointment.vue:100-171` |
| 无排班/无时段 | 时间区空态 | `appointment.vue:100-171` |
| 当天已有预约 | warning 且禁止确认 | `appointment.vue:10-18,359-386` |
| 其他日期已有预约 | info 提示,不等同当天阻断 | `appointment.vue:359-375` |
| 表格无数据 | 各组件 Element empty/自定义空态 | `PatientOrderList.vue:1-6`; `CallRecordPanel.vue:55-74` |
操作权限应控制“是否渲染/是否可编辑”,而不是只把无权按钮做成 disabled;这正是 Tab 通过 `v-if` 实现的模式。
---
## 8. PySide6 组件映射
### 8.1 结构映射
| Vue / Element 结构 | PySide6 建议 | 必须保留的视觉行为 |
|---|---|---|
| `el-drawer` 右侧抽屉 | 模态 `QDialog` + 右侧面板,或主窗口上的遮罩 `QFrame` + 固定宽面板 | 桌面约 60% 宽;edit 在窄屏切全宽;Header/Body/Footer 三段分离 |
| Drawer body | `QScrollArea` + body widget | 只让 body 滚动,footer 不随滚动 |
| Drawer footer slot | 独立 `QFrame` + `QHBoxLayout` | 上边框、白底、固定在底部;不要放进 ScrollArea |
| `el-tabs` | `QTabWidget` / 自定义 `QTabBar + QStackedWidget` | 可横向滚动、3 px active indicator、按 canonical permission 移除页签 |
| `el-form` + `el-row/el-col` | `QFormLayout``QGridLayout` | 桌面 160 px 编辑标签 / 100 px 预约标签;窄屏改上标签单列 |
| input/select/date/input-number | `QLineEdit``QComboBox``QDateEdit``QSpinBox/QDoubleSpinBox` | 常规高 32 px、圆角 10 pxfooter 按钮 40/44 px |
| radio/checkbox button groups | `QButtonGroup` + 可换行 FlowLayout | 12 px 字号,组间 1216 px;小窗必须换行 |
| textarea | `QTextEdit/QPlainTextEdit` | 2/3/4 行按源码用途设置 minimumHeight,而非无限增高 |
| alert / empty | `QFrame + QLabel` / 统一 EmptyState | warning/info/error 色语义与文案位置一致 |
| card | `QFrame` | 白底、1 px `#e6ebf2`、14 px radius、18 px padding |
| table | `QTableView + QAbstractTableModel` | stripe、固定/最小列宽、状态 `QStyledItemDelegate` tag、右侧动作列 |
| timeline | `QListView` 或纵向 QWidget 列表 + paintEvent 轴线 | 22 px 左缩进、2 px 轴、10 px node,图片缩略图 64 px |
| appointment slot grid | `QScrollArea + FlowLayout` / `QGridLayout` 动态列 | cell min 110 × 70;选中/禁用/可用状态显式 |
| loading | overlay `QFrame` + spinner/文字 | 遮住当前内容但保留布局尺寸,异步返回后解除 |
### 8.2 推荐常量(来自源码,不是重新设计)
```text
FONT_FAMILY = "PingFang SC, Arial, Hiragino Sans GB, Microsoft YaHei"
FONT_BASE = 14
FONT_FORM = 12
CONTROL_HEIGHT = 32
FOOTER_BUTTON_HEIGHT = 40 # <=768 对应布局时 44
CARD_RADIUS = 14
CARD_PADDING = 18
CONTROL_RADIUS = 10
PANEL_GAP = 16
BORDER = #e6ebf2
BODY_BG = #f8fafc
PAGE_BG = #f6f6f6
TEXT_PRIMARY = #333333
TEXT_REGULAR = #666666
TEXT_MUTED = #999999
PRIMARY = #409eff # 继承 Element 语义主色
READONLY_ACCENT = #2563eb
READONLY_ACCENT_STRONG = #1d4ed8
```
### 8.3 PySide 字段装配顺序
为避免实现时按数据模型字母序排字段,应按以下 UI 顺序装配:
```text
编辑病历:
诊单ID
→ 姓名 / 身份证
→ 手机 / 性别
→ 年龄
→ [生命体征] 婚姻 / 身高 / 体重
→ 地区 / 高压 / 低压
→ 空腹血糖
→ 诊断类型
→ 状态 / 渠道
→ 统计端就诊卡
→ 在用药物
→ [主诉] 当地诊断日期 / 糖尿病病史
→ 当地医院诊断结果
→ 当地医院名称
→ [现病史] 口腔 → 饮水 → 体重变化 → 脂肪肝 → 饮食
→ 肢体 → 睡眠 → 眼睛 → 头部 → 出汗 → 皮肤 → 小便 → 大便 → 腰肾
→ 其他补充
→ [既往史] 既往史
→ [其他病史] 外伤 / 手术 / 过敏 → 家族 / 妊娠
→ [诊断信息] 病史补充
预约:
上次面诊 → 预约方式 → 预约类型 → 预约患者 → 渠道来源
→ [条件] 自媒体详情 → 预约医生 → 日期 → 时段 → 备注
```
---
## 9. 验收清单
1. 独立 readonly 是纵向卡片流,不出现 Tabs;抽屉 viewOnly 才是 Tabs + disabled 表单。
2. 编辑 Drawer 桌面 60%<=768 等效状态下全宽;预约 Drawer 源码没有该响应式覆盖,需明确属于适配增强。
3. 编辑桌面 label 160 px,预约 label 100 px;编辑移动端 label 在控件上方。
4. 编辑的 body 独立滚动,footer 始终可见;实现中没有把按钮放到滚动区末尾。
5. Tab 顺序与 canonical permission 一致;“跟踪备注”不渲染。
6. 编辑病历字段严格按 §4.5;不把脚本中未渲染字段自行加入。
7. 只读病例按 4/3 列网格及 §3.4 顺序;小窗若做降列,需视为桌面端增强而非源码既有行为。
8. 预约状态至少覆盖:未选医生、无排班、可约、不可约、选中、当天冲突、其他日期提示、loading。
9. 订单、备注、视频、聊天、指派历史、挂号历史的列顺序/动作显隐与 §6 一致。
10. 所有表格提供 loading、empty、error;权限失去时移除入口并将当前页回退到可见页。
以上规格记录的是当前后台源码的可见事实;PySide 可为桌面小窗增加降列和全宽适配,但不得改变字段顺序、权限门槛、状态语义或主操作位置。