chore: record session journal - 握力环训练趣味化

This commit is contained in:
2026-05-27 16:53:33 +08:00
parent 261f8315de
commit b9d2541b32
946 changed files with 107438 additions and 0 deletions
@@ -0,0 +1 @@
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
@@ -0,0 +1 @@
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
@@ -0,0 +1,106 @@
# 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` 搬出:
```ts
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`(新建)
```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
```ts
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
```ts
interface Props {
apt: Record<string, any>
diag: Record<string, any>
}
```
内部组件:把 `KVItem` / `MetricKVItem`reception 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. **回归 grep**`grep -n "isHighFastingBloodSugar\|KVItem\b" reception/index.vue` 应该只剩 `import` 语句
@@ -0,0 +1,26 @@
{
"id": "tcm-diagnosis-shared-extract",
"name": "tcm-diagnosis-shared-extract",
"title": "阈值工具与病例公共组件抽离(T4)",
"description": "T4:把 reception/index.vue 的 isHigh* 6 函数抽到 admin/src/utils/blood-thresholds.ts;把「患者信息」「患者病例」两张 card 抽到 components/{PatientInfoCard,PatientCaseCard}.vuereception/index.vue 改为引用新文件。视觉/功能 0 回归。为 T1+T2 铺路。",
"status": "completed",
"dev_type": null,
"scope": null,
"package": null,
"priority": "P2",
"creator": "codex-agent",
"assignee": "codex-agent",
"createdAt": "2026-05-05",
"completedAt": "2026-05-11",
"branch": null,
"base_branch": "fix-diagnosis-20250505",
"worktree_path": null,
"commit": null,
"pr_url": null,
"subtasks": [],
"children": [],
"parent": null,
"relatedFiles": [],
"notes": "",
"meta": {}
}