# 项目长期记忆(kyj-yanglao-web-new) ## 项目身份 湖北省养老机构系统前端(yudao 框架:Vue3 + TS + Element Plus)。重点模块:九防看板、合同(湖北2024版)、入住登记、长期/临时医嘱单、护士执行医嘱。 ## 医嘱模块(2026-08 搭建) - 长期医嘱 `long-doctor-order/`:长者 + 多条 entries 子表,条目含 status 启用/停止 - 临时医嘱 `short-doctor-order/`:一次性,无启停,含 executeTime - 护士执行 `execute-doctor-order/`:前端按频次展开待执行行 + 执行/跳过弹窗 + 打印 Dialog(v-print 走可见 Dialog,禁止离屏) - API 集中在 `src/api/elderly/elder/bed-change/index.ts` - **时间字段请求契约(双向)**:orderTime/stopTime/executeTime/planTime/execTime **双向**统一用**毫秒时间戳(13位)**。 - 请求方向:API 层 `serializeLongOrder/serializeShortOrder/serializeExecution` 把字符串转毫秒(dayjs().valueOf()) - 响应方向:API 层 `fromTs` helper 把毫秒(兼容 10 位秒)转回 `"YYYY-MM-DD HH:mm:ss"` 字符串,挂载在 5 个 GET 接口的 `.then`(getLongDoctorOrderPage / getLongDoctorOrder / getShortDoctorOrderPage / getShortDoctorOrder / getDoctorOrderExecutionPage),列表与详情/打印/表单都按字符串使用 - `planDate` 查询参数保持 `YYYY-MM-DD` 字符串(按日期匹配,不是具体时刻) - 给药三要素(frequency/medTime/route)存缩写,前端 `MED_*_OPTIONS` 翻译;状态枚举 `LONG_ORDER_STATUS` / `EXEC_STATUS` - 后端规格文档(不在项目内):用户侧 `doctor-order-backend-spec.md`,已交付后端 ## 用户偏好 / 约定 - ⚠️ **保持项目目录整洁**:非源码文件(.md 规格、交付物等)不要 Write 到项目根;交付文档走用户指定位置或先问 - 打印页(v-print)打印区必须在可见 `` 内,禁止 `position:absolute; left:-9999px` 离屏(会空白) - 列表/接口未通时填充 mock 数据便于看效果 - 多项目并行,不愿为单项目切 Node 版本(本地 Node v22 vs Vue2 项目要求 ≤20 冲突已知) ## ⚠️ axios 拦截器兼容性陷阱(已修复) - 项目拦截器 `src/config/axios/service.ts:277` 原只认 `code === 200`(`result_code=200`),code !== 200 走 `Promise.reject('error')` 分支 - **本系统后端用 `code:0` 表示成功**(医嘱/执行接口),所以**调用方 `await` 后其实是被 reject 的**,但 Network 看似"成功" - 排查信号:看到「Network 200 + 后端响应 `code:0` + UI 完全不刷新 + 没抛错」,**立刻打开 service.ts 看拦截器** - 预防范式:写接口调用方 try/catch 都按成功处理(catch 里 swallow,因为后端实际已写入),然后无条件 emit/继续 UI 流程,**关键 UI 刷新不能依赖 `await` 不抛错** - ✅ **已全量实施**:`service.ts:277` 改为 `code !== 200 && code !== 0`,兼容 yudao 标准成功码 `code:0`(不影响原 code:200 接口)。所有返回 `code:0` 的接口(含 `doctorOrderExecution/page` 读接口)现在 `await` 正常返回 data - 执行业务状态真相源:**后端 `doctorOrderExecution/page` 接口返回的 execution 记录**(含 `orderType/orderEntryId/planTime/status`)。buildRows 合并时 `execMap`(后端)优先;前端**不持久化业务状态到 localStorage**(换浏览器/清缓存/多端会不一致——用户 2026-08-26 明确否决该方案),仅在执行瞬间用纯内存 Map 防 UI 闪回。`page` 接口缺关键字段时会 `console.warn('[执行医嘱] execution 记录缺少关键字段')`——若刷新后状态回退为「待执行」,说明该接口未返回正确 execution 记录,**需后端修接口**,前端无法凭空持久 - ⚠️ **后端 planTime 入库 BUG(待修)**:`elderly/doctorOrderExecution/execute` 入库时 `planTime` 未按请求体毫秒戳精确写入,page 返回的 `planTime` 总是同一个固定值/当前时间,与前端展开值对不上。前端在 `execute-doctor-order/index.vue` buildRows 做了**精确优先 + (entry,索引) 兜底**两层匹配: 1. 精确 key = `${orderType}-${orderEntryId}-${planTime}` 2. 兜底:execution 按 `createTime` 升序、row 按 `planTime` 升序,用各自桶内索引对齐 3. 兜底命中会 `console.warn('[执行医嘱] 检测到 N 条 execution.planTime 与前端展开值不一致...')` 输出 `{rowPlanTime, execPlanTime, key}` 4. 总命中统计:`console.info('[执行医嘱] execution 合并: 精确 X / 兜底 Y / 总行 N')` - 兜底适用大多数真实场景(护士按时间顺序逐项执行),但用户倒序执行(如先点 bid 第二行)会错配。**根除需后端按请求体 `planTime` 精确入库** ## ⚠️ 表单 reset 失效陷阱(2026-08-27 已修) - **症状**:编辑→关闭→新增 → Dialog 标题误判「编辑」、选择器锁死、提交参数带旧 id - **禁用模式**:`Object.assign(form, JSON.parse(JSON.stringify(defaultForm)))` - 原因:`JSON.stringify({id:undefined, ...})` 会**丢弃 undefined 字段**(不写入 JSON 字符串) - 反序列化后 source 对象没有 `id`/`elderId` key - `Object.assign` 只复制 source 自身可枚举属性 → target 上的 `form.id` 残留不变 - **范式**:表单 reset 必须**逐字段显式重置**(`form.id = undefined; form.entries = [emptyEntry()]; ...`),不依赖 JSON 拷贝。如果 defaultForm 不含 undefined 字段才能用 JSON 拷贝路径 - 详见两个 Form.vue 文件头注释