|
|
@@ -0,0 +1,476 @@
|
|
|
+# 2026-09-08 工作日志
|
|
|
+
|
|
|
+## 给药途径字典扩充(临时/长期/执行医嘱共用)
|
|
|
+
|
|
|
+### 需求
|
|
|
+临时医嘱单编辑弹窗的"给药途径"下拉,补充用户列出的常用给药途径缩写,重复的项不加。
|
|
|
+
|
|
|
+### 实现
|
|
|
+- **唯一源**:`src/api/elderly/elder/bed-change/index.ts` 的 `MED_ROUTE_OPTIONS`(MedOption[]),被 6 个文件共享:
|
|
|
+ - `short-doctor-order/Form.vue` + `short-doctor-order/Print.vue`
|
|
|
+ - `long-doctor-order/Form.vue` + `long-doctor-order/Print.vue`
|
|
|
+ - `execute-doctor-order/index.vue` + `execute-doctor-order/ExecuteDialog.vue`
|
|
|
+ - 加一处即全端生效
|
|
|
+- **重复判定(与现有 9 项对比)**:
|
|
|
+ - po/p.o. → 已有 po,**不加**
|
|
|
+ - iv/i.v. → 已有 iv,**不加**
|
|
|
+ - im/i.m. → 已有 im,**不加**
|
|
|
+ - ih/H/sc → ih + sc 都在,**不加**
|
|
|
+ - ivgtt/ivdrip → 已有 ivgtt/iv drip,**不加**
|
|
|
+ - inh → 已有,**不加**
|
|
|
+ - top 与现有 ext "外用" 语义相近但价值不同(top 特指皮肤/经皮),**保留为不同项**
|
|
|
+- **新增 7 项**:
|
|
|
+ ```ts
|
|
|
+ { value: 'id', label: 'id 皮内注射', cn: '皮内注射', tip: '皮试、疫苗过敏试验等' },
|
|
|
+ { value: 'sl', label: 'sl 舌下含服', cn: '舌下含服', tip: '硝酸甘油、速效救心丸等急救药' },
|
|
|
+ { value: 'top', label: 'top 皮肤外用/经皮给药', cn: '皮肤外用/经皮给药', tip: '软膏、贴片、涂抹类外用药' },
|
|
|
+ { value: 'pr', label: 'pr 直肠给药', cn: '直肠给药', tip: '栓剂、灌肠、退热等' },
|
|
|
+ { value: 'buccal', label: 'buccal 颊部给药', cn: '颊部给药', tip: '口腔黏膜贴片、含化药片' },
|
|
|
+ { value: 'ia', label: 'ia 动脉内注射', cn: '动脉内注射', tip: '介入治疗、动脉化疗等' },
|
|
|
+ { value: 'ip', label: 'ip 腹腔注射', cn: '腹腔注射', tip: '腹膜透析、腹腔化疗等' }
|
|
|
+ ```
|
|
|
+
|
|
|
+### 安全性验证
|
|
|
+- `MedOption` 是 interface,`{ value, label, cn, tip }` 全部 `string`,新增项符合
|
|
|
+- `getMedCn(options, val)`(同文件 line 481)找不到 value 时直接返回 val 兜底——零破坏性,旧数据翻译不受影响
|
|
|
+- 数组纯增,无白名单/枚举校验,不会引入运行时错误
|
|
|
+
|
|
|
+### 涉及文件
|
|
|
+- 仅 `src/api/elderly/elder/bed-change/index.ts` 1 处(+13 行)
|
|
|
+
|
|
|
+## 长期/临时医嘱操作栏新增「执行记录」按钮(9-08 上午)
|
|
|
+
|
|
|
+### 需求
|
|
|
+长期医嘱 + 临时医嘱的列表行操作栏,加一颗「执行记录」按钮,点击后弹出"医嘱执行单"(类似执行医嘱模块的打印弹窗),**只显示当前行长者**的执行记录,可打印。
|
|
|
+
|
|
|
+### 设计决策
|
|
|
+- **不复用 ExecuteDialog.vue**(那是单行执行/跳过弹窗,不是按长者汇总)
|
|
|
+- **新写 ExecutionRecordDialog.vue**(放置在 `execute-doctor-order/` 目录下,作为"按长者过滤的医嘱执行单"通用弹窗)
|
|
|
+- **不复用执行医嘱 index.vue 的 printDialogVisible**:那个弹窗强耦合当日的"长期展开 + 临时当日 + 合并"逻辑,需要全部 planTime 占位,不适合"历史执行记录"场景
|
|
|
+- 数据范围:**默认当日**(与执行医嘱模块"当日汇总"一致);长期按钮传 `orderType=1`、临时传 `orderType=2`,与后端 `doctorOrderExecution/page` 接口的 orderType 字段对齐;想看历史/跨日可下一轮加日期选择器
|
|
|
+- 表格列:与执行医嘱 all 弹窗**完全一致**(序号/长者/床位/年龄/医嘱内容/频次/给药时间/途径/计划时间/执行护士/实际时间/状态/备注),打印格式(colgroup %、`#555` 细线、A4 竖版)也复用
|
|
|
+
|
|
|
+### 实现
|
|
|
+
|
|
|
+**1) 新建 `src/views/elderly/elder/doctor-orders/execute-doctor-order/ExecutionRecordDialog.vue`**
|
|
|
+- 接收 `open(row, { orderType?, title? })`
|
|
|
+- 内部 `getDoctorOrderExecutionPage({ elderId, planDate: today, orderType?, tenantIds })`
|
|
|
+- 失败 → mock 3 条兜底(项目惯例)
|
|
|
+- 复用执行医嘱的 `formatDateTimeSplit` / `freqCn` / `timeCn` / `routeCn` / `statusText`(保持同源)
|
|
|
+- `v-print` 指令直接可用(main.ts 全局注册 vue3-print-nb)
|
|
|
+- 标题自动推断:`orderType=1` → "长期医嘱执行记录";`orderType=2` → "临时医嘱执行记录";否则"医嘱执行记录";外部传 title 优先
|
|
|
+- 信息栏:机构/执行日期/长者/类型
|
|
|
+- 空数据占位:「该长者当日暂无执行记录」
|
|
|
+
|
|
|
+**2) 修改 `long-doctor-order/index.vue`**
|
|
|
+- import `ExecutionRecordDialog from '../execute-doctor-order/ExecutionRecordDialog.vue'`
|
|
|
+- 模板:操作栏 #next 新增 `<el-button link type="warning" @click="openExecutionRecord(scope)">执行记录</el-button>`(**无 v-hasPermi**)
|
|
|
+- 模板底部挂载 `<ExecutionRecordDialog ref="execRecordRef" />`
|
|
|
+- script 新增 `execRecordRef` + `openExecutionRecord(row)`:缺 elderId 弹错误;否则 `execRecordRef.value.open(row, { orderType: 1 })`
|
|
|
+
|
|
|
+**3) 修改 `short-doctor-order/index.vue`**
|
|
|
+- 同上,但传 `orderType: 2`
|
|
|
+
|
|
|
+### 安全性
|
|
|
+- 三个接口 (`getLongDoctorOrderPage` / `getShortDoctorOrderPage` / `getDoctorOrderExecutionPage`) 都接受任意 params 透传(`params: query`),新增 `elderId` 字段后端若不支持会按 name 模糊匹配兜底
|
|
|
+- DoctorOrderExecution 类型已包含 orderContent/frequency/medTime/route/planTime/execTime/status/remark/bedName/elderName/elderAge 等所有渲染字段,**无需 join**
|
|
|
+- mock 数据行已含 elderId 字段(长期 801/802/803/804、临时 901/902),按钮触发路径完整
|
|
|
+
|
|
|
+### 类型检查(两轮)
|
|
|
+- **第一轮发现 4 个真实错误**(我引入):`DoctorOrderExecution` 接口**没有 `elderAge` 字段**,但新组件表格"年龄"列在用 → 4 处 TS2551/TS2561
|
|
|
+- **修复**:给 `bed-change/index.ts` 的 `DoctorOrderExecution` 接口补 `elderAge?: number | string`(与执行医嘱 `makeRow` 的 `elderAge: vo.elderAge ?? ''` 对齐——那里是 any 所以不报错)
|
|
|
+- **第二轮:ExecutionRecordDialog 零错误** ✅
|
|
|
+- 其余筛出的错误(long/short 的 `Form.vue` TS2322、`Print.vue` TS6133、`index.vue` 的 `getLongDoctorOrderStatusText` / `openDetail` 未使用)全是**既有基线噪声**,非本次引入
|
|
|
+
|
|
|
+### 涉及文件
|
|
|
+- 新建 1 个:`execute-doctor-order/ExecutionRecordDialog.vue`(~280 行)
|
|
|
+- 修改 3 个:`long-doctor-order/index.vue`(+13 行)、`short-doctor-order/index.vue`(+13 行)、`bed-change/index.ts`(+1 行 elderAge 字段)
|
|
|
+
|
|
|
+## 长期医嘱隐藏护士签名 + 执行记录打印列宽 + 切长者数据残留(9-08 上午)
|
|
|
+
|
|
|
+### 三个用户反馈 + 对应修复
|
|
|
+
|
|
|
+#### ① 长期医嘱编辑/打印隐藏"护士签名"和"停止护士签名"两列
|
|
|
+- **Form.vue**(编辑弹窗):删除 `<el-table-column label="护士签名">` + `<el-table-column label="停止护士签名">` 两个 el-table-column
|
|
|
+ - emptyEntry 仍保留 `nurseSign/stopNurseSign` 字段,**数据字段不删**(仅 UI 隐藏),接口兼容
|
|
|
+- **Print.vue**(打印):同步删除 th/td 对应两列,colgroup 由 12 列变 10 列
|
|
|
+ - 释放的 ~12.3% 重新分配:医嘱内容 25.64→30、备注 12.31→13.5、医嘱时间/停止时间 9.23→10.5、医生签名 6.15→7 等
|
|
|
+ - 新的 10 列:3.5 / 10.5 / 30 / 6 / 6 / 6 / 7 / 10.5 / 7 / 13.5 = 100%
|
|
|
+
|
|
|
+#### ② 医嘱执行记录打印:计划时间/实际时间列宽 + nowrap
|
|
|
+- **现象**:日期 "2026-09-08" 被 word-break: break-all 在 "-" 处强制断行成 "2026-09-" + "08 08:00" 两行
|
|
|
+- **修复**(ExecutionRecordDialog.vue):
|
|
|
+ 1. colgroup 把计划时间/实际时间列各从 8.25% → 10%(+1.75% × 2 = +3.5%)
|
|
|
+ 2. 从床位 8.25→7、医嘱内容 18.04→16.5、备注 10.31→10、频次/给药时间/年龄/途径 5.67→5.5 等"瘦"列共匀出 3.5%
|
|
|
+ 3. `.datetime` 加 `white-space: nowrap` 防止日期中间断行(双保险)
|
|
|
+
|
|
|
+#### ③ 切换长者时表格残留旧数据
|
|
|
+- **现象**(图3):信息栏显示新长者"测试离往非退住02",但表格第一行"长者"列还是旧长者"测试变更01"
|
|
|
+- **根因**:后端 `doctorOrderExecution/page` 接口**未实现 elderId 字段过滤**(透传参数被忽略),返回全量 execution 记录
|
|
|
+- **修复**(ExecutionRecordDialog.vue):
|
|
|
+ 1. **fetchList 加前端兜底过滤**:`list.value = (data.list || []).filter(r => Number(r.elderId) === Number(elderId))`
|
|
|
+ - `Number()` 兼容后端 string/number 混用
|
|
|
+ - 无论后端是否过滤,前端永远只显示当前长者
|
|
|
+ 2. **open() 立即 list.value = []** 清空(fetchList 同步执行前的极短窗口也清掉,防"旧表闪一下")
|
|
|
+
|
|
|
+### 安全性
|
|
|
+- 接口/类型零破坏性
|
|
|
+- "护士签名"字段保留在数据层(emptyEntry/默认对象/接口)—— 仅 UI 隐藏
|
|
|
+- 前端兜底过滤只对 elderId 字段做 Number 等值比较,不修改原数据
|
|
|
+
|
|
|
+### 涉及文件
|
|
|
+- 改 3 个:`long-doctor-order/Form.vue`(-16 行)、`long-doctor-order/Print.vue`(-9 行 + colgroup 重排)、`execute-doctor-order/ExecutionRecordDialog.vue`(colgroup 13 列重排 + datetime nowrap + 二次过滤 + open 清空)
|
|
|
+
|
|
|
+## 执行记录弹窗布局调整(9-08 上午,按用户截图布局范式)
|
|
|
+
|
|
|
+### 需求
|
|
|
+用户给了一张「医嘱执行单」截图作为布局范式,按其样式调整执行记录弹窗。
|
|
|
+
|
|
|
+### 截图布局要点
|
|
|
+1. 标题"医嘱执行单"居中粗体
|
|
|
+2. 信息行:机构/执行日期/长者/类型(label 加粗 + 均匀 25% 分摊)
|
|
|
+3. 表格 13 列:序号/长者/床位/年龄/医嘱内容/频次/给药时间/途径/计划时间/执行护士/实际时间/状态/备注
|
|
|
+4. **单元格垂直居中**(middle 而非 top)
|
|
|
+5. 单元格水平对齐:序号/年龄/频次/给药时间/途径/时间/护士/状态 → **居中**;长者/床位/医嘱内容/备注 → 左对齐
|
|
|
+6. 边框 #555 细线、12px 字体、thead 灰色背景
|
|
|
+
|
|
|
+### 改动(ExecutionRecordDialog.vue,CSS + colgroup)
|
|
|
+- **colgroup 微调**(按截图视觉比例):
|
|
|
+ - 序号 3.09 → 3.5、医嘱内容 16.5 → 17、床位 7 → 8.5、执行护士 7.22 → 6、长者 8.7 → 8.5、备注 10 → 9.5
|
|
|
+ - 合计 100%
|
|
|
+- **垂直对齐**:`vertical-align: top` → `middle`(截图明显居中)
|
|
|
+- **水平对齐**:
|
|
|
+ - `td` 默认 `text-align: center`
|
|
|
+ - 用 `nth-child(2/3/5/13)` 把长者/床位/医嘱内容/备注改回 `text-align: left`
|
|
|
+ - `.empty-tip` 仍居中(colspan=13 不触发 nth-child)
|
|
|
+- 保留项:信息栏 4 项、13 列顺序、边框、字体、A4 竖版、nowrap(计划时间上下两行)
|
|
|
+
|
|
|
+### 涉及文件
|
|
|
+- 改 1 个:`execute-doctor-order/ExecutionRecordDialog.vue`(CSS colgroup + td 对齐)
|
|
|
+
|
|
|
+## 医嘱执行语义核对(9-08 上午,纯调研无改动)
|
|
|
+
|
|
|
+用户提问:"临时医嘱只执行一次,长期医嘱没停止前每天都要执行,现在是按这样设计的吗?"
|
|
|
+
|
|
|
+**结论:是,完全按此设计**。代码证据(`execute-doctor-order/index.vue` buildRows):
|
|
|
+- **长期**(line 532-540):`if (e.status !== 1) return` 仅"在用";`buildExecutionPlanTimes(freq, medTime)` 展开时间点后拼 `${execDate} ${t}` → **每天用当天 execDate 重新生成一批待执行行**;换一天就是全新 planTime,无 execution 记录 → 又变"待执行"。停止后不再展开 ✅
|
|
|
+- **临时**(line 541-550):`const plan = fromTs(e.orderTime); if (plan.slice(0,10) !== execDate) return` → planTime 固定为开单时间,**只在开单当天出现一行**,换任何一天都不展开 ✅
|
|
|
+- 执行状态匹配 key = `${orderType}-${orderEntryId}-${planTime}`(含日期),天然做到"今天执行了不影响明天"
|
|
|
+
|
|
|
+### ⚠️ 已修复:非每日频次 + 欠账累积(9-08 上午,用户确认规则后实施)
|
|
|
+
|
|
|
+用户拍板的两条业务规则:
|
|
|
+1. **不限制,完全累积**(没执行就一直顺延累加)
|
|
|
+2. **停止后仍要补**(停止只代表以后不产生新的,之前欠的仍要做完)
|
|
|
+
|
|
|
+**用户原话**:"按周的话,默认就是按'医嘱时间'开始执行第一次,如果过了一周,就展开第二次,周一没执行,就周二展开,周二没执行,就周三展开。又过了一周,下下周就展开2次。以此类推。每天也是一样,今天没有执行,第二天就展开2次。"
|
|
|
+
|
|
|
+### 实现
|
|
|
+
|
|
|
+**1) `api/elderly/elder/bed-change/index.ts` 新增**
|
|
|
+- `FREQ_CYCLE_RULES`:频次 → `{ days: number[]; times: string[] }`
|
|
|
+ - days = 相邻执行日间隔天数,**数组表示循环**(`biw:[3,4]` 交替、`tiw:[2,2,3]` 循环)
|
|
|
+ - times = 每执行日内时点,后缀 `'+1'` 表示次日(q8h/q6h/q4h 跨零点)
|
|
|
+ - 覆盖 qd/bid/tid/qid/qn/q8h/q6h/q4h/qod/qw/biw/tiw/q2w/q3w/q4w
|
|
|
+- `applyMedTime(def, medTime)`:给药时间微调(仅对**单时点**频次生效,多时点保持标准排班)
|
|
|
+- `buildPendingPlanTimes({frequency, medTime, startTime, stopTime, now})` → 应执行时点数组
|
|
|
+ - `startTime`=orderTime,早于它的时点不算欠账(下午开医嘱不会倒算上午)
|
|
|
+ - `stopTime` 硬截止优先于 `now`;未停止时 `now` 默认"今天 23:59"
|
|
|
+ - `MAX_SPAN_DAYS = 3650` 防死循环
|
|
|
+- 保留旧 `buildExecutionPlanTimes`(未被本模块引用,但避免破坏潜在调用方)
|
|
|
+
|
|
|
+**2) `execute-doctor-order/index.vue` buildRows 重构(顺序调整)**
|
|
|
+```
|
|
|
+1) 拉长期医嘱 2) 拉临时医嘱
|
|
|
+3) 拉全量 execution(去掉 planDate 过滤!)→ closedSet + execMap
|
|
|
+4) 展开:长期 = 应执行 − 已闭环;临时 = 当日一次性
|
|
|
+5) 回填状态(纯精确匹配)
|
|
|
+6) 筛选 + 排序
|
|
|
+```
|
|
|
+- `closedSet`: `${orderType}-${orderEntryId}` → Set\<planTime\>;**已执行(1)/已跳过(2) 算闭环,待执行(0) 不算**
|
|
|
+- 长期展开条件由 `status !== 1` 放宽为 `status !== 1 && status !== 2`(在用 + 已停止都展开,未开始0不展开)
|
|
|
+- 停止医嘱传 `stopTime` 作硬截止
|
|
|
+- 顶部「执行日期」execDate 作为 `now` 传给 buildPendingPlanTimes → 选历史日期可回看当天欠账
|
|
|
+- **取消旧的"索引兜底"匹配**(execByEntry/rowsByEntry/DEBUG_MISMATCH 全部删除):欠账模型下行数 ≠ execution 数,索引对齐会**销错账**,宁可显示待执行
|
|
|
+- mock 首条改为 3 天前开立,便于演示欠账累积
|
|
|
+
|
|
|
+### ⚠️ 硬依赖(必须让后端配合)
|
|
|
+**后端必须精确写入前端传入的 `planTime`(YYYY-MM-DD HH:mm)**。已知后端入库 planTime 不精确,若不修复:
|
|
|
+- 已闭环集合里的 planTime 与前端生成值对不上 → 欠账无法销账 → **已执行的会重复出现**
|
|
|
+
|
|
|
+### 验证
|
|
|
+- **类型检查 6分41秒**:我改的两个文件(`api/.../bed-change/index.ts`、`execute-doctor-order/index.vue`)**零错误**;报出的 3 条在 `views/elderly/elder/bed-change/index.vue`(换床视图) 与 `ExecuteDialog.vue`(nickname),均为既有基线
|
|
|
+- **算法实跑 10 个用例全通过**(node + dayjs 临时脚本,已清理):qd 4条 / qw 3条 / 停止4条 / tid当天3条 / tid下午开1条 / qod隔日4条 / 未来医嘱0条 / 视图截止日3条 / biw 3条 / q8h跨零点2条
|
|
|
+
|
|
|
+## planTime 全链路位置速查(用户要求定位核对传参/回参)
|
|
|
+**传出(前端 → 后端)**
|
|
|
+1. 生成:`execute-doctor-order/index.vue` `makeRow(1, e, t, vo)`(:475)t 来自 `buildPendingPlanTimes`,格式 **"YYYY-MM-DD HH:mm"(16 位)**
|
|
|
+2. 取值:`ExecuteDialog.vue:120`(执行)/ `index.vue:798`(跳过)→ `planTime: row.value.planTime`
|
|
|
+3. 序列化:`api/.../bed-change/index.ts:51-55` `serializeExecution` → `toTs()` → **13 位毫秒数字**
|
|
|
+4. 发送:`api/.../bed-change/index.ts:467` `executeDoctorOrder` → POST `elderly/doctorOrderExecution/execute`
|
|
|
+
|
|
|
+**接收(后端 → 前端)**
|
|
|
+5. 接口:`api/.../bed-change/index.ts:449` `getDoctorOrderExecutionPage`
|
|
|
+6. 反序列化:`:457` `planTime: fromTs(row.planTime)`(数字→"YYYY-MM-DD HH:mm:ss";已是字符串则原样)
|
|
|
+7. 归一:`execute-doctor-order/index.vue:555` `String(r.planTime).slice(0, 16)` → 16 位
|
|
|
+8. 匹配 key:`:557` / `rowKey` `:455` = `${orderType}-${orderEntryId}-${planTime}`
|
|
|
+
|
|
|
+**⚠️ 已加临时诊断日志(核对完需删)**
|
|
|
+- `api/.../bed-change/index.ts` `executeDoctorOrder` → `console.log('[planTime-发出]', {前端原始值, 发给后端, 可读时间})`
|
|
|
+- `api/.../bed-change/index.ts` `getDoctorOrderExecutionPage` → `[planTime-收到-原始]`(含 `typeOf`)+ `[planTime-收到-转换后]`(含 matchKey)
|
|
|
+- `execute-doctor-order/index.vue` buildRows 第 4 步后 → `[planTime-展开]`(前端展开的全量待执行 key)
|
|
|
+- 判定:三条日志里 16 位 key 应完全一致;若「收到-原始」是固定值/当前时间 → 后端 planTime 写入 BUG 确认
|
|
|
+
|
|
|
+## 执行医嘱列表三项修复(9-08 下午,用户测试反馈)
|
|
|
+
|
|
|
+### 用户反馈
|
|
|
+1. 执行之后,已执行的数据在列表中不展示
|
|
|
+2. 去掉执行时间过滤后出 7298 条 = 无限展开
|
|
|
+3. planTime 日志是否够用
|
|
|
+
|
|
|
+### 根因
|
|
|
+1. `buildRows` 旧逻辑 `.filter((t) => !closed.has(t))` 把已执行/已跳过行从列表减掉 → 只显欠账
|
|
|
+2. `buildPendingPlanTimes` 下界是 `orderTime`(可能数年前医嘱),无回看窗口上限 → 历史欠账无限累积
|
|
|
+
|
|
|
+### 修复
|
|
|
+- **`api/.../bed-change/index.ts` `buildPendingPlanTimes`** 新增可选参数 `viewStart`(视图下界):
|
|
|
+ - `if (viewStart && plan < viewStart) return` 跳过早于下界的历史欠账
|
|
|
+- **`execute-doctor-order/index.vue` `buildRows`**:
|
|
|
+ - 删 `closedSet` 减集合逻辑 → 长期展开改为「展示全部应执行时点」,状态由 `execMap` 精确回填(已执行/已跳过也保留在列表,status 0/1/2 分别显示 待执行/已执行/已跳过)
|
|
|
+ - 新增窗口常量 `VIEW_PAST_DAYS=30`(回看欠账)+ `VIEW_AHEAD_DAYS=30`(提前规划,呼应"最多提前一个月")
|
|
|
+ - 长期展开传 `now = execDate+VIEW_AHEAD_DAYS 23:59:59`、`viewStart = execDate-VIEW_PAST_DAYS 00:00:00`
|
|
|
+ - 默认合计约两个月窗口,7298 问题消除(1 年前 qd 医嘱只展最近 30 天欠账而非 365 天)
|
|
|
+- **诊断日志增强**:
|
|
|
+ - 删旧 `[planTime-展开]`(仅打印 key,无法判断命中)
|
|
|
+ - 新增 step5 后 `[planTime-诊断]`:`{展开行数, 后端execution记录, 命中展开行, 未命中_后端planTime与前端展开不一致}`
|
|
|
+ - 判定:未命中 > 0 → 后端 planTime 未按请求体精确入库(已执行仍显待执行的根因);命中=后端记录数 → 前后端一致 OK
|
|
|
+
|
|
|
+### 验证
|
|
|
+- 类型检查两个改动文件零新增错误(vue-tsc 后台跑,过滤 execute-doctor-order/index.vue / bed-change/index.ts)
|
|
|
+- 量化预期:1 年前 qd 长期医嘱 → 旧 365 行/条 → 新 ≤ (30+30)=60 行/条;已执行行现正常显示
|
|
|
+
|
|
|
+### ⚠️ 待用户确认
|
|
|
+- `VIEW_PAST_DAYS/VIEW_AHEAD_DAYS` 默认 30/30 是否合适("提前一个月"按 ±30 天解读;若只想看当天可把 AHEAD 调 0)
|
|
|
+- 未来 30 天计划行也展示为「待执行」,护士可能提前执行——是否需要禁用未来行执行(未做,留待确认)
|
|
|
+- 诊断日志仍为临时,后端 planTime 写入 BUG 确认/修复后需删除
|
|
|
+
|
|
|
+## ⚠️ 误读"提前一个月"——回退到「只展开当天」(9-08 下午,用户纠正)
|
|
|
+
|
|
|
+### 用户澄清
|
|
|
+「搞错了,应该不能提前展开数据,只需要展开当天的。我需要您把执行日期,不能被删除,变成空」
|
|
|
+→ 上一轮我按"回看30天+提前30天"理解是错的。真实诉求:
|
|
|
+1. **不展未来、不展历史欠账**,只展开所选「执行日期」当天
|
|
|
+2. **执行日期必填**(prop=execDate 必选校验,clearable=false)
|
|
|
+3. **执行日期默认空**(不自动填今天),由用户主动选择要查看/回看的日期
|
|
|
+
|
|
|
+### 修改(execute-doctor-order/index.vue)
|
|
|
+- **模板**:
|
|
|
+ - `<el-date-picker ... :clearable="false" />` 关闭清除按钮(一旦选了不能清回空)
|
|
|
+ - `<el-form ... :rules="queryRules">` 挂载校验
|
|
|
+- **脚本**:
|
|
|
+ - `execDate` 默认 `''`(不再预填今天)
|
|
|
+ - 新增 `queryRules.execDate = [{ required: true, message: '请选择执行日期', trigger: 'change' }]`
|
|
|
+ - `handleQuery` 先 `await queryFormRef.value?.validate()`,校验失败直接 return(表单自动红字提示)
|
|
|
+ - `resetQuery` 改回 `execDate = ''` + `list.value=[]; pageNo=1`(不调 buildRows)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 11:40-11:46 二次修正:执行日期默认今天 + 全部类型回看历史
|
|
|
+用户纠正:「我没说执行日期默认空啊,默认就是今天,并且不能删除」
|
|
|
+### 修改(execute-doctor-order/index.vue)
|
|
|
+- `execDate` 默认 `formatDate(new Date(),'YYYY-MM-DD')`(今天);`:clearable="false"` 保留;必填校验保留
|
|
|
+- `resetQuery`:重置回今天 + `buildRows()` 重新加载(不再留空列表)
|
|
|
+- `onMounted` 已调 buildRows → 进入页面自动加载今天数据
|
|
|
+
|
|
|
+### 11:46 新需求:医嘱类型=全部 → 回看历史执行单
|
|
|
+「如果箭头处(医嘱类型)是全部,那么9月8号之前的历史执行单(包含已执行和未执行),都要展示出来」
|
|
|
+- **语义**:`showHistory = queryParams.orderType == null`
|
|
|
+ - 全部:展开 `[execDate-30天, execDate]` 的长期应执行时点(含已执行/已跳过/欠账,状态由 execMap 回填)+ 窗口内历史临时医嘱
|
|
|
+ - 指定长期/临时:仍只展执行日期当天
|
|
|
+- `HISTORY_DAYS = 30` 回看窗口常量(防 7298 无限展开);复用 API 层 `buildPendingPlanTimes` 的 `viewStart` 参数(上界仍为 execDate 23:59:59 不展未来)
|
|
|
+- 临时医嘱过滤从 `planDate === execDate` 改为 `viewStartDate <= planDate <= execDate`
|
|
|
+- 长期 filter 双保险:`viewStartDate <= t.slice(0,10) <= execDate`
|
|
|
+ - **buildRows 步骤 4.1 长期展开回退**:
|
|
|
+ - 删 `now: execDate+30d` → 改回 `now: ${execDate} 23:59:59`
|
|
|
+ - 删 `viewStart: execDate-30d` → 不再传
|
|
|
+ - 删 `VIEW_PAST_DAYS/VIEW_AHEAD_DAYS` 常量
|
|
|
+ - 长期展开后再加 `.filter((t) => t.slice(0, 10) === execDate)`,**只保留当天时点**
|
|
|
+ - buildRows 顶部加 `if (!execDate) { list.value=[]; return }` 兜底(onMounted 直接调用时)
|
|
|
+
|
|
|
+### 语义对比
|
|
|
+| 维度 | 旧(错误) | 新(正确) |
|
|
|
+|---|---|---|
|
|
|
+| 默认值 | 今天 | **空** |
|
|
|
+| 是否必填 | 否 | **是** |
|
|
|
+
|
|
|
+## 11:58 用户实测「执行日期默认空值」——重新修复
|
|
|
+- 排查发现 435 行 `queryParams.execDate` 实际仍是 `''`(此前"改默认今天"的编辑未保留,原因不明,疑似热更新/IDE 回退)
|
|
|
+- ✅ 已重新改回:`execDate: formatDate(new Date(), 'YYYY-MM-DD') as any`
|
|
|
+- 更新 resetQuery 注释(行为不变:回今天 + buildRows)
|
|
|
+- ⚠️ 经验:**改动后如用户实测未生效,先 Read 确认磁盘文件实际内容**,热更新回退会导致 Edit 显示成功但代码被还原
|
|
|
+| 能否清除 | 能 | **不能**(clearable=false) |
|
|
|
+| 展开范围 | 回看30天+提前30天 | **仅当天** |
|
|
|
+| 历史欠账 | 累积展示 | **不展**(要回看历史选哪天查哪天) |
|
|
|
+| 未来计划 | 提前展示 | **不展** |
|
|
|
+
|
|
|
+### 验证
|
|
|
+- vue-tsc 类型检查 execute-doctor-order/index.vue:后台跑中
|
|
|
+- bed-change/index.ts 的 `viewStart` 参数保留(无外部调用方成本,可供将来"按周/月汇总"复用),本次不传
|
|
|
+
|
|
|
+## 14:09 用户实测发现 BUG:长期医嘱筛选时只剩 2 条
|
|
|
+### 现象
|
|
|
+- 医嘱类型=全部 → 9 条(5 个 qw 周展开 + 4 个 bid 两日展开)
|
|
|
+- 医嘱类型=长期 → 仅 2 条(9月8号 bid 09:00+15:00),**所有历史行被吞掉**
|
|
|
+- 临时筛同理也会丢历史
|
|
|
+### 根因
|
|
|
+上一轮 11:46 把"是否回看历史"绑死到 `queryParams.orderType == null`:
|
|
|
+```ts
|
|
|
+const showHistory = queryParams.orderType == null
|
|
|
+const viewStartDate = showHistory ? execDate-30d : execDate
|
|
|
+```
|
|
|
+→ 类型筛选=长期/临时时 viewStartDate=execDate,过滤 `[viewStartDate, execDate]` 只剩当天
|
|
|
+### 设计正解
|
|
|
+**类型筛选只过滤类型,不改变时间窗口**。长期/临时/全部 都回看 [execDate-30天, execDate] 历史
|
|
|
+### 修改(execute-doctor-order/index.vue buildRows 第 4 步)
|
|
|
+- 删 `const showHistory = queryParams.orderType == null`
|
|
|
+- `viewStartDate` 恒为 `dayjs(execDate).subtract(30, 'day').format('YYYY-MM-DD')`
|
|
|
+- 注释同步更新:明确"类型筛选不影响时间窗口"
|
|
|
+### 效果
|
|
|
+- 全部:长期 + 临时,30 天历史 + 当天
|
|
|
+- 长期:仅长期,30 天历史 + 当天(之前 9 条数据全集 + 0 临时 = 9 条)
|
|
|
+- 临时:仅临时,30 天历史 + 当天
|
|
|
+### 教训
|
|
|
+区分「数据范围」与「过滤维度」:时间窗口是数据范围,类型是过滤维度——两个维度正交,不该耦合
|
|
|
+
|
|
|
+## 14:36 大改造:执行日期单日 → daterange 范围(执行页 + 执行记录弹窗)
|
|
|
+用户给真实后端规格文档(`D:/Users/chenjun/Documents/WXWork/1688856573655686/Cache/File/2026-08/doctor-order-backend-spec.md`),核对后端现状:
|
|
|
+- `doctorOrderExecution/page` 仅支持单日 planDate
|
|
|
+- 长期/临时医嘱 page 无时间过滤
|
|
|
+- `plan_time` 已有 `idx_plan(plan_time, tenant_id)` 索引,范围查询无性能问题
|
|
|
+- 已更新桌面规格建议文档《医嘱执行单-时间范围查询-后端接口规格建议.md》
|
|
|
+
|
|
|
+### 执行记录弹窗 `ExecutionRecordDialog.vue`(长/短两个入口都复用此弹窗)
|
|
|
+- `execDate: string` → `dateRange: [string, string]`,默认近 30 天 ~ 今天
|
|
|
+- `<el-date-picker type="daterange" :clearable="false">`
|
|
|
+- 信息行「执行日期」→ 范围文本(单日简写)
|
|
|
+- 接口 `getDoctorOrderExecutionPage` 传 `planDateBegin` / `planDateEnd`(替代单日 `planDate`)
|
|
|
+- `pageSize: 1000` 已符合
|
|
|
+- 表格容器 `.table-scroll{max-height:60vh; overflow-y:auto}`,超 60vh 弹框内自动滚动
|
|
|
+- `@media print` 取消滚动让打印完整
|
|
|
+- 新增「查询」「重置」按钮,重置回近 30 天 ~ 今天
|
|
|
+
|
|
|
+### 执行页 `execute-doctor-order/index.vue`
|
|
|
+- `queryParams.execDate` 单日 → `queryParams.dateRange` 范围
|
|
|
+- `<el-date-picker type="daterange" :clearable="false">`,label 改"执行日期"
|
|
|
+- `queryRules.dateRange` 自定义 validator:必填 + 起始不能晚于结束
|
|
|
+- `dateRangeText` computed:单日简化 / 多日「YYYY-MM-DD 至 YYYY-MM-DD」
|
|
|
+- 删 `HISTORY_DAYS=30` 常量;`viewStartDate = dateRange[0]`,`dateEnd = dateRange[1]`
|
|
|
+- buildRows 顶部守卫 `if (!dateRange || dateRange.length !== 2 || !dateRange[0] || !dateRange[1])`
|
|
|
+- `getDoctorOrderExecutionPage` 传 `planDateBegin`/`planDateEnd`
|
|
|
+- 长期/临时展开上下界改用 `dateBegin`/`dateEnd`(`buildPendingPlanTimes` 的 now/viewStart)
|
|
|
+- 打印区 2 处(all 汇总 / single 单条)「执行日期」→ `dateRangeText`
|
|
|
+- 重置 → dateRange = [今天-30, 今天] + buildRows
|
|
|
+- onMounted → buildRows(默认 dateRange 已含值,自动加载近 30 天 ~ 今天)
|
|
|
+
|
|
|
+### ✅ 实际后端参数命名(2026-09-08 已确认)
|
|
|
+- `longDoctorOrder/page` / `shortDoctorOrder/page` 新增 `latestOrderTime`(array[string],按 entry 最大 `order_time` 过滤)
|
|
|
+- `doctorOrderExecution/page` 新增 `planTime`(array[string],按 `plan_time` 范围过滤)
|
|
|
+- ⚠️ **实测:后端接收的是 YYYY-MM-DD 日期字符串数组**(不是毫秒戳),与规格文档「四之一·时间字段传递约定」原文不一致——以**实际接口格式**为准
|
|
|
+ - axios 序列化为 `?planTime=2026-08-09&planTime=2026-09-08`
|
|
|
+ - 后端 Spring MVC 用 `@RequestParam List<String>` 接收
|
|
|
+ - 用户(2026-09-08 15:36)明确说明:"是传 array[string],也就是日期字符串数组"
|
|
|
+- 旧的 `planDate`(单日 YYYY-MM-DD 字符串)保留:单日仍可用,本次未传(统一走范围)
|
|
|
+
|
|
|
+**调用方改动**:
|
|
|
+- `execute-doctor-order/index.vue` buildRows:3 处接口调用
|
|
|
+ - 长期/临时医嘱:新增 `latestOrderTime: [dateBegin, dateEnd]`(YYYY-MM-DD 字符串)
|
|
|
+ - 执行记录:`planDateBegin/planDateEnd` → `planTime: [dateBegin, dateEnd]`(YYYY-MM-DD 字符串)
|
|
|
+- `ExecutionRecordDialog.vue` fetchList:1 处接口调用 + 兜底 2 处
|
|
|
+ - 执行记录:同上 `planTime: [dateBegin, dateEnd]`
|
|
|
+ - 兜底 long/short 医嘱 page:同步加 `latestOrderTime: [dateBegin, dateEnd]`
|
|
|
+- ⚠️ **2026-09-08 漏改**:长期/临时医嘱**列表页** `getList` 仍传旧参数 `beginTime/endTime`(项目惯例,yudao 时间范围查询通用名)
|
|
|
+ - 已改:长期/临时医嘱列表 `long-doctor-order/index.vue:267-271` 和 `short-doctor-order/index.vue:174-178`
|
|
|
+ - 改法:`params.beginTime/endTime` → `params.latestOrderTime = [b, e]`
|
|
|
+ - 原因:后端已加新参数 `latestOrderTime`(按 entry 最大 order_time 过滤),旧的 `beginTime/endTime` 估计走的是订单的 create_time,与"按 entry 最大 order_time 过滤"语义不符
|
|
|
+
|
|
|
+## 执行记录弹窗:医嘱内容前端兜底(2026-09-08)
|
|
|
+
|
|
|
+**用户反馈**:某长者的执行记录表格里医嘱内容为空(长者B 91岁那条),但频次/给药时间/途径都填了。
|
|
|
+
|
|
|
+**根因**:execution 表是引用型设计(仅存 `orderType+orderEntryId`,不冗余存 `orderContent/frequency/medTime/route`)。
|
|
|
+后端 `doctorOrderExecution/page` 接口的 join 在某些长者上漏了字段——典型表现就是「医嘱内容空、但其它字段都在」。
|
|
|
+
|
|
|
+**前端兜底**(`ExecutionRecordDialog.vue` fetchList):
|
|
|
+1. 拉到 execution 后,判断是否有空字段(orderContent/frequency/medTime/route 任一为空)
|
|
|
+2. 若需要兜底 → 并行拉 `longDoctorOrderPage` + `shortDoctorOrderPage`(按 elderId 过滤)
|
|
|
+3. 按 `orderType-orderEntryId` 建 Map,把空字段从 entry 上取出来
|
|
|
+4. 只补缺失字段,不覆盖后端实际返回的值(真实值优先级最高)
|
|
|
+5. 接口失败不阻塞主流程(catch 静默)
|
|
|
+
|
|
|
+**长期解法**:让后端 page 接口 join 完整所有字段;前端兜底纯属保险。
|
|
|
+
|
|
|
+**入参变化**:`longDoctorOrderPage/shortDoctorOrderPage` 现在传 `elderId`(之前未传,按 elderName 模糊匹配;
|
|
|
+改成 elderId 精确匹配,更准确)。
|
|
|
+
|
|
|
+## 执行医嘱页:默认窗口与默认状态调整(2026-09-08 16:00)
|
|
|
+
|
|
|
+**用户反馈**:默认「近 30 天 ~ 今天」数据量太大(截图里看到 4 条长者),且未筛状态时已执行+未执行混着看。
|
|
|
+
|
|
|
+**改动**(仅 `execute-doctor-order/index.vue`,**弹窗 `ExecutionRecordDialog.vue` 不动**):
|
|
|
+- `queryParams.dateRange` 默认值:`今天-30天~今天` → `今天-3天~今天`
|
|
|
+- `queryParams.status` 默认值:`undefined`(全部)→ `0`(仅未执行)
|
|
|
+- `resetQuery` 重置回同样的默认值(保持一致行为)
|
|
|
+- 改完进入页面即展示「前 3 天 ~ 今天 + 仅未执行」的首屏干净视图
|
|
|
+- 用户想看已执行/全部:清掉状态筛选项;想看更早:拉宽日期范围
|
|
|
+
|
|
|
+**教训**:列表页默认窗口不宜过大,3~7 天是「近期欠账回看」的合适跨度;状态筛选器默认聚焦核心场景(待执行),减少首屏噪声。
|
|
|
+
|
|
|
+## v-print 打印区 id 必须动态化(2026-09-08 16:10 串号 BUG)
|
|
|
+
|
|
|
+**用户反馈**:在长期医嘱页打了一次「执行记录」,再切到临时医嘱页打开执行记录弹窗点打印,预览里仍是「长期医嘱」表格内容。
|
|
|
+
|
|
|
+**根因**:`ExecutionRecordDialog.vue` 的 `printConfig.id` 之前写死成 `execRecordPrintArea`(固定字符串),导致:
|
|
|
+- vue3-print-nb 在多次打印间缓存 DOM 副本到 iframe
|
|
|
+- 不同路由/不同长者用同一 id 时,库按 id 找到的是 iframe 里的旧 DOM(甚至离屏节点)
|
|
|
+- 表现为"打印内容串号"
|
|
|
+
|
|
|
+**修复**:打印区 id 改成动态拼接 `execRecordPrintArea-{elderId}-{openCounter}`
|
|
|
+- `openCounter` 单调递增(每次 open 自增),保证同长者重复打开也有新 id
|
|
|
+- `printConfig` 改 `computed`,模板 `:id="printAreaId"` 同步
|
|
|
+- 库每次按新 id querySelector 必然拿到本次弹窗的新 DOM,覆盖 iframe 缓存
|
|
|
+
|
|
|
+**范式**:项目里所有用 v-print 的弹窗(不只是执行记录)都应该避免固定 id。
|
|
|
+- 当前其它打印区 id(暂未发现串号问题,但同隐患):`longOrderPrintArea`、`shortOrderPrintArea`、`execPrintArea`、`singlePrintArea`
|
|
|
+- 如果后续发现串号,同样用 `computed + counter` 范式修复
|
|
|
+
|
|
|
+## 批量执行医嘱功能(2026-09-08 16:16)
|
|
|
+
|
|
|
+**用户需求**:执行医嘱页加批量执行,弹窗顶部展示选中的项,统一填时间/护士/备注后循环调接口。
|
|
|
+
|
|
|
+**实现**:
|
|
|
+- 新增 `BatchExecuteDialog.vue`(与 `ExecuteDialog.vue` 风格一致)
|
|
|
+- 表格加 `type="selection"` 列 + `selectable` 限定只能选 `status=0`(待执行)
|
|
|
+- 顶部「批量执行(N 项)」按钮,未选中时禁用
|
|
|
+- 选中后点击 → 弹窗顶部显示选中项清单(长者/床位/计划时间/医嘱内容)
|
|
|
+- 表单共用:实际执行时间(必填)+ 执行护士 + 备注
|
|
|
+- 顺序 `for await` 循环调 `executeDoctorOrder`(避免并发压力后端)
|
|
|
+- 错误处理与单条 ExecuteDialog 一致:拦截器对 `code:0` 走 reject,try/catch 都按成功处理
|
|
|
+- 完成后 emit `success`,父组件清选中 + 调 `buildRows()` 刷新
|
|
|
+
|
|
|
+**额外修复**:`userStore.nickname` → `(userStore as any).user?.nickname`(store 真实结构在 user 顶层)
|
|
|
+- `ExecuteDialog.vue` 第 91 行也有同样问题,一并修复
|
|
|
+- 这是项目基线就有的 TS 错误(vue-tsc 漏报),现在批量执行弹窗被触发报出来
|
|
|
+
|
|
|
+**新建文件**:
|
|
|
+- `src/views/elderly/elder/doctor-orders/execute-doctor-order/BatchExecuteDialog.vue`
|
|
|
+
|
|
|
+**改动文件**:
|
|
|
+- `src/views/elderly/elder/doctor-orders/execute-doctor-order/index.vue`(加 selection 列、按钮、状态/方法)
|
|
|
+- `src/views/elderly/elder/doctor-orders/execute-doctor-order/ExecuteDialog.vue`(修 userStore 路径)
|
|
|
+
|
|
|
+### ⚠️ 孤儿结束标签陷阱(2026-09-08 已修复)
|
|
|
+- **症状**:vite:vue 报 `Invalid end tag` at 行:列,错误信息里出现 `</content>` / `</invoke>` 等与代码无关的 tag 名
|
|
|
+- **真实原因**:SFC 文件末尾不小心残留了一个孤儿结束标签(如 `</content>`),没有对应的开始标签
|
|
|
+- 来源可能是 Write/Edit 工具调用时无意带进了工具指令的收尾,或 IDE 粘贴板错位
|
|
|
+- **vue-tsc 不会报错**(它走 AST 不严格解析 HTML),但 vite:vue 编译器严格做 HTML 解析会被卡住
|
|
|
+- **自检范式**:写完新 SFC 文件,立刻 `Grep` 看末尾是不是干净的 `</style>` / `</script>` / `</template>` 配对;任何其它 tag 立即删除
|