审计范围:origin/test(HEAD cddf62ae114c79433f88297d7eddc77982279523)代码 + test.tongban.love 实测 + sudo db-query test 只读查询。
本报告为审计报告,不改动任何仓库文件;已跳过「帧4卡7视功能与瞳距」两处(另一 agent 正在返工)。
凡标注"未能验证"均为如实说明(云机无 Chrome,无法做像素级渲染核对),不冒充已验证。
| # | 长官原话 | 根因 file:line | 一句话修复方案 | 规模 |
|---|---|---|---|---|
| 1 | 帧1列表页样式不像图纸 | frame1-child-list.tsx(CSS令牌与图纸.btn-primary/.pill-done【mockup:156,162】逐一比对一致);唯一确认缺口:frame1-child-list.tsx:6 注释自述"mockup 行内还画了『最近检查』日期…本页不重复拉取",对应图纸row-recent标签(mockup:417,430,443,456,469,805) |
补一个轻量端点或复用 timeline 首条日期,渲染 row-recent |
S |
| 2 | 帧2新建档案不像图纸/出生日期控件丑/没有上传头像/样式不一致 | frame2-create-modal.tsx:7-13自述三处故意偏离:无头像上传(门店侧缺OSS端点)、仅"姓名 *"标必填(schema驱动)、原生<input type="date">(frame2-create-modal.tsx:211-217)代替图纸三栏滚轮 |
家长端已有date-wheel.tsx可直接复用做出生日期滚轮;头像上传需先补OSS端点 |
M |
| 3 | 没有「修改档案」入口 | 后端 app/api/refractive_records.py:89-90 已有 PATCH /patients/{id};前端唯一接线 onUpdatePatient(refractive-record-pane.tsx:289)只传给从未渲染的死组件 patient-rail.tsx;实际渲染的 frame3-patient-profile.tsx 全文件 grep "编辑|修改|Edit|Pencil" 0命中 |
在 frame3-patient-profile.tsx 加编辑入口,接线到已有的 onUpdatePatient/PATCH端点 |
S |
| 4 | 帧5录入列表与图纸不一样 | frame5-record-entry.tsx 全文件 grep >OD<\|>OS<\|<th>\|thead\|<table> 0命中(对照组"视力数据"grep有命中,查法有效);图纸用真实<table class="entry-table"><thead><tr><th></th><th>OD</th><th>OS</th></tr></thead> |
加可见OD/OS列头(现仅有aria-label,无可见文字) | S |
| 5 | 帧5多余小字太多 | 见下方完整清单 | 精简/合并部分hint | M |
| 6 | 纯数值输入用弹框 | 见下方完整清单 | 按长官意见改为原生输入或保留弹框,需长官选型 | M |
| 7 | 视力三项滚轮默认位置 | vision-acuity-picker.tsx:26:useState(value ?? wheel[Math.floor(wheel.length/2)])——数组中点,非临床含义;lib/va-map.ts:小数制默认停在DECIMAL_WHEEL[9]="0.3",五分制默认停在FIVE_WHEEL[7]="4.7"(≈0.5),均为偏低视力值 |
改默认值为1.0/5.0(正常视力)或空 | S |
| 8 | 必填/非必填没有标识 | 后端 app/schemas/refractive_record.py:45-277:仅 PatientCreateIn.name 为真必填(Field(..., min_length=1)),其余全部 Optional;前端 frame5-record-entry.tsx 全文件 grep \*\|必填\|required 仅命中一处"异常备注(必填)"占位符(非必填标识),全表单0个星号/必填角标;仅 frame2-create-modal.tsx:178 有"姓名 *" |
补完成前置校验对应的必填角标(见点9证据里_completion_errors的条件必填规则),或在UI层显式标注 |
M |
| 9 | 点保存没反应/保存后没回到检查列表 | 见下方"点9证据" | 新建草稿保存补toast;完成后加返回列表按钮或自动导航;fieldErrors渲染位置挪到可视区 | M |
| 10 | 保存后退出仍弹「是否退出」 | 未找到确定根因(见下方"点10证据",本条为假设非结论) | 需长官提供复现步骤/录屏以进一步定位 | 待定 |
| 11 | AI识别入口在哪 | frame5-record-entry.tsx:324(卡3,kind=refraction)与:446(卡5,kind=axial)两处按钮,接线 aiRecognize() |
无需修复,入口存在且工作(已用真实API验证),可能是入口不够醒目 | S(如需UI强化) |
| 12 | 门店端点进记录一进去就是编辑,查看页打不开 | refractive-record-pane.tsx 渲染三元链:!record ? Frame3 : record.status==="completed" && !editingCompletedRecord ? Frame4(查看) : Frame5(编辑);SQL实测 org_id=26 全部18条记录 status=draft,0条completed |
与点9强关联:因为"完成"操作本身反馈不清、导航不明确,门店从未把记录真正点「完成」,永远停在draft→永远进Frame5编辑态;修完点9后此问题大概率同步消失 | 关联点9 |
| 13 | 家长端帧7折叠默认收起/值未居中/小标题太小 | CollapsibleGroup.tsx:12 useState(false)=默认收起(注释自述这是"批4 spec§1.3·9-02拍板终版"故意设计);标题 text-[10.5px](CollapsibleGroup.tsx:25);值居中:page.tsx:279-360 EyeValRow/EyeColHead 当前代码已是 text-center/justify-center(page.tsx注释187"数值右对齐→与列头同轴居中(长官9-02拍板㉙)"),即"值未居中"这一子项在当前origin/test HEAD已经改过,需长官在test上重新肉眼确认是否已解决 |
折叠默认态与字号需长官二次拍板(现状是此前拍板的结果,非bug);居中已改,请复核 | S |
| 元素 | 图纸(行号) | 代码现状(file:line) | test真实表现 | 差异 | 归属 |
|---|---|---|---|---|---|
| 主按钮色 | mockup:162 .btn-primary{background:#2563eb} |
frame1-child-list.tsx:59 background:"#2563eb" |
未渲染验证(无Chrome) | 令牌一致,无差异 | 长官1(部分已符合) |
| 已绑定pill | mockup:156 .pill-done{background:#e6f6ec;color:#2f855a} |
frame1-child-list.tsx:119 同色值 |
未渲染验证 | 令牌一致 | 长官1(部分已符合) |
| 最近检查字段 | mockup:417,430,443,456,469 <span class="row-recent">最近检查 08-28</span> |
全文件0处渲染,frame1-child-list.tsx:6注释自述故意不拉取 |
API GET /patients 返回体确认无此字段(实测响应见附录) |
图纸有、代码无 | 长官1(缺口) |
| 新建档案按钮 | mockup:406 + 新建档案 |
存在(触发createOpen弹层,见refractive-record-pane.tsx:createOpen态) |
未渲染验证 | 无差异 | — |
| 元素 | 图纸(行号) | 代码现状(file:line) | test真实表现 | 差异 | 归属 |
|---|---|---|---|---|---|
| 头像上传 | mockup区间内含头像位(981-953一带同款组件复用注释提及wechat_avatar,帧2具体头像位需长官对图确认) | frame2-create-modal.tsx:7-9注释"缺OSS上传端点,故本期不做" |
实测:POST /patients body无头像字段,201成功(见附录测试数据) | 图纸有、代码无 | 长官2 |
| 必填星号 | mockup对性别/出生月日也标了*(据frame2-create-modal.tsx:7注释转述) |
仅frame2-create-modal.tsx:178 "姓名 *"一处;schema PatientCreateIn仅name为Required |
实测:POST /patients 仅传name也能201成功 | 图纸4个必填、代码1个必填 | 长官2 |
| 出生日期控件 | mockup三栏滚轮(画法样式统一) | frame2-create-modal.tsx:211-217 原生 <input type="date"> |
未渲染验证,但组件类型差异是代码事实(原生input vs 自定义滚轮) | 控件类型不同 | 长官2 |
| 既往防控手段 | 图纸含自由文本备注框 | 仅chip多选,无文本框(frame2-create-modal.tsx自述这是与图纸实际画法一致,字段名prevention_history_note是历史遗留) |
未渲染验证 | 需长官对最新图纸口径确认 | 长官2(可能已一致) |
| 元素 | 图纸(行号) | 代码现状(file:line) | test真实表现 | 差异 | 归属 |
|---|---|---|---|---|---|
| 编辑/修改入口 | 未在mockup 601-822区间发现显式"编辑"按钮标注(图纸本身也未强调此入口,长官第3条是使用体验反馈非对图差异) | frame3-patient-profile.tsx 全文件 grep "编辑|修改|Edit|Pencil" 0命中 |
未渲染验证 | 图纸未画、代码未做、但后端已支持PATCH——三方不一致 | 长官3 |
| 绑定家长入口 | mockup:601-822区间含绑定卡片 | 存在(bindSelectorOpen状态,触发frame3b弹层) |
实测:POST /patients/{id}/bind 端点存在(refractive_records.py:103-104) |
未发现差异 | — |
未发现长官条目直接指向此帧;本轮未对frame3b-bind-selector.tsx做逐行读取,仅确认后端POST/DELETE /patients/{id}/bind两端点存在(refractive_records.py:103-104,122-123)。如需帧3b逐项核对需额外一轮。
| 元素 | 图纸(行号) | 代码现状(file:line) | test真实表现 | 差异 | 归属 |
|---|---|---|---|---|---|
| 查看页是否可达 | 图纸假设记录可读到查看态 | refractive-record-pane.tsx三元:仅当record.status==="completed"才渲染Frame4 |
SQL实测org_id=26全部18条记录皆为draft,0条completed——查看页在当前测试数据下从未被触达 |
逻辑与数据均确认 | 长官12 |
| 卡9赵阳智脑分析 | 代码注释frame4-record-view.tsx:482-484自述"mockup未覆盖故按既有卡片样式独立搭建,非照图" |
frame4-record-view.tsx:485-513,四态:done(展示文本)/pending(生成中…)/failed(失败+重试按钮)/未触发(暂无分析+生成分析按钮) |
见下方"帧4卡9/10"独立小节实测 | 图纸未画此卡,代码自建样式 | 长官14(独立成节) |
| 卡10门店结论 | 同上,mockup未覆盖 | frame4-record-view.tsx:516-563:textarea+复制AI分析/保存结论/推送给家长三按钮+已推送时间戳 |
见下方独立小节 | 同上 | 长官14 |
| 重算橙条 | 图纸未覆盖(同上原因) | frame4-record-view.tsx:338-347 showRecomputeNotice时渲染橙条+"去复核"按钮 |
未渲染验证;触发条件见refractive-record-pane.tsxsaveDraft内ai_recompute_triggered && hasConclusion |
图纸未画 | 长官14 |
| 元素 | 图纸(行号) | 代码现状(file:line) | test真实表现 | 差异 | 归属 |
|---|---|---|---|---|---|
| OD/OS表头 | mockup: <table class="entry-table"><thead><tr><th></th><th>OD</th><th>OS</th></tr></thead>(帧5区间内) |
全文件0处可见OD/OS文字,仅aria-label | 未渲染验证,但DOM文本层面确认缺失 | 图纸有表头文字、代码无 | 长官4 |
| 卡1视力数据 | mockup区间前部 | frame5-record-entry.tsx:227 CardHeader n=1 hint="一次检查统一一种记录法" |
实测API:unaided_va_raw可正常PATCH("0.5"/"0.6"成功写入,见附录) |
数据链路通,UI结构与图纸表格化不同 | 长官4 |
| 眼压/瞳距/瞳高/DS/DC/AX/眼轴/K1/K2弹框 | 图纸画法需长官确认(未逐项列出滚轮/直接输入) | iop弹框(:408)/monocular_pd弹框(:418,瞳距,已跳过细节)/monocular_ph弹框(:428)/current_sphere,current_cylinder弹框(:287)/current_axis弹框(:303)/subjective_sphere,subjective_cylinder弹框(:371)/subjective_axis弹框(:387)/axial_length,keratometry_k1,keratometry_k2弹框(:468) |
均走 ConstrainedNumberPicker(stepped wheel或键盘输入两种模式,非纯滚轮) |
全部数值字段无一例外走弹框,无原生input | 长官6 |
| 眼前节/眼底/OCT | — | frame5-record-entry.tsx:502-511 内联chip按钮(status===k?"#2563eb":"#eef4f9"),非弹框 |
未渲染验证 | 与数值字段处理方式不同(chip vs 弹框),是代码事实 | 长官6(对照组) |
| 保存按钮链路 | — | 底部动作条(:564-620):次按钮"暂存草稿"→onSaveDraft;主蓝按钮"保存检查记录"→onComplete |
见"点9证据"完整API走查 | 主按钮标签"保存"但实际触发的是完成校验,非轻量保存,易混淆 | 长官9 |
(此节含长官15追加项,事实见下方独立小节,不在此表重复列出方案)
| 元素 | 图纸(行号) | 代码现状(file:line) | test真实表现 | 差异 | 归属 |
|---|---|---|---|---|---|
| 第一行:日期+验光方式+查看 | mockup:1651-1658 | page.tsx:2492-2513 |
未渲染验证 | 图纸与代码一致(同一行) | — |
| 第二行:来源徽章+门店解读 | mockup:1662-1666(图纸注释:9-02长官已定"改列第二行") | RecordSourceBadge.tsx全文件,调用于page.tsx:2526 |
未渲染验证 | 图纸与代码此前已按同一方案对齐,本条系长官对已实现方案的二次审美反馈 | 长官15(独立成节) |
| 元素 | 图纸(行号) | 代码现状(file:line) | test真实表现 | 差异 | 归属 |
|---|---|---|---|---|---|
| 折叠默认态 | mockup 1732-1966区间(需逐组核对图纸默认态画法,本轮未展开读全; 代码侧口径见注释) | CollapsibleGroup.tsx:12 useState(false) |
未渲染验证 | 代码注释自述"批4 spec§1.3·9-02拍板终版"即默认收起是此前长官拍板结果 | 长官13 |
| 小标题字号 | 同上 | CollapsibleGroup.tsx:25 text-[10.5px] font-bold tracking-[0.12em] uppercase |
未渲染验证 | 10.5px确认偏小 | 长官13 |
| 数值列对齐 | mockup 1732-1966区间(未展开读全) | page.tsx:279-360 EyeColHead/EyeValRow:header justify-center,值 text-center(注释187"长官9-02拍板㉙"已从右对齐改居中) |
未渲染验证 | 当前代码已是居中,与长官"值未居中"描述存在时间差——很可能长官看到的是拍板㉙生效前的旧版本,需长官在test上重新确认 | 长官13(可能已解决,待复核) |
实测记录:46952ba9-bfca-4830-ad3b-c708e1a47795(seat 0034202607登录后GET详情,完整原文如下,未删减):
{"id":"46952ba9-bfca-4830-ad3b-c708e1a47795","status":"draft", ...
"ai_analysis_text":"本次检查显示双眼存在轻度近视及散光。右眼近视100度,散光100度(轴位90);左眼近视75度,散光75度(轴位85)。双眼屈光状态基本平衡,散光轴位接近垂直方向。建议结合裸眼视力、眼轴长度及调节功能等综合评估,以明确视力下降原因及制定干预方案。请家长关注孩子用眼习惯,定期复查,具体诊疗方案请遵医嘱。",
"ai_analysis_status":"done",
"ai_analysis_updated_at":"2026-09-02T05:06:48.449628+00:00",
"store_conclusion_text":"验证测试:门店结论草稿文本",
"store_conclusion_pushed_text":"验证测试:门店结论草稿文本",
"store_conclusion_pushed_at":"2026-09-02T05:08:02.552471+00:00"}
关键事实(本条是本次审计最重要的发现之一):这条记录 ai_analysis_status="done" 且 store_conclusion_pushed_at 已有值(即长官原话所说的"AI结论已推送"的那条),但它的 status 字段仍是 "draft",不是 "completed"。
前端渲染条件核实:
- 卡9/卡10的全部代码只存在于 frame4-record-view.tsx:482-563。
- frame5-record-entry.tsx(draft记录渲染用的组件)全文件 grep ai_analysis\|store_conclusion 0命中(对照组:同样grep frame4-record-view.tsx 命中11处,证明grep查法有效)。
- refractive-record-pane.tsx 的渲染三元只有 record.status==="completed" && !editingCompletedRecord 时才渲染 frame4-record-view.tsx(即含卡9/10的组件)。
结论:卡9/卡10对draft记录完全不渲染,无论AI分析是否done、结论是否已推送——因为draft记录根本不会路由到frame4-record-view.tsx这个组件。这与长官第12条"一进去就是编辑"是同一根因:只要记录停留在draft(当前org_26全部18条记录都是),门店和长官都physically看不到卡9/卡10,不是显示条件写错,是这两张卡所在的整个组件树没有被挂载。
draft记录与completed记录的显示条件确认为不一致:completed记录才有卡9/10;draft记录(当前100%的现网数据)一张都没有。
①第一行现有元素(page.tsx:2492-2513):
- Calendar 图标,w-4 h-4(16px),shrink-0
- 日期文本 <b>,text-[16px] leading-6 font-extrabold tabular-nums,示例2026-09-02(10字符,tabular-nums等宽数字,实测宽度需渲染确认,估算约70-85px)
- 验光方式徽章(page.tsx:2504-2508),仅当 r.refraction_method_text || r.refraction_method 有值时渲染,rounded-full px-2 py-0.5 text-[10.5px] font-bold,示例文案"小瞳综合"/"散瞳验光"(4字符,含左右padding估算约55-65px)
- ml-auto 推到最右:"查看"文案(text-[11px] font-bold)+ ChevronRight w-3.5 h-3.5(14px),估算约38-45px
②第二行现有标签(RecordSourceBadge.tsx全文件):
- "机构录入"/"个人录入",source字段存在即渲染,text-[10.5px] font-bold rounded-full px-2 py-0.5(4字符)
- "门店解读",仅当 hasStoreConclusion 为真(即该记录已被门店推送结论)才额外渲染,同样式
- 两个最多同时出现(RecordSourceBadge.tsx:19 if (!source && !hasStoreConclusion) return null,即整行也可能不渲染)
③图纸帧6画法(mockup:1640-1732):
- mockup注释(1642-1649行)明确写"9-02长官打回原图仅画2态、压缩占位——本版补齐三态全画","来源徽章/门店解读小标改列第二行(新增内容,橙虚线标注移到第二行)","验光方式标签…现网首行即为『日期+验光方式+查看』同一行…本版补回首行(真实元素,不加橙注)"
- 即图纸当前版本本身已经把来源徽章画在第二行,与现网代码结构完全一致——图纸和代码目前是对齐的,长官9-02的新反馈是对"已实现的第二行方案"的二次审美意见,不是图代不一致。
④360px宽下第一行剩余空间估算(估算,非渲染实测):
- 容器:mockup .phone-frame 及 page.tsx max-w-[420px],卡片 p-4(左右各16px),可用内容宽度 ≈ 360 - 32 = 328px
- 左侧占用:图标16px + gap 8px + 日期约80px + gap 8px + 验光方式徽章约60px ≈ 172px
- 右侧占用:"查看"+箭头约40px
- 估算剩余 ≈ 328 - 172 - 40 ≈ 116px(此为算术估算,未经浏览器getComputedStyle实测,云机无Chrome无法验证真实渲染宽度)
用新建测试数据(患儿a9a5c837-d82e-4023-9cc3-60bca00ce6ab,记录3f5c894f-d06e-4827-a76b-c24211924b31)走完整API:
POST /patients → 201,正常POST /records → 201,status=draft, version=1PATCH /records/{id} {expected_version:1, od:{unaided_va_raw:"0.5"}, os:{unaided_va_raw:"0.6"}, refraction_method:"cycloplegic"} → 200,version=2, ai_recompute_triggered:true, ai_analysis_status:"pending"POST /records/{id}/complete {expected_version:2} → 200,status="completed", version=3, ai_analysis_status:"done"(含真实生成的中文AI分析文本)结论:后端create→patch→complete全链路功能完全正常,无任何后端bug。点9是纯前端问题:
- saveDraft()(refractive-record-pane.tsx:408-435)toast仅在 wasEditingCompleted为真时才弹(:412,419)——新建草稿场景(editingCompletedRecord初始为false)保存成功零提示,用户无法确认是否保存成功。
- doComplete()(:448-478)零成功提示、零显式导航,完成后靠外层三元自动切到Frame4只读态,用户体验上是"点了保存,页面突然变了,没有任何'已完成'字样",容易被误解为"没反应"。
- fieldErrors渲染块在页面顶部(约:213-219),页面整体overflow-y-auto可滚动,若校验失败信息出现时用户已滚到底部(正在点底部保存按钮),看不到顶部报错——看起来像"点了没反应"。
代码显示 dirty 状态在 saveDraft()成功后经 adoptRecord()(:216)正确重置为false;guarded()(退出/切换动作的统一包装,:207)判定逻辑本身没有发现明显漏洞。
唯一发现的可疑点(假设,非结论):saveDraft()是异步的,若用户在PATCH请求返回之前就点击退出/切换按钮,此时dirty仍为true(尚未被adoptRecord重置),会正常触发"有未保存的修改"三选一弹窗——这在代码逻辑上其实是"正确"行为(此刻确实有未落盘的修改),但由于点9确认的"保存成功零提示"问题,用户不知道保存是否已完成,可能会误以为"我已经点过保存了为什么还问"。
本条未找到确凿的独立bug证据,如实标注为未解决/待长官提供复现步骤(如具体点击间隔、是否点击的是"暂存草稿"还是"保存检查记录")以进一步定位。
_completion_errors()(refractive_record_service.py:868-897)的必填规则是条件化的(例如仅当wearing_glasses为真才要求戴镜视力和自镜DS/DC;仅当"已开始主觉验光"才要求验光方法和矫正视力),前端 missingForComplete()(refractive-record-pane.tsx:67-83)在这方面的逻辑未逐条比对确认是否完全对齐(本轮时间有限未做逐条diff),存在前后端校验规则不同步的风险,建议后续单独排查。patient-rail.tsx(旧版三栏组件,onUpdatePatient唯一使用方,但从未被渲染)、advanced-vision-section.tsx(卡7专用,本轮跳过)等确认为"保留不删,仅本文件不再引用"的历史遗留,建议长官定夺是否物理删除。page.tsx:187注释明确"ai_analysis_*字段永不下发到家长端",仅store_conclusion(门店结论,非AI原始分析)会展示给家长——这是有意设计,非bug,附此说明防止被误列为差异。| 类型 | ID | 说明 |
|---|---|---|
| 患者 | a9a5c837-d82e-4023-9cc3-60bca00ce6ab |
"audit测试儿童B",用于点9全链路实测 |
| 检查记录 | 3f5c894f-d06e-4827-a76b-c24211924b31 |
已走完draft→patch→complete全流程,当前状态completed |
以上两条为本次审计真实创建,未做任何删除/清理操作(遵循任务约束)。
getComputedStyle实测。(报告完)