Compare commits
61 Commits
fix-668-te
...
017ed885d9
| Author | SHA1 | Date | |
|---|---|---|---|
| 017ed885d9 | |||
| e20d9fbf7d | |||
| d7a32eb8c5 | |||
| d515c47e89 | |||
| 200b4853db | |||
| 4229196574 | |||
| 4ff58b3f2e | |||
| ab3431c53d | |||
| bb20d8308e | |||
| db84f4b2bd | |||
| 0a2978bc0a | |||
| 4e9c1a9716 | |||
| 2aa8b88b3a | |||
| 1a51508e78 | |||
| cd523cced0 | |||
| 4b3663c7d7 | |||
|
|
5e594e7c25 | ||
| a18143ef41 | |||
| 4f3b1dff8f | |||
| a45b6e7955 | |||
| cec2f47a1f | |||
| a350095ced | |||
| 3f52a98a32 | |||
| d60b579dcd | |||
| d413a4cd60 | |||
| 93447b0e46 | |||
| 2921d4535a | |||
| b71354d3b6 | |||
| 57a33e0baa | |||
| 759f10d9d0 | |||
| d8e2c485a4 | |||
| 69e24ba2b4 | |||
| 81f5001601 | |||
| 96087d8dac | |||
| 9331dc7525 | |||
| 6372e3c80f | |||
| 615be87c71 | |||
| c0ab80bd4d | |||
| 772119e320 | |||
| 256791348c | |||
|
|
a08808b41d | ||
|
|
f407a2a886 | ||
| babd8d0c04 | |||
| 1f738c969a | |||
| 3f67753344 | |||
| 3e650dd041 | |||
| 773a485114 | |||
| 9675106d4b | |||
|
|
f655f06871 | ||
| 2c2dbd7542 | |||
| 8b47a8ab55 | |||
| 5ebe6c6333 | |||
| 65a52e9742 | |||
|
|
d04be6062b | ||
|
|
defab36cca | ||
| 681107ca64 | |||
| f75133369a | |||
| ca812421d2 | |||
| ae12cb2135 | |||
| d2a1cd6f29 | |||
| d9d2b83c5b |
544
AGENTS.md
544
AGENTS.md
@@ -107,6 +107,143 @@
|
|||||||
- **违规判定**: 因修改导致原有代码编译失败或运行报错,视为违反铁律18,必须立即回滚修复
|
- **违规判定**: 因修改导致原有代码编译失败或运行报错,视为违反铁律18,必须立即回滚修复
|
||||||
|
|
||||||
|
|
||||||
|
**铁律19: 编译错误不区分来源(Bug #698 教训)**
|
||||||
|
- `mvn compile`、`vite build`、`vue-tsc` 等构建命令报错 = 不过关,**不管是自己引入的还是历史遗留的**
|
||||||
|
- 禁止说"这是预存问题""不是我改的""原有bug"——构建通不过就不能宣称完成
|
||||||
|
- 正确做法:定位错误 → 修复 → 重新构建确认通过 → 然后才能继续
|
||||||
|
- **违规判定**: 构建命令有 ERROR 但未修复就报告"编译通过",视为违反铁律
|
||||||
|
|
||||||
|
**铁律20: 数据来源必须验证(Bug #698 教训)**
|
||||||
|
- 涉及数据查询/提取时,必须先确认数据实际存储位置,不能假设
|
||||||
|
- 案例:从 `raw_steps_html` 提取 fileID,而不是从 `steps`(纯文本,已被 strip)
|
||||||
|
- 修复前必须:打印/检查原始数据结构 → 确认字段存在 → 再写提取逻辑
|
||||||
|
- 禁止:凭代码推断数据位置、假设"应该在这里"
|
||||||
|
|
||||||
|
**铁律21: 外部配置值必须实测验证(Bug #698 教训)**
|
||||||
|
- 使用外部服务(API、模型、数据库)的配置值,必须实际调用验证,不能仅凭记忆或推测
|
||||||
|
- 案例:模型名 `mino-v2.5` 应为 `mimo-v2.5`,拼写错误导致 400
|
||||||
|
- 配置变更后必须:发起一次真实请求 → 确认返回 200 → 再宣称配置正确
|
||||||
|
- 禁止:改完配置不测试、假设"应该能用"
|
||||||
|
|
||||||
|
**铁律22: 端到端验证必须有实际输出证据(Bug #698 教训)**
|
||||||
|
- 声称功能生效前,必须有实际的端到端输出证据
|
||||||
|
- 不能仅凭代码路径推断"应该走了 vision"——必须看到实际返回内容
|
||||||
|
- 验证方式:运行命令 → 检查输出中包含预期关键词(如 vision 分析结果、图片识别文字)
|
||||||
|
- 禁止:只检查代码路径可达就算"验证通
|
||||||
|
**铁律23: 文件读写强制 UTF-8 编码(必遵守)**
|
||||||
|
- **禁止**使用 Get-Content -Raw(不带 -Encoding UTF8)读取源文件
|
||||||
|
- **禁止**使用 Out-File -Encoding utf8(会写 BOM)
|
||||||
|
- **正确写法**:
|
||||||
|
- 读取:[System.IO.File]::ReadAllText(, [System.Text.Encoding]::UTF8)
|
||||||
|
- 写入:[System.IO.File]::WriteAllText(, # HealthLink-HIS — AI 开发规范
|
||||||
|
|
||||||
|
> 🤖 本文件由 Codex CLI、Claude Code 等工具自动读取。
|
||||||
|
> 工具进入项目目录时会自动加载此文件作为开发规范上下文。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# HealthLink-HIS — AI 开发规范(自动加载)
|
||||||
|
|
||||||
|
> 🤖 **本文件供所有 AI 编码工具自动读取**。进入本项目后必须遵守以下规范。
|
||||||
|
>
|
||||||
|
> **模型决定上限,Harness 决定底线。**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、项目概览
|
||||||
|
|
||||||
|
| 属性 | 值 |
|
||||||
|
|------|------|
|
||||||
|
| 项目名 | HealthLink-HIS(医院信息系统) |
|
||||||
|
| 后端路径 | `healthlink-his-server/` |
|
||||||
|
| 前端路径 | `healthlink-his-ui/` |
|
||||||
|
| 文档路径 | `MD/` |
|
||||||
|
| JDK | 25 (OpenJDK) |
|
||||||
|
| Spring Boot | 4.0.6 |
|
||||||
|
| MyBatis-Plus | 3.5.16 |
|
||||||
|
| Vue | 3.x + Vite + Element Plus |
|
||||||
|
| 数据库 | PostgreSQL 15+ |
|
||||||
|
| 包名 | `com.healthlink.his` |
|
||||||
|
| 后端端口 | 18082 |
|
||||||
|
| 前端端口 | 81 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、铁律(必须遵守,违反即失败)
|
||||||
|
|
||||||
|
### 🔴 P0 铁律 — 不可违反
|
||||||
|
|
||||||
|
**铁律1: 修改完必须测试**
|
||||||
|
```
|
||||||
|
后端: mvn clean compile -DskipTests → mvn install -DskipTests → mvn test
|
||||||
|
前端: npm run build:dev → npm run lint
|
||||||
|
```
|
||||||
|
- 白盒:编译通过,无 ERROR
|
||||||
|
- 黑盒:关键接口返回 `{code:200, data:...}`,验证业务逻辑
|
||||||
|
- 冒烟:应用正常启动,核心流程通畅
|
||||||
|
|
||||||
|
**铁律2: Flyway 数据库迁移**
|
||||||
|
- 凡是新建表、新增字段,必须创建 Flyway 迁移脚本
|
||||||
|
- 路径:`healthlink-his-domain/src/main/resources/db/migration/`
|
||||||
|
- 命名:`V{版本号}__{描述}.sql`(双下划线)
|
||||||
|
|
||||||
|
**铁律3: 测试通过后才提交**
|
||||||
|
- 编译 + 测试全部通过后才能 git commit
|
||||||
|
- 不提交未完成的功能、调试代码、临时文件
|
||||||
|
|
||||||
|
**铁律4: 前后端API路径对齐**
|
||||||
|
- 后端前缀:`/healthlink-his/api/v1/`
|
||||||
|
- 前端 `request.js` 的 baseURL 必须与后端匹配
|
||||||
|
|
||||||
|
**铁律5: 状态值一致性(Bug #574 教训)**
|
||||||
|
- 修改任何状态值前,必须先列出完整的状态流转链路
|
||||||
|
- 检查项:枚举定义 → Service 设置 → 查询映射 → 前端 STATUS_CLASS_MAP → 前端 v-if → 统计SQL
|
||||||
|
- 禁止:只改一端不检查其他端
|
||||||
|
|
||||||
|
**铁律6: 禁止删除源文件(Bug #574 教训)**
|
||||||
|
- 绝对禁止删除项目中已有的 Java/Vue/SQL 源文件
|
||||||
|
- 编译错误 → 修复错误;重复文件 → 重构合并
|
||||||
|
- 唯一例外:明确由人类确认删除的文件
|
||||||
|
|
||||||
|
**铁律7: 禁止修改已有公开方法签名**
|
||||||
|
- 不能删除/重命名已有的 public 方法,不能修改参数列表
|
||||||
|
- 需要新功能 → 添加重载方法;需要改行为 → 修改内部实现
|
||||||
|
|
||||||
|
**铁律8: 验证后才宣称完成(Verification Before Completion)**
|
||||||
|
- **没有跑过验证命令,就不能说"完成了""通过了""没问题"**
|
||||||
|
- 禁止使用"应该可以""大概没问题""看起来正确"
|
||||||
|
- 必须:运行命令 → 读取输出 → 确认结果 → 才能宣称
|
||||||
|
- 这是诚实原则,不是效率问题
|
||||||
|
|
||||||
|
|
||||||
|
**铁律9: 开发前必须审核原有代码(P0 — 铁律)**
|
||||||
|
- **任何新功能开发前,必须先搜索项目中是否已有相关代码**
|
||||||
|
- 搜索路径:Controller / AppService / Service / Mapper / Entity / 前端页面 / API接口
|
||||||
|
- 如果已有部分功能 → 在原有代码基础上**升级优化完善**,禁止另起炉灶
|
||||||
|
- 如果已有接口但前端缺失 → 只补前端,不重复建后端
|
||||||
|
- 如果已有前端但后端缺失 → 只补后端,不重写前端
|
||||||
|
- 搜索命令:`rg -l "关键词" healthlink-his-server/ healthlink-his-ui/src/`
|
||||||
|
- 禁止:不看代码就新建模块、重复实现已有功能、废弃原有代码另写一套
|
||||||
|
|
||||||
|
|
||||||
|
**铁律12: 设计文档确认后自主开发(铁律)**
|
||||||
|
- 设计文档(如 `MD/architecture/GRADE3A_GAP_ANALYSIS_AND_DESIGN.md`)一旦确认,后续开发**必须按文档自主执行**
|
||||||
|
- **禁止反复询问"是否继续""下一步做什么""是否开始"**——直接按计划推进
|
||||||
|
- 每完成一个 Sprint,自动提交推送,然后立即开始下一个 Sprint
|
||||||
|
- 只在遇到**无法解决的阻塞**(如技术选型冲突、需求不明确、第三方依赖不可用)时才暂停询问
|
||||||
|
- 设计文档是"**已签合同**",不是"参考意见"。铁律执行优先级:设计文档 > 人类临时指令 > AI 自行判断
|
||||||
|
|
||||||
|
**铁律18: 禁止破坏原有功能(P0绝对铁律)**
|
||||||
|
- **完善增加功能和流程时,绝对不能破坏或者让原有功能不能用**
|
||||||
|
- 修改已有实体前必须对比原始文件(`git show HEAD~N:./file.java`),保留所有原有字段和方法
|
||||||
|
- 新增字段只能追加,不能删除或重命名已有字段
|
||||||
|
- SQL迁移只允许 `ALTER TABLE ADD COLUMN`,不允许 `DROP COLUMN` 或 `RENAME COLUMN`
|
||||||
|
- Controller新端点不能修改已有端点的路径或参数
|
||||||
|
- 前端新页面不能修改已有页面的组件结构
|
||||||
|
- 每次修改后必须 `mvn clean compile -DskipTests` 验证
|
||||||
|
- **违规判定**: 因修改导致原有代码编译失败或运行报错,视为违反铁律18,必须立即回滚修复
|
||||||
|
|
||||||
|
|
||||||
**铁律19: 编译错误不区分来源(Bug #698 教训)**
|
**铁律19: 编译错误不区分来源(Bug #698 教训)**
|
||||||
- `mvn compile`、`vite build`、`vue-tsc` 等构建命令报错 = 不过关,**不管是自己引入的还是历史遗留的**
|
- `mvn compile`、`vite build`、`vue-tsc` 等构建命令报错 = 不过关,**不管是自己引入的还是历史遗留的**
|
||||||
- 禁止说"这是预存问题""不是我改的""原有bug"——构建通不过就不能宣称完成
|
- 禁止说"这是预存问题""不是我改的""原有bug"——构建通不过就不能宣称完成
|
||||||
@@ -533,3 +670,410 @@ git status && git add -A && git commit -m "feat(module): desc" && git push origi
|
|||||||
---
|
---
|
||||||
|
|
||||||
> 📅 最后同步: 2026-06-06 15:09 | 源文件: RULES.md | 重新同步: `bash scripts/sync-ai-rules.sh`
|
> 📅 最后同步: 2026-06-06 15:09 | 源文件: RULES.md | 重新同步: `bash scripts/sync-ai-rules.sh`
|
||||||
|
, [System.Text.UTF8Encoding]::new(False))
|
||||||
|
- git提取:先 Out-File -Encoding utf8 保存到临时文件,再用 [System.IO.File]::ReadAllText() 读取
|
||||||
|
- **根因**:PowerShell 管道会丢失换行符,git show | Out-File 会将多行文件压缩为一行
|
||||||
|
过"
|
||||||
|
|
||||||
|
|
||||||
|
### 🟡 P1 铁律 — 强烈建议
|
||||||
|
|
||||||
|
**铁律9: 先分解再行动**
|
||||||
|
- 修改超过3个文件、涉及多模块、数据库变更,必须先制定计划
|
||||||
|
|
||||||
|
**铁律10: 验证后信**
|
||||||
|
- 每次修改后必须验证编译通过,不信记忆
|
||||||
|
|
||||||
|
**铁律13: 文档统一管理**
|
||||||
|
- 所有文档存储在 `MD/` 目录
|
||||||
|
- 文件名:大写英文+下划线(如 `BACKEND_CHECKLIST.md`)
|
||||||
|
- 文档头部必须包含元数据块(文档类型、版本、日期)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
**铁律14: 设计文档必须包含UI设计和调用流程**
|
||||||
|
- 所有新模块/页面的设计文档必须包含:UI布局描述、交互效果清单、前后端调用流程
|
||||||
|
- 没有明确UI设计的模块,禁止直接编码
|
||||||
|
- 详见
|
||||||
|
- 设计文档必须写清楚:系统调用关系、方法函数调用关系、完整业务流程
|
||||||
|
- 设计文档中每个用户操作必须对应:前端事件 → API调用 → 后端处理链路 → 返回数据 → UI渲染
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、Karpathy 编码准则
|
||||||
|
|
||||||
|
> 减少 LLM 常见编码错误。偏向谨慎而非速度。
|
||||||
|
|
||||||
|
### 3.1 先想再写
|
||||||
|
- 明确陈述假设,不确定就问
|
||||||
|
- 多种解读时都列出来,不要默默选一种
|
||||||
|
- 有更简单的方案就说出来,该推回就推回
|
||||||
|
- 不清楚的地方停下来,说清楚哪里不清楚
|
||||||
|
|
||||||
|
### 3.2 简洁优先
|
||||||
|
- 不做没要求的功能,不做一次性代码的抽象
|
||||||
|
- 不加没要求的"灵活性"和"可配置性"
|
||||||
|
- 200 行能 50 行搞定就重写
|
||||||
|
- 自问:"高级工程师会不会觉得这过度设计?"
|
||||||
|
|
||||||
|
### 3.3 精准修改
|
||||||
|
- 只改必须改的,不"顺手改进"相邻代码
|
||||||
|
- 匹配现有代码风格,即使你有不同的偏好
|
||||||
|
- 每行改动都能追溯到用户的请求
|
||||||
|
- 只清理你自己改动产生的无用代码
|
||||||
|
|
||||||
|
### 3.4 目标驱动
|
||||||
|
- 把任务转化为可验证目标
|
||||||
|
- 多步任务声明计划:`[步骤] → 验证: [检查]`
|
||||||
|
- 强验收标准让 Agent 能独立循环,弱标准需要持续澄清
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、全链路 6 环分析
|
||||||
|
|
||||||
|
> ⚠️ **涉及数据库字段的 Bug / 需求,必须走完整链路。**
|
||||||
|
|
||||||
|
```
|
||||||
|
前端/页面 → Controller → Service → Mapper → DB/SQL → 关联模块
|
||||||
|
①录入 ②验证 ③业务 ④持久化 ⑤存储 ⑥联动
|
||||||
|
```
|
||||||
|
|
||||||
|
| 环 | 检查内容 |
|
||||||
|
|----|---------|
|
||||||
|
| ① 录入 | 前端有无输入入口(弹窗、表格行编辑、表单) |
|
||||||
|
| ② 验证 | Controller 参数校验、@Valid、权限控制 |
|
||||||
|
| ③ 业务 | Service 业务逻辑、事务边界、多个 Service 实现类入口 |
|
||||||
|
| ④ 持久化 | Mapper XML、DTO 字段映射、类型转换 |
|
||||||
|
| ⑤ 存储 | 数据库表结构、索引、NOT NULL 约束 |
|
||||||
|
| ⑥ 联动 | 上游(医嘱→护士站)、下游(打印、计费、报表)是否同步 |
|
||||||
|
|
||||||
|
**修复后的验证顺序**:
|
||||||
|
1. 数据库:确认状态值已正确写入
|
||||||
|
2. 后端接口:确认返回的状态映射正确
|
||||||
|
3. 前端显示:确认页面显示正确状态文本
|
||||||
|
4. 前端交互:确认按钮/操作基于正确状态启用/禁用
|
||||||
|
5. 统计数据:确认池/报表统计包含新状态
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、Harness Engineering 方法论
|
||||||
|
|
||||||
|
> Harness = 约束 + 反馈 + 控制平面 + 持久执行
|
||||||
|
|
||||||
|
### 5.1 四层约束金字塔
|
||||||
|
|
||||||
|
| 层级 | 内容 | 落地方式 |
|
||||||
|
|------|------|---------|
|
||||||
|
| **L1 架构约束** | 接口合约、包结构、命名规范、禁止模式 | 本文件铁律 |
|
||||||
|
| **L2 代码质量** | 圈复杂度、代码风格、类型提示 | 编译门禁 + ESLint |
|
||||||
|
| **L3 安全约束** | 敏感信息检测、权限检查、输入验证 | 配置不可硬编码 |
|
||||||
|
| **L4 业务规则** | 领域逻辑、数据一致性、事务边界 | 全链路 6 环验证 |
|
||||||
|
|
||||||
|
**约束设计原则**:
|
||||||
|
- **可验证**:每条约束必须能被自动化检查("覆盖率>90%"✅ "质量要高"❌)
|
||||||
|
- **无歧义**:"每函数不超过50行"✅ "函数不要太长"❌
|
||||||
|
- **优先级**:安全(1) > 架构(2) > 业务(3) > 质量(4) > 性能(5)
|
||||||
|
- **渐进增强**:L1编译通过 → L2+命名规范 → L3+测试覆盖 → L4+安全扫描
|
||||||
|
|
||||||
|
### 5.2 三层反馈系统
|
||||||
|
|
||||||
|
| 层级 | 速度 | 覆盖范围 | 失败处理 |
|
||||||
|
|------|------|---------|---------|
|
||||||
|
| **L1 编译检查** | <30秒 | 语法、类型、签名 | 立即阻断,自行修复 |
|
||||||
|
| **L2 数据流验证** | <5分钟 | 全链路字段、Mapper XML、DTO | 修复后上报 |
|
||||||
|
| **L3 人工审查** | 10-30分钟 | 架构、设计、业务正确性 | 驳回/指导/批准 |
|
||||||
|
|
||||||
|
**反馈铁律**:
|
||||||
|
- 反馈必须可行动(文件 + 行号 + 错误类型 + 修复方向)
|
||||||
|
- 失败后先回滚到最近检查点,再重试
|
||||||
|
- 持续失败3次 → 上报人类
|
||||||
|
|
||||||
|
### 5.3 控制平面
|
||||||
|
|
||||||
|
```
|
||||||
|
战略层(人类) → 设定目标、审批决策、异常升级
|
||||||
|
战术层(Agent) → 任务分解、update_plan、依赖协调、检查点保存
|
||||||
|
执行层(Agent) → 代码生成、测试执行、错误恢复、幂等重试
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.4 持久执行
|
||||||
|
|
||||||
|
- 每个关键步骤保存检查点(`update_plan` 进度)
|
||||||
|
- 失败后从最新检查点恢复,不从头开始
|
||||||
|
- 幂等设计:同一操作重复执行结果一致
|
||||||
|
- **三层状态管理**:系统层(工作流ID/超时/重试) → 执行层(当前活动/进度) → 业务层(已完成工作/中间产物)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、五层质量门禁
|
||||||
|
|
||||||
|
| 门禁 | 时间 | 范围 | 失败处理 |
|
||||||
|
|------|------|------|---------|
|
||||||
|
| **L1 编译检查** | <30秒 | 语法、类型、导入 | Agent 自行修复 |
|
||||||
|
| **L2 静态分析** | <2分钟 | 代码风格、复杂度、安全 | Agent 修复 |
|
||||||
|
| **L3 单元测试** | <5分钟 | 功能正确性、边界条件 | 自动修复或上报 |
|
||||||
|
| **L4 集成测试** | <15分钟 | 模块间交互、数据流 | 上报人工 |
|
||||||
|
| **L5 生产验证** | 持续 | 监控、告警、性能 | 自动回滚 |
|
||||||
|
|
||||||
|
**提交铁律**:L1-L2 必须通过才能 commit,L3(如有DB变更)必须通过才能 push
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、系统化调试(Systematic Debugging)
|
||||||
|
|
||||||
|
> **铁律:没有根因调查,不能提出修复方案。**
|
||||||
|
|
||||||
|
### 四阶段流程
|
||||||
|
|
||||||
|
**阶段1:根因调查**(修复前必须完成)
|
||||||
|
1. 仔细阅读错误信息(堆栈、行号、错误码)
|
||||||
|
2. 稳定复现(能否可靠触发?步骤?每次?)
|
||||||
|
3. 检查最近变更(git diff、新依赖、配置变更)
|
||||||
|
4. 多组件系统:在每个组件边界加诊断日志,定位哪一层断裂
|
||||||
|
5. 追踪数据流:坏值从哪里来?谁调用的?一直追溯到源头
|
||||||
|
|
||||||
|
**阶段2:模式分析**
|
||||||
|
- 找到同代码库中类似的正常工作代码
|
||||||
|
- 逐项对比差异
|
||||||
|
- 理解依赖关系
|
||||||
|
|
||||||
|
**阶段3:假设与测试**
|
||||||
|
- 形成单一假设:"我认为X是根因,因为Y"
|
||||||
|
- 做最小改动测试
|
||||||
|
- 有效 → 阶段4;无效 → 新假设
|
||||||
|
|
||||||
|
**阶段4:实施**
|
||||||
|
- 创建失败测试用例
|
||||||
|
- 修复根因(不是症状)
|
||||||
|
- 验证修复
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 八、后端开发规范
|
||||||
|
|
||||||
|
### 分层架构
|
||||||
|
```
|
||||||
|
Controller → AppService → Service → Mapper → Entity
|
||||||
|
```
|
||||||
|
|
||||||
|
### 命名规范
|
||||||
|
| 类型 | 规则 | 示例 |
|
||||||
|
|------|------|------|
|
||||||
|
| Controller | `XxxController` | `RegistrationController` |
|
||||||
|
| AppService | `IXxxAppService` / `XxxAppServiceImpl` | `IRegistrationAppService` |
|
||||||
|
| Service | `IXxxService` / `XxxServiceImpl` | `IRegistrationService` |
|
||||||
|
| Mapper | `XxxMapper` | `RegistrationMapper` |
|
||||||
|
| Entity | `Xxx` | `Registration` |
|
||||||
|
| DTO | `XxxDto` / `XxxQueryDto` | `RegistrationDto` |
|
||||||
|
|
||||||
|
### 包结构
|
||||||
|
```
|
||||||
|
com.healthlink.his.web.{module}.controller
|
||||||
|
com.healthlink.his.web.{module}.appservice
|
||||||
|
com.healthlink.his.web.{module}.service
|
||||||
|
com.healthlink.his.web.{module}.mapper
|
||||||
|
com.healthlink.his.web.{module}.dto
|
||||||
|
com.healthlink.his.domain.{module}
|
||||||
|
com.healthlink.his.common.enums
|
||||||
|
```
|
||||||
|
|
||||||
|
### 关键约束
|
||||||
|
- 所有查询使用 `LambdaQueryWrapper`,禁止字符串拼接 SQL
|
||||||
|
- `@Transactional(rollbackFor = Exception.class)` 管理事务
|
||||||
|
- 所有接口标注 `@PreAuthorize` 权限控制
|
||||||
|
- 患者敏感信息在日志中脱敏
|
||||||
|
- **扩展功能不修改原有函数签名**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 九、前端开发规范
|
||||||
|
|
||||||
|
### 技术栈
|
||||||
|
- Vue 3 + Vite + Element Plus + Pinia + Axios(基于 RuoYi-Vue3)
|
||||||
|
|
||||||
|
### 目录结构
|
||||||
|
```
|
||||||
|
src/api/{module}/ # API接口
|
||||||
|
src/views/{module}/ # 页面组件
|
||||||
|
src/store/modules/ # Pinia状态管理
|
||||||
|
src/components/ # 公共组件
|
||||||
|
```
|
||||||
|
|
||||||
|
### 关键约束
|
||||||
|
- API前缀:`/healthlink-his/api/v1/`
|
||||||
|
- 路由懒加载:`() => import('@/views/xxx/index.vue')`
|
||||||
|
- 页面使用 `<script setup>` 语法
|
||||||
|
- 按钮权限使用 `v-hasPermi` 指令
|
||||||
|
- `onMounted` 中注册的事件在 `onUnmounted` 中移除
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十、Agent 体系
|
||||||
|
|
||||||
|
### 角色与路由
|
||||||
|
|
||||||
|
| 代号 | 名称 | 角色 | 路由关键词 |
|
||||||
|
|------|------|------|-----------|
|
||||||
|
| liubei | 刘备 | 项目经理 | 协调、分派、异常升级 |
|
||||||
|
| zhugeliang | 诸葛亮 | 架构师 | 分析、路由、设计 |
|
||||||
|
| guanyu | 关羽 | 后端开发 | java, api, spring, service, controller |
|
||||||
|
| zhaoyun | 赵云 | 前端开发 | vue, 界面, 显示, 弹窗, 按钮 |
|
||||||
|
| xunyu | 荀彧 | DBA | 数据库, sql, 迁移, mapper xml |
|
||||||
|
| zhangfei | 张飞 | 测试 | 测试, QA, 回归 |
|
||||||
|
| huatuo | 华佗 | 验收 | 需求验收、质量确认 |
|
||||||
|
| chenlin | 陈琳 | 文档 | 文档、归档、Git提交 |
|
||||||
|
|
||||||
|
### 协作流水线
|
||||||
|
|
||||||
|
```
|
||||||
|
刘备(协调) → 诸葛亮(分析路由) → {关羽|赵云}(修复) → 荀彧(DB审查) → 张飞(测试) → 华佗(验收) → 陈琳(归档)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bug 修复完整管线(BDT 方法论)
|
||||||
|
|
||||||
|
```
|
||||||
|
获取Bug → 设计测试用例 → 基线测试(应失败) → 全链路修复 → 回归测试(应通过) → 扩展测试(无回归) → 提交
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bug 状态管理铁律
|
||||||
|
- 人类提的 Bug:只加备注,不改状态,不改分配
|
||||||
|
- 智能体提的 Bug:可以改分配和加备注
|
||||||
|
- 已关闭/已解决的 Bug 不再处理
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十一、审查与审计
|
||||||
|
|
||||||
|
### 三层审查体系
|
||||||
|
|
||||||
|
| 层级 | 内容 | 时机 |
|
||||||
|
|------|------|------|
|
||||||
|
| **L1 自审** | Agent 对照约束逐条检查 | 每次提交前 |
|
||||||
|
| **L2 配对审查** | Agent 生成变更摘要,人类终审 | PR/提交时 |
|
||||||
|
| **L3 合规审查** | 审计追踪,记录所有 AI 操作 | 持续 |
|
||||||
|
|
||||||
|
### L1 自审清单
|
||||||
|
```yaml
|
||||||
|
self_review:
|
||||||
|
- "所有修改能通过编译?"
|
||||||
|
- "遵守命名规范?"
|
||||||
|
- "测试覆盖达标?"
|
||||||
|
- "没有遗漏的 TODO / DEBUG?"
|
||||||
|
- "变更范围没超出任务边界?"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 评审评分维度
|
||||||
|
| 维度 | 问题 |
|
||||||
|
|------|------|
|
||||||
|
| 正确性 | 行为是否符合目标功能? |
|
||||||
|
| 验证 | 检查是否真的跑过并留下证据? |
|
||||||
|
| 范围纪律 | 是否保持在选定功能范围内? |
|
||||||
|
| 可靠性 | 结果能否在重启后继续工作? |
|
||||||
|
| 可维护性 | 代码和文档是否清楚到可交接? |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十二、标准工作循环
|
||||||
|
|
||||||
|
```
|
||||||
|
开始会话
|
||||||
|
├→ 1. Init — 读 AGENTS.md + PROGRESS.md + git log
|
||||||
|
├→ 2. Select — 只选一个未完成功能
|
||||||
|
├→ 3. Implement — 一次只做一个,不扩大范围
|
||||||
|
├→ 4. Verify — 运行验证命令,有证据才标记完成
|
||||||
|
└→ 5. Cleanup — 更新进度 + clean-state-checklist + git commit
|
||||||
|
```
|
||||||
|
|
||||||
|
### 会话结束前必须运行 Clean State Checklist
|
||||||
|
```
|
||||||
|
□ 标准启动路径仍然可用
|
||||||
|
□ 标准验证路径仍然可运行
|
||||||
|
□ 当前进度已记录到进度日志
|
||||||
|
□ 无半成品步骤处于未记录状态
|
||||||
|
□ 下一轮会话无需人工修复即可继续
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十三、开发流程
|
||||||
|
|
||||||
|
```
|
||||||
|
收到任务
|
||||||
|
├→ ① 分析需求 → 读相关文档(MD/)、读全链路6环
|
||||||
|
├→ ② 制定计划 → update_plan (3-6个阶段)
|
||||||
|
├→ ③ 后端开发 → Controller → AppService → Service → Mapper → Entity → Flyway
|
||||||
|
├→ ④ 后端测试 → mvn test → 接口测试(业务逻辑验证)
|
||||||
|
├→ ⑤ 前端开发 → API接口 → 页面组件 → 路由配置
|
||||||
|
├→ ⑥ 前端测试 → npm run build:dev → 功能验证
|
||||||
|
├→ ⑦ 质量门禁 → L1编译 → L2测试 → L3DB审查 → L4验收 → L5归档
|
||||||
|
└→ ⑧ 提交代码 → git commit(规范格式) → git push → 文档更新
|
||||||
|
```
|
||||||
|
|
||||||
|
### Git Commit 格式
|
||||||
|
```
|
||||||
|
<type>(<scope>): <subject>
|
||||||
|
|
||||||
|
type: feat|fix|docs|refactor|test|chore
|
||||||
|
scope: 模块名(如 registration, billing, pharmacy)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十四、快速参考命令
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# === 后端 ===
|
||||||
|
export JAVA_HOME=/opt/jdk-25
|
||||||
|
mvn clean compile -DskipTests # 编译
|
||||||
|
mvn install -DskipTests # 构建
|
||||||
|
mvn test -pl healthlink-his-application -Dtest="XxxTest" -Dsurefire.failIfNoSpecifiedTests=false
|
||||||
|
|
||||||
|
# === 前端 ===
|
||||||
|
cd healthlink-his-ui
|
||||||
|
npm run dev && npm run build:dev && npm run lint && npm run test:run
|
||||||
|
|
||||||
|
# === Git ===
|
||||||
|
git status && git add -A && git commit -m "feat(module): desc" && git push origin develop
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十五、详细规范文档索引
|
||||||
|
|
||||||
|
| 文档 | 路径 | 用途 |
|
||||||
|
|------|------|------|
|
||||||
|
| 执行铁律 | `MD/specs/IRON_RULES.md` | 铁律完整版 |
|
||||||
|
| 后端规范 | `MD/specs/BACKEND_DEVELOPMENT_STANDARD.md` | 后端编码标准 |
|
||||||
|
| 前端规范 | `MD/specs/FRONTEND_DEVELOPMENT_STANDARD.md` | 前端编码标准 |
|
||||||
|
| Harness方法论 | `MD/specs/HARNESS_ENGINEERING.md` | 完整Harness+Agent方法论 |
|
||||||
|
| 文档规范 | `MD/DOCUMENTATION_STANDARD.md` | 文档管理标准 |
|
||||||
|
| 后端清单 | `MD/specs/BACKEND_CHECKLIST.md` | 发布前检查 |
|
||||||
|
| 前端清单 | `MD/specs/FRONTEND_CHECKLIST.md` | 发布前检查 |
|
||||||
|
| 三甲标准 | `MD/standards/GRADE3A_HIS_STANDARD.md` | 三甲医院达标标准 |
|
||||||
|
| Flyway指南 | `MD/guides/FLYWAY_USAGE_GUIDE.md` | 数据库迁移指南 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十六、过往教训
|
||||||
|
|
||||||
|
| 教训 | 内容 |
|
||||||
|
|------|------|
|
||||||
|
| 状态链路断裂 | Bug#574: 签到设 BOOKED(1) 而非 CHECKED_IN(3),前端映射缺失 → 必须走完整状态链路 |
|
||||||
|
| 盲删源文件 | AI 看到编译错误直接删文件,没检查 baseline → 必须先确认文件来源 |
|
||||||
|
| 修复方向偏差 | 多次 fallback 改的是错误的 Service → 必须用 rg 搜索所有相关代码路径 |
|
||||||
|
| bug_reports 缺列 | INSERT 静默失败 → 必须检查表结构 |
|
||||||
|
| 禅道 comment API | API 不存在,用 resolve+activate workaround |
|
||||||
|
| SQLite WAL 并发 | 多进程并发写需要 checkpoint |
|
||||||
|
| UTF-8 切片 | 多字节字符不能用 byte index 切片 |
|
||||||
|
| 上下文焦虑 | Agent 感觉上下文快满时会匆忙结束,跳过验证 → 注意 context 40% 阈值 |
|
||||||
|
| 过早宣告胜利 | 自评≠验证,分开"干活"和"检查" |
|
||||||
|
| 覆盖率幻觉 | 覆盖率达标但逻辑没测 → 引入变异测试 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> ⚠️ 本文件是 AI 开发规范的唯一信源。各工具配置文件由 `bash scripts/sync-ai-rules.sh` 同步。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 📅 最后同步: 2026-06-06 15:09 | 源文件: RULES.md | 重新同步: `bash scripts/sync-ai-rules.sh`
|
||||||
|
|||||||
424
MD/MODULE_INDEX.md
Normal file
424
MD/MODULE_INDEX.md
Normal file
@@ -0,0 +1,424 @@
|
|||||||
|
# HealthLink-HIS 代码模块索引
|
||||||
|
|
||||||
|
> 供 LLM 快速定位代码。每个模块列出 Controller → Service → Mapper 关键文件。
|
||||||
|
|
||||||
|
## 关键词 → 模块速查
|
||||||
|
|
||||||
|
| 关键词 | 后端模块 | 前端目录 |
|
||||||
|
|---|---|---|
|
||||||
|
| 门诊医生站/门诊医嘱/门诊处方/诊断/检查申请 | `doctorstation` | `doctorstation` |
|
||||||
|
| 住院医生站/住院医嘱/临床医嘱/签发/停嘱 | `regdoctorstation` | `inpatientDoctor` |
|
||||||
|
| 住院护士站/医嘱校对/医嘱执行/护理/换床 | `inhospitalnursestation` | `inpatientNurse` |
|
||||||
|
| 挂号/门诊收费/门诊结算 | `chargemanage` | `charge` |
|
||||||
|
| 住院收费/住院结算/预交金 | `inhospitalcharge` | `inHospitalManagement` |
|
||||||
|
| 收费管理/计费/退费 | `paymentmanage` | `outpatientFinance` |
|
||||||
|
| 药品/药房/药库/发药/取药 | `pharmacymanage` | `pharmacymanagement` |
|
||||||
|
| 药房发药/门诊发药 | `pharmacyDispensarymanage` | `drug` |
|
||||||
|
| 药库管理/库存 | `pharmacyWarehousemanage` | `medicineStorage` |
|
||||||
|
| 库存管理/盘点/出入库 | `inventorymanage` | `medicineStorage` |
|
||||||
|
| 物资管理/耗材 | `materialmanage` | `` |
|
||||||
|
| 字典/数据字典/诊疗目录/基础数据 | `datadictionary` | `datadictionary` |
|
||||||
|
| 部门/科室管理 | `departmentmanage` | `system` |
|
||||||
|
| 卡管理/就诊卡 | `cardmanagement` | `cardmanagement` |
|
||||||
|
| 检验/化验/标本 | `lab` | `inspection` |
|
||||||
|
| 检查/影像/放射 | `Inspection` | `inspection` |
|
||||||
|
| 手术/手术安排/手术申请 | `surgicalschedule` | `surgerymanage` |
|
||||||
|
| 病历/电子病历/EMR | `emr` | `emr` |
|
||||||
|
| 护理记录/护理评估 | `nursing` | `nursing` |
|
||||||
|
| 分诊/排队/叫号 | `triageandqueuemanage` | `triageandqueuemanage` |
|
||||||
|
| 医保/医保对码/医保目录 | `ybmanage` | `ybmanagement` |
|
||||||
|
| 会诊/会诊申请 | `consultation` | `consultationmanagement` |
|
||||||
|
| 院感/感染上报 | `infection` | `infection` |
|
||||||
|
| 合理用药/处方审核 | `rationaldrug` | `rationaldrug` |
|
||||||
|
| 中医/中医处方 | `tcm` | `tcm` |
|
||||||
|
| 患者管理/患者信息 | `patientmanage` | `patientmanagement` |
|
||||||
|
| 预约/挂号预约 | `appointmentmanage` | `appoinmentmanage` |
|
||||||
|
| 报告/报告管理 | `reportmanage` | `` |
|
||||||
|
| 质控/质量 | `quality` | `quality` |
|
||||||
|
| 系统管理/用户/角色/权限 | `basicmanage` | `system` |
|
||||||
|
| 门诊管理/门诊工作站 | `outpatientmanage` | `doctorstation` |
|
||||||
|
| 前置手术/术前管理 | `preopmanage` | `preopmanage` |
|
||||||
|
| 危急值 | `criticalvalue` | `criticalvalue` |
|
||||||
|
| 抗菌药 | `antibiotic` | `antibiotic` |
|
||||||
|
| 随访 | `followup` | `followup` |
|
||||||
|
| request.js/请求拦截/响应拦截 | `common` | `crossmodule` |
|
||||||
|
|
||||||
|
## 后端模块详情
|
||||||
|
|
||||||
|
### `Inspection` (40 files)
|
||||||
|
- **Controller**: `Inspection/controller/SampleCollectController.java` `Inspection/controller/ObservationDefController.java` `Inspection/controller/LabReferenceRangeController.java`
|
||||||
|
- **AppService**: `Inspection/appservice/ISampleCollectAppManageAppService.java` `Inspection/appservice/ILisConfigManageAppService.java` `Inspection/appservice/IInstrumentManageAppService.java`
|
||||||
|
- **ServiceImpl**: `Inspection/appservice/impl/LisConfigManageAppServiceImpl.java` `Inspection/appservice/impl/ObservationManageAppServiceImpl.java` `Inspection/appservice/impl/SpecimenManageAppServiceImpl.java`
|
||||||
|
- **Mapper**: `Inspection/mapper/SampleCollectMapper.java` `Inspection/mapper/LisReportMapper.java` `Inspection/mapper/GroupRecMapper.java`
|
||||||
|
- **DTO**: `Inspection/dto/SampleCollectManageDto.java` `Inspection/dto/SpecimenDefManageDto.java` `Inspection/dto/InstrumentManageDto.java` `Inspection/dto/LisConfigManageDto.java` `Inspection/dto/InstrumentSelParam.java`
|
||||||
|
|
||||||
|
### `adjustprice` (10 files)
|
||||||
|
- **Controller**: `adjustprice/controller/ChangePriceController.java` `adjustprice/controller/ChangePriceDataListPageController.java`
|
||||||
|
- **ServiceImpl**: `adjustprice/appservice/impl/AdjustPriceServiceImpl.java`
|
||||||
|
- **Mapper**: `adjustprice/mapper/AdjustPriceMapper.java`
|
||||||
|
- **DTO**: `adjustprice/dto/ChangePriceDataDto.java` `adjustprice/dto/AdjustPriceManagerSearchParam.java` `adjustprice/dto/ChangePricePageDto.java`
|
||||||
|
|
||||||
|
### `anesthesia` (4 files)
|
||||||
|
- **Controller**: `anesthesia/controller/AnesthesiaController.java` `anesthesia/controller/AnesthesiaEnhancedController.java`
|
||||||
|
- **AppService**: `anesthesia/appservice/IAnesthesiaAppService.java`
|
||||||
|
- **ServiceImpl**: `anesthesia/appservice/impl/AnesthesiaAppServiceImpl.java`
|
||||||
|
|
||||||
|
### `antibiotic` (3 files)
|
||||||
|
- **Controller**: `antibiotic/controller/AntibioticController.java`
|
||||||
|
- **AppService**: `antibiotic/appservice/IAntibioticAppService.java`
|
||||||
|
- **ServiceImpl**: `antibiotic/appservice/impl/AntibioticAppServiceImpl.java`
|
||||||
|
|
||||||
|
### `appointmentmanage` (29 files)
|
||||||
|
- **Controller**: `appointmentmanage/controller/ScheduleSlotController.java` `appointmentmanage/controller/DeptAppthoursController.java` `appointmentmanage/controller/SchedulePoolController.java`
|
||||||
|
- **AppService**: `appointmentmanage/appservice/IDeptAppService.java` `appointmentmanage/appservice/IDoctorScheduleAppService.java` `appointmentmanage/appservice/IClinicRoomAppService.java`
|
||||||
|
- **ServiceImpl**: `appointmentmanage/appservice/impl/DoctorScheduleAppServiceImpl.java` `appointmentmanage/appservice/impl/DeptAppointmentHoursAppServiceImpl.java` `appointmentmanage/appservice/impl/TicketAppServiceImpl.java`
|
||||||
|
- **Mapper**: `appointmentmanage/mapper/DoctorScheduleAppMapper.java` `appointmentmanage/mapper/SchedulePoolAppMapper.java` `appointmentmanage/mapper/DeptAppMapper.java`
|
||||||
|
- **DTO**: `appointmentmanage/dto/TicketDto.java` `appointmentmanage/dto/SchedulePoolDto.java`
|
||||||
|
|
||||||
|
### `basedatamanage` (44 files)
|
||||||
|
- **Controller**: `basedatamanage/controller/OrganizationLocationController.java` `basedatamanage/controller/BodyStructureController.java` `basedatamanage/controller/OperatingRoomController.java`
|
||||||
|
- **AppService**: `basedatamanage/appservice/IOrganizationAppService.java` `basedatamanage/appservice/IBodyStructureAppService.java` `basedatamanage/appservice/ILocationAppService.java`
|
||||||
|
- **ServiceImpl**: `basedatamanage/appservice/impl/PractitionerAppServiceImpl.java` `basedatamanage/appservice/impl/BodyStructureAppServiceImpl.java` `basedatamanage/appservice/impl/OrganizationAppServiceImpl.java`
|
||||||
|
- **Mapper**: `basedatamanage/mapper/PractitionerAppAppMapper.java`
|
||||||
|
- **DTO**: `basedatamanage/dto/SelectableOrgDto.java` `basedatamanage/dto/PractitionerOrgAndLocationDto.java` `basedatamanage/dto/OrganizationInitDto.java` `basedatamanage/dto/OperatingRoomDto.java` `basedatamanage/dto/LocationInitDto.java`
|
||||||
|
|
||||||
|
### `basicmanage` (5 files)
|
||||||
|
- **Controller**: `basicmanage/controller/BedController.java` `basicmanage/controller/InvoiceController.java` `basicmanage/controller/InvoiceSegmentController.java`
|
||||||
|
|
||||||
|
### `basicservice` (7 files)
|
||||||
|
- **Controller**: `basicservice/controller/HealthcareServiceController.java`
|
||||||
|
- **Mapper**: `basicservice/mapper/HealthcareServiceBizMapper.java`
|
||||||
|
- **DTO**: `basicservice/dto/HealthcareServiceAddOrUpdateParam.java` `basicservice/dto/HealthcareServiceDto.java` `basicservice/dto/HealthcareServiceInitDto.java`
|
||||||
|
|
||||||
|
### `ca` (3 files)
|
||||||
|
- **Controller**: `ca/controller/CaSignatureController.java`
|
||||||
|
- **AppService**: `ca/appservice/ICaSignatureAppService.java`
|
||||||
|
- **ServiceImpl**: `ca/appservice/impl/CaSignatureAppServiceImpl.java`
|
||||||
|
|
||||||
|
### `cardmanagement` (17 files)
|
||||||
|
- **Controller**: `cardmanagement/controller/CardManageController.java`
|
||||||
|
- **AppService**: `cardmanagement/appservice/ICardManageAppService.java`
|
||||||
|
- **ServiceImpl**: `cardmanagement/appservice/impl/CardManageAppServiceImpl.java`
|
||||||
|
- **Mapper**: `cardmanagement/mapper/InfectiousAuditMapper.java` `cardmanagement/mapper/InfectiousCardMapper.java`
|
||||||
|
- **DTO**: `cardmanagement/dto/InfectiousCardDto.java` `cardmanagement/dto/DoctorCardQueryDto.java` `cardmanagement/dto/DoctorCardListDto.java` `cardmanagement/dto/SingleReturnDto.java` `cardmanagement/dto/CardStatisticsDto.java`
|
||||||
|
|
||||||
|
### `catalogmanage` (4 files)
|
||||||
|
- **Controller**: `catalogmanage/controller/CatalogController.java`
|
||||||
|
- **ServiceImpl**: `catalogmanage/appservice/impl/CatalogServiceImpl.java`
|
||||||
|
- **Mapper**: `catalogmanage/mapper/CatalogMapper.java`
|
||||||
|
|
||||||
|
### `charge` (4 files)
|
||||||
|
- **Controller**: `charge/patientcardrenewal/PatientCardRenewalController.java`
|
||||||
|
- **ServiceImpl**: `charge/patientcardrenewal/PatientCardRenewalServiceImpl.java`
|
||||||
|
|
||||||
|
### `chargemanage` (46 files)
|
||||||
|
- **Controller**: `chargemanage/controller/OutpatientRegistrationController.java` `chargemanage/controller/OutpatientPricingController.java` `chargemanage/controller/InpatientChargeController.java`
|
||||||
|
- **AppService**: `chargemanage/appservice/IInpatientChargeAppService.java` `chargemanage/appservice/IOutpatientRegistrationAppService.java` `chargemanage/appservice/IOutpatientRefundAppService.java`
|
||||||
|
- **ServiceImpl**: `chargemanage/appservice/impl/OutpatientChargeAppServiceImpl.java` `chargemanage/appservice/impl/InpatientChargeAppServiceImpl.java` `chargemanage/appservice/impl/OutpatientRefundAppServiceImpl.java`
|
||||||
|
- **Mapper**: `chargemanage/mapper/OutpatientRefundAppMapper.java` `chargemanage/mapper/OutpatientRegistrationAppMapper.java` `chargemanage/mapper/OutpatientChargeAppMapper.java`
|
||||||
|
- **DTO**: `chargemanage/dto/ReprintRegistrationDto.java` `chargemanage/dto/EncounterPatientRefundDto.java` `chargemanage/dto/OutpatientPricingPriceDto.java` `chargemanage/dto/OutpatientPricingInventoryDto.java` `chargemanage/dto/RefundItemParam.java`
|
||||||
|
|
||||||
|
### `check` (27 files)
|
||||||
|
- **Controller**: `check/controller/CheckMethodController.java` `check/controller/SpecimenBarcodeController.java` `check/controller/RadiologyEnhancedController.java`
|
||||||
|
- **AppService**: `check/appservice/ILisGroupInfoAppService.java` `check/appservice/ICheckPartAppService.java` `check/appservice/ICheckMethodAppService.java`
|
||||||
|
- **ServiceImpl**: `check/appservice/impl/CheckMethodAppServiceImpl.java` `check/appservice/impl/CheckPartAppServiceImpl.java` `check/appservice/impl/CheckPackageAppServiceImpl.java`
|
||||||
|
- **Mapper**: `check/mapper/LisGroupInfoAppMapper.java` `check/mapper/CheckMethodAppMapper.java` `check/mapper/CheckPartAppMapper.java`
|
||||||
|
- **DTO**: `check/dto/CheckPackageDetailDto.java` `check/dto/ExamApplyDto.java` `check/dto/ExamApplyItemDto.java` `check/dto/CheckPackageDto.java` `check/dto/CheckMethodDto.java`
|
||||||
|
|
||||||
|
### `clinical` (2 files)
|
||||||
|
- **Controller**: `clinical/controller/KnowledgeBaseController.java` `clinical/controller/ClinicalPathwayController.java`
|
||||||
|
|
||||||
|
### `clinicalmanage` (11 files)
|
||||||
|
- **Controller**: `clinicalmanage/controller/SurgicalScheduleController.java` `clinicalmanage/controller/SurgeryController.java`
|
||||||
|
- **AppService**: `clinicalmanage/appservice/ISurgicalScheduleAppService.java` `clinicalmanage/appservice/ISurgeryAppService.java`
|
||||||
|
- **ServiceImpl**: `clinicalmanage/appservice/impl/SurgicalScheduleAppServiceImpl.java` `clinicalmanage/appservice/impl/SurgeryAppServiceImpl.java`
|
||||||
|
- **Mapper**: `clinicalmanage/mapper/SurgicalScheduleAppMapper.java` `clinicalmanage/mapper/SurgeryAppMapper.java`
|
||||||
|
- **DTO**: `clinicalmanage/dto/SurgeryDto.java` `clinicalmanage/dto/OpScheduleDto.java` `clinicalmanage/dto/OpCreateScheduleDto.java`
|
||||||
|
|
||||||
|
### `common` (17 files)
|
||||||
|
- **Controller**: `common/controller/CommonAppController.java`
|
||||||
|
- **ServiceImpl**: `common/appservice/impl/CommonServiceImpl.java`
|
||||||
|
- **Mapper**: `common/mapper/CommonAppMapper.java`
|
||||||
|
- **DTO**: `common/dto/ActivityDefinitionDto.java` `common/dto/PerformInfoDto.java` `common/dto/PractitionerInfoDto.java` `common/dto/LocationInventoryDto.java` `common/dto/PerformRecordDto.java`
|
||||||
|
|
||||||
|
### `consultation` (19 files)
|
||||||
|
- **Controller**: `consultation/controller/ConsultationController.java`
|
||||||
|
- **AppService**: `consultation/appservice/IConsultationAppService.java`
|
||||||
|
- **ServiceImpl**: `consultation/appservice/impl/ConsultationAppServiceImpl.java`
|
||||||
|
- **Mapper**: `consultation/mapper/ConsultationInvitedMapper.java` `consultation/mapper/ConsultationConfirmationMapper.java` `consultation/mapper/ConsultationRequestMapper.java`
|
||||||
|
- **DTO**: `consultation/dto/PhysicianNodeDto.java` `consultation/dto/InvitedObjectDto.java` `consultation/dto/ConsultationActivityDto.java` `consultation/dto/DepartmentTreeDto.java` `consultation/dto/ConsultationRequestDto.java`
|
||||||
|
|
||||||
|
### `controller` (2 files)
|
||||||
|
- **Controller**: `controller/WorkflowController.java` `controller/HomeStatisticsController.java`
|
||||||
|
|
||||||
|
### `criticalvalue` (3 files)
|
||||||
|
- **Controller**: `criticalvalue/controller/CriticalValueController.java`
|
||||||
|
- **AppService**: `criticalvalue/appservice/ICriticalValueAppService.java`
|
||||||
|
- **ServiceImpl**: `criticalvalue/appservice/impl/CriticalValueAppServiceImpl.java`
|
||||||
|
|
||||||
|
### `crossmodule` (3 files)
|
||||||
|
- **Controller**: `crossmodule/controller/CrossModuleController.java` `crossmodule/controller/EnhancementController.java` `crossmodule/controller/IntegrationController.java`
|
||||||
|
|
||||||
|
### `datadictionary` (65 files)
|
||||||
|
- **Controller**: `datadictionary/controller/DiagnosisTreatmentController.java` `datadictionary/controller/MedicationManageController.java` `datadictionary/controller/DiseaseManageController.java`
|
||||||
|
- **AppService**: `datadictionary/appservice/IDeviceManageAppService.java` `datadictionary/appservice/IDiagTreatMAppService.java` `datadictionary/appservice/ItemDefinitionAppService.java`
|
||||||
|
- **ServiceImpl**: `datadictionary/appservice/impl/DiagTreatMAppServiceImpl.java` `datadictionary/appservice/impl/SupplierManagementAppServiceImpl.java` `datadictionary/appservice/impl/ItemDefinitionAppServiceImpl.java`
|
||||||
|
- **Mapper**: `datadictionary/mapper/MedicationManageSearchMapper.java` `datadictionary/mapper/ICDCodeMapper.java` `datadictionary/mapper/ActivityDefinitionManageMapper.java`
|
||||||
|
- **DTO**: `datadictionary/dto/DeviceManageUpDto.java` `datadictionary/dto/ChargeItemOptionDto.java` `datadictionary/dto/SupplierDto.java` `datadictionary/dto/DiagnosisTreatmentInitDto.java` `datadictionary/dto/DiagnosisTreatmentSelParam.java`
|
||||||
|
|
||||||
|
### `departmentmanage` (42 files)
|
||||||
|
- **Controller**: `departmentmanage/controller/DepartmentTransferOutOrderController.java` `departmentmanage/controller/DepartmentReturnToWarehouseOrderController.java` `departmentmanage/controller/DepartmentStocktakingOrderController.java`
|
||||||
|
- **ServiceImpl**: `departmentmanage/appservice/impl/DepartmentReceiptApprovalServiceImpl.java` `departmentmanage/appservice/impl/DepartmentStockInOrderServiceImpl.java` `departmentmanage/appservice/impl/DepartmentCommonServiceImpl.java`
|
||||||
|
- **Mapper**: `departmentmanage/mapper/DepartmentTransferInOrderMapper.java` `departmentmanage/mapper/DepartmentStocktakingOrderMapper.java` `departmentmanage/mapper/DepartmentTransferOutOrderMapper.java`
|
||||||
|
- **DTO**: `departmentmanage/dto/DepartmentDeviceInfoDto.java` `departmentmanage/dto/DepartmentDetailDto.java` `departmentmanage/dto/DepartmentInitDto.java` `departmentmanage/dto/DepartmentSearchParam.java` `departmentmanage/dto/DepartmentDto.java`
|
||||||
|
|
||||||
|
### `doctorstation` (91 files)
|
||||||
|
- **Controller**: `doctorstation/controller/DoctorStationDiagnosisController.java` `doctorstation/controller/DoctorStationInspectionLabApplyController.java` `doctorstation/controller/DoctorStationChineseMedicalController.java`
|
||||||
|
- **AppService**: `doctorstation/appservice/IDoctorPhraseAppService.java` `doctorstation/appservice/IDoctorStationEmrAppService.java` `doctorstation/appservice/IDoctorStationMainAppService.java`
|
||||||
|
- **ServiceImpl**: `doctorstation/appservice/impl/DoctorStationPtDetailsAppServiceImpl.java` `doctorstation/appservice/impl/DoctorStationElepPrescriptionServiceImpl.java` `doctorstation/appservice/impl/DoctorPhraseAppServiceImpl.java`
|
||||||
|
- **Mapper**: `doctorstation/mapper/DoctorStationAdviceAppMapper.java` `doctorstation/mapper/DoctorStationEmrAppMapper.java` `doctorstation/mapper/DoctorStationDiagnosisAppMapper.java`
|
||||||
|
- **DTO**: `doctorstation/dto/EncounterContractDto.java` `doctorstation/dto/AdviceInventoryDto.java` `doctorstation/dto/ActivityChildrenJsonParams.java` `doctorstation/dto/DoctorStationLabApplyItemDto.java` `doctorstation/dto/DoctorStationInitDto.java`
|
||||||
|
|
||||||
|
### `document` (47 files)
|
||||||
|
- **Controller**: `document/controller/DocRecordController.java` `document/controller/DocDefinitionController.java` `document/controller/InformedConsentController.java`
|
||||||
|
- **AppService**: `document/appservice/IDocStatisticsAppService.java` `document/appservice/IDocRecordAppService.java` `document/appservice/IDocTemplateAppService.java`
|
||||||
|
- **ServiceImpl**: `document/appservice/impl/DocStatisticsDefinitionAppServiceImpl.java` `document/appservice/impl/DocRecordAppServiceImpl.java` `document/appservice/impl/DocStatisticsAppServiceImpl.java`
|
||||||
|
- **Mapper**: `document/mapper/DocRecordAppMapper.java` `document/mapper/DocStatisticsDefinitionAppMapper.java` `document/mapper/DocDefinitionAppMapper.java`
|
||||||
|
- **DTO**: `document/dto/DocStatisticsDefinitionDto.java` `document/dto/DocRecordPatientQueryParam.java` `document/dto/DocDefinitionOrganizationDto.java` `document/dto/DocRecordDto.java` `document/dto/DocTemplateDto.java`
|
||||||
|
|
||||||
|
### `empi` (5 files)
|
||||||
|
- **Controller**: `empi/controller/EmpiController.java` `empi/controller/EmpiIdVerificationController.java` `empi/controller/EmpiEnhancedController.java`
|
||||||
|
- **AppService**: `empi/appservice/IEmpiAppService.java`
|
||||||
|
- **ServiceImpl**: `empi/appservice/impl/EmpiAppServiceImpl.java`
|
||||||
|
|
||||||
|
### `emr` (6 files)
|
||||||
|
- **Controller**: `emr/controller/EmrArchiveController.java` `emr/controller/StructuredEmrController.java` `emr/controller/EmrRevisionController.java`
|
||||||
|
- **AppService**: `emr/appservice/IStructuredEmrAppService.java`
|
||||||
|
- **ServiceImpl**: `emr/appservice/impl/StructuredEmrAppServiceImpl.java`
|
||||||
|
|
||||||
|
### `epidemic` (3 files)
|
||||||
|
- **Controller**: `epidemic/controller/EpidemicController.java`
|
||||||
|
- **AppService**: `epidemic/appservice/IEpidemicAppService.java`
|
||||||
|
- **ServiceImpl**: `epidemic/appservice/impl/EpidemicAppServiceImpl.java`
|
||||||
|
|
||||||
|
### `esbmanage` (4 files)
|
||||||
|
- **Controller**: `esbmanage/controller/EsbReliabilityController.java` `esbmanage/controller/EsbMessageController.java` `esbmanage/controller/EsbServiceRegistryController.java`
|
||||||
|
|
||||||
|
### `externalintegration` (18 files)
|
||||||
|
- **Controller**: `externalintegration/controller/FoodborneAcquisitionAppController.java`
|
||||||
|
- **AppService**: `externalintegration/appservice/IBankPosCloudAppService.java` `externalintegration/appservice/IFoodborneAcquisitionAppService.java`
|
||||||
|
- **ServiceImpl**: `externalintegration/appservice/impl/FoodborneAcquisitionAppServiceImpl.java` `externalintegration/appservice/impl/BankPosCloudAppServiceImpl.java`
|
||||||
|
- **Mapper**: `externalintegration/mapper/FoodborneAcquisitionAppMapper.java`
|
||||||
|
- **DTO**: `externalintegration/dto/BpcTransactionResponseDto.java` `externalintegration/dto/BpcPaymentScanNotifyDto.java` `externalintegration/dto/FaSimplediseaseAddNopwParam.java` `externalintegration/dto/BpcTransactionRequestDto.java` `externalintegration/dto/BpcDataElementDto.java`
|
||||||
|
|
||||||
|
### `infection` (4 files)
|
||||||
|
- **Controller**: `infection/controller/InfectionEnhancedController.java` `infection/controller/InfectionController.java`
|
||||||
|
- **AppService**: `infection/appservice/IInfectionAppService.java`
|
||||||
|
- **ServiceImpl**: `infection/appservice/impl/InfectionAppServiceImpl.java`
|
||||||
|
|
||||||
|
### `inhospitalcharge` (17 files)
|
||||||
|
- **Controller**: `inhospitalcharge/controller/AdvancePaymentManageController.java` `inhospitalcharge/controller/InHospitalRegisterController.java`
|
||||||
|
- **AppService**: `inhospitalcharge/appservice/IInHospitalRegisterAppService.java` `inhospitalcharge/appservice/IAdvancePaymentManageAppService.java`
|
||||||
|
- **ServiceImpl**: `inhospitalcharge/appservice/impl/AdvancePaymentManageAppServiceImpl.java` `inhospitalcharge/appservice/impl/InHospitalRegisterAppServiceImpl.java`
|
||||||
|
- **Mapper**: `inhospitalcharge/mapper/InHospitalRegisterAppMapper.java` `inhospitalcharge/mapper/AdvancePaymentManageAppMapper.java`
|
||||||
|
- **DTO**: `inhospitalcharge/dto/AdvancePaymentInAndOutDto.java` `inhospitalcharge/dto/PatientUpdateDto.java` `inhospitalcharge/dto/NoFilesRegisterDto.java` `inhospitalcharge/dto/InHospitalPatientInfoDto.java` `inhospitalcharge/dto/InHospitalRegisterQueryDto.java`
|
||||||
|
|
||||||
|
### `inhospitalnursestation` (52 files)
|
||||||
|
- **Controller**: `inhospitalnursestation/controller/AdviceProcessController.java` `inhospitalnursestation/controller/NurseBillingController.java` `inhospitalnursestation/controller/EncounterAutoRollAppController.java`
|
||||||
|
- **AppService**: `inhospitalnursestation/appservice/IOrgDeviceStockTakeAppService.java` `inhospitalnursestation/appservice/IAdviceProcessAppService.java` `inhospitalnursestation/appservice/INurseBillingAppService.java`
|
||||||
|
- **ServiceImpl**: `inhospitalnursestation/appservice/impl/OrgDeviceStockTakeAppServiceImpl.java` `inhospitalnursestation/appservice/impl/ATDManageAppServiceImpl.java` `inhospitalnursestation/appservice/impl/EncounterAutoRollAppServiceImpl.java`
|
||||||
|
- **Mapper**: `inhospitalnursestation/mapper/ATDManageAppMapper.java` `inhospitalnursestation/mapper/EncounterAutoRollAppMapper.java` `inhospitalnursestation/mapper/MedicineSummaryAppMapper.java`
|
||||||
|
- **DTO**: `inhospitalnursestation/dto/AdmissionBedPageDto.java` `inhospitalnursestation/dto/AdviceExecuteParam.java` `inhospitalnursestation/dto/InpatientAdviceParam.java` `inhospitalnursestation/dto/DispenseFormSearchParam.java` `inhospitalnursestation/dto/AutoRollNursingDto.java`
|
||||||
|
|
||||||
|
### `inpatientmanage` (40 files)
|
||||||
|
- **Controller**: `inpatientmanage/controller/NursingVitalSignsChartController.java` `inpatientmanage/controller/VitalSignsController.java` `inpatientmanage/controller/PatientHomeController.java`
|
||||||
|
- **AppService**: `inpatientmanage/appservice/IPatientHomeAppService.java` `inpatientmanage/appservice/IDepositAppService.java` `inpatientmanage/appservice/INursingRecordAppService.java`
|
||||||
|
- **ServiceImpl**: `inpatientmanage/appservice/impl/DepositAppServiceImpl.java` `inpatientmanage/appservice/impl/NursingRecordAppServiceImpl.java` `inpatientmanage/appservice/impl/PatientHomeAppServiceImpl.java`
|
||||||
|
- **Mapper**: `inpatientmanage/mapper/VitalSignsAppMapper.java` `inpatientmanage/mapper/DepositMapper.java` `inpatientmanage/mapper/NursingRecordAppMapper.java`
|
||||||
|
- **DTO**: `inpatientmanage/dto/DepositDetailDto.java` `inpatientmanage/dto/VitalSignsChartSmallDto.java` `inpatientmanage/dto/VitalSignsSaveDto.java` `inpatientmanage/dto/PatientHomeSearchParam.java` `inpatientmanage/dto/PatientHomeEmptyBedDto.java`
|
||||||
|
|
||||||
|
### `inventorymanage` (107 files)
|
||||||
|
- **Controller**: `inventorymanage/controller/PurchaseReturnController.java` `inventorymanage/controller/InventorySettlementController.java` `inventorymanage/controller/ReturnIssueController.java`
|
||||||
|
- **AppService**: `inventorymanage/appservice/IProductStocktakingAppService.java` `inventorymanage/appservice/IInventoryDetailsAppService.java` `inventorymanage/appservice/IReturnIssueAppService.java`
|
||||||
|
- **ServiceImpl**: `inventorymanage/appservice/impl/InventoryDetailsAppServiceImpl.java` `inventorymanage/appservice/impl/ProductTransferAppServiceImpl.java` `inventorymanage/appservice/impl/ReceiptApprovalAppServiceImpl.java`
|
||||||
|
- **Mapper**: `inventorymanage/mapper/ProductDetailAppMapper.java` `inventorymanage/mapper/RequisitionIssueMapper.java` `inventorymanage/mapper/PurchaseReturnMapper.java`
|
||||||
|
- **DTO**: `inventorymanage/dto/ProductTransferPageDto.java` `inventorymanage/dto/PurchaseInventoryDto.java` `inventorymanage/dto/ReceiptDetailDto.java` `inventorymanage/dto/RequisitionOutDetailDto.java` `inventorymanage/dto/InventoryReceiptDetailDto.java`
|
||||||
|
|
||||||
|
### `jlau` (5 files)
|
||||||
|
- **Controller**: `jlau/controller/ReviewPrescriptionRecordsController.java`
|
||||||
|
- **AppService**: `jlau/appservice/IReviewPrescriptionRecordsAppService.java`
|
||||||
|
- **ServiceImpl**: `jlau/appservice/impl/ReviewPrescriptionRecordsAppServiceImpl.java`
|
||||||
|
- **Mapper**: `jlau/mapper/ReviewPrescriptionRecordsAppMapper.java`
|
||||||
|
- **DTO**: `jlau/dto/ReviewPrescriptionRecordsDto.java`
|
||||||
|
|
||||||
|
### `lab` (7 files)
|
||||||
|
- **Controller**: `lab/controller/LabActivityDefinitionController.java` `lab/controller/LabHistoryController.java` `lab/controller/LabEnhancedController.java`
|
||||||
|
- **AppService**: `lab/appservice/ILabActivityDefinitionAppService.java`
|
||||||
|
- **ServiceImpl**: `lab/appservice/impl/LabActivityDefinitionAppServiceImpl.java`
|
||||||
|
|
||||||
|
### `materialmanage` (46 files)
|
||||||
|
- **Controller**: `materialmanage/controller/MaterialReturnOrderController.java` `materialmanage/controller/MaterialTransferInOrderController.java` `materialmanage/controller/MaterialTransferOutOrderController.java`
|
||||||
|
- **ServiceImpl**: `materialmanage/appservice/impl/MaterialPurchaseOrderServiceImpl.java` `materialmanage/appservice/impl/MaterialTransferOutOrderServiceImpl.java` `materialmanage/appservice/impl/MaterialReturnToWarehouseOrderServiceImpl.java`
|
||||||
|
- **Mapper**: `materialmanage/mapper/MaterialCommonMapper.java` `materialmanage/mapper/MaterialProfitLossOrderMapper.java` `materialmanage/mapper/MaterialTransferOutOrderMapper.java`
|
||||||
|
- **DTO**: `materialmanage/dto/MaterialInitDto.java` `materialmanage/dto/MaterialSearchParam.java` `materialmanage/dto/MaterialDto.java` `materialmanage/dto/MaterialDetailDto.java` `materialmanage/dto/MaterialDeviceInfoDto.java`
|
||||||
|
|
||||||
|
### `mrhomepage` (6 files)
|
||||||
|
- **Controller**: `mrhomepage/controller/DrgAnalysisController.java` `mrhomepage/controller/MrManagementController.java` `mrhomepage/controller/MrHomepageController.java`
|
||||||
|
- **AppService**: `mrhomepage/appservice/IMrHomepageAppService.java`
|
||||||
|
- **ServiceImpl**: `mrhomepage/appservice/impl/MrHomepageAppServiceImpl.java`
|
||||||
|
|
||||||
|
### `nenu` (22 files)
|
||||||
|
- **Controller**: `nenu/controller/GfRatioApplicationRecordController.java` `nenu/controller/GfStudentListController.java` `nenu/controller/GfRatioManageController.java`
|
||||||
|
- **AppService**: `nenu/appservice/IGfRatioManageAppService.java` `nenu/appservice/IGfRatioApplicationRecordAppService.java` `nenu/appservice/IGfStudentListAppService.java`
|
||||||
|
- **ServiceImpl**: `nenu/appservice/impl/GfRatioApplicationRecordAppServiceImpl.java` `nenu/appservice/impl/GfRatioManageAppServiceImpl.java` `nenu/appservice/impl/GfStudentListAppServiceImpl.java`
|
||||||
|
- **Mapper**: `nenu/mapper/GfStudentListAppMapper.java` `nenu/mapper/GfRatioManageAppMapper.java` `nenu/mapper/GfRatioApplicationRecordAppMapper.java`
|
||||||
|
- **DTO**: `nenu/dto/GfIndividualRatioDto.java` `nenu/dto/GfRatioApplicationRecordDto.java` `nenu/dto/GfStudentListImportDto.java` `nenu/dto/GfRatioApplicationProcessDto.java` `nenu/dto/GfStudentPeisDto.java`
|
||||||
|
|
||||||
|
### `nursing` (8 files)
|
||||||
|
- **Controller**: `nursing/controller/NursingExecutionController.java` `nursing/controller/NursingAssessmentEnhancedController.java` `nursing/controller/NursingEnhancedController.java`
|
||||||
|
- **AppService**: `nursing/appservice/INursingAppService.java`
|
||||||
|
- **ServiceImpl**: `nursing/appservice/impl/NursingAppServiceImpl.java`
|
||||||
|
|
||||||
|
### `orderclosedloop` (3 files)
|
||||||
|
- **Controller**: `orderclosedloop/controller/OrderClosedLoopController.java`
|
||||||
|
- **AppService**: `orderclosedloop/appservice/IOrderClosedLoopAppService.java`
|
||||||
|
- **ServiceImpl**: `orderclosedloop/appservice/impl/OrderClosedLoopAppServiceImpl.java`
|
||||||
|
|
||||||
|
### `outpatientmanage` (22 files)
|
||||||
|
- **Controller**: `outpatientmanage/controller/OutpatientTreatmentController.java` `outpatientmanage/controller/OutpatientSkinTestAppController.java` `outpatientmanage/controller/OutpatientInfusionController.java`
|
||||||
|
- **AppService**: `outpatientmanage/appservice/IOutpatientTreatmentAppService.java` `outpatientmanage/appservice/IOutpatientInfusionAppService.java` `outpatientmanage/appservice/IOutpatientSkinTestAppService.java`
|
||||||
|
- **ServiceImpl**: `outpatientmanage/appservice/impl/OutpatientTreatmentAppServiceImpl.java` `outpatientmanage/appservice/impl/OutpatientSkinTestAppServiceImpl.java` `outpatientmanage/appservice/impl/OutpatientInfusionAppServiceImpl.java`
|
||||||
|
- **Mapper**: `outpatientmanage/mapper/OutpatientTreatmentAppMapper.java` `outpatientmanage/mapper/OutpatientInfusionAppMapper.java` `outpatientmanage/mapper/OutpatientSkinTestAppMapper.java`
|
||||||
|
- **DTO**: `outpatientmanage/dto/SkinTestMedLotNumberDto.java` `outpatientmanage/dto/OutpatientInfusionRecordDto.java` `outpatientmanage/dto/SkinTestSaveDto.java` `outpatientmanage/dto/OutpatientTreatmentInfoDto.java` `outpatientmanage/dto/OutpatientStationInitDto.java`
|
||||||
|
|
||||||
|
### `patientmanage` (13 files)
|
||||||
|
- **Controller**: `patientmanage/controller/PatientInformationController.java` `patientmanage/controller/OutpatientRecordController.java`
|
||||||
|
- **ServiceImpl**: `patientmanage/appservice/impl/OutpatientRecordServiceImpl.java` `patientmanage/appservice/impl/PatientInformationServiceImpl.java`
|
||||||
|
- **Mapper**: `patientmanage/mapper/PatientManageMapper.java`
|
||||||
|
- **DTO**: `patientmanage/dto/PatientInfoInitDto.java` `patientmanage/dto/PatientIdInfoDto.java` `patientmanage/dto/OutpatientRecordSearchParam.java` `patientmanage/dto/PatientBaseInfoDto.java` `patientmanage/dto/OutpatientRecordDto.java`
|
||||||
|
|
||||||
|
### `paymentmanage` (57 files)
|
||||||
|
- **Controller**: `paymentmanage/controller/EleInvoiceController.java` `paymentmanage/controller/ChargeBillController.java` `paymentmanage/controller/PaymentContractController.java`
|
||||||
|
- **ServiceImpl**: `paymentmanage/appservice/impl/PaymentRecServiceImpl.java` `paymentmanage/appservice/impl/IChargeBillServiceImpl.java` `paymentmanage/appservice/impl/EleInvoiceServiceImpl.java`
|
||||||
|
- **Mapper**: `paymentmanage/mapper/EleInvoiceMapper.java` `paymentmanage/mapper/ThreePartPayMapper.java` `paymentmanage/mapper/ChangePriceMapper.java`
|
||||||
|
- **DTO**: `paymentmanage/dto/NenuBpcPayDto.java` `paymentmanage/dto/EleInvoiceResultDto.java` `paymentmanage/dto/ChargeSummaryDto.java` `paymentmanage/dto/EleInvoicePaymentInfoDto.java` `paymentmanage/dto/Clinic2207OrderResultInfoDto.java`
|
||||||
|
|
||||||
|
### `personalization` (22 files)
|
||||||
|
- **Controller**: `personalization/controller/ActivityDeviceController.java` `personalization/controller/OrdersGroupPackageController.java` `personalization/controller/OrderGroupController.java`
|
||||||
|
- **AppService**: `personalization/appservice/IOrderGroupAppService.java` `personalization/appservice/IOrdersGroupPackageAppService.java` `personalization/appservice/IActivityDeviceAppService.java`
|
||||||
|
- **ServiceImpl**: `personalization/appservice/impl/OrdersGroupPackageAppServiceImpl.java` `personalization/appservice/impl/ActivityDeviceAppServiceImpl.java` `personalization/appservice/impl/IOrderGroupAppServiceImpl.java`
|
||||||
|
- **Mapper**: `personalization/mapper/OrdersGroupPackageAppMapper.java` `personalization/mapper/OrderGroupAppMapper.java` `personalization/mapper/ActivityDeviceAppMapper.java`
|
||||||
|
- **DTO**: `personalization/dto/OrdersGroupPackageDetailSaveDto.java` `personalization/dto/OrderGroupDto.java` `personalization/dto/OrdersGroupPackageDto.java` `personalization/dto/OrderGroupInitDto.java` `personalization/dto/OrdersGroupPackageDetailQueryDto.java`
|
||||||
|
|
||||||
|
### `pharmacyDispensarymanage` (42 files)
|
||||||
|
- **Controller**: `pharmacyDispensarymanage/controller/PharmacyDispensaryTransferOutOrderController.java` `pharmacyDispensarymanage/controller/PharmacyDispensaryDispensingOrderController.java` `pharmacyDispensarymanage/controller/PharmacyDispensaryStocktakingOrderController.java`
|
||||||
|
- **ServiceImpl**: `pharmacyDispensarymanage/appservice/impl/PharmacyDispensaryStocktakingOrderServiceImpl.java` `pharmacyDispensarymanage/appservice/impl/PharmacyDispensaryTransferInOrderServiceImpl.java` `pharmacyDispensarymanage/appservice/impl/PharmacyDispensaryStockInOrderServiceImpl.java`
|
||||||
|
- **Mapper**: `pharmacyDispensarymanage/mapper/PharmacyDispensaryReturnToWarehouseOrderMapper.java` `pharmacyDispensarymanage/mapper/PharmacyDispensaryTransferOutOrderMapper.java` `pharmacyDispensarymanage/mapper/PharmacyDispensaryRequisitionOrderMapper.java`
|
||||||
|
- **DTO**: `pharmacyDispensarymanage/dto/PharmacyDispensaryDto.java` `pharmacyDispensarymanage/dto/PharmacyDispensaryDetailDto.java` `pharmacyDispensarymanage/dto/PharmacyDispensarySearchParam.java` `pharmacyDispensarymanage/dto/PharmacyDispensaryMedicationInfoDto.java` `pharmacyDispensarymanage/dto/PharmacyDispensaryInitDto.java`
|
||||||
|
|
||||||
|
### `pharmacyWarehousemanage` (42 files)
|
||||||
|
- **Controller**: `pharmacyWarehousemanage/controller/PharmacyWarehouseProfitLossOrderController.java` `pharmacyWarehousemanage/controller/PharmacyWarehouseReturnToWarehouseOrderController.java` `pharmacyWarehousemanage/controller/PharmacyWarehouseStockOutOrderController.java`
|
||||||
|
- **ServiceImpl**: `pharmacyWarehousemanage/appservice/impl/PharmacyWarehousePurchaseOrderServiceImpl.java` `pharmacyWarehousemanage/appservice/impl/PharmacyWarehouseDocumentManagementServiceImpl.java` `pharmacyWarehousemanage/appservice/impl/PharmacyWarehouseProfitLossOrderServiceImpl.java`
|
||||||
|
- **Mapper**: `pharmacyWarehousemanage/mapper/PharmacyWarehousePurchaseOrderMapper.java` `pharmacyWarehousemanage/mapper/PharmacyWarehouseDocumentManagementMapper.java` `pharmacyWarehousemanage/mapper/PharmacyWarehouseStockInOrderMapper.java`
|
||||||
|
- **DTO**: `pharmacyWarehousemanage/dto/PharmacyWarehouseDto.java` `pharmacyWarehousemanage/dto/PharmacyWarehouseDetailDto.java` `pharmacyWarehousemanage/dto/PharmacyWarehouseMedicationInfoDto.java` `pharmacyWarehousemanage/dto/PharmacyWarehouseInitDto.java` `pharmacyWarehousemanage/dto/PharmacyWarehouseSearchParam.java`
|
||||||
|
|
||||||
|
### `pharmacymanage` (53 files)
|
||||||
|
- **Controller**: `pharmacymanage/controller/InHospitalReturnMedicineController.java` `pharmacymanage/controller/PharmacyStockAlertController.java` `pharmacymanage/controller/MedicationDetailsController.java`
|
||||||
|
- **AppService**: `pharmacymanage/appservice/ISummaryDispenseMedicineAppService.java` `pharmacymanage/appservice/IPendingMedicationDetailsAppService.java` `pharmacymanage/appservice/IInHospitalReturnMedicineAppService.java`
|
||||||
|
- **ServiceImpl**: `pharmacymanage/appservice/impl/ReturnMedicineAppServiceImpl.java` `pharmacymanage/appservice/impl/MedicationDetailsAppServiceImpl.java` `pharmacymanage/appservice/impl/WesternMedicineDispenseAppServiceImpl.java`
|
||||||
|
- **Mapper**: `pharmacymanage/mapper/PendingMedicationDetailsMapper.java` `pharmacymanage/mapper/MedicalDeviceDispenseMapper.java` `pharmacymanage/mapper/SummaryDispenseMedicineMapper.java`
|
||||||
|
- **DTO**: `pharmacymanage/dto/MedDetailsInitDto.java` `pharmacymanage/dto/EncounterInfoSearchParam.java` `pharmacymanage/dto/ItemDispenseOrderDto.java` `pharmacymanage/dto/MedicineSummaryDto.java` `pharmacymanage/dto/MedicineSummarySearchParam.java`
|
||||||
|
|
||||||
|
### `quality` (5 files)
|
||||||
|
- **Controller**: `quality/controller/BusinessAnalyticsController.java` `quality/controller/QualityEnhancedController.java` `quality/controller/EmrQualityController.java`
|
||||||
|
- **AppService**: `quality/appservice/IEmrQualityAppService.java`
|
||||||
|
- **ServiceImpl**: `quality/appservice/impl/EmrQualityAppServiceImpl.java`
|
||||||
|
|
||||||
|
### `rationaldrug` (3 files)
|
||||||
|
- **Controller**: `rationaldrug/controller/RationalDrugController.java`
|
||||||
|
- **AppService**: `rationaldrug/appservice/IRationalDrugAppService.java`
|
||||||
|
- **ServiceImpl**: `rationaldrug/appservice/impl/RationalDrugAppServiceImpl.java`
|
||||||
|
|
||||||
|
### `regdoctorstation` (38 files)
|
||||||
|
- **Controller**: `regdoctorstation/controller/NurseManageController.java` `regdoctorstation/controller/AdviceManageController.java` `regdoctorstation/controller/SpecialAdviceController.java`
|
||||||
|
- **AppService**: `regdoctorstation/appservice/IAdviceManageAppService.java` `regdoctorstation/appservice/IRequestFormManageAppService.java` `regdoctorstation/appservice/ISpecialAdviceAppService.java`
|
||||||
|
- **ServiceImpl**: `regdoctorstation/appservice/impl/SpecialAdviceAppServiceImpl.java` `regdoctorstation/appservice/impl/RequestFormManageAppServiceImpl.java` `regdoctorstation/appservice/impl/NurseManageServiceImpl.java`
|
||||||
|
- **Mapper**: `regdoctorstation/mapper/RequestFormManageAppMapper.java` `regdoctorstation/mapper/AdviceManageAppMapper.java` `regdoctorstation/mapper/SpecialAdviceAppMapper.java`
|
||||||
|
- **DTO**: `regdoctorstation/dto/RegPatientMainInfoDto.java` `regdoctorstation/dto/NursingOrdersDetailDto.java` `regdoctorstation/dto/LeaveHospitalParam.java` `regdoctorstation/dto/NursingOrdersSaveDto.java` `regdoctorstation/dto/NursingOrdersEncounterDto.java`
|
||||||
|
|
||||||
|
### `reportManagement` (11 files)
|
||||||
|
- **Controller**: `reportManagement/controller/reportManagementController.java`
|
||||||
|
- **AppService**: `reportManagement/appservice/IInfectiousCardAppService.java`
|
||||||
|
- **ServiceImpl**: `reportManagement/appservice/impl/InfectiousCardAppServiceImpl.java`
|
||||||
|
- **Mapper**: `reportManagement/mapper/ReportManageCardMapper.java`
|
||||||
|
- **DTO**: `reportManagement/dto/InfectiousCardDto.java` `reportManagement/dto/InfectiousCardParam.java`
|
||||||
|
|
||||||
|
### `reportmanage` (164 files)
|
||||||
|
- **Controller**: `reportmanage/controller/AmbAdviceStatisticsAppController.java` `reportmanage/controller/MonthlySettlementController.java` `reportmanage/controller/PurchaseReturnReportController.java`
|
||||||
|
- **AppService**: `reportmanage/appservice/PurchaseReturnReportAppService.java` `reportmanage/appservice/IDrugDosageSettlementAppService.java` `reportmanage/appservice/IDepartmentRevenueStatisticsAppService.java`
|
||||||
|
- **ServiceImpl**: `reportmanage/appservice/impl/InboundReportAppServiceImpl.java` `reportmanage/appservice/impl/MedicationInboundReportAppServiceImpl.java` `reportmanage/appservice/impl/ReportStatisticsAppServiceImpl.java`
|
||||||
|
- **Mapper**: `reportmanage/mapper/PrintReportMapper.java` `reportmanage/mapper/ReportStatisticsMapper.java` `reportmanage/mapper/LossReportMapper.java`
|
||||||
|
- **DTO**: `reportmanage/dto/ReportDiseaseDetailsDto.java` `reportmanage/dto/InboundReportSearchParam.java` `reportmanage/dto/InpatientMedicalRecordHomePageCollectionDto.java` `reportmanage/dto/ZyCostDetailParam.java` `reportmanage/dto/BottleLabelDto.java`
|
||||||
|
|
||||||
|
### `review` (3 files)
|
||||||
|
- **Controller**: `review/controller/ReviewController.java`
|
||||||
|
- **AppService**: `review/appservice/IReviewAppService.java`
|
||||||
|
- **ServiceImpl**: `review/appservice/impl/ReviewAppServiceImpl.java`
|
||||||
|
|
||||||
|
### `service` (2 files)
|
||||||
|
- **ServiceImpl**: `service/impl/HomeStatisticsServiceImpl.java`
|
||||||
|
|
||||||
|
### `system` (5 files)
|
||||||
|
- **Controller**: `system/controller/ApiAuthController.java` `system/controller/DashboardController.java` `system/controller/SysAuditLogController.java`
|
||||||
|
|
||||||
|
### `tcm` (3 files)
|
||||||
|
- **Controller**: `tcm/controller/TcmController.java`
|
||||||
|
- **AppService**: `tcm/appservice/ITcmAppService.java`
|
||||||
|
- **ServiceImpl**: `tcm/appservice/impl/TcmAppServiceImpl.java`
|
||||||
|
|
||||||
|
### `tencentJH` (13 files)
|
||||||
|
- **Controller**: `tencentJH/controller/TencentController.java`
|
||||||
|
- **AppService**: `tencentJH/appservice/ITencentAppService.java`
|
||||||
|
- **ServiceImpl**: `tencentJH/appservice/impl/TencentAppServiceImpl.java`
|
||||||
|
- **Mapper**: `tencentJH/mapper/TencentAppMapper.java`
|
||||||
|
- **DTO**: `tencentJH/dto/PatientInfoTencentDto.java` `tencentJH/dto/CurrentDayEncounterTencentDto.java`
|
||||||
|
|
||||||
|
### `triageandqueuemanage` (13 files)
|
||||||
|
- **Controller**: `triageandqueuemanage/controller/CallNumberVoiceConfigController.java` `triageandqueuemanage/controller/TriageQueueController.java`
|
||||||
|
- **AppService**: `triageandqueuemanage/appservice/CallNumberVoiceConfigAppService.java` `triageandqueuemanage/appservice/TriageQueueAppService.java`
|
||||||
|
- **ServiceImpl**: `triageandqueuemanage/appservice/impl/CallNumberVoiceConfigAppServiceImpl.java` `triageandqueuemanage/appservice/impl/TriageQueueAppServiceImpl.java`
|
||||||
|
- **Mapper**: `triageandqueuemanage/mapper/CallNumberVoiceConfigAppMapper.java`
|
||||||
|
|
||||||
|
### `ybmanage` (55 files)
|
||||||
|
- **Controller**: `ybmanage/controller/YbInpatientController.java` `ybmanage/controller/YbElepController.java` `ybmanage/controller/YbController.java`
|
||||||
|
- **ServiceImpl**: `ybmanage/service/impl/YbEleHttpServiceImpl.java` `ybmanage/service/impl/YbServiceImpl.java` `ybmanage/service/impl/YbElepBaseServiceImpl.java`
|
||||||
|
- **Mapper**: `ybmanage/mapper/YbElepMapper.java` `ybmanage/mapper/YbMapper.java`
|
||||||
|
- **DTO**: `ybmanage/dto/FinancialHand3203AWebParam.java` `ybmanage/dto/FinancialHand3201WebParam.java` `ybmanage/dto/Financial13203WebParam.java` `ybmanage/dto/VeriPrescriptionInfoDto.java` `ybmanage/dto/YbInHospitalRegisterQueryDto.java`
|
||||||
|
|
||||||
|
## 前端关键文件
|
||||||
|
|
||||||
|
| 目录 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| `src/utils/request.js` | Axios 请求/响应拦截器 |
|
||||||
|
| `src/api/` | API 接口定义 |
|
||||||
|
| `src/components/` | 公共组件 |
|
||||||
|
| `src/views/doctorstation/` | 门诊医生站 |
|
||||||
|
| `src/views/inpatientDoctor/` | 住院医生站 |
|
||||||
|
| `src/views/inpatientNurse/` | 住院护士站 |
|
||||||
|
| `src/views/charge/` | 收费工作站 |
|
||||||
|
| `src/views/datadictionary/` | 数据字典 |
|
||||||
|
| `src/views/system/` | 系统管理 |
|
||||||
|
|
||||||
|
## 公共/通用文件
|
||||||
|
|
||||||
|
- `com.core.common.core.domain.R` — 统一响应封装
|
||||||
|
- `com.core.common.core.domain.entity.SysDictData` — 字典数据实体
|
||||||
|
- `com.core.common.utils.SecurityUtils` — 安全工具(获取当前用户)
|
||||||
|
- `com.core.common.enums.*` — 枚举定义
|
||||||
|
- `com.healthlink.his.common.constant.CommonConstants` — 公共常量
|
||||||
|
- `com.healthlink.his.common.utils.HisQueryUtils` — 查询工具
|
||||||
|
- `com.healthlink.his.common.utils.HisPageUtils` — 分页工具
|
||||||
|
- `com.healthlink.his.web.doctorstation.utils.AdviceUtils` — 医嘱工具类
|
||||||
|
|
||||||
|
|
||||||
|
=== 已生成 421 行索引 ===
|
||||||
25
MD/bugs/BUG_698_ANALYSIS.md
Normal file
25
MD/bugs/BUG_698_ANALYSIS.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Bug #698 诸葛亮分析报告
|
||||||
|
|
||||||
|
> **文档类型**: Bug分析
|
||||||
|
> **分析时间**: 2026-06-11 16:51:39
|
||||||
|
> **分析模型**: mimo-v2.5 (LLM深度分析)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 基本信息
|
||||||
|
- **Bug #**: 698
|
||||||
|
- **标题**: [收费工作站-住院登记-已登记入院] 检索维度单一,且关键归档信息缺失(需增设检索条件与补充列表字段展示)
|
||||||
|
- **模块**: 住院登记管理
|
||||||
|
- **提出人**: 陈显精
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(LLM 失败,关键词分析)
|
||||||
|
Bug: [收费工作站-住院登记-已登记入院] 检索维度单一,且关键归档信息缺失(需增设检索条件与补充列表字段展示)
|
||||||
|
模块: 住院登记管理
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 路由决策
|
||||||
|
- **修复 Agent**: zhaoyun
|
||||||
|
- **原因**: 关键词: 前端
|
||||||
84
MD/bugs/BUG_741_ANALYSIS.md
Normal file
84
MD/bugs/BUG_741_ANALYSIS.md
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
# Bug #741 诸葛亮分析报告
|
||||||
|
|
||||||
|
> **文档类型**: Bug分析
|
||||||
|
> **分析时间**: 2026-06-12 11:46:17
|
||||||
|
> **分析模型**: mimo-v2.5 (LLM深度分析)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 基本信息
|
||||||
|
- **Bug #**: 741
|
||||||
|
- **标题**: 【住院医生工作站】打开门诊医生工作站会有代码列表报错
|
||||||
|
- **模块**: 住院医生工作站
|
||||||
|
- **提出人**: 王栩坤
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 一、Bug 理解
|
||||||
|
|
||||||
|
用户登录 doctor1 账号进入**住院医生工作站**页面时,页面加载过程中某个 API 请求返回了 500 错误,错误信息为 `class java.util.ArrayList cannot be cast to class com.fasterxml.jackson.databind.JsonNode`。这个 Java ClassCastException 被前端 `request.js` 拦截器捕获并弹出错误提示,导致页面功能异常。期望是页面能正常加载,患者列表和各 Tab 页正常工作。
|
||||||
|
|
||||||
|
### 二、根因分析
|
||||||
|
|
||||||
|
**直接原因**:后端某个 API 接口在处理请求或序列化响应时,抛出了 `ClassCastException: ArrayList cannot be cast to JsonNode`。异常被 `GlobalExceptionHandler` 捕获后返回 `{code:500, msg:"class java.util.ArrayList cannot be cast to class com.fasterxml.jackson.databind.JsonNode"}`。
|
||||||
|
|
||||||
|
**根因定位**:commit `68cfa4882` 修改了 `ApplicationConfig`,将 `Jackson2ObjectMapperBuilderCustomizer` 替换为直接创建 `new ObjectMapper()` 的 `@Bean`。
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 旧代码 — 定制 Spring Boot 自动配置的 ObjectMapper
|
||||||
|
@Bean
|
||||||
|
public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() {
|
||||||
|
return builder -> { ... };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新代码 — 直接覆盖 Spring Boot 自动配置的 ObjectMapper
|
||||||
|
@Bean
|
||||||
|
public ObjectMapper objectMapper() {
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**问题机制**:
|
||||||
|
1. 定义 `@Bean ObjectMapper` 会**替换** Spring Boot 自动配置的 `ObjectMapper`,丢失大量自动配置(模块注册、类型解析器、序列化注解处理等)
|
||||||
|
2. Spring Boot 4.x 的 `MappingJackson2HttpMessageConverter` 使用此 Bean 做响应序列化
|
||||||
|
3. 当 `DictAspect`(拦截所有 `@GetMapping`/`@PostMapping`)处理 `R<IPage<RegPatientMainInfoDto>>` 响应时,`IPage` 的泛型信息在新 `ObjectMapper` 下无法正确解析
|
||||||
|
4. Jackson 内部在序列化过程中尝试将 `ArrayList`(`IPage` 内部的 records 列表)强转为 `JsonNode`,导致 `ClassCastException`
|
||||||
|
|
||||||
|
**涉及文件**:
|
||||||
|
- `core-framework/.../ApplicationConfig.java` — **根因所在**,ObjectMapper Bean 配置不当
|
||||||
|
- `healthlink-his-common/.../DictAspect.java` — 拦截所有 Controller 方法,触发序列化链路
|
||||||
|
- `regdoctorstation/.../AdviceManageController.java` — `/reg-patient-zk` 端点
|
||||||
|
- `regdoctorstation/.../AdviceManageAppServiceImpl.java` — `getRegPatientMainInfo()` 返回 `IPage`
|
||||||
|
- `utils/request.js` — 前端拦截器,line 186 抛出 Promise reject
|
||||||
|
|
||||||
|
### 三、修复方案
|
||||||
|
|
||||||
|
**修改文件**:`core-framework/src/main/java/com/core/framework/config/ApplicationConfig.java`
|
||||||
|
|
||||||
|
**修复方式**:将 `@Bean ObjectMapper` 回退为 `Jackson2ObjectMapperBuilderCustomizer`,这样 Spring Boot 自动配置的 ObjectMapper 保持不变,只在其基础上追加自定义配置:
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Bean
|
||||||
|
public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() {
|
||||||
|
return builder -> {
|
||||||
|
builder.timeZone(TimeZone.getDefault());
|
||||||
|
builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
JavaTimeModule javaTimeModule = new JavaTimeModule();
|
||||||
|
javaTimeModule.addDeserializer(LocalDateTime.class, LOCAL_DATE_TIME_DESERIALIZER);
|
||||||
|
javaTimeModule.addSerializer(LocalDateTime.class,
|
||||||
|
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||||
|
builder.modules(javaTimeModule);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**验证步骤**:
|
||||||
|
1. `mvn clean compile -DskipTests` — 编译通过
|
||||||
|
2. 启动应用 → 以 doctor1 登录 → 进入住院医生工作站 → 确认无报错
|
||||||
|
3. 验证患者列表正常加载、诊断/医嘱 Tab 页正常切换
|
||||||
|
|
||||||
|
### 四、路由决策
|
||||||
|
|
||||||
|
- **修复 Agent**: guanyu(后端开发)
|
||||||
|
- **原因**: 修复点在 `ApplicationConfig.java` 的 ObjectMapper Bean 配置,属于后端 Spring 配置问题,需要回退 Jackson 序列化配置并验证编译通过。
|
||||||
26
MD/bugs/BUG_752_ANALYSIS.md
Normal file
26
MD/bugs/BUG_752_ANALYSIS.md
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# Bug #752 诸葛亮分析报告
|
||||||
|
|
||||||
|
> **文档类型**: Bug分析
|
||||||
|
> **分析时间**: 2026-06-12 22:09:00
|
||||||
|
> **分析模型**: mimo-v2.5 (LLM深度分析)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 基本信息
|
||||||
|
- **Bug #**: 752
|
||||||
|
- **标题**: 【门诊医生站-检查项目】保存检查申请单时报JSON解析错误
|
||||||
|
- **模块**: 门诊医生工作站
|
||||||
|
- **提出人**: 陈显精
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
分析完成。根因明确、修复方案清晰,建议直接分派给赵云执行修复。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 路由决策
|
||||||
|
- **FIXER_ID**: guanyu
|
||||||
|
- **修复 Agent**: guanyu(后端)
|
||||||
|
- **原因**: LLM 分析决策
|
||||||
|
|
||||||
|
> ⚠️ 修复人员请先验证以上分析是否正确,再执行修复。
|
||||||
174
MD/bugs/BUG_753_ANALYSIS.md
Normal file
174
MD/bugs/BUG_753_ANALYSIS.md
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
# Bug #753 诸葛亮分析报告
|
||||||
|
|
||||||
|
> **文档类型**: Bug分析
|
||||||
|
> **分析时间**: 2026-06-12 22:03:57
|
||||||
|
> **分析模型**: mimo-v2.5 (LLM深度分析)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 基本信息
|
||||||
|
- **Bug #**: 753
|
||||||
|
- **标题**: 【收费工作站-住院登记】“待登记入院”与“已登记入院”页签下页面容器高度异常,系统自动无限下扩产生大量空白区
|
||||||
|
- **模块**: 住院登记管理
|
||||||
|
- **提出人**: 陈显精
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、Bug 理解
|
||||||
|
|
||||||
|
**原文引用:**
|
||||||
|
|
||||||
|
> **标题**:【收费工作站-住院登记】"待登记入院"与"已登记入院"页签下页面容器高度异常,系统自动无限下扩产生大量空白区
|
||||||
|
>
|
||||||
|
> **重现步骤**:
|
||||||
|
> 1. 登录医院信息管理系统账号。
|
||||||
|
> 2. 在左侧主菜单栏中依次点击:「收费工作站」->「住院登记」。
|
||||||
|
> 3. 在右侧主工作区中,首先查看默认的「待登记入院」页签,往下滑动页面或观察底部数据区域。
|
||||||
|
> 4. 接着点击切换至「已登记入院」页签,同样向下滑动并观察底部。
|
||||||
|
>
|
||||||
|
> **结果**:表格与尾底部分页控件(写有"共 59 条 10条/页..."的控制条)之间存在异常巨大的空白间隔。页面右侧纵向滚动条极长,系统自动无限往下拉高窗口,给用户视觉呈瞬间呈现"断层/留白过长"现象。(注:在"待登记入院"和"已登记入院"两个子标签下均存在该问题。)
|
||||||
|
>
|
||||||
|
> **期望**:页面各组件高度计算正确,自适应浏览器窗口大小。分页控件行应紧跟紧随在表格区域底部显示,或者将表格区固定在一定高度内(超出出现局部滚动条),不能出现无限制的页面底部空白区和全局滚动条。
|
||||||
|
|
||||||
|
**附图分析**:
|
||||||
|
- 已登记入院页签:10行数据的表格下方出现大面积空白区域,分页控件被推到页面最底部,右侧纵向滚动条极长。
|
||||||
|
- 待登记入院页签:表格显示"暂无数据",但页面同样存在高度异常。
|
||||||
|
- 两个标签页下均有"系统自动无限往下扩高窗口"的标注。
|
||||||
|
|
||||||
|
**综合总结**:用户在住院登记页面的两个页签(待登记/已登记)中,表格下方出现大面积异常空白,分页控件与表格严重脱节,页面滚动条极长。这是一个纯前端布局问题,由 CSS 高度约束缺失导致 vxe-table 在无约束父容器中无限撑开高度。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、根因分析
|
||||||
|
|
||||||
|
**直接原因**:两个组件(`accomplishList.vue` 和 `awaitList.vue`)的 `.table-container` 缺少高度约束和溢出控制。
|
||||||
|
|
||||||
|
**详细技术分析**:
|
||||||
|
|
||||||
|
布局链条高度约束断裂:
|
||||||
|
|
||||||
|
```
|
||||||
|
.app-container (min-height: calc(100vh - 84px), 无固定height, 无overflow)
|
||||||
|
└─ el-tabs (auto height)
|
||||||
|
└─ .awaitList-container (height: 100%, 但父元素无固定高度 → 实际等于 auto)
|
||||||
|
├─ .operate (height: 40px, 固定)
|
||||||
|
└─ .table-container (无高度约束, 仅 padding)
|
||||||
|
├─ vxe-table (height="100%", 父容器auto → 无法正确约束)
|
||||||
|
└─ pagination
|
||||||
|
```
|
||||||
|
|
||||||
|
关键问题:
|
||||||
|
1. **`.awaitList-container` 使用 `height: 100%`,但其父元素(el-tabs content)无固定高度**——导致 `100%` 实际解析为 auto,无法约束子元素。
|
||||||
|
2. **`.table-container` 无 `overflow` 约束、无 flex 布局**——内容可以无限撑高。
|
||||||
|
3. **`vxe-table` 的 `height="100%"` 属性**——在无固定高度的父容器中无法创建滚动区域,表格内容直接撑开容器。
|
||||||
|
|
||||||
|
**涉及文件**(均为纯前端 CSS 问题):
|
||||||
|
- `healthlink-his-ui/src/views/inHospitalManagement/charge/register/components/accomplishList.vue` — 已登记入院列表
|
||||||
|
- `healthlink-his-ui/src/views/inHospitalManagement/charge/register/components/awaitList.vue` — 待登记入院列表
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、修复方案
|
||||||
|
|
||||||
|
**核心思路**:用 flexbox 将 `.awaitList-container` 改为纵向弹性布局,让 `.table-container` 自动填充剩余空间并限制溢出,使 vxe-table 的 `height="100%"` 能正确约束在固定高度内。
|
||||||
|
|
||||||
|
### 修改文件 1:`accomplishList.vue`
|
||||||
|
|
||||||
|
```scss
|
||||||
|
<!-- 修改前 -->
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.awaitList-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
.operate {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 40px;
|
||||||
|
padding: 0 16px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.table-container {
|
||||||
|
padding: 8px 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- 修改后 -->
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.awaitList-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
.operate {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 40px;
|
||||||
|
padding: 0 16px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.table-container {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 8px 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 修改文件 2:`awaitList.vue`
|
||||||
|
|
||||||
|
同样的 CSS 修改(两个文件的 style 完全一致):
|
||||||
|
|
||||||
|
```scss
|
||||||
|
<!-- 修改后 -->
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.awaitList-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
.operate {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 40px;
|
||||||
|
padding: 0 16px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.table-container {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 8px 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
```
|
||||||
|
|
||||||
|
**修改要点**(3处 CSS 变更,两文件相同):
|
||||||
|
1. `.awaitList-container` 加 `display: flex; flex-direction: column;` — 建立纵向弹性布局
|
||||||
|
2. `.operate` 加 `flex-shrink: 0;` — 防止搜索栏被压缩
|
||||||
|
3. `.table-container` 加 `flex: 1; min-height: 0; overflow: hidden;` — **关键修复**:自动填充剩余空间 + 禁止溢出撑高 + `min-height: 0` 确保 flex 子元素可缩小
|
||||||
|
|
||||||
|
这样 vxe-table 的 `height="100%"` 就能在固定的 `.table-container` 内正确创建滚动区域,表格内容超出时在表格内部滚动,分页控件紧随表格下方,不再撑开整个页面。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、路由决策
|
||||||
|
|
||||||
|
**FIXER**: zhaoyun
|
||||||
|
**REASON**: 这是纯前端 CSS 布局问题,只涉及两个 Vue 组件的 `<style>` 块修改,无后端变更、无数据库变更,由前端开发修复最合适。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 路由决策
|
||||||
|
- **FIXER_ID**: guanyu
|
||||||
|
- **修复 Agent**: guanyu(后端)
|
||||||
|
- **原因**: LLM 分析决策
|
||||||
|
|
||||||
|
> ⚠️ 修复人员请先验证以上分析是否正确,再执行修复。
|
||||||
164
MD/bugs/BUG_757_ANALYSIS.md
Normal file
164
MD/bugs/BUG_757_ANALYSIS.md
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
# Bug #757 诸葛亮分析报告
|
||||||
|
|
||||||
|
> **文档类型**: Bug分析
|
||||||
|
> **分析时间**: 2026-06-12 14:58:17
|
||||||
|
> **分析模型**: mimo-v2.5 (LLM深度分析)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 基本信息
|
||||||
|
- **Bug #**: 757
|
||||||
|
- **标题**: 【门诊医生工作站】中医诊断中没有相同的诊断和症候,但就无法新增中医诊断
|
||||||
|
- **模块**: 门诊医生工作站
|
||||||
|
- **提出人**: 王栩坤
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
I have enough information now to produce the analysis. Let me compile the findings.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、Bug 理解
|
||||||
|
|
||||||
|
用户在门诊医生站打开"中医诊断"对话框,选择中医诊断和中医证候后点击确定,**无法成功保存**。同时,已经保存过的中医诊断也无法正确回显诊断详情。期望:能正常选择诊断和证候、保存成功,并回显诊断详情数据。
|
||||||
|
|
||||||
|
## 二、根因分析
|
||||||
|
|
||||||
|
核心问题在 `tcmdiagnosisDialog.vue` 的 `submit()` 函数,它向后端发送的字段名与后端 DTO 完全不匹配:
|
||||||
|
|
||||||
|
**前端发送的数据结构:**
|
||||||
|
```js
|
||||||
|
const diagnosisChildList = [{
|
||||||
|
conditionCode: condition.value, // ← 字段名错误
|
||||||
|
syndromeCode: syndrome.value, // ← 字段名错误
|
||||||
|
}];
|
||||||
|
```
|
||||||
|
|
||||||
|
**后端 `SaveDiagnosisChildParam` 期望的数据结构:**
|
||||||
|
- `definitionId` (Long) — 诊断定义 ID
|
||||||
|
- `ybNo` (String) — 医保编码
|
||||||
|
- `syndromeGroupNo` (String) — 中医证候组号(用于关联病和证)
|
||||||
|
- `maindiseFlag` (Integer) — 主诊断标记
|
||||||
|
- `diagSrtNo` (Integer) — 排序号
|
||||||
|
|
||||||
|
**具体根因列表:**
|
||||||
|
|
||||||
|
| # | 问题 | 位置 | 影响 |
|
||||||
|
|---|------|------|------|
|
||||||
|
| 1 | `submit()` 发送 `conditionCode`/`syndromeCode`,后端接收不到 `definitionId` 和 `ybNo` | `tcmdiagnosisDialog.vue:submit()` | 保存时 Condition 记录的 `definitionId` 为 null,保存失败或数据损坏 |
|
||||||
|
| 2 | 没有传 `syndromeGroupNo` 来关联"病"和"证" | `tcmdiagnosisDialog.vue:submit()` | 后端无法将诊断和证候配对成一组 |
|
||||||
|
| 3 | `openDialog()` 获取下拉选项时用 `item.ybNo` 作为 value,但没有保存 `definitionId` | `tcmdiagnosisDialog.vue:openDialog()` | 丢失了关键的 `definitionId` |
|
||||||
|
| 4 | 没有传 `patientInfo` prop(dialog 用 `defineProps` 声明了但父组件可能未传) | `tcmdiagnosisDialog.vue` | `saveTcmDiagnosis` 请求中 `patientId`/`encounterId` 为 null |
|
||||||
|
|
||||||
|
**可能涉及的文件:**
|
||||||
|
- `healthlink-his-ui/src/views/doctorstation/components/tcm/tcmdiagnosisDialog.vue` — 主要 Bug 所在
|
||||||
|
- `healthlink-his-ui/src/views/doctorstation/components/api.js` — API 定义(无误)
|
||||||
|
- `healthlink-his-server/.../appservice/impl/DoctorStationChineseMedicalAppServiceImpl.java` — 后端 `saveTcmDiagnosis` 方法
|
||||||
|
|
||||||
|
## 三、修复方案
|
||||||
|
|
||||||
|
### 修复 1:`tcmdiagnosisDialog.vue` — `openDialog()` 方法
|
||||||
|
|
||||||
|
将下拉选项的 value 从 `ybNo` 改为同时保存 `definitionId`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// 修改前
|
||||||
|
conditionOptions.value = res.data.records.map((item) => ({
|
||||||
|
value: item.ybNo,
|
||||||
|
label: item.name,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 修改后
|
||||||
|
conditionOptions.value = res.data.records.map((item) => ({
|
||||||
|
value: item.id, // 用 definition ID 作为 value
|
||||||
|
ybNo: item.ybNo, // 保留医保编码
|
||||||
|
label: item.name,
|
||||||
|
}));
|
||||||
|
syndromeOptions.value = res.data.records.map((item) => ({
|
||||||
|
value: item.id,
|
||||||
|
ybNo: item.ybNo,
|
||||||
|
label: item.name,
|
||||||
|
}));
|
||||||
|
```
|
||||||
|
|
||||||
|
### 修复 2:`tcmdiagnosisDialog.vue` — `submit()` 方法
|
||||||
|
|
||||||
|
重写提交逻辑,匹配后端 `SaveDiagnosisChildParam` 的字段名:
|
||||||
|
|
||||||
|
```js
|
||||||
|
function submit() {
|
||||||
|
if (!condition.value || !syndrome.value) {
|
||||||
|
proxy.$modal.msgWarning('请选择诊断和证候');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 找到选中的诊断和证候的完整信息
|
||||||
|
const selectedCondition = conditionOptions.value.find(item => item.value === condition.value);
|
||||||
|
const selectedSyndrome = syndromeOptions.value.find(item => item.value === syndrome.value);
|
||||||
|
|
||||||
|
// 生成证候组号(时间戳)
|
||||||
|
const syndromeGroupNo = 'TCM' + Date.now();
|
||||||
|
|
||||||
|
const diagnosisChildList = [
|
||||||
|
{
|
||||||
|
definitionId: condition.value, // 中医诊断 definition ID
|
||||||
|
ybNo: selectedCondition?.ybNo, // 中医诊断医保编码
|
||||||
|
syndromeGroupNo: syndromeGroupNo,
|
||||||
|
maindiseFlag: 1, // 主诊断标记
|
||||||
|
diagSrtNo: 1, // 排序号(病)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
definitionId: syndrome.value, // 中医证候 definition ID
|
||||||
|
ybNo: selectedSyndrome?.ybNo, // 中医证候医保编码
|
||||||
|
syndromeGroupNo: syndromeGroupNo, // 同一组号
|
||||||
|
maindiseFlag: 0,
|
||||||
|
diagSrtNo: 2, // 排序号(证)
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
saveTcmDiagnosis({
|
||||||
|
patientId: props.patientInfo.patientId,
|
||||||
|
encounterId: props.patientInfo.encounterId,
|
||||||
|
diagnosisChildList: diagnosisChildList,
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
proxy.$modal.msgSuccess('保存成功');
|
||||||
|
emit('flush');
|
||||||
|
close();
|
||||||
|
} else {
|
||||||
|
proxy.$modal.msgError(res.msg || '保存失败');
|
||||||
|
}
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error('保存中医诊断失败:', error);
|
||||||
|
proxy.$modal.msgError('保存失败,请重试');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 修复 3:确保父组件传递 `patientInfo` prop
|
||||||
|
|
||||||
|
检查父组件(`tcmAdvice.vue` 或使用 `tcmdiagnosisDialog` 的页面)是否正确传递了 `patientInfo` prop。`tcmAdvice.vue` 已有 `patientInfo` prop 定义,所以如果是从 `tcmAdvice` 中使用该 dialog,需要通过 `:patientInfo="patientInfo"` 传递。
|
||||||
|
|
||||||
|
### 修复 4(可选):后端防御性处理
|
||||||
|
|
||||||
|
后端 `saveTcmDiagnosis` 方法可以增加对 `definitionId` 为空的校验,避免写入脏数据:
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 在 saveTcmDiagnosis 方法开头增加
|
||||||
|
for (SaveDiagnosisChildParam param : diagnosisChildList) {
|
||||||
|
if (param.getDefinitionId() == null) {
|
||||||
|
return R.fail("诊断定义ID不能为空,请重新选择诊断");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 四、路由决策
|
||||||
|
|
||||||
|
**FIXER: zhaoyun**(前端开发)
|
||||||
|
**REASON:** Bug 根因在前端对话框组件 `tcmdiagnosisDialog.vue` 的字段映射错误和提交逻辑缺陷,需要修改 Vue 前端代码(openDialog 数据映射 + submit 参数构建 + 父组件 prop 传递),属于前端界面和 API 调用层修复。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 路由决策
|
||||||
|
- **修复 Agent**: zhaoyun
|
||||||
|
- **原因**: ** Bug 根因在前端对话框组件 `tcmdiagnosisDialog.vue` 的字段映射错误和提交逻辑缺陷,需要修改 Vue 前端代码(openDialog 数据映射 + submit 参数构建 + 父组件 prop 传递),属于前端界面和 API 调用层修复。
|
||||||
122
MD/bugs/BUG_758_ANALYSIS.md
Normal file
122
MD/bugs/BUG_758_ANALYSIS.md
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
# Bug #758 诸葛亮分析报告
|
||||||
|
|
||||||
|
> **文档类型**: Bug分析
|
||||||
|
> **分析时间**: 2026-06-12 15:34:50
|
||||||
|
> **分析模型**: mimo-v2.5 (LLM深度分析)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 基本信息
|
||||||
|
- **Bug #**: 758
|
||||||
|
- **标题**: 【门诊医生工作站-检验】检验信息下的新增的字段按钮点击会出现报错Cannot deserialize value of type `com.core.common.core.domain.entity.SysDictData` from Array value
|
||||||
|
- **模块**: 门诊医生工作站
|
||||||
|
- **提出人**: 王栩坤
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
I now have a complete understanding of the root cause. Let me provide the analysis.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 一、Bug 理解
|
||||||
|
|
||||||
|
用户在门诊医生工作站的"检验信息"区域点击"新增"按钮时,页面弹出 Jackson 反序列化错误 `Cannot deserialize value of type SysDictData from Array value`,无法正常新增检验信息。期望点击新增后能正常清空表单、准备录入新检验申请单。
|
||||||
|
|
||||||
|
### 二、根因分析
|
||||||
|
|
||||||
|
**错误触发链路:**
|
||||||
|
|
||||||
|
```
|
||||||
|
用户点击"新增"
|
||||||
|
→ handleNewApplication()
|
||||||
|
→ resetForm()
|
||||||
|
→ getEncounterDiagnosis(encounterId) [API 调用]
|
||||||
|
→ 后端返回 R<List<DiagnosisQueryDto>>
|
||||||
|
→ DictAspect 拦截 @GetMapping 响应
|
||||||
|
→ processDict() 发现 DiagnosisQueryDto.medTypeCode 有 @Dict(dictCode = "med_type")
|
||||||
|
→ DictUtils.getDictLabel("med_type", value)
|
||||||
|
→ DictUtils.getDictCache("med_type")
|
||||||
|
→ mapper.convertValue(cached, TypeReference<List<SysDictData>>) ← 💥 这里抛异常
|
||||||
|
→ DictAspect 无 try-catch,异常直接传播到前端
|
||||||
|
```
|
||||||
|
|
||||||
|
**根因:`DictUtils.getDictCache()` 缺少异常处理**
|
||||||
|
|
||||||
|
- 文件:`core-common/src/main/java/com/core/common/utils/DictUtils.java:38-62`
|
||||||
|
- Redis 中的字典缓存数据结构异常(可能是旧 Fastjson 序列化格式遗留、嵌套数组等)
|
||||||
|
- Jackson `ObjectMapper.convertValue()` 无法将异常结构转为 `List<SysDictData>`,抛出 `JsonMappingException`
|
||||||
|
- 该异常未被 `DictUtils` 或 `DictAspect` 捕获,直接传播为 HTTP 500 错误
|
||||||
|
|
||||||
|
**涉及的关键文件:**
|
||||||
|
1. `core-common/src/main/java/com/core/common/utils/DictUtils.java` — `getDictCache()` 方法(核心问题)
|
||||||
|
2. `healthlink-his-common/src/main/java/com/healthlink/his/common/aspectj/DictAspect.java` — `processDict()` 方法(缺少异常保护)
|
||||||
|
3. `healthlink-his-application/src/main/java/com/healthlink/his/web/doctorstation/controller/DoctorStationDiagnosisController.java` — 被 DictAspect 拦截的控制器
|
||||||
|
4. `healthlink-his-application/src/main/java/com/healthlink/his/web/doctorstation/dto/DiagnosisQueryDto.java` — 含 `@Dict` 注解的 DTO
|
||||||
|
|
||||||
|
**与历史 Bug 的关联:** 此前 commit `babd8d0c0` 修复了类似问题(Jackson 配置从 ObjectMapper bean 改回 Jackson2ObjectMapperBuilderCustomizer),但 `DictUtils.getDictCache()` 的 `convertValue` 仍缺少防御性异常处理。
|
||||||
|
|
||||||
|
### 三、修复方案
|
||||||
|
|
||||||
|
**修改 1:`DictUtils.getDictCache()` 添加 try-catch 防御**(核心修复)
|
||||||
|
|
||||||
|
文件:`core-common/src/main/java/com/core/common/utils/DictUtils.java`
|
||||||
|
|
||||||
|
在 `getDictCache()` 方法中,为 `mapper.convertValue()` 添加 try-catch,失败时清理损坏缓存并返回 null:
|
||||||
|
|
||||||
|
```java
|
||||||
|
public static List<SysDictData> getDictCache(String key) {
|
||||||
|
Object cached = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
|
||||||
|
if (StringUtils.isNull(cached)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (cached instanceof List && ((List<?>) cached).stream().allMatch(e -> e instanceof SysDictData)) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<SysDictData> result = (List<SysDictData>) cached;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
com.fasterxml.jackson.core.type.TypeReference<List<SysDictData>> typeRef =
|
||||||
|
new com.fasterxml.jackson.core.type.TypeReference<List<SysDictData>>() {};
|
||||||
|
ObjectMapper mapper = new ObjectMapper()
|
||||||
|
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
if (cached instanceof JsonNode jsonNode) {
|
||||||
|
return mapper.convertValue(jsonNode, typeRef);
|
||||||
|
}
|
||||||
|
return mapper.convertValue(cached, typeRef);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 缓存数据格式异常,清理损坏缓存,下次重新加载
|
||||||
|
org.slf4j.LoggerFactory.getLogger(DictUtils.class)
|
||||||
|
.warn("字典缓存转换失败(key={}),已清理: {}", key, e.getMessage());
|
||||||
|
removeDictCache(key);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**修改 2:`DictAspect.processDict()` 添加 try-catch 防御**(防止字典翻译失败影响 API 响应)
|
||||||
|
|
||||||
|
文件:`healthlink-his-common/src/main/java/com/healthlink/his/common/aspectj/DictAspect.java`
|
||||||
|
|
||||||
|
在 `processDict()` 方法中,对字典查询部分包裹 try-catch:
|
||||||
|
|
||||||
|
```java
|
||||||
|
} else if (field.isAnnotationPresent(Dict.class)) {
|
||||||
|
try {
|
||||||
|
// ... 原有字典翻译逻辑 ...
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug("字段 {} 字典翻译失败,跳过: {}", field.getName(), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 四、路由决策
|
||||||
|
|
||||||
|
**FIXER: guanyu(后端开发)**
|
||||||
|
|
||||||
|
**REASON:** 修复涉及 `DictUtils`(core-common 模块)和 `DictAspect`(healthlink-his-common 模块)两个后端 Java 文件的异常处理逻辑,纯后端修复,无需前端改动。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 路由决策
|
||||||
|
- **修复 Agent**: guanyu
|
||||||
|
- **原因**: ** 修复涉及 `DictUtils`(core-common 模块)和 `DictAspect`(healthlink-his-common 模块)两个后端 Java 文件的异常处理逻辑,纯后端修复,无需前端改动。
|
||||||
104
MD/bugs/BUG_759_ANALYSIS.md
Normal file
104
MD/bugs/BUG_759_ANALYSIS.md
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
# Bug #759 诸葛亮分析报告
|
||||||
|
|
||||||
|
> **文档类型**: Bug分析
|
||||||
|
> **分析时间**: 2026-06-12 21:51:43
|
||||||
|
> **分析模型**: mimo-v2.5 (LLM深度分析)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 基本信息
|
||||||
|
- **Bug #**: 759
|
||||||
|
- **标题**: 【门诊医生工作站】电子处方点击新增处方,报卡在100%卡出屏幕且诊断等下拉框无数据回显
|
||||||
|
- **模块**: 门诊医生工作站
|
||||||
|
- **提出人**: 王栩坤
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
I now have a complete understanding. Here is my analysis:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、Bug 理解
|
||||||
|
|
||||||
|
**禅道 Bug #759 原文:**
|
||||||
|
|
||||||
|
- **标题**:【门诊医生工作站】电子处方点击新增处方,报卡在100%卡出屏幕且诊断等下拉框无数据回显
|
||||||
|
- **重现步骤**:登录内科医生1账号(doctor1/123456)→ 进入门诊医生工作站 → 选择一名患者 → 点击处方 → 点击新增处方
|
||||||
|
- **实际结果**:报卡界面边距超出,下拉框无数据回显
|
||||||
|
- **期望结果**:能够在100%视图下,新增处方的报卡能够完全展示出来;诊断和慢性诊断的下拉框有数据回显
|
||||||
|
|
||||||
|
**附图关键信息**:
|
||||||
|
- 截图显示"新增处方"弹窗右侧被截断,"服药时间(结束)"和"途径"列不可见,右下角"删除"按钮被裁剪
|
||||||
|
- "诊断"下拉框显示占位文本"诊断","慢病诊断"下拉框点击后显示"无数据"
|
||||||
|
|
||||||
|
**综合总结**:用户在门诊医生工作站新增处方时,弹窗宽度固定为 `1840px`,在 100% 缩放下超出屏幕可视区域导致内容溢出;同时"诊断"和"慢病诊断"两个下拉框均无数据可选,无法正常使用处方开具功能。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、根因分析
|
||||||
|
|
||||||
|
**涉及唯一文件**:`healthlink-his-ui/src/views/doctorstation/components/eprescriptiondialog.vue`
|
||||||
|
|
||||||
|
### 问题1:弹窗宽度溢出
|
||||||
|
|
||||||
|
- **根因**:`el-dialog` 第5行设置 `width="1840px"` 为固定像素值。标准 1920px 屏幕减去浏览器 UI 和滚动条后可用宽度不足 1840px,导致右侧内容被截断。此外第240行药品搜索弹出框 `popover` 设置 `width="1200"`,也加剧了溢出。
|
||||||
|
- **证据**:第5行 `width="1840px"`,第240行 `:width="1200"`
|
||||||
|
|
||||||
|
### 问题2:诊断下拉框无数据
|
||||||
|
|
||||||
|
- **根因**:"诊断"下拉框使用 `remote-method="getInit"`(第134行),这是一个远程搜索模式 —— **只有用户输入关键字时才会触发 `getInit` 函数调用 API**。弹窗打开时 `open()` 函数调用了 `getDiagnosisInfo()`,其中 `getEncounterDiagnosis()` 获取的诊断数据存入了 `diagnosisList`(第764行),但 **没有同步填充 `diagnosisListOption`**(下拉框 v-for 绑定的数据源,第138行)。因此弹窗打开时下拉框列表为空。
|
||||||
|
- **代码证据**:`getDiagnosisInfo()` 第764行 `diagnosisList.value = res.data`,但 `diagnosisListOption` 仅在 `getInit` 的 remote 回调中被赋值(第716行)
|
||||||
|
|
||||||
|
### 问题3:慢病诊断下拉框无数据
|
||||||
|
|
||||||
|
- **根因**:`getChronicDisease` 调用医保接口 `/yb-request/getConditionDefinition`(第779行)。如果医保服务未连接或返回空数据,catch 中静默处理并设为空数组(第786行)。这可能是医保环境未配置的预期行为,但即使医保已连接,如果 `encounterId` 传参有问题也会导致返回空。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、修复方案
|
||||||
|
|
||||||
|
### 修复1:弹窗宽度改为响应式
|
||||||
|
|
||||||
|
**文件**:`eprescriptiondialog.vue` 第5行
|
||||||
|
|
||||||
|
```diff
|
||||||
|
- width="1840px"
|
||||||
|
+ width="90vw"
|
||||||
|
+ style="max-width: 1840px"
|
||||||
|
```
|
||||||
|
|
||||||
|
同时将第240行药品搜索 popover 宽度从 `1200` 缩减为 `min(1200px, 80vw)` 或直接改为 `"100%"`。
|
||||||
|
|
||||||
|
### 修复2:诊断下拉框打开时加载初始数据
|
||||||
|
|
||||||
|
**文件**:`eprescriptiondialog.vue` `getDiagnosisInfo()` 函数(约第763行)
|
||||||
|
|
||||||
|
在 `getEncounterDiagnosis` 成功回调中,增加 `diagnosisListOption` 的赋值:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
getEncounterDiagnosis(props.patient.encounterId).then((res) => {
|
||||||
|
diagnosisList.value = res.data;
|
||||||
|
+ diagnosisListOption.value = res.data || [];
|
||||||
|
let diagnosisInfo = diagnosisList.value.filter((item) => {
|
||||||
|
```
|
||||||
|
|
||||||
|
### 修复3:慢病诊断 — 确认 API 返回
|
||||||
|
|
||||||
|
此问题取决于医保服务是否可用。如果医保服务已连接但仍无数据,需检查后端 `/yb-request/getConditionDefinition` 接口的返回值。如果是医保未配置环境,则属于已知限制,可考虑在下拉框上增加"医保未连接"的提示文案。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、路由决策
|
||||||
|
|
||||||
|
**FIXER: zhaoyun(赵云 — 前端开发)**
|
||||||
|
|
||||||
|
**REASON**:两个问题的根因全部在前端 `eprescriptiondialog.vue` 的样式和数据初始化逻辑中,不需要后端改动,属于纯前端修复任务。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 路由决策
|
||||||
|
- **FIXER_ID**: zhaoyun
|
||||||
|
- **修复 Agent**: zhaoyun(前端)
|
||||||
|
- **原因**: LLM 分析决策
|
||||||
|
|
||||||
|
> ⚠️ 修复人员请先验证以上分析是否正确,再执行修复。
|
||||||
114
MD/bugs/BUG_760_ANALYSIS.md
Normal file
114
MD/bugs/BUG_760_ANALYSIS.md
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
# Bug #760 诸葛亮分析报告
|
||||||
|
|
||||||
|
> **文档类型**: Bug分析
|
||||||
|
> **分析时间**: 2026-06-12 21:48:44
|
||||||
|
> **分析模型**: mimo-v2.5 (LLM深度分析)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 基本信息
|
||||||
|
- **Bug #**: 760
|
||||||
|
- **标题**: [住院护士站-护理记录] 选中患者时系统报错
|
||||||
|
- **模块**: 病区护士工作站
|
||||||
|
- **提出人**: 陈显精
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Analysis complete. Here's the full report.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 一、Bug 理解
|
||||||
|
|
||||||
|
**禅道 Bug #760:[住院护士站-护理记录] 选中患者时系统报错**
|
||||||
|
|
||||||
|
**重现步骤:**
|
||||||
|
1. 登录账号:wx,密码:123456,登录系统,进入【住院护士站】
|
||||||
|
2. 点击【护理记录】页签
|
||||||
|
3. 在左侧列表中选中任意已入院的患者
|
||||||
|
|
||||||
|
**期望结果:**
|
||||||
|
1. 选中患者后,系统正常响应,无报错弹窗
|
||||||
|
2. 成功加载并展示该患者对应的护理记录表单及历史数据
|
||||||
|
|
||||||
|
**实际结果:**
|
||||||
|
- 页面弹出红色报错:`No static resource nursing/statistics/summary/list for request '/healthlink-his/nursing/statistics/summary/list'`
|
||||||
|
- 右侧护理记录列表显示"暂无数据"
|
||||||
|
|
||||||
|
**截图确认:** 顶部红色报错横幅清晰可见,错误 URL 为 `/healthlink-his/nursing/statistics/summary/list`,选中患者"陈显精"后右侧表格为空。
|
||||||
|
|
||||||
|
**总结:** 用户在住院护士站的「护理记录」页签选中患者时,前端发起了一个后端不存在的 API 请求 `/nursing/statistics/summary/list`,导致 404 报错,护理记录数据无法加载。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 二、根因分析
|
||||||
|
|
||||||
|
**根因:Tab 组件映射错误 — "护理记录"页签加载了错误的组件。**
|
||||||
|
|
||||||
|
在 `healthlink-his-ui/src/views/inpatientNurse/inpatientNurseStation/index.vue` 中:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- 第72-76行 -->
|
||||||
|
<el-tab-pane label="护理记录" name="NursingRecord">
|
||||||
|
<Criticalrecord v-if="activeTabName === 'NursingRecord'" />
|
||||||
|
</el-tab-pane>
|
||||||
|
```
|
||||||
|
|
||||||
|
这里渲染的是 `Criticalrecord` 组件,而不是 `NursingRecord` 组件。
|
||||||
|
|
||||||
|
**关键文件对比:**
|
||||||
|
|
||||||
|
| 文件 | API 路径 | 后端是否有对应 Controller |
|
||||||
|
|------|----------|--------------------------|
|
||||||
|
| `nursingstatistics/criticalrecord.vue` → `nursingstatistics/api.js` | `/nursing/statistics/summary/list` | ❌ **不存在** |
|
||||||
|
| `nursingRecord/index.vue` → `nursingRecord/components/api.js` | `/nursing-record/nursing-patient-page` 等 | ✅ `NursingRecordController` |
|
||||||
|
|
||||||
|
- `inpatientNurseStation/index.js` 中已经同时导入了两个组件:
|
||||||
|
- `NursingRecord` from `@/views/inpatientNurse/nursingRecord/index.vue`
|
||||||
|
- `Criticalrecord` from `@/views/inpatientNurse/nursingstatistics/criticalrecord.vue`
|
||||||
|
- 但 `index.vue` 的模板中**用错了组件名**:`<Criticalrecord>` 应该是 `<NursingRecord>`
|
||||||
|
- 后端 `NursingRecordController` 映射在 `/nursing-record`,有完整的 patient-page、nursing-patient-page、save-nursing、delete-nursing 等端点
|
||||||
|
|
||||||
|
**涉及的文件:**
|
||||||
|
- `healthlink-his-ui/src/views/inpatientNurse/inpatientNurseStation/index.vue` — 模板中 Tab 渲染了错误组件
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 三、修复方案
|
||||||
|
|
||||||
|
**修改 1 个文件,1 处改动:**
|
||||||
|
|
||||||
|
**文件:** `healthlink-his-ui/src/views/inpatientNurse/inpatientNurseStation/index.vue`
|
||||||
|
|
||||||
|
**改动:** 将第 74 行的 `<Criticalrecord>` 替换为 `<NursingRecord>`
|
||||||
|
|
||||||
|
```diff
|
||||||
|
- <el-tab-pane label="护理记录" name="NursingRecord">
|
||||||
|
- <Criticalrecord v-if="activeTabName === 'NursingRecord'" />
|
||||||
|
+ <el-tab-pane label="护理记录" name="NursingRecord">
|
||||||
|
+ <NursingRecord v-if="activeTabName === 'NursingRecord'" />
|
||||||
|
</el-tab-pane>
|
||||||
|
```
|
||||||
|
|
||||||
|
`NursingRecord` 已在同文件的 `index.js` 中导入(第3行),无需额外添加 import。
|
||||||
|
|
||||||
|
**验证:**
|
||||||
|
1. `cd healthlink-his-ui && npm run build:dev` — 编译通过
|
||||||
|
2. 登录后进入住院护士站 → 护理记录 → 选中患者 → 应加载出患者护理记录列表,无红色报错
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 四、路由决策
|
||||||
|
|
||||||
|
**FIXER: zhaoyun**
|
||||||
|
|
||||||
|
**REASON:** 纯前端组件映射修复,仅改动 1 个 Vue 文件中的 1 行模板标签(`Criticalrecord` → `NursingRecord`),属于前端界面/组件层级的问题。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 路由决策
|
||||||
|
- **FIXER_ID**: zhaoyun
|
||||||
|
- **修复 Agent**: zhaoyun(前端)
|
||||||
|
- **原因**: ** 纯前端组件映射修复,仅改动 1 个 Vue 文件中的 1 行模板标签(`Criticalrecord` → `NursingRecord`),属于前端界面/组件层级的问题。
|
||||||
|
|
||||||
|
> ⚠️ 修复人员请先验证以上分析是否正确,再执行修复。
|
||||||
132
MD/bugs/BUG_761_ANALYSIS.md
Normal file
132
MD/bugs/BUG_761_ANALYSIS.md
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
# Bug #761 诸葛亮分析报告
|
||||||
|
|
||||||
|
> **文档类型**: Bug分析
|
||||||
|
> **分析时间**: 2026-06-12 16:31:36
|
||||||
|
> **分析模型**: mimo-v2.5 (LLM深度分析)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 基本信息
|
||||||
|
- **Bug #**: 761
|
||||||
|
- **标题**: [住院护士站-汇总领药]领药明细列表,“领药时间”显示逻辑异常且早于医嘱开立时间
|
||||||
|
- **模块**: 病区护士工作站
|
||||||
|
- **提出人**: 陈显精
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
I now have a complete understanding of the bug. Let me produce the analysis.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 一、Bug 理解
|
||||||
|
|
||||||
|
用户在"住院护士站 → 汇总领药"页面看到"领药时间"列显示了错误的日期("06-09"),早于医嘱开立时间(06-10 05:18:44)和实际执行时间(06-10 05:18)。期望:①列名改为"执行时间";②时间值应与医嘱执行界面的执行时间一致;③未发药/未汇总前不应展示"领药时间"。
|
||||||
|
|
||||||
|
### 二、根因分析
|
||||||
|
|
||||||
|
**全链路追踪:**
|
||||||
|
|
||||||
|
```
|
||||||
|
前端 prescriptionList.vue → API: getPrescriptionList
|
||||||
|
→ 后端 MedicineSummaryController.getMedicineDispenseFormPage
|
||||||
|
→ MedicineSummaryAppServiceImpl.getMedicineDispenseFormPage
|
||||||
|
→ MedicineSummaryAppMapper.selectMedicineDispenseFormPage (SQL)
|
||||||
|
→ 返回 MedicineDispenseFormDto.medicineSummaryParamList
|
||||||
|
→ 其中 dispenseTime 来自 med_medication_dispense.planned_dispense_time
|
||||||
|
```
|
||||||
|
|
||||||
|
**核心问题(2处):**
|
||||||
|
|
||||||
|
**问题1:数据源错误 — `planned_dispense_time` ≠ 执行时间**
|
||||||
|
|
||||||
|
- Mapper XML 第39行:`<result property="dispenseTime" column="planned_dispense_time"/>`,将 `med_medication_dispense.planned_dispense_time` 映射为 `dispenseTime`
|
||||||
|
- `planned_dispense_time` 是在 `AdviceProcessAppServiceImpl` 调用 `generateMedicationDispense()` 时通过 `parseExecuteTime(executeTime)` 设置的,来自前端传入的执行时间字符串
|
||||||
|
- 实际执行时间存储在 `cli_procedure.occurrence_time`(`Procedure.java` 第54行),这才是医嘱执行界面显示的"执行时间"
|
||||||
|
- `planned_dispense_time` 的值可能因时区转换、字符串解析精度等原因与 `occurrence_time` 不一致(差一天即 "06-09" vs "06-10")
|
||||||
|
|
||||||
|
**问题2:列名语义错误 — "领药时间"应为"执行时间"**
|
||||||
|
|
||||||
|
- `prescriptionList.vue` 第164行:`title="领药时间"`,此列展示的是每条医嘱的执行时间点,不是"领药时间"
|
||||||
|
- 在未生成汇总领药单之前,不存在"领药"动作,显示"领药时间"不符合业务逻辑
|
||||||
|
|
||||||
|
**涉及文件:**
|
||||||
|
|
||||||
|
| 文件 | 行号 | 问题 |
|
||||||
|
|------|------|------|
|
||||||
|
| `prescriptionList.vue` | 164 | 列名 "领药时间" 应改为 "执行时间" |
|
||||||
|
| `MedicineSummaryAppMapper.xml` | 39, 78, ~125, 203 | `planned_dispense_time` 应改为 `cli_procedure.occurrence_time` |
|
||||||
|
| `MedicineSummaryParam.java` | 22 | 字段名 `dispenseTime` 可保持不变(仅改数据源) |
|
||||||
|
|
||||||
|
### 三、修复方案
|
||||||
|
|
||||||
|
#### 修改1:后端 Mapper XML — 改用执行时间
|
||||||
|
|
||||||
|
**文件**: `healthlink-his-server/healthlink-his-application/src/main/resources/mapper/inhospitalnursestation/MedicineSummaryAppMapper.xml`
|
||||||
|
|
||||||
|
**改动A**:resultMap collection 映射,将 `dispenseTime` 的数据源从 `planned_dispense_time` 改为 `occurrence_time`(来自 `cli_procedure` 表):
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<!-- 第36-41行,collection 改为: -->
|
||||||
|
<collection property="medicineSummaryParamList" ofType="com.healthlink.his.web.inhospitalnursestation.dto.MedicineSummaryParam">
|
||||||
|
<result property="procedureId" column="procedure_id"/>
|
||||||
|
<result property="dispenseId" column="dispense_id"/>
|
||||||
|
<result property="dispenseTime" column="execution_time"/>
|
||||||
|
<result property="dispenseStatus" column="dispense_status"/>
|
||||||
|
</collection>
|
||||||
|
```
|
||||||
|
|
||||||
|
**改动B**:内层 SQL 增加 `cli_procedure` JOIN 并选取 `occurrence_time`:
|
||||||
|
|
||||||
|
在内层 SELECT(约第98行 `mmd.status_enum AS dispense_status` 之后)添加:
|
||||||
|
```sql
|
||||||
|
cp.occurrence_time AS execution_time,
|
||||||
|
```
|
||||||
|
|
||||||
|
在 FROM 子句中 `med_medication_dispense AS mmd` 之后添加 LEFT JOIN:
|
||||||
|
```sql
|
||||||
|
LEFT JOIN cli_procedure cp
|
||||||
|
ON cp.id = mmd.procedure_id
|
||||||
|
AND cp.delete_flag = '0'
|
||||||
|
```
|
||||||
|
|
||||||
|
**改动C**:外层 SELECT(第78行)将 `ii.planned_dispense_time` 改为 `ii.execution_time`:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
ii.execution_time,
|
||||||
|
```
|
||||||
|
|
||||||
|
**改动D**:ORDER BY(第203行)将 `mmd.planned_dispense_time` 改为 `cp.occurrence_time`:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
ORDER BY cp.occurrence_time )) AS ii
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 修改2:前端列名 — "领药时间" → "执行时间"
|
||||||
|
|
||||||
|
**文件**: `healthlink-his-ui/src/views/inpatientNurse/drugDistribution/components/prescriptionList.vue`
|
||||||
|
|
||||||
|
第164行:
|
||||||
|
```vue
|
||||||
|
<!-- 修改前 -->
|
||||||
|
<vxe-column title="领药时间" field="times">
|
||||||
|
|
||||||
|
<!-- 修改后 -->
|
||||||
|
<vxe-column title="执行时间" field="times">
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 无需修改的部分
|
||||||
|
- `MedicineSummaryParam.java` — 字段名 `dispenseTime` 保持不变,仅后端数据源改变
|
||||||
|
- `MedicineSummaryAppServiceImpl.java` — 无变化(`medicineSummary()` 方法提交时自行用 `new Date()` 覆盖)
|
||||||
|
- 前端时间格式化逻辑 — `item.dispenseTime?.substring(5, 10)` 从 "yyyy-MM-dd HH:mm:ss" 截取 "MM-dd",格式兼容
|
||||||
|
|
||||||
|
### 四、路由决策
|
||||||
|
|
||||||
|
**FIXER: guanyu(后端开发)**
|
||||||
|
|
||||||
|
**REASON**: 修复核心在 Mapper XML SQL 改写(JOIN `cli_procedure` 取 `occurrence_time` 替代 `planned_dispense_time`),属于后端数据查询层改动。前端仅改一个列名文本,可一并处理但主要工作量在后端 SQL。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 路由决策
|
||||||
|
- **修复 Agent**: guanyu
|
||||||
|
- **原因**: LLM 分析决策
|
||||||
102
MD/bugs/BUG_762_ANALYSIS.md
Normal file
102
MD/bugs/BUG_762_ANALYSIS.md
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# Bug #762 诸葛亮分析报告
|
||||||
|
|
||||||
|
> **文档类型**: Bug分析
|
||||||
|
> **分析时间**: 2026-06-12 16:21:51
|
||||||
|
> **分析模型**: mimo-v2.5 (LLM深度分析)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 基本信息
|
||||||
|
- **Bug #**: 762
|
||||||
|
- **标题**: [住院护士站-领药汇总]“汇总领药”界面的筛选标签文字丢失且功能失效
|
||||||
|
- **模块**: 病区护士工作站
|
||||||
|
- **提出人**: 陈显精
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Now I have the complete picture. Here's my analysis:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 一、Bug 理解
|
||||||
|
|
||||||
|
住院护士站的「汇总领药」页面(`drugDistribution/index.vue`)顶部筛选栏有 4 个按钮——"西药""中药""明细""汇总",但目前这 4 个按钮**仅显示空白**,用户看不到文字标签,也无法通过点击"西药/中药"进行药物类别筛选。期望按钮正常显示中文标签,且点击可触发对应的数据筛选。
|
||||||
|
|
||||||
|
### 二、根因分析
|
||||||
|
|
||||||
|
**根因完全在前端**,`healthlink-his-ui/src/views/inpatientNurse/drugDistribution/index.vue` 存在两个问题:
|
||||||
|
|
||||||
|
**问题1:`el-radio-button` 缺少标签文字**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- 第50~64行,当前代码 -->
|
||||||
|
<el-radio-group v-model="drugType" class="ml10">
|
||||||
|
<el-radio-button value="1" /> <!-- ← 缺少标签文字 -->
|
||||||
|
<el-radio-button value="2" /> <!-- ← 缺少标签文字 -->
|
||||||
|
</el-radio-group>
|
||||||
|
<el-radio-group v-model="isDetails" class="ml20" @change="handleRadioChange">
|
||||||
|
<el-radio-button value="1" /> <!-- ← 缺少标签文字 -->
|
||||||
|
<el-radio-button value="2" /> <!-- ← 缺少标签文字 -->
|
||||||
|
</el-radio-group>
|
||||||
|
```
|
||||||
|
|
||||||
|
Element Plus 的 `el-radio-button` 需要通过默认 slot 或 `label` 属性显示文字,仅设 `value` 不会渲染任何可见文本。
|
||||||
|
|
||||||
|
**问题2:`drugType` 未传递给子组件,筛选功能失效**
|
||||||
|
|
||||||
|
- `drugType` 在 `index.vue:178` 定义(`ref('1')`),但 `PrescriptionList` 和 `SummaryMedicineList` 组件在模板中**未接收此 prop**:
|
||||||
|
```html
|
||||||
|
<PrescriptionList v-if="isDetails == 1" ref="prescriptionRefs"
|
||||||
|
:exe-status="exeStatus" :request-status="requestStatus"
|
||||||
|
:deadline="deadline" :therapy-enum="therapyEnum" />
|
||||||
|
<!-- 缺少 :drug-type="drugType" -->
|
||||||
|
```
|
||||||
|
- `prescriptionList.vue` 和 `summaryMedicineList.vue` 的 `defineProps` 中均未定义 `drugType`
|
||||||
|
- API 调用时也未传 `tcmFlag` 参数
|
||||||
|
|
||||||
|
**后端已具备筛选能力**:`DispenseFormSearchParam` 已有 `tcmFlag` 字段(第34行),`HisQueryUtils.buildQueryWrapper` 会自动生成 WHERE 条件,Mapper XML 使用 `${ew.customSqlSegment}` 动态拼接。前端只需传参即可。
|
||||||
|
|
||||||
|
### 三、修复方案
|
||||||
|
|
||||||
|
纯前端修复,涉及 3 个文件,后端无需改动。
|
||||||
|
|
||||||
|
**文件1:`healthlink-his-ui/src/views/inpatientNurse/drugDistribution/index.vue`**
|
||||||
|
|
||||||
|
| 修改点 | 内容 |
|
||||||
|
|--------|------|
|
||||||
|
| 第53行 `el-radio-button value="1"` | 改为 `<el-radio-button value="1">西药</el-radio-button>` |
|
||||||
|
| 第56行 `el-radio-button value="2"` | 改为 `<el-radio-button value="2">中药</el-radio-button>` |
|
||||||
|
| 第62行 `el-radio-button value="1"` | 改为 `<el-radio-button value="1">明细</el-radio-button>` |
|
||||||
|
| 第65行 `el-radio-button value="2"` | 改为 `<el-radio-button value="2">汇总</el-radio-button>` |
|
||||||
|
| `PrescriptionList` 组件标签 | 添加 `:drug-type="drugType"` prop |
|
||||||
|
| `SummaryMedicineList` 组件标签 | 添加 `:drug-type="drugType"` prop |
|
||||||
|
|
||||||
|
**文件2:`healthlink-his-ui/src/views/inpatientNurse/drugDistribution/components/prescriptionList.vue`**
|
||||||
|
|
||||||
|
| 修改点 | 内容 |
|
||||||
|
|--------|------|
|
||||||
|
| `defineProps` 块(第259行) | 新增 `drugType: { type: String, default: '1' }` |
|
||||||
|
| `handleGetPrescription` 函数(第281行) | API 调用参数中添加 `tcmFlag: props.drugType === '1' ? 0 : 1`(西药=0,中药=1) |
|
||||||
|
|
||||||
|
**文件3:`healthlink-his-ui/src/views/inpatientNurse/drugDistribution/components/summaryMedicineList.vue`**
|
||||||
|
|
||||||
|
| 修改点 | 内容 |
|
||||||
|
|--------|------|
|
||||||
|
| `defineProps` 块(第168行) | 新增 `drugType: { type: String, default: '1' }` |
|
||||||
|
| `handleGetPrescription` 函数(第186行) | API 调用参数中添加 `tcmFlag: props.drugType === '1' ? 0 : 1` |
|
||||||
|
|
||||||
|
**验证方式:**
|
||||||
|
1. `cd healthlink-his-ui && npm run build:dev` 编译通过
|
||||||
|
2. `npm run lint` 无报错
|
||||||
|
3. 手动验证:进入汇总领药页,4 个按钮显示"西药""中药""明细""汇总"文字;点击切换正常
|
||||||
|
|
||||||
|
### 四、路由决策
|
||||||
|
|
||||||
|
**FIXER: zhaoyun**(前端开发)
|
||||||
|
**REASON:** 此 Bug 纯前端问题,涉及 3 个 Vue 组件的模板和 props 修复,属于前端 UI/交互层面,无需后端改动,最适合由赵云处理。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 路由决策
|
||||||
|
- **修复 Agent**: zhaoyun
|
||||||
|
- **原因**: ** 此 Bug 纯前端问题,涉及 3 个 Vue 组件的模板和 props 修复,属于前端 UI/交互层面,无需后端改动,最适合由赵云处理。
|
||||||
90
MD/bugs/BUG_763_ANALYSIS.md
Normal file
90
MD/bugs/BUG_763_ANALYSIS.md
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
# Bug #763 诸葛亮分析报告
|
||||||
|
|
||||||
|
> **文档类型**: Bug分析
|
||||||
|
> **分析时间**: 2026-06-12 16:18:00
|
||||||
|
> **分析模型**: mimo-v2.5 (LLM深度分析)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 基本信息
|
||||||
|
- **Bug #**: 763
|
||||||
|
- **标题**: [住院护士站-医嘱校对]医生工作站已签发的临时医嘱在护士站“医嘱校对”中无法查询
|
||||||
|
- **模块**: 病区护士工作站
|
||||||
|
- **提出人**: 陈显精
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
This confirms `effectiveDoseEnd` is only set in outpatient prescriptions, NOT in inpatient order signing. Now I have the complete root cause.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 一、Bug 理解
|
||||||
|
|
||||||
|
护士在"医嘱校对"界面选择患者并点击查询时,医生已签发的临时医嘱(药品类,如注射用头孢)无法显示,列表为空。期望行为:已签发的临时医嘱应出现在"未校对"列表中,供护士校对。
|
||||||
|
|
||||||
|
### 二、根因分析
|
||||||
|
|
||||||
|
**根因:Bug #665 修复引入的 `deadline` 过滤条件未处理 `NULL` 值。**
|
||||||
|
|
||||||
|
完整数据链路追踪:
|
||||||
|
|
||||||
|
1. **医生签发临时医嘱** → `AdviceManageAppServiceImpl.handMedication()` → `tempMedicationRequest.setStatusEnum(ACTIVE=2)` → 调用 `saveOrUpdate()` → 写入 `med_medication_request` 表
|
||||||
|
2. **关键遗漏**:`effectiveDoseEnd`(服药结束时间)在整个签发流程中**从未被设置**(`setEffectiveDoseEnd` 仅在门诊处方 `DoctorStationElepPrescriptionServiceImpl` 中调用,住院医嘱路径不涉及),因此数据库中 `effective_dose_end = NULL`
|
||||||
|
3. **护士站查询** → 前端 `prescriptionList.vue` 默认发送 `deadline = "2026-06-12 23:59:59"` → 后端 `AdviceProcessAppServiceImpl.getInpatientAdvicePage()` 拼接条件:
|
||||||
|
```java
|
||||||
|
queryWrapper.le("end_time", deadlineTime); // Bug #665 引入
|
||||||
|
```
|
||||||
|
生成 SQL:`end_time <= '2026-06-12 23:59:59'`
|
||||||
|
4. **NULL 比较失败**:PostgreSQL 中 `NULL <= anything` 结果为 `NULL`(等价于 `FALSE`),WHERE 子句排除该行 → 查询结果为空
|
||||||
|
|
||||||
|
**涉及文件:**
|
||||||
|
- `AdviceProcessAppServiceImpl.java`(第 235-243 行)— deadline 条件拼接
|
||||||
|
- `AdviceProcessAppMapper.xml` — UNION 查询,`T1.effective_dose_end AS end_time`
|
||||||
|
|
||||||
|
### 三、修复方案
|
||||||
|
|
||||||
|
**修改文件**:`healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/inhospitalnursestation/appservice/impl/AdviceProcessAppServiceImpl.java`
|
||||||
|
|
||||||
|
**修改内容**:将 deadline 过滤条件从 `le` 改为 NULL 安全的写法:
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 修改前(Bug #665 代码):
|
||||||
|
if (deadline != null && !deadline.isEmpty()) {
|
||||||
|
try {
|
||||||
|
LocalDateTime deadlineTime = LocalDateTime.parse(deadline,
|
||||||
|
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
queryWrapper.le("end_time", deadlineTime);
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
// 忽略无效的日期格式
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改后:
|
||||||
|
if (deadline != null && !deadline.isEmpty()) {
|
||||||
|
try {
|
||||||
|
LocalDateTime deadlineTime = LocalDateTime.parse(deadline,
|
||||||
|
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
queryWrapper.and(w -> w.le("end_time", deadlineTime).or().isNull("end_time"));
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
// 忽略无效的日期格式
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**原理**:`end_time <= deadline OR end_time IS NULL`,确保 `effective_dose_end` 为 NULL 的新签发医嘱也能被查询到。
|
||||||
|
|
||||||
|
**验证**:
|
||||||
|
1. `mvn clean compile -DskipTests` → 编译通过
|
||||||
|
2. 签发临时医嘱 → 护士站查询 → 应能查到
|
||||||
|
3. 长期医嘱、有截止时间的医嘱 → deadline 筛选仍然生效
|
||||||
|
|
||||||
|
### 四、路由决策
|
||||||
|
|
||||||
|
**FIXER**: guanyu
|
||||||
|
**REASON**: 修复范围仅涉及后端 Java Service 层一处 SQL 条件修改,属于纯后端逻辑修复,由后端开发关羽执行。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 路由决策
|
||||||
|
- **修复 Agent**: guanyu
|
||||||
|
- **原因**: LLM 分析决策
|
||||||
121
MD/bugs/BUG_764_ANALYSIS.md
Normal file
121
MD/bugs/BUG_764_ANALYSIS.md
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
# Bug #764 诸葛亮分析报告
|
||||||
|
|
||||||
|
> **文档类型**: Bug分析
|
||||||
|
> **分析时间**: 2026-06-12 16:05:34
|
||||||
|
> **分析模型**: mimo-v2.5 (LLM深度分析)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 基本信息
|
||||||
|
- **Bug #**: 764
|
||||||
|
- **标题**: [门诊医生工作站-检验] 已维护诊疗项目的检验项目“肾功能5项”在开立保存时报错“未找到对应的诊疗定义”
|
||||||
|
- **模块**: 门诊医生工作站
|
||||||
|
- **提出人**: 陈显精
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Now I have a complete understanding of the bug. Let me output the analysis.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 一、Bug 理解
|
||||||
|
|
||||||
|
用户在门诊医生工作站选择检验项目"肾功能5项"并点击保存时,系统报错"未找到检验项目 '肾功能5项' 对应的诊疗定义"。该检验项目已在后台正确维护,期望保存成功并自动联动生成门诊医嘱记录。
|
||||||
|
|
||||||
|
### 二、根因分析
|
||||||
|
|
||||||
|
**根因**:`DoctorStationLabApplyServiceImpl.java` 的检验申请保存方法包含两个阶段:
|
||||||
|
|
||||||
|
1. **阶段一(保存申请单明细)**:正确使用 `labActivityDefinitionService.getById(activityId)` 从 `lab_activity_definition` 表查询检验项目定义(第182行)。
|
||||||
|
2. **阶段二(自动创建门诊医嘱)**:**错误地**调用 `activityDefinitionService.getAppointActivityDefinitionId(itemName)`,该方法按名称精确匹配 `wor_activity_definition` 表(SQL: `WHERE NAME = #{activityName}`)。
|
||||||
|
|
||||||
|
**关键问题**:检验项目(如"肾功能5项")存储在独立的 `lab_activity_definition` 表中,**不存在于** `wor_activity_definition` 表中。按名称查询 `wor_activity_definition` 必然返回 null,触发 RuntimeException。
|
||||||
|
|
||||||
|
**对比参考**:`ExamApplyController`(检查申请)已正确处理类似情况——使用 `activityId = 0L` 占位,不依赖 `wor_activity_definition`(第224行注释:"检查申请不走诊疗定义,设置为0占位")。
|
||||||
|
|
||||||
|
**涉及文件**:
|
||||||
|
- `DoctorStationLabApplyServiceImpl.java:254-259` — 查询逻辑错误(根因)
|
||||||
|
- `ActivityDefinitionMapper.xml:7-13` — SQL 查询 `wor_activity_definition` by name
|
||||||
|
- `ActivityDefinitionServiceImpl.java:76-77` — `getAppointActivityDefinitionId` 方法
|
||||||
|
|
||||||
|
### 三、修复方案
|
||||||
|
|
||||||
|
修改 `DoctorStationLabApplyServiceImpl.java` 中阶段二(门诊医嘱创建循环),将从 `wor_activity_definition` 按名称查询改为使用 `lab_activity_definition` 的 `activityId` 直接查询:
|
||||||
|
|
||||||
|
**修改文件**:`healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/doctorstation/appservice/impl/DoctorStationLabApplyServiceImpl.java`
|
||||||
|
|
||||||
|
**具体改动**:
|
||||||
|
|
||||||
|
将第254-370行附近的代码从:
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 1. 根据检验项目名称查询诊疗定义(检验项目)
|
||||||
|
String itemName = labApplyItemDto.getItemName();
|
||||||
|
Long activityDefinitionId = activityDefinitionService.getAppointActivityDefinitionId(itemName);
|
||||||
|
if (activityDefinitionId == null) {
|
||||||
|
throw new RuntimeException("未找到检验项目 '" + itemName + "' 对应的诊疗定义");
|
||||||
|
}
|
||||||
|
// 2. 获取诊疗定义详情
|
||||||
|
ActivityDefinition activityDefinition = activityDefinitionService.getById(activityDefinitionId);
|
||||||
|
if (activityDefinition == null) {
|
||||||
|
throw new RuntimeException("诊疗定义不存在");
|
||||||
|
}
|
||||||
|
...
|
||||||
|
adviceSaveDto.setAdviceDefinitionId(activityDefinitionId);
|
||||||
|
adviceSaveDto.setDefinitionId(activityDefinitionId);
|
||||||
|
adviceSaveDto.setCategoryCode(activityDefinition.getCategoryCode());
|
||||||
|
adviceSaveDto.setActivityId(activityDefinitionId);
|
||||||
|
adviceSaveDto.setAdviceTableName("wor_activity_definition");
|
||||||
|
...
|
||||||
|
adviceSaveDto.setUnitCode(activityDefinition.getPermittedUnitCode());
|
||||||
|
Long feePackageId = activityDefinition.getFeePackageId();
|
||||||
|
```
|
||||||
|
|
||||||
|
改为:
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 1. 获取检验项目定义(从 lab_activity_definition 表,不走 wor_activity_definition)
|
||||||
|
String itemName = labApplyItemDto.getItemName();
|
||||||
|
Long labActivityId = labApplyItemDto.getActivityId();
|
||||||
|
if (labActivityId == null) {
|
||||||
|
throw new RuntimeException("检验项目 '" + itemName + "' 未传入 activityId,请重新选择检验项目");
|
||||||
|
}
|
||||||
|
LabActivityDefinition labActivityDef = labActivityDefinitionService.getById(labActivityId);
|
||||||
|
if (labActivityDef == null) {
|
||||||
|
throw new RuntimeException("检验项目定义不存在,activityId=" + labActivityId);
|
||||||
|
}
|
||||||
|
...
|
||||||
|
// 医嘱定义 ID:使用 lab_activity_definition 的 ID
|
||||||
|
adviceSaveDto.setAdviceDefinitionId(labActivityId);
|
||||||
|
// 费用定价 ID:检验项目不走 wor_activity_definition 定价体系,用 0 占位(与 ExamApplyController 一致)
|
||||||
|
adviceSaveDto.setDefinitionId(0L);
|
||||||
|
adviceSaveDto.setCategoryCode(labActivityDef.getCategoryCode());
|
||||||
|
adviceSaveDto.setActivityId(labActivityId);
|
||||||
|
adviceSaveDto.setAdviceTableName("lab_activity_definition");
|
||||||
|
...
|
||||||
|
adviceSaveDto.setUnitCode(labActivityDef.getPermittedUnitCode());
|
||||||
|
Long feePackageId = labActivityDef.getFeePackageId();
|
||||||
|
```
|
||||||
|
|
||||||
|
**核心改动点**:
|
||||||
|
| 字段 | 原值 | 新值 | 原因 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| 数据源 | `wor_activity_definition` (by name) | `lab_activity_definition` (by ID) | 检验项目独立存储 |
|
||||||
|
| `adviceDefinitionId` | `wor_activity_definition.id` | `lab_activity_definition.id` | 正确引用产品表 |
|
||||||
|
| `definitionId` | `wor_activity_definition.id` | `0L` 占位 | 检验项目不走诊疗定价体系 |
|
||||||
|
| `adviceTableName` | `"wor_activity_definition"` | `"lab_activity_definition"` | 正确指向产品来源表 |
|
||||||
|
| `categoryCode` | `ActivityDefinition.categoryCode` | `LabActivityDefinition.categoryCode` | 同名字段,来源切换 |
|
||||||
|
| `unitCode` | `ActivityDefinition.permittedUnitCode` | `LabActivityDefinition.permittedUnitCode` | 同名字段,来源切换 |
|
||||||
|
| `feePackageId` | `ActivityDefinition.feePackageId` | `LabActivityDefinition.feePackageId` | 同名字段,来源切换 |
|
||||||
|
|
||||||
|
### 四、路由决策
|
||||||
|
|
||||||
|
**FIXER**: `guanyu`(后端开发)
|
||||||
|
|
||||||
|
**REASON**: 此 Bug 仅涉及后端 Java 代码修改(`DoctorStationLabApplyServiceImpl.java` 一个文件),核心是修正检验项目的数据源查询逻辑——从 `wor_activity_definition` 切换到 `lab_activity_definition`。不需要前端改动(前端已正确传递 `activityId`),不需要数据库变更。属于后端 Service 层逻辑修复,由关羽执行最合适。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 路由决策
|
||||||
|
- **修复 Agent**: guanyu
|
||||||
|
- **原因**: LLM 分析决策
|
||||||
74
MD/bugs/BUG_765_ANALYSIS.md
Normal file
74
MD/bugs/BUG_765_ANALYSIS.md
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
# Bug #765 诸葛亮分析报告
|
||||||
|
|
||||||
|
> **文档类型**: Bug分析
|
||||||
|
> **分析时间**: 2026-06-12 15:58:59
|
||||||
|
> **分析模型**: mimo-v2.5 (LLM深度分析)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 基本信息
|
||||||
|
- **Bug #**: 765
|
||||||
|
- **标题**: [收费工作站-门诊挂号] 在“患者身份信息”框中选中检索的患者后,患者列表浮窗未自动隐藏
|
||||||
|
- **模块**: 建档挂号管理
|
||||||
|
- **提出人**: 陈显精
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Now I have the complete picture. Here's my analysis:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 一、Bug 理解
|
||||||
|
|
||||||
|
在门诊挂号页面的"患者身份信息"输入框中,用户输入关键字后弹出患者列表浮窗(`el-popover`),点击选中某行患者后,表单信息已正确回填,但浮窗没有自动关闭,继续遮挡下方录入项。用户期望选中后浮窗自动收起。
|
||||||
|
|
||||||
|
### 二、根因分析
|
||||||
|
|
||||||
|
问题出在 `outpatientregistration/index.vue` 中的 **popover 可见性控制逻辑**。
|
||||||
|
|
||||||
|
**关键代码链路:**
|
||||||
|
|
||||||
|
| 位置 | 代码 | 作用 |
|
||||||
|
|------|------|------|
|
||||||
|
| `index.vue:118` | `:visible="showPopover"` | popover 显隐由 `showPopover` 控制 |
|
||||||
|
| `index.vue:125` | `@mousedown.prevent` | 阻止 mousedown 冒泡到 input,防止点击列表时 input 失焦 |
|
||||||
|
| `index.vue:1990` | `handleFocus() → showPopover = true` | input 获焦显示浮窗 |
|
||||||
|
| `index.vue:1996` | `handleBlur() → showPopover = false` | input 失焦隐藏浮窗 |
|
||||||
|
| `index.vue:2228` | `selsectPatient(row)` — **只回填表单,未关闭浮窗** | ⬅️ 根因 |
|
||||||
|
|
||||||
|
**根因**:`selsectPatient` 函数只做了 `Object.assign(form.value, row)` 等字段回填,**没有设置 `showPopover.value = false`**。由于 `@mousedown.prevent` 阻止了点击列表时 input 的 blur 事件,`handleBlur` 不会被触发,浮窗就一直保持显示。
|
||||||
|
|
||||||
|
### 三、修复方案
|
||||||
|
|
||||||
|
**修改文件**:`healthlink-his-ui/src/views/charge/outpatientregistration/index.vue`
|
||||||
|
|
||||||
|
**修改内容**:在 `selsectPatient` 函数末尾添加一行,关闭 popover:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
function selsectPatient(row) {
|
||||||
|
Object.assign(form.value, row);
|
||||||
|
form.value.patientId = row.id;
|
||||||
|
form.value.searchKey = row.name;
|
||||||
|
form.value.name = row.name;
|
||||||
|
form.value.idCard = row.idCard;
|
||||||
|
form.value.genderEnum_enumText = row.genderEnum_enumText;
|
||||||
|
form.value.phone = row.phone;
|
||||||
|
form.value.firstEnum_enumText = row.firstEnum_enumText;
|
||||||
|
form.value.age = row.age;
|
||||||
|
form.value.identifierNo = row.identifierNo;
|
||||||
|
showPopover.value = false; // ← 新增:选中患者后关闭浮窗
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**影响范围**:仅一处,不涉及后端、不涉及数据库、不涉及其他组件。
|
||||||
|
|
||||||
|
### 四、路由决策
|
||||||
|
|
||||||
|
**FIXER**: `zhaoyun`(前端开发)
|
||||||
|
**REASON**: 纯前端 Vue 组件修复,只需在 `index.vue` 的 `selsectPatient` 函数中增加一行 `showPopover.value = false;`,属于 Element Plus popover 交互问题,赵云负责前端界面修复。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 路由决策
|
||||||
|
- **修复 Agent**: guanyu
|
||||||
|
- **原因**: LLM 分析决策
|
||||||
43
MD/bugs/BUG_诊疗目录_SYSDESDICT_ANALYSIS.md
Normal file
43
MD/bugs/BUG_诊疗目录_SYSDESDICT_ANALYSIS.md
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# 诊疗目录 SysDictData 反序列化错误 诸葛亮分析报告
|
||||||
|
|
||||||
|
> **文档类型**: Bug分析
|
||||||
|
> **分析时间**: 2026-06-11
|
||||||
|
> **分析模型**: mimo-v2.5 (LLM深度分析)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 基本信息
|
||||||
|
- **标题**: 诊疗目录 /system/catalog/diagnosistreatment 进入报错
|
||||||
|
- **错误**: Cannot deserialize value of type SysDictData from Array value
|
||||||
|
- **模块**: 诊疗目录管理
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 根因分析
|
||||||
|
|
||||||
|
**根本原因**: commit `68cfa4882` 将 Jackson 配置从 `Jackson2ObjectMapperBuilderCustomizer` 改为直接定义 `ObjectMapper` bean。
|
||||||
|
|
||||||
|
直接定义 `ObjectMapper` bean 会导致 Spring Boot 的 Jackson 自动配置完全失效:
|
||||||
|
1. Spring Boot 默认的 Jackson 模块(如 `jackson-datatype-jdk8`、`jackson-datatype-jsr310`)不会自动注册
|
||||||
|
2. 默认的序列化/反序列化特性设置丢失
|
||||||
|
3. `ObjectMapper` 的默认可见性设置可能不同
|
||||||
|
|
||||||
|
当 `DictAspect` 处理 `@Dict` 注解的 DTO 时,Jackson 在序列化/反序列化过程中遇到 `SysDictData` 类型,由于缺少正确的模块配置,无法正确处理嵌套的数组/对象结构。
|
||||||
|
|
||||||
|
## 修复方案
|
||||||
|
|
||||||
|
将 `ApplicationConfig.java` 中的 `ObjectMapper` bean 改回 `Jackson2ObjectMapperBuilderCustomizer`,让 Spring Boot 自动配置保持生效。
|
||||||
|
|
||||||
|
### 修改文件
|
||||||
|
- `core-framework/src/main/java/com/core/framework/config/ApplicationConfig.java`
|
||||||
|
|
||||||
|
### 修改内容
|
||||||
|
- `public ObjectMapper objectMapper()` → `public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization()`
|
||||||
|
- 移除手动创建的 `ObjectMapper` 实例
|
||||||
|
- 使用 builder 模式配置,保留 Spring Boot 默认设置
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 路由决策
|
||||||
|
- **修复 Agent**: guanyu (后端)
|
||||||
|
- **原因**: Jackson 配置问题,纯后端修改
|
||||||
34
docs/bug-fixes/bug-761.md
Normal file
34
docs/bug-fixes/bug-761.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# Bug #761 修复报告
|
||||||
|
|
||||||
|
## 基本信息
|
||||||
|
- **标题**: Bug #761 测试完成,请验收。提出人: chenxj。
|
||||||
|
- **提出人**: chenxj
|
||||||
|
- **修复时间**: 17:05:05 ~ 17:31:09
|
||||||
|
- **修复耗时**: 1465.3s
|
||||||
|
- **Commit**: `008ae24b4`
|
||||||
|
- **测试结果**: ❌ FAIL
|
||||||
|
|
||||||
|
## 根因分析
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bug #761 修复完成
|
||||||
|
|
||||||
|
**根因**:
|
||||||
|
- `MedicineSummaryAppMapper.xml` 中 `dispenseTime` 字段映射自 `med_medication_dispense.planned_dispense_time`(计划发药时间),而非实际执行时间。`planned_dispense_time` 在 `AdviceProcessAppServi | 文件变更: 无变更 | 阶段: generator:PASS reviewer:PASS qa:PASS verifier:PASS
|
||||||
|
|
||||||
|
## 修复文件
|
||||||
|
.../impl/DoctorStationLabApplyServiceImpl.java | 32 ++++++++++------------
|
||||||
|
|
||||||
|
## 流程时间线
|
||||||
|
| 时间 | 智能体 | 事件 | 状态 | 耗时 |
|
||||||
|
|------|--------|------|------|------|
|
||||||
|
| 14:24:44 | zhugeliang | pre_analyze_done | ✅ | 0.0s |
|
||||||
|
| 15:06:07 | zhugeliang | pre_analyze_done | ✅ | 0.0s |
|
||||||
|
| 15:53:07 | zhugeliang | pre_analyze_done | ✅ | 0.0s |
|
||||||
|
| 17:05:05 | guanyu | fix_start | ⏳ | 0.0s |
|
||||||
|
| 17:31:09 | guanyu | fix_done | ✅ | 1465.3s |
|
||||||
|
| 17:31:21 | zhugeliang | analyze_done | ✅ | 0.0s |
|
||||||
|
| 21:33:09 | chenlin | doc_done | ✅ | <1s |
|
||||||
|
|
||||||
|
## 全流程
|
||||||
|
诸葛亮分析 → guanyu 修复 → 张飞测试 → 华佗验收 → 陈琳归档
|
||||||
35
docs/bug-fixes/bug-763.md
Normal file
35
docs/bug-fixes/bug-763.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Bug #763 修复报告
|
||||||
|
|
||||||
|
## 基本信息
|
||||||
|
- **标题**: Bug #763 测试完成,请验收。提出人: chenxj。
|
||||||
|
- **提出人**: chenxj
|
||||||
|
- **修复时间**: 17:31:18 ~ 18:13:03
|
||||||
|
- **修复耗时**: 1310.2s
|
||||||
|
- **Commit**: `008ae24b4`
|
||||||
|
- **测试结果**: ❌ FAIL
|
||||||
|
|
||||||
|
## 根因分析
|
||||||
|
**编译验证通过 ✅ BUILD SUCCESS**
|
||||||
|
|
||||||
|
## Bug #763 修复验证结果
|
||||||
|
|
||||||
|
**根因确认(诸葛亮分析正确)**:
|
||||||
|
- Bug #665 引入的 `queryWrapper.le("end_time", deadlineTime)` 对 NULL 值处理不当
|
||||||
|
- 住院临时医嘱签发时 `effectiveDoseEnd` 未赋值 → DB 中 `effective_dose_end | 文件变更: 无变更 | 阶段: generator:PASS reviewer:PASS qa:PASS verifier:PASS
|
||||||
|
|
||||||
|
## 修复文件
|
||||||
|
.../impl/DoctorStationLabApplyServiceImpl.java | 32 ++++++++++------------
|
||||||
|
|
||||||
|
## 流程时间线
|
||||||
|
| 时间 | 智能体 | 事件 | 状态 | 耗时 |
|
||||||
|
|------|--------|------|------|------|
|
||||||
|
| 14:06:51 | guanyu | fix_start | ⏳ | 0.0s |
|
||||||
|
| 16:18:32 | zhugeliang | pre_analyze_done | ✅ | 0.0s |
|
||||||
|
| 17:31:18 | guanyu | fix_start | ⏳ | 0.0s |
|
||||||
|
| 17:48:37 | guanyu | fix_retry | ❓ | 0.0s |
|
||||||
|
| 18:13:03 | guanyu | fix_done | ✅ | 1310.2s |
|
||||||
|
| 18:13:16 | zhugeliang | analyze_done | ✅ | 0.0s |
|
||||||
|
| 21:33:23 | chenlin | doc_done | ✅ | <1s |
|
||||||
|
|
||||||
|
## 全流程
|
||||||
|
诸葛亮分析 → guanyu 修复 → 张飞测试 → 华佗验收 → 陈琳归档
|
||||||
32
docs/bug-fixes/bug-764.md
Normal file
32
docs/bug-fixes/bug-764.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# Bug #764 修复报告
|
||||||
|
|
||||||
|
## 基本信息
|
||||||
|
- **标题**: Bug #764 测试完成,请验收。提出人: chenxj。
|
||||||
|
- **提出人**: chenxj
|
||||||
|
- **修复时间**: 18:13:10 ~ 18:36:37
|
||||||
|
- **修复耗时**: 1285.2s
|
||||||
|
- **Commit**: `008ae24b4`
|
||||||
|
- **测试结果**: ❌ FAIL
|
||||||
|
|
||||||
|
## 根因分析
|
||||||
|
**修复完成** ✅
|
||||||
|
|
||||||
|
修改文件:`healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/doctorstation/appservice/impl/DoctorStationLabApplyServiceImpl.java`
|
||||||
|
|
||||||
|
核心改动:将门诊医嘱创建阶段的检验项目定义查询从 ` | 文件变更: 无变更 | 阶段: generator:PASS reviewer:PASS qa:PASS verifier:PASS
|
||||||
|
|
||||||
|
## 修复文件
|
||||||
|
.../impl/DoctorStationLabApplyServiceImpl.java | 32 ++++++++++------------
|
||||||
|
|
||||||
|
## 流程时间线
|
||||||
|
| 时间 | 智能体 | 事件 | 状态 | 耗时 |
|
||||||
|
|------|--------|------|------|------|
|
||||||
|
| 16:05:49 | zhugeliang | pre_analyze_done | ✅ | 0.0s |
|
||||||
|
| 18:13:10 | guanyu | fix_start | ⏳ | 0.0s |
|
||||||
|
| 18:36:37 | guanyu | fix_done | ✅ | 1285.2s |
|
||||||
|
| 18:36:49 | zhugeliang | analyze_done | ✅ | 0.0s |
|
||||||
|
| 21:33:06 | xunyu | db_review_done | ✅ | 0.0s |
|
||||||
|
| 21:33:52 | chenlin | doc_done | ✅ | <1s |
|
||||||
|
|
||||||
|
## 全流程
|
||||||
|
诸葛亮分析 → guanyu 修复 → 张飞测试 → 华佗验收 → 陈琳归档
|
||||||
34
docs/bug-fixes/bug-765.md
Normal file
34
docs/bug-fixes/bug-765.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# Bug #765 修复报告
|
||||||
|
|
||||||
|
## 基本信息
|
||||||
|
- **标题**: Bug #765 测试完成,请验收。提出人: chenxj。
|
||||||
|
- **提出人**: chenxj
|
||||||
|
- **修复时间**: 18:36:43 ~ 19:01:34
|
||||||
|
- **修复耗时**: 1410.2s
|
||||||
|
- **Commit**: `008ae24b4`
|
||||||
|
- **测试结果**: ✅ PASS
|
||||||
|
|
||||||
|
## 根因分析
|
||||||
|
✅ **编译成功**,`✓ built in 1m 55s`,0 错误。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 修复摘要
|
||||||
|
|
||||||
|
**根因**:`selsectPatient` 函数(第 2228 行)只做了患者信息回填(`Object.assign` + 逐字段赋值),没有关闭 `showPopover`。由于 `@mousedown.prevent` 阻止了 input 失焦,`handleBlur` 中的 `show | 文件变更: 无变更 | 阶段: generator:PASS reviewer:PASS qa:PASS verifier:PASS
|
||||||
|
|
||||||
|
## 修复文件
|
||||||
|
.../impl/DoctorStationLabApplyServiceImpl.java | 32 ++++++++++------------
|
||||||
|
|
||||||
|
## 流程时间线
|
||||||
|
| 时间 | 智能体 | 事件 | 状态 | 耗时 |
|
||||||
|
|------|--------|------|------|------|
|
||||||
|
| 15:59:27 | zhugeliang | pre_analyze_done | ✅ | 0.0s |
|
||||||
|
| 18:36:43 | guanyu | fix_start | ⏳ | 0.0s |
|
||||||
|
| 19:01:34 | guanyu | fix_done | ✅ | 1410.2s |
|
||||||
|
| 19:01:44 | zhugeliang | analyze_done | ✅ | 0.0s |
|
||||||
|
| 21:33:38 | zhangfei | test_done | ✅ | 0.0s |
|
||||||
|
| 21:33:38 | chenlin | doc_done | ✅ | <1s |
|
||||||
|
|
||||||
|
## 全流程
|
||||||
|
诸葛亮分析 → guanyu 修复 → 张飞测试 → 华佗验收 → 陈琳归档
|
||||||
@@ -115,10 +115,6 @@
|
|||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>tools.jackson.core</groupId>
|
|
||||||
<artifactId>jackson-databind</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- 阿里JSONè§£æžÂÂ器 -->
|
<!-- 阿里JSONè§£æžÂÂ器 -->
|
||||||
<!-- io常çâ€Â¨å·¥å…·ç±» -->
|
<!-- io常çâ€Â¨å·¥å…·ç±» -->
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.core.common.core.redis;
|
package com.core.common.core.redis;
|
||||||
|
|
||||||
import com.core.common.exception.UtilException;
|
import com.core.common.exception.UtilException;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.redis.core.BoundSetOperations;
|
import org.springframework.data.redis.core.BoundSetOperations;
|
||||||
import org.springframework.data.redis.core.HashOperations;
|
import org.springframework.data.redis.core.HashOperations;
|
||||||
@@ -18,6 +19,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
**/
|
**/
|
||||||
@SuppressWarnings(value = {"unchecked", "rawtypes"})
|
@SuppressWarnings(value = {"unchecked", "rawtypes"})
|
||||||
@Component
|
@Component
|
||||||
|
@Slf4j
|
||||||
public class RedisCache {
|
public class RedisCache {
|
||||||
@Autowired
|
@Autowired
|
||||||
public RedisTemplate redisTemplate;
|
public RedisTemplate redisTemplate;
|
||||||
@@ -94,8 +96,20 @@ public class RedisCache {
|
|||||||
* @return 缓存键值对应的数据
|
* @return 缓存键值对应的数据
|
||||||
*/
|
*/
|
||||||
public <T> T getCacheObject(final String key) {
|
public <T> T getCacheObject(final String key) {
|
||||||
ValueOperations<String, T> operation = redisTemplate.opsForValue();
|
try {
|
||||||
return operation.get(key);
|
ValueOperations<String, T> operation = redisTemplate.opsForValue();
|
||||||
|
return operation.get(key);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Redis获取对象异常, key: {}, 错误信息: {}", key, e.getMessage());
|
||||||
|
// 如果发生序列化等异常,可能是旧版本数据或损坏数据,直接删除以防止程序崩溃
|
||||||
|
try {
|
||||||
|
redisTemplate.delete(key);
|
||||||
|
log.info("已自动清理损坏的缓存Key: {}", key);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
log.error("自动清理损坏缓存失败, key: {}", key, ex);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.core.common.utils;
|
package com.core.common.utils;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.core.common.constant.CacheConstants;
|
import com.core.common.constant.CacheConstants;
|
||||||
@@ -38,11 +39,24 @@ public class DictUtils {
|
|||||||
* @return dictDatas 字典数据列表
|
* @return dictDatas 字典数据列表
|
||||||
*/
|
*/
|
||||||
public static List<SysDictData> getDictCache(String key) {
|
public static List<SysDictData> getDictCache(String key) {
|
||||||
JsonNode arrayCache = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
|
Object cached = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
|
||||||
if (StringUtils.isNotNull(arrayCache)) {
|
if (StringUtils.isNull(cached)) {
|
||||||
return new ObjectMapper().convertValue(arrayCache, new com.fasterxml.jackson.core.type.TypeReference<List<SysDictData>>() {});
|
return null;
|
||||||
}
|
}
|
||||||
return null;
|
// 如果已经是目标类型,直接返回
|
||||||
|
if (cached instanceof List && ((List<?>) cached).stream().allMatch(e -> e instanceof SysDictData)) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<SysDictData> result = (List<SysDictData>) cached;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
com.fasterxml.jackson.core.type.TypeReference<List<SysDictData>> typeRef =
|
||||||
|
new com.fasterxml.jackson.core.type.TypeReference<List<SysDictData>>() {};
|
||||||
|
ObjectMapper mapper = new ObjectMapper()
|
||||||
|
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
if (cached instanceof JsonNode jsonNode) {
|
||||||
|
return mapper.convertValue(jsonNode, typeRef);
|
||||||
|
}
|
||||||
|
return mapper.convertValue(cached, typeRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,17 +3,15 @@ package com.core.framework.config;
|
|||||||
import com.fasterxml.jackson.core.JsonParser;
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
|
||||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||||
import org.mybatis.spring.annotation.MapperScan;
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
|
import org.springframework.boot.jackson2.autoconfigure.Jackson2ObjectMapperBuilderCustomizer;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
@@ -40,19 +38,14 @@ public class ApplicationConfig {
|
|||||||
};
|
};
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ObjectMapper objectMapper() {
|
public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() {
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
return builder -> {
|
||||||
mapper.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
|
builder.timeZone(TimeZone.getDefault());
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
|
JavaTimeModule javaTimeModule = new JavaTimeModule();
|
||||||
mapper.setDateFormat(sdf);
|
javaTimeModule.addDeserializer(LocalDateTime.class, LOCAL_DATE_TIME_DESERIALIZER);
|
||||||
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
builder.modules(javaTimeModule);
|
||||||
|
builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||||
JavaTimeModule javaTimeModule = new JavaTimeModule();
|
};
|
||||||
javaTimeModule.addDeserializer(LocalDateTime.class, LOCAL_DATE_TIME_DESERIALIZER);
|
|
||||||
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
|
||||||
mapper.registerModule(javaTimeModule);
|
|
||||||
|
|
||||||
return mapper;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package com.core.framework.config;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
|
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||||
|
import org.springframework.data.redis.serializer.SerializationException;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Jackson Redis序列化器 - 兼容fastjson旧格式
|
||||||
|
*
|
||||||
|
* 新数据: 纯JSON (无类型包装),调用方用 convertValue 转换
|
||||||
|
* 旧fastjson: 去除L后缀后按JSON解析
|
||||||
|
* 旧Jackson activateDefaultTyping: 解包 ["className",{data}] 后取data部分
|
||||||
|
*/
|
||||||
|
public class FastjsonCompatibleRedisSerializer implements RedisSerializer<Object> {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(FastjsonCompatibleRedisSerializer.class);
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
/** 全局ObjectMapper,供外部调用方做 convertValue 转换 */
|
||||||
|
private static final ObjectMapper sharedMapper = createMapper();
|
||||||
|
|
||||||
|
public FastjsonCompatibleRedisSerializer() { log.info("[INIT] FastjsonCompatibleRedisSerializer loaded - plain JSON mode");
|
||||||
|
this.objectMapper = createMapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ObjectMapper createMapper() {
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||||
|
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
return mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取共享ObjectMapper,供 DictUtils / TokenService 等做 convertValue */
|
||||||
|
public static ObjectMapper getSharedMapper() {
|
||||||
|
return sharedMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serialize(Object object) throws SerializationException {
|
||||||
|
if (object == null) {
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return objectMapper.writeValueAsBytes(object);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new SerializationException("Redis序列化失败: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object deserialize(byte[] bytes) throws SerializationException {
|
||||||
|
if (bytes == null || bytes.length <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String json = new String(bytes, StandardCharsets.UTF_8);
|
||||||
|
// 移除fastjson特有的Long L后缀: 123L -> 123
|
||||||
|
String cleaned = json.replaceAll("(\\d+)L", "$1");
|
||||||
|
try {
|
||||||
|
// 处理旧Jackson activateDefaultTyping格式: ["className", {data}]
|
||||||
|
if (cleaned.startsWith("[\"") && cleaned.length() > 10) {
|
||||||
|
com.fasterxml.jackson.databind.JsonNode node = objectMapper.readTree(cleaned);
|
||||||
|
if (node.isArray() && node.size() >= 2 && node.get(0).isTextual()) {
|
||||||
|
// 取data部分(第2个元素),忽略className
|
||||||
|
return objectMapper.treeToValue(node.get(1), Object.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return objectMapper.readValue(cleaned, Object.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Redis数据反序列化失败(已忽略): {}", e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,51 +4,24 @@ import org.springframework.cache.annotation.CachingConfigurerSupport;
|
|||||||
import org.springframework.cache.annotation.EnableCaching;
|
import org.springframework.cache.annotation.EnableCaching;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.data.redis.core.ValueOperations;
|
|
||||||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||||
import org.springframework.data.redis.serializer.GenericJacksonJsonRedisSerializer;
|
|
||||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||||
import tools.jackson.databind.DeserializationFeature;
|
|
||||||
import tools.jackson.databind.DatabindContext;
|
|
||||||
import tools.jackson.databind.JavaType;
|
|
||||||
import tools.jackson.databind.json.JsonMapper;
|
|
||||||
import tools.jackson.databind.jsontype.PolymorphicTypeValidator;
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableCaching
|
@EnableCaching
|
||||||
public class RedisConfig extends CachingConfigurerSupport {
|
public class RedisConfig extends CachingConfigurerSupport {
|
||||||
|
|
||||||
private static final PolymorphicTypeValidator ALLOW_ALL = new PolymorphicTypeValidator() {
|
|
||||||
@Override
|
|
||||||
public Validity validateBaseType(DatabindContext ctxt, JavaType baseType) {
|
|
||||||
return Validity.ALLOWED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Validity validateSubClassName(DatabindContext ctxt, JavaType baseType, String subClassName) {
|
|
||||||
return Validity.ALLOWED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Validity validateSubType(DatabindContext ctxt, JavaType baseType, JavaType subType) {
|
|
||||||
return Validity.ALLOWED;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@Primary
|
||||||
@SuppressWarnings(value = {"unchecked", "rawtypes"})
|
@SuppressWarnings(value = {"unchecked", "rawtypes"})
|
||||||
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
|
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
|
||||||
RedisTemplate<Object, Object> template = new RedisTemplate<>();
|
RedisTemplate<Object, Object> template = new RedisTemplate<>();
|
||||||
template.setConnectionFactory(connectionFactory);
|
template.setConnectionFactory(connectionFactory);
|
||||||
|
|
||||||
tools.jackson.databind.ObjectMapper objectMapper = JsonMapper.builder()
|
FastjsonCompatibleRedisSerializer serializer = new FastjsonCompatibleRedisSerializer();
|
||||||
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
|
|
||||||
.activateDefaultTyping(ALLOW_ALL, tools.jackson.databind.DefaultTyping.NON_FINAL)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
GenericJacksonJsonRedisSerializer serializer = new GenericJacksonJsonRedisSerializer(objectMapper);
|
|
||||||
|
|
||||||
template.setKeySerializer(new StringRedisSerializer());
|
template.setKeySerializer(new StringRedisSerializer());
|
||||||
template.setValueSerializer(serializer);
|
template.setValueSerializer(serializer);
|
||||||
@@ -68,16 +41,18 @@ public class RedisConfig extends CachingConfigurerSupport {
|
|||||||
return redisScript;
|
return redisScript;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ValueOperations<Object, Object> valueOperations(RedisTemplate<Object, Object> redisTemplate) {
|
|
||||||
return redisTemplate.opsForValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String limitScriptText() {
|
private String limitScriptText() {
|
||||||
return "local key = KEYS[1]\n" + "local count = tonumber(ARGV[1])\n" + "local time = tonumber(ARGV[2])\n"
|
return "local key = KEYS[1]\n" +
|
||||||
+ "local current = redis.call('get', key);\n" + "if current and tonumber(current) > count then\n"
|
"local count = tonumber(ARGV[1])\n" +
|
||||||
+ " return tonumber(current);\n" + "end\n" + "current = redis.call('incr', key)\n"
|
"local ttl = tonumber(ARGV[2])\n" +
|
||||||
+ "if tonumber(current) == 1 then\n" + " redis.call('expire', key, time)\n" + "end\n"
|
"local current = redis.call('get', KEYS[1]);\n" +
|
||||||
+ "return tonumber(current);";
|
"if current and tonumber(current) > count then\n" +
|
||||||
|
" return tonumber(current);\n" +
|
||||||
|
"end\n" +
|
||||||
|
"current = redis.call('incr', KEYS[1]);\n" +
|
||||||
|
"if tonumber(current) == 1 then\n" +
|
||||||
|
" redis.call('expire', KEYS[1], ttl);\n" +
|
||||||
|
"end\n" +
|
||||||
|
"return tonumber(current);\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -63,8 +63,28 @@ public class TokenService {
|
|||||||
// 解析对应的权限以及用户信息
|
// 解析对应的权限以及用户信息
|
||||||
String uuid = (String)claims.get(Constants.LOGIN_USER_KEY);
|
String uuid = (String)claims.get(Constants.LOGIN_USER_KEY);
|
||||||
String userKey = getTokenKey(uuid);
|
String userKey = getTokenKey(uuid);
|
||||||
LoginUser user = redisCache.getCacheObject(userKey);
|
Object cached = redisCache.getCacheObject(userKey);
|
||||||
return user;
|
if (cached instanceof LoginUser) {
|
||||||
|
return (LoginUser) cached;
|
||||||
|
}
|
||||||
|
// 兼容旧Jackson activateDefaultTyping格式: ["className",{data}]
|
||||||
|
if (cached instanceof java.util.List<?> list && list.size() >= 2 && list.get(0) instanceof String) {
|
||||||
|
Object data = list.get(1);
|
||||||
|
if (data instanceof java.util.Map) {
|
||||||
|
com.fasterxml.jackson.databind.ObjectMapper mapper =
|
||||||
|
new com.fasterxml.jackson.databind.ObjectMapper();
|
||||||
|
mapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
return mapper.convertValue(data, LoginUser.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 兼容纯JSON格式: LinkedHashMap -> LoginUser
|
||||||
|
if (cached instanceof java.util.Map) {
|
||||||
|
com.fasterxml.jackson.databind.ObjectMapper mapper =
|
||||||
|
new com.fasterxml.jackson.databind.ObjectMapper();
|
||||||
|
mapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
return mapper.convertValue(cached, LoginUser.class);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("获取用户信息异常'{}'", e.getMessage());
|
log.error("获取用户信息异常'{}'", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public class AntibioticAppServiceImpl implements IAntibioticAppService {
|
|||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public AntibioticApproval requestApproval(AntibioticApproval a) {
|
public AntibioticApproval requestApproval(AntibioticApproval a) {
|
||||||
a.setStatus("PENDING"); a.setDelFlag("0"); approvalService.save(a); return a;
|
a.setStatus("PENDING"); a.setDeleteFlag("0"); approvalService.save(a); return a;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void approve(Long id, Long approverId, String approverName, String result) {
|
public void approve(Long id, Long approverId, String approverName, String result) {
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ public class TicketAppServiceImpl implements ITicketAppService {
|
|||||||
dto.setIdCard(raw.getIdCard());
|
dto.setIdCard(raw.getIdCard());
|
||||||
dto.setDoctorId(raw.getDoctorId());
|
dto.setDoctorId(raw.getDoctorId());
|
||||||
dto.setDepartmentId(raw.getDepartmentId());
|
dto.setDepartmentId(raw.getDepartmentId());
|
||||||
dto.setRealPatientId(raw.getPatientId());
|
dto.setRealPatientId(raw.getRealPatientId() != null ? raw.getRealPatientId() : raw.getPatientId());
|
||||||
dto.setOrderId(raw.getOrderId());
|
dto.setOrderId(raw.getOrderId());
|
||||||
dto.setOrderNo(raw.getOrderNo());
|
dto.setOrderNo(raw.getOrderNo());
|
||||||
|
|
||||||
|
|||||||
@@ -515,29 +515,28 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
|
|||||||
// 构建查询条件
|
// 构建查询条件
|
||||||
QueryWrapper<CurrentDayEncounterDto> queryWrapper = HisQueryUtils.buildQueryWrapper(null, searchKey,
|
QueryWrapper<CurrentDayEncounterDto> queryWrapper = HisQueryUtils.buildQueryWrapper(null, searchKey,
|
||||||
new HashSet<>(Arrays.asList("patient_name", "organization_name", "practitioner_name", "healthcare_name", "identifier_no")),
|
new HashSet<>(Arrays.asList("patient_name", "organization_name", "practitioner_name", "healthcare_name", "identifier_no")),
|
||||||
request);
|
null); // registerTimeSTime/ETime 已下推到 SQL 内层 WHERE,跳过 buildQueryWrapper 的自动 *STime/*ETime 处理
|
||||||
|
|
||||||
// 手动处理 statusEnum 参数(用于过滤退号记录)
|
// 提取statusEnum参数,下推到内层WHERE(避免外层重复过滤)
|
||||||
|
Integer statusFilter = null;
|
||||||
String statusEnumParam = request.getParameter("statusEnum");
|
String statusEnumParam = request.getParameter("statusEnum");
|
||||||
if (statusEnumParam != null && !statusEnumParam.isEmpty()) {
|
if (statusEnumParam != null && !statusEnumParam.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
Integer statusEnum = Integer.parseInt(statusEnumParam);
|
statusFilter = Integer.parseInt(statusEnumParam);
|
||||||
if (statusEnum == -1) {
|
|
||||||
// -1 表示排除退号记录(正常挂号)
|
|
||||||
queryWrapper.ne("status_enum", 6);
|
|
||||||
} else {
|
|
||||||
// 其他值表示精确匹配
|
|
||||||
queryWrapper.eq("status_enum", statusEnum);
|
|
||||||
}
|
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
// 忽略无效的参数值
|
// 忽略无效的参数值
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 提取日期范围参数,下推到内层WHERE以优化性能(避免全表JOIN后再过滤)
|
||||||
|
String registerTimeSTime = request.getParameter("registerTimeSTime");
|
||||||
|
String registerTimeETime = request.getParameter("registerTimeETime");
|
||||||
|
|
||||||
IPage<CurrentDayEncounterDto> currentDayEncounter = outpatientRegistrationAppMapper.getCurrentDayEncounter(
|
IPage<CurrentDayEncounterDto> currentDayEncounter = outpatientRegistrationAppMapper.getCurrentDayEncounter(
|
||||||
new Page<>(pageNo, pageSize), EncounterClass.AMB.getValue(), EncounterStatus.IN_PROGRESS.getValue(),
|
new Page<>(pageNo, pageSize), EncounterClass.AMB.getValue(), EncounterStatus.IN_PROGRESS.getValue(),
|
||||||
ParticipantType.ADMITTER.getCode(), ParticipantType.REGISTRATION_DOCTOR.getCode(), queryWrapper,
|
ParticipantType.ADMITTER.getCode(), ParticipantType.REGISTRATION_DOCTOR.getCode(), queryWrapper,
|
||||||
ChargeItemContext.REGISTER.getValue(), PaymentStatus.SUCCESS.getValue());
|
ChargeItemContext.REGISTER.getValue(), PaymentStatus.SUCCESS.getValue(),
|
||||||
|
registerTimeSTime, registerTimeETime, statusFilter);
|
||||||
|
|
||||||
// 过滤候选池排除列表
|
// 过滤候选池排除列表
|
||||||
// 仅当调用方显式传 excludeFromCandidatePool=true 时才过滤,避免非分诊场景(挂号/收费)
|
// 仅当调用方显式传 excludeFromCandidatePool=true 时才过滤,避免非分诊场景(挂号/收费)
|
||||||
|
|||||||
@@ -54,7 +54,10 @@ public interface OutpatientRegistrationAppMapper {
|
|||||||
@Param("classEnum") Integer classEnum, @Param("statusEnum") Integer statusEnum,
|
@Param("classEnum") Integer classEnum, @Param("statusEnum") Integer statusEnum,
|
||||||
@Param("participantType1") String participantType1, @Param("participantType2") String participantType2,
|
@Param("participantType1") String participantType1, @Param("participantType2") String participantType2,
|
||||||
@Param(Constants.WRAPPER) QueryWrapper<CurrentDayEncounterDto> queryWrapper,
|
@Param(Constants.WRAPPER) QueryWrapper<CurrentDayEncounterDto> queryWrapper,
|
||||||
@Param("register") Integer register, @Param("paymentStatus") Integer paymentStatus);
|
@Param("register") Integer register, @Param("paymentStatus") Integer paymentStatus,
|
||||||
|
@Param("registerTimeSTime") String registerTimeSTime,
|
||||||
|
@Param("registerTimeETime") String registerTimeETime,
|
||||||
|
@Param("statusFilter") Integer statusFilter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询item绑定的信息(耗材或诊疗)
|
* 查询item绑定的信息(耗材或诊疗)
|
||||||
|
|||||||
@@ -30,13 +30,17 @@ public class ClinicalPathwayController {
|
|||||||
}
|
}
|
||||||
@PutMapping("/complete/{id}") @Transactional(rollbackFor=Exception.class)
|
@PutMapping("/complete/{id}") @Transactional(rollbackFor=Exception.class)
|
||||||
public R<?> completePathway(@PathVariable Long id) {
|
public R<?> completePathway(@PathVariable Long id) {
|
||||||
ClinicalPathwayExecution e = executionService.getById(id); if (e == null) return R.fail("执行记录不存在");
|
LambdaQueryWrapper<ClinicalPathwayExecution> qw = new LambdaQueryWrapper<>();
|
||||||
|
qw.eq(ClinicalPathwayExecution::getPathwayId, id).eq(ClinicalPathwayExecution::getStatus, "IN_PATH").orderByDesc(ClinicalPathwayExecution::getCreateTime).last("LIMIT 1");
|
||||||
|
ClinicalPathwayExecution e = executionService.getOne(qw); if (e == null) return R.fail("执行记录不存在");
|
||||||
e.setStatus("COMPLETED"); e.setCompleteDate(java.time.LocalDate.now());
|
e.setStatus("COMPLETED"); e.setCompleteDate(java.time.LocalDate.now());
|
||||||
executionService.updateById(e); return R.ok();
|
executionService.updateById(e); return R.ok();
|
||||||
}
|
}
|
||||||
@PutMapping("/vary/{id}") @Transactional(rollbackFor=Exception.class)
|
@PutMapping("/vary/{id}") @Transactional(rollbackFor=Exception.class)
|
||||||
public R<?> varyPathway(@PathVariable Long id, @RequestParam("reason") String reason) {
|
public R<?> varyPathway(@PathVariable Long id, @RequestParam("reason") String reason) {
|
||||||
ClinicalPathwayExecution e = executionService.getById(id); if (e == null) return R.fail("执行记录不存在");
|
LambdaQueryWrapper<ClinicalPathwayExecution> qw = new LambdaQueryWrapper<>();
|
||||||
|
qw.eq(ClinicalPathwayExecution::getPathwayId, id).eq(ClinicalPathwayExecution::getStatus, "IN_PATH").orderByDesc(ClinicalPathwayExecution::getCreateTime).last("LIMIT 1");
|
||||||
|
ClinicalPathwayExecution e = executionService.getOne(qw); if (e == null) return R.fail("执行记录不存在");
|
||||||
e.setStatus("VARIATION"); e.setVariationReason(reason); executionService.updateById(e); return R.ok();
|
e.setStatus("VARIATION"); e.setVariationReason(reason); executionService.updateById(e); return R.ok();
|
||||||
}
|
}
|
||||||
@GetMapping("/stats")
|
@GetMapping("/stats")
|
||||||
@@ -44,11 +48,12 @@ public class ClinicalPathwayController {
|
|||||||
Map<String, Object> stats = new HashMap<>();
|
Map<String, Object> stats = new HashMap<>();
|
||||||
stats.put("totalPathways", pathwayService.count());
|
stats.put("totalPathways", pathwayService.count());
|
||||||
stats.put("totalExecutions", executionService.count());
|
stats.put("totalExecutions", executionService.count());
|
||||||
LambdaQueryWrapper<ClinicalPathwayExecution> cw = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<ClinicalPathwayExecution> ccw = new LambdaQueryWrapper<>();
|
||||||
cw.eq(ClinicalPathwayExecution::getStatus, "COMPLETED");
|
ccw.eq(ClinicalPathwayExecution::getStatus, "COMPLETED");
|
||||||
stats.put("completedExecutions", executionService.count(cw));
|
stats.put("completedExecutions", executionService.count(ccw));
|
||||||
cw.eq(ClinicalPathwayExecution::getStatus, "VARIATION");
|
LambdaQueryWrapper<ClinicalPathwayExecution> vcw = new LambdaQueryWrapper<>();
|
||||||
stats.put("variedExecutions", executionService.count(cw));
|
vcw.eq(ClinicalPathwayExecution::getStatus, "VARIATION");
|
||||||
|
stats.put("variedExecutions", executionService.count(vcw));
|
||||||
long total = executionService.count();
|
long total = executionService.count();
|
||||||
long completed = stats.containsKey("completedExecutions") ? (long) stats.get("completedExecutions") : 0;
|
long completed = stats.containsKey("completedExecutions") ? (long) stats.get("completedExecutions") : 0;
|
||||||
stats.put("completionRate", total > 0 ? Math.round(completed * 100.0 / total) : 0);
|
stats.put("completionRate", total > 0 ? Math.round(completed * 100.0 / total) : 0);
|
||||||
|
|||||||
@@ -666,7 +666,7 @@ public class CommonServiceImpl implements ICommonService {
|
|||||||
.eq(DocInventoryItemStatic::getDeleteFlag, DelFlag.NO.getCode())
|
.eq(DocInventoryItemStatic::getDeleteFlag, DelFlag.NO.getCode())
|
||||||
.eq(DocInventoryItemStatic::getTenantId, SecurityUtils.getLoginUser().getTenantId()));
|
.eq(DocInventoryItemStatic::getTenantId, SecurityUtils.getLoginUser().getTenantId()));
|
||||||
if (docInventoryItemStaticList.isEmpty()) {
|
if (docInventoryItemStaticList.isEmpty()) {
|
||||||
return null;
|
return R.ok(Collections.emptyList());
|
||||||
}
|
}
|
||||||
// 直接去重并按BusNo倒序排序
|
// 直接去重并按BusNo倒序排序
|
||||||
List<String> busNoList = docInventoryItemStaticList.stream().map(DocInventoryItemStatic::getBusNo).distinct() // 去重
|
List<String> busNoList = docInventoryItemStaticList.stream().map(DocInventoryItemStatic::getBusNo).distinct() // 去重
|
||||||
|
|||||||
@@ -451,10 +451,12 @@ public class DoctorStationChineseMedicalAppServiceImpl implements IDoctorStation
|
|||||||
// 删除费用项
|
// 删除费用项
|
||||||
iChargeItemService.deleteByServiceTableAndId(CommonConstants.TableName.MED_MEDICATION_REQUEST,
|
iChargeItemService.deleteByServiceTableAndId(CommonConstants.TableName.MED_MEDICATION_REQUEST,
|
||||||
adviceSaveDto.getRequestId());
|
adviceSaveDto.getRequestId());
|
||||||
// 删除代煎费
|
// 删除代煎费(按处方号精确清理)
|
||||||
iChargeItemService.remove(new LambdaQueryWrapper<ChargeItem>()
|
if (adviceSaveDto.getPrescriptionNo() != null) {
|
||||||
.eq(ChargeItem::getPrescriptionNo, adviceSaveDto.getPrescriptionNo())
|
iChargeItemService.remove(new LambdaQueryWrapper<ChargeItem>()
|
||||||
.eq(ChargeItem::getProductId, sufferingDefinitionId));
|
.eq(ChargeItem::getPrescriptionNo, adviceSaveDto.getPrescriptionNo())
|
||||||
|
.eq(ChargeItem::getProductId, sufferingDefinitionId));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,7 +616,7 @@ public class DoctorStationChineseMedicalAppServiceImpl implements IDoctorStation
|
|||||||
Long encounterDiagnosisId = medicineList.get(0).getEncounterDiagnosisId();
|
Long encounterDiagnosisId = medicineList.get(0).getEncounterDiagnosisId();
|
||||||
// 中药付数
|
// 中药付数
|
||||||
BigDecimal chineseHerbsDoseQuantity = medicineList.get(0).getChineseHerbsDoseQuantity();
|
BigDecimal chineseHerbsDoseQuantity = medicineList.get(0).getChineseHerbsDoseQuantity();
|
||||||
// 🔧 Bug Fix #668: 收集所有处方号(不同分组可能有不同处方号)
|
// 收集所有处方号(不同分组可能有不同处方号)
|
||||||
List<String> prescriptionNos = insertOrUpdateList.stream()
|
List<String> prescriptionNos = insertOrUpdateList.stream()
|
||||||
.map(AdviceSaveDto::getPrescriptionNo)
|
.map(AdviceSaveDto::getPrescriptionNo)
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
@@ -628,12 +630,10 @@ public class DoctorStationChineseMedicalAppServiceImpl implements IDoctorStation
|
|||||||
AdviceBaseDto adviceBaseDto = new AdviceBaseDto();
|
AdviceBaseDto adviceBaseDto = new AdviceBaseDto();
|
||||||
adviceBaseDto.setAdviceDefinitionId(sufferingDefinitionId); // 医嘱定义id
|
adviceBaseDto.setAdviceDefinitionId(sufferingDefinitionId); // 医嘱定义id
|
||||||
|
|
||||||
// 🔧 Bug Fix #668: 先删除所有处方号关联的中药代煎账单
|
// 先删除该就诊关联的所有中药代煎账单
|
||||||
if (!prescriptionNos.isEmpty()) {
|
iChargeItemService.remove(new LambdaQueryWrapper<ChargeItem>()
|
||||||
iChargeItemService.remove(new LambdaQueryWrapper<ChargeItem>()
|
.eq(ChargeItem::getEncounterId, encounterId)
|
||||||
.in(ChargeItem::getPrescriptionNo, prescriptionNos)
|
.eq(ChargeItem::getProductId, sufferingDefinitionId));
|
||||||
.eq(ChargeItem::getProductId, sufferingDefinitionId));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 对应的诊疗医嘱信息
|
// 对应的诊疗医嘱信息
|
||||||
AdviceBaseDto activityAdviceBaseDto = iDoctorStationAdviceAppService.getAdviceBaseInfo(adviceBaseDto, null,
|
AdviceBaseDto activityAdviceBaseDto = iDoctorStationAdviceAppService.getAdviceBaseInfo(adviceBaseDto, null,
|
||||||
@@ -642,7 +642,7 @@ public class DoctorStationChineseMedicalAppServiceImpl implements IDoctorStation
|
|||||||
// 费用定价
|
// 费用定价
|
||||||
AdvicePriceDto advicePriceDto = activityAdviceBaseDto.getPriceList().get(0);
|
AdvicePriceDto advicePriceDto = activityAdviceBaseDto.getPriceList().get(0);
|
||||||
if (advicePriceDto != null) {
|
if (advicePriceDto != null) {
|
||||||
// 🔧 Bug Fix #668: 为每个处方号分别生成代煎账单
|
// 为每个处方号分别生成代煎账单
|
||||||
for (String prescriptionNo : prescriptionNos) {
|
for (String prescriptionNo : prescriptionNos) {
|
||||||
chargeItem = new ChargeItem();
|
chargeItem = new ChargeItem();
|
||||||
chargeItem.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源
|
chargeItem.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源
|
||||||
@@ -674,12 +674,10 @@ public class DoctorStationChineseMedicalAppServiceImpl implements IDoctorStation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (Whether.NO.getValue().equals(sufferingFlag)) {
|
} else if (Whether.NO.getValue().equals(sufferingFlag)) {
|
||||||
// 🔧 Bug Fix #668: 删除所有处方号关联的中药代煎账单
|
// 删除该就诊关联的所有中药代煎账单
|
||||||
if (!prescriptionNos.isEmpty()) {
|
iChargeItemService.remove(new LambdaQueryWrapper<ChargeItem>()
|
||||||
iChargeItemService.remove(new LambdaQueryWrapper<ChargeItem>()
|
.eq(ChargeItem::getEncounterId, encounterId)
|
||||||
.in(ChargeItem::getPrescriptionNo, prescriptionNos)
|
.eq(ChargeItem::getProductId, sufferingDefinitionId));
|
||||||
.eq(ChargeItem::getProductId, sufferingDefinitionId));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 签发时,把草稿状态的账单更新为待收费[中医]
|
// 签发时,把草稿状态的账单更新为待收费[中医]
|
||||||
|
|||||||
@@ -251,18 +251,16 @@ public class DoctorStationLabApplyServiceImpl implements IDoctorStationInspectio
|
|||||||
|
|
||||||
// 遍历检验申请单明细,为每个检验项目创建对应的门诊医嘱记录
|
// 遍历检验申请单明细,为每个检验项目创建对应的门诊医嘱记录
|
||||||
for (DoctorStationLabApplyItemDto labApplyItemDto : doctorStationLabApplyDto.getLabApplyItemList()) {
|
for (DoctorStationLabApplyItemDto labApplyItemDto : doctorStationLabApplyDto.getLabApplyItemList()) {
|
||||||
// 1. 根据检验项目名称查询诊疗定义(检验项目)
|
// 1. Bug #764: 使用 lab_activity_definition 表的 activityId 查询检验项目定义
|
||||||
|
// 检验项目存储在 lab_activity_definition 独立表中,不走 wor_activity_definition
|
||||||
String itemName = labApplyItemDto.getItemName();
|
String itemName = labApplyItemDto.getItemName();
|
||||||
Long activityDefinitionId = activityDefinitionService.getAppointActivityDefinitionId(itemName);
|
Long labActivityId = labApplyItemDto.getActivityId();
|
||||||
|
if (labActivityId == null) {
|
||||||
if (activityDefinitionId == null) {
|
throw new RuntimeException("检验项目 '" + itemName + "' 未传入 activityId,请重新选择检验项目");
|
||||||
throw new RuntimeException("未找到检验项目 '" + itemName + "' 对应的诊疗定义");
|
|
||||||
}
|
}
|
||||||
|
LabActivityDefinition labActivityDef = labActivityDefinitionService.getById(labActivityId);
|
||||||
// 2. 获取诊疗定义详情
|
if (labActivityDef == null) {
|
||||||
ActivityDefinition activityDefinition = activityDefinitionService.getById(activityDefinitionId);
|
throw new RuntimeException("检验项目 '" + itemName + "' 对应的检验项目定义不存在(ID: " + labActivityId + ")");
|
||||||
if (activityDefinition == null) {
|
|
||||||
throw new RuntimeException("诊疗定义不存在");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 根据执行科室代码获取科室 ID(positionId)
|
// 3. 根据执行科室代码获取科室 ID(positionId)
|
||||||
@@ -297,17 +295,17 @@ public class DoctorStationLabApplyServiceImpl implements IDoctorStationInspectio
|
|||||||
|
|
||||||
// 设置检验项目相关信息
|
// 设置检验项目相关信息
|
||||||
// 医嘱定义 ID(诊疗定义 ID)
|
// 医嘱定义 ID(诊疗定义 ID)
|
||||||
adviceSaveDto.setAdviceDefinitionId(activityDefinitionId);
|
adviceSaveDto.setAdviceDefinitionId(labActivityId);
|
||||||
// 费用定价主表 ID(对应 adm_charge_item 表的 definition_id 字段)
|
// 费用定价主表 ID(对应 adm_charge_item 表的 definition_id 字段)
|
||||||
adviceSaveDto.setDefinitionId(activityDefinitionId);
|
adviceSaveDto.setDefinitionId(labActivityId);
|
||||||
// 医嘱名称
|
// 医嘱名称
|
||||||
adviceSaveDto.setAdviceName(itemName);
|
adviceSaveDto.setAdviceName(itemName);
|
||||||
// 医嘱详细分类
|
// 医嘱详细分类
|
||||||
adviceSaveDto.setCategoryCode(activityDefinition.getCategoryCode());
|
adviceSaveDto.setCategoryCode(labActivityDef.getCategoryCode());
|
||||||
// 活动 ID(诊疗定义 ID)
|
// 活动 ID(诊疗定义 ID)
|
||||||
adviceSaveDto.setActivityId(activityDefinitionId);
|
adviceSaveDto.setActivityId(labActivityId);
|
||||||
// 医嘱定义对应表名
|
// 医嘱定义对应表名
|
||||||
adviceSaveDto.setAdviceTableName("wor_activity_definition");
|
adviceSaveDto.setAdviceTableName("lab_activity_definition");
|
||||||
// 执行科室 ID
|
// 执行科室 ID
|
||||||
adviceSaveDto.setPositionId(positionId);
|
adviceSaveDto.setPositionId(positionId);
|
||||||
|
|
||||||
@@ -346,13 +344,13 @@ public class DoctorStationLabApplyServiceImpl implements IDoctorStationInspectio
|
|||||||
// 请求数量
|
// 请求数量
|
||||||
adviceSaveDto.setQuantity(labApplyItemDto.getItemQty() != null ? labApplyItemDto.getItemQty() : java.math.BigDecimal.ONE);
|
adviceSaveDto.setQuantity(labApplyItemDto.getItemQty() != null ? labApplyItemDto.getItemQty() : java.math.BigDecimal.ONE);
|
||||||
// 请求单位编码(使用诊疗定义的使用单位)
|
// 请求单位编码(使用诊疗定义的使用单位)
|
||||||
adviceSaveDto.setUnitCode(activityDefinition.getPermittedUnitCode());
|
adviceSaveDto.setUnitCode(labActivityDef.getPermittedUnitCode());
|
||||||
|
|
||||||
// 单价处理(BugFix#CodeReview: 根据套餐ID从正确的数据源获取价格)
|
// 单价处理(BugFix#CodeReview: 根据套餐ID从正确的数据源获取价格)
|
||||||
// 套餐项目:从 inspection_basic_information 表获取 package_amount
|
// 套餐项目:从 inspection_basic_information 表获取 package_amount
|
||||||
// 普通项目:使用前端传入的 itemPrice(已从诊疗项目获取)
|
// 普通项目:使用前端传入的 itemPrice(已从诊疗项目获取)
|
||||||
java.math.BigDecimal unitPrice;
|
java.math.BigDecimal unitPrice;
|
||||||
Long feePackageId = activityDefinition.getFeePackageId();
|
Long feePackageId = labActivityDef.getFeePackageId();
|
||||||
|
|
||||||
if (feePackageId != null) {
|
if (feePackageId != null) {
|
||||||
// 套餐项目:查询套餐价格
|
// 套餐项目:查询套餐价格
|
||||||
|
|||||||
@@ -304,6 +304,9 @@ public class EmergencyController {
|
|||||||
@PostMapping("/green-channel/activate")
|
@PostMapping("/green-channel/activate")
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public R<?> activateGreenChannel(@RequestBody EmergencyGreenChannel gc) {
|
public R<?> activateGreenChannel(@RequestBody EmergencyGreenChannel gc) {
|
||||||
|
if (gc.getPatientId() == null) {
|
||||||
|
return R.fail("患者ID不能为空,请选择患者后再激活绿色通道");
|
||||||
|
}
|
||||||
gc.setActivateTime(new Date());
|
gc.setActivateTime(new Date());
|
||||||
gc.setCreateTime(new Date());
|
gc.setCreateTime(new Date());
|
||||||
greenChannelService.save(gc);
|
greenChannelService.save(gc);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import com.healthlink.his.web.inhospitalcharge.dto.*;
|
|||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,11 +31,15 @@ public interface IInHospitalRegisterAppService {
|
|||||||
* @param registeredFlag 已登记标识,已登记传 1 ,待登记传 0
|
* @param registeredFlag 已登记标识,已登记传 1 ,待登记传 0
|
||||||
* @param pageNo 当前页
|
* @param pageNo 当前页
|
||||||
* @param pageSize 每页多少条
|
* @param pageSize 每页多少条
|
||||||
|
* @param startTime 开始时间
|
||||||
|
* @param endTime 结束时间
|
||||||
|
* @param organizationId 入院科室ID
|
||||||
* @param request 请求
|
* @param request 请求
|
||||||
* @return 住院登记信息
|
* @return 住院登记信息
|
||||||
*/
|
*/
|
||||||
IPage<InHospitalRegisterQueryDto> getRegisterInfo(InHospitalRegisterQueryDto inHospitalRegisterQueryDto,
|
IPage<InHospitalRegisterQueryDto> getRegisterInfo(InHospitalRegisterQueryDto inHospitalRegisterQueryDto,
|
||||||
String searchKey, String registeredFlag, Integer pageNo, Integer pageSize, HttpServletRequest request);
|
String searchKey, String registeredFlag, Integer pageNo, Integer pageSize,
|
||||||
|
Date startTime, Date endTime, Long organizationId, HttpServletRequest request);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询患者基本信息
|
* 查询患者基本信息
|
||||||
|
|||||||
@@ -173,7 +173,8 @@ public class InHospitalRegisterAppServiceImpl implements IInHospitalRegisterAppS
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public IPage<InHospitalRegisterQueryDto> getRegisterInfo(InHospitalRegisterQueryDto inHospitalRegisterQueryDto,
|
public IPage<InHospitalRegisterQueryDto> getRegisterInfo(InHospitalRegisterQueryDto inHospitalRegisterQueryDto,
|
||||||
String searchKey, String registeredFlag, Integer pageNo, Integer pageSize, HttpServletRequest request) {
|
String searchKey, String registeredFlag, Integer pageNo, Integer pageSize,
|
||||||
|
Date startTime, Date endTime, Long organizationId, HttpServletRequest request) {
|
||||||
Integer encounterStatus = EncounterZyStatus.TO_BE_REGISTERED.getValue(); // 待登记
|
Integer encounterStatus = EncounterZyStatus.TO_BE_REGISTERED.getValue(); // 待登记
|
||||||
// 构建查询条件
|
// 构建查询条件
|
||||||
QueryWrapper<InHospitalRegisterQueryDto> queryWrapper
|
QueryWrapper<InHospitalRegisterQueryDto> queryWrapper
|
||||||
@@ -182,7 +183,8 @@ public class InHospitalRegisterAppServiceImpl implements IInHospitalRegisterAppS
|
|||||||
|
|
||||||
IPage<InHospitalRegisterQueryDto> inHospitalRegisterInfo = inHospitalRegisterAppMapper
|
IPage<InHospitalRegisterQueryDto> inHospitalRegisterInfo = inHospitalRegisterAppMapper
|
||||||
.getInHospitalRegisterInfo(new Page<>(pageNo, pageSize), EncounterClass.IMP.getValue(), encounterStatus,
|
.getInHospitalRegisterInfo(new Page<>(pageNo, pageSize), EncounterClass.IMP.getValue(), encounterStatus,
|
||||||
registeredFlag, LocationForm.WARD.getValue(), queryWrapper);
|
registeredFlag, LocationForm.WARD.getValue(), startTime, endTime, organizationId,
|
||||||
|
queryWrapper);
|
||||||
inHospitalRegisterInfo.getRecords().forEach(e -> {
|
inHospitalRegisterInfo.getRecords().forEach(e -> {
|
||||||
// 性别
|
// 性别
|
||||||
e.setGenderEnum_enumText(EnumUtils.getInfoByValue(AdministrativeGender.class, e.getGenderEnum()));
|
e.setGenderEnum_enumText(EnumUtils.getInfoByValue(AdministrativeGender.class, e.getGenderEnum()));
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import lombok.AllArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,6 +55,9 @@ public class InHospitalRegisterController {
|
|||||||
* @param registeredFlag 已登记标识,已登记传 1 ,待登记传 0
|
* @param registeredFlag 已登记标识,已登记传 1 ,待登记传 0
|
||||||
* @param pageNo 当前页
|
* @param pageNo 当前页
|
||||||
* @param pageSize 每页多少条
|
* @param pageSize 每页多少条
|
||||||
|
* @param startTime 开始时间
|
||||||
|
* @param endTime 结束时间
|
||||||
|
* @param organizationId 入院科室ID
|
||||||
* @param request 请求
|
* @param request 请求
|
||||||
* @return 住院登记信息
|
* @return 住院登记信息
|
||||||
*/
|
*/
|
||||||
@@ -61,9 +66,13 @@ public class InHospitalRegisterController {
|
|||||||
@RequestParam(value = "searchKey", defaultValue = "") String searchKey,
|
@RequestParam(value = "searchKey", defaultValue = "") String searchKey,
|
||||||
@RequestParam(value = "registeredFlag") String registeredFlag,
|
@RequestParam(value = "registeredFlag") String registeredFlag,
|
||||||
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
|
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
|
||||||
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, HttpServletRequest request) {
|
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
|
||||||
|
@RequestParam(value = "startTime", required = false) Date startTime,
|
||||||
|
@RequestParam(value = "endTime", required = false) Date endTime,
|
||||||
|
@RequestParam(value = "organizationId", required = false) Long organizationId,
|
||||||
|
HttpServletRequest request) {
|
||||||
return R.ok(iInHospitalRegisterAppService.getRegisterInfo(inHospitalRegisterQueryDto, searchKey, registeredFlag,
|
return R.ok(iInHospitalRegisterAppService.getRegisterInfo(inHospitalRegisterQueryDto, searchKey, registeredFlag,
|
||||||
pageNo, pageSize, request));
|
pageNo, pageSize, startTime, endTime, organizationId, request));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -100,5 +100,24 @@ public class InHospitalRegisterQueryDto {
|
|||||||
*/
|
*/
|
||||||
private Integer statusEnum;
|
private Integer statusEnum;
|
||||||
|
|
||||||
}
|
|
||||||
// PLACEHOLDER_FOR_NEW_FIELDS
|
/**
|
||||||
|
* 开始时间(查询条件)
|
||||||
|
*/
|
||||||
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date startTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束时间(查询条件)
|
||||||
|
*/
|
||||||
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date endTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组织ID(查询条件)
|
||||||
|
*/
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
|
private Long organizationId;
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ import com.healthlink.his.web.inhospitalcharge.dto.InHospitalRegisterQueryDto;
|
|||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,12 +28,17 @@ public interface InHospitalRegisterAppMapper {
|
|||||||
* @param encounterStatus 登记状态
|
* @param encounterStatus 登记状态
|
||||||
* @param registeredFlag 已登记标识,已登记传 1 ,待登记传 0
|
* @param registeredFlag 已登记标识,已登记传 1 ,待登记传 0
|
||||||
* @param formEnum 物理位置
|
* @param formEnum 物理位置
|
||||||
|
* @param startTime 开始时间
|
||||||
|
* @param endTime 结束时间
|
||||||
|
* @param organizationId 入院科室ID
|
||||||
* @param queryWrapper 查询条件
|
* @param queryWrapper 查询条件
|
||||||
* @return 住院登记信息
|
* @return 住院登记信息
|
||||||
*/
|
*/
|
||||||
IPage<InHospitalRegisterQueryDto> getInHospitalRegisterInfo(@Param("page") Page<InHospitalRegisterQueryDto> page,
|
IPage<InHospitalRegisterQueryDto> getInHospitalRegisterInfo(@Param("page") Page<InHospitalRegisterQueryDto> page,
|
||||||
@Param("encounterClass") Integer encounterClass, @Param("encounterStatus") Integer encounterStatus,
|
@Param("encounterClass") Integer encounterClass, @Param("encounterStatus") Integer encounterStatus,
|
||||||
@Param("registeredFlag") String registeredFlag, @Param("formEnum") Integer formEnum,
|
@Param("registeredFlag") String registeredFlag, @Param("formEnum") Integer formEnum,
|
||||||
|
@Param("startTime") Date startTime, @Param("endTime") Date endTime,
|
||||||
|
@Param("organizationId") Long organizationId,
|
||||||
@Param(Constants.WRAPPER) QueryWrapper<InHospitalRegisterQueryDto> queryWrapper);
|
@Param(Constants.WRAPPER) QueryWrapper<InHospitalRegisterQueryDto> queryWrapper);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -192,6 +192,9 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
|||||||
// 提取requestStatus手动处理,支持COMPLETED(3)和CHECK_VERIFIED(10)同时查询
|
// 提取requestStatus手动处理,支持COMPLETED(3)和CHECK_VERIFIED(10)同时查询
|
||||||
Integer requestStatus = inpatientAdviceParam.getRequestStatus();
|
Integer requestStatus = inpatientAdviceParam.getRequestStatus();
|
||||||
inpatientAdviceParam.setRequestStatus(null);
|
inpatientAdviceParam.setRequestStatus(null);
|
||||||
|
// Bug #714: 提取deadline手动处理,UNION子查询列名为end_time
|
||||||
|
String deadline = inpatientAdviceParam.getDeadline();
|
||||||
|
inpatientAdviceParam.setDeadline(null);
|
||||||
// 构建查询条件
|
// 构建查询条件
|
||||||
QueryWrapper<InpatientAdviceParam> queryWrapper
|
QueryWrapper<InpatientAdviceParam> queryWrapper
|
||||||
= HisQueryUtils.buildQueryWrapper(inpatientAdviceParam, null, null, null);
|
= HisQueryUtils.buildQueryWrapper(inpatientAdviceParam, null, null, null);
|
||||||
@@ -223,6 +226,16 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
|||||||
if (therapyEnum != null) {
|
if (therapyEnum != null) {
|
||||||
queryWrapper.and(w -> w.eq("therapy_enum", therapyEnum).or().isNull("therapy_enum"));
|
queryWrapper.and(w -> w.eq("therapy_enum", therapyEnum).or().isNull("therapy_enum"));
|
||||||
}
|
}
|
||||||
|
// Bug #714: 手动拼接deadline条件,按医嘱截止时间筛选
|
||||||
|
if (deadline != null && !deadline.isEmpty()) {
|
||||||
|
try {
|
||||||
|
LocalDateTime deadlineTime = LocalDateTime.parse(deadline,
|
||||||
|
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
queryWrapper.le("end_time", deadlineTime);
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
// 忽略无效的日期格式
|
||||||
|
}
|
||||||
|
}
|
||||||
// 患者医嘱分页列表
|
// 患者医嘱分页列表
|
||||||
Page<InpatientAdviceDto> inpatientAdvicePage
|
Page<InpatientAdviceDto> inpatientAdvicePage
|
||||||
= adviceProcessAppMapper.selectInpatientAdvicePage(new Page<>(pageNo, pageSize), queryWrapper,
|
= adviceProcessAppMapper.selectInpatientAdvicePage(new Page<>(pageNo, pageSize), queryWrapper,
|
||||||
@@ -642,6 +655,7 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
|||||||
* @return 操作结果
|
* @return 操作结果
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public R<?> adviceCancel(AdviceExecuteParam adviceExecuteParam) {
|
public R<?> adviceCancel(AdviceExecuteParam adviceExecuteParam) {
|
||||||
// 获取当前执行时间
|
// 获取当前执行时间
|
||||||
Date exeDate = DateUtils.getNowDate();
|
Date exeDate = DateUtils.getNowDate();
|
||||||
@@ -688,6 +702,7 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
|||||||
longMedDispensedList.add(medicationDispense);
|
longMedDispensedList.add(medicationDispense);
|
||||||
} else if (DispenseStatus.EXECUTED.getValue().equals(medicationDispense.getStatusEnum())
|
} else if (DispenseStatus.EXECUTED.getValue().equals(medicationDispense.getStatusEnum())
|
||||||
|| DispenseStatus.SUBMITTED.getValue().equals(medicationDispense.getStatusEnum())) {
|
|| DispenseStatus.SUBMITTED.getValue().equals(medicationDispense.getStatusEnum())) {
|
||||||
|
longMedDispensedList.add(medicationDispense);
|
||||||
longMedUndispenseList.add(medicationDispense);
|
longMedUndispenseList.add(medicationDispense);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -716,6 +731,7 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
|||||||
tempMedDispensedList.add(medicationDispense);
|
tempMedDispensedList.add(medicationDispense);
|
||||||
} else if (DispenseStatus.EXECUTED.getValue().equals(medicationDispense.getStatusEnum())
|
} else if (DispenseStatus.EXECUTED.getValue().equals(medicationDispense.getStatusEnum())
|
||||||
|| DispenseStatus.SUBMITTED.getValue().equals(medicationDispense.getStatusEnum())) {
|
|| DispenseStatus.SUBMITTED.getValue().equals(medicationDispense.getStatusEnum())) {
|
||||||
|
tempMedDispensedList.add(medicationDispense);
|
||||||
tempMedUndispenseList.add(medicationDispense);
|
tempMedUndispenseList.add(medicationDispense);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -863,7 +879,7 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
|||||||
if (!longMedUndispenseList.isEmpty()) {
|
if (!longMedUndispenseList.isEmpty()) {
|
||||||
// 排除已汇总的药品
|
// 排除已汇总的药品
|
||||||
List<MedicationDispense> medicationDispenseList
|
List<MedicationDispense> medicationDispenseList
|
||||||
= tempMedUndispenseList.stream().filter(x -> x.getSummaryNo() == null).toList();
|
= longMedUndispenseList.stream().filter(x -> x.getSummaryNo() == null).toList();
|
||||||
medicationDispenseService
|
medicationDispenseService
|
||||||
.removeByIds(medicationDispenseList.stream().map(MedicationDispense::getId).toList());
|
.removeByIds(medicationDispenseList.stream().map(MedicationDispense::getId).toList());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,10 +150,21 @@ public class MedicineSummaryAppServiceImpl implements IMedicineSummaryAppService
|
|||||||
@Override
|
@Override
|
||||||
public R<?> getMedicineSummaryFormPage(DispenseFormSearchParam dispenseFormSearchParam, Integer pageNo,
|
public R<?> getMedicineSummaryFormPage(DispenseFormSearchParam dispenseFormSearchParam, Integer pageNo,
|
||||||
Integer pageSize, String searchKey, HttpServletRequest request) {
|
Integer pageSize, String searchKey, HttpServletRequest request) {
|
||||||
|
// 就诊ID集合
|
||||||
|
String encounterIds = dispenseFormSearchParam.getEncounterIds();
|
||||||
|
dispenseFormSearchParam.setEncounterIds(null);
|
||||||
|
|
||||||
// 构建查询条件
|
// 构建查询条件
|
||||||
QueryWrapper<DispenseFormSearchParam> queryWrapper = HisQueryUtils.buildQueryWrapper(dispenseFormSearchParam,
|
QueryWrapper<DispenseFormSearchParam> queryWrapper = HisQueryUtils.buildQueryWrapper(dispenseFormSearchParam,
|
||||||
searchKey, new HashSet<>(List.of(CommonConstants.FieldName.BusNo)), request);
|
searchKey, new HashSet<>(List.of(CommonConstants.FieldName.BusNo)), request);
|
||||||
|
|
||||||
|
// 如果传了就诊ID,过滤关联的汇总单
|
||||||
|
if (StringUtils.isNotEmpty(encounterIds)) {
|
||||||
|
queryWrapper.inSql(CommonConstants.FieldName.BusNo,
|
||||||
|
"SELECT DISTINCT summary_no FROM med_medication_dispense " +
|
||||||
|
"WHERE encounter_id IN (" + encounterIds + ") AND summary_no IS NOT NULL");
|
||||||
|
}
|
||||||
|
|
||||||
// 汇总单分页列表
|
// 汇总单分页列表
|
||||||
Page<MedicineSummaryFormDto> medicineSummaryFormPage = medicineSummaryAppMapper.selectMedicineSummaryFormPage(
|
Page<MedicineSummaryFormDto> medicineSummaryFormPage = medicineSummaryAppMapper.selectMedicineSummaryFormPage(
|
||||||
new Page<>(pageNo, pageSize), queryWrapper, DispenseStatus.PREPARATION.getValue(),
|
new Page<>(pageNo, pageSize), queryWrapper, DispenseStatus.PREPARATION.getValue(),
|
||||||
|
|||||||
@@ -11,5 +11,6 @@ public interface IOrderClosedLoopAppService {
|
|||||||
void executeOrder(OrderExecuteRecord record);
|
void executeOrder(OrderExecuteRecord record);
|
||||||
void completeOrder(OrderExecuteRecord record);
|
void completeOrder(OrderExecuteRecord record);
|
||||||
void cancelOrder(OrderExecuteRecord record);
|
void cancelOrder(OrderExecuteRecord record);
|
||||||
Map<String, Object> getStatistics();
|
Map<String, Object> getStatistics(String type, String groupBy, Integer pageNum, Integer pageSize);
|
||||||
|
void remindOrder(Map<String, Object> params);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import org.springframework.jdbc.support.JdbcUtils;
|
||||||
@Service
|
@Service
|
||||||
public class OrderClosedLoopAppServiceImpl implements IOrderClosedLoopAppService {
|
public class OrderClosedLoopAppServiceImpl implements IOrderClosedLoopAppService {
|
||||||
@Autowired private IOrderExecuteRecordService recordService;
|
@Autowired private IOrderExecuteRecordService recordService;
|
||||||
@@ -90,20 +91,128 @@ public class OrderClosedLoopAppServiceImpl implements IOrderClosedLoopAppService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private com.healthlink.his.orderclosedloop.mapper.OrderExecuteRecordMapper recordMapper;
|
||||||
|
|
||||||
|
private long getLong(java.util.Map<String, Object> map, String key) {
|
||||||
|
Object val = map.get(key);
|
||||||
|
if (val == null) {
|
||||||
|
// Try lowercase key (PostgreSQL returns lowercase column names)
|
||||||
|
val = map.get(key.toLowerCase());
|
||||||
|
}
|
||||||
|
return val instanceof Number ? ((Number) val).longValue() : 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double getDouble(java.util.Map<String, Object> map, String key) {
|
||||||
|
Object val = map.get(key);
|
||||||
|
if (val == null) {
|
||||||
|
val = map.get(key.toLowerCase());
|
||||||
|
}
|
||||||
|
return val instanceof Number ? ((Number) val).doubleValue() : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getString(java.util.Map<String, Object> map, String key) {
|
||||||
|
Object val = map.get(key);
|
||||||
|
if (val == null) {
|
||||||
|
val = map.get(key.toLowerCase());
|
||||||
|
}
|
||||||
|
return val != null ? val.toString() : "";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> getStatistics() {
|
public Map<String, Object> getStatistics(String type, String groupBy, Integer pageNum, Integer pageSize) {
|
||||||
|
if ("unclosedWarnings".equals(type)) {
|
||||||
|
return getUnclosedWarnings(pageNum, pageSize);
|
||||||
|
}
|
||||||
|
if (groupBy != null && !groupBy.isEmpty()) {
|
||||||
|
return getGroupStats(groupBy);
|
||||||
|
}
|
||||||
|
return getOverviewStats();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> getOverviewStats() {
|
||||||
Map<String, Object> stats = new HashMap<>();
|
Map<String, Object> stats = new HashMap<>();
|
||||||
long total = recordService.count();
|
List<Map<String, Object>> rows = recordMapper.selectOverviewByType();
|
||||||
long pending = recordService.count(new LambdaQueryWrapper<OrderExecuteRecord>().eq(OrderExecuteRecord::getExecuteStatus, "pending"));
|
String[] rateKeys = {"drugClosedRate", "labClosedRate", "examClosedRate", "treatmentClosedRate"};
|
||||||
long executing = recordService.count(new LambdaQueryWrapper<OrderExecuteRecord>().eq(OrderExecuteRecord::getExecuteStatus, "executing"));
|
String[] types = {"drug", "lab", "exam", "treatment"};
|
||||||
long completed = recordService.count(new LambdaQueryWrapper<OrderExecuteRecord>().eq(OrderExecuteRecord::getExecuteStatus, "completed"));
|
long total = 0;
|
||||||
long cancelled = recordService.count(new LambdaQueryWrapper<OrderExecuteRecord>().eq(OrderExecuteRecord::getExecuteStatus, "cancelled"));
|
for (Map<String, Object> row : rows) {
|
||||||
|
String orderType = getString(row, "orderType");
|
||||||
|
long totalOrders = getLong(row, "totalOrders");
|
||||||
|
long closedCount = getLong(row, "closedCount");
|
||||||
|
total += totalOrders;
|
||||||
|
for (int i = 0; i < types.length; i++) {
|
||||||
|
if (types[i].equals(orderType)) {
|
||||||
|
double rate = totalOrders > 0 ? Math.round(closedCount * 1000.0 / totalOrders) / 10.0 : 0;
|
||||||
|
stats.put(rateKeys[i], rate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
stats.put("total", total);
|
stats.put("total", total);
|
||||||
stats.put("pending", pending);
|
|
||||||
stats.put("executing", executing);
|
|
||||||
stats.put("completed", completed);
|
|
||||||
stats.put("cancelled", cancelled);
|
|
||||||
stats.put("completionRate", total > 0 ? Math.round(completed * 100.0 / total) : 0);
|
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> getGroupStats(String groupBy) {
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
List<Map<String, Object>> dbRows;
|
||||||
|
if ("doctor".equals(groupBy)) {
|
||||||
|
dbRows = recordMapper.selectGroupByDoctor();
|
||||||
|
} else {
|
||||||
|
dbRows = recordMapper.selectGroupByDepartment();
|
||||||
|
}
|
||||||
|
List<Map<String, Object>> records = new ArrayList<>();
|
||||||
|
for (Map<String, Object> row : dbRows) {
|
||||||
|
Map<String, Object> item = new LinkedHashMap<>(row);
|
||||||
|
long totalOrders = getLong(row, "totalOrders");
|
||||||
|
long closedCount = getLong(row, "closedCount");
|
||||||
|
item.put("unclosedCount", totalOrders - closedCount);
|
||||||
|
item.put("closedRate", totalOrders > 0 ? Math.round(closedCount * 1000.0 / totalOrders) / 10.0 : 0);
|
||||||
|
records.add(item);
|
||||||
|
}
|
||||||
|
result.put("records", records);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> getUnclosedWarnings(Integer pageNum, Integer pageSize) {
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
List<Map<String, Object>> rows = recordMapper.selectUnclosedWarnings();
|
||||||
|
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
List<Map<String, Object>> warnings = new ArrayList<>();
|
||||||
|
for (Map<String, Object> row : rows) {
|
||||||
|
Map<String, Object> warning = new LinkedHashMap<>(row);
|
||||||
|
Object orderTimeObj = row.get("orderTime");
|
||||||
|
if (orderTimeObj instanceof java.sql.Timestamp) {
|
||||||
|
long hours = (System.currentTimeMillis() - ((java.sql.Timestamp) orderTimeObj).getTime()) / (1000 * 60 * 60);
|
||||||
|
if (hours > 24) {
|
||||||
|
warning.put("overdueDuration", (hours / 24) + "天" + (hours % 24) + "小时");
|
||||||
|
} else {
|
||||||
|
warning.put("overdueDuration", hours + "小时");
|
||||||
|
}
|
||||||
|
warning.put("orderTime", sdf.format((java.sql.Timestamp) orderTimeObj));
|
||||||
|
} else {
|
||||||
|
warning.put("overdueDuration", "未知");
|
||||||
|
warning.put("orderTime", "");
|
||||||
|
}
|
||||||
|
warnings.add(warning);
|
||||||
|
}
|
||||||
|
result.put("records", warnings);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remindOrder(Map<String, Object> params) {
|
||||||
|
String orderNo = params.get("orderNo") != null ? params.get("orderNo").toString() : null;
|
||||||
|
if (orderNo == null || orderNo.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LambdaQueryWrapper<OrderExecuteRecord> w = new LambdaQueryWrapper<>();
|
||||||
|
w.eq(OrderExecuteRecord::getOrderNo, orderNo);
|
||||||
|
OrderExecuteRecord record = recordService.getOne(w);
|
||||||
|
if (record != null) {
|
||||||
|
record.setUpdateBy("system");
|
||||||
|
record.setUpdateTime(new Date());
|
||||||
|
recordService.updateById(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,17 @@ public class OrderClosedLoopController {
|
|||||||
|
|
||||||
@Operation(summary = "统计")
|
@Operation(summary = "统计")
|
||||||
@GetMapping("/statistics")
|
@GetMapping("/statistics")
|
||||||
public AjaxResult statistics() {
|
public AjaxResult statistics(@RequestParam(required = false) String type,
|
||||||
return AjaxResult.success(appService.getStatistics());
|
@RequestParam(required = false) String groupBy,
|
||||||
|
@RequestParam(required = false) Integer pageNum,
|
||||||
|
@RequestParam(required = false) Integer pageSize) {
|
||||||
|
return AjaxResult.success(appService.getStatistics(type, groupBy, pageNum, pageSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "催办提醒")
|
||||||
|
@PostMapping("/remind")
|
||||||
|
public AjaxResult remind(@RequestBody Map<String, Object> params) {
|
||||||
|
appService.remindOrder(params);
|
||||||
|
return AjaxResult.success("催办提醒已发送");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
|||||||
|
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||||
@@ -227,6 +228,7 @@ public class InHospitalReturnMedicineAppServiceImpl implements IInHospitalReturn
|
|||||||
* @return 处理结果
|
* @return 处理结果
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public R<?> medicineReturn(List<ReturnMedicineDto> medicineReturnList) {
|
public R<?> medicineReturn(List<ReturnMedicineDto> medicineReturnList) {
|
||||||
if (medicineReturnList == null || medicineReturnList.isEmpty()) {
|
if (medicineReturnList == null || medicineReturnList.isEmpty()) {
|
||||||
return R.ok();
|
return R.ok();
|
||||||
@@ -249,6 +251,10 @@ public class InHospitalReturnMedicineAppServiceImpl implements IInHospitalReturn
|
|||||||
// 进销存参数
|
// 进销存参数
|
||||||
List<SupplyItemDetailDto> supplyItemDetailList = new ArrayList<>();
|
List<SupplyItemDetailDto> supplyItemDetailList = new ArrayList<>();
|
||||||
|
|
||||||
|
// 记录未发药(无库存变动)的发药单ID
|
||||||
|
Set<Long> noInventoryUpdateMedIds = new HashSet<>();
|
||||||
|
Set<Long> noInventoryUpdateDevIds = new HashSet<>();
|
||||||
|
|
||||||
// 处理退药
|
// 处理退药
|
||||||
// 获取药品退药id列表
|
// 获取药品退药id列表
|
||||||
List<Long> medReturnIdList = new ArrayList<>();
|
List<Long> medReturnIdList = new ArrayList<>();
|
||||||
@@ -278,6 +284,14 @@ public class InHospitalReturnMedicineAppServiceImpl implements IInHospitalReturn
|
|||||||
throw new ServiceException("药品已退药,请勿重复退药");
|
throw new ServiceException("药品已退药,请勿重复退药");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 在更新退药单状态前,统计出实际没有发药(已发药数量为0/空)的退药单,避免后续加回库存和报错
|
||||||
|
for (MedicationDispense medicationDispense : refundMedList) {
|
||||||
|
if (medicationDispense.getDispenseQuantity() == null
|
||||||
|
|| medicationDispense.getDispenseQuantity().compareTo(BigDecimal.ZERO) == 0) {
|
||||||
|
noInventoryUpdateMedIds.add(medicationDispense.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 更新退药单
|
// 更新退药单
|
||||||
for (MedicationDispense medicationDispense : refundMedList) {
|
for (MedicationDispense medicationDispense : refundMedList) {
|
||||||
// 退药状态
|
// 退药状态
|
||||||
@@ -291,20 +305,22 @@ public class InHospitalReturnMedicineAppServiceImpl implements IInHospitalReturn
|
|||||||
// 退药人
|
// 退药人
|
||||||
medicationDispense.setPractitionerId(SecurityUtils.getLoginUser().getPractitionerId());
|
medicationDispense.setPractitionerId(SecurityUtils.getLoginUser().getPractitionerId());
|
||||||
|
|
||||||
// 设置库存变更参数
|
// 设置库存变更参数(仅针对实际发过药的药品)
|
||||||
SupplyItemDetailDto supplyItemDetailDto = new SupplyItemDetailDto();
|
if (!noInventoryUpdateMedIds.contains(medicationDispense.getId())) {
|
||||||
for (MedicationRequest medicationRequest : refundMedRequestList) {
|
SupplyItemDetailDto supplyItemDetailDto = new SupplyItemDetailDto();
|
||||||
// 根据退药id查询退药请求id(用于医保关联)
|
for (MedicationRequest medicationRequest : refundMedRequestList) {
|
||||||
if (medicationDispense.getMedReqId().equals(medicationRequest.getId())) {
|
// 根据退药id查询退药请求id(用于医保关联)
|
||||||
supplyItemDetailDto.setRequestId(medicationRequest.getRefundMedicineId());
|
if (medicationDispense.getMedReqId().equals(medicationRequest.getId())) {
|
||||||
|
supplyItemDetailDto.setRequestId(medicationRequest.getRefundMedicineId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
supplyItemDetailDto.setItemTable(CommonConstants.TableName.MED_MEDICATION_DEFINITION)
|
||||||
|
.setItemId(medicationDispense.getMedicationId()).setLotNumber(medicationDispense.getLotNumber());
|
||||||
|
supplyItemDetailList.add(supplyItemDetailDto);
|
||||||
}
|
}
|
||||||
supplyItemDetailDto.setItemTable(CommonConstants.TableName.MED_MEDICATION_DEFINITION)
|
|
||||||
.setItemId(medicationDispense.getMedicationId()).setLotNumber(medicationDispense.getLotNumber());
|
|
||||||
supplyItemDetailList.add(supplyItemDetailDto);
|
|
||||||
|
|
||||||
// 追溯码表相关处理
|
// 追溯码表相关处理(仅针对实际发过药的药品)
|
||||||
if (medicationDispense.getTraceNo() != null) {
|
if (!noInventoryUpdateMedIds.contains(medicationDispense.getId()) && medicationDispense.getTraceNo() != null) {
|
||||||
// 使用逗号分割追溯码并转换为List
|
// 使用逗号分割追溯码并转换为List
|
||||||
String[] traceNoList = medicationDispense.getTraceNo().split(CommonConstants.Common.COMMA);
|
String[] traceNoList = medicationDispense.getTraceNo().split(CommonConstants.Common.COMMA);
|
||||||
for (String item : traceNoList) {
|
for (String item : traceNoList) {
|
||||||
@@ -345,7 +361,7 @@ public class InHospitalReturnMedicineAppServiceImpl implements IInHospitalReturn
|
|||||||
devReturnIdList =
|
devReturnIdList =
|
||||||
returnDeviceList.stream().map(ReturnMedicineDto::getDispenseId).collect(Collectors.toList());
|
returnDeviceList.stream().map(ReturnMedicineDto::getDispenseId).collect(Collectors.toList());
|
||||||
// 获取退耗材请求id列表
|
// 获取退耗材请求id列表
|
||||||
List<Long> devRequestIdList = returnDeviceList.stream().map(ReturnMedicineDto::getRequestId).toList();
|
List<Long> devRequestIdList = returnDeviceList.stream().map(ReturnMedicineDto::getRequestId).collect(Collectors.toList());
|
||||||
if (devReturnIdList.isEmpty()) {
|
if (devReturnIdList.isEmpty()) {
|
||||||
throw new ServiceException("请选择要退的耗材");
|
throw new ServiceException("请选择要退的耗材");
|
||||||
}
|
}
|
||||||
@@ -362,6 +378,15 @@ public class InHospitalReturnMedicineAppServiceImpl implements IInHospitalReturn
|
|||||||
.anyMatch(x -> x.equals(DispenseStatus.REFUNDED.getValue()))) {
|
.anyMatch(x -> x.equals(DispenseStatus.REFUNDED.getValue()))) {
|
||||||
throw new ServiceException("耗材已退,请勿重复操作");
|
throw new ServiceException("耗材已退,请勿重复操作");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 在更新退耗材单状态前,统计出实际没有发放(已发放数量为0/空)的退耗材单
|
||||||
|
for (DeviceDispense deviceDispense : refundDevList) {
|
||||||
|
if (deviceDispense.getDispenseQuantity() == null
|
||||||
|
|| deviceDispense.getDispenseQuantity().compareTo(BigDecimal.ZERO) == 0) {
|
||||||
|
noInventoryUpdateDevIds.add(deviceDispense.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 更新退耗材单状态
|
// 更新退耗材单状态
|
||||||
for (DeviceDispense deviceDispense : refundDevList) {
|
for (DeviceDispense deviceDispense : refundDevList) {
|
||||||
// 退药时间
|
// 退药时间
|
||||||
@@ -370,40 +395,20 @@ public class InHospitalReturnMedicineAppServiceImpl implements IInHospitalReturn
|
|||||||
deviceDispense.setDispenseQuantity(deviceDispense.getQuantity());
|
deviceDispense.setDispenseQuantity(deviceDispense.getQuantity());
|
||||||
// 退药状态
|
// 退药状态
|
||||||
deviceDispense.setStatusEnum(DispenseStatus.REFUNDED.getValue());
|
deviceDispense.setStatusEnum(DispenseStatus.REFUNDED.getValue());
|
||||||
// 设置库存变更参数
|
// 设置库存变更参数(仅针对实际发放过的耗材)
|
||||||
supplyItemDetailList
|
if (!noInventoryUpdateDevIds.contains(deviceDispense.getId())) {
|
||||||
.add(new SupplyItemDetailDto().setItemTable(CommonConstants.TableName.ADM_DEVICE_DEFINITION)
|
supplyItemDetailList
|
||||||
.setItemId(deviceDispense.getDeviceDefId()).setLotNumber(deviceDispense.getLotNumber()));
|
.add(new SupplyItemDetailDto().setItemTable(CommonConstants.TableName.ADM_DEVICE_DEFINITION)
|
||||||
// // 使用逗号分割追溯码并转换为List
|
.setItemId(deviceDispense.getDeviceDefId()).setLotNumber(deviceDispense.getLotNumber()));
|
||||||
// String[] traceNoList = deviceDispense.getTraceNo().split(CommonConstants.Common.COMMA);
|
}
|
||||||
// for (String item : traceNoList) {
|
|
||||||
// traceNoManage = new TraceNoManage();
|
|
||||||
// // 追溯码处理
|
|
||||||
// traceNoManage.setItemTable(CommonConstants.TableName.ADM_DEVICE_DEFINITION)
|
|
||||||
// // 项目id
|
|
||||||
// .setItemId(deviceDispense.getDeviceDefId())
|
|
||||||
// // 仓库类型
|
|
||||||
// .setLocationTypeEnum(LocationForm.PHARMACY.getValue())
|
|
||||||
// // 仓库
|
|
||||||
// .setLocationId(deviceDispense.getLocationId())
|
|
||||||
// // 产品批号
|
|
||||||
// .setLotNumber(deviceDispense.getLotNumber())
|
|
||||||
// // 追溯码
|
|
||||||
// .setTraceNo(item)
|
|
||||||
// // 追溯码状态
|
|
||||||
// .setStatusEnum(TraceNoStatus.IN.getValue())
|
|
||||||
// // 追溯码单位
|
|
||||||
// .setUnitCode(deviceDispense.getUnitCode())
|
|
||||||
// // 操作类型
|
|
||||||
// .setOperationType(SupplyType.RETURN_MEDICATION.getValue());
|
|
||||||
// traceNoManageList.add(traceNoManage);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
deviceDispenseService.updateBatchById(refundDevList);
|
deviceDispenseService.updateBatchById(refundDevList);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 追溯码管理表数据追加
|
// 追溯码管理表数据追加
|
||||||
traceNoManageService.saveBatch(traceNoManageList);
|
if (!traceNoManageList.isEmpty()) {
|
||||||
|
traceNoManageService.saveBatch(traceNoManageList);
|
||||||
|
}
|
||||||
|
|
||||||
// 处理退库存
|
// 处理退库存
|
||||||
// 获取库存信息
|
// 获取库存信息
|
||||||
@@ -424,6 +429,11 @@ public class InHospitalReturnMedicineAppServiceImpl implements IInHospitalReturn
|
|||||||
BigDecimal minQuantity = BigDecimal.ZERO;
|
BigDecimal minQuantity = BigDecimal.ZERO;
|
||||||
|
|
||||||
for (UnDispenseInventoryDto unDispenseInventoryDto : inventoryList) {
|
for (UnDispenseInventoryDto unDispenseInventoryDto : inventoryList) {
|
||||||
|
// 过滤未实际发药/发耗材的项目,其库存不加回
|
||||||
|
if (noInventoryUpdateMedIds.contains(unDispenseInventoryDto.getDispenseId())
|
||||||
|
|| noInventoryUpdateDevIds.contains(unDispenseInventoryDto.getDispenseId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
BigDecimal quantity = unDispenseInventoryDto.getQuantity();
|
BigDecimal quantity = unDispenseInventoryDto.getQuantity();
|
||||||
if (!unDispenseInventoryDto.getDispenseUnit()
|
if (!unDispenseInventoryDto.getDispenseUnit()
|
||||||
.equals(unDispenseInventoryDto.getInventoryUnitCode())) {
|
.equals(unDispenseInventoryDto.getInventoryUnitCode())) {
|
||||||
@@ -433,14 +443,19 @@ public class InHospitalReturnMedicineAppServiceImpl implements IInHospitalReturn
|
|||||||
}
|
}
|
||||||
minQuantity = minQuantity.add(quantity);
|
minQuantity = minQuantity.add(quantity);
|
||||||
}
|
}
|
||||||
// 理论上不出bug的情况下以项目id,批号,仓库进行分组处理库存一定唯一所以get(0)
|
// 只有当有需要恢复库存的药品/器材时才加回库存
|
||||||
// 设置待更新的库存信息
|
if (minQuantity.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
inventoryItemList.add(new InventoryItem().setId(inventoryList.get(0).getInventoryId())
|
// 理论上不出bug的情况下以项目id,批号,仓库进行分组处理库存一定唯一所以get(0)
|
||||||
.setQuantity(inventoryList.get(0).getInventoryQuantity().add(minQuantity)));
|
// 设置待更新的库存信息
|
||||||
|
inventoryItemList.add(new InventoryItem().setId(inventoryList.get(0).getInventoryId())
|
||||||
|
.setQuantity(inventoryList.get(0).getInventoryQuantity().add(minQuantity)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 库存更新
|
// 库存更新
|
||||||
iInventoryItemService.updateBatchById(inventoryItemList);
|
if (!inventoryItemList.isEmpty()) {
|
||||||
|
iInventoryItemService.updateBatchById(inventoryItemList);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new ServiceException("请检查库存信息");
|
throw new ServiceException("请检查库存信息");
|
||||||
}
|
}
|
||||||
@@ -497,13 +512,26 @@ public class InHospitalReturnMedicineAppServiceImpl implements IInHospitalReturn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uploadFailedNoList = this.ybReturnIntegrated(medReturnIdList, null);
|
|
||||||
uploadFailedNoList = receiptApprovalAppService.ybInventoryIntegrated(supplyItemDetailList,
|
// 仅对实际发过药(生成了收费记录且计费的)调用医保退货接口
|
||||||
YbInvChgType.OTHER_OUT, DateUtils.getNowDate(), true);
|
List<Long> medReturnIdsForYb = medReturnIdList.stream()
|
||||||
if (uploadFailedNoList != null) {
|
.filter(id -> !noInventoryUpdateMedIds.contains(id))
|
||||||
returnMsg = "3506商品销售退货上传错误,错误项目编码" + uploadFailedNoList;
|
.collect(Collectors.toList());
|
||||||
} else {
|
if (!medReturnIdsForYb.isEmpty()) {
|
||||||
returnMsg = "3506商品销售退货上传成功";
|
uploadFailedNoList = this.ybReturnIntegrated(medReturnIdsForYb, null);
|
||||||
|
if (uploadFailedNoList != null) {
|
||||||
|
returnMsg = "3506商品销售退货上传错误,错误项目编码" + uploadFailedNoList;
|
||||||
|
} else {
|
||||||
|
returnMsg = "3506商品销售退货上传成功";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!supplyItemDetailList.isEmpty()) {
|
||||||
|
uploadFailedNoList = receiptApprovalAppService.ybInventoryIntegrated(supplyItemDetailList,
|
||||||
|
YbInvChgType.OTHER_OUT, DateUtils.getNowDate(), true);
|
||||||
|
if (uploadFailedNoList != null) {
|
||||||
|
returnMsg = (returnMsg != null ? returnMsg + ";" : "") + "医保进销存集成上传错误: " + uploadFailedNoList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 返回退药成功信息
|
// 返回退药成功信息
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public class RationalDrugController {
|
|||||||
|
|
||||||
@GetMapping("/trend")
|
@GetMapping("/trend")
|
||||||
@Operation(summary = "审核趋势")
|
@Operation(summary = "审核趋势")
|
||||||
public AjaxResult getAuditTrend(@RequestParam String startDate) {
|
public AjaxResult getAuditTrend(@RequestParam(required = false) String startDate) {
|
||||||
List<Map<String, Object>> trend = rationalDrugAppService.getAuditTrend(startDate);
|
List<Map<String, Object>> trend = rationalDrugAppService.getAuditTrend(startDate);
|
||||||
return AjaxResult.success(trend);
|
return AjaxResult.success(trend);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -712,6 +712,7 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
|
|||||||
tempServiceRequest.setUnitCode(regAdviceSaveDto.getUnitCode()); // 请求单位编码
|
tempServiceRequest.setUnitCode(regAdviceSaveDto.getUnitCode()); // 请求单位编码
|
||||||
tempServiceRequest.setCategoryEnum(regAdviceSaveDto.getCategoryEnum()); // 请求类型
|
tempServiceRequest.setCategoryEnum(regAdviceSaveDto.getCategoryEnum()); // 请求类型
|
||||||
tempServiceRequest.setTherapyEnum(regAdviceSaveDto.getTherapyEnum()); // 治疗类型,临时(需要前端传)
|
tempServiceRequest.setTherapyEnum(regAdviceSaveDto.getTherapyEnum()); // 治疗类型,临时(需要前端传)
|
||||||
|
tempServiceRequest.setRateCode(regAdviceSaveDto.getRateCode()); // 用药频次
|
||||||
// 文字医嘱(type=8)不走定价体系,activityId设置为0L占位
|
// 文字医嘱(type=8)不走定价体系,activityId设置为0L占位
|
||||||
if (ItemType.TEXT.getValue().equals(regAdviceSaveDto.getAdviceType())) {
|
if (ItemType.TEXT.getValue().equals(regAdviceSaveDto.getAdviceType())) {
|
||||||
tempServiceRequest.setActivityId(0L);
|
tempServiceRequest.setActivityId(0L);
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ public class RequestFormManageController {
|
|||||||
* @return 申请单
|
* @return 申请单
|
||||||
*/
|
*/
|
||||||
@RequestMapping(value = "/page")
|
@RequestMapping(value = "/page")
|
||||||
public R<IPage<RequestFormPageDto>> getRequestFormPage(@RequestBody RequestFormDto requestFormDto) {
|
public R<IPage<RequestFormPageDto>> getRequestFormPage(@ModelAttribute RequestFormDto requestFormDto) {
|
||||||
return R.ok(iRequestFormManageAppService.getRequestFormPage(requestFormDto));
|
return R.ok(iRequestFormManageAppService.getRequestFormPage(requestFormDto));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
-- Fix: prescription_intercept_log missing HisBaseEntity columns
|
||||||
|
ALTER TABLE prescription_intercept_log ADD COLUMN IF NOT EXISTS delete_flag VARCHAR(1) DEFAULT '0';
|
||||||
|
ALTER TABLE prescription_intercept_log ADD COLUMN IF NOT EXISTS create_by VARCHAR(64) DEFAULT '';
|
||||||
|
ALTER TABLE prescription_intercept_log ADD COLUMN IF NOT EXISTS create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
|
||||||
|
ALTER TABLE prescription_intercept_log ADD COLUMN IF NOT EXISTS update_by VARCHAR(64) DEFAULT '';
|
||||||
|
ALTER TABLE prescription_intercept_log ADD COLUMN IF NOT EXISTS update_time TIMESTAMP;
|
||||||
|
ALTER TABLE prescription_intercept_log ADD COLUMN IF NOT EXISTS tenant_id BIGINT DEFAULT 1;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
-- Bug #735: 新医嘱签发后"停嘱医生"字段错误生成数据
|
||||||
|
-- 原因:stopper_name 映射到 update_by 字段,签发时 MyBatis-Plus 自动填充导致错误赋值
|
||||||
|
-- 修复:添加专用 stopper_id 字段,仅在停嘱操作时设置
|
||||||
|
|
||||||
|
-- 药品请求表添加停嘱医生ID字段
|
||||||
|
ALTER TABLE med_medication_request ADD COLUMN IF NOT EXISTS stopper_id BIGINT;
|
||||||
|
|
||||||
|
-- 服务请求表添加停嘱医生ID字段
|
||||||
|
ALTER TABLE wor_service_request ADD COLUMN IF NOT EXISTS stopper_id BIGINT;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
-- 为 sys_audit_log 和 antibiotic_approval 添加 delete_flag 列以匹配 HisBaseEntity 默认映射
|
||||||
|
-- HisBaseEntity.deleteFlag 映射到 delete_flag (MyBatis-Plus camelCase默认)
|
||||||
|
ALTER TABLE sys_audit_log ADD COLUMN IF NOT EXISTS delete_flag CHAR(1) DEFAULT '0';
|
||||||
|
COMMENT ON COLUMN sys_audit_log.delete_flag IS '删除标识(0=正常,1=删除)';
|
||||||
|
UPDATE sys_audit_log SET delete_flag = '0' WHERE delete_flag IS NULL;
|
||||||
|
|
||||||
|
-- antibiotic_approval 表原有 del_flag 列,新增 delete_flag 列供 HisBaseEntity 使用
|
||||||
|
ALTER TABLE antibiotic_approval ADD COLUMN IF NOT EXISTS delete_flag CHAR(1) DEFAULT '0';
|
||||||
|
COMMENT ON COLUMN antibiotic_approval.delete_flag IS '删除标识(0=正常,1=删除)';
|
||||||
|
UPDATE antibiotic_approval SET delete_flag = '0' WHERE delete_flag IS NULL;
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
-- 为 clinical_pathway_execution 添加 HisBaseEntity 所需的基础字段
|
||||||
|
ALTER TABLE clinical_pathway_execution ADD COLUMN IF NOT EXISTS create_by VARCHAR(64);
|
||||||
|
ALTER TABLE clinical_pathway_execution ADD COLUMN IF NOT EXISTS create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
|
||||||
|
ALTER TABLE clinical_pathway_execution ADD COLUMN IF NOT EXISTS update_by VARCHAR(64);
|
||||||
|
ALTER TABLE clinical_pathway_execution ADD COLUMN IF NOT EXISTS update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- 为 prescription_intercept_log 添加 delete_flag 列以匹配 HisBaseEntity 默认映射
|
||||||
|
ALTER TABLE prescription_intercept_log ADD COLUMN IF NOT EXISTS delete_flag CHAR(1) DEFAULT '0';
|
||||||
|
COMMENT ON COLUMN prescription_intercept_log.delete_flag IS '删除标识(0=正常,1=删除)';
|
||||||
|
UPDATE prescription_intercept_log SET delete_flag = '0' WHERE delete_flag IS NULL;
|
||||||
@@ -52,4 +52,5 @@ apl.payment.M00007=\u672A\u67E5\u8BE2\u5230\u6536\u8D39\u9879\u76EE
|
|||||||
apl.payment.M00008=\u672A\u67E5\u8BE2\u5230{0}\u8D26\u6237\u4FE1\u606F
|
apl.payment.M00008=\u672A\u67E5\u8BE2\u5230{0}\u8D26\u6237\u4FE1\u606F
|
||||||
apl.payment.M00009=\u672A\u67E5\u8BE2\u5230\u6536\u8D39\u9879\u76EE\uFF0C\u4E0D\u9700\u8981\u8F6C\u6362\u8D26\u6237
|
apl.payment.M00009=\u672A\u67E5\u8BE2\u5230\u6536\u8D39\u9879\u76EE\uFF0C\u4E0D\u9700\u8981\u8F6C\u6362\u8D26\u6237
|
||||||
apl.adjustPrice.M00001=\u6267\u884C\u5931\u8D25\uFF0C\u672A\u52A0\u8F7D\u5230\u4EFB\u4F55\u6570\u636E\uFF01
|
apl.adjustPrice.M00001=\u6267\u884C\u5931\u8D25\uFF0C\u672A\u52A0\u8F7D\u5230\u4EFB\u4F55\u6570\u636E\uFF01
|
||||||
apl.adjustPrice.M00002=\u6267\u884C\u5931\u8D25\uFF0C\u6539\u4EF7\u5355\u4E2D\u6709\u6B63\u5728\u5BA1\u6838\u4E2D\u7684\u8D27\u54C1\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u65B0\u63D0\u4EA4\uFF01
|
apl.adjustPrice.M00002=\u6267\u884C\u5931\u8D25\uFF0C\u6539\u4EF7\u5355\u4E2D\u6709\u6B63\u5728\u5BA1\u6838\u4E2D\u7684\u8D27\u54C1\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u65B0\u63D0\u4EA4\uFF01
|
||||||
|
apl.yb.M00001={0} catalog does not exist, please contact administrator
|
||||||
|
|||||||
@@ -52,4 +52,5 @@ apl.payment.M00007=\u672A\u67E5\u8BE2\u5230\u6536\u8D39\u9879\u76EE
|
|||||||
apl.payment.M00008=\u672A\u67E5\u8BE2\u5230{0}\u8D26\u6237\u4FE1\u606F
|
apl.payment.M00008=\u672A\u67E5\u8BE2\u5230{0}\u8D26\u6237\u4FE1\u606F
|
||||||
apl.payment.M00009=\u672A\u67E5\u8BE2\u5230\u6536\u8D39\u9879\u76EE\uFF0C\u4E0D\u9700\u8981\u8F6C\u6362\u8D26\u6237
|
apl.payment.M00009=\u672A\u67E5\u8BE2\u5230\u6536\u8D39\u9879\u76EE\uFF0C\u4E0D\u9700\u8981\u8F6C\u6362\u8D26\u6237
|
||||||
apl.adjustPrice.M00001=\u6267\u884C\u5931\u8D25\uFF0C\u672A\u52A0\u8F7D\u5230\u4EFB\u4F55\u6570\u636E\uFF01
|
apl.adjustPrice.M00001=\u6267\u884C\u5931\u8D25\uFF0C\u672A\u52A0\u8F7D\u5230\u4EFB\u4F55\u6570\u636E\uFF01
|
||||||
apl.adjustPrice.M00002=\u6267\u884C\u5931\u8D25\uFF0C\u6539\u4EF7\u5355\u4E2D\u6709\u6B63\u5728\u5BA1\u6838\u4E2D\u7684\u8D27\u54C1\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u65B0\u63D0\u4EA4\uFF01
|
apl.adjustPrice.M00002=\u6267\u884C\u5931\u8D25\uFF0C\u6539\u4EF7\u5355\u4E2D\u6709\u6B63\u5728\u5BA1\u6838\u4E2D\u7684\u8D27\u54C1\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u65B0\u63D0\u4EA4\uFF01
|
||||||
|
apl.yb.M00001={0}\u76EE\u5F55\u4E0D\u5B58\u5728\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
|
||||||
|
|||||||
@@ -217,6 +217,20 @@
|
|||||||
WHERE T1.delete_flag = '0'
|
WHERE T1.delete_flag = '0'
|
||||||
AND T1.class_enum = #{classEnum}
|
AND T1.class_enum = #{classEnum}
|
||||||
AND T10.context_enum = #{register}
|
AND T10.context_enum = #{register}
|
||||||
|
<if test='registerTimeSTime != null'>
|
||||||
|
AND T1.create_time >= CAST(#{registerTimeSTime} AS TIMESTAMP)
|
||||||
|
</if>
|
||||||
|
<if test='registerTimeETime != null'>
|
||||||
|
AND T1.create_time <= CAST(#{registerTimeETime} AS TIMESTAMP)
|
||||||
|
</if>
|
||||||
|
<if test='statusFilter != null'>
|
||||||
|
<if test='statusFilter >= 0'>
|
||||||
|
AND T1.status_enum = #{statusFilter}
|
||||||
|
</if>
|
||||||
|
<if test='statusFilter == -1'>
|
||||||
|
AND T1.status_enum != 6
|
||||||
|
</if>
|
||||||
|
</if>
|
||||||
) AS T9
|
) AS T9
|
||||||
${ew.customSqlSegment}
|
${ew.customSqlSegment}
|
||||||
ORDER BY T9.register_time DESC
|
ORDER BY T9.register_time DESC
|
||||||
|
|||||||
@@ -512,7 +512,7 @@
|
|||||||
personal_account.balance_amount,
|
personal_account.balance_amount,
|
||||||
personal_account.id AS account_id,
|
personal_account.id AS account_id,
|
||||||
T2.category_code,
|
T2.category_code,
|
||||||
ao.name AS org_name
|
COALESCE(ao.name, al1."name") AS org_name
|
||||||
FROM med_medication_request AS T1
|
FROM med_medication_request AS T1
|
||||||
LEFT JOIN med_medication_definition AS T2
|
LEFT JOIN med_medication_definition AS T2
|
||||||
ON T2.id = T1.medication_id
|
ON T2.id = T1.medication_id
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
<collection property="medicineSummaryParamList" ofType="com.healthlink.his.web.inhospitalnursestation.dto.MedicineSummaryParam">
|
<collection property="medicineSummaryParamList" ofType="com.healthlink.his.web.inhospitalnursestation.dto.MedicineSummaryParam">
|
||||||
<result property="procedureId" column="procedure_id"/>
|
<result property="procedureId" column="procedure_id"/>
|
||||||
<result property="dispenseId" column="dispense_id"/>
|
<result property="dispenseId" column="dispense_id"/>
|
||||||
<result property="dispenseTime" column="planned_dispense_time"/>
|
<result property="dispenseTime" column="execution_time"/>
|
||||||
<result property="dispenseStatus" column="dispense_status"/>
|
<result property="dispenseStatus" column="dispense_status"/>
|
||||||
</collection>
|
</collection>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
ii.admitting_doctor_name,
|
ii.admitting_doctor_name,
|
||||||
ii.balance_amount,
|
ii.balance_amount,
|
||||||
ii.dispense_id,
|
ii.dispense_id,
|
||||||
ii.planned_dispense_time,
|
ii.execution_time,
|
||||||
ii.procedure_id,
|
ii.procedure_id,
|
||||||
ii.dispense_status
|
ii.dispense_status
|
||||||
FROM (( SELECT T1.encounter_id,
|
FROM (( SELECT T1.encounter_id,
|
||||||
@@ -113,7 +113,7 @@
|
|||||||
pra."name" AS admitting_doctor_name,
|
pra."name" AS admitting_doctor_name,
|
||||||
personal_account.balance_amount,
|
personal_account.balance_amount,
|
||||||
mmd.id AS dispense_id,
|
mmd.id AS dispense_id,
|
||||||
mmd.planned_dispense_time,
|
cp.occurrence_time AS execution_time,
|
||||||
mmd.procedure_id,
|
mmd.procedure_id,
|
||||||
mmd.status_enum AS dispense_status
|
mmd.status_enum AS dispense_status
|
||||||
FROM med_medication_request AS T1
|
FROM med_medication_request AS T1
|
||||||
@@ -121,6 +121,9 @@
|
|||||||
ON T1.id = mmd.med_req_id
|
ON T1.id = mmd.med_req_id
|
||||||
AND mmd.delete_flag = '0'
|
AND mmd.delete_flag = '0'
|
||||||
AND mmd.status_enum != #{summarized}
|
AND mmd.status_enum != #{summarized}
|
||||||
|
LEFT JOIN cli_procedure cp
|
||||||
|
ON cp.id = mmd.procedure_id
|
||||||
|
AND cp.delete_flag = '0'
|
||||||
LEFT JOIN med_medication_definition AS T2
|
LEFT JOIN med_medication_definition AS T2
|
||||||
ON T2.id = T1.medication_id
|
ON T2.id = T1.medication_id
|
||||||
AND T2.delete_flag = '0'
|
AND T2.delete_flag = '0'
|
||||||
@@ -200,7 +203,7 @@
|
|||||||
AND T1.status_enum = #{completed}
|
AND T1.status_enum = #{completed}
|
||||||
AND T1.refund_medicine_id IS NULL
|
AND T1.refund_medicine_id IS NULL
|
||||||
AND mmd.procedure_id IS NOT NULL
|
AND mmd.procedure_id IS NOT NULL
|
||||||
ORDER BY mmd.planned_dispense_time )) AS ii
|
ORDER BY cp.occurrence_time )) AS ii
|
||||||
${ew.customSqlSegment}
|
${ew.customSqlSegment}
|
||||||
</select>
|
</select>
|
||||||
<select id="selectMedicineSummaryFormPage"
|
<select id="selectMedicineSummaryFormPage"
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
<mapper namespace="com.healthlink.his.web.pharmacymanage.mapper.InHospitalReturnMedicineAppMapper">
|
<mapper namespace="com.healthlink.his.web.pharmacymanage.mapper.InHospitalReturnMedicineAppMapper">
|
||||||
<select id="selectEncounterInfoListPage" resultType="com.healthlink.his.web.pharmacymanage.dto.EncounterInfoDto">
|
<select id="selectEncounterInfoListPage" resultType="com.healthlink.his.web.pharmacymanage.dto.EncounterInfoDto">
|
||||||
SELECT ii.reception_time,
|
SELECT MAX(ii.reception_time) AS reception_time,
|
||||||
ii.start_time,
|
MAX(ii.start_time) AS start_time,
|
||||||
ii.encounter_id,
|
ii.encounter_id,
|
||||||
ii.encounter_no,
|
ii.encounter_no,
|
||||||
ii.refund_enum,
|
MAX(ii.refund_enum) AS refund_enum,
|
||||||
ii.patient_name,
|
ii.patient_name,
|
||||||
ii.patient_wb_str,
|
ii.patient_wb_str,
|
||||||
ii.patient_py_str,
|
ii.patient_py_str,
|
||||||
@@ -15,11 +15,11 @@
|
|||||||
ii.birth_date,
|
ii.birth_date,
|
||||||
ii.department_name
|
ii.department_name
|
||||||
FROM (
|
FROM (
|
||||||
SELECT ae.reception_time,
|
SELECT mmd.create_time AS reception_time,
|
||||||
ae.id AS encounter_id,
|
ae.id AS encounter_id,
|
||||||
ae.bus_no AS encounter_no,
|
ae.bus_no AS encounter_no,
|
||||||
ae.tenant_id,
|
ae.tenant_id,
|
||||||
ae.start_time,
|
mmd.create_time AS start_time,
|
||||||
ae.class_enum,
|
ae.class_enum,
|
||||||
mmd.status_enum AS refund_enum,
|
mmd.status_enum AS refund_enum,
|
||||||
ap."name" AS patient_name,
|
ap."name" AS patient_name,
|
||||||
@@ -52,11 +52,11 @@
|
|||||||
AND mmd.status_enum = #{refundStatus}
|
AND mmd.status_enum = #{refundStatus}
|
||||||
</if>
|
</if>
|
||||||
UNION
|
UNION
|
||||||
SELECT ae.reception_time,
|
SELECT wdd.create_time AS reception_time,
|
||||||
ae.id AS encounter_id,
|
ae.id AS encounter_id,
|
||||||
ae.bus_no AS encounter_no,
|
ae.bus_no AS encounter_no,
|
||||||
ae.tenant_id,
|
ae.tenant_id,
|
||||||
ae.start_time,
|
wdd.create_time AS start_time,
|
||||||
ae.class_enum,
|
ae.class_enum,
|
||||||
wdd.status_enum AS refund_enum,
|
wdd.status_enum AS refund_enum,
|
||||||
ap."name" AS patient_name,
|
ap."name" AS patient_name,
|
||||||
@@ -90,7 +90,16 @@
|
|||||||
</if>
|
</if>
|
||||||
) AS ii
|
) AS ii
|
||||||
${ew.customSqlSegment}
|
${ew.customSqlSegment}
|
||||||
ORDER BY ii.reception_time DESC
|
GROUP BY ii.encounter_id,
|
||||||
|
ii.encounter_no,
|
||||||
|
ii.patient_name,
|
||||||
|
ii.patient_wb_str,
|
||||||
|
ii.patient_py_str,
|
||||||
|
ii.id_card,
|
||||||
|
ii.gender_enum,
|
||||||
|
ii.birth_date,
|
||||||
|
ii.department_name
|
||||||
|
ORDER BY reception_time DESC
|
||||||
</select>
|
</select>
|
||||||
<select id="selectReturnMedicineInfo"
|
<select id="selectReturnMedicineInfo"
|
||||||
resultType="com.healthlink.his.web.pharmacymanage.dto.ReturnMedicineInfoDto">
|
resultType="com.healthlink.his.web.pharmacymanage.dto.ReturnMedicineInfoDto">
|
||||||
|
|||||||
@@ -108,8 +108,6 @@
|
|||||||
<if test="statusEnum == 18">
|
<if test="statusEnum == 18">
|
||||||
T4.status_enum = #{submitted}
|
T4.status_enum = #{submitted}
|
||||||
</if>
|
</if>
|
||||||
AND T4.summary_no IS NOT NULL
|
|
||||||
AND T4.summary_no != ''
|
|
||||||
) AS ii
|
) AS ii
|
||||||
${ew.customSqlSegment}
|
${ew.customSqlSegment}
|
||||||
GROUP BY ii.encounter_id,
|
GROUP BY ii.encounter_id,
|
||||||
@@ -268,8 +266,6 @@
|
|||||||
AND T15.delete_flag = '0'
|
AND T15.delete_flag = '0'
|
||||||
WHERE T1.delete_flag = '0'
|
WHERE T1.delete_flag = '0'
|
||||||
-- 因发药配药合并,前台只能看到待发药,已发药状态,但是后台配药发药状态都查
|
-- 因发药配药合并,前台只能看到待发药,已发药状态,但是后台配药发药状态都查
|
||||||
AND T1.summary_no IS NOT NULL
|
|
||||||
AND T1.summary_no != ''
|
|
||||||
AND
|
AND
|
||||||
<if test="dispenseStatus == null">
|
<if test="dispenseStatus == null">
|
||||||
T1.status_enum IN (#{inProgress},#{completed},#{preparation},#{prepared},#{summarized})
|
T1.status_enum IN (#{inProgress},#{completed},#{preparation},#{prepared},#{summarized})
|
||||||
|
|||||||
@@ -222,8 +222,8 @@
|
|||||||
T1.based_on_id AS based_on_id,
|
T1.based_on_id AS based_on_id,
|
||||||
T1.medication_id AS advice_definition_id,
|
T1.medication_id AS advice_definition_id,
|
||||||
T1.content_json::jsonb ->> 'remark' AS remark,
|
T1.content_json::jsonb ->> 'remark' AS remark,
|
||||||
T1.effective_dose_end AS stop_time,
|
CASE WHEN T1.status_enum = 6 THEN T1.effective_dose_end ELSE NULL END AS stop_time,
|
||||||
T1.update_by AS stop_user_name
|
CASE WHEN T1.status_enum = 6 THEN T1.update_by ELSE NULL END AS stop_user_name
|
||||||
FROM med_medication_request AS T1
|
FROM med_medication_request AS T1
|
||||||
LEFT JOIN adm_practitioner AS ap ON ap.id = T1.practitioner_id AND ap.delete_flag = '0'
|
LEFT JOIN adm_practitioner AS ap ON ap.id = T1.practitioner_id AND ap.delete_flag = '0'
|
||||||
LEFT JOIN med_medication_definition AS T2 ON T2.ID = T1.medication_id
|
LEFT JOIN med_medication_definition AS T2 ON T2.ID = T1.medication_id
|
||||||
@@ -339,8 +339,8 @@
|
|||||||
T1.based_on_id AS based_on_id,
|
T1.based_on_id AS based_on_id,
|
||||||
T1.activity_id AS advice_definition_id,
|
T1.activity_id AS advice_definition_id,
|
||||||
T1.remark AS remark,
|
T1.remark AS remark,
|
||||||
T1.occurrence_end_time AS stop_time,
|
CASE WHEN T1.status_enum = 6 THEN T1.occurrence_end_time ELSE NULL END AS stop_time,
|
||||||
T1.update_by AS stop_user_name
|
CASE WHEN T1.status_enum = 6 THEN T1.update_by ELSE NULL END AS stop_user_name
|
||||||
FROM wor_service_request AS T1
|
FROM wor_service_request AS T1
|
||||||
LEFT JOIN adm_practitioner AS ap ON ap.id = T1.requester_id AND ap.delete_flag = '0'
|
LEFT JOIN adm_practitioner AS ap ON ap.id = T1.requester_id AND ap.delete_flag = '0'
|
||||||
LEFT JOIN wor_activity_definition AS T2
|
LEFT JOIN wor_activity_definition AS T2
|
||||||
|
|||||||
@@ -1,16 +1,31 @@
|
|||||||
package com.healthlink.his.antibiotic.domain;
|
package com.healthlink.his.antibiotic.domain;
|
||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
|
||||||
import com.core.common.core.domain.HisBaseEntity;
|
import com.core.common.core.domain.HisBaseEntity;
|
||||||
import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@Data @TableName("antibiotic_approval") @Accessors(chain = true) @EqualsAndHashCode(callSuper = false)
|
|
||||||
|
@Data
|
||||||
|
@TableName("antibiotic_approval")
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class AntibioticApproval extends HisBaseEntity {
|
public class AntibioticApproval extends HisBaseEntity {
|
||||||
@TableId(type = IdType.ASSIGN_ID) private Long id;
|
@TableId(type = IdType.ASSIGN_ID)
|
||||||
private Long encounterId; private Long patientId;
|
private Long id;
|
||||||
private String drugCode; private String drugName; private String antibioticClass;
|
private Long encounterId;
|
||||||
private Long requesterId; private String requesterName;
|
private Long patientId;
|
||||||
private Long approverId; private String approverName; private Date approvalTime;
|
private String drugCode;
|
||||||
private String approvalResult; private String reason; private String status; private String delFlag;
|
private String drugName;
|
||||||
}
|
private String antibioticClass;
|
||||||
|
private Long requesterId;
|
||||||
|
private String requesterName;
|
||||||
|
private Long approverId;
|
||||||
|
private String approverName;
|
||||||
|
private Date approvalTime;
|
||||||
|
private String approvalResult;
|
||||||
|
private String reason;
|
||||||
|
private String status;
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ public class TicketSlotDTO {
|
|||||||
private String patientName;
|
private String patientName;
|
||||||
private String medicalCard;
|
private String medicalCard;
|
||||||
private Long patientId;
|
private Long patientId;
|
||||||
|
private Long realPatientId;
|
||||||
private String phone;
|
private String phone;
|
||||||
private Integer orderStatus;
|
private Integer orderStatus;
|
||||||
private Long orderId;
|
private Long orderId;
|
||||||
|
|||||||
@@ -1,5 +1,54 @@
|
|||||||
package com.healthlink.his.orderclosedloop.mapper;
|
package com.healthlink.his.orderclosedloop.mapper;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.healthlink.his.orderclosedloop.domain.OrderExecuteRecord;
|
import com.healthlink.his.orderclosedloop.domain.OrderExecuteRecord;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
@Mapper public interface OrderExecuteRecordMapper extends BaseMapper<OrderExecuteRecord> {}
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface OrderExecuteRecordMapper extends BaseMapper<OrderExecuteRecord> {
|
||||||
|
|
||||||
|
@Select("SELECT m.department_name FROM order_main m WHERE m.order_no = #{orderNo} AND m.delete_flag = '0' LIMIT 1")
|
||||||
|
String findDepartmentByOrderNo(@Param("orderNo") String orderNo);
|
||||||
|
|
||||||
|
@Select("SELECT e.order_type AS orderType, " +
|
||||||
|
"COUNT(*) AS totalOrders, " +
|
||||||
|
"COUNT(CASE WHEN e.execute_status = 'completed' THEN 1 END) AS closedCount " +
|
||||||
|
"FROM order_execute_record e " +
|
||||||
|
"WHERE e.delete_flag = '0' AND e.execute_status != 'cancelled' " +
|
||||||
|
"GROUP BY e.order_type")
|
||||||
|
List<Map<String, Object>> selectOverviewByType();
|
||||||
|
|
||||||
|
@Select("SELECT COALESCE(m.department_name, '未知') AS department, " +
|
||||||
|
"COUNT(*) AS totalOrders, " +
|
||||||
|
"COUNT(CASE WHEN e.execute_status = 'completed' THEN 1 END) AS closedCount " +
|
||||||
|
"FROM order_execute_record e " +
|
||||||
|
"LEFT JOIN order_main m ON e.order_no = m.order_no AND m.delete_flag = '0' " +
|
||||||
|
"WHERE e.delete_flag = '0' AND e.execute_status != 'cancelled' " +
|
||||||
|
"GROUP BY m.department_name ORDER BY totalOrders DESC")
|
||||||
|
List<Map<String, Object>> selectGroupByDepartment();
|
||||||
|
|
||||||
|
@Select("SELECT COALESCE(m.doctor_name, '未知') AS doctorName, " +
|
||||||
|
"COUNT(*) AS totalOrders, " +
|
||||||
|
"COUNT(CASE WHEN e.execute_status = 'completed' THEN 1 END) AS closedCount " +
|
||||||
|
"FROM order_execute_record e " +
|
||||||
|
"LEFT JOIN order_main m ON e.order_no = m.order_no AND m.delete_flag = '0' " +
|
||||||
|
"WHERE e.delete_flag = '0' AND e.execute_status != 'cancelled' " +
|
||||||
|
"GROUP BY m.doctor_name ORDER BY totalOrders DESC")
|
||||||
|
List<Map<String, Object>> selectGroupByDoctor();
|
||||||
|
|
||||||
|
@Select("SELECT e.order_no AS orderNo, e.patient_name AS patientName, e.order_type AS orderType, " +
|
||||||
|
"COALESCE(m.department_name, '未知') AS department, " +
|
||||||
|
"COALESCE(m.doctor_name, '未知') AS doctorName, " +
|
||||||
|
"e.current_step AS currentStep, e.create_time AS orderTime " +
|
||||||
|
"FROM order_execute_record e " +
|
||||||
|
"LEFT JOIN order_main m ON e.order_no = m.order_no AND m.delete_flag = '0' " +
|
||||||
|
"WHERE e.delete_flag = '0' " +
|
||||||
|
"AND e.execute_status IN ('pending', 'in_progress', 'overdue', 'executing') " +
|
||||||
|
"ORDER BY e.create_time DESC")
|
||||||
|
List<Map<String, Object>> selectUnclosedWarnings();
|
||||||
|
}
|
||||||
@@ -25,4 +25,4 @@ public class SysAuditLog extends HisBaseEntity {
|
|||||||
private String result;
|
private String result;
|
||||||
private String errorMsg;
|
private String errorMsg;
|
||||||
private Integer durationMs;
|
private Integer durationMs;
|
||||||
}
|
}
|
||||||
@@ -1317,6 +1317,9 @@ public class YbDao {
|
|||||||
public List<Settlement3201DetailDto> reconcileGeneralLedgerDetail(Settlement3201WebParam settlement3201WebParam) {
|
public List<Settlement3201DetailDto> reconcileGeneralLedgerDetail(Settlement3201WebParam settlement3201WebParam) {
|
||||||
// 获取条件
|
// 获取条件
|
||||||
String clrType = settlement3201WebParam.getClrType();// 住院 or 门诊
|
String clrType = settlement3201WebParam.getClrType();// 住院 or 门诊
|
||||||
|
if (StringUtils.isEmpty(clrType)) {
|
||||||
|
throw new ServiceException("请选择医疗类型:住院/门诊");
|
||||||
|
}
|
||||||
Integer kindEnum;
|
Integer kindEnum;
|
||||||
if (clrType.equals(YbClrType.OUTPATIENT_CLINIC.getValue())) {
|
if (clrType.equals(YbClrType.OUTPATIENT_CLINIC.getValue())) {
|
||||||
kindEnum = PaymentKind.OUTPATIENT_CLINIC.getValue();
|
kindEnum = PaymentKind.OUTPATIENT_CLINIC.getValue();
|
||||||
|
|||||||
@@ -111,6 +111,7 @@
|
|||||||
o.order_no AS orderNo,
|
o.order_no AS orderNo,
|
||||||
COALESCE(CAST(o.gender AS VARCHAR), CAST(pinfo.gender_enum AS VARCHAR)) AS patientGender,
|
COALESCE(CAST(o.gender AS VARCHAR), CAST(pinfo.gender_enum AS VARCHAR)) AS patientGender,
|
||||||
pinfo.gender_enum AS genderEnum,
|
pinfo.gender_enum AS genderEnum,
|
||||||
|
pinfo.id AS realPatientId,
|
||||||
pinfo.id_card AS idCard,
|
pinfo.id_card AS idCard,
|
||||||
o.appointment_time AS appointmentTime,
|
o.appointment_time AS appointmentTime,
|
||||||
<include refid="orderStatusNormExpr" /> AS orderStatus,
|
<include refid="orderStatusNormExpr" /> AS orderStatus,
|
||||||
@@ -230,6 +231,7 @@
|
|||||||
o.order_no AS orderNo,
|
o.order_no AS orderNo,
|
||||||
COALESCE(CAST(o.gender AS VARCHAR), CAST(pinfo.gender_enum AS VARCHAR)) AS patientGender,
|
COALESCE(CAST(o.gender AS VARCHAR), CAST(pinfo.gender_enum AS VARCHAR)) AS patientGender,
|
||||||
pinfo.gender_enum AS genderEnum,
|
pinfo.gender_enum AS genderEnum,
|
||||||
|
pinfo.id AS realPatientId,
|
||||||
pinfo.id_card AS idCard,
|
pinfo.id_card AS idCard,
|
||||||
o.appointment_time AS appointmentTime,
|
o.appointment_time AS appointmentTime,
|
||||||
<include refid="orderStatusNormExpr" /> AS orderStatus,
|
<include refid="orderStatusNormExpr" /> AS orderStatus,
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
AND account.contract_no = #{contractNo}
|
AND account.contract_no = #{contractNo}
|
||||||
</if>
|
</if>
|
||||||
GROUP BY payment.ID,
|
GROUP BY payment.ID,
|
||||||
account.ID
|
account.ID,
|
||||||
|
account.contract_no
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
export function createRecord(data) { return request({ url: '/healthlink-his/api/v1/anesthesia/record', method: 'post', data }) }
|
export function createRecord(data) { return request({ url: '/api/v1/anesthesia/record', method: 'post', data }) }
|
||||||
export function updateRecord(data) { return request({ url: '/healthlink-his/api/v1/anesthesia/record', method: 'put', data }) }
|
export function updateRecord(data) { return request({ url: '/api/v1/anesthesia/record', method: 'put', data }) }
|
||||||
export function getRecordDetail(id) { return request({ url: '/healthlink-his/api/v1/anesthesia/record/' + id, method: 'get' }) }
|
export function getRecordDetail(id) { return request({ url: '/api/v1/anesthesia/record/' + id, method: 'get' }) }
|
||||||
export function getByEncounter(encounterId) { return request({ url: '/healthlink-his/api/v1/anesthesia/record/encounter/' + encounterId, method: 'get' }) }
|
export function getByEncounter(encounterId) { return request({ url: '/api/v1/anesthesia/record/encounter/' + encounterId, method: 'get' }) }
|
||||||
export function getVitalSigns(recordId) { return request({ url: '/healthlink-his/api/v1/anesthesia/vital-sign/' + recordId, method: 'get' }) }
|
export function getVitalSigns(recordId) { return request({ url: '/api/v1/anesthesia/vital-sign/' + recordId, method: 'get' }) }
|
||||||
export function getMedications(recordId) { return request({ url: '/healthlink-his/api/v1/anesthesia/medication/' + recordId, method: 'get' }) }
|
export function getMedications(recordId) { return request({ url: '/api/v1/anesthesia/medication/' + recordId, method: 'get' }) }
|
||||||
export function getIoSummary(recordId) { return request({ url: '/healthlink-his/api/v1/anesthesia/io-summary/' + recordId, method: 'get' }) }
|
export function getIoSummary(recordId) { return request({ url: '/api/v1/anesthesia/io-summary/' + recordId, method: 'get' }) }
|
||||||
export function completeRecord(id) { return request({ url: '/healthlink-his/api/v1/anesthesia/complete/' + id, method: 'put' }) }
|
export function completeRecord(id) { return request({ url: '/api/v1/anesthesia/complete/' + id, method: 'put' }) }
|
||||||
|
|||||||
@@ -2,23 +2,23 @@ import request from '@/utils/request'
|
|||||||
|
|
||||||
// ==================== 抗菌药物管控 ====================
|
// ==================== 抗菌药物管控 ====================
|
||||||
export function getRules(drugCode) {
|
export function getRules(drugCode) {
|
||||||
return request({ url: `/healthlink-his/api/v1/antibiotic/rules/${drugCode}`, method: 'get' })
|
return request({ url: `/api/v1/antibiotic/rules/${drugCode}`, method: 'get' })
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkRestriction(drugCode, doctorLevel) {
|
export function checkRestriction(drugCode, doctorLevel) {
|
||||||
return request({ url: '/healthlink-his/api/v1/antibiotic/check-restriction', method: 'get', params: { drugCode, doctorLevel } })
|
return request({ url: '/api/v1/antibiotic/check-restriction', method: 'get', params: { drugCode, doctorLevel } })
|
||||||
}
|
}
|
||||||
|
|
||||||
export function requestApproval(data) {
|
export function requestApproval(data) {
|
||||||
return request({ url: '/healthlink-his/api/v1/antibiotic/approval', method: 'post', data })
|
return request({ url: '/api/v1/antibiotic/approval', method: 'post', data })
|
||||||
}
|
}
|
||||||
|
|
||||||
export function approve(id, approverId, approverName, result) {
|
export function approve(id, approverId, approverName, result) {
|
||||||
return request({ url: `/healthlink-his/api/v1/antibiotic/approval/${id}`, method: 'put', params: { approverId, approverName, result } })
|
return request({ url: `/api/v1/antibiotic/approval/${id}`, method: 'put', params: { approverId, approverName, result } })
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getStatistics(startDate, endDate) {
|
export function getStatistics(startDate, endDate) {
|
||||||
return request({ url: '/healthlink-his/api/v1/antibiotic/statistics', method: 'get', params: { startDate, endDate } })
|
return request({ url: '/api/v1/antibiotic/statistics', method: 'get', params: { startDate, endDate } })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新增抗菌药物规则
|
// 新增抗菌药物规则
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
export function getRules(drugCode) { return request({ url: '/healthlink-his/api/v1/antibiotic/rules/' + drugCode, method: 'get' }) }
|
export function getRules(drugCode) { return request({ url: '/api/v1/antibiotic/rules/' + drugCode, method: 'get' }) }
|
||||||
export function checkRestriction(drugCode, doctorLevel) { return request({ url: '/healthlink-his/api/v1/antibiotic/check-restriction', method: 'get', params: { drugCode, doctorLevel } }) }
|
export function checkRestriction(drugCode, doctorLevel) { return request({ url: '/api/v1/antibiotic/check-restriction', method: 'get', params: { drugCode, doctorLevel } }) }
|
||||||
export function requestApproval(data) { return request({ url: '/healthlink-his/api/v1/antibiotic/approval', method: 'post', data }) }
|
export function requestApproval(data) { return request({ url: '/api/v1/antibiotic/approval', method: 'post', data }) }
|
||||||
export function approve(id, params) { return request({ url: '/healthlink-his/api/v1/antibiotic/approval/' + id, method: 'put', params }) }
|
export function approve(id, params) { return request({ url: '/api/v1/antibiotic/approval/' + id, method: 'put', params }) }
|
||||||
export function getStatistics() { return request({ url: '/healthlink-his/api/v1/antibiotic/statistics', method: 'get' }) }
|
export function getStatistics() { return request({ url: '/api/v1/antibiotic/statistics', method: 'get' }) }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
export function verifySignature(documentType, documentId) { return request({ url: '/healthlink-his/api/v1/ca-signature/verify/' + documentType + '/' + documentId, method: 'get' }) }
|
export function verifySignature(documentType, documentId) { return request({ url: '/api/v1/ca-signature/verify/' + documentType + '/' + documentId, method: 'get' }) }
|
||||||
export function getSignatureHistory(documentType, documentId) { return request({ url: '/healthlink-his/api/v1/ca-signature/history/' + documentType + '/' + documentId, method: 'get' }) }
|
export function getSignatureHistory(documentType, documentId) { return request({ url: '/api/v1/ca-signature/history/' + documentType + '/' + documentId, method: 'get' }) }
|
||||||
export function revokeSignature(id) { return request({ url: '/healthlink-his/api/v1/ca-signature/revoke/' + id, method: 'put' }) }
|
export function revokeSignature(id) { return request({ url: '/api/v1/ca-signature/revoke/' + id, method: 'put' }) }
|
||||||
export function getSignatureStatistics() { return request({ url: '/healthlink-his/api/v1/ca-signature/statistics', method: 'get' }) }
|
export function getSignatureStatistics() { return request({ url: '/api/v1/ca-signature/statistics', method: 'get' }) }
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import request from '@/utils/request'
|
|||||||
// 查询会诊申请列表
|
// 查询会诊申请列表
|
||||||
export function listRequest(query) {
|
export function listRequest(query) {
|
||||||
return request({
|
return request({
|
||||||
url: '/consultation/request/list',
|
url: '/consultation/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
})
|
})
|
||||||
@@ -12,7 +12,7 @@ export function listRequest(query) {
|
|||||||
// 查询会诊申请详细
|
// 查询会诊申请详细
|
||||||
export function getRequest(id) {
|
export function getRequest(id) {
|
||||||
return request({
|
return request({
|
||||||
url: '/consultation/request/' + id,
|
url: '/consultation/detail/' + id,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,7 @@ export function getRequest(id) {
|
|||||||
// 新增会诊申请
|
// 新增会诊申请
|
||||||
export function addRequest(data) {
|
export function addRequest(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/consultation/request',
|
url: '/consultation/save',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
@@ -29,8 +29,8 @@ export function addRequest(data) {
|
|||||||
// 修改会诊申请
|
// 修改会诊申请
|
||||||
export function updateRequest(data) {
|
export function updateRequest(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/consultation/request',
|
url: '/consultation/save',
|
||||||
method: 'put',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -38,48 +38,48 @@ export function updateRequest(data) {
|
|||||||
// 删除会诊申请
|
// 删除会诊申请
|
||||||
export function delRequest(id) {
|
export function delRequest(id) {
|
||||||
return request({
|
return request({
|
||||||
url: '/consultation/request/' + id,
|
url: '/consultation/cancel/' + id,
|
||||||
method: 'delete'
|
method: 'post'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提交会诊申请
|
// 提交会诊申请
|
||||||
export function submitRequest(id) {
|
export function submitRequest(id) {
|
||||||
return request({
|
return request({
|
||||||
url: '/consultation/request/submit/' + id,
|
url: '/consultation/submit/' + id,
|
||||||
method: 'put'
|
method: 'post'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 取消提交会诊申请
|
// 取消提交会诊申请
|
||||||
export function cancelSubmitRequest(id) {
|
export function cancelSubmitRequest(id) {
|
||||||
return request({
|
return request({
|
||||||
url: '/consultation/request/cancelSubmit/' + id,
|
url: '/consultation/cancel/' + id,
|
||||||
method: 'put'
|
method: 'post'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 结束会诊申请
|
// 结束会诊申请
|
||||||
export function endRequest(id) {
|
export function endRequest(id) {
|
||||||
return request({
|
return request({
|
||||||
url: '/consultation/request/end/' + id,
|
url: '/consultation/complete/' + id,
|
||||||
method: 'put'
|
method: 'post'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 作废会诊申请
|
// 作废会诊申请
|
||||||
export function cancelRequest(id) {
|
export function cancelRequest(id) {
|
||||||
return request({
|
return request({
|
||||||
url: '/consultation/request/cancel/' + id,
|
url: '/consultation/cancel/' + id,
|
||||||
method: 'put'
|
method: 'post'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确认会诊
|
// 确认会诊
|
||||||
export function confirmRequest(data) {
|
export function confirmRequest(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/consultation/request/confirm',
|
url: '/consultation/confirmation/confirm',
|
||||||
method: 'put',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -87,8 +87,8 @@ export function confirmRequest(data) {
|
|||||||
// 签名会诊
|
// 签名会诊
|
||||||
export function signRequest(data) {
|
export function signRequest(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/consultation/request/sign',
|
url: '/consultation/confirmation/sign',
|
||||||
method: 'put',
|
method: 'post',
|
||||||
data: data
|
params: { consultationId: data.consultationId }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
export function getPendingList() { return request({ url: '/healthlink-his/api/v1/critical-value/pending', method: 'get' }) }
|
export function getPendingList() { return request({ url: '/api/v1/critical-value/pending', method: 'get' }) }
|
||||||
export function confirmValue(id, params) { return request({ url: '/healthlink-his/api/v1/critical-value/confirm/' + id, method: 'put', params }) }
|
export function confirmValue(id, params) { return request({ url: '/api/v1/critical-value/confirm/' + id, method: 'put', params }) }
|
||||||
export function closeValue(id) { return request({ url: '/healthlink-his/api/v1/critical-value/close/' + id, method: 'put' }) }
|
export function closeValue(id) { return request({ url: '/api/v1/critical-value/close/' + id, method: 'put' }) }
|
||||||
export function getStatistics() { return request({ url: '/healthlink-his/api/v1/critical-value/statistics', method: 'get' }) }
|
export function getStatistics() { return request({ url: '/api/v1/critical-value/statistics', method: 'get' }) }
|
||||||
export function getOverdueList() { return request({ url: '/healthlink-his/api/v1/critical-value/overdue', method: 'get' }) }
|
export function getOverdueList() { return request({ url: '/api/v1/critical-value/overdue', method: 'get' }) }
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
export function createRevision(data) { return request({ url: '/healthlink-his/api/v1/emr/revision', method: 'post', data }) }
|
export function createRevision(data) { return request({ url: '/api/v1/emr/revision', method: 'post', data }) }
|
||||||
export function getRevisionHistory(emrId) { return request({ url: '/healthlink-his/api/v1/emr/revision/' + emrId, method: 'get' }) }
|
export function getRevisionHistory(emrId) { return request({ url: '/api/v1/emr/revision/' + emrId, method: 'get' }) }
|
||||||
export function executeCompletenessCheck(emrId) { return request({ url: '/healthlink-his/api/v1/emr/completeness-check/' + emrId, method: 'post' }) }
|
export function executeCompletenessCheck(emrId) { return request({ url: '/api/v1/emr/completeness-check/' + emrId, method: 'post' }) }
|
||||||
export function getCompletenessCheck(emrId) { return request({ url: '/healthlink-his/api/v1/emr/completeness-check/' + emrId, method: 'get' }) }
|
export function getCompletenessCheck(emrId) { return request({ url: '/api/v1/emr/completeness-check/' + emrId, method: 'get' }) }
|
||||||
export function getTimelinessByEncounter(encounterId) { return request({ url: '/healthlink-his/api/v1/emr/timeliness/encounter/' + encounterId, method: 'get' }) }
|
export function getTimelinessByEncounter(encounterId) { return request({ url: '/api/v1/emr/timeliness/encounter/' + encounterId, method: 'get' }) }
|
||||||
export function getOverdueList() { return request({ url: '/healthlink-his/api/v1/emr/timeliness/overdue', method: 'get' }) }
|
export function getOverdueList() { return request({ url: '/api/v1/emr/timeliness/overdue', method: 'get' }) }
|
||||||
export function getTimelinessStatistics(params) { return request({ url: '/healthlink-his/api/v1/emr/timeliness/statistics', method: 'get', params }) }
|
export function getTimelinessStatistics(params) { return request({ url: '/api/v1/emr/timeliness/statistics', method: 'get', params }) }
|
||||||
export function checkTimeliness(data) { return request({ url: '/healthlink-his/api/v1/emr/timeliness/check', method: 'post', data }) }
|
export function checkTimeliness(data) { return request({ url: '/api/v1/emr/timeliness/check', method: 'post', data }) }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
export function getCaseList(params) { return request({ url: '/healthlink-his/api/v1/infection/case', method: 'get', params }) }
|
export function getCaseList(params) { return request({ url: '/api/v1/infection/case', method: 'get', params }) }
|
||||||
export function getStatistics() { return request({ url: '/healthlink-his/api/v1/infection/statistics', method: 'get' }) }
|
export function getStatistics() { return request({ url: '/api/v1/infection/statistics', method: 'get' }) }
|
||||||
export function getExposureList() { return request({ url: '/healthlink-his/api/v1/infection/exposure', method: 'get' }) }
|
export function getExposureList() { return request({ url: '/api/v1/infection/exposure', method: 'get' }) }
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
export function generateHomepage(data) { return request({ url: '/healthlink-his/api/v1/mr-homepage/generate', method: 'post', data }) }
|
export function generateHomepage(data) { return request({ url: '/api/v1/mr-homepage/generate', method: 'post', data }) }
|
||||||
export function updateHomepage(data) { return request({ url: '/healthlink-his/api/v1/mr-homepage', method: 'put', data }) }
|
export function updateHomepage(data) { return request({ url: '/api/v1/mr-homepage', method: 'put', data }) }
|
||||||
export function getHomepageDetail(id) { return request({ url: '/healthlink-his/api/v1/mr-homepage/' + id, method: 'get' }) }
|
export function getHomepageDetail(id) { return request({ url: '/api/v1/mr-homepage/' + id, method: 'get' }) }
|
||||||
export function executeQualityCheck(id) { return request({ url: '/healthlink-his/api/v1/mr-homepage/quality-check/' + id, method: 'post' }) }
|
export function executeQualityCheck(id) { return request({ url: '/api/v1/mr-homepage/quality-check/' + id, method: 'post' }) }
|
||||||
export function getQualityCheck(homepageId) { return request({ url: '/healthlink-his/api/v1/mr-homepage/quality-check/' + homepageId, method: 'get' }) }
|
export function getQualityCheck(homepageId) { return request({ url: '/api/v1/mr-homepage/quality-check/' + homepageId, method: 'get' }) }
|
||||||
export function getStatistics(params) { return request({ url: '/healthlink-his/api/v1/mr-homepage/statistics', method: 'get', params }) }
|
export function getStatistics(params) { return request({ url: '/api/v1/mr-homepage/statistics', method: 'get', params }) }
|
||||||
export function submitHomepage(id) { return request({ url: '/healthlink-his/api/v1/mr-homepage/submit/' + id, method: 'put' }) }
|
export function submitHomepage(id) { return request({ url: '/api/v1/mr-homepage/submit/' + id, method: 'put' }) }
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
export function createAssessment(data) { return request({ url: '/healthlink-his/api/v1/nursing/assessment', method: 'post', data }) }
|
export function createAssessment(data) { return request({ url: '/api/v1/nursing/assessment', method: 'post', data }) }
|
||||||
export function getAssessmentsByEncounter(encounterId) { return request({ url: '/healthlink-his/api/v1/nursing/assessment/encounter/' + encounterId, method: 'get' }) }
|
export function getAssessmentsByEncounter(encounterId) { return request({ url: '/api/v1/nursing/assessment/encounter/' + encounterId, method: 'get' }) }
|
||||||
export function createCarePlan(data) { return request({ url: '/healthlink-his/api/v1/nursing/care-plan', method: 'post', data }) }
|
export function createCarePlan(data) { return request({ url: '/api/v1/nursing/care-plan', method: 'post', data }) }
|
||||||
export function getCarePlansByEncounter(encounterId) { return request({ url: '/healthlink-his/api/v1/nursing/care-plan/encounter/' + encounterId, method: 'get' }) }
|
export function getCarePlansByEncounter(encounterId) { return request({ url: '/api/v1/nursing/care-plan/encounter/' + encounterId, method: 'get' }) }
|
||||||
export function createHandoff(data) { return request({ url: '/healthlink-his/api/v1/nursing/handoff', method: 'post', data }) }
|
export function createHandoff(data) { return request({ url: '/api/v1/nursing/handoff', method: 'post', data }) }
|
||||||
export function getHandoffList(params) { return request({ url: '/healthlink-his/api/v1/nursing/handoff', method: 'get', params }) }
|
export function getHandoffList(params) { return request({ url: '/api/v1/nursing/handoff', method: 'get', params }) }
|
||||||
|
|||||||
@@ -28,3 +28,7 @@ export function cancelOrder(data) {
|
|||||||
export function getClosedLoopStatistics(params) {
|
export function getClosedLoopStatistics(params) {
|
||||||
return request({ url: '/api/v1/order-closed-loop/statistics', method: 'get', params })
|
return request({ url: '/api/v1/order-closed-loop/statistics', method: 'get', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function remindOrder(data) {
|
||||||
|
return request({ url: '/api/v1/order-closed-loop/remind', method: 'post', data })
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ import request from '@/utils/request'
|
|||||||
// 医嘱执行记录列表
|
// 医嘱执行记录列表
|
||||||
export function listOrderExecuteRecord(params) {
|
export function listOrderExecuteRecord(params) {
|
||||||
return request({
|
return request({
|
||||||
url: '/healthlink-his/api/v1/order-closed-loop/list',
|
url: '/api/v1/order-closed-loop/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: params
|
params: params
|
||||||
})
|
})
|
||||||
@@ -12,7 +12,7 @@ export function listOrderExecuteRecord(params) {
|
|||||||
// 医嘱闭环状态查询
|
// 医嘱闭环状态查询
|
||||||
export function getOrderClosedLoopStatus(orderId) {
|
export function getOrderClosedLoopStatus(orderId) {
|
||||||
return request({
|
return request({
|
||||||
url: '/healthlink-his/api/v1/order-closed-loop/status/' + orderId,
|
url: '/api/v1/order-closed-loop/status/' + orderId,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,7 @@ export function getOrderClosedLoopStatus(orderId) {
|
|||||||
// 执行医嘱步骤
|
// 执行医嘱步骤
|
||||||
export function executeOrderStep(data) {
|
export function executeOrderStep(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/healthlink-his/api/v1/order-closed-loop/execute',
|
url: '/api/v1/order-closed-loop/execute',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
@@ -29,7 +29,7 @@ export function executeOrderStep(data) {
|
|||||||
// 闭环统计
|
// 闭环统计
|
||||||
export function getClosedLoopStatistics(params) {
|
export function getClosedLoopStatistics(params) {
|
||||||
return request({
|
return request({
|
||||||
url: '/healthlink-his/api/v1/order-closed-loop/statistics',
|
url: '/api/v1/order-closed-loop/statistics',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: params
|
params: params
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
export function createPlan(data) { return request({ url: '/healthlink-his/api/v1/review/plan', method: 'post', data }) }
|
export function createPlan(data) { return request({ url: '/api/v1/review/plan', method: 'post', data }) }
|
||||||
export function getRecords(planId) { return request({ url: '/healthlink-his/api/v1/review/records/' + planId, method: 'get' }) }
|
export function getRecords(planId) { return request({ url: '/api/v1/review/records/' + planId, method: 'get' }) }
|
||||||
export function getStatistics() { return request({ url: '/healthlink-his/api/v1/review/statistics', method: 'get' }) }
|
export function getStatistics() { return request({ url: '/api/v1/review/statistics', method: 'get' }) }
|
||||||
|
|||||||
@@ -10,16 +10,16 @@ export function executeExamOrder(data) { return request({ url: "/tech-station/ex
|
|||||||
export function executeLabOrder(data) { return request({ url: "/tech-station/execute/lab", method: "post", data }) }
|
export function executeLabOrder(data) { return request({ url: "/tech-station/execute/lab", method: "post", data }) }
|
||||||
|
|
||||||
// 查询退费审批列表
|
// 查询退费审批列表
|
||||||
export function listRefundApproveOrders(params) { return request({ url: "/tech-station/refund/approve/list", method: "get", params }) }
|
export function listRefundApproveOrders(params) { return request({ url: "/tech-station/refund-approve/list", method: "get", params }) }
|
||||||
|
|
||||||
// 审批通过检查退费
|
// 审批通过检查退费
|
||||||
export function approveExamRefund(data) { return request({ url: "/tech-station/refund/approve/exam", method: "post", data }) }
|
export function approveExamRefund(data) { return request({ url: "/tech-station/refund-approve/approve/exam/" + data.applyNo, method: "put", data }) }
|
||||||
|
|
||||||
// 审批驳回检查退费
|
// 审批驳回检查退费
|
||||||
export function rejectExamRefund(data) { return request({ url: "/tech-station/refund/reject/exam", method: "post", data }) }
|
export function rejectExamRefund(data) { return request({ url: "/tech-station/refund-approve/reject/exam/" + data.applyNo, method: "put", data }) }
|
||||||
|
|
||||||
// 审批通过检验退费
|
// 审批通过检验退费
|
||||||
export function approveLabRefund(data) { return request({ url: "/tech-station/refund/approve/lab", method: "post", data }) }
|
export function approveLabRefund(data) { return request({ url: "/tech-station/refund-approve/approve/lab/" + data.applyNo, method: "put", data }) }
|
||||||
|
|
||||||
// 审批驳回检验退费
|
// 审批驳回检验退费
|
||||||
export function rejectLabRefund(data) { return request({ url: "/tech-station/refund/reject/lab", method: "post", data }) }
|
export function rejectLabRefund(data) { return request({ url: "/tech-station/refund-approve/reject/lab/" + data.applyNo, method: "put", data }) }
|
||||||
|
|||||||
@@ -3,33 +3,32 @@
|
|||||||
{
|
{
|
||||||
"index": 0,
|
"index": 0,
|
||||||
"name": 1,
|
"name": 1,
|
||||||
"paperType": "自定义",
|
"paperType": "A5",
|
||||||
"height": 80,
|
"height": 148,
|
||||||
"width": 279,
|
"width": 210,
|
||||||
"paperList": {
|
"paperList": {
|
||||||
"type": "自定义",
|
"type": "A5",
|
||||||
"width": 279,
|
"width": 210,
|
||||||
"height": 80
|
"height": 148
|
||||||
},
|
},
|
||||||
"panelPageRule": "none",
|
|
||||||
"paperHeader": 0,
|
"paperHeader": 0,
|
||||||
"paperFooter": 422.3622047244095,
|
"paperFooter": 419.53,
|
||||||
"paperNumberDisabled": true,
|
"paperNumberDisabled": true,
|
||||||
"paperNumberContinue": true,
|
"paperNumberContinue": true,
|
||||||
"panelAngle": 0,
|
"panelAngle": 0,
|
||||||
"overPrintOptions": {
|
"overPrintOptions": {
|
||||||
"content": "",
|
"content": "",
|
||||||
"opacity": 0.7,
|
"opacity": 0.01,
|
||||||
"type": 1
|
"type": 1
|
||||||
},
|
},
|
||||||
"watermarkOptions": {
|
"watermarkOptions": {
|
||||||
"content": "",
|
"content": "",
|
||||||
"fillStyle": "rgba(87, 13, 248, 0.5)",
|
"fillStyle": "rgba(87, 13, 248, 0.5)",
|
||||||
"fontSize": "36px",
|
"fontSize": "10px",
|
||||||
"rotate": 25,
|
"rotate": 0,
|
||||||
"width": 413,
|
"width": 100,
|
||||||
"height": 310,
|
"height": 100,
|
||||||
"timestamp": true,
|
"timestamp": false,
|
||||||
"format": "YYYY-MM-DD HH:mm"
|
"format": "YYYY-MM-DD HH:mm"
|
||||||
},
|
},
|
||||||
"panelLayoutOptions": {
|
"panelLayoutOptions": {
|
||||||
@@ -40,238 +39,30 @@
|
|||||||
"printElements": [
|
"printElements": [
|
||||||
{
|
{
|
||||||
"options": {
|
"options": {
|
||||||
"left": 0,
|
"left": 505.5,
|
||||||
"top": 15,
|
"top": 20,
|
||||||
"height": 16.5,
|
"height": 20,
|
||||||
"width": 792,
|
"width": 60,
|
||||||
"title": "{{HOSPITAL_NAME}}预交金收据",
|
|
||||||
"coordinateSync": false,
|
|
||||||
"widthHeightSync": false,
|
|
||||||
"fontWeight": "bold",
|
|
||||||
"letterSpacing": 0.75,
|
|
||||||
"textAlign": "center",
|
|
||||||
"qrCodeLevel": 0,
|
|
||||||
"fontSize": 15,
|
|
||||||
"fontFamily": "Microsoft YaHei"
|
|
||||||
},
|
|
||||||
"printElementType": {
|
|
||||||
"title": "文本",
|
|
||||||
"type": "text"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"options": {
|
|
||||||
"left": 111,
|
|
||||||
"top": 46.5,
|
|
||||||
"height": 14,
|
|
||||||
"width": 151.5,
|
|
||||||
"title": "姓名",
|
|
||||||
"coordinateSync": false,
|
|
||||||
"widthHeightSync": false,
|
|
||||||
"qrCodeLevel": 0,
|
|
||||||
"field": "patientName",
|
|
||||||
"fontFamily": "Microsoft YaHei"
|
|
||||||
},
|
|
||||||
"printElementType": {
|
|
||||||
"title": "文本",
|
|
||||||
"type": "text"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"options": {
|
|
||||||
"left": 295.5,
|
|
||||||
"top": 48,
|
|
||||||
"height": 14,
|
|
||||||
"width": 148.5,
|
|
||||||
"title": "住院号",
|
|
||||||
"coordinateSync": false,
|
|
||||||
"widthHeightSync": false,
|
|
||||||
"qrCodeLevel": 0,
|
|
||||||
"field": "encounterNosd",
|
|
||||||
"fontFamily": "Microsoft YaHei"
|
|
||||||
},
|
|
||||||
"printElementType": {
|
|
||||||
"title": "文本",
|
|
||||||
"type": "text"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"options": {
|
|
||||||
"left": 480,
|
|
||||||
"top": 48,
|
|
||||||
"height": 14,
|
|
||||||
"width": 162,
|
|
||||||
"title": "科室",
|
|
||||||
"coordinateSync": false,
|
|
||||||
"widthHeightSync": false,
|
|
||||||
"qrCodeLevel": 0,
|
|
||||||
"field": "inHospitalOrgName",
|
|
||||||
"fontFamily": "Microsoft YaHei"
|
|
||||||
},
|
|
||||||
"printElementType": {
|
|
||||||
"title": "文本",
|
|
||||||
"type": "text"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"options": {
|
|
||||||
"left": 111,
|
|
||||||
"top": 73.5,
|
|
||||||
"height": 14,
|
|
||||||
"width": 153,
|
|
||||||
"title": "ID号",
|
|
||||||
"coordinateSync": false,
|
|
||||||
"widthHeightSync": false,
|
|
||||||
"qrCodeLevel": 0,
|
|
||||||
"field": "patientId",
|
|
||||||
"fontFamily": "Microsoft YaHei"
|
|
||||||
},
|
|
||||||
"printElementType": {
|
|
||||||
"title": "文本",
|
|
||||||
"type": "text"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"options": {
|
|
||||||
"left": 295.5,
|
|
||||||
"top": 73.5,
|
|
||||||
"height": 14,
|
|
||||||
"width": 147,
|
|
||||||
"title": "医保类别",
|
|
||||||
"coordinateSync": false,
|
|
||||||
"widthHeightSync": false,
|
|
||||||
"qrCodeLevel": 0,
|
|
||||||
"field": "contractName",
|
|
||||||
"fontFamily": "Microsoft YaHei"
|
|
||||||
},
|
|
||||||
"printElementType": {
|
|
||||||
"title": "文本",
|
|
||||||
"type": "text"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"options": {
|
|
||||||
"left": 480,
|
|
||||||
"top": 73.5,
|
|
||||||
"height": 14,
|
|
||||||
"width": 163.5,
|
|
||||||
"title": "时间",
|
|
||||||
"coordinateSync": false,
|
|
||||||
"widthHeightSync": false,
|
|
||||||
"qrCodeLevel": 0,
|
|
||||||
"field": "currentTime",
|
|
||||||
"fontFamily": "Microsoft YaHei"
|
|
||||||
},
|
|
||||||
"printElementType": {
|
|
||||||
"title": "文本",
|
|
||||||
"type": "text"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"options": {
|
|
||||||
"left": 111,
|
|
||||||
"top": 105,
|
|
||||||
"height": 25,
|
|
||||||
"width": 120,
|
|
||||||
"title": "金额",
|
|
||||||
"coordinateSync": false,
|
|
||||||
"widthHeightSync": false,
|
|
||||||
"textAlign": "center",
|
|
||||||
"textContentVerticalAlign": "middle",
|
|
||||||
"borderLeft": "solid",
|
|
||||||
"borderTop": "solid",
|
|
||||||
"borderRight": "solid",
|
|
||||||
"borderBottom": "solid",
|
|
||||||
"qrCodeLevel": 0
|
|
||||||
},
|
|
||||||
"printElementType": {
|
|
||||||
"title": "文本",
|
|
||||||
"type": "text"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"options": {
|
|
||||||
"left": 231,
|
|
||||||
"top": 105,
|
|
||||||
"height": 25,
|
|
||||||
"width": 393,
|
|
||||||
"title": "金额",
|
|
||||||
"coordinateSync": false,
|
|
||||||
"widthHeightSync": false,
|
|
||||||
"textAlign": "center",
|
|
||||||
"textContentVerticalAlign": "middle",
|
|
||||||
"borderTop": "solid",
|
|
||||||
"borderRight": "solid",
|
|
||||||
"borderBottom": "solid",
|
|
||||||
"qrCodeLevel": 0,
|
|
||||||
"field": "balanceAmount",
|
|
||||||
"hideTitle": true
|
|
||||||
},
|
|
||||||
"printElementType": {
|
|
||||||
"title": "文本",
|
|
||||||
"type": "text"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"options": {
|
|
||||||
"left": 111,
|
|
||||||
"top": 129,
|
|
||||||
"height": 30,
|
|
||||||
"width": 120,
|
|
||||||
"title": "人民币(大写)",
|
|
||||||
"coordinateSync": false,
|
|
||||||
"widthHeightSync": false,
|
|
||||||
"textAlign": "center",
|
|
||||||
"textContentVerticalAlign": "middle",
|
|
||||||
"borderLeft": "solid",
|
|
||||||
"borderTop": "solid",
|
|
||||||
"borderRight": "solid",
|
|
||||||
"qrCodeLevel": 0
|
|
||||||
},
|
|
||||||
"printElementType": {
|
|
||||||
"title": "文本",
|
|
||||||
"type": "text"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"options": {
|
|
||||||
"left": 231,
|
|
||||||
"top": 129,
|
|
||||||
"height": 30,
|
|
||||||
"width": 393,
|
|
||||||
"title": "金额",
|
|
||||||
"coordinateSync": false,
|
|
||||||
"widthHeightSync": false,
|
|
||||||
"textAlign": "center",
|
|
||||||
"textContentVerticalAlign": "middle",
|
|
||||||
"borderTop": "solid",
|
|
||||||
"borderRight": "solid",
|
|
||||||
"qrCodeLevel": 0,
|
|
||||||
"field": "amountInWords",
|
|
||||||
"hideTitle": true
|
|
||||||
},
|
|
||||||
"printElementType": {
|
|
||||||
"title": "文本",
|
|
||||||
"type": "text"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"options": {
|
|
||||||
"left": 111,
|
|
||||||
"top": 159,
|
|
||||||
"height": 30,
|
|
||||||
"width": 513,
|
|
||||||
"title": " ",
|
"title": " ",
|
||||||
|
"field": "reprintTag",
|
||||||
|
"hideTitle": true,
|
||||||
|
"customClass": "reprint-tag",
|
||||||
"coordinateSync": false,
|
"coordinateSync": false,
|
||||||
"widthHeightSync": false,
|
"widthHeightSync": false,
|
||||||
"textAlign": "center",
|
"textAlign": "center",
|
||||||
"textContentVerticalAlign": "middle",
|
"textContentVerticalAlign": "middle",
|
||||||
|
"fontSize": 9,
|
||||||
|
"color": "#ff0000",
|
||||||
|
"fontWeight": "bold",
|
||||||
"borderLeft": "solid",
|
"borderLeft": "solid",
|
||||||
"borderRight": "solid",
|
"borderRight": "solid",
|
||||||
|
"borderTop": "solid",
|
||||||
"borderBottom": "solid",
|
"borderBottom": "solid",
|
||||||
|
"borderColor": "#ff0000",
|
||||||
|
"borderWidth": 1.5,
|
||||||
"qrCodeLevel": 0,
|
"qrCodeLevel": 0,
|
||||||
"field": "paymentDetails",
|
"fixed": true,
|
||||||
"hideTitle": true
|
"styler": "function(value, options, target, templateData, paperNo) { if (!value || value.trim() === '') { return { display: 'none' }; } return {}; }"
|
||||||
},
|
},
|
||||||
"printElementType": {
|
"printElementType": {
|
||||||
"title": "文本",
|
"title": "文本",
|
||||||
@@ -280,16 +71,20 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"options": {
|
"options": {
|
||||||
"left": 111,
|
"left": 30,
|
||||||
"top": 198,
|
"top": 20,
|
||||||
"height": 14,
|
"height": 30,
|
||||||
"width": 120,
|
"width": 535.5,
|
||||||
"title": "签章",
|
"title": "{{hospitalName}}",
|
||||||
"coordinateSync": false,
|
"coordinateSync": false,
|
||||||
"widthHeightSync": false,
|
"widthHeightSync": false,
|
||||||
"qrCodeLevel": 0,
|
"textAlign": "center",
|
||||||
"field": "patientNamesfs",
|
"fontWeight": "bold",
|
||||||
"fontFamily": "Microsoft YaHei"
|
"fontSize": 19.5,
|
||||||
|
"fontFamily": "SimSun",
|
||||||
|
"letterSpacing": 5,
|
||||||
|
"color": "#000000",
|
||||||
|
"fixed": true
|
||||||
},
|
},
|
||||||
"printElementType": {
|
"printElementType": {
|
||||||
"title": "文本",
|
"title": "文本",
|
||||||
@@ -298,16 +93,20 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"options": {
|
"options": {
|
||||||
"left": 297,
|
"left": 30,
|
||||||
"top": 198,
|
"top": 52,
|
||||||
"height": 14,
|
"height": 20,
|
||||||
"width": 132,
|
"width": 535.5,
|
||||||
"title": "交款人",
|
"title": "住院预缴金收据(收执联)",
|
||||||
"coordinateSync": false,
|
"coordinateSync": false,
|
||||||
"widthHeightSync": false,
|
"widthHeightSync": false,
|
||||||
"qrCodeLevel": 0,
|
"textAlign": "center",
|
||||||
"field": "patientNameada",
|
"fontSize": 12,
|
||||||
"fontFamily": "Microsoft YaHei"
|
"fontFamily": "SimSun",
|
||||||
|
"fontWeight": "normal",
|
||||||
|
"letterSpacing": 2,
|
||||||
|
"color": "#000000",
|
||||||
|
"fixed": true
|
||||||
},
|
},
|
||||||
"printElementType": {
|
"printElementType": {
|
||||||
"title": "文本",
|
"title": "文本",
|
||||||
@@ -316,16 +115,143 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"options": {
|
"options": {
|
||||||
"left": 481.5,
|
"left": 30,
|
||||||
"top": 198,
|
"top": 78,
|
||||||
"height": 14,
|
"height": 15,
|
||||||
"width": 124.5,
|
"width": 250,
|
||||||
"title": "收款人",
|
"title": "收据号:{{receiptNo}}",
|
||||||
"coordinateSync": false,
|
"fontSize": 9,
|
||||||
"widthHeightSync": false,
|
"color": "#000000",
|
||||||
"qrCodeLevel": 0,
|
"fixed": true
|
||||||
"field": "cashier",
|
},
|
||||||
"fontFamily": "Microsoft YaHei"
|
"printElementType": {
|
||||||
|
"title": "文本",
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"left": 288.35,
|
||||||
|
"top": 78,
|
||||||
|
"height": 15,
|
||||||
|
"width": 277.15,
|
||||||
|
"title": "收款日期:{{currentTime}}",
|
||||||
|
"textAlign": "right",
|
||||||
|
"fontSize": 9,
|
||||||
|
"color": "#000000",
|
||||||
|
"fixed": true
|
||||||
|
},
|
||||||
|
"printElementType": {
|
||||||
|
"title": "文本",
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"left": 14.17,
|
||||||
|
"top": 96.38,
|
||||||
|
"width": 566.92,
|
||||||
|
"height": 185.0,
|
||||||
|
"title": "<table style='width:100%; border-collapse:collapse; border:1px solid #000000; table-layout:fixed; font-family:SimSun, serif; font-size:11px; color:#000000;'><tr style='height:28px;'><td style='border:1px solid #000; background:#F5F5F5; text-align:center; width:65px; font-weight:bold; color:#000000;'>住院号</td><td style='border:1px solid #000; padding:0 4px; width:130px; white-space:normal; word-break:break-all; color:#000000;'>{{encounterNosd}}</td><td style='border:1px solid #000; background:#F5F5F5; text-align:center; width:50px; font-weight:bold; color:#000000;'>姓名</td><td style='border:1px solid #000; padding:0 4px; width:110px; white-space:normal; word-break:break-all; color:#000000;'>{{patientName}}</td><td style='border:1px solid #000; background:#F5F5F5; text-align:center; width:50px; font-weight:bold; color:#000000;'>性别</td><td style='border:1px solid #000; text-align:center; width:50px; white-space:normal; word-break:break-all; color:#000000;'>{{gender}}</td><td style='border:1px solid #000; background:#F5F5F5; text-align:center; width:60px; font-weight:bold; color:#000000;'>年龄</td><td style='border:1px solid #000; text-align:center; width:51.92px; white-space:normal; word-break:break-all; color:#000000;'>{{age}}</td></tr><tr style='height:28px;'><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>病区/科室</td><td style='border:1px solid #000; padding:0 4px; white-space:normal; word-break:break-all; color:#000000;' colspan='3'>{{inHospitalOrgName}}</td><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>床号</td><td style='border:1px solid #000; text-align:center; white-space:normal; word-break:break-all; color:#000000;'>{{bedName}}</td><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>医保类型</td><td style='border:1px solid #000; text-align:center; white-space:normal; word-break:break-all; color:#000000;'>{{contractName}}</td></tr><tr style='height:28px;'><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>收费项目</td><td style='border:1px solid #000; padding:0 4px; white-space:normal; word-break:break-all; color:#000000;' colspan='7'>住院预缴款</td></tr><tr style='height:28px;'><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>支付方式</td><td style='border:1px solid #000; padding:0 4px; white-space:normal; word-break:break-all; color:#000000;' colspan='7'>{{paymentMethod}}</td></tr><tr style='height:28px;'><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>金额(大写)</td><td style='border:1px solid #000; padding:0 4px; font-weight:normal; white-space:normal; word-break:break-all; color:#000000;' colspan='7'>{{amountInWords}}</td></tr><tr style='height:28px;'><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>金额(小写)</td><td style='border:1px solid #000; padding:0 4px; font-weight:normal; white-space:normal; word-break:break-all; color:#000000;' colspan='7'>{{balanceAmount}}</td></tr></table>",
|
||||||
|
"fixed": true
|
||||||
|
},
|
||||||
|
"printElementType": {
|
||||||
|
"title": "HTML表格",
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"left": 25.0,
|
||||||
|
"top": 300.0,
|
||||||
|
"height": 55.0,
|
||||||
|
"width": 55.0,
|
||||||
|
"field": "receiptNo",
|
||||||
|
"hideTitle": true,
|
||||||
|
"fixed": true
|
||||||
|
},
|
||||||
|
"printElementType": {
|
||||||
|
"type": "qrcode"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"left": 15.0,
|
||||||
|
"top": 359.0,
|
||||||
|
"height": 11.34,
|
||||||
|
"width": 80.0,
|
||||||
|
"title": "扫码查验电子票据",
|
||||||
|
"textAlign": "center",
|
||||||
|
"fontSize": 7,
|
||||||
|
"color": "#000000",
|
||||||
|
"fixed": true
|
||||||
|
},
|
||||||
|
"printElementType": {
|
||||||
|
"title": "文本",
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"left": 113.39,
|
||||||
|
"top": 300.0,
|
||||||
|
"height": 65.0,
|
||||||
|
"width": 467.7,
|
||||||
|
"title": "说明/备注:\n1. 本收据为预收款凭证,非最终医疗自费/统筹消费发票。\n2. 患者出院结算时,须凭此收据联原件退回换取正式的住院发票。\n3. 请妥善保管此收据。如若遗失,请及时前往收费处办理挂失及证明审核。",
|
||||||
|
"fontSize": 8,
|
||||||
|
"lineHeight": 14,
|
||||||
|
"color": "#000000",
|
||||||
|
"fixed": true
|
||||||
|
},
|
||||||
|
"printElementType": {
|
||||||
|
"title": "文本",
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"left": 14.17,
|
||||||
|
"top": 376.0,
|
||||||
|
"height": 14.17,
|
||||||
|
"width": 566.92,
|
||||||
|
"title": "根据《中华人民共和国电子签名法》规定,本电子票据由医院开具并经国家电子认证中心认证,具有法律效力。请妥善保管。",
|
||||||
|
"textAlign": "center",
|
||||||
|
"fontSize": 7,
|
||||||
|
"color": "#000000",
|
||||||
|
"fixed": true
|
||||||
|
},
|
||||||
|
"printElementType": {
|
||||||
|
"title": "文本",
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"left": 14.17,
|
||||||
|
"top": 396.0,
|
||||||
|
"height": 17.01,
|
||||||
|
"width": 320.0,
|
||||||
|
"title": "收款单位:{{hospitalName}}财务结算专用章(电子印章)",
|
||||||
|
"fontSize": 9,
|
||||||
|
"color": "#000000",
|
||||||
|
"fixed": true
|
||||||
|
},
|
||||||
|
"printElementType": {
|
||||||
|
"title": "文本",
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"left": 330.0,
|
||||||
|
"top": 396.0,
|
||||||
|
"height": 17.01,
|
||||||
|
"width": 251.1,
|
||||||
|
"title": "收款员:{{cashier}}",
|
||||||
|
"textAlign": "right",
|
||||||
|
"fontSize": 9,
|
||||||
|
"color": "#000000",
|
||||||
|
"fixed": true
|
||||||
},
|
},
|
||||||
"printElementType": {
|
"printElementType": {
|
||||||
"title": "文本",
|
"title": "文本",
|
||||||
@@ -335,4 +261,4 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -172,13 +172,13 @@ function getPatchedVxeTable() {
|
|||||||
// 修补 cell-click:在 dispatchEvent 前注入参数归一化
|
// 修补 cell-click:在 dispatchEvent 前注入参数归一化
|
||||||
code = code.replace(
|
code = code.replace(
|
||||||
"dispatchEvent('cell-click', params, evnt);",
|
"dispatchEvent('cell-click', params, evnt);",
|
||||||
`params.row = params; params.column = params.column; dispatchEvent('cell-click', params, evnt);`
|
`var _orgRow = params.row; Object.assign(params, _orgRow); params.row = _orgRow; dispatchEvent('cell-click', params, evnt);`
|
||||||
)
|
)
|
||||||
|
|
||||||
// 修补 current-change:在 dispatchEvent 前注入参数归一化
|
// 修补 current-change:在 dispatchEvent 前注入参数归一化
|
||||||
code = code.replace(
|
code = code.replace(
|
||||||
"dispatchEvent('current-change', Object.assign({ oldValue, newValue }, params), evnt);",
|
"dispatchEvent('current-change', Object.assign({ oldValue, newValue }, params), evnt);",
|
||||||
`var _ccp = Object.assign({ oldValue, newValue }, params); _ccp.newValue = _ccp; _ccp.oldValue = oldValue; dispatchEvent('current-change', _ccp, evnt);`
|
`var _ccp = Object.assign({ oldValue, newValue }, params); Object.assign(_ccp, newValue); _ccp.newValue = newValue; _ccp.oldValue = oldValue; dispatchEvent('current-change', _ccp, evnt);`
|
||||||
)
|
)
|
||||||
|
|
||||||
cachedVxeTable = code
|
cachedVxeTable = code
|
||||||
|
|||||||
@@ -301,9 +301,19 @@ export function executePrint(data, template, printerName, options = {}, business
|
|||||||
|
|
||||||
let processedTemplate;
|
let processedTemplate;
|
||||||
try {
|
try {
|
||||||
processedTemplate = JSON.parse(
|
let templateStr = JSON.stringify(template);
|
||||||
JSON.stringify(template).replace(/{{HOSPITAL_NAME}}/g, userStore.hospitalName)
|
// 统一处理医院名称占位符(支持大小写)
|
||||||
);
|
const hospitalName = userStore.hospitalName || data.hospitalName || "中联医院";
|
||||||
|
templateStr = templateStr.replace(/\{\{HOSPITAL_NAME\}\}/gi, hospitalName);
|
||||||
|
|
||||||
|
if (data && typeof data === 'object') {
|
||||||
|
Object.keys(data).forEach(key => {
|
||||||
|
// 使用更安全的替换方式
|
||||||
|
const val = data[key] ?? '';
|
||||||
|
templateStr = templateStr.split(`{{${key}}}`).join(val);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
processedTemplate = JSON.parse(templateStr);
|
||||||
console.log('[4] 模板处理成功');
|
console.log('[4] 模板处理成功');
|
||||||
} catch (parseError) {
|
} catch (parseError) {
|
||||||
console.error('[4] 模板处理失败:', parseError);
|
console.error('[4] 模板处理失败:', parseError);
|
||||||
@@ -332,8 +342,8 @@ export function executePrint(data, template, printerName, options = {}, business
|
|||||||
|
|
||||||
const printOptions = {
|
const printOptions = {
|
||||||
title: '打印标题',
|
title: '打印标题',
|
||||||
height: 210,
|
width: 210,
|
||||||
width: 148,
|
height: 297,
|
||||||
...options,
|
...options,
|
||||||
};
|
};
|
||||||
console.log('[7] 打印选项:', printOptions);
|
console.log('[7] 打印选项:', printOptions);
|
||||||
@@ -385,7 +395,13 @@ export function executePrint(data, template, printerName, options = {}, business
|
|||||||
hiprintTemplate.print(data, printOptions, {
|
hiprintTemplate.print(data, printOptions, {
|
||||||
styleHandler: () => {
|
styleHandler: () => {
|
||||||
console.log('[10] styleHandler被调用');
|
console.log('[10] styleHandler被调用');
|
||||||
return '<style>@media print { @page { margin: 0; } }</style>';
|
// 从 printOptions 获取纸张尺寸(mm),用于 @page size
|
||||||
|
const pageWidth = printOptions.width || 210;
|
||||||
|
const pageHeight = printOptions.height || 297;
|
||||||
|
const pageStyle = `<style>@media print { @page { size: ${pageWidth}mm ${pageHeight}mm; margin: 0; } }</style>`;
|
||||||
|
// 合并外部传入的 styleHandler(包含元素定位样式)与内部 @page 样式
|
||||||
|
const externalStyle = (options && typeof options.styleHandler === 'function') ? options.styleHandler() : '';
|
||||||
|
return pageStyle + externalStyle;
|
||||||
},
|
},
|
||||||
callback: (e) => {
|
callback: (e) => {
|
||||||
console.log('[10] 打印回调被调用:', e);
|
console.log('[10] 打印回调被调用:', e);
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const open = (data) => { formData.value = data || {}; visible.value = true }
|
|||||||
|
|
||||||
const handleSign = async () => {
|
const handleSign = async () => {
|
||||||
try {
|
try {
|
||||||
await request({ url: '/healthlink-his/api/v1/ca-signature/sign', method: 'post', data: formData.value })
|
await request({ url: '/api/v1/ca-signature/sign', method: 'post', data: formData.value })
|
||||||
ElMessage.success('签名成功')
|
ElMessage.success('签名成功')
|
||||||
visible.value = false
|
visible.value = false
|
||||||
} catch (e) { ElMessage.error('签名失败') }
|
} catch (e) { ElMessage.error('签名失败') }
|
||||||
|
|||||||
@@ -61,7 +61,7 @@
|
|||||||
ref="patientListRef"
|
ref="patientListRef"
|
||||||
height="620"
|
height="620"
|
||||||
:data="patientList"
|
:data="patientList"
|
||||||
:row-config="{ keyField: 'encounterId', keyField: 'id' }"
|
:row-config="{ keyField: 'encounterId' }"
|
||||||
@cell-click="clickRow"
|
@cell-click="clickRow"
|
||||||
>
|
>
|
||||||
<vxe-column
|
<vxe-column
|
||||||
@@ -447,7 +447,8 @@ function checkSelectable(row, index) {
|
|||||||
/**
|
/**
|
||||||
* 点击患者列表行 获取处方列表
|
* 点击患者列表行 获取处方列表
|
||||||
*/
|
*/
|
||||||
function clickRow(row) {
|
function clickRow(params) {
|
||||||
|
const row = params.row || params;
|
||||||
patientInfo.value = row;
|
patientInfo.value = row;
|
||||||
chargeLoading.value = true;
|
chargeLoading.value = true;
|
||||||
encounterId.value = row.encounterId;
|
encounterId.value = row.encounterId;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
v-loading="readCardLoading"
|
v-loading="readCardLoading"
|
||||||
class="app-container"
|
class="app-container"
|
||||||
@@ -122,6 +122,7 @@
|
|||||||
<patientList
|
<patientList
|
||||||
:searchkey="patientSearchKey"
|
:searchkey="patientSearchKey"
|
||||||
@selsect-patient="selsectPatient"
|
@selsect-patient="selsectPatient"
|
||||||
|
@mousedown.prevent
|
||||||
/>
|
/>
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<el-input
|
<el-input
|
||||||
@@ -2079,10 +2080,20 @@ async function confirmCheckIn() {
|
|||||||
// 每次开始新的签到流程先清理残留 slotId,避免历史脏值串单
|
// 每次开始新的签到流程先清理残留 slotId,避免历史脏值串单
|
||||||
currentSlotId.value = null;
|
currentSlotId.value = null;
|
||||||
|
|
||||||
|
// 防御性校验:确保关键字段存在
|
||||||
|
if (!patient.departmentId) {
|
||||||
|
ElMessage.error('该号源缺少科室信息,无法完成签到,请联系管理员');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!patient.realPatientId) {
|
||||||
|
ElMessage.error('该号源缺少患者信息,无法完成签到,请联系管理员');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 弹出确认提示
|
// 弹出确认提示
|
||||||
try {
|
try {
|
||||||
await ElMessageBox.confirm(
|
await ElMessageBox.confirm(
|
||||||
`确认为患者【${patient.patientName}】办理签到挂号?\n` +
|
`确认为患者【${patient.patientName || '未知患者'}】办理签到挂号?\n` +
|
||||||
`科室:${patient.department || '-'}\n` +
|
`科室:${patient.department || '-'}\n` +
|
||||||
`医生:${patient.doctor || '-'}\n` +
|
`医生:${patient.doctor || '-'}\n` +
|
||||||
`费用:¥${patient.fee || '0.00'}`,
|
`费用:¥${patient.fee || '0.00'}`,
|
||||||
@@ -2215,7 +2226,7 @@ async function confirmCheckIn() {
|
|||||||
* 点击患者列表给表单赋值
|
* 点击患者列表给表单赋值
|
||||||
*/
|
*/
|
||||||
function selsectPatient(row) {
|
function selsectPatient(row) {
|
||||||
form.value = { ...form.value, ...row };
|
Object.assign(form.value, row);
|
||||||
form.value.patientId = row.id;
|
form.value.patientId = row.id;
|
||||||
form.value.searchKey = row.name;
|
form.value.searchKey = row.name;
|
||||||
form.value.name = row.name;
|
form.value.name = row.name;
|
||||||
@@ -2225,6 +2236,7 @@ function selsectPatient(row) {
|
|||||||
form.value.firstEnum_enumText = row.firstEnum_enumText;
|
form.value.firstEnum_enumText = row.firstEnum_enumText;
|
||||||
form.value.age = row.age;
|
form.value.age = row.age;
|
||||||
form.value.identifierNo = row.identifierNo;
|
form.value.identifierNo = row.identifierNo;
|
||||||
|
showPopover.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置新增参数
|
// 设置新增参数
|
||||||
|
|||||||
@@ -52,40 +52,43 @@
|
|||||||
搜索
|
搜索
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<vxe-table
|
<div style="flex: 1; overflow: hidden; margin-top: 10px;">
|
||||||
:row-config="{ isCurrent: true }" :data="encounterList"
|
<vxe-table
|
||||||
border
|
:row-config="{ isCurrent: true }"
|
||||||
style="width: 100%"
|
:data="encounterList"
|
||||||
height="calc(100vh - 300px)"
|
border
|
||||||
@cell-click="handleGetReturnDrugList"
|
style="width: 100%"
|
||||||
>
|
height="100%"
|
||||||
<vxe-column
|
@cell-click="handleGetReturnDrugList"
|
||||||
field="patientName"
|
|
||||||
align="center"
|
|
||||||
title="姓名"
|
|
||||||
width="130"
|
|
||||||
show-overflow
|
|
||||||
/>
|
|
||||||
<vxe-column
|
|
||||||
field="genderEnum_enumText"
|
|
||||||
align="center"
|
|
||||||
title="性别"
|
|
||||||
show-overflow
|
|
||||||
/>
|
|
||||||
<vxe-column
|
|
||||||
align="center"
|
|
||||||
width="140"
|
|
||||||
title="就诊日期"
|
|
||||||
show-overflow
|
|
||||||
>
|
>
|
||||||
<template #default="scope">
|
<vxe-column
|
||||||
{{
|
field="patientName"
|
||||||
scope.row.receptionTime ? formatDateStr(scope.row.receptionTime, 'YYYY-MM-DD') : '-'
|
align="center"
|
||||||
}}
|
title="姓名"
|
||||||
</template>
|
width="130"
|
||||||
</vxe-column>
|
show-overflow
|
||||||
<!-- <vxe-column title="状态" align="center" field="refundEnum_enumText" /> -->
|
/>
|
||||||
</vxe-table>
|
<vxe-column
|
||||||
|
field="genderEnum_enumText"
|
||||||
|
align="center"
|
||||||
|
title="性别"
|
||||||
|
show-overflow
|
||||||
|
/>
|
||||||
|
<vxe-column
|
||||||
|
align="center"
|
||||||
|
width="140"
|
||||||
|
title="就诊日期"
|
||||||
|
show-overflow
|
||||||
|
>
|
||||||
|
<template #default="scope">
|
||||||
|
{{
|
||||||
|
scope.row.receptionTime ? formatDateStr(scope.row.receptionTime, 'YYYY-MM-DD') : '-'
|
||||||
|
}}
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
|
<!-- <vxe-column title="状态" align="center" field="refundEnum_enumText" /> -->
|
||||||
|
</vxe-table>
|
||||||
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!-- 右侧退药列表 -->
|
<!-- 右侧退药列表 -->
|
||||||
@@ -100,130 +103,132 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-button
|
<div style="display: flex; gap: 10px; margin-bottom: 10px;">
|
||||||
type="primary"
|
<el-button
|
||||||
:disabled="!selectedMedicines.length"
|
type="primary"
|
||||||
style="margin-bottom: 10px"
|
:disabled="!selectedMedicines.length"
|
||||||
@click="handleReturnDrug(undefined)"
|
@click="handleReturnDrug(undefined)"
|
||||||
>
|
|
||||||
确认退药
|
|
||||||
</el-button>
|
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
style="margin-bottom: 10px"
|
|
||||||
@click="handleScan()"
|
|
||||||
>
|
|
||||||
扫码
|
|
||||||
</el-button>
|
|
||||||
<vxe-table
|
|
||||||
ref="returnDrugRef"
|
|
||||||
:data="returDrugList"
|
|
||||||
style="width: 100%"
|
|
||||||
height="calc(100vh - 300px)"
|
|
||||||
border
|
|
||||||
:span-method="handelSpanMethod"
|
|
||||||
class="no-hover-table"
|
|
||||||
@select="handleSelection"
|
|
||||||
@checkbox-change="handelSelectRows"
|
|
||||||
>
|
|
||||||
<vxe-column
|
|
||||||
type="checkbox"
|
|
||||||
width="55"
|
|
||||||
align="center"
|
|
||||||
/>
|
|
||||||
<vxe-column
|
|
||||||
field="itemName"
|
|
||||||
title="药品名称"
|
|
||||||
show-overflow
|
|
||||||
align="center"
|
|
||||||
/>
|
|
||||||
<vxe-column
|
|
||||||
field="totalPrice"
|
|
||||||
title="总价"
|
|
||||||
width="100"
|
|
||||||
align="right"
|
|
||||||
header-align="center"
|
|
||||||
>
|
>
|
||||||
<template #default="scope">
|
确认退药
|
||||||
{{ scope.row.totalPrice ? scope.row.totalPrice.toFixed(2) + ' 元' : '-' }}
|
</el-button>
|
||||||
</template>
|
<el-button
|
||||||
</vxe-column>
|
type="primary"
|
||||||
<vxe-column
|
@click="handleScan()"
|
||||||
field="lotNumber"
|
|
||||||
title="批号"
|
|
||||||
width="180"
|
|
||||||
align="center"
|
|
||||||
/>
|
|
||||||
<vxe-column
|
|
||||||
field="traceNo"
|
|
||||||
title="追溯码"
|
|
||||||
width="180"
|
|
||||||
align="center"
|
|
||||||
>
|
>
|
||||||
<template #default="scope">
|
扫码
|
||||||
<el-input
|
</el-button>
|
||||||
v-model="scope.row.traceNo"
|
</div>
|
||||||
placeholder="请输入追溯码"
|
<div style="flex: 1; overflow: hidden; margin-bottom: 10px;">
|
||||||
/>
|
<vxe-table
|
||||||
</template>
|
ref="returnDrugRef"
|
||||||
</vxe-column>
|
:data="returDrugList"
|
||||||
<vxe-column
|
style="width: 100%"
|
||||||
field="reqStatus_enumText"
|
height="100%"
|
||||||
title="退药状态"
|
border
|
||||||
width="100"
|
:span-method="handelSpanMethod"
|
||||||
align="center"
|
class="no-hover-table"
|
||||||
|
@checkbox-all="handelSelectRows"
|
||||||
|
@checkbox-change="handelSelectRows"
|
||||||
>
|
>
|
||||||
<template #default="scope">
|
<vxe-column
|
||||||
{{ scope.row.refundEnum_enumText }}
|
type="checkbox"
|
||||||
</template>
|
width="55"
|
||||||
</vxe-column>
|
align="center"
|
||||||
<vxe-column
|
/>
|
||||||
field="waitingQuantity"
|
<vxe-column
|
||||||
title="退药数量"
|
field="itemName"
|
||||||
width="100"
|
title="药品名称"
|
||||||
align="center"
|
show-overflow
|
||||||
>
|
align="center"
|
||||||
<template #default="scope">
|
/>
|
||||||
<span>{{
|
<vxe-column
|
||||||
scope.row.quantity
|
field="totalPrice"
|
||||||
? Math.abs(scope.row.quantity) + ' ' + scope.row.unitCode_dictText
|
title="总价"
|
||||||
: '0' + ' ' + scope.row.unitCode_dictText
|
width="100"
|
||||||
}}</span>
|
align="right"
|
||||||
</template>
|
header-align="center"
|
||||||
</vxe-column>
|
>
|
||||||
<vxe-column
|
<template #default="scope">
|
||||||
field="doctorName"
|
{{ scope.row.totalPrice ? scope.row.totalPrice.toFixed(2) + ' 元' : '-' }}
|
||||||
title="开单医生"
|
</template>
|
||||||
align="center"
|
</vxe-column>
|
||||||
width="180"
|
<vxe-column
|
||||||
/>
|
field="lotNumber"
|
||||||
<vxe-column
|
title="批号"
|
||||||
title="操作"
|
width="180"
|
||||||
width="100"
|
align="center"
|
||||||
align="center"
|
/>
|
||||||
fixed="right"
|
<vxe-column
|
||||||
>
|
field="traceNo"
|
||||||
<template #default="scope">
|
title="追溯码"
|
||||||
<el-popconfirm
|
width="180"
|
||||||
width="150"
|
align="center"
|
||||||
hide-after="10"
|
>
|
||||||
title="操作确认"
|
<template #default="scope">
|
||||||
placement="top-start"
|
<el-input
|
||||||
@confirm="handleReturnDrug(scope.row)"
|
v-model="scope.row.traceNo"
|
||||||
>
|
placeholder="请输入追溯码"
|
||||||
<template #reference>
|
/>
|
||||||
<el-button
|
</template>
|
||||||
type="primary"
|
</vxe-column>
|
||||||
link
|
<vxe-column
|
||||||
:disabled="scope.row.refundEnum != 16"
|
field="reqStatus_enumText"
|
||||||
>
|
title="退药状态"
|
||||||
退药
|
width="100"
|
||||||
</el-button>
|
align="center"
|
||||||
</template>
|
>
|
||||||
</el-popconfirm>
|
<template #default="scope">
|
||||||
</template>
|
{{ scope.row.refundEnum_enumText }}
|
||||||
</vxe-column>
|
</template>
|
||||||
</vxe-table>
|
</vxe-column>
|
||||||
|
<vxe-column
|
||||||
|
field="waitingQuantity"
|
||||||
|
title="退药数量"
|
||||||
|
width="100"
|
||||||
|
align="center"
|
||||||
|
>
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{
|
||||||
|
scope.row.quantity
|
||||||
|
? Math.abs(scope.row.quantity) + ' ' + scope.row.unitCode_dictText
|
||||||
|
: '0' + ' ' + scope.row.unitCode_dictText
|
||||||
|
}}</span>
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
|
<vxe-column
|
||||||
|
field="doctorName"
|
||||||
|
title="开单医生"
|
||||||
|
align="center"
|
||||||
|
width="180"
|
||||||
|
/>
|
||||||
|
<vxe-column
|
||||||
|
title="操作"
|
||||||
|
width="100"
|
||||||
|
align="center"
|
||||||
|
fixed="right"
|
||||||
|
>
|
||||||
|
<template #default="scope">
|
||||||
|
<el-popconfirm
|
||||||
|
width="150"
|
||||||
|
hide-after="10"
|
||||||
|
title="操作确认"
|
||||||
|
placement="top-start"
|
||||||
|
@confirm="handleReturnDrug(scope.row)"
|
||||||
|
>
|
||||||
|
<template #reference>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
link
|
||||||
|
:disabled="scope.row.refundEnum != 16"
|
||||||
|
>
|
||||||
|
退药
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-popconfirm>
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
|
</vxe-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 底部操作栏 -->
|
<!-- 底部操作栏 -->
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
@@ -288,7 +293,7 @@ function initOptions() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleGetReturnDrugList(row) {
|
function handleGetReturnDrugList({ row }) {
|
||||||
encounterId.value = row.encounterId;
|
encounterId.value = row.encounterId;
|
||||||
getReturnDrugList({
|
getReturnDrugList({
|
||||||
encounterId: row.encounterId,
|
encounterId: row.encounterId,
|
||||||
@@ -363,7 +368,7 @@ function handleReturnDrug(row) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
saveList = proxy.$refs.returnDrugRef.getSelectionRows().map((item) => {
|
saveList = proxy.$refs.returnDrugRef.getCheckboxRecords().map((item) => {
|
||||||
return {
|
return {
|
||||||
requestId: item.requestId,
|
requestId: item.requestId,
|
||||||
dispenseId: item.dispenseId,
|
dispenseId: item.dispenseId,
|
||||||
@@ -387,31 +392,22 @@ function handleReturnDrug(row) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 选择框改变时的处理
|
function handelSelectRows({ checked, row }) {
|
||||||
function handleSelection(selection, row) {
|
if (row) {
|
||||||
const isSelected = selection.some((item) => item.dispenseId === row.dispenseId);
|
returDrugList.value
|
||||||
returDrugList.value
|
.filter((item) => item.requestId == row.requestId)
|
||||||
.filter((item) => {
|
.forEach((r) => {
|
||||||
return item.requestId == row.requestId;
|
proxy.$refs['returnDrugRef'].setCheckboxRow(r, checked);
|
||||||
})
|
});
|
||||||
.forEach((row) => {
|
}
|
||||||
proxy.$refs['returnDrugRef'].toggleCheckboxRow(row, isSelected);
|
|
||||||
});
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
selectedMedicines.value = proxy.$refs['returnDrugRef'].getSelectionRows();
|
selectedMedicines.value = proxy.$refs['returnDrugRef'].getCheckboxRecords();
|
||||||
totalAmount.value = selectedMedicines.value.reduce((accumulator, currentRow) => {
|
totalAmount.value = selectedMedicines.value.reduce((accumulator, currentRow) => {
|
||||||
return accumulator + (currentRow.totalPrice || 0);
|
return accumulator + (currentRow.totalPrice || 0);
|
||||||
}, 0);
|
}, 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handelSelectRows(selection) {
|
|
||||||
selectedMedicines.value = selection;
|
|
||||||
totalAmount.value = selectedMedicines.value.reduce((accumulator, currentRow) => {
|
|
||||||
return accumulator + (currentRow.totalPrice || 0);
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据 requestId 合并相同行的方法(只合并药品名称和总价列)
|
// 根据 requestId 合并相同行的方法(只合并药品名称和总价列)
|
||||||
function handelSpanMethod({ row, column, rowIndex, columnIndex }) {
|
function handelSpanMethod({ row, column, rowIndex, columnIndex }) {
|
||||||
// 定义需要合并的列索引
|
// 定义需要合并的列索引
|
||||||
@@ -465,7 +461,7 @@ function handelSpanMethod({ row, column, rowIndex, columnIndex }) {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 90vh;
|
height: calc(100vh - 150px);
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
background: #f0f2f5;
|
background: #f0f2f5;
|
||||||
@@ -474,10 +470,24 @@ function handelSpanMethod({ row, column, rowIndex, columnIndex }) {
|
|||||||
.patient-list {
|
.patient-list {
|
||||||
width: 600px;
|
width: 600px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.refund-list {
|
.refund-list {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-card__body) {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.patient-item {
|
.patient-item {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
export function reportCriticalValue(data) { return request({ url: '/healthlink-his/api/v1/critical-value/report', method: 'post', data }) }
|
export function reportCriticalValue(data) { return request({ url: '/api/v1/critical-value/report', method: 'post', data }) }
|
||||||
export function confirmCriticalValue(id, params) { return request({ url: '/healthlink-his/api/v1/critical-value/confirm/' + id, method: 'put', params }) }
|
export function confirmCriticalValue(id, params) { return request({ url: '/api/v1/critical-value/confirm/' + id, method: 'put', params }) }
|
||||||
export function processCriticalValue(id, params) { return request({ url: '/healthlink-his/api/v1/critical-value/process/' + id, method: 'put', params }) }
|
export function processCriticalValue(id, params) { return request({ url: '/api/v1/critical-value/process/' + id, method: 'put', params }) }
|
||||||
export function closeCriticalValue(id) { return request({ url: '/healthlink-his/api/v1/critical-value/close/' + id, method: 'put' }) }
|
export function closeCriticalValue(id) { return request({ url: '/api/v1/critical-value/close/' + id, method: 'put' }) }
|
||||||
export function getPendingList() { return request({ url: '/healthlink-his/api/v1/critical-value/pending', method: 'get' }) }
|
export function getPendingList() { return request({ url: '/api/v1/critical-value/pending', method: 'get' }) }
|
||||||
export function getOverdueList() { return request({ url: '/healthlink-his/api/v1/critical-value/overdue', method: 'get' }) }
|
export function getOverdueList() { return request({ url: '/api/v1/critical-value/overdue', method: 'get' }) }
|
||||||
export function getStatistics(params) { return request({ url: '/healthlink-his/api/v1/critical-value/statistics', method: 'get', params }) }
|
export function getStatistics(params) { return request({ url: '/api/v1/critical-value/statistics', method: 'get', params }) }
|
||||||
|
|||||||
@@ -394,7 +394,7 @@
|
|||||||
>
|
>
|
||||||
皮试:<el-checkbox
|
皮试:<el-checkbox
|
||||||
v-model="scope.row.skinTestFlag"
|
v-model="scope.row.skinTestFlag"
|
||||||
:true-value="true"
|
:true-value="1"
|
||||||
:false-value="0"
|
:false-value="0"
|
||||||
@change="handleSkinTestChange(scope.row, scope.rowIndex)"
|
@change="handleSkinTestChange(scope.row, scope.rowIndex)"
|
||||||
>
|
>
|
||||||
@@ -837,7 +837,7 @@
|
|||||||
>
|
>
|
||||||
皮试:<el-checkbox
|
皮试:<el-checkbox
|
||||||
v-model="scope.row.skinTestFlag"
|
v-model="scope.row.skinTestFlag"
|
||||||
:true-value="true"
|
:true-value="1"
|
||||||
:false-value="0"
|
:false-value="0"
|
||||||
@change="handleSkinTestChange(scope.row, scope.rowIndex)"
|
@change="handleSkinTestChange(scope.row, scope.rowIndex)"
|
||||||
>
|
>
|
||||||
@@ -1332,7 +1332,7 @@
|
|||||||
<template v-if="scope.row.isEdit">
|
<template v-if="scope.row.isEdit">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
v-model="scope.row.skinTestFlag"
|
v-model="scope.row.skinTestFlag"
|
||||||
:true-value="true"
|
:true-value="1"
|
||||||
:false-value="0"
|
:false-value="0"
|
||||||
@change="handleSkinTestChange(scope.row, scope.rowIndex)"
|
@change="handleSkinTestChange(scope.row, scope.rowIndex)"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!--
|
<!--
|
||||||
* @Description: 门诊手术申请
|
* @Description: 门诊手术申请
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
@@ -339,9 +339,11 @@
|
|||||||
<el-select
|
<el-select
|
||||||
v-model="form.surgeryName"
|
v-model="form.surgeryName"
|
||||||
filterable
|
filterable
|
||||||
|
remote
|
||||||
reserve-keyword
|
reserve-keyword
|
||||||
placeholder="请输入关键词搜索手术"
|
placeholder="请输入关键词搜索手术"
|
||||||
:filter-method="filterSurgery"
|
:remote-method="remoteSearchSurgery"
|
||||||
|
:loading="surgeryLoading"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@change="handleSurgeryChange"
|
@change="handleSurgeryChange"
|
||||||
>
|
>
|
||||||
@@ -414,9 +416,11 @@
|
|||||||
<el-select
|
<el-select
|
||||||
v-model="scope.row.surgeryName"
|
v-model="scope.row.surgeryName"
|
||||||
filterable
|
filterable
|
||||||
|
remote
|
||||||
reserve-keyword
|
reserve-keyword
|
||||||
placeholder="搜索次要手术"
|
placeholder="搜索次要手术"
|
||||||
:filter-method="filterSurgery"
|
:remote-method="remoteSearchSurgery"
|
||||||
|
:loading="surgeryLoading"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@change="(val) => handleSecondarySurgeryChange(val, scope.row)"
|
@change="(val) => handleSecondarySurgeryChange(val, scope.row)"
|
||||||
>
|
>
|
||||||
@@ -1344,6 +1348,8 @@ function remoteSearchSurgery(query) {
|
|||||||
function doSearchSurgery(query) {
|
function doSearchSurgery(query) {
|
||||||
surgeryLoading.value = true
|
surgeryLoading.value = true
|
||||||
getDiagnosisTreatmentList({
|
getDiagnosisTreatmentList({
|
||||||
|
categoryCode: '24',
|
||||||
|
statusEnum: 2,
|
||||||
searchKey: query || '',
|
searchKey: query || '',
|
||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
pageSize: 100
|
pageSize: 100
|
||||||
@@ -1438,10 +1444,13 @@ function filterAnesthesia(query) {
|
|||||||
|
|
||||||
// 加载手术和麻醉全量数据供本地过滤
|
// 加载手术和麻醉全量数据供本地过滤
|
||||||
function loadSurgeryAndAnesthesiaOptions() {
|
function loadSurgeryAndAnesthesiaOptions() {
|
||||||
|
// 1. 初始加载前 100 个启用状态的手术项目,供下拉菜单默认展示,避免全量加载 10,102 条数据导致卡顿
|
||||||
getDiagnosisTreatmentList({
|
getDiagnosisTreatmentList({
|
||||||
|
categoryCode: '24',
|
||||||
|
statusEnum: 2,
|
||||||
searchKey: '',
|
searchKey: '',
|
||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
pageSize: 1000
|
pageSize: 100
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
let data = []
|
let data = []
|
||||||
if (res.data && res.data.records) {
|
if (res.data && res.data.records) {
|
||||||
@@ -1455,14 +1464,34 @@ function loadSurgeryAndAnesthesiaOptions() {
|
|||||||
(item.categoryCode === '24' || item.categoryCode_dictText === '手术') &&
|
(item.categoryCode === '24' || item.categoryCode_dictText === '手术') &&
|
||||||
(item.statusEnum === 2 || item.statusEnum_enumText === '启用' || !item.statusEnum)
|
(item.statusEnum === 2 || item.statusEnum_enumText === '启用' || !item.statusEnum)
|
||||||
)
|
)
|
||||||
|
surgeryNameList.value = allSurgeryItems.value
|
||||||
|
}).catch(error => {
|
||||||
|
console.error('加载手术选项失败:', error)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 2. 加载全部启用状态的麻醉项目(麻醉数量较少,可以直接加载全部)
|
||||||
|
getDiagnosisTreatmentList({
|
||||||
|
categoryCode: '25',
|
||||||
|
statusEnum: 2,
|
||||||
|
searchKey: '',
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 200
|
||||||
|
}).then(res => {
|
||||||
|
let data = []
|
||||||
|
if (res.data && res.data.records) {
|
||||||
|
data = res.data.records
|
||||||
|
} else if (res.data && Array.isArray(res.data)) {
|
||||||
|
data = res.data
|
||||||
|
} else if (res.records && Array.isArray(res.records)) {
|
||||||
|
data = res.records
|
||||||
|
}
|
||||||
allAnesthesiaItems.value = data.filter(item =>
|
allAnesthesiaItems.value = data.filter(item =>
|
||||||
(item.categoryCode === '25' || item.categoryCode_dictText === '麻醉') &&
|
(item.categoryCode === '25' || item.categoryCode_dictText === '麻醉') &&
|
||||||
(item.statusEnum === 2 || item.statusEnum_enumText === '启用' || !item.statusEnum)
|
(item.statusEnum === 2 || item.statusEnum_enumText === '启用' || !item.statusEnum)
|
||||||
)
|
)
|
||||||
surgeryNameList.value = allSurgeryItems.value
|
|
||||||
anesthesiaNameList.value = allAnesthesiaItems.value
|
anesthesiaNameList.value = allAnesthesiaItems.value
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
console.error('加载手术/麻醉选项失败:', error)
|
console.error('加载麻醉选项失败:', error)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1664,6 +1693,8 @@ function reset() {
|
|||||||
if (surgeryRef.value) {
|
if (surgeryRef.value) {
|
||||||
surgeryRef.value.resetFields()
|
surgeryRef.value.resetFields()
|
||||||
}
|
}
|
||||||
|
surgeryNameList.value = allSurgeryItems.value
|
||||||
|
anesthesiaNameList.value = allAnesthesiaItems.value
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取状态标签类型
|
// 获取状态标签类型
|
||||||
|
|||||||
@@ -636,13 +636,14 @@ const inputRefs = ref({}); // 存储输入框实例
|
|||||||
const requiredProps = ref([]); // 存储必填项 prop 顺序
|
const requiredProps = ref([]); // 存储必填项 prop 顺序
|
||||||
const totalAmount = ref(0);
|
const totalAmount = ref(0);
|
||||||
const tcmDianosis = ref();
|
const tcmDianosis = ref();
|
||||||
const { method_code, unit_code, rate_code, distribution_category_code, dosage_instruction } =
|
const { method_code, unit_code, rate_code, distribution_category_code, dosage_instruction, method_of_decocting_medicine } =
|
||||||
proxy.useDict(
|
proxy.useDict(
|
||||||
'method_code',
|
'method_code',
|
||||||
'unit_code',
|
'unit_code',
|
||||||
'rate_code',
|
'rate_code',
|
||||||
'distribution_category_code',
|
'distribution_category_code',
|
||||||
'dosage_instruction'
|
'dosage_instruction',
|
||||||
|
'method_of_decocting_medicine'
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="pending-emr-page">
|
<div class="pending-emr-page">
|
||||||
<!-- 页面头部 -->
|
<!-- 页面头部 -->
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
@@ -139,8 +139,12 @@ import { parseTime } from '@/utils/index.js'
|
|||||||
import Pagination from '@/components/Pagination'
|
import Pagination from '@/components/Pagination'
|
||||||
import { Document, Refresh, Search, Delete } from '@element-plus/icons-vue'
|
import { Document, Refresh, Search, Delete } from '@element-plus/icons-vue'
|
||||||
import { ElDivider } from 'element-plus'
|
import { ElDivider } from 'element-plus'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { updatePatientInfo } from '@/views/inpatientDoctor/home/store/patient'
|
||||||
|
import { updateLocalPatientInfo } from '@/views/inpatientDoctor/home/store/localPatient'
|
||||||
|
|
||||||
// 响应式数据
|
// 响应式数据
|
||||||
|
const router = useRouter()
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const total = ref(0)
|
const total = ref(0)
|
||||||
const emrList = ref([])
|
const emrList = ref([])
|
||||||
@@ -209,38 +213,18 @@ const handleRowClick = (row) => {
|
|||||||
|
|
||||||
// 写病历
|
// 写病历
|
||||||
const handleWriteEmr = (row) => {
|
const handleWriteEmr = (row) => {
|
||||||
console.log('写病历:', row)
|
// 存储患者信息并跳转到住院医生工作站
|
||||||
// 弹出写病历弹窗
|
updatePatientInfo(row)
|
||||||
ElMessageBox.confirm('确定要为患者 ' + row.patientName + ' 写病历吗?', '确认', {
|
updateLocalPatientInfo(row)
|
||||||
confirmButtonText: '确定',
|
router.push({ path: '/inHospital/inpatientDoctor' })
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'info'
|
|
||||||
}).then(() => {
|
|
||||||
// 这里可以跳转到病历编辑页面或弹出病历编辑弹窗
|
|
||||||
ElMessage.success('正在打开病历编辑页面...')
|
|
||||||
// TODO: 实现写病历的具体逻辑
|
|
||||||
// 例如:router.push({ path: '/doctorstation/emr', query: { encounterId: row.encounterId } })
|
|
||||||
}).catch(() => {
|
|
||||||
// 取消操作
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查看患者
|
// 查看患者
|
||||||
const handleViewPatient = (row) => {
|
const handleViewPatient = (row) => {
|
||||||
console.log('查看患者:', row)
|
// 存储患者信息并跳转到住院医生工作站
|
||||||
// 弹出查看患者弹窗
|
updatePatientInfo(row)
|
||||||
ElMessageBox.confirm('确定要查看患者 ' + row.patientName + ' 的详细信息吗?', '确认', {
|
updateLocalPatientInfo(row)
|
||||||
confirmButtonText: '确定',
|
router.push({ path: '/inHospital/inpatientDoctor' })
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'info'
|
|
||||||
}).then(() => {
|
|
||||||
// 这里可以跳转到患者详情页面或弹出患者详情弹窗
|
|
||||||
ElMessage.success('正在打开患者详情页面...')
|
|
||||||
// TODO: 实现查看患者的具体逻辑
|
|
||||||
// 例如:router.push({ path: '/doctorstation/patient-details', query: { encounterId: row.encounterId } })
|
|
||||||
}).catch(() => {
|
|
||||||
// 取消操作
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取性别文本
|
// 获取性别文本
|
||||||
|
|||||||
@@ -52,40 +52,43 @@
|
|||||||
搜索
|
搜索
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<vxe-table
|
<div style="flex: 1; overflow: hidden; margin-top: 10px;">
|
||||||
:row-config="{ isCurrent: true }" :data="encounterList"
|
<vxe-table
|
||||||
border
|
:row-config="{ isCurrent: true }"
|
||||||
style="width: 100%"
|
:data="encounterList"
|
||||||
height="calc(100vh - 300px)"
|
border
|
||||||
@cell-click="handleGetReturnDrugList"
|
style="width: 100%"
|
||||||
>
|
height="100%"
|
||||||
<vxe-column
|
@cell-click="handleGetReturnDrugList"
|
||||||
field="patientName"
|
|
||||||
align="center"
|
|
||||||
title="姓名"
|
|
||||||
width="130"
|
|
||||||
show-overflow
|
|
||||||
/>
|
|
||||||
<vxe-column
|
|
||||||
field="genderEnum_enumText"
|
|
||||||
align="center"
|
|
||||||
title="性别"
|
|
||||||
show-overflow
|
|
||||||
/>
|
|
||||||
<vxe-column
|
|
||||||
align="center"
|
|
||||||
width="140"
|
|
||||||
title="就诊日期"
|
|
||||||
show-overflow
|
|
||||||
>
|
>
|
||||||
<template #default="scope">
|
<vxe-column
|
||||||
{{
|
field="patientName"
|
||||||
scope.row.receptionTime ? formatDateStr(scope.row.receptionTime, 'YYYY-MM-DD') : '-'
|
align="center"
|
||||||
}}
|
title="姓名"
|
||||||
</template>
|
width="130"
|
||||||
</vxe-column>
|
show-overflow
|
||||||
<!-- <vxe-column title="状态" align="center" field="refundEnum_enumText" /> -->
|
/>
|
||||||
</vxe-table>
|
<vxe-column
|
||||||
|
field="genderEnum_enumText"
|
||||||
|
align="center"
|
||||||
|
title="性别"
|
||||||
|
show-overflow
|
||||||
|
/>
|
||||||
|
<vxe-column
|
||||||
|
align="center"
|
||||||
|
width="140"
|
||||||
|
title="就诊日期"
|
||||||
|
show-overflow
|
||||||
|
>
|
||||||
|
<template #default="scope">
|
||||||
|
{{
|
||||||
|
scope.row.receptionTime ? formatDateStr(scope.row.receptionTime, 'YYYY-MM-DD') : '-'
|
||||||
|
}}
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
|
<!-- <vxe-column title="状态" align="center" field="refundEnum_enumText" /> -->
|
||||||
|
</vxe-table>
|
||||||
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!-- 右侧退药列表 -->
|
<!-- 右侧退药列表 -->
|
||||||
@@ -100,130 +103,132 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-button
|
<div style="display: flex; gap: 10px; margin-bottom: 10px;">
|
||||||
type="primary"
|
<el-button
|
||||||
:disabled="!selectedMedicines.length"
|
type="primary"
|
||||||
style="margin-bottom: 10px"
|
:disabled="!selectedMedicines.length"
|
||||||
@click="handleReturnDrug(undefined)"
|
@click="handleReturnDrug(undefined)"
|
||||||
>
|
|
||||||
确认退药
|
|
||||||
</el-button>
|
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
style="margin-bottom: 10px"
|
|
||||||
@click="handleScan()"
|
|
||||||
>
|
|
||||||
扫码
|
|
||||||
</el-button>
|
|
||||||
<vxe-table
|
|
||||||
ref="returnDrugRef"
|
|
||||||
:data="returDrugList"
|
|
||||||
style="width: 100%"
|
|
||||||
height="calc(100vh - 300px)"
|
|
||||||
border
|
|
||||||
:span-method="handelSpanMethod"
|
|
||||||
class="no-hover-table"
|
|
||||||
@select="handleSelection"
|
|
||||||
@checkbox-change="handelSelectRows"
|
|
||||||
>
|
|
||||||
<vxe-column
|
|
||||||
type="checkbox"
|
|
||||||
width="55"
|
|
||||||
align="center"
|
|
||||||
/>
|
|
||||||
<vxe-column
|
|
||||||
field="itemName"
|
|
||||||
title="药品名称"
|
|
||||||
show-overflow
|
|
||||||
align="center"
|
|
||||||
/>
|
|
||||||
<vxe-column
|
|
||||||
field="totalPrice"
|
|
||||||
title="总价"
|
|
||||||
width="100"
|
|
||||||
align="right"
|
|
||||||
header-align="center"
|
|
||||||
>
|
>
|
||||||
<template #default="scope">
|
确认退药
|
||||||
{{ scope.row.totalPrice ? scope.row.totalPrice.toFixed(2) + ' 元' : '-' }}
|
</el-button>
|
||||||
</template>
|
<el-button
|
||||||
</vxe-column>
|
type="primary"
|
||||||
<vxe-column
|
@click="handleScan()"
|
||||||
field="lotNumber"
|
|
||||||
title="批号"
|
|
||||||
width="180"
|
|
||||||
align="center"
|
|
||||||
/>
|
|
||||||
<vxe-column
|
|
||||||
field="traceNo"
|
|
||||||
title="追溯码"
|
|
||||||
width="180"
|
|
||||||
align="center"
|
|
||||||
>
|
>
|
||||||
<template #default="scope">
|
扫码
|
||||||
<el-input
|
</el-button>
|
||||||
v-model="scope.row.traceNo"
|
</div>
|
||||||
placeholder="请输入追溯码"
|
<div style="flex: 1; overflow: hidden; margin-bottom: 10px;">
|
||||||
/>
|
<vxe-table
|
||||||
</template>
|
ref="returnDrugRef"
|
||||||
</vxe-column>
|
:data="returDrugList"
|
||||||
<vxe-column
|
style="width: 100%"
|
||||||
field="reqStatus_enumText"
|
height="100%"
|
||||||
title="退药状态"
|
border
|
||||||
width="100"
|
:span-method="handelSpanMethod"
|
||||||
align="center"
|
class="no-hover-table"
|
||||||
|
@checkbox-all="handelSelectRows"
|
||||||
|
@checkbox-change="handelSelectRows"
|
||||||
>
|
>
|
||||||
<template #default="scope">
|
<vxe-column
|
||||||
{{ scope.row.refundEnum_enumText }}
|
type="checkbox"
|
||||||
</template>
|
width="55"
|
||||||
</vxe-column>
|
align="center"
|
||||||
<vxe-column
|
/>
|
||||||
field="waitingQuantity"
|
<vxe-column
|
||||||
title="退药数量"
|
field="itemName"
|
||||||
width="100"
|
title="药品名称"
|
||||||
align="center"
|
show-overflow
|
||||||
>
|
align="center"
|
||||||
<template #default="scope">
|
/>
|
||||||
<span>{{
|
<vxe-column
|
||||||
scope.row.quantity
|
field="totalPrice"
|
||||||
? Math.abs(scope.row.quantity) + ' ' + scope.row.unitCode_dictText
|
title="总价"
|
||||||
: '0' + ' ' + scope.row.unitCode_dictText
|
width="100"
|
||||||
}}</span>
|
align="right"
|
||||||
</template>
|
header-align="center"
|
||||||
</vxe-column>
|
>
|
||||||
<vxe-column
|
<template #default="scope">
|
||||||
field="doctorName"
|
{{ scope.row.totalPrice ? scope.row.totalPrice.toFixed(2) + ' 元' : '-' }}
|
||||||
title="开单医生"
|
</template>
|
||||||
align="center"
|
</vxe-column>
|
||||||
width="180"
|
<vxe-column
|
||||||
/>
|
field="lotNumber"
|
||||||
<vxe-column
|
title="批号"
|
||||||
title="操作"
|
width="180"
|
||||||
width="100"
|
align="center"
|
||||||
align="center"
|
/>
|
||||||
fixed="right"
|
<vxe-column
|
||||||
>
|
field="traceNo"
|
||||||
<template #default="scope">
|
title="追溯码"
|
||||||
<el-popconfirm
|
width="180"
|
||||||
width="150"
|
align="center"
|
||||||
hide-after="10"
|
>
|
||||||
title="操作确认"
|
<template #default="scope">
|
||||||
placement="top-start"
|
<el-input
|
||||||
@confirm="handleReturnDrug(scope.row)"
|
v-model="scope.row.traceNo"
|
||||||
>
|
placeholder="请输入追溯码"
|
||||||
<template #reference>
|
/>
|
||||||
<el-button
|
</template>
|
||||||
type="primary"
|
</vxe-column>
|
||||||
link
|
<vxe-column
|
||||||
:disabled="scope.row.refundEnum != 16"
|
field="reqStatus_enumText"
|
||||||
>
|
title="退药状态"
|
||||||
退药
|
width="100"
|
||||||
</el-button>
|
align="center"
|
||||||
</template>
|
>
|
||||||
</el-popconfirm>
|
<template #default="scope">
|
||||||
</template>
|
{{ scope.row.refundEnum_enumText }}
|
||||||
</vxe-column>
|
</template>
|
||||||
</vxe-table>
|
</vxe-column>
|
||||||
|
<vxe-column
|
||||||
|
field="waitingQuantity"
|
||||||
|
title="退药数量"
|
||||||
|
width="100"
|
||||||
|
align="center"
|
||||||
|
>
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{
|
||||||
|
scope.row.quantity
|
||||||
|
? Math.abs(scope.row.quantity) + ' ' + scope.row.unitCode_dictText
|
||||||
|
: '0' + ' ' + scope.row.unitCode_dictText
|
||||||
|
}}</span>
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
|
<vxe-column
|
||||||
|
field="doctorName"
|
||||||
|
title="开单医生"
|
||||||
|
align="center"
|
||||||
|
width="180"
|
||||||
|
/>
|
||||||
|
<vxe-column
|
||||||
|
title="操作"
|
||||||
|
width="100"
|
||||||
|
align="center"
|
||||||
|
fixed="right"
|
||||||
|
>
|
||||||
|
<template #default="scope">
|
||||||
|
<el-popconfirm
|
||||||
|
width="150"
|
||||||
|
hide-after="10"
|
||||||
|
title="操作确认"
|
||||||
|
placement="top-start"
|
||||||
|
@confirm="handleReturnDrug(scope.row)"
|
||||||
|
>
|
||||||
|
<template #reference>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
link
|
||||||
|
:disabled="scope.row.refundEnum != 16"
|
||||||
|
>
|
||||||
|
退药
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-popconfirm>
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
|
</vxe-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 底部操作栏 -->
|
<!-- 底部操作栏 -->
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
@@ -289,7 +294,7 @@ function initOptions() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleGetReturnDrugList(row) {
|
function handleGetReturnDrugList({ row }) {
|
||||||
encounterId.value = row.encounterId;
|
encounterId.value = row.encounterId;
|
||||||
getReturnDrugList({
|
getReturnDrugList({
|
||||||
encounterId: row.encounterId,
|
encounterId: row.encounterId,
|
||||||
@@ -364,7 +369,7 @@ function handleReturnDrug(row) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
saveList = proxy.$refs.returnDrugRef.getSelectionRows().map((item) => {
|
saveList = proxy.$refs.returnDrugRef.getCheckboxRecords().map((item) => {
|
||||||
return {
|
return {
|
||||||
requestId: item.requestId,
|
requestId: item.requestId,
|
||||||
dispenseId: item.dispenseId,
|
dispenseId: item.dispenseId,
|
||||||
@@ -388,31 +393,22 @@ function handleReturnDrug(row) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 选择框改变时的处理
|
function handelSelectRows({ checked, row }) {
|
||||||
function handleSelection(selection, row) {
|
if (row) {
|
||||||
const isSelected = selection.some((item) => item.dispenseId === row.dispenseId);
|
returDrugList.value
|
||||||
returDrugList.value
|
.filter((item) => item.requestId == row.requestId)
|
||||||
.filter((item) => {
|
.forEach((r) => {
|
||||||
return item.requestId == row.requestId;
|
proxy.$refs['returnDrugRef'].setCheckboxRow(r, checked);
|
||||||
})
|
});
|
||||||
.forEach((row) => {
|
}
|
||||||
proxy.$refs['returnDrugRef'].toggleCheckboxRow(row, isSelected);
|
|
||||||
});
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
selectedMedicines.value = proxy.$refs['returnDrugRef'].getSelectionRows();
|
selectedMedicines.value = proxy.$refs['returnDrugRef'].getCheckboxRecords();
|
||||||
totalAmount.value = selectedMedicines.value.reduce((accumulator, currentRow) => {
|
totalAmount.value = selectedMedicines.value.reduce((accumulator, currentRow) => {
|
||||||
return accumulator + (currentRow.totalPrice || 0);
|
return accumulator + (currentRow.totalPrice || 0);
|
||||||
}, 0);
|
}, 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handelSelectRows(selection) {
|
|
||||||
selectedMedicines.value = selection;
|
|
||||||
totalAmount.value = selectedMedicines.value.reduce((accumulator, currentRow) => {
|
|
||||||
return accumulator + (currentRow.totalPrice || 0);
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据 requestId 合并相同行的方法(只合并药品名称和总价列)
|
// 根据 requestId 合并相同行的方法(只合并药品名称和总价列)
|
||||||
function handelSpanMethod({ row, column, rowIndex, columnIndex }) {
|
function handelSpanMethod({ row, column, rowIndex, columnIndex }) {
|
||||||
// 定义需要合并的列索引
|
// 定义需要合并的列索引
|
||||||
@@ -466,17 +462,31 @@ function handelSpanMethod({ row, column, rowIndex, columnIndex }) {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 80vh;
|
height: calc(100vh - 150px);
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.patient-list {
|
.patient-list {
|
||||||
width: 600px;
|
width: 600px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.refund-list {
|
.refund-list {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-card__body) {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.patient-item {
|
.patient-item {
|
||||||
|
|||||||
@@ -247,13 +247,13 @@ export function medicineMatch(data) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------门诊退药接口----------------------------------------------------------------------
|
// ----------------------------------------------住院退药接口----------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* 获取患者列表
|
* 获取患者列表
|
||||||
*/
|
*/
|
||||||
export function getList(queryParams) {
|
export function getList(queryParams) {
|
||||||
return request({
|
return request({
|
||||||
url: '/pharmacy-manage/return-medicine/return-patient-page',
|
url: '/pharmacy-manage/inHospital-return-medicine/return-patient-page',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: queryParams,
|
params: queryParams,
|
||||||
});
|
});
|
||||||
@@ -264,7 +264,7 @@ export function getList(queryParams) {
|
|||||||
*/
|
*/
|
||||||
export function getReturnDrugList(params) {
|
export function getReturnDrugList(params) {
|
||||||
return request({
|
return request({
|
||||||
url: '/pharmacy-manage/return-medicine/medicine-return-list',
|
url: '/pharmacy-manage/inHospital-return-medicine/medicine-return-list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: params,
|
params: params,
|
||||||
});
|
});
|
||||||
@@ -275,7 +275,7 @@ export function getReturnDrugList(params) {
|
|||||||
*/
|
*/
|
||||||
export function returnDrug(data) {
|
export function returnDrug(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/pharmacy-manage/return-medicine/medicine-return',
|
url: '/pharmacy-manage/inHospital-return-medicine/medicine-return',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: data,
|
data: data,
|
||||||
});
|
});
|
||||||
@@ -286,7 +286,7 @@ export function returnDrug(data) {
|
|||||||
*/
|
*/
|
||||||
export function init() {
|
export function init() {
|
||||||
return request({
|
return request({
|
||||||
url: '/pharmacy-manage/return-medicine/init',
|
url: '/pharmacy-manage/inHospital-return-medicine/init',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,8 +47,8 @@
|
|||||||
</el-table>
|
</el-table>
|
||||||
<el-pagination style="margin-top:12px;justify-content:flex-end" v-model:current-page="q.pageNo" v-model:page-size="q.pageSize" :total="total" layout="total,prev,pager,next" @current-change="loadData"/>
|
<el-pagination style="margin-top:12px;justify-content:flex-end" v-model:current-page="q.pageNo" v-model:page-size="q.pageSize" :total="total" layout="total,prev,pager,next" @current-change="loadData"/>
|
||||||
<el-dialog v-model="addVisible" title="激活绿色通道" width="500px">
|
<el-dialog v-model="addVisible" title="激活绿色通道" width="500px">
|
||||||
<el-form :model="addForm" label-width="120px">
|
<el-form ref="addFormRef" :model="addForm" :rules="addFormRules" label-width="120px">
|
||||||
<el-form-item label="患者ID"><el-input-number v-model="addForm.patientId" :min="1"/></el-form-item>
|
<el-form-item label="患者ID" prop="patientId"><el-input-number v-model="addForm.patientId" :min="1" style="width:100%"/></el-form-item>
|
||||||
<el-form-item label="疾病类型"><el-input v-model="addForm.diseaseType" placeholder="如: 急性心肌梗死、脑卒中"/></el-form-item>
|
<el-form-item label="疾病类型"><el-input v-model="addForm.diseaseType" placeholder="如: 急性心肌梗死、脑卒中"/></el-form-item>
|
||||||
<el-form-item label="目标时间(min)"><el-input-number v-model="addForm.targetTime" :min="1"/></el-form-item>
|
<el-form-item label="目标时间(min)"><el-input-number v-model="addForm.targetTime" :min="1"/></el-form-item>
|
||||||
<el-form-item label="医生"><el-input v-model="addForm.doctor"/></el-form-item>
|
<el-form-item label="医生"><el-input v-model="addForm.doctor"/></el-form-item>
|
||||||
@@ -76,13 +76,15 @@ import {getPage,activate,complete,getStats,del} from './api'
|
|||||||
const tableData=ref([]);const total=ref(0);const stats=ref({})
|
const tableData=ref([]);const total=ref(0);const stats=ref({})
|
||||||
const addVisible=ref(false);const completeVisible=ref(false)
|
const addVisible=ref(false);const completeVisible=ref(false)
|
||||||
const addForm=ref({patientId:null,diseaseType:'',targetTime:90,doctor:''})
|
const addForm=ref({patientId:null,diseaseType:'',targetTime:90,doctor:''})
|
||||||
|
const addFormRef=ref(null)
|
||||||
|
const addFormRules={patientId:[{required:true,message:'请选择患者',trigger:'blur'}]}
|
||||||
const completeForm=ref({doorToTreatmentTime:60});let currentId=null
|
const completeForm=ref({doorToTreatmentTime:60});let currentId=null
|
||||||
const q=ref({pageNo:1,pageSize:20,diseaseType:'',isAchieved:null})
|
const q=ref({pageNo:1,pageSize:20,diseaseType:'',isAchieved:null})
|
||||||
const loadData=async()=>{const r=await getPage(q.value);tableData.value=r.data?.records||[];total.value=r.data?.total||0}
|
const loadData=async()=>{const r=await getPage(q.value);tableData.value=r.data?.records||[];total.value=r.data?.total||0}
|
||||||
const refreshStats=async()=>{const r=await getStats({});stats.value=r.data||{}}
|
const refreshStats=async()=>{const r=await getStats({});stats.value=r.data||{}}
|
||||||
const showAdd=()=>{addForm.value={patientId:null,diseaseType:'',targetTime:90,doctor:''};addVisible.value=true}
|
const showAdd=()=>{addForm.value={patientId:null,diseaseType:'',targetTime:90,doctor:''};addVisible.value=true}
|
||||||
const showComplete=(row)=>{currentId=row.id;completeForm.value={doorToTreatmentTime:60};completeVisible.value=true}
|
const showComplete=(row)=>{currentId=row.id;completeForm.value={doorToTreatmentTime:60};completeVisible.value=true}
|
||||||
const submitAdd=async()=>{await activate(addForm.value);ElMessage.success('绿色通道已激活');addVisible.value=false;loadData();refreshStats()}
|
const submitAdd=async()=>{if(addFormRef.value){try{await addFormRef.value.validate()}catch{return}}await activate(addForm.value);ElMessage.success('绿色通道已激活');addVisible.value=false;loadData();refreshStats()}
|
||||||
const doComplete=async()=>{await complete(currentId,completeForm.value);ElMessage.success('评估完成');completeVisible.value=false;loadData();refreshStats()}
|
const doComplete=async()=>{await complete(currentId,completeForm.value);ElMessage.success('评估完成');completeVisible.value=false;loadData();refreshStats()}
|
||||||
const delItem=async(id)=>{await del(id);ElMessage.success('已删除');loadData();refreshStats()}
|
const delItem=async(id)=>{await del(id);ElMessage.success('已删除');loadData();refreshStats()}
|
||||||
onMounted(()=>{loadData();refreshStats()})
|
onMounted(()=>{loadData();refreshStats()})
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
export function registerPerson(data) { return request({ url: '/healthlink-his/api/v1/empi/person', method: 'post', data }) }
|
export function registerPerson(data) { return request({ url: '/api/v1/empi/person', method: 'post', data }) }
|
||||||
export function mergePersons(primaryId, secondaryIds) { return request({ url: '/healthlink-his/api/v1/empi/merge', method: 'post', params: { primaryId, secondaryIds: secondaryIds.join(',') } }) }
|
export function mergePersons(primaryId, secondaryIds) { return request({ url: '/api/v1/empi/merge', method: 'post', params: { primaryId, secondaryIds: secondaryIds.join(',') } }) }
|
||||||
export function findByGlobalId(globalId) { return request({ url: '/healthlink-his/api/v1/empi/person/global/' + globalId, method: 'get' }) }
|
export function findByGlobalId(globalId) { return request({ url: '/api/v1/empi/person/global/' + globalId, method: 'get' }) }
|
||||||
export function findByIdCard(idCardNo) { return request({ url: '/healthlink-his/api/v1/empi/person/idcard/' + idCardNo, method: 'get' }) }
|
export function findByIdCard(idCardNo) { return request({ url: '/api/v1/empi/person/idcard/' + idCardNo, method: 'get' }) }
|
||||||
export function getMappings(globalId) { return request({ url: '/healthlink-his/api/v1/empi/mappings/' + globalId, method: 'get' }) }
|
export function getMappings(globalId) { return request({ url: '/api/v1/empi/mappings/' + globalId, method: 'get' }) }
|
||||||
export function getStatistics() { return request({ url: '/healthlink-his/api/v1/empi/statistics', method: 'get' }) }
|
export function getStatistics() { return request({ url: '/api/v1/empi/statistics', method: 'get' }) }
|
||||||
|
|
||||||
export function getPhotos(patientId) { return request({ url: '/empi-enhanced/photo/list', method: 'get', params: { patientId } }) }
|
export function getPhotos(patientId) { return request({ url: '/empi-enhanced/photo/list', method: 'get', params: { patientId } }) }
|
||||||
export function addPhoto(data) { return request({ url: '/empi-enhanced/photo/add', method: 'post', data }) }
|
export function addPhoto(data) { return request({ url: '/empi-enhanced/photo/add', method: 'post', data }) }
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user