PP-03 凭据泄露处置: - 清除 wiki + 2 份历史文档中的 Redis 明文密码与公网 IP(4 文件 5 处) - wiki 新增安全告警 + 症状导航条目 - 核实降级:泄露旧密码已失效,HMS 连本地 Redis,云端闲置;公网已关闭 系统深度分析(9 维度 + 6 主题多专家组): - docs/discussions/2026-06-25-analysis/ 新增 7 文件 - 综合 6.8/10,4 CRITICAL,TOP 12 痛点,4 阶段路线图 wiki 关键数字校正(PP-02/05a fix 触发): - 迁移数 175→176(m20260626_000170) - 症状导航新增 device_readings 分区硬截止 + claim_next 注入修复条目
18 KiB
多端体验统一 — 主题综合
日期: 2026-06-25 | 分支: feat/media-library-banner | 主题负责人: 综合主持 范围: V1 上线后 6-12 个月,跨 Web / 小程序 / 适老化 / 无障碍的多端体验治理 证据基线: 所有论断附文件路径:行号,已逐项核验(见文末附录 A)
一、主题愿景 (Vision)
以"行为契约一致"取代"像素级对齐"作为多端统一的度量: 同一份交互契约、同一份设计 Token 源、同一类用户在任何端完成同等质量的操作。视觉层尊重三端语境差异(PC 鼠标精确点击 vs 手机触控 vs 老人手抖),但状态语义层(错误/空/加载/危急)必须跨端一致——同一类危急值告警在三端都拥有图标、朗读、重试与多通道触达。
当前 HMS 的多端体验是"4 处 token 副本 + 2 套请求层 + 隐式导航结构 + Web 无障碍盲区"的离散态:色值在 variables.scss:5(#C4623A 橙)、App.tsx:153/175/194/218(4 套硬编码 themeConfigs)、index.css:12(#2563EB 蓝)、token-values.ts 四处平行复制且已发生漂移;Web 与小程序的缓存 TTL(5s vs 60s)、错误映射(无 vs 有)、Token 刷新(预检 vs 响应式)三处配置已发散。本主题的目标是把"统一=改一处生效全端"从口号变为 CI 可校验的硬约束,让设计系统从"审美问题"升级为"医疗可见性错误的根因防线"。
二、专家提案摘要
| 专家 | 核心切入点 | 关键提案 |
|---|---|---|
| 设计系统架构师 | DTCG JSON 单一真相源 + 代码生成器分发三端 | DTCG tokens.json 单源 → Style Dictionary 生成 SCSS/CSS/antd themeConfigs;语义化导航契约根治 TabBar 硬编码索引;跨端语义组件契约(AlertCard/EmptyState);Web 适老化主题补盲;Figma-代码双向 sync |
| 前端架构师 | @hms/shared 跨端内核 + 契约驱动 + 性能预算 | 抽错误码/缓存策略/Token 状态机三大不变量为共享包;token 单源不统一命名空间(--erp-* / --tk-* 双轨);Web Vitals 采集 + 性能预算门禁;路由表契约收敛 PP-09/PP-06;error_code enum + codegen |
| UX 研究员 / 无障碍专家 | 真实使用情境(医护效率 + 老年降级 + WCAG) | dashboardNavMap 意图层契约;危急值多通道触达(震动/语音/横幅);Design Token v2 含四态语义 + WCAG 对比度门禁;情境感知适老化(行为信号推断);键盘快捷键 + 撤销模式 |
三专家共识点(已收敛为举措基础)
- 路由/导航契约化是 PP-06 + PP-09 共同根因解(三方都提出,措辞不同:dashboardNavMap / NavigationContract / routeConfig 扩展)。
- 设计 Token 单源 + 生成器取代手工多副本(三方一致,分歧仅在命名是否统一)。
- 危急值可达性 + WCAG 对比度门禁是无障碍从主观转客观的唯一路径。
- Web 适老化主题是系统性盲区,需补齐(小程序 58/58 覆盖,Web 0)。
主要分歧(已在第四节调和)
- token 命名空间:设计系统架构师倾向 DTCG 语义命名重整,前端架构师主张保留双命名空间(--erp-* / --tk-*)只统一源。→ 采纳前端方案(改名风险大,生成器桥接更安全)。
- 共享包粒度:前端架构师主张 packages/shared 全量抽象,设计系统架构师主张 packages/design-tokens 独立。→ 分两包但同 monorepo:design-tokens 先行,shared 内核第二轮。
- token 跨端范围:UX 专家主张视觉 token 各端独立 + 语义 token 共享,设计系统架构师倾向全量统一。→ 采纳 UX 方案(蓝橙调色板本质不同不强行统一,只统一语义层)。
三、战略举措 (Initiatives)
举措 1:路由与导航契约层 — 根治 PP-09 死链与 PP-06 角标错位
理由: PP-09(4 Dashboard 6 条死链 navigate,AdminDashboard.tsx:51/69 指向 /health/follow-ups//health/vital-signs,实际路由是 follow-up-tasks / 体征路由不存在)与 PP-06(useAlertPolling.ts:64 写死 setTabBarBadge({index:2}),但 app.config.ts:80 index 2=商城,告警应到 index 3=助手)的共同根因是路由/Tab 配置为运行时字符串字面量与裸数字索引,无单一契约源。影响面 100% 角色、100% 用户、上线即暴露。
分阶段落地点:
- Phase 0(2 周): 修 6 条死链 navigate + 清理
AdminDashboard.tsx:88 value={healthDataStats ? 0 : 0}僵尸写法;useAlertPolling.ts改resolveTabBarIndex('/pages/messages/index')动态查找。 - Phase 1(1 个月): 在
routeConfig.ts扩展dashboardNavMap(业务意图键 → path + permissions + 后端统计字段);抽useDashboardCard(intent)hook 按权限过滤卡片;CI 加 navigate 目标存在性单测(遍历 map 断言每个 path 在 routeConfig 存在)。 - Phase 2(3 个月):
packages/shared-contracts/navigation.ts跨端 NavigationContract,Web 侧边栏 + 小程序 TabBar 都从契约读取;权限字段统一从契约派生。
工作量估算: Phase 0 约 2-3 人日;Phase 1 约 5-7 人日;Phase 2 约 10-15 人日(跨端 + 类型系统差异)。 预期影响: 消灭医疗管理后台 403 死胡同与假数据展示,根除"TabBar 顺序一变就复发"的角标 bug 类。高 / 中量 KPI: navigate 死链数 = 0(CI 门禁);TabBar 角标错位 bug 复发次数 = 0;权限过滤后无权卡片不再渲染(点击前拦截率 100%)。 依赖: 后端菜单 API(Phase 2 才需扩展 path 字段);routeConfig 现有结构。
举措 2:设计 Token 单源 + 代码生成器(DTCG JSON)
理由: 当前色值/字号在 4 处平行复制且已漂移:variables.scss:5(#C4623A 橙)、App.tsx:153-218(4 套硬编码 colorPrimary)、index.css:12(#2563EB 蓝)、token-values.ts。Web 完全缺失适老化主题与 motion/a11y token。纯 SCSS 无法跨仓库收敛,已发生手工漂移。
分阶段落地点:
- Phase 1(1 个月): 新建
packages/design-tokens/(monorepo 首个共享包),DTCG JSON 为唯一源;Style Dictionary 生成三端产物(小程序 variables.scss + tokens.scss + token-values.ts;Web index.css :root + antd themeConfigs.ts);CI 加产物与源同步 diff 检查。保留双命名空间(--erp-* / --tk-*),只统一源不强行改名。 - Phase 2(3 个月): 新增四态语义 token(
--tk-state-error/empty/loading/critical) + Web 适老化 variant(controlHeight 40→52, fontSize 14→18)+ motion token(duration/easing 自动尊重 prefers-reduced-motion) + a11y token(focus-ring);Web 用户菜单增加"适老化"开关。 - Phase 3(6 个月): Figma Tokens 插件双向 sync + 视觉回归(Playwright + miniprogram-automator 核心页面截图比对) + WCAG 对比度自动化门禁(正文/背景 ≥4.5:1,关怀模式 ≥7:1)。
工作量估算: Phase 1 约 8-10 人日(含 Style Dictionary 选型与构建集成);Phase 2 约 12-15 人日;Phase 3 约 15-20 人日(含视觉回归基线调优)。 预期影响: 消灭 token 漂移(CI 硬约束),补齐 Web 适老化盲区,无障碍从主观评价转为 CI 红绿灯。中 / 大量 KPI: token 副本数从 4 → 1(CI 门禁);Web 适老化主题覆盖 0 → ≥30 核心页面;WCAG 对比度门禁通过率 100%;token 变更影响面自动标注覆盖率 100%。 依赖: pnpm workspace 接入;Antd ConfigProvider 对自定义 variant 的支持;团队 DTCG 命名培训。
举措 3:跨端语义组件契约层 — AlertCard / EmptyState / VitalCard
理由: 不追求像素级跨端一致(Ant Design vs 微信原生组件库是硬约束),而是为高频业务语义组件规定统一 TS 接口,让后端 DTO 字段名对齐组件 prop 名,减少 transform 层。优先 AlertCard(PP-06 危急值可见性)与 EmptyState(积分商城 Tab 空白 bug wiki 已记)。
分阶段落地点:
- Phase 1(1 个月): 定义
packages/shared-contracts/components.ts中 AlertCardProps(severity: critical|warning|info, title, value, action) + EmptyStateProps(icon, title, action);Web 与小程序各自实现但 satisfy interface(TS implements)。 - Phase 2(3 个月): 后端
alert_dto.rs等响应字段与契约对齐;Storybook(Web) + 组件 demo 页(小程序) 按契约生成 demo。 - Phase 3(6 个月): 扩展到 VitalCard / ErrorBoundaryFallback / LoadingState / StatusTag 共 6 类;CI 跑视觉回归保证 prop 兼容。
工作量估算: Phase 1 约 5-7 人日;Phase 2 约 8-10 人日;Phase 3 约 12-15 人日。 预期影响: 消灭两端各自重复造轮子(40+ 小程序组件与 Web Antd 隐式重复),减少前后端 DTO 不同步症状。中 / 大量 KPI: 高频业务组件契约覆盖率(AlertCard/EmptyState 优先);前端 transform 层代码行数下降;DTO ↔ prop 字段对齐率。 依赖: 举措 2 的 token 层;两端 StatusTag severity 枚举映射层(小程序 abnormal/critical vs antd error/warning)。
举措 4:危急值可达性 + 多通道触达(无障碍优先)
理由: 医疗安全信息必须多通道冗余(WCAG 2.2 Status Updates + IEC 62366 alarms 原则)。当前危急值仅靠单一角标(且写错 Tab),老年患者对延迟和字号容忍度更低。hapticHeavy() 已实现于 utils/haptic.ts 但未接入告警。
分阶段落地点:
- Phase 0(2 周): 修
useAlertPolling.ts:64角标 index bug(举措 1 联动);接入 hapticHeavy/medium。 - Phase 1(1 个月): 多通道触达:(a) 触觉 haptic;(b) elder-mode 下 TTS 语音播报/预录提示音;(c) 页面顶部 sticky 红色横幅(不依赖 Tab 切换);elder-mode 自动缩短轮询间隔 10s → 5s + 放大横幅字号。
- Phase 2(3 个月): Web 端补齐 aria-live:所有数据加载/错误/告警区域加 role=status aria-live=polite(critical 用 assertive);e2e mock 验证角标出现在正确 Tab。
工作量估算: Phase 0 约 1 人日;Phase 1 约 5-7 人日;Phase 2 约 4-5 人日。 预期影响: 危急值不再被单一视觉通道埋没,视障医护可朗读工作台状态。高 / 小量 KPI: Web aria-live 覆盖区域数(当前仅 1 处 PluginDashboardPage:448 → 目标 ≥20);危急值多通道触达覆盖率 100%;elder-mode 下告警延迟 ≤5s。 依赖: 举措 1 的 TabBar 契约;微信小程序 TTS 插件能力(可能降级预录音频)。
举措 5:医护效率层 + 情境感知适老化(差异化体验)
理由: 医护 8 小时班次高频重复操作(确认告警/回复咨询/标记随访),每次点击 + modal + 确认造成腕劳损;elder-mode 完全依赖用户主动开启,真正需要它的老年患者往往不知道。
分阶段落地点:
- Phase 2(3 个月): 键盘快捷键层(J/K 选择、Enter 详情、C 确认告警、/ 聚焦搜索,参照 Linear/GitHub);危险操作改"软删除 + 5 秒撤销"替代二次确认 modal;告警/随访批量操作;小程序医生端左滑快速完成/右滑推迟。
- Phase 3(6 个月):
useAdaptiveMode()hook 被动采集信号(连续校验失败 ≥2 次 / 触摸偏离中心 >40% / 停留时长超中位数 2 倍),顶部柔和提示邀请开启长辈模式(不静默改设置,信号只本地不上传);情感化关怀文案(异常体征不再冷冰冰,配合 AI 主动关怀)。
工作量估算: Phase 2 约 10-12 人日;Phase 3 约 12-15 人日。 预期影响: 降低医护重复劳损与误操作,把适老化从"用户主动开启"升级为"系统主动识别并邀请"。中 / 大量 KPI: 医护高频操作点击数下降 ≥30%;elder-mode 主动邀请转化率;撤销模式误操作回退成功率。 依赖: 后端撤销 API(先纯前端 5 秒延迟窗口,后端分批补);隐私政策声明(行为信号采集);法务审核情感文案。
四、专家分歧调和(Dissenting Views → 最终取舍)
| 分歧 | 设计系统架构师 | 前端架构师 | UX/无障碍专家 | 最终取舍 |
|---|---|---|---|---|
| token 命名空间 | DTCG 语义命名重整 | 保留双命名空间只统一源 | 视觉各端独立 + 语义共享 | 保留双命名 + 源统一 + 语义层共享(改名风险大,语义层价值高) |
| 共享包结构 | packages/design-tokens 独立 | packages/shared 全量抽象 | 跨端共享 token v2 | design-tokens 先行 + shared 内核第二轮(降低首轮风险) |
| 跨端统一范围 | 全量统一 | 统一源不统一命名 | 视觉独立语义统一 | 视觉层各端独立,状态语义层跨端共享(蓝橙调色板本质不同) |
| 优先级之争 | — | 与 DevOps 争优先级(PP-01/02/04 vs 前端) | — | PP-01/PP-02/PP-03 硬截止让路,PP-09/PP-06 并行(影响面 100% 用户,修复成本低) |
| 传输层抽象时机 | — | 先抽纯逻辑后抽传输层 | — | 采纳:第一轮只抽错误/缓存/状态机,axios vs Taro 延迟 |
五、速赢(Quick Wins,1-2 周可落地)
- 修 PP-09 工作台 6 条死链 navigate + value={0} 僵尸写法(
AdminDashboard.tsx:51改/health/follow-ups→/health/follow-up-tasks;:69删除或改真实体征路由;:88删除value={healthDataStats ? 0 : 0})— 约 0.5 人日,影响面 100% 角色。 - 修 PP-06 告警角标写错 Tab(
useAlertPolling.ts:64index:2 → 按app.config.ts:81pagePathpages/messages/index动态查找)— 约 0.5 人日,根除"危急值被埋没在商城 Tab"。 - 接入 hapticHeavy/medium 到告警(utils/haptic.ts 已实现未接线)— 约 0.5 人日,危急值触觉反馈。
- Web Vitals 采集 MVP(引入 web-vitals ~1KB,main.tsx 采集 LCP/CLS/INP,走现有 /analytics/batch 上报)— 约 1 人日,唯一不依赖后端可观测性落地的性能观测手段。
六、主题级风险(Risks)
- monorepo 引入增加构建复杂度:packages/ 目录首次创建,pnpm workspace 接入需同步改 apps/web 与 apps/miniprogram 的 tsconfig paths;小程序对依赖体积敏感,shared 包须支持 tree-shaking 且零浏览器 API 依赖。缓解: 第一轮只抽纯逻辑层,传输层延迟;shared 包严格 side-effect free。
- DTCG 标准对多主题支持尚在草案:项目 Web 有 4 套主题,需用 $extensions 字段扩展,可能偏离标准。缓解: Phase 1 先用单主题 + variant 覆盖,多主题 Phase 2 再处理。
- 视觉回归基线维护成本高:初始会有大量误报需调阈值。缓解: 先只对 5 个核心页面(首页/工作台/告警详情/患者详情/咨询)跑,逐步扩展。
- Web 适老化业务价值需产品确认:医疗管理后台多为医护使用,elder 模式优先级可能低于小程序适老化。缓解: 先做 motion/a11y token(医护通用受益),elder variant 待产品确认。
- 情境感知适老化涉及行为数据采集:与 PP-12 合规通道缺失形成张力。缓解: 信号只在端内计算、不落库、不上传,隐私政策声明;保留手动开关且不静默改设置。
- 跨端契约抽象过早绑定错误 shape:6 类语义组件契约若设计不当会绑定错误 API surface。缓解: 先落地 2 类(AlertCard + EmptyState)验证后再扩。
- DTCG/Figma 双向 sync 多人协作冲突:Figma 同时被多人改易冲突。缓解: 引入 lock 机制或约定"每周一次设计 sync 日"。
- 键盘快捷键与浏览器/输入法冲突:需可配置。缓解: 参照 Linear/GitHub 键位规范,提供设置页自定义。
七、路线(Roadmap,对齐总览 Phase 0-3)
| 阶段 | 时间 | 本主题交付物 |
|---|---|---|
| Phase 0 | 0-2 周 | Quick Wins 1-3(PP-09 死链 + PP-06 角标 + haptic 接入);Web Vitals MVP |
| Phase 1 | 1-3 个月 | 举措 1 Phase 1(dashboardNavMap + CI 门禁);举措 2 Phase 1(DTCG 单源 + 生成器 + CI diff 检查);举措 3 Phase 1(AlertCard + EmptyState 契约);举措 4 Phase 1(多通道触达) |
| Phase 2 | 3-6 个月 | 举措 1 Phase 2(跨端 NavigationContract);举措 2 Phase 2(四态语义 token + Web 适老化 variant + motion/a11y token);举措 3 Phase 2(DTO 对齐);举措 5 Phase 2(键盘快捷键 + 撤销模式 + 批量操作) |
| Phase 3 | 6-12 个月 | 举措 2 Phase 3(Figma 双向 sync + 视觉回归 + WCAG 门禁);举措 3 Phase 3(6 类契约全覆盖);举措 5 Phase 3(情境感知适老化 + 情感文案) |
附录 A:证据核验清单(已逐项验证)
| 论断 | 证据 | 核验结果 |
|---|---|---|
| Web 色值 #2563EB | apps/web/src/index.css:12 --erp-primary: #2563eb |
✓ |
| 小程序色值 #C4623A | apps/miniprogram/src/styles/variables.scss:5 $pri: #C4623A |
✓ |
| App.tsx 4 套硬编码 themeConfigs | apps/web/src/App.tsx:153/175/194/218 colorPrimary |
✓ |
| PP-09 死链 follow-ups | AdminDashboard.tsx:51 navigate('/health/follow-ups') vs routeConfig.ts:60 实际 /health/follow-up-tasks |
✓ |
| PP-09 死链 vital-signs | AdminDashboard.tsx:69 navigate('/health/vital-signs')(routeConfig 无此路由) |
✓ |
| 僵尸写法 value=0 | AdminDashboard.tsx:88 value={healthDataStats ? 0 : 0} |
✓ |
| PP-06 角标 index:2 | useAlertPolling.ts:64 setTabBarBadge({index:2}) vs app.config.ts:80 index 2=商城 |
✓ |
| 告警应到 index 3 | app.config.ts:81 index 3=助手(messages) |
✓ |
| Web CACHE_TTL 5s | apps/web/src/api/client.ts:11 CACHE_TTL = 5000 |
✓ |
| Web 预检 token 刷新 | client.ts:63/74 isTokenExpiringSoon |
✓ |
| 小程序 ResponseCache 60s | apps/miniprogram/src/services/request.ts:3/66 |
✓ |
| 小程序 ERROR_CODE_MAP | request.ts:15/246 |
✓ |
| Web 无 error_code 映射 | client.ts grep 无 ERROR_CODE_MAP | ✓ |
| Web aria-live 仅 1 处 | PluginDashboardPage.tsx:448 role="alert" |
✓ |
| Web 无 web-vitals | grep web-vitals/onLCP/onCLS/onINP 全 0 命中 | ✓ |
| Web 无 i18n | grep useTranslation/FormattedMessage 全 0 命中 | ✓ |
| Web 无 elder-mode | grep elder-mode/elderMode 全 0 命中 | ✓ |
| 无 packages 目录 | ls packages → NO packages dir |
✓ |
本主题与 00-INDEX.md 的 T4(僵尸 UI 清理)、PP-06(告警角标)、PP-09(Dashboard 死链)强关联,是这些上线前就绪项向"长期治理体制"的升格。