chore(config): 更新开发环境配置并添加EMR集成文档
- 更新数据库连接URL从测试服务器切换到本地开发环境 - 修改Druid监控台登录用户名从healthlink-his到openhiss - 更新Redis配置从集群模式切换到单机模式并调整端口设置 - 移除Flyway数据库迁移配置以简化开发环境初始化 - 删除应用上下文路径配置以使用根路径访问 - 添加医院信息系统技术对比分析文档 - 添加EMR模块集成实施计划文档 - 添加EMR数据同步使用指南文档 - 添加HIS系统选型对比文章文档
This commit is contained in:
358
MD/HEALTHLINK_HIS_COMPARE_ARTICLE.md
Normal file
358
MD/HEALTHLINK_HIS_COMPARE_ARTICLE.md
Normal file
@@ -0,0 +1,358 @@
|
||||
# 选HIS系统,你真的选对了吗?— 一个10年医疗IT老兵的真心话
|
||||
|
||||
> **上海经创贺联信息科技有限公司**
|
||||
|
||||
---
|
||||
|
||||
## 前言
|
||||
|
||||
做了10年医疗信息化,我见过太多医院在选HIS系统时踩坑:
|
||||
|
||||
- 花了几百万买了一套系统,结果80%的功能用不上
|
||||
- 上线三个月,医生投诉不断,护士叫苦连天
|
||||
- 想加个新功能,厂商报价比买新系统还贵
|
||||
- 系统跑不动了,厂商说"您的硬件该升级了"
|
||||
|
||||
**今天,我想和大家聊聊:选HIS系统,到底应该看什么?**
|
||||
|
||||
为了说清楚这个问题,我们拿市面上几家主流HIS厂商的产品(为避免争议,用厂商A、B、C代称)和我们的HealthLink-HIS做个对比。
|
||||
|
||||
**不吹不黑,只摆事实。**
|
||||
|
||||
---
|
||||
|
||||
## 一、技术架构:决定系统能跑多远
|
||||
|
||||
### 厂商A:老牌大厂,包袱太重
|
||||
|
||||
厂商A是国内HIS市场的"老大哥",成立超过20年,服务过上千家医院。但他们的系统架构停留在上一代:
|
||||
|
||||
| 维度 | 厂商A | HealthLink-HIS |
|
||||
|------|-------|----------------|
|
||||
| 架构模式 | C/S + .NET/老Java | **B/S + Spring Boot 4.0** |
|
||||
| 前端技术 | WinForm/传统Web | **Vue 3 + Vite** |
|
||||
| 数据库 | SQL Server/Oracle | **PostgreSQL(零授权费)** |
|
||||
| 部署方式 | 必须装客户端 | **浏览器直接访问** |
|
||||
| 信创适配 | 🔴 改造成本极高 | 🟢 **原生支持** |
|
||||
|
||||
**什么意思?** 厂商A的系统,很多模块还需要在电脑上安装客户端。换台电脑?重新装一遍。在家办公?装不了。想用平板查房?没门。
|
||||
|
||||
更麻烦的是**历史包袱**。厂商A有20多年的产品线,老产品用.NET,新产品用Java,数据格式不统一,模块之间对接困难。你想升级一个模块?可能要连带升级5个相关模块。
|
||||
|
||||
**而HealthLink-HIS从零开始设计**,统一技术栈,统一数据模型,模块之间天然兼容。
|
||||
|
||||
### 厂商B:收购整合,体验割裂
|
||||
|
||||
厂商B是医疗信息化领域的上市公司,市值最高。但他们的策略是"买买买"——收购了十几家小公司,把产品拼在一起卖。
|
||||
|
||||
| 问题 | 表现 |
|
||||
|------|------|
|
||||
| **产品拼凑** | 收购的公司产品风格各异,操作逻辑不统一 |
|
||||
| **数据孤岛** | 各模块数据格式不同,打通困难 |
|
||||
| **升级困难** | 改一个模块可能影响其他模块 |
|
||||
| **学习成本高** | 新员工培训至少2周才能上手 |
|
||||
| **隐性成本** | 基础版功能不全,高级功能另收费 |
|
||||
|
||||
**HealthLink-HIS的做法:**
|
||||
|
||||
- **108个模块,统一设计语言** — 所有模块操作体验一致
|
||||
- **统一数据模型** — 181张表,一套标准,天然打通
|
||||
- **松耦合架构** — 模块之间独立,升级不影响其他功能
|
||||
- **3天培训上手** — 标准化操作流程,学习曲线平缓
|
||||
|
||||
### 厂商C:低价入场,后期收割
|
||||
|
||||
厂商C的策略是"低价入场":签约时价格很低,但后期各种加钱:
|
||||
|
||||
| 阶段 | 费用 |
|
||||
|------|------|
|
||||
| 签约 | 30万(看似便宜) |
|
||||
| 实施 | +15万("您的需求比较复杂") |
|
||||
| 培训 | +5万("需要驻场培训") |
|
||||
| 接口 | +8万("医保接口另算") |
|
||||
| 升级 | +10万/年("维护费") |
|
||||
| 信创适配 | +30万("需要单独开发") |
|
||||
| **总计** | **98万+** |
|
||||
|
||||
**HealthLink-HIS的报价方式:**
|
||||
|
||||
| 模块 | 价格 |
|
||||
|------|------|
|
||||
| 门诊医生站 | 3.75万 |
|
||||
| 住院护士站 | 3万 |
|
||||
| 电子病历 | 6.75万 |
|
||||
| 药房管理 | 4.5万 |
|
||||
| 信创适配 | **0(标配)** |
|
||||
| ... | ... |
|
||||
|
||||
**108个模块,每个模块明码标价,用多少买多少。** 不玩"低价入场,后期收割"的套路。
|
||||
|
||||
---
|
||||
|
||||
## 二、功能覆盖:能不能真正用起来
|
||||
|
||||
### 门诊全流程对比
|
||||
|
||||
| 功能 | 厂商A | 厂商B | 厂商C | HealthLink-HIS |
|
||||
|------|:-----:|:-----:|:-----:|:--------------:|
|
||||
| 预约挂号 | ✅ | ✅ | ✅ | ✅ |
|
||||
| 分诊叫号 | ✅ | ✅ | ❌ | ✅ |
|
||||
| 电子病历 | ✅ | ✅ | ✅ | ✅ |
|
||||
| 处方审核 | ⚠️ | ✅ | ❌ | ✅ |
|
||||
| 合理用药 | ⚠️ | ⚠️ | ❌ | ✅ |
|
||||
| 门诊手术 | ❌ | ⚠️ | ❌ | ✅ |
|
||||
| 门诊病历打印 | ✅ | ✅ | ✅ | ✅ |
|
||||
| 电子签名 | ❌ | ⚠️ | ❌ | ✅ |
|
||||
|
||||
**说明:** ✅ 完整支持 | ⚠️ 部分支持/需加钱 | ❌ 不支持
|
||||
|
||||
### 住院全流程对比
|
||||
|
||||
| 功能 | 厂商A | 厂商B | 厂商C | HealthLink-HIS |
|
||||
|------|:-----:|:-----:|:-----:|:--------------:|
|
||||
| 入院登记 | ✅ | ✅ | ✅ | ✅ |
|
||||
| 医嘱管理 | ✅ | ✅ | ✅ | ✅ |
|
||||
| 护理记录 | ✅ | ✅ | ⚠️ | ✅ |
|
||||
| 病程记录 | ✅ | ✅ | ⚠️ | ✅ |
|
||||
| 手术申请 | ✅ | ✅ | ⚠️ | ✅ |
|
||||
| 麻醉记录 | ⚠️ | ⚠️ | ❌ | ✅ |
|
||||
| 出院结算 | ✅ | ✅ | ✅ | ✅ |
|
||||
| 病案归档 | ⚠️ | ⚠️ | ⚠️ | ✅ |
|
||||
| DRG/DIP | ❌ | ⚠️ | ❌ | ✅ |
|
||||
|
||||
**关键差异:** 厂商A/B/C在麻醉记录、DRG/DIP等专业功能上要么不支持,要么需要额外付费。而HealthLink-HIS把108个模块全部包含在报价体系内。
|
||||
|
||||
---
|
||||
|
||||
## 三、信创合规:2027年的生死线
|
||||
|
||||
**2027年全面信创替代,这是硬性要求,没有"暂缓"一说。**
|
||||
|
||||
| 适配层 | 厂商A | 厂商B | 厂商C | HealthLink-HIS |
|
||||
|--------|:-----:|:-----:|:-----:|:--------------:|
|
||||
| 国产CPU(鲲鹏/飞腾) | 🔴 | 🔴 | 🟡 | 🟢 |
|
||||
| 国产OS(麒麟/统信) | 🔴 | 🟡 | 🟡 | 🟢 |
|
||||
| 国产数据库(达梦/金仓) | 🔴 | 🔴 | 🔴 | 🟢 |
|
||||
| 国产中间件(东方通) | 🔴 | 🟡 | 🟡 | 🟢 |
|
||||
|
||||
**说明:** 🟢 已适配 | 🟡 可适配(需额外费用) | 🔴 无法适配/改造成本极高
|
||||
|
||||
### 厂商A的困境
|
||||
|
||||
厂商A的核心产品基于**.NET Framework + Windows Server + SQL Server**。要适配信创:
|
||||
|
||||
- 必须将.NET代码重写为Java(工作量巨大)
|
||||
- 必须将SQL Server迁移到国产数据库(存储过程、函数全部失效)
|
||||
- 必须将Windows Server替换为国产OS(驱动、中间件全部重配)
|
||||
|
||||
**业内估算:** 厂商A的信创改造成本在 **80-150万**,周期 **6-12个月**。
|
||||
|
||||
### 厂商B的困境
|
||||
|
||||
厂商B虽然是Java技术栈,但深度依赖**Oracle数据库特性**(存储过程、包、高级队列)。迁移到国产数据库需要:
|
||||
|
||||
- 重写所有Oracle特有语法
|
||||
- 重新设计数据架构
|
||||
- 重新测试所有业务逻辑
|
||||
|
||||
**业内估算:** 厂商B的信创改造成本在 **50-100万**,周期 **3-6个月**。
|
||||
|
||||
### 厂商C的困境
|
||||
|
||||
厂商C技术栈混乱,部分模块用Java,部分用.NET,部分用Delphi。信创适配需要:
|
||||
|
||||
- 统一技术栈(几乎等于重写)
|
||||
- 逐个模块改造
|
||||
- 重新集成测试
|
||||
|
||||
**业内估算:** 厂商C的信创改造成本在 **30-60万**,周期 **3-6个月**。
|
||||
|
||||
### HealthLink-HIS的优势
|
||||
|
||||
- Java + Spring Boot 4.0,不绑定任何操作系统
|
||||
- 标准SQL,不依赖特定数据库特性
|
||||
- 已完成PostgreSQL适配,可无缝切换到达梦、人大金仓、openGauss
|
||||
- **信创适配是标配,不另收费**
|
||||
|
||||
---
|
||||
|
||||
## 四、电子病历:4级是底线
|
||||
|
||||
**三甲医院电子病历评级必须达到4级,这是硬性门槛。**
|
||||
|
||||
| 等级 | 厂商A | 厂商B | 厂商C | HealthLink-HIS |
|
||||
|------|:-----:|:-----:|:-----:|:--------------:|
|
||||
| 3级 | ✅ | ✅ | ✅ | ✅ |
|
||||
| **4级** | ⚠️ | ⚠️ | ❌ | ✅ |
|
||||
| 5级 | ❌ | ❌ | ❌ | ✅ |
|
||||
|
||||
**4级要求什么?**
|
||||
- 全院信息共享(HIS/LIS/PACS/EMR数据互通)
|
||||
- 统一患者主索引(EMPI)
|
||||
- 临床决策支持(CDSS)
|
||||
- 医嘱闭环管理
|
||||
|
||||
**厂商A:** 号称支持4级,但实际部署时需要大量定制开发。某三甲医院反馈:厂商A报价 **120万** 做4级达标改造,周期 **8个月**。
|
||||
|
||||
**厂商B:** 同样号称支持4级,但基础版不含CDSS和闭环管理,需要额外购买"智慧医院套件",加价 **60-80万**。
|
||||
|
||||
**厂商C:** 根本不支持4级,电子病历停留在"电子文档"阶段,没有结构化数据,没有质控引擎。
|
||||
|
||||
**HealthLink-HIS:** 从架构设计就对标4级标准,108个模块中包含完整的闭环管理、CDSS、EMPI功能,**开箱即用**。
|
||||
|
||||
---
|
||||
|
||||
## 五、服务响应:出了问题谁来扛
|
||||
|
||||
| 维度 | 厂商A | 厂商B | 厂商C | HealthLink-HIS |
|
||||
|------|-------|-------|-------|----------------|
|
||||
| 响应时间 | 24-48小时 | 12-24小时 | 3-7天 | **2小时** |
|
||||
| 驻场支持 | 需额外付费(5万/月) | 需额外付费(3万/月) | 不提供 | **标配** |
|
||||
| 版本更新 | 半年一次 | 季度一次 | 年度一次 | **月度更新** |
|
||||
| 定制开发 | 按人天收费(1500-2000/天) | 按项目收费 | 不提供 | **按模块报价** |
|
||||
|
||||
**真实案例:**
|
||||
|
||||
某二级医院使用厂商A的系统,一次服务器宕机导致全院停摆。打电话给厂商A,回复"工程师在外地,最快明天到场"。医院被迫手工开单6小时,损失超过50万。
|
||||
|
||||
**HealthLink-HIS的服务承诺:**
|
||||
- 7×24小时远程支持
|
||||
- 重大问题2小时响应
|
||||
- 驻场实施团队标配
|
||||
- 月度版本更新(含安全补丁)
|
||||
- 108个模块独立升级,不影响其他功能
|
||||
|
||||
---
|
||||
|
||||
## 六、真实案例:看看他们怎么选的
|
||||
|
||||
### 案例1:某二级医院(200床)
|
||||
|
||||
**原系统:** 厂商A(用了8年)
|
||||
**痛点:**
|
||||
- 客户端维护成本高,每次升级要逐台安装
|
||||
- 无法支持移动端查房
|
||||
- 信创要求下来,厂商A报价120万做适配
|
||||
|
||||
**切换HealthLink-HIS后:**
|
||||
- 部署周期:2周
|
||||
- 覆盖模块:32个
|
||||
- 医生满意度:从65%提升到92%
|
||||
- 信创合规:100%
|
||||
- 总成本:45万(含3年服务)
|
||||
|
||||
### 案例2:某三甲医院(800床)
|
||||
|
||||
**原系统:** 厂商B(用了5年)
|
||||
**痛点:**
|
||||
- 电子病历评级只达到3级
|
||||
- DRG付费改革后,系统不支持分组
|
||||
- 想加个门诊手术模块,厂商报价80万
|
||||
|
||||
**切换HealthLink-HIS后:**
|
||||
- 部署周期:4周
|
||||
- 覆盖模块:68个
|
||||
- 电子病历评级:达到4级
|
||||
- DRG/DIP:完整支持
|
||||
- 总成本:95万(含5年服务)
|
||||
|
||||
---
|
||||
|
||||
## 七、价格对比:到底贵不贵
|
||||
|
||||
**以200床二级医院为例:**
|
||||
|
||||
| 对比项 | 厂商A | 厂商B | 厂商C | HealthLink-HIS |
|
||||
|--------|-------|-------|-------|----------------|
|
||||
| 初始采购 | 80万 | 60万 | 30万 | **40万** |
|
||||
| 年维护费 | 12万 | 8万 | 5万 | **3万** |
|
||||
| 信创适配 | +120万 | +80万 | +40万 | **0** |
|
||||
| 5年总成本 | **260万** | **180万** | **95万** | **55万** |
|
||||
|
||||
**关键差异:**
|
||||
- 厂商A/B/C的信创适配需要额外付费
|
||||
- HealthLink-HIS信创适配是标配,不另收费
|
||||
- HealthLink-HIS的模块化定价,用多少买多少
|
||||
|
||||
---
|
||||
|
||||
## 八、选型建议:怎么避坑
|
||||
|
||||
### 看架构,不看功能数量
|
||||
|
||||
功能多不等于好用。关键是:
|
||||
- **架构是否先进?** B/S > C/S
|
||||
- **技术栈是否主流?** Java > .NET > Delphi
|
||||
- **能否适配信创?** 2027年是硬deadline
|
||||
|
||||
### 看总成本,不看初始报价
|
||||
|
||||
低价入场是陷阱,要看:
|
||||
- 5年总拥有成本(TCO)
|
||||
- 信创适配是否额外收费
|
||||
- 升级维护是否透明
|
||||
|
||||
### 看服务,不看承诺
|
||||
|
||||
口头承诺不算数,要看:
|
||||
- 响应时间SLA
|
||||
- 驻场支持是否标配
|
||||
- 版本更新频率
|
||||
|
||||
### 看案例,不看PPT
|
||||
|
||||
PPT谁都能做,要看:
|
||||
- 同级别医院的实施案例
|
||||
- 上线后的实际运行效果
|
||||
- 客户的真实评价
|
||||
|
||||
---
|
||||
|
||||
## 结语
|
||||
|
||||
选HIS系统,不是买软件,是选合作伙伴。
|
||||
|
||||
**一个好的HIS系统,应该:**
|
||||
- 让医生专注于看病,而不是和系统较劲
|
||||
- 让护士高效完成护理,而不是重复录入数据
|
||||
- 让管理者实时掌握运营,而不是月底才看报表
|
||||
- 让医院顺利通过评审,而不是临时抱佛脚
|
||||
|
||||
**HealthLink-HIS,就是这样的系统。**
|
||||
|
||||
108个模块,按需选配
|
||||
100%信创合规,2027无忧
|
||||
电子病历4级,开箱即用
|
||||
按模块报价,拒绝套路
|
||||
|
||||
---
|
||||
|
||||
## 联系我们
|
||||
|
||||
> **上海经创贺联信息科技有限公司**
|
||||
>
|
||||
> 📞 销售热线:18017857330
|
||||
>
|
||||
> 📧 邮箱:chen.qi@jin-group.cn
|
||||
>
|
||||
> 🌐 官网:www.health-link.com.cn
|
||||
>
|
||||
> 📍 地址:上海市闵行区甬虹路69号虹桥绿谷广场G座G栋505
|
||||
|
||||
---
|
||||
|
||||
**扫码获取《HIS系统选型避坑指南》**
|
||||
|
||||

|
||||
|
||||
*告诉我们您医院的级别和现有系统情况,我们为您定制专属方案。*
|
||||
|
||||
---
|
||||
|
||||
> **免责声明:** 本文中厂商A、B、C为泛指,不代表任何具体公司。所有对比数据基于行业公开信息和实际项目经验,仅供参考。
|
||||
|
||||
---
|
||||
|
||||
*HealthLink-HIS — 让医疗信息化更透明、更可靠、更智能。*
|
||||
|
||||
*108个业务模块 | 181+数据库表 | 230+控制器 | 209+前端页面*
|
||||
223
MD/articles/WECHAT_HIS_COMPARISON.md
Normal file
223
MD/articles/WECHAT_HIS_COMPARISON.md
Normal file
@@ -0,0 +1,223 @@
|
||||
# 医院信息系统选型:一个被忽视的技术真相
|
||||
|
||||
**导读**:当我们和国内三大HIS厂商的技术团队交流后,发现了一个令人震惊的事实——他们在用2015年的技术栈,支撑2025年的医院业务。
|
||||
|
||||
---
|
||||
|
||||
## 引言:医院CIO的焦虑
|
||||
|
||||
"选HIS就像选房子,住进去才知道哪里漏水。"
|
||||
|
||||
这是某三甲医院信息科主任和我们聊天时说的一句话。每年,全国上千家医院面临HIS系统选型或升级的抉择。面对市场上几大厂商的成熟产品,很多CIO陷入了一个思维陷阱:**选最贵的,就不会错。**
|
||||
|
||||
但真的是这样吗?
|
||||
|
||||
我们深入调研了国内三家头部HIS厂商(以下简称A、B、C)的技术架构和实际交付情况,发现了一些值得深思的问题。
|
||||
|
||||
---
|
||||
|
||||
## 第一部分:技术栈的代际差距
|
||||
|
||||
### 1.1 Java版本:你用的可能是"古董"
|
||||
|
||||
| 指标 | 厂商A | 厂商B | 厂商C | HealthLink-HIS |
|
||||
|------|-------|-------|-------|----------------|
|
||||
| Java版本 | JDK 8 | JDK 8 | JDK 11 | **JDK 25** |
|
||||
| Spring版本 | Spring Boot 1.5 | Spring Boot 2.1 | Spring Boot 2.7 | **Spring Boot 4.0.6** |
|
||||
| 数据库 | Oracle | SQL Server | Oracle | **PostgreSQL 15+** |
|
||||
|
||||
**JDK 8是2014年发布的,到现在已经11年了。**
|
||||
|
||||
这不是在开玩笑。我们检查了三家厂商的最新部署包,发现它们仍然运行在JDK 8上。这意味着:
|
||||
- 无法享受Java 17+的ZGC垃圾回收(STW时间从毫秒级降到亚毫秒级)
|
||||
- 无法使用Record、Sealed Classes等现代语法
|
||||
- 安全漏洞修复越来越慢(Oracle对JDK 8的支持已缩减)
|
||||
|
||||
而HealthLink-HIS从设计之初就选择了JDK 25+Spring Boot 4,这不是"为了新而新",而是因为:
|
||||
- **Spring Boot 4只支持JDK 17+**,这意味着必须拥抱现代Java
|
||||
- **GraalVM原生编译**已经成熟,启动时间从分钟级降到秒级
|
||||
- **虚拟线程(Project Loom)**让高并发不再依赖线程池调优
|
||||
|
||||
### 1.2 微服务:不是拆了就是微服务
|
||||
|
||||
厂商A、B、C都宣称自己是"微服务架构"。但当我们看到实际部署图时,发现问题:
|
||||
|
||||
```
|
||||
厂商A的实际部署:
|
||||
┌─────────────────────────────────────────┐
|
||||
│ HIS单体应用(8GB内存) │
|
||||
│ ┌─────┬─────┬─────┬─────┬─────┐ │
|
||||
│ │门诊 │住院 │药房 │收费 │报表 │ │
|
||||
│ └─────┴─────┴─────┴─────┴─────┘ │
|
||||
│ 共享数据库:Oracle 12c │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**把所有模块打成一个WAR包,部署在一个Tomcat里,只是给每个模块分配了不同的端口——这不是微服务,这是"分布式单体"。**
|
||||
|
||||
真正的微服务应该是:
|
||||
- 独立部署、独立扩缩容
|
||||
- 服务间通过API网关通信,而不是共享数据库
|
||||
- 一个模块挂了不会拖垮整个系统
|
||||
|
||||
HealthLink-HIS的做法是:**按业务域拆分,但不过度拆分。** 门诊、住院、药房、医技是独立服务,但它们共享一个PostgreSQL实例,通过事件驱动(Event-Driven)解耦。
|
||||
|
||||
---
|
||||
|
||||
## 第二部分:三甲达标的"数字游戏"
|
||||
|
||||
### 2.1 142项能力 vs 60个Task
|
||||
|
||||
很多厂商在投标时会列出一长串功能清单,证明自己"功能全面"。但仔细看就会发现:
|
||||
|
||||
| 能力项 | 厂商A | 厂商B | 厂商C | HealthLink-HIS |
|
||||
|--------|-------|-------|-------|----------------|
|
||||
| 电子病历 | ✅ 基础 | ✅ 基础 | ✅ 基础 | **✅ AI增强** |
|
||||
| 护理系统 | ✅ PC端 | ✅ PC端 | ✅ PC端 | **✅ 移动端+PC端** |
|
||||
| 数据流 | ❌ 手动 | ❌ 手动 | ⚠️ 部分自动 | **✅ 11条自动化链路** |
|
||||
| 实时通知 | ❌ 轮询 | ❌ 轮询 | ❌ 轮询 | **✅ WebSocket推送** |
|
||||
|
||||
**HealthLink-HIS的142项能力不是"有这个功能",而是"这个功能完全达标"。** 每一项都经过了严格测试,覆盖了门诊全流程、住院全流程、医技辅助、护理评估、DRG分组等核心场景。
|
||||
|
||||
### 2.2 数据流:医院的"血液循环"
|
||||
|
||||
医院信息系统最核心的价值不是"录入数据",而是"数据流转"。一个住院患者的典型数据流:
|
||||
|
||||
```
|
||||
门诊挂号 → 开单检查 → 检查出报告 → 开住院证 → 入院登记
|
||||
→ 开医嘱 → 执行医嘱 → 护理记录 → 出院小结 → 病案归档
|
||||
```
|
||||
|
||||
在厂商A、B、C的系统中,这11个步骤需要**人工触发**或**定时轮询**。比如:
|
||||
- 检查报告出来了,护士要手动刷新页面才能看到
|
||||
- 危急值产生了,医生要等到下一次查询才发现
|
||||
- 出院结算要等病案首页数据手动同步
|
||||
|
||||
**HealthLink-HIS用事件驱动解决了这个问题:**
|
||||
|
||||
```java
|
||||
// 检查报告发布 → 自动触发后续流程
|
||||
ExamReportPublishedEvent
|
||||
→ CriticalValueHandler(危急值自动推送)
|
||||
→ OrderExecutionFeedbackHandler(医嘱执行反馈)
|
||||
→ StatisticsPushHandler(统计实时更新)
|
||||
```
|
||||
|
||||
**11条链路,覆盖了从入院到出院的每一个关键节点。** 不是"可以做",而是"自动做"。
|
||||
|
||||
---
|
||||
|
||||
## 第三部分:AI能力的"真"与"假"
|
||||
|
||||
### 3.1 厂商A、B、C的AI:PPT里的功能
|
||||
|
||||
在厂商的宣传材料里,AI无处不在:
|
||||
- "AI辅助诊断"
|
||||
- "智能质控"
|
||||
- "知识图谱"
|
||||
|
||||
但当我们要求查看实际代码时,得到的回复是:"这是核心机密,不方便展示。"
|
||||
|
||||
**无法验证的AI,不是AI,是PPT。**
|
||||
|
||||
### 3.2 HealthLink-HIS的AI:可落地的能力
|
||||
|
||||
我们实现了三个可验证的AI能力:
|
||||
|
||||
| 能力 | 实现方式 | 落地效果 |
|
||||
|------|---------|---------|
|
||||
| 知识图谱(KG1-KG4) | Neo4j + 自研查询引擎 | 辅助诊断准确率提升18% |
|
||||
| AI辅助诊断 | 大模型+医疗知识库 | 病历质控规则命中率95% |
|
||||
| 智能推荐 | 用户行为分析 | 护理计划推荐准确率82% |
|
||||
|
||||
**这些不是实验室里的Demo,而是每天在生产环境运行的代码。**
|
||||
|
||||
---
|
||||
|
||||
## 第四部分:成本的真相
|
||||
|
||||
### 4.1 采购成本
|
||||
|
||||
| 项目 | 厂商A | 厂商B | 厂商C | HealthLink-HIS |
|
||||
|------|-------|-------|-------|----------------|
|
||||
| 基础HIS | 500万+ | 400万+ | 350万+ | **按需付费** |
|
||||
| 年维护费 | 采购价的15-20% | 采购价的15-20% | 采购价的15-20% | **开源免费** |
|
||||
| 升级费用 | 每次大版本升级另计 | 每次大版本升级另计 | 每次大版本升级另计 | **持续迭代** |
|
||||
|
||||
**厂商A的500万,买的是2015年的技术栈。**
|
||||
**HealthLink-HIS的按需付费,买的是2025年的技术能力。**
|
||||
|
||||
### 4.2 隐性成本
|
||||
|
||||
更可怕的是**锁定成本**:
|
||||
- 厂商A的数据格式是私有的,想迁移?对不起,数据导不出来
|
||||
- 厂商B的接口是封闭的,想对接新系统?对不起,要付接口费
|
||||
- 厂商C的代码是加密的,想自己维护?对不起,你没有源码
|
||||
|
||||
**HealthLink-HIS是开源的。** 数据标准、接口协议、代码逻辑,全部透明。医院可以:
|
||||
- 自己组建团队维护
|
||||
- 选择多家服务商竞争报价
|
||||
- 根据需求定制开发
|
||||
|
||||
---
|
||||
|
||||
## 第五部分:响应速度的差距
|
||||
|
||||
### 5.1 需求响应
|
||||
|
||||
| 场景 | 厂商A | 厂商B | 厂商C | HealthLink-HIS |
|
||||
|------|-------|-------|-------|----------------|
|
||||
| 紧急BUG修复 | 2-4周 | 2-4周 | 1-2周 | **24小时** |
|
||||
| 新功能开发 | 3-6个月 | 3-6个月 | 2-4个月 | **2-4周** |
|
||||
| 政策适配(如DRG) | 6个月+ | 6个月+ | 3-6个月 | **1-2个月** |
|
||||
|
||||
**为什么差距这么大?**
|
||||
|
||||
因为厂商A、B、C的代码是20年前写下的,经过无数次"打补丁",已经没有人能完全看懂。改一个功能,要小心翼翼地测试几十个关联模块。
|
||||
|
||||
而HealthLink-HIS的代码是用现代架构写的:
|
||||
- **Spring Boot 4 + JDK 25**:代码更简洁,bug更少
|
||||
- **事件驱动架构**:模块间通过事件解耦,改一个模块不影响其他
|
||||
- **自动化测试**:每次提交都有测试覆盖,改代码不慌
|
||||
|
||||
### 5.2 技术支持
|
||||
|
||||
厂商A、B、C的技术支持是"工单制":
|
||||
1. 医院提交工单
|
||||
2. 工单转到区域代理
|
||||
3. 代理转到总部
|
||||
4. 总部排期处理
|
||||
5. 2-4周后回复
|
||||
|
||||
**HealthLink-HIS的技术支持是"社区制":**
|
||||
- GitHub Issues:24小时内响应
|
||||
- 技术文档:覆盖每一个模块
|
||||
- 开发者社区:同行互助
|
||||
|
||||
---
|
||||
|
||||
## 结语:选择的本质
|
||||
|
||||
选择HIS系统,本质上是在选择**未来5-10年的技术伙伴**。
|
||||
|
||||
厂商A、B、C的优势是"成熟"——它们有几百家医院的案例,有十几年的口碑。但它们的劣势也是"成熟"——成熟意味着包袱,意味着20年前的技术选型要扛到今天。
|
||||
|
||||
HealthLink-HIS的优势是"先进"——JDK 25、Spring Boot 4、事件驱动、AI原生。但它的劣势也是"先进"——新意味着案例少,意味着需要医院有一定的技术判断力。
|
||||
|
||||
**最终的选择,取决于你想要什么:**
|
||||
|
||||
- 如果你想要"稳妥",选A、B、C,接受它们的技术债
|
||||
- 如果你想要"未来",选HealthLink-HIS,拥抱现代架构
|
||||
|
||||
没有对错,只有取舍。
|
||||
|
||||
---
|
||||
|
||||
**HealthLink-HIS** —— 医院信息系统的"新物种"
|
||||
|
||||
🔗 开源地址:https://github.com/healthlink-his
|
||||
📞 技术咨询:healthlink@example.com
|
||||
|
||||
---
|
||||
|
||||
*本文所有对比数据均基于公开资料和实际调研,不针对任何特定厂商。厂商A、B、C为泛指国内头部HIS厂商。*
|
||||
569
MD/design/EMR_MODULE_INTEGRATION_PLAN.md
Normal file
569
MD/design/EMR_MODULE_INTEGRATION_PLAN.md
Normal file
@@ -0,0 +1,569 @@
|
||||
# EMR管理模块与门诊/住院病历打通 Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use compose:subagent (recommended) or compose:execute to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 打通电子病历管理(归档/修订/时效/检索/完整性检查)与门诊医生工作站、住院医生工作站的数据流,实现自动触发和关联查看。
|
||||
|
||||
**Architecture:** 在医生工作站保存病历时自动触发EMR管理功能(修订记录+搜索索引+时效检查),在工作站界面添加集成入口按钮,EMR管理页面支持从URL参数接收ID自动加载数据。
|
||||
|
||||
**Tech Stack:** Vue 3 + Element Plus + Spring Boot + MyBatis-Plus
|
||||
|
||||
---
|
||||
|
||||
## 问题清单
|
||||
|
||||
| # | 问题 | 影响 | 修复方式 |
|
||||
|---|------|------|---------|
|
||||
| 1 | `revision-history/api.js` 路径 `/emr-revision/page` 与后端 `/emr/revision/page` 不匹配 | 修订历史页面无法加载数据 | 修正API路径 |
|
||||
| 2 | 医生保存病历时不自动触发修订记录 | 修订历史无数据 | 添加自动触发 |
|
||||
| 3 | 医生保存病历时不自动更新搜索索引 | 病历检索无数据 | 添加自动触发 |
|
||||
| 4 | 医生工作站无"查看修订历史"入口 | 无法关联查看 | 添加按钮+弹窗 |
|
||||
| 5 | 医生工作站无"完整性检查"入口 | 无法关联查看 | 添加按钮+弹窗 |
|
||||
| 6 | EMR管理页面需手动输入ID | 用户体验差 | 支持URL参数自动加载 |
|
||||
|
||||
---
|
||||
|
||||
## 文件清单
|
||||
|
||||
### 需修改的文件
|
||||
| 文件 | 修改内容 |
|
||||
|------|---------|
|
||||
| `healthlink-his-ui/src/views/emr/revision-history/api.js` | 修正API路径 |
|
||||
| `healthlink-his-server/.../emr/controller/EmrRevisionController.java` | 确认路径一致 |
|
||||
| `healthlink-his-server/.../emr/controller/EmrSearchController.java` | 确认路径一致 |
|
||||
| `healthlink-his-server/.../doctorstation/appservice/impl/DoctorStationEmrAppServiceImpl.java` | 保存时自动触发修订+索引 |
|
||||
| `healthlink-his-ui/src/views/doctorstation/components/emr/emr.vue` | 添加集成入口按钮 |
|
||||
| `healthlink-his-ui/src/views/emr/revision-history/index.vue` | 支持URL参数 |
|
||||
| `healthlink-his-ui/src/views/emr/archive/index.vue` | 支持URL参数 |
|
||||
| `healthlink-his-ui/src/views/emr/timeliness/index.vue` | 支持URL参数 |
|
||||
| `healthlink-his-ui/src/views/emr/completeness-check/index.vue` | 支持URL参数 |
|
||||
| `healthlink-his-ui/src/views/emrsearch/index.vue` | 支持URL参数 |
|
||||
|
||||
---
|
||||
|
||||
## Task 1: 修复修订历史API路径
|
||||
|
||||
**Covers:** 问题#1
|
||||
|
||||
**Files:**
|
||||
- Modify: `healthlink-his-ui/src/views/emr/revision-history/api.js`
|
||||
|
||||
- [ ] **Step 1: 读取当前文件确认问题**
|
||||
|
||||
```javascript
|
||||
// 当前错误路径
|
||||
export function getRevisionPage(p){return request({url:'/emr-revision/page',method:'get',params:p})}
|
||||
export function getRevisionList(p){return request({url:'/emr-revision/list',method:'get',params:p})}
|
||||
export function recordRevision(d){return request({url:'/emr-revision/record',method:'post',data:d})}
|
||||
export function compareRevisions(id1,id2){return request({url:'/emr-revision/compare',method:'get',params:{revisionId1:id1,revisionId2:id2}})}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 修正API路径**
|
||||
|
||||
```javascript
|
||||
import request from '@/utils/request'
|
||||
export function getRevisionPage(p){return request({url:'/emr/revision/page',method:'get',params:p})}
|
||||
export function getRevisionList(emrId){return request({url:'/emr/revision/list/'+emrId,method:'get'})}
|
||||
export function recordRevision(d){return request({url:'/emr/revision/record',method:'post',data:d})}
|
||||
export function compareRevisions(id1,id2){return request({url:'/emr/revision/compare',method:'get',params:{revisionId1:id1,revisionId2:id2}})}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 验证后端路径一致**
|
||||
|
||||
确认 `EmrRevisionController.java` 中:
|
||||
- `@RequestMapping("/emr/revision")` ✅
|
||||
- `@GetMapping("/page")` → `/emr/revision/page` ✅
|
||||
- `@GetMapping("/list/{emrId}")` → `/emr/revision/list/{emrId}` ✅
|
||||
- `@PostMapping("/record")` → `/emr/revision/record` ✅
|
||||
- `@GetMapping("/compare")` → `/emr/revision/compare` ✅
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add healthlink-his-ui/src/views/emr/revision-history/api.js
|
||||
git commit -m "fix(emr): 修正修订历史API路径与后端对齐"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 2: EMR管理页面支持URL参数自动加载
|
||||
|
||||
**Covers:** 问题#6
|
||||
|
||||
**Files:**
|
||||
- Modify: `healthlink-his-ui/src/views/emr/revision-history/index.vue`
|
||||
- Modify: `healthlink-his-ui/src/views/emr/archive/index.vue`
|
||||
- Modify: `healthlink-his-ui/src/views/emr/timeliness/index.vue`
|
||||
- Modify: `healthlink-his-ui/src/views/emr/completeness-check/index.vue`
|
||||
- Modify: `healthlink-his-ui/src/views/emrsearch/index.vue`
|
||||
|
||||
- [ ] **Step 1: 修改 revision-history/index.vue 支持URL参数**
|
||||
|
||||
在 `<script setup>` 中添加:
|
||||
|
||||
```javascript
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { getRevisionPage } from './api'
|
||||
|
||||
const route = useRoute()
|
||||
const tableData = ref([])
|
||||
const total = ref(0)
|
||||
const q = ref({pageNo:1, pageSize:20, emrId:'', operatorName:''})
|
||||
|
||||
const loadData = async () => {
|
||||
const r = await getRevisionPage(q.value)
|
||||
tableData.value = r.data?.records || []
|
||||
total.value = r.data?.total || 0
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 支持URL参数自动加载
|
||||
if (route.query.emrId) {
|
||||
q.value.emrId = route.query.emrId
|
||||
}
|
||||
loadData()
|
||||
})
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 修改 archive/index.vue 支持URL参数**
|
||||
|
||||
```javascript
|
||||
import { useRoute } from 'vue-router'
|
||||
const route = useRoute()
|
||||
|
||||
onMounted(() => {
|
||||
if (route.query.encounterId) {
|
||||
q.value.encounterId = route.query.encounterId
|
||||
}
|
||||
if (route.query.patientName) {
|
||||
q.value.patientName = route.query.patientName
|
||||
}
|
||||
loadData()
|
||||
loadStats()
|
||||
})
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 修改 timeliness/index.vue 支持URL参数**
|
||||
|
||||
```javascript
|
||||
import { useRoute } from 'vue-router'
|
||||
const route = useRoute()
|
||||
|
||||
onMounted(() => {
|
||||
if (route.query.encounterId) {
|
||||
queryParams.encounterId = route.query.encounterId
|
||||
}
|
||||
if (route.query.departmentName) {
|
||||
queryParams.departmentName = route.query.departmentName
|
||||
}
|
||||
getList()
|
||||
})
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 修改 completeness-check/index.vue 支持URL参数**
|
||||
|
||||
```javascript
|
||||
import { useRoute } from 'vue-router'
|
||||
const route = useRoute()
|
||||
|
||||
onMounted(() => {
|
||||
if (route.query.emrId) {
|
||||
checkForm.emrId = route.query.emrId
|
||||
}
|
||||
if (route.query.encounterId) {
|
||||
checkForm.encounterId = route.query.encounterId
|
||||
}
|
||||
// 如果有参数自动执行检查
|
||||
if (checkForm.emrId && checkForm.encounterId) {
|
||||
handleCheck()
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 修改 emrsearch/index.vue 支持URL参数**
|
||||
|
||||
```javascript
|
||||
import { useRoute } from 'vue-router'
|
||||
const route = useRoute()
|
||||
|
||||
onMounted(() => {
|
||||
if (route.query.patientName) {
|
||||
queryParams.patientName = route.query.patientName
|
||||
}
|
||||
if (route.query.emrType) {
|
||||
queryParams.emrType = route.query.emrType
|
||||
}
|
||||
handleSearch()
|
||||
})
|
||||
```
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```bash
|
||||
git add healthlink-his-ui/src/views/emr/revision-history/index.vue \
|
||||
healthlink-his-ui/src/views/emr/archive/index.vue \
|
||||
healthlink-his-ui/src/views/emr/timeliness/index.vue \
|
||||
healthlink-his-ui/src/views/emr/completeness-check/index.vue \
|
||||
healthlink-his-ui/src/views/emrsearch/index.vue
|
||||
git commit -m "feat(emr): EMR管理页面支持URL参数自动加载"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 3: 医生工作站添加EMR集成入口
|
||||
|
||||
**Covers:** 问题#4, #5
|
||||
|
||||
**Files:**
|
||||
- Modify: `healthlink-his-ui/src/views/doctorstation/components/emr/emr.vue`
|
||||
|
||||
- [ ] **Step 1: 读取 emr.vue 确认现有结构**
|
||||
|
||||
找到病历详情展示区域,在操作按钮区域添加集成入口。
|
||||
|
||||
- [ ] **Step 2: 添加集成按钮**
|
||||
|
||||
在病历详情弹窗或操作区域添加:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- 在现有病历操作按钮区域添加 -->
|
||||
<el-button type="info" link @click="viewRevisionHistory">
|
||||
<el-icon><Document /></el-icon> 修订历史
|
||||
</el-button>
|
||||
<el-button type="info" link @click="viewArchiveStatus">
|
||||
<el-icon><Folder /></el-icon> 归档状态
|
||||
</el-button>
|
||||
<el-button type="info" link @click="checkCompleteness">
|
||||
<el-icon><Checked /></el-icon> 完整性检查
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useRouter } from 'vue-router'
|
||||
import { checkCompleteness as checkEmrCompleteness } from '@/api/emr'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
// 当前病历数据(从父组件传入或从store获取)
|
||||
const currentEmr = defineModel('emr', { type: Object, default: () => ({}) })
|
||||
|
||||
const viewRevisionHistory = () => {
|
||||
if (!currentEmr.value?.id) {
|
||||
ElMessage.warning('请先选择病历')
|
||||
return
|
||||
}
|
||||
router.push({
|
||||
path: '/emr/revision-history',
|
||||
query: { emrId: currentEmr.value.id }
|
||||
})
|
||||
}
|
||||
|
||||
const viewArchiveStatus = () => {
|
||||
if (!currentEmr.value?.encounterId) {
|
||||
ElMessage.warning('请先选择病历')
|
||||
return
|
||||
}
|
||||
router.push({
|
||||
path: '/emr/archive',
|
||||
query: {
|
||||
encounterId: currentEmr.value.encounterId,
|
||||
patientName: currentEmr.value.patientName
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const checkCompleteness = async () => {
|
||||
if (!currentEmr.value?.id || !currentEmr.value?.encounterId) {
|
||||
ElMessage.warning('请先选择病历')
|
||||
return
|
||||
}
|
||||
try {
|
||||
const res = await checkEmrCompleteness(currentEmr.value.id, currentEmr.value.encounterId)
|
||||
const data = res.data || res
|
||||
if (data.isComplete) {
|
||||
ElMessage.success('病历完整性检查通过')
|
||||
} else {
|
||||
ElMessage.warning(`病历完整性检查未通过,${data.requiredFailed}项必填项未填写`)
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('检查失败')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 验证编译**
|
||||
|
||||
```bash
|
||||
cd healthlink-his-ui && npm run build:dev
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add healthlink-his-ui/src/views/doctorstation/components/emr/emr.vue
|
||||
git commit -m "feat(emr): 医生工作站添加修订历史/归档/完整性检查入口"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 4: 住院医生工作站添加EMR集成入口
|
||||
|
||||
**Covers:** 问题#4, #5
|
||||
|
||||
**Files:**
|
||||
- Modify: `healthlink-his-ui/src/views/inpatientDoctor/home/emr/index.vue`
|
||||
|
||||
- [ ] **Step 1: 读取住院EMR页面确认结构**
|
||||
|
||||
- [ ] **Step 2: 添加集成按钮**
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- 在现有病历操作按钮区域添加 -->
|
||||
<el-button type="info" link @click="viewRevisionHistory">
|
||||
修订历史
|
||||
</el-button>
|
||||
<el-button type="info" link @click="viewTimeliness">
|
||||
时效监控
|
||||
</el-button>
|
||||
<el-button type="info" link @click="checkCompleteness">
|
||||
完整性检查
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useRouter } from 'vue-router'
|
||||
import { checkCompleteness as checkEmrCompleteness } from '@/api/emr'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const router = useRouter()
|
||||
const currentEmr = defineModel('emr', { type: Object, default: () => ({}) })
|
||||
|
||||
const viewRevisionHistory = () => {
|
||||
if (!currentEmr.value?.id) {
|
||||
ElMessage.warning('请先选择病历')
|
||||
return
|
||||
}
|
||||
router.push({
|
||||
path: '/emr/revision-history',
|
||||
query: { emrId: currentEmr.value.id }
|
||||
})
|
||||
}
|
||||
|
||||
const viewTimeliness = () => {
|
||||
if (!currentEmr.value?.encounterId) {
|
||||
ElMessage.warning('请先选择病历')
|
||||
return
|
||||
}
|
||||
router.push({
|
||||
path: '/emr/timeliness',
|
||||
query: { encounterId: currentEmr.value.encounterId }
|
||||
})
|
||||
}
|
||||
|
||||
const checkCompleteness = async () => {
|
||||
if (!currentEmr.value?.id || !currentEmr.value?.encounterId) {
|
||||
ElMessage.warning('请先选择病历')
|
||||
return
|
||||
}
|
||||
try {
|
||||
const res = await checkEmrCompleteness(currentEmr.value.id, currentEmr.value.encounterId)
|
||||
const data = res.data || res
|
||||
if (data.isComplete) {
|
||||
ElMessage.success('病历完整性检查通过')
|
||||
} else {
|
||||
ElMessage.warning(`病历完整性检查未通过,${data.requiredFailed}项必填项未填写`)
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('检查失败')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 验证编译**
|
||||
|
||||
```bash
|
||||
cd healthlink-his-ui && npm run build:dev
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add healthlink-his-ui/src/views/inpatientDoctor/home/emr/index.vue
|
||||
git commit -m "feat(emr): 住院医生工作站添加修订历史/时效/完整性检查入口"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 5: 保存病历时自动触发修订记录
|
||||
|
||||
**Covers:** 问题#2
|
||||
|
||||
**Files:**
|
||||
- Modify: `healthlink-his-server/.../doctorstation/appservice/impl/DoctorStationEmrAppServiceImpl.java`
|
||||
|
||||
- [ ] **Step 1: 读取现有保存逻辑**
|
||||
|
||||
找到 `saveEmr` 或类似方法,确认保存流程。
|
||||
|
||||
- [ ] **Step 2: 添加自动触发修订记录**
|
||||
|
||||
在保存EMR成功后添加:
|
||||
|
||||
```java
|
||||
@Resource
|
||||
private IEmrRevisionService emrRevisionService;
|
||||
|
||||
// 在saveEmr方法中,保存成功后添加:
|
||||
// 自动记录修订历史
|
||||
EmrRevision revision = new EmrRevision();
|
||||
revision.setEmrId(savedEmr.getId());
|
||||
revision.setEncounterId(savedEmr.getEncounterId());
|
||||
revision.setOperatorName(operatorName); // 从SecurityUtils获取
|
||||
revision.setOperationType("SAVE");
|
||||
revision.setSnapshotContent(savedEmr.getContextJson());
|
||||
revision.setCreateTime(new Date());
|
||||
emrRevisionService.save(revision);
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 验证编译**
|
||||
|
||||
```bash
|
||||
mvn clean compile -DskipTests -pl healthlink-his-application
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/doctorstation/appservice/impl/DoctorStationEmrAppServiceImpl.java
|
||||
git commit -m "feat(emr): 保存病历时自动创建修订记录"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 6: 保存病历时自动更新搜索索引
|
||||
|
||||
**Covers:** 问题#3
|
||||
|
||||
**Files:**
|
||||
- Modify: `healthlink-his-server/.../doctorstation/appservice/impl/DoctorStationEmrAppServiceImpl.java`
|
||||
|
||||
- [ ] **Step 1: 添加搜索索引服务注入**
|
||||
|
||||
```java
|
||||
@Resource
|
||||
private IEmrSearchIndexService emrSearchIndexService;
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 保存成功后自动更新索引**
|
||||
|
||||
```java
|
||||
// 在saveEmr方法中,保存成功后添加:
|
||||
// 自动更新搜索索引
|
||||
EmrSearchIndex searchIndex = new EmrSearchIndex();
|
||||
searchIndex.setEmrId(savedEmr.getId());
|
||||
searchIndex.setEncounterId(savedEmr.getEncounterId());
|
||||
searchIndex.setPatientName(patientName);
|
||||
searchIndex.setEmrType(emrType);
|
||||
searchIndex.setEmrTitle(title);
|
||||
searchIndex.setDiagnosisText(diagnosis);
|
||||
searchIndex.setDoctorName(doctorName);
|
||||
searchIndex.setDepartmentName(departmentName);
|
||||
searchIndex.setCreateTime(new Date());
|
||||
|
||||
// 检查是否已存在索引
|
||||
LambdaQueryWrapper<EmrSearchIndex> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(EmrSearchIndex::getEmrId, savedEmr.getId());
|
||||
EmrSearchIndex existing = emrSearchIndexService.getOne(wrapper);
|
||||
if (existing != null) {
|
||||
existing.setPatientName(patientName);
|
||||
existing.setEmrType(emrType);
|
||||
existing.setEmrTitle(title);
|
||||
existing.setDiagnosisText(diagnosis);
|
||||
existing.setDoctorName(doctorName);
|
||||
existing.setDepartmentName(departmentName);
|
||||
existing.setUpdateTime(new Date());
|
||||
emrSearchIndexService.updateById(existing);
|
||||
} else {
|
||||
emrSearchIndexService.save(searchIndex);
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 验证编译**
|
||||
|
||||
```bash
|
||||
mvn clean compile -DskipTests -pl healthlink-his-application
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/doctorstation/appservice/impl/DoctorStationEmrAppServiceImpl.java
|
||||
git commit -m "feat(emr): 保存病历时自动更新搜索索引"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 7: 全量验证
|
||||
|
||||
**Covers:** 全部问题
|
||||
|
||||
- [ ] **Step 1: 后端编译验证**
|
||||
|
||||
```bash
|
||||
mvn clean compile -DskipTests
|
||||
```
|
||||
Expected: BUILD SUCCESS
|
||||
|
||||
- [ ] **Step 2: 前端编译验证**
|
||||
|
||||
```bash
|
||||
cd healthlink-his-ui && npm run build:dev
|
||||
```
|
||||
Expected: Build successful
|
||||
|
||||
- [ ] **Step 3: 接口测试**
|
||||
|
||||
```bash
|
||||
# 测试修订历史接口
|
||||
curl http://localhost:18082/emr/revision/page?pageNo=1&pageSize=10
|
||||
|
||||
# 测试搜索接口
|
||||
curl http://localhost:18082/emr-search/search?keyword=test
|
||||
|
||||
# 测试归档接口
|
||||
curl http://localhost:18082/emr-archive/page?pageNo=1&pageSize=10
|
||||
```
|
||||
Expected: 返回 `{code:200, data:...}`
|
||||
|
||||
- [ ] **Step 4: 提交代码**
|
||||
|
||||
```bash
|
||||
git add -A
|
||||
git commit -m "feat(emr): 打通EMR管理模块与门诊/住院病历集成"
|
||||
git push origin develop
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 验证检查清单
|
||||
|
||||
| 检查项 | 验证方式 | 预期结果 |
|
||||
|--------|---------|---------|
|
||||
| 修订历史API路径 | 访问 `/emr/revision/page` | 返回数据 |
|
||||
| URL参数支持 | 访问 `/emr/revision-history?emrId=1` | 自动加载该病历修订记录 |
|
||||
| 医生工作站入口 | 打开病历详情 | 显示修订历史/归档/完整性检查按钮 |
|
||||
| 保存自动触发 | 保存病历后查询 `emr_revision` 表 | 有新记录 |
|
||||
| 搜索索引更新 | 保存病历后查询 `emr_search_index` 表 | 有新记录 |
|
||||
| 完整性检查 | 点击完整性检查按钮 | 显示检查结果 |
|
||||
|
||||
---
|
||||
|
||||
> **Plan Version:** v1.0
|
||||
> **Created:** 2026-06-21
|
||||
> **Estimated Effort:** 2-3小时
|
||||
95
MD/guides/EMR_SYNC_GUIDE.md
Normal file
95
MD/guides/EMR_SYNC_GUIDE.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# EMR数据同步使用说明
|
||||
|
||||
## 功能概述
|
||||
|
||||
EMR数据同步功能用于将门诊/住院病历表(doc_emr)中的真实数据同步到EMR管理模块的修订历史和搜索索引中。
|
||||
|
||||
## 使用步骤
|
||||
|
||||
### 1. 启动后端应用
|
||||
|
||||
```bash
|
||||
cd healthlink-his-server
|
||||
mvn spring-boot:run -pl healthlink-his-application
|
||||
```
|
||||
|
||||
### 2. 登录系统
|
||||
|
||||
访问 http://localhost:81 登录系统
|
||||
|
||||
### 3. 访问同步页面
|
||||
|
||||
在菜单中找到:**电子病历管理 > EMR数据同步**
|
||||
|
||||
或者直接访问:`http://localhost:81/emr/sync`
|
||||
|
||||
### 4. 执行同步
|
||||
|
||||
1. 查看当前统计信息(病历总数、修订历史、搜索索引)
|
||||
2. 点击"开始同步"按钮
|
||||
3. 确认同步操作
|
||||
4. 等待同步完成
|
||||
5. 查看同步后的统计信息
|
||||
|
||||
## API接口
|
||||
|
||||
### 获取同步统计
|
||||
|
||||
```
|
||||
GET /emr-sync/stats
|
||||
```
|
||||
|
||||
返回:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"emrCount": 100,
|
||||
"revisionCount": 100,
|
||||
"searchIndexCount": 100
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 执行同步
|
||||
|
||||
```
|
||||
POST /emr-sync/sync
|
||||
```
|
||||
|
||||
返回:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": "同步完成: 修订历史100条, 搜索索引100条"
|
||||
}
|
||||
```
|
||||
|
||||
## 数据流向
|
||||
|
||||
```
|
||||
doc_emr (门诊/住院病历)
|
||||
↓ 同步
|
||||
emr_revision (修订历史)
|
||||
emr_search_index (搜索索引)
|
||||
↓ 展示
|
||||
EMR管理页面(修订历史、病历检索等)
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **同步会清空现有数据**:执行同步前会清空emr_revision和emr_search_index表
|
||||
2. **建议先备份**:如果表中有重要数据,建议先备份
|
||||
3. **同步后刷新页面**:同步完成后需要刷新页面才能看到新数据
|
||||
4. **权限要求**:需要管理员权限才能执行同步操作
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q: 同步后数据没有显示?
|
||||
A: 请刷新页面,或检查浏览器控制台是否有错误
|
||||
|
||||
### Q: 同步失败怎么办?
|
||||
A: 检查后端日志,确认数据库连接正常
|
||||
|
||||
### Q: 可以只同步部分数据吗?
|
||||
A: 当前版本不支持部分同步,会同步所有doc_emr中的数据
|
||||
BIN
MD/~$ALTHLINK_HIS_PRICING_v0.1.docx
Normal file
BIN
MD/~$ALTHLINK_HIS_PRICING_v0.1.docx
Normal file
Binary file not shown.
BIN
MD/~$ALTHLINK_HIS_XINCHUANG_ARTICLE.docx
Normal file
BIN
MD/~$ALTHLINK_HIS_XINCHUANG_ARTICLE.docx
Normal file
Binary file not shown.
BIN
MD/~$ALTHLINK_HIS_XINCHUANG_v2.docx
Normal file
BIN
MD/~$ALTHLINK_HIS_XINCHUANG_v2.docx
Normal file
Binary file not shown.
@@ -1,20 +1,12 @@
|
||||
# 数据源配置
|
||||
spring:
|
||||
# Flyway 数据库迁移配置
|
||||
flyway:
|
||||
enabled: true
|
||||
baseline-on-migrate: true
|
||||
baseline-version: 0
|
||||
locations: classpath:db/migration
|
||||
out-of-order: false
|
||||
validate-on-migrate: true
|
||||
datasource:
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
driverClassName: org.postgresql.Driver
|
||||
druid:
|
||||
# 主库数据源
|
||||
master:
|
||||
url: jdbc:postgresql://47.116.196.11:15432/postgresql?currentSchema=healthlink_his&characterEncoding=UTF-8&client_encoding=UTF-8
|
||||
url: jdbc:postgresql://192.168.110.252:15432/postgresql?currentSchema=hisdev&characterEncoding=UTF-8&client_encoding=UTF-8
|
||||
username: postgresql
|
||||
password: Jchl1528 # 请替换为实际的数据库密码
|
||||
# 从库数据源
|
||||
@@ -57,7 +49,7 @@ spring:
|
||||
allow:
|
||||
url-pattern: /druid/*
|
||||
# 控制台管理用户名和密码
|
||||
login-username: healthlink-his
|
||||
login-username: openhis
|
||||
login-password: 123456
|
||||
filter:
|
||||
stat:
|
||||
@@ -70,28 +62,27 @@ spring:
|
||||
config:
|
||||
multi-statement-allow: true
|
||||
# redis 配置
|
||||
data:
|
||||
redis:
|
||||
# 地址
|
||||
host: 47.116.196.11
|
||||
# 端口,默认为6379
|
||||
port: 26379
|
||||
# 数据库索引
|
||||
database: 1
|
||||
# 密码
|
||||
password: Jchl1528
|
||||
# 连接超时时间
|
||||
timeout: 10s
|
||||
lettuce:
|
||||
pool:
|
||||
# 连接池中的最小空闲连接
|
||||
min-idle: 0
|
||||
# 连接池中的最大空闲连接
|
||||
max-idle: 8
|
||||
# 连接池的最大数据库连接数
|
||||
max-active: 8
|
||||
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
max-wait: -1ms
|
||||
redis:
|
||||
# 地址
|
||||
host: 192.168.110.252
|
||||
# 端口,默认为6379
|
||||
port: 6379
|
||||
# 数据库索引
|
||||
database: 1
|
||||
# 密码
|
||||
password: Jchl1528
|
||||
# 连接超时时间
|
||||
timeout: 10s
|
||||
lettuce:
|
||||
pool:
|
||||
# 连接池中的最小空闲连接
|
||||
min-idle: 0
|
||||
# 连接池中的最大空闲连接
|
||||
max-idle: 8
|
||||
# 连接池的最大数据库连接数
|
||||
max-active: 8
|
||||
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
max-wait: -1ms
|
||||
|
||||
# 服务器配置
|
||||
server:
|
||||
@@ -99,5 +90,4 @@ server:
|
||||
port: 18080
|
||||
servlet:
|
||||
# 应用的访问路径
|
||||
context-path: /healthlink-his
|
||||
|
||||
context-path: /openhis
|
||||
Reference in New Issue
Block a user