Files
zyt/app/research/diagnosis_index_visual_spec.md
T
2026-08-11 09:12:51 +08:00

374 lines
35 KiB
Markdown
Raw 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.
# 管理端“诊单列表”视觉规格(源码基准)
> 审计日期:2026-08-10
> 唯一业务页面基准:`D:/web/zyt/admin/src/views/tcm/diagnosis/index.vue`
> 方法:只读检查 Vue 模板、同文件 scoped SCSS、直接挂载组件、全局样式、主题生成逻辑和当前锁定的 Element Plus 源码;未启动浏览器、未改业务源码。
## 1. 结论摘要
1. 该页面**没有页面内标题、说明文案或独立标题栏**。路由内容从一张无边框、无阴影的筛选卡直接开始;“新增诊单”等主操作位于第二张列表卡顶部,而不是页面标题旁。证据:`index.vue:2-154`
2. 页面是“浅灰页面底 + 两张白卡”的高密度后台列表。外层路由容器提供左右 `8px`、上下 `16px` 的留白;筛选卡和列表卡之间为 `12px`。证据:`D:/web/zyt/admin/src/layout/default/components/main.vue:2-10``index.vue:154``D:/web/zyt/admin/tailwind.config.js:103-113`
3. 顶部不是常规 tabs,而是可换行的圆角文字 chip:6 个日期入口,再接“待预约 / 已完成 / 待分配医助”,计数是文字后面的普通半透明数字,不是独立 badge。当天默认选中。证据:`index.vue:6-70,964-976,2174-2182,2222-2317`
4. 表格声明列的最小总宽约为 **1403px**;右侧固定“视频旁观” `120px` 与“操作” `340px`,合计 `460px`。窄于该宽度时由 Element Table 横向滚动,右侧两列保持 fixed。证据:`index.vue:191-342`
5. 表格使用斑马纹;普通偶数行是 `#FAFAFA`,普通悬停是 `#F8F8F8`。未确认、未挂号行还声明了左侧语义色和横向渐变,但静态渐变写在 `tr`,斑马纹及 fixed cell 的 `td` 背景可能遮住它;两类行的 hover 渐变直接写在 `td`,表现更稳定。证据:`index.vue:2723-2735`、Element Plus `table.scss:560-588,665-668`
6. 空态不是 `el-empty` 插画,而是表格默认的 **60px 高“暂无数据”文本区**;加载态是覆盖表格的半透明蒙层和 `42px` 主色环。证据:Element Plus `table.scss:52-70``loading.scss:19-73`、中文 locale `zh-cn.mjs:137`
## 2. 源码证据层级
| 层级 | 文件 | 本规格使用内容 |
|---|---|---|
| 页面模板与局部样式 | `D:/web/zyt/admin/src/views/tcm/diagnosis/index.vue:1-2766` | DOM 次序、列宽、状态类、局部尺寸和颜色 |
| 路由内容容器 | `D:/web/zyt/admin/src/layout/default/components/main.vue:1-12` | 页面底色、外层滚动、`px-2 py-4` |
| 共享组件 | `D:/web/zyt/admin/src/components/pagination/index.vue:1-50``D:/web/zyt/admin/src/components/daterange-picker/index.vue:1-49` | 分页布局、页容量、日期范围控件行为 |
| 项目全局样式 | `D:/web/zyt/admin/src/styles/index.scss:1-5``var.css:1-49``element.scss:58-68,106-115,140-151,177-201``public.scss:1-3` | 全局字体、颜色、表格、输入焦点、移动分页 |
| 项目主题 | `D:/web/zyt/admin/src/config/setting.ts:1-15``src/utils/theme.ts:3-75``src/App.vue:25-34` | 默认主色、明暗主题色派生、运行时覆盖 |
| Tailwind token | `D:/web/zyt/admin/tailwind.config.js:5-155` | 字体族、颜色映射、间距值 |
| UI 框架 | `D:/web/zyt/admin/pnpm-lock.yaml:47-49,2412-2415``node_modules/element-plus/theme-chalk/src/**` | 当前锁定 Element Plus 2.13.7 的默认组件尺寸 |
`package.json:27` 写的是兼容范围 `^2.9.4`,当前 lock 与已安装源码均为 **2.13.7**;本规格的框架默认尺寸以锁文件和当前安装源码为准。
## 3. 页面骨架与 ASCII wireframe
### 3.1 宽屏主态
```text
主内容滚动区,#F6F6F6;左右 8,上下 16
┌────────────────────────────────────────────────────────────────────────────────────────────┐
│ 筛选卡 #FFF / r4 / 无边框无阴影;内边距 12V × 16H │
│ [昨天挂号 n] [前天挂号 n] [当天挂号 n] [明天挂号 n] [后天挂号 n] [全部 n] │
│ [待预约 n] [已完成 n] [待分配医助 n] [患者姓名 / 手机号 160] [查询 32h] │
│ ──────────────────────────────────────────────────────────────────────────────────────── │
│ 挂号:[全部] [已挂号] [未挂号] │ 确认:[全部] [已确认] [未确认] 更多筛选⌄ │
│ · · · 展开时:诊断类型 / 证型 / 医助 / 最近挂号日期 / 最近指派日期 / 渠道 / 重置 · · · │
└────────────────────────────────────────────────────────────────────────────────────────────┘
12px
┌────────────────────────────────────────────────────────────────────────────────────────────┐
│ [新增诊单] [批量指派医助] [批量取消指派] 已选 n 条(按需显示) │
├────┬──────┬──────┬───────────┬──────────────┬──────┬────────┬──────┬──────┬──────────┬──────┬────────────────────┤
│ □ │ ID │ 患者 │ 性别/年龄 │ 挂号 │ 确认 │ 复诊 │ 助理 │ 开方 │未服务天数│旁观* │ 操作* │
├────┼──────┼──────┼───────────┼──────────────┼──────┼────────┼──────┼──────┼──────────┼──────┼────────────────────┤
│ □ │123 NEW│张三 │ 男 · 42岁 │[待问诊] 医生 │未确认│日期/医生│医助 │已开方│ 8 │进入 │查看 诊单 开方 … 更多│
│ │ │ │ │时间 / 渠道 │ │ │ │ │ │ │ │
├────┴──────┴──────┴───────────┴──────────────┴──────┴────────┴──────┴──────┴──────────┴──────┴────────────────────┤
│ 共 n 条 [15条/页] [<] 1 2 … [>] 前往 [ ] 页 │
└────────────────────────────────────────────────────────────────────────────────────────────┘
* 右侧固定列,共 460px
```
### 3.2 结构说明
- 外层 `main` 是整页垂直滚动容器;诊单表没有本页固定高度或纵向虚拟滚动,15 条数据会把页面自然撑高。证据:`layout/default/components/main.vue:2-11``index.vue:179-190`
- 两张卡都使用 `shadow="never"``!border-none`;保留 Element Card 的白底、裁切和 `4px` 圆角。框架默认:Element Plus `card.scss:9-17``common/var.scss:1226-1235`
- 页面根节点只设 `min-height:100%`、页面底色和水平居中;不设自身宽度、最大宽度或 padding。证据:`index.vue:2200-2206`
- 顶部全局 header、面包屑和多页签属于应用壳,不在 `index.vue` 中;它们是否出现受全局 setting 控制,不能当作本页标题复刻。
## 4. 可复刻的基础 token
### 4.1 字体与基础尺寸
| 项 | 源码确定值 | 证据 |
|---|---:|---|
| 字体族 | `PingFang SC, Arial, Hiragino Sans GB, Microsoft YaHei, sans-serif` | `tailwind.config.js:79-81``var.css:2` |
| body / Element base | `14px` | `public.scss:1-3``var.css:16` |
| small / extra-small | `13px / 12px` | `var.css:17-18` |
| 默认控件高度 | `32px` | Element Plus `common/var.scss:233-241` |
| small 控件高度 | `24px` | 同上 |
| 默认圆角 | `4px` | Element Plus `base.css:1` |
| 卡片圆角 | `4px` | Element Plus `common/var.scss:1227-1234` |
字体栅格的真实像素高度仍受 Windows 缩放、浏览器 DPR 与首个可用字体影响;页面 chip 没有固定 `height`/`line-height`,只能精确复刻 padding,不能仅凭源码承诺最终外框高度。
### 4.2 亮色主题
项目在 `App.vue` mount 时用 setting 重写 Element 语义色。默认主色不是 Element 原生蓝,而是 `#4A5DFF`。主题派生算法见 `src/utils/theme.ts:3-18,29-37,55-74`
| token | 默认运行值 | 使用处 |
|---|---|---|
| `--el-color-primary` | `#4A5DFF` | active chip、主按钮、链接、loading |
| primary light-3 / 5 / 7 / 8 / 9 | `#808EFF / #A5AEFF / #C9CEFF / #DBDFFF / #EDEFFF` | hover、focus、轻底色 |
| primary dark-2 | `#3B4ACC` | active 状态;页面另有硬编码近似值 `#3A4ACC` |
| success | `#67C23A` | 已完成 chip、已确认、成功按钮 |
| warning | `#E6A23C` | 待分配、未确认、警示行 |
| danger | `#F56C6C` | NEW、删除/取消 |
| info | `#909399` | 待预约、完成预约、次要态 |
| page / card | `#F6F6F6 / #FFFFFF` | 页面底 / 卡片与普通行 |
| primary / regular / secondary text | `#333333 / #666666 / #999999` | 标题信息 / 常规 / 辅助 |
| placeholder / disabled | `#A8ABB2 / #C0C4CC` | 空值、禁用 |
| border / light / lighter | `#DCDFE6 / #E4E7ED / #EBEEF5` | 控件、卡线、行分隔 |
| fill / light / lighter | `#F0F2F5 / #F8F8F8 / #FAFAFA` | hover、表头、斑马纹 |
| loading mask | `rgba(255,255,255,.5)` | 表格加载蒙层 |
证据:`src/config/setting.ts:9-14``src/styles/var.css:9-43`。主色的派生结果使用项目同一 `css-color-function` 算法计算;不是页面硬编码。warning/info 的页面渐变使用 `--el-color-*-rgb`,其当前框架默认分别为 `230,162,60``144,147,153`Element Plus `base.css:1`)。
### 4.3 暗色与运行时主题边界
- `.dark` 下页面底为 `#0A0A0A`、普通背景 `#1D2124`、overlay `#1D1E1F`,主/常规/次要文字为 `#E5EAF3 / #CFD3DC / #A3A6AD`lighter border 为 `#363637`。证据:`src/styles/dark.css:1-31`
- `App.vue` 根据 `useDark()` 调用主题生成器,主色仍可保持 `#4A5DFF`,但 light-* 在暗色下改用 shade 算法。证据:`src/App.vue:29-34``src/utils/theme.ts:12-18,55-77`
- setting 会从本地缓存覆盖默认颜色,因此**某个真实账号的主色/语义色可能不同**。证据:`src/stores/modules/setting.ts:12-50,65-77`。上表是无用户自定义时的确定基线。
- 页面内硬编码的 `#4A5DFF``#3A4ACC``rgba(74,93,255,...)` 不会随自定义主题变化,因而自定义主题下会出现两套蓝色。证据:`index.vue:2522-2529,2556-2559,2596-2599`
## 5. 顶部筛选卡
### 5.1 卡与第一行
筛选卡 body padding 为 `12px 16px`。第一行 `.filter-main` 是单行 flex:垂直居中、两端对齐、组间 `16px`、下边距 `8px`**自身没有 `flex-wrap`**。左侧 `.date-chips` 才可换行,chip 间距 `6px`。证据:`index.vue:3-76,2208-2225`
| 元素 | 几何/排版 | 默认/交互颜色 | 证据 |
|---|---|---|---|
| 普通日期 chip | padding `6px 12px`14px/500r6transition `.2s` | 常规 `#666` + `#F8F8F8`hover `#F0F2F5`active 白字 + 主色 | `index.vue:2227-2250` |
| chip 计数 | 与标题相隔 `4px`normal styleopacity `.8` | 跟随父 chip | `index.vue:23-24,2237-2241` |
| 待预约 | 普通 chip 外再有左 margin `8px` | info / info-light-9active info 实色 | `index.vue:26-32,2253-2265` |
| 已完成 | 左 margin `8px` | success / success-light-9active success 实色 | `index.vue:33-39,2268-2280` |
| 待分配医助 | 权限控制;外容器可换行、gap `8px`、左 margin `8px` | warning / warning-light-9active warning 实色 | `index.vue:40-70,2283-2308` |
| 待分配月份 | default 月选择器;宽 `128px` | Element 默认输入态 | `index.vue:51-60,2310-2312` |
| 待分配宽搜索 | default 输入;宽 `220px`,最大 `42vw` | Element 默认输入态 | `index.vue:61-69,2314-2317` |
| 主搜索 | default 输入宽 `160px` | placeholder“患者姓名 / 手机号” | `index.vue:72-75,2320-2326` |
| 查询 | primary default button;高 `32px`14pxr4 | 白字/主色底 | `index.vue:74`、Element Plus `button.scss:22-43,76-82` |
日期 chip 的实际顺序是:**昨天、前天、当天、明天、后天、全部**,不是按自然日期升序;随后才是 3 个业务 chip。证据:`index.vue:964-976`。页面挂载时直接选中当天并请求列表;各 chip 计数延后到 idle(不支持时延后约 `120ms`)获取,所以首帧可能只有标签、稍后才出现数字。证据:`index.vue:1046-1095,2174-2182`
### 5.2 第二行快捷筛选
- 第二行上方有 `1px solid #EBEEF5`;自身 `padding-top:8px``margin-top:8px`、水平 gap `6px`、垂直居中。证据:`index.vue:78-102,2329-2335`
- “挂号:”“确认:”为 `13px #999`label 后额外 `2px`。每组都是“全部 / 已… / 未…”。证据:`index.vue:79-97,2337-2341`
- 小 chip 最终 padding 是 `.chip-sm``4px 10px`13px、r4、透明底;hover/active 用主色文字与 primary-light-9active 权重 500。证据:`index.vue:2343-2366`
- 两组之间为 `1×14px` 的 lighter 分隔线,左右 margin `4px`。证据:`index.vue:2368-2373`
- “更多筛选”是 primary/link/small 按钮,左 margin `8px`;展开时 ArrowDown 旋转 `180°`,文字变“收起”。源码没有为该旋转指定独立 transition。证据:`index.vue:98-101,2375-2380`
### 5.3 展开筛选区
展开区使用 `v-show`,所以是即时显隐而非折叠动画。它为可换行 flex,gap `10px`,上 margin/padding 各 `8px`,顶部是 `1px dashed #EBEEF5`。证据:`index.vue:104-151,2384-2391`
控件从左到右:
1. 诊断类型 selectsmall`24px` 高);
2. 证型 selectsmall);
3. 医助 selectsmall,可搜索);
4. 最近挂号日期范围(共享 `DaterangePicker``260px` 宽、最大 100%,未传 size,故 default `32px` 高);
5. 最近指派日期范围(同上);
6. 最近挂号渠道(small,可搜索,宽 `170px`);
7. 重置(small button`24px` 高)。
证据:`index.vue:104-150,2393-2405`;共享日期组件只是透传一个 `el-date-picker`,见 `components/daterange-picker/index.vue:1-11,15-31`。因此展开区客观上混有 `24px``32px` 两种控件高度。前三个 select 没有本页固定宽度;Element Select 自身是 `width:100%` 的可收缩 flex item,最终每行宽度依赖可用空间与浏览器 flex 计算,源码不能给出一个稳定像素值。
## 6. 列表卡操作栏
- 列表卡距筛选卡 `12px`body padding 清零。证据:`index.vue:154,2408-2412`、Tailwind spacing `tailwind.config.js:103-113`
- 操作栏为左右两端布局,padding `10px 16px`,底边 `1px #EBEEF5`;未固定高度。default button 高 `32px`,故无换行时栏高至少约 `52px`。证据:`index.vue:155-177,2414-2429`
- 左侧依权限显示:primary“新增诊单”、success“批量指派医助”、warning/plain“批量取消指派”。后两者按选中状态禁用。右侧仅在选中数量大于 0 时显示 `13px #999` 的“已选 n 条”。证据:`index.vue:157-176`
- `.list-actions` 声明 `gap:8px`,但 Element 默认还有 `.el-button + .el-button { margin-left:12px }`,此处没有清零。因此相邻按钮的实际起点间空白通常是 **20px8+12**,而不是设计者表面写下的 8px。证据:`index.vue:2421-2424`、Element Plus `button.scss:72-74`
## 7. 表格规格
### 7.1 外框与表头
- 表格外围 padding `10px 16px 0`;表格宽度 100%,默认 fixed layout、无竖边框;行之间由 `1px #EBEEF5` 底边分隔。证据:`index.vue:178-190,2432-2434`、Element Plus `table.scss:11-20,188-195,217-235`
- 表头底 `#F8F8F8`、13px/600、文字 `#666`。默认 cell 水平 padding `12px`,行高 `23px`,纵向 padding `8px`,所以单行表头的理论最小高度约 **39px**(23+16,不含亚像素/边线差异)。证据:`index.vue:2710-2716`、Element Plus `table.scss:156-195``common/var.scss:1014-1031`
- 表头“未服务天数”有双态排序箭头,顺序只允许 descending → ascending;激活箭头使用主色。证据:`index.vue:297-304`、Element Plus `table.scss:548-552`
### 7.2 列宽与内容
| 次序 | 列 | 声明宽度 | 对齐/固定 | 主要视觉内容 |
|---:|---|---:|---|---|
| 1 | 选择 | `48px` | center | header 全选 + 行 checkbox |
| 2 | ID | `min 70px` | left | ID 为 14px/600;未读指派时附 small/dark/danger `NEW` |
| 3 | 患者 | `min 60px` | left | 患者名 14px/600;头像模板已注释,不显示 |
| 4 | 性别 / 年龄 | `100px` | left | `男 · 42岁`,继承表格 14px |
| 5 | 挂号 | `min 175px` | left | 预约状态 badge、医生、时间、可取消链接、最近渠道;无则“未挂号” |
| 6 | 确认 | `88px` | center | 13px 已确认/未确认文字 |
| 7 | 复诊 | `min 120px` | left | 时间、医生、可选“处方已作废” tag;无则“无” |
| 8 | 助理 | `100px` | left | 13px 次要文字,溢出 tooltip |
| 9 | 开方 | `72px` | center | 13px 已开方/未开方 |
| 10 | 未服务天数 | `110px` | center | 13px/600 tabular number,按天数绿/橙/红;可有健康打卡 tooltip |
| 11 | 视频旁观 | `120px` | center / right fixed | small link 或 12px 次要状态 |
| 12 | 操作 | `340px` | left / right fixed | 5 个 small/link 主动作 + click dropdown |
证据:`index.vue:191-406`。声明宽度/最小宽度合计约 `1403px``min-width` 列在更宽窗口可继续分配余量。右固定区域为 `120+340=460px`Element 会在滚动边缘加 fixed-column 阴影;阴影值来自框架 `common/var.scss:981-1000`
### 7.3 行高与密度
- 本页再次把 body cell 设为 `padding:8px 0`cell 内层保留 Element 的水平 `12px``23px` line-height。纯单行内容的最小行高约 **39px**。证据:`index.vue:2720-2722`、Element Plus `table.scss:188-195`
- 挂号 cell 有 `min-height:36px`、内 padding `4px 8px`、r6,所以含该列的常规数据行通常至少约 **52px**cell 36 + table 上下 16);实际由内容较高者决定。证据:`index.vue:2485-2489`
- 同一诊单多条预约时,每一后续预约额外带 `8px` top margin、`8px` top padding 和 `1px dashed #EBEEF5`,行高会显著增加,不是固定行高。证据:`index.vue:227-247,2490-2494`
- 操作区允许换行;链接数量受权限与记录状态影响,所以操作列也可能增高整行。证据:`index.vue:344-403,2683-2688`
### 7.4 斑马、hover 与业务高亮
| 状态 | 静态 | hover | 判定优先级 |
|---|---|---|---|
| 普通奇数行 | 白 `#FFF` | `#F8F8F8` | 无业务类 |
| 普通偶数行 | `#FAFAFA` | `#F8F8F8` | `stripe` |
| 未确认 | 预期左侧 `3px #E6A23C`;从左到右 warning RGB `.06 → transparent` | warning RGB `.10 → transparent`,直接覆盖 `td` | 第一优先 |
| 已确认但未挂号 | 预期左侧 `3px #909399`info RGB `.04 → transparent` | info RGB `.08 → transparent`,直接覆盖 `td` | 第二优先 |
判定函数先检查“是否确认”,只有已确认才检查“是否挂号”,所以一行不会同时得到两个业务类。证据:`index.vue:1313-1337`。页面声明见 `index.vue:2723-2735`;斑马和 hover 框架规则见 Element Plus `table.scss:560-588,665-668`
实现时必须区分“源码意图”和“浏览器可见结果”:
- 静态业务渐变在 `tr`,而偶数斑马行和 fixed cell 的背景落在 `td`;不透明 `td` 会遮住下面的 `tr` 渐变。
- 业务 hover 选择器直接命中 `td` 且带 `!important`,因此 hover 更可靠。
- `border-left` 施加在 `tr`,在 `border-collapse:separate` 的 table 中具体像素绘制还受浏览器表格格式化上下文影响。
PySide 复刻应按“意图”直接给每个可见 cell/row delegate 绘背景和 3px 左条,避免复现 CSS 遮挡缺陷;若目标是截图逐像素一致,则需先用指定 Chromium、固定数据测一张运行态截图。
### 7.5 单元格内部视觉
#### 患者与 ID
- `.patient-name` 为 14px/600、`#333`、line-height `1.3`。ID 与患者列都复用该样式。证据:`index.vue:194-212,2461-2470`
- 32×32、r8、主色渐变的头像 CSS 存在,但患者模板已注释,不参与实际页面。证据:`index.vue:207,2447-2459`
- `NEW` 是 small (`20px` 高)、danger、dark tag:白字、danger 实色底;字体 12px、r4。证据:`index.vue:198`、Element Plus `tag.scss:66-87,142-165``common/var.scss:1110-1138`
#### 挂号块
- 每个预约 badge11px/600、padding `2px 6px`、r4、下 margin `2px`;医生 14px/600 `#333`;时间 12px、上 margin `2px`。证据:`index.vue:2496-2519`
- 活跃预约 badge 为 `#3A4ACC` / `rgba(74,93,255,.15)`,时间硬编码 `#4A5DFF`;整块为 135° 蓝色渐变 `.12 → .06`,边 `rgba(74,93,255,.3)`。证据:`index.vue:2522-2531,2556-2559`
- 已完成预约用 info-dark-2 / info-light-7;爽约用 warning-dark-2 / warning-light-7。整块也分别换成 info 或 warning 透明渐变。证据:`index.vue:2533-2569`
- 最近渠道为上 margin `6px`、12px、line-height `1.35``#999`;未挂号为 13px `#A8ABB2`。证据:`index.vue:2571-2581`
#### 语义文字与 tag
- 已确认:13px/500 success;未确认:13px/600 warning。证据:`index.vue:2584-2594`
- 已开方:13px/500、硬编码 `#4A5DFF`;未开方:13px `#A8ABB2`。证据:`index.vue:2596-2605`
- 复诊时间 13px/500 `#333`,医生 12px `#999`,纵向 gap `4px`、line-height `1.35`;“处方已作废”是 small/plain/info tag。证据:`index.vue:268-285,2651-2676`
- 未服务天数:最小 `28px`、13px/600、等宽数字;空值灰 `#A8ABB2`/400`<=2` 绿 `#16A34A``3-6``#EA580C``>=7``#DC2626`。证据:`index.vue:305-316,1319-1329,2607-2632`
- 视频旁观为 12px、line-height `1.4`,左右 padding `2px`;不可进入时是 `#999`。证据:`index.vue:318-341,2690-2704`
## 8. 按钮、dropdown、tooltip
### 8.1 操作列链接
直接动作依次为:查看(primary)、诊单(primary)、开方/查看处方(primary)、预约(success)、补全身份证(warning),最后是 info“更多”。权限会移除部分按钮。证据:`index.vue:345-403`
- 均为 `size="small"``link`12px,透明边/底,padding `2px`,高度 autohover 使用各语义色的 light-3。证据:Element Plus `button.scss:223-248``element.scss:113-127`
- `.action-cell` 设 flex-wrap + `gap:4px`;但相邻 `.el-button + .el-button` 仍有 `12px` 左 margin,因此连续按钮间通常是 **16px4+12**。dropdown 外壳与前一按钮之间只有 flex gap `4px`。证据:`index.vue:2683-2688`、Element Plus `button.scss:72-74`
- 340px 操作列不足时允许链接换行;没有强制单行或省略号。
### 8.2 “更多”菜单
- click 触发、`bottom-end` 对齐。菜单项按权限/状态可包含:指派、取消指派、视频二维码、二维码、取消挂号、挂号日志、创建订单、删除。证据:`index.vue:379-403`
- Element 默认 dropdown item 为 14px、line-height `22px`、padding `5px 16px`,故普通项约 `32px` 高;菜单上下净 padding 约 `5px`r4、overlay 白底,popper 有 light border 与 shadow。hover 为 fill-light + primary。证据:Element Plus `dropdown.scss:7-24,42-70,137-176`
- 删除项有 divided 顶线,文字由 `.text-danger` 强制为 danger。证据:`index.vue:400,2706-2708`
- tooltip 使用 Element 默认 popper12px、line-height `20px`、padding `5px 11px`;实际位置由视口碰撞计算,不能从源码固定。
## 9. 分页、空态与加载态
### 9.1 分页
- 列表默认 `page=1, size=15`;共享组件页容量选项为 `[15,20,30,40]`。证据:`src/hooks/usePaging.ts:14-34``components/pagination/index.vue:18-28`
- 布局固定为 `total, sizes, prev, pager, next, jumper`,最多显示 5 个 pager,单页也不隐藏。证据:`components/pagination/index.vue:3-14,24-28`
- 容器右对齐,padding `10px 16px 16px`。默认分页按钮 `32×32px`(最小宽),14pxr2,项组间 gap token `16px`active 仅主色文字 + bold,并未启用 background 模式。证据:`index.vue:408-410,2436-2440`、Element Plus `common/var.scss:1034-1057``pagination.scss:5-67`
- page-size select 框架宽 `128px`jumper 输入 `56px`。证据:Element Plus `pagination.scss:73-75,118-150`
- 视口 `<=768px` 时,全局 CSS 隐藏 size selector 与 jumper,仍保留 total、prev、pager、next。证据:`src/styles/element.scss:177-184`
### 9.2 空态
页面没有提供 table `#empty` slot,也没有在主列表使用 `el-empty`。因此空列表为:
- sticky empty blockmin-height `60px`
- 居中纯文本“暂无数据”;
- 文字 `#999`line-height `60px`,宽 50%
- 表头、底线和分页仍存在。
证据:`index.vue:179-190`、Element Plus `table.scss:52-70``src/App.vue:5,25-28`、Element 中文 locale `zh-cn.mjs:137`
### 9.3 加载
- `v-loading="pager.loading"` 直接挂表格;普通请求开始时 loading=true,完成后 false。证据:`index.vue:179-184``src/hooks/usePaging.ts:35-72`
- 蒙层绝对覆盖 tablez-index 2000,亮色为 `rgba(255,255,255,.5)`;中央环 `42px`,主色描边 `2px`,2 秒旋转、1.5 秒 dash 动画。证据:`src/styles/var.css:41-43`、Element Plus `loading.scss:19-73,85-103``common/var.scss:1340-1349`
- 页面每 20 秒静默刷新列表和计数;标签页不可见时跳过,静默刷新不打开 loading,因此不会周期性白闪。证据:`index.vue:1098-1105,2182-2195``src/hooks/usePaging.ts:36-42,64-71`
- 首次 `pager.loading` 初值是 false,但 mount 后立即调用 `getLists()`,正常网络下会很快进入蒙层;能否肉眼看到取决于响应时长。
## 10. 响应式与滚动行为
1. `index.vue` 的 scoped 样式**没有 media query**。页面级响应式主要来自 flex-wrap、宽度上限、Element Table 横向滚动及全局分页规则。
2. body 被全局设为 `min-width:375px``overflow:hidden`;应用主内容通过 `el-scrollbar` 承担页面滚动。证据:`src/styles/public.scss:1-3``layout/default/components/main.vue:2-11`
3. 第一筛选行本身不换行。左侧日期 chip 可换行,但右侧 160px 搜索 + 32px 查询按钮仍与左侧同一 flex 行;在极窄内容宽度下可能压缩、增高左侧或溢出,源码没有把搜索行堆到下一行的断点。
4. 待分配容器可换行,宽搜索最多 `42vw`;展开筛选区可换行,两个日期范围各为 `260px``max-width:100%`。证据:`index.vue:2298-2317,2384-2405`
5. 表格 min 总宽约 1403px。Element Table 内部提供横向 scrollbar;右侧 460px fixed 区保持可见,导致很窄时可见的左侧业务列空间进一步减少。
6. 外层应用在窄屏会折叠侧栏,但那是壳层行为,不改变本页筛选/表格 DOM。证据:`src/App.vue:36-53`
7. dark mode 有完整全局变量,但页面的硬编码蓝/绿/橙/红不会自适应;其亮度对比应另做暗色运行态验收。
## 11. 直接挂载的覆盖层(不占主页面静态布局)
主列表下方常驻挂载多个异步组件或 dialog/drawer;关闭时不占主页面空间,操作后覆盖在页面之上:
| 入口 | 覆盖层 | 关键尺寸 | 证据 |
|---|---|---:|---|
| 新增/诊单 | `edit.vue` 诊单 drawer | `60%` | `index.vue:414``edit.vue:1-10` |
| 详情组件 | `detail.vue` popup | `800px` | `index.vue:415``detail.vue:1-10` |
| 开方/处方 | `tcm-prescription` drawer | `1200px` | `index.vue:416``components/tcm-prescription/index.vue:1-8` |
| 预约 | `appointment.vue` drawer | `60%` | `index.vue:417``appointment.vue:1-10` |
| 视频旁观 | AssistantWatchCall dialog | `760px`;视频 grid min `220px` | `index.vue:418-422``AssistantWatchCallDialog.vue:1-19,242-284` |
| 挂号日志 | drawer | `460px` | `index.vue:424-447` |
| 小程序二维码 | dialog | `400px`;二维码 `256×256` | `index.vue:449-481` |
| 指派医助 | dialog | `500px` | `index.vue:483-531` |
| 创建订单 | dialog | `600px` | `index.vue:533-587` |
| 补全身份证 | dialog | `400px` | `index.vue:589-615` |
| 企微记录 | drawer | `600px` | `index.vue:617-722` |
这些覆盖层说明“操作按钮点击后”的页面层级,但其完整内部视觉不应混入诊单 index 主页面的静态复刻范围。
## 12. PySide 映射建议
### 12.1 页面与筛选
| Vue/CSS 意图 | PySide 建议 | 复刻要点 |
|---|---|---|
| 外层 `el-scrollbar` + 两张 card | `QScrollArea` → 单一 `QWidget/QVBoxLayout`;卡用 `QFrame` | viewport `#F6F6F6`;外 margin `16V/8H`;卡 r4、白底、无 border/shadow;卡间 12 |
| date chips | 自定义 `FlowLayout` + checkable `QToolButton` | padding 6×12、r6、gap6;计数拼接为同一 label,保持源码顺序 |
| 业务色 chip | 同一 button class 加 dynamic property | `pending_booking/info``completed/success``pending/warning`active 白字实底 |
| 第一行搜索 | `QHBoxLayout` 右侧固定 `QLineEdit(160)` + `QPushButton` | 高 32、gap8;若追求源码一致,不自行添加窄屏 stack |
| 第二行筛选 | `QHBoxLayout`/FlowLayout + `QToolButton` | top line、上下 813pxactive primary-light-9 |
| 更多筛选 | 可显隐 `QWidget` + FlowLayout | 无动画;top dashed bordergap10small 控件 24,日期范围 32 |
Qt 没有内建通用 FlowLayout,建议采用 Qt 示例式 `FlowLayout`,并把 chip 的 `sizeHint()` 包含字体宽度、左右 12/10px padding;不要用固定总宽,否则计数从一位变三位时会截断。
### 12.2 表格
- 使用 `QTableView + QAbstractTableModel`,不要堆 15 行 QWidget。列的 initial/min widths 按本规格表设置;表头高建议从 `39px` 起,常规 row 从 `52px` 起,并由 delegate `sizeHint()` 为多预约/操作换行增高。
- 选择列用 check-state delegateID/患者、确认、复诊、开方、未服务天数分别用专用 delegate 绘文字和 tag,避免嵌套控件带来的滚动性能问题。
- 挂号列用一个复合 delegater6 的状态背景、11px badge、14px/600 医生、12px 时间、多预约虚线分隔。可点击“取消挂号”若必须嵌入,可在命中区域处理 mouse event,而不是每格常驻 QPushButton。
- 两个右固定列可用**同步滚动的双 `QTableView`**:主表隐藏最后两列,右表只显示 120/340 两列,共宽 460;共享 model、selection model、vertical scrollbar 与 row height。单一 QTableView 无 Element 的 sticky fixed-column 等价物。
- 行背景应在 delegate 对每个 cell 绘制:普通白/`#FAFAFA`hover `#F8F8F8`;业务行覆盖渐变并在第一可见 cell 绘 3px 语义条。不要把渐变只画在 viewport 底层,否则会重现 HTML `td` 遮挡问题。
- 操作列优先使用 delegate + 命中区域或常驻 `QWidget` 行容器;若用按钮,链接样式为 12px、2px padding、无背景/边框,并预留源码实际的较大按钮间距。
- 横向滚动时保持右表固定;表头与 body 必须共用列宽。多预约行要同步两张表的 row height。
### 12.3 dropdown、分页、空态、加载
- “更多”使用 `QMenu`item 高约 32、左右 padding16、14px;按权限/状态动态构建,删除项前 `addSeparator()` 且 danger 文本。
- 分页建议自定义 `PaginationBar`total、15/20/30/40 combo、prev、最多 5 页、next、jump;高度32,容器右对齐并保留 `10T/16H/16B`。窗口内容宽度 <=768 时隐藏 combo 与 jump。
- 空态在 `QTableView.viewport()` 中央放一个透明 `QLabel("暂无数据")`,有效高度 60;不要用大插画。仍显示 header 和分页。
- 加载态用覆盖 table rect 的半透明 widget:亮色 `rgba(255,255,255,.5)`,中央约 42px 主色 spinner。新请求显示;20 秒静默刷新不显示。
- 用 generation/request id 丢弃过期异步响应,并只在当前请求结束时关闭 overlay;这不是 Vue 当前 `latestOnly:false` 的视觉保证,但能避免 PySide 快速筛选时旧响应造成闪回。
### 12.4 主题与字体
- 定义集中 token,而不是把 `#4A5DFF` 散落在 QSS;但为了忠实,挂号块与“已开方”目前应保留硬编码蓝,或在设计确认后统一为 theme primary。
- Windows 上首选“Microsoft YaHei UI”还是源码的“Microsoft YaHei”会改变字宽;逐像素复刻应显式用 `Microsoft YaHei`14px CSS 大致映射为 Qt pixelSize 14,而不是 pointSize 14。
- Qt 的 devicePixelRatio 与 CSS px 不同。截图验收需固定 Windows 缩放(建议 100%)、字体、窗口内容宽度和主题。
## 13. 能从源码确定 / 不能从源码确定
### 可以确定
- DOM 顺序、无页面内标题、两张卡、每个筛选和操作入口;
- 页面局部 padding/gap/宽度、列声明宽度、固定列、颜色、字体大小/字重;
- 日期 chip 的顺序与当天默认态;
- 表格 stripe、业务类判定优先级、语义文本与预约块状态;
- 共享分页的页容量、布局、空态文案、loading 结构;
- 默认亮/暗 token 及运行时主题派生方式;
- 权限或数据条件控制哪些按钮/tag 出现。
### 仅运行态可最终确定
1. **最终换行和行高**:取决于 viewport、数据长度、按钮权限、预约条数、字体回退、DPR;chip 和多数 row 都没有固定 height。
2. **实际主题色**:setting 存在本地缓存,账号可改主色及语义色;dark 状态也来自浏览器存储/系统偏好。
3. **业务行静态渐变是否完整可见**:受 `tr` 背景、striped/fixed `td` 背景与 Chromium table paint 顺序影响;源码只能确定规则叠加关系。
4. **fixed-column 阴影和 scrollbar 尺寸**:由 Chromium/Element 的滚动状态、平台 scrollbar 策略决定。
5. **tooltip/dropdown 的最终坐标**popper 会做视口碰撞与翻转。
6. **加载态停留时间和计数出现时间**:由 API 延迟、idle callback 调度决定;静默轮询通常无蒙层。
7. **应用壳标题/面包屑/多页签**:由路由菜单、setting 和权限生成,不是 `index.vue` 的页面内视觉。
若后续要求“像素级截图一致”,应在固定 `Element Plus 2.13.7 + Chromium 版本 + 100% Windows 缩放 + 默认亮色主题 + 固定权限/样本数据` 下补一轮运行态测量;本文件已经给出源码能够保证的全部静态约束与明确边界。