Files

5.1 KiB
Raw Permalink Blame History

T4 · 阈值工具 + 病例公共组件抽离

来源:~/.claude/plans/6-7-fluffy-sunset.mdT4 节) 目标:把 reception/index.vue 中的工具函数和两张「患者信息 / 患者病例」卡片抽成共用模块,为 T1 只读病例页面铺路。 验收硬指标:reception/index.vue 视觉与功能 0 回归

背景

  • T1 二诊只读病例页要复用 reception/index.vue 的「患者信息」「患者病例」两张卡,且 isHigh* 阈值规则要保持一致。
  • T2 跟踪矩阵也用同一套 isHigh* 函数标红。
  • 当前两套规则只活在 reception/index.vue 内联 → 任何 T1/T2 直接 import 都办不到。

拆分

1) admin/src/utils/blood-thresholds.ts(新建)

reception/index.vue:540-599 搬出:

export function toNumeric(value: unknown): number | null
export function getBloodSugarThresholds(age: unknown): { fasting: number; postprandial: number } | null
export function isHighFastingBloodSugar(value: unknown, age: unknown): boolean
export function isHighPostprandialBloodSugar(value: unknown, age: unknown): boolean
export function isHighOtherBloodSugar(value: unknown, age: unknown): boolean
export function isHighSystolicPressure(value: unknown): boolean
export function isHighDiastolicPressure(value: unknown): boolean
export function isHighBloodPressure(row: { systolic_pressure?: unknown; diastolic_pressure?: unknown }): boolean
export function formatBp(row: { systolic_pressure?: unknown; diastolic_pressure?: unknown }): string

2) admin/src/utils/diag-display.ts(新建)

export function maskPhone(phone?: string): string
export function formatGender(g?: number): string
export function formatPeriod(period?: string): string
export function joinArray(arr: unknown): string
export function makeTextOf(diagRef: { value: any } | (() => any)): (field: string) => string

textOf 在原文件里闭包了 diag.value,抽离后做成工厂,由调用方传 ref/getter,避免把 diag 全局化。

3) admin/src/views/tcm/diagnosis/components/PatientInfoCard.vue(新建)

复用 reception/index.vue:113-127

Props

interface Props {
  apt: Record<string, any>
  diag: Record<string, any>
}

内部组件:函数式 KVItem 不需要(这张卡里没用 KVItem)。

4) admin/src/views/tcm/diagnosis/components/PatientCaseCard.vue(新建)

复用 reception/index.vue:129-233

Props

interface Props {
  apt: Record<string, any>
  diag: Record<string, any>
}

内部组件:把 KVItem / MetricKVItemreception 376-420 行的函数式组件)一起搬过来。 内部 computed:caseTypeLabel。 工具函数:从 utils 引入。

5) reception/index.vue 修改

  • import 新工具:@/utils/blood-thresholds@/utils/diag-display
  • import 新组件:PatientInfoCard / PatientCaseCard
  • 删除:540-599 行的 isHigh* / toNumeric / formatBp / joinArray / getBloodSugarThresholds(共 60 行)
  • 删除:376-420 行的内联 KVItem / MetricKVItem(共 ~45 行)
  • 删除:maskPhone / formatGender / formatPeriodutils 通用化后 reception 也用 import
  • 删除:caseTypeLabel computed(搬到 PatientCaseCard 内)
  • 替换:113-233 行两个 card div → <PatientInfoCard> <PatientCaseCard>
  • 保留:formatGenderAge(队列里的列表用,跟 card 无关)、textOf(仍要在 reception 里被用到 case card 之外的地方)

实际只要 reception/index.vue 现存的 isHigh* 用法 / KVItem 用法 / 工具函数引用 全部消失,剩下只用到 utils 和子组件即可。

6) 不修改

  • BloodRecordList.vue / DietRecordList.vue 等已有列表组件(它们用各自的内联实现,T4 不动它们 —— 后续可以渐进迁移)。
  • 对外 API、模板布局、CSS 类名 全部保持。

关键风险与缓解

风险 缓解
两张 card 视觉回归 reception 用与抽离前完全一致的 props 调用;CSS 类名(.card/.case-card/.patient-card/.kv-grid/.grid-block 等)原样搬到子组件里 <style scoped>
KVItem / MetricKVItem 函数式组件 type 漂移 子组件内部继续用 h() 函数式定义,签名不变
textOf 在 reception 顶部还有别的引用? 抽离前 grep 全文,凡是 reception 模板里非 case-card 区域用到的,由 reception 自己保留 textOf 闭包
caseTypeLabel 移走后影响外部? reception 模板里只在 case-card 里使用,搬走安全
类型声明完整性 6 个 isHigh* + formatBp / joinArray 都加 unknown 入参 + 严格 narrow,避免 any 漏判

验收

  1. 视觉reception/index.vue 接诊页 patient card / case card 像素级一致(手动 vs git diff 对比)
  2. 类型npx vue-tsc --noEmit 无新增错误(T4 文件 0 报错)
  3. 功能:reception 一遍走通:选患者、看 case card、看血糖记录红字标记、点完成接诊
  4. 可复用性T1 只读病例页能直接 import { PatientInfoCard, PatientCaseCard } from '...' 使用
  5. 回归 grepgrep -n "isHighFastingBloodSugar\|KVItem\b" reception/index.vue 应该只剩 import 语句