Compare commits
152 Commits
9ae9fae2c8
...
guanyu
| Author | SHA1 | Date | |
|---|---|---|---|
| 0f6c6ec3c8 | |||
| b3e938540b | |||
|
|
f56aa2ad2e | ||
| 775d37481f | |||
| 84cc974597 | |||
| dfdfa53ce9 | |||
| 36acf6c513 | |||
| 702fc7b757 | |||
| 808c0305c9 | |||
| d5f177ae56 | |||
|
|
d7d76c922e | ||
|
|
b6eec300a9 | ||
| 52b94b9df4 | |||
| c49c9229a8 | |||
| eccc0ec7cf | |||
| 84c0f6a43d | |||
| f1a8fafb72 | |||
| 786fc14147 | |||
| 5cd42a3253 | |||
| b5f83b96e6 | |||
| fb24d3e377 | |||
| 9694184748 | |||
| e7bdf4e5ac | |||
| 0156884099 | |||
| d6e64e5019 | |||
| 9ea5830095 | |||
| 7b912ee96c | |||
| a32d750591 | |||
| 9d4c0b6b2a | |||
| 52377d7529 | |||
| 5100237faf | |||
| e344091a41 | |||
| 1ca9761171 | |||
| 73aa812544 | |||
| de6d6a2b51 | |||
|
|
57d14603ee | ||
| 1df1f0d1ad | |||
| 00604b2d01 | |||
| cf73dacc77 | |||
|
|
a58168c6de | ||
| 310a4f5a9d | |||
|
|
7f1f3e1a3b | ||
| 09e43e4b8c | |||
| 9673c0ed80 | |||
| f3a24a9129 | |||
| 6184ed262f | |||
| cee0a2152a | |||
| f0d20a8d79 | |||
| e19d229a94 | |||
| 694935b648 | |||
|
|
5801fec21c | ||
| b3800b7ae0 | |||
| 557263875b | |||
| 40adecc24e | |||
| 8adee630fb | |||
| f444584908 | |||
| 0ec77ab89c | |||
| e8356f5f83 | |||
| 803e2f7fa7 | |||
| fc892e96dc | |||
| 58238e6b25 | |||
| f79c5a2c26 | |||
| 51b1d37e80 | |||
| 815b80437e | |||
| 4385472f26 | |||
| 5ef05b9b55 | |||
| d7455684db | |||
| d8e9da965b | |||
| 575f5d6c32 | |||
| 3fd7862a85 | |||
| 892890b59f | |||
| 621bc27267 | |||
|
|
62c1b4278b | ||
|
|
690486084e | ||
|
|
d792f03bbd | ||
| 6a4545c240 | |||
| a2e607caf4 | |||
|
|
cfc7ca9b4e | ||
|
|
bdb7d978fb | ||
| 5a227014fe | |||
| 1c68860541 | |||
| 2a0303d0e6 | |||
| acd19fa9b9 | |||
| 81d5c99a35 | |||
| 8258d3e2da | |||
| 7fb3964be1 | |||
| 3812561ede | |||
| d60f25c7d7 | |||
|
|
48189a075f | ||
| 7cd8a12496 | |||
|
|
c26b458298 | ||
| e38c5993a0 | |||
| 4ada4ba31a | |||
|
|
cb82f8d5bf | ||
|
|
ea8dca058a | ||
| deb5683ca6 | |||
| c4ca097bf6 | |||
| 4d024529f4 | |||
|
|
8b6265801d | ||
| 418135867e | |||
|
|
bf5a9674df | ||
| 69dd77e916 | |||
| 954462272e | |||
| 2fcfc34afe | |||
| 9a5d772c72 | |||
| d861c20d5e | |||
| 488573a51b | |||
| bc43085cef | |||
| f818ca8174 | |||
|
|
259a5946c2 | ||
| 651bc758b7 | |||
| d0d6cf3533 | |||
| 8808ba1663 | |||
|
|
fef1ca6637 | ||
|
|
fca3d0ca86 | ||
| a7378ceef7 | |||
| 193a08acbd | |||
| bdd8c9c4d8 | |||
|
|
41d05a1629 | ||
|
|
8cfa6fe05e | ||
|
|
8eb6feb70d | ||
|
|
f93bec967a | ||
|
|
020d1be4be | ||
|
|
f7f037aee9 | ||
| 6c77ee8f84 | |||
| 0855d1153b | |||
|
|
168961e656 | ||
|
|
9dc4a12339 | ||
|
|
9bbf7c6c08 | ||
| 05088a1d1a | |||
|
|
5e9dbb2f1b | ||
|
|
b25d2fbaa9 | ||
| 690e7ca22c | |||
| 43ab5b4498 | |||
| 219ac30dc5 | |||
| 20f71ec5d9 | |||
| 601be0d66b | |||
| e825f5fb33 | |||
| 97827b6ff0 | |||
| 01e8cc459c | |||
|
|
cc7c669fc1 | ||
|
|
5c73cc6987 | ||
| cb792684e2 | |||
| 871690848e | |||
| 17616a32cb | |||
|
|
2609791b62 | ||
|
|
c7ae277613 | ||
|
|
6882085d69 | ||
|
|
b1391afcd8 | ||
| d12b77f81a | |||
| acf685fbaf | |||
|
|
dfce7d0332 |
@@ -47,7 +47,7 @@
|
||||
|
||||
**铁律2: Flyway 数据库迁移**
|
||||
- 凡是新建表、新增字段,必须创建 Flyway 迁移脚本
|
||||
- 路径:`healthlink-his-domain/src/main/resources/db/migration/`
|
||||
- 路径:`healthlink-his-application/src/main/resources/db/migration/`
|
||||
- 命名:`V{版本号}__{描述}.sql`(双下划线)
|
||||
|
||||
**铁律3: 测试通过后才提交**
|
||||
@@ -184,7 +184,7 @@
|
||||
|
||||
**铁律2: Flyway 数据库迁移**
|
||||
- 凡是新建表、新增字段,必须创建 Flyway 迁移脚本
|
||||
- 路径:`healthlink-his-domain/src/main/resources/db/migration/`
|
||||
- 路径:`healthlink-his-application/src/main/resources/db/migration/`
|
||||
- 命名:`V{版本号}__{描述}.sql`(双下划线)
|
||||
|
||||
**铁律3: 测试通过后才提交**
|
||||
|
||||
439
MD/GRADE3A_FULL_IMPLEMENTATION_PLAN.md
Normal file
439
MD/GRADE3A_FULL_IMPLEMENTATION_PLAN.md
Normal file
@@ -0,0 +1,439 @@
|
||||
# HealthLink-HIS 三甲达标完整实现计划
|
||||
|
||||
> **文档类型**: 实施计划
|
||||
> **版本**: v1.0
|
||||
> **编制日期**: 2026-06-17
|
||||
> **依据标准**:
|
||||
> - 《三级医院评审标准(2022年版)》及广西实施细则
|
||||
> - 《电子病历系统应用水平分级评价标准》(≥4级 = 三甲硬性)
|
||||
> - 《医院信息互联互通标准化成熟度测评方案》(≥四级甲等 = 三甲硬性)
|
||||
> - 《MODULE_CAPABILITY_REQUIREMENTS.md》142项必备能力清单
|
||||
> - 《GRADE3A_GAP_ANALYSIS_AND_DESIGN.md》差距分析
|
||||
|
||||
---
|
||||
|
||||
## 一、现状总览
|
||||
|
||||
### 1.1 能力完成度
|
||||
|
||||
| 维度 | 数量 | 占比 | 说明 |
|
||||
|------|:----:|:----:|------|
|
||||
| 总必备能力 | **142** | 100% | 三甲评审14个模块域 |
|
||||
| ✅ 已实现 | **59** | 42% | 功能完整可用 |
|
||||
| ⚠️ 基础实现 | **31** | 22% | 有框架/表结构,功能未完善 |
|
||||
| ❌ 缺失 | **52** | 37% | 完全没有实现 |
|
||||
| **综合完成率** | — | **53%** | (59 + 31×0.5) / 142 |
|
||||
|
||||
### 1.2 各模块完成率
|
||||
|
||||
| 模块 | 必备能力 | ✅已实现 | ⚠️基础 | ❌缺失 | 完成率 | 优先级 |
|
||||
|------|:-------:|:-------:|:------:|:------:|:-----:|:-----:|
|
||||
| 门诊医生站 | 10 | 7 | 2 | 1 | 80% | — |
|
||||
| 住院医生站 | 10 | 4 | 2 | 4 | 50% | P0 |
|
||||
| 护士站 | 10 | 5 | 2 | 3 | 60% | P1 |
|
||||
| 合理用药 | 12 | 10 | 1 | 1 | 83% | — |
|
||||
| 手术麻醉 | 12 | 6 | 2 | 4 | 58% | P0 |
|
||||
| 检验(LIS) | 10 | 5 | 2 | 3 | 60% | P1 |
|
||||
| 检查(PACS) | 10 | 3 | 3 | 4 | 45% | P1 |
|
||||
| 电子病历 | 10 | 4 | 2 | 4 | 50% | P0 |
|
||||
| 病案管理 | 10 | 2 | 3 | 5 | 35% | P0 |
|
||||
| 院感管理 | 10 | 3 | 1 | 6 | 35% | P1 |
|
||||
| 护理评估 | 10 | 4 | 3 | 3 | 55% | P1 |
|
||||
| ESB集成 | 10 | 0 | 4 | 6 | 20% | P1 |
|
||||
| EMPI | 8 | 2 | 3 | 3 | 38% | P1 |
|
||||
| 统计报表 | 10 | 4 | 1 | 5 | 45% | P1 |
|
||||
|
||||
### 1.3 三甲硬性指标对照
|
||||
|
||||
| 指标 | 要求 | 当前状态 | 差距 |
|
||||
|------|------|---------|------|
|
||||
| 处方审核率 | ≥100% | ✅ 合理用药12项能力已实现10项 | 基本达标 |
|
||||
| 抗菌药物使用率 | ≤60% | ✅ 分级管控已实现 | 达标 |
|
||||
| 危急值处理率 | ≥95% | ✅ LIS危急值闭环已实现 | 达标 |
|
||||
| 电子病历评级 | ≥4级 | ⚠️ 部分能力缺失 | 差版本管理/时效/检索完善 |
|
||||
| 互联互通成熟度 | ≥四级甲等 | ⚠️ ESB/FHIR基础框架有 | 差完整集成 |
|
||||
| 首页编码正确率 | ≥95% | ✅ ICD-10编码库已实现 | 达标 |
|
||||
| 术前讨论率 | 100% | ✅ 已实现(V14) | 达标 |
|
||||
| 病案24h归档率 | ≥90% | ✅ 已完成(P2) | 达标 |
|
||||
|
||||
---
|
||||
|
||||
## 二、52项缺失能力详细清单
|
||||
|
||||
### 2.1 住院医生站(4项缺失)
|
||||
|
||||
| # | 缺失能力 | 三甲依据 | 实现方案 | 预估工时 |
|
||||
|---|---------|---------|---------|:-------:|
|
||||
| 1 | **医嘱执行闭环追踪** | 医嘱管理制度 | 扩展`order_execute_record`表,增加每步时间戳 | 3天 |
|
||||
| 2 | **输血管理** | 临床用血管理规范 | 新建输血申请→配血→发血→输注→观察全流程 | 5天 |
|
||||
| 3 | **临床路径执行** | 临床路径管理 | 路径入径→执行→变异记录→退出 | 5天 |
|
||||
| 4 | **危急值处理记录** | 危急值管理规范 | 危急值接收→确认→处理→记录闭环 | 3天 |
|
||||
|
||||
**小计**: 16天
|
||||
|
||||
### 2.2 手术麻醉(4项缺失)
|
||||
|
||||
| # | 缺失能力 | 三甲依据 | 实现方案 | 预估工时 |
|
||||
|---|---------|---------|---------|:-------:|
|
||||
| 5 | **麻醉评估(ASA分级)** | 麻醉质控 | 新建`anes_assessment`表+评估工作台 | 3天 |
|
||||
| 6 | **术中生命体征(5min间隔)** | 麻醉记录规范 | 新建`anes_vital_sign`表+自动采集 | 4天 |
|
||||
| 7 | **麻醉小结** | 麻醉质控 | 新建麻醉总结+并发症记录 | 2天 |
|
||||
| 8 | **术后随访记录** | 麻醉质控 | 24h/48h/72h随访+疼痛评估 | 3天 |
|
||||
|
||||
**小计**: 12天
|
||||
|
||||
### 2.3 电子病历(4项缺失)
|
||||
|
||||
| # | 缺失能力 | 三甲依据 | 实现方案 | 预估工时 |
|
||||
|---|---------|---------|---------|:-------:|
|
||||
| 9 | **病历修改留痕** | 电子病历管理规范 | 新建`emr_revision`表,diff追踪 | 3天 |
|
||||
| 10 | **病历版本管理** | 电子病历管理规范 | 扩展`doc_emr`增加version字段+版本对比 | 3天 |
|
||||
| 11 | **病历完整性检查** | 病历质控 | 新建`EmrCompletenessChecker`自动校验 | 2天 |
|
||||
| 12 | **病历时效监控** | 病历书写规范 | 新建`EmrTimelinessMonitor`超时提醒 | 2天 |
|
||||
|
||||
**小计**: 10天
|
||||
|
||||
### 2.4 病案管理(5项缺失)
|
||||
|
||||
| # | 缺失能力 | 三甲依据 | 实现方案 | 预估工时 |
|
||||
|---|---------|---------|---------|:-------:|
|
||||
| 13 | **病案首页数据质量校验** | 首页数据质量≥95% | 新建`mr_homepage_quality_check`表 | 3天 |
|
||||
| 14 | **病案首页上报(HQMS)** | 卫统报表 | 新建HQMS上报接口 | 3天 |
|
||||
| 15 | **病案终末质控** | 病案管理规范 | 新建终末质控评分+缺陷管理 | 3天 |
|
||||
| 16 | **病案示踪管理** | 病案管理 | 在架/借出/归档状态追踪 | 2天 |
|
||||
| 17 | **死亡病例讨论记录** | 评审必查 | 新建死亡讨论记录+7日内完成提醒 | 2天 |
|
||||
|
||||
**小计**: 13天
|
||||
|
||||
### 2.5 院感管理(6项缺失)
|
||||
|
||||
| # | 缺失能力 | 三甲依据 | 实现方案 | 预估工时 |
|
||||
|---|---------|---------|---------|:-------:|
|
||||
| 18 | **院感病例自动筛查** | 院感管理办法 | 规则引擎自动匹配疑似病例 | 3天 |
|
||||
| 19 | **暴发预警** | 院感管理办法 | 同科室短时间多例感染预警 | 2天 |
|
||||
| 20 | **目标性监测(ICU/手术部位)** | 院感监测规范 | ICU导管/手术部位感染监测 | 3天 |
|
||||
| 21 | **手卫生依从性监测** | 患者安全目标 | 手卫生执行率统计 | 2天 |
|
||||
| 22 | **环境卫生学监测** | 院感管理办法 | 空气/物表/手培养结果管理 | 2天 |
|
||||
| 23 | **多重耐药菌管理** | 院感管理办法 | 耐药菌检出→隔离→跟踪→解除 | 2天 |
|
||||
|
||||
**小计**: 14天
|
||||
|
||||
### 2.6 检验系统LIS(3项缺失)
|
||||
|
||||
| # | 缺失能力 | 三甲依据 | 实现方案 | 预估工时 |
|
||||
|---|---------|---------|---------|:-------:|
|
||||
| 24 | **室内质控(Westgard规则)** | 质量管理 | 质控图+Westgard规则+失控处理 | 3天 |
|
||||
| 25 | **室间质评** | 质量管理 | 参加省级/国家级室间质评 | 2天 |
|
||||
| 26 | **检验报告标准格式打印** | 基本功能规范 | 标准检验报告单模板 | 1天 |
|
||||
|
||||
**小计**: 6天
|
||||
|
||||
### 2.7 检查系统PACS(4项缺失)
|
||||
|
||||
| # | 缺失能力 | 三甲依据 | 实现方案 | 预估工时 |
|
||||
|---|---------|---------|---------|:-------:|
|
||||
| 27 | **DICOM图像采集存储** | DICOM标准 | PACS对接+图像存储 | 5天 |
|
||||
| 28 | **结构化图文报告** | 检查规范 | 结构化报告模板+图像标注 | 3天 |
|
||||
| 29 | **影像对比查看** | 临床决策 | 历史影像对比功能 | 2天 |
|
||||
| 30 | **DICOM打印(胶片)** | 基本功能规范 | 胶片打印接口 | 2天 |
|
||||
|
||||
**小计**: 12天
|
||||
|
||||
### 2.8 护理评估(3项缺失)
|
||||
|
||||
| # | 缺失能力 | 三甲依据 | 实现方案 | 预估工时 |
|
||||
|---|---------|---------|---------|:-------:|
|
||||
| 31 | **管道滑脱风险评估** | 护理安全 | 导管类型/位置/状态评估量表 | 2天 |
|
||||
| 32 | **营养风险筛查(NRS2002)** | 营养管理 | NRS2002量表+自动评分 | 2天 |
|
||||
| 33 | **疼痛评估(NRS/VAS)** | 疼痛管理 | NRS/VAS评分+干预+再评估 | 2天 |
|
||||
|
||||
**小计**: 6天
|
||||
|
||||
### 2.9 护士站(3项缺失)
|
||||
|
||||
| # | 缺失能力 | 三甲依据 | 实现方案 | 预估工时 |
|
||||
|---|---------|---------|---------|:-------:|
|
||||
| 34 | **护理文书(一般/危重)** | 病历书写规范 | 一般/危重护理记录单模板 | 3天 |
|
||||
| 35 | **护理质量指标上报** | 护理质量 | 护理敏感指标自动采集+上报 | 3天 |
|
||||
| 36 | **护理交接班(重点患者)** | 护理安全 | 电子交接班+重点患者提示 | 2天 |
|
||||
|
||||
**小计**: 8天
|
||||
|
||||
### 2.10 ESB集成平台(6项缺失)
|
||||
|
||||
| # | 缺失能力 | 三甲依据 | 实现方案 | 预估工时 |
|
||||
|---|---------|---------|---------|:-------:|
|
||||
| 37 | **HL7 FHIR R4消息转换** | 互联互通 | FHIR资源映射+格式转换 | 5天 |
|
||||
| 38 | **CDA临床文档** | 互联互通 | 入院/出院/检验/处方CDA文档 | 5天 |
|
||||
| 39 | **院内编码↔标准编码映射** | 互联互通 | ICD-10/LOINC/SNOMED CT映射 | 3天 |
|
||||
| 40 | **集成监控仪表盘** | 互联互通 | 消息流量/成功率/失败率可视化 | 3天 |
|
||||
| 41 | **消息可靠性保障** | 互联互通 | 存储转发+确认机制+死信处理 | 3天 |
|
||||
| 42 | **接口版本管理** | 互联互通 | 接口版本控制+向后兼容 | 2天 |
|
||||
|
||||
**小计**: 21天
|
||||
|
||||
### 2.11 EMPI患者主索引(3项缺失)
|
||||
|
||||
| # | 缺失能力 | 三甲依据 | 实现方案 | 预估工时 |
|
||||
|---|---------|---------|---------|:-------:|
|
||||
| 43 | **患者身份合并/拆分** | EMPI | 多来源患者信息合并+拆分 | 3天 |
|
||||
| 44 | **重复检测算法** | 数据质量 | 身份证+姓名+手机号模糊匹配 | 3天 |
|
||||
| 45 | **跨系统同步** | 互联互通 | EMPI→HIS/LIS/PACS/EMR同步 | 3天 |
|
||||
|
||||
**小计**: 9天
|
||||
|
||||
### 2.12 统计报表(5项缺失)
|
||||
|
||||
| # | 缺失能力 | 三甲依据 | 实现方案 | 预估工时 |
|
||||
|---|---------|---------|---------|:-------:|
|
||||
| 46 | **质控指标自动采集** | 评审指标 | 十八项核心制度执行指标 | 3天 |
|
||||
| 47 | **DRG/DIP分析** | 医保支付 | 病组分布/费用结构/时间消耗 | 3天 |
|
||||
| 48 | **经营分析(科室成本)** | 经营管理 | 科室成本/收益/绩效分析 | 3天 |
|
||||
| 49 | **数据导出(Excel/PDF)** | 基本功能 | 多格式导出+定时推送 | 2天 |
|
||||
| 50 | **可视化仪表盘** | 高级功能 | 数据大屏+图表展示 | 3天 |
|
||||
|
||||
**小计**: 14天
|
||||
|
||||
### 2.13 门诊医生站(1项缺失)
|
||||
|
||||
| # | 缺失能力 | 三甲依据 | 实现方案 | 预估工时 |
|
||||
|---|---------|---------|---------|:-------:|
|
||||
| 51 | **传染病报告卡** | 传染病管理 | 传染病直报卡填报+审核 | 3天 |
|
||||
|
||||
**小计**: 3天
|
||||
|
||||
### 2.14 合理用药(1项缺失)
|
||||
|
||||
| # | 缺失能力 | 三甲依据 | 实现方案 | 预估工时 |
|
||||
|---|---------|---------|---------|:-------:|
|
||||
| 52 | **肝肾功能自动调量** | 合理用药 | 根据化验结果自动建议调量 | 3天 |
|
||||
|
||||
**小计**: 3天
|
||||
|
||||
---
|
||||
|
||||
## 三、31项基础实现补全清单
|
||||
|
||||
> 以下模块已有表结构/框架,但功能未完善,需补全。
|
||||
|
||||
### 3.1 需补全的基础实现
|
||||
|
||||
| # | 模块 | 当前状态 | 需补全内容 | 预估工时 |
|
||||
|---|------|---------|-----------|:-------:|
|
||||
| B1 | 门诊退号 | 空壳视图 | 退号流程+费用退回 | 2天 |
|
||||
| B2 | 门诊退药 | 空壳视图 | 退药申请+审批+重新入库 | 2天 |
|
||||
| B3 | 门诊退费 | 空壳视图 | 退费流程+医保回退 | 2天 |
|
||||
| B4 | 收费详情查询 | 空壳视图 | 费用明细+发票查询 | 1天 |
|
||||
| B5 | 申请单管理 | 空壳视图 | 检验检查申请单查看 | 2天 |
|
||||
| B6 | 结果查看 | 空壳视图 | LIS/PACS结果统一查看 | 2天 |
|
||||
| B7 | 医嘱查看与打印 | 空壳视图 | 医嘱单打印 | 1天 |
|
||||
| B8 | 入院诊断 | 空壳视图 | 入院诊断录入+ICD编码 | 2天 |
|
||||
| B9 | 医嘱管理 | 空壳视图 | 医嘱查询+统计 | 2天 |
|
||||
| B10 | 门诊收费结算 | 空壳视图 | 结算流程完善 | 2天 |
|
||||
| B11 | 排班管理 | 空壳视图 | 医生排班+号源管理 | 2天 |
|
||||
| B12 | 病案管理 | 空壳视图 | 病案借阅/封存/示踪 | 3天 |
|
||||
| B13 | 费用清单 | 空壳视图 | 患者每日费用清单 | 2天 |
|
||||
| B14 | 手术管理 | 空壳视图 | 手术全流程管理 | 3天 |
|
||||
| B15 | 服务目录 | 空壳视图 | 诊疗服务项目目录 | 2天 |
|
||||
| B16 | 常用诊断 | 空壳视图 | 常用诊断维护 | 1天 |
|
||||
| B17 | 中医处方 | 空壳视图 | 中药饮片处方 | 2天 |
|
||||
| B18 | 床位管理 | 空壳视图 | 实时床位图+利用率统计 | 2天 |
|
||||
| B19 | 费用配置 | 空壳视图 | 收费项目配置 | 1天 |
|
||||
| B20 | LIS对照 | 空壳视图 | 检验项目目录对照 | 2天 |
|
||||
| B21 | PACS对照 | 空壳视图 | 检查项目目录对照 | 2天 |
|
||||
| B22 | 诊断对照 | 空壳视图 | 院内诊断↔ICD↔医保诊断 | 2天 |
|
||||
| B23 | 货位管理 | 空壳视图 | 药品货位维护 | 2天 |
|
||||
| B24 | 调价管理 | 空壳视图 | 药品/服务调价流程 | 2天 |
|
||||
| B25 | 退药管理 | 空壳视图 | 药房退药流程 | 2天 |
|
||||
| B26 | 自动计算 | 空壳视图 | 自动计费规则 | 2天 |
|
||||
|
||||
**小计**: 49天
|
||||
|
||||
---
|
||||
|
||||
## 四、广西地方特色模块(P2)
|
||||
|
||||
| # | 模块 | 广西要求 | 实现方案 | 预估工时 |
|
||||
|---|------|---------|---------|:-------:|
|
||||
| G1 | **壮医/中医特色** | 广西壮医药诊疗 | 壮医望诊/脉诊/目诊+中药方剂模板 | 10天 |
|
||||
| G2 | **传染病直报** | 对接广西疾控 | 传染病自动筛查+直报对接 | 5天 |
|
||||
| G3 | **电子健康卡** | 对接广西平台 | 健康卡申领+就诊使用 | 5天 |
|
||||
| G4 | **电子票据** | 对接广西财政 | 财政电子票据+核销对账 | 5天 |
|
||||
| G5 | **DRG/DIP深化** | 广西医保规则 | 广西DRG/DIP分组+费用预警 | 10天 |
|
||||
|
||||
**小计**: 35天
|
||||
|
||||
---
|
||||
|
||||
## 五、实施路线图
|
||||
|
||||
### Phase 1: 核心达标(Sprint 1-4,4周)
|
||||
|
||||
**目标**: 补齐P0缺失能力,达到电子病历4级基本要求
|
||||
|
||||
```
|
||||
Week 1: 住院医生站闭环 + 医嘱执行追踪 + 危急值处理
|
||||
Week 2: 麻醉评估 + 术中记录 + 麻醉小结 + 术后随访
|
||||
Week 3: 病历修改留痕 + 版本管理 + 完整性检查 + 时效监控
|
||||
Week 4: 病案首页质控 + HQMS上报 + 死亡病例讨论 + 病案示踪
|
||||
```
|
||||
|
||||
| 周 | 工作内容 | 工时 | 交付物 |
|
||||
|:--:|---------|:---:|--------|
|
||||
| W1 | 住院医生站4项缺失 | 16天 | 医嘱闭环+输血+临床路径+危急值 |
|
||||
| W2 | 手术麻醉4项缺失 | 12天 | 麻醉评估+术中记录+小结+随访 |
|
||||
| W3 | 电子病历4项缺失 | 10天 | 留痕+版本+完整性+时效 |
|
||||
| W4 | 病案管理5项缺失 | 13天 | 首页质控+HQMS+终末质控+示踪+死亡讨论 |
|
||||
| | **Phase 1 合计** | **51天** | |
|
||||
|
||||
### Phase 2: 评审保障(Sprint 5-8,4周)
|
||||
|
||||
**目标**: 补齐P1缺失能力,达到三甲评审合格线
|
||||
|
||||
```
|
||||
Week 5: 院感管理6项缺失
|
||||
Week 6: 护理评估3项 + 护士站3项
|
||||
Week 7: 检验3项 + 检查4项
|
||||
Week 8: ESB集成平台6项
|
||||
```
|
||||
|
||||
| 周 | 工作内容 | 工时 | 交付物 |
|
||||
|:--:|---------|:---:|--------|
|
||||
| W5 | 院感管理6项缺失 | 14天 | 自动筛查+暴发预警+目标监测+手卫生+环境+耐药菌 |
|
||||
| W6 | 护理+护士6项缺失 | 14天 | 管道评估+营养筛查+疼痛评估+护理文书+质量指标+交接班 |
|
||||
| W7 | LIS+PACS 7项缺失 | 18天 | 质控+室间质评+报告打印+DICOM+图文报告+影像对比+胶片 |
|
||||
| W8 | ESB集成6项 | 21天 | FHIR+CDA+编码映射+监控+可靠性+版本管理 |
|
||||
| | **Phase 2 合计** | **67天** | |
|
||||
|
||||
### Phase 3: 能力补全(Sprint 9-12,4周)
|
||||
|
||||
**目标**: 补全31项空壳视图 + 统计报表5项 + 其他缺失
|
||||
|
||||
```
|
||||
Week 9: 空壳视图第一批(门诊退号/退药/退费/收费详情/申请单/结果查看)
|
||||
Week 10: 空壳视图第二批(医嘱查看/入院诊断/医嘱管理/结算/排班/病案/费用)
|
||||
Week 11: 空壳视图第三批(手术/服务目录/常用诊断/中医处方/床位/费用配置)
|
||||
+ 统计报表5项
|
||||
Week 12: 空壳视图第四批(LIS/PACS/诊断对照/货位/调价/退药/自动计算)
|
||||
+ EMPI 3项 + 合理用药1项 + 传染病报告1项
|
||||
```
|
||||
|
||||
| 周 | 工作内容 | 工时 | 交付物 |
|
||||
|:--:|---------|:---:|--------|
|
||||
| W9 | 空壳视图6项 | 11天 | 门诊退号/退药/退费/收费详情/申请单/结果查看 |
|
||||
| W10 | 空壳视图7项 | 14天 | 医嘱查看/入院诊断/医嘱管理/结算/排班/病案/费用 |
|
||||
| W11 | 空壳视图6项+报表5项 | 20天 | 手术/服务目录/常用诊断/中医/床位/费用+统计报表 |
|
||||
| W12 | 空壳视图7项+EMPI+合理用药+传染病 | 22天 | 目录对照/货位/调价/退药/计算+EMPI+调量+报卡 |
|
||||
| | **Phase 3 合计** | **67天** | |
|
||||
|
||||
### Phase 4: 地方特色(Sprint 13-15,3周)
|
||||
|
||||
**目标**: 满足广西地方要求
|
||||
|
||||
```
|
||||
Week 13: 壮医/中医特色 + 传染病直报
|
||||
Week 14: 电子健康卡 + 电子票据
|
||||
Week 15: DRG/DIP深化
|
||||
```
|
||||
|
||||
| 周 | 工作内容 | 工时 | 交付物 |
|
||||
|:--:|---------|:---:|--------|
|
||||
| W13 | 壮医/中医+传染病 | 15天 | 壮医诊疗+中药方剂+传染病直报 |
|
||||
| W14 | 电子健康卡+电子票据 | 10天 | 健康卡对接+财政票据 |
|
||||
| W15 | DRG/DIP深化 | 10天 | 广西DRG/DIP分组+费用预警 |
|
||||
| | **Phase 4 合计** | **35天** | |
|
||||
|
||||
---
|
||||
|
||||
## 六、工时汇总
|
||||
|
||||
| 类别 | 模块数 | 工时 | 占比 |
|
||||
|------|:-----:|:----:|:----:|
|
||||
| 🔴 P0 核心达标(Phase 1) | 17项 | 51天 | 19% |
|
||||
| 🟡 P1 评审保障(Phase 2) | 25项 | 67天 | 26% |
|
||||
| 🔧 空壳补全+其他(Phase 3) | 37项 | 67天 | 26% |
|
||||
| 🟢 P2 地方特色(Phase 4) | 5项 | 35天 | 14% |
|
||||
| **合计** | **84项** | **220天** | — |
|
||||
|
||||
> **并行开发估算**:
|
||||
> - 2人并行: ~16周(4个月)
|
||||
> - 3人并行: ~11周(3个月)
|
||||
> - 4人并行: ~8周(2个月)
|
||||
|
||||
---
|
||||
|
||||
## 七、关键里程碑
|
||||
|
||||
| 里程碑 | 时间 | 验收标准 | 评审支撑 |
|
||||
|--------|------|---------|---------|
|
||||
| **M1** | Phase 1 结束 | 电子病历4级核心能力就绪 | 电子病历评级申请 |
|
||||
| **M2** | Phase 2 结束 | 三甲评审17项必测项全部覆盖 | 三甲评审自查 |
|
||||
| **M3** | Phase 3 结束 | 142项必备能力完成率≥90% | 评审材料准备 |
|
||||
| **M4** | Phase 4 结束 | 广西地方特色全覆盖 | 地方评审加分 |
|
||||
|
||||
---
|
||||
|
||||
## 八、风险与依赖
|
||||
|
||||
### 8.1 技术风险
|
||||
|
||||
| 风险 | 影响 | 缓解措施 |
|
||||
|------|------|---------|
|
||||
| ESB集成平台复杂度高 | Phase 2延期 | 优先使用开源集成引擎(Kafka/RabbitMQ) |
|
||||
| PACS设备对接不确定性 | 图像采集延期 | 先做框架,设备对接延后 |
|
||||
| 医保接口联调周期长 | DRG/DIP延期 | 预留联调缓冲期 |
|
||||
|
||||
### 8.2 外部依赖
|
||||
|
||||
| 依赖 | 影响 | 应对 |
|
||||
|------|------|------|
|
||||
| 广西医保平台接口文档 | DRG/DIP对接 | 提前获取文档 |
|
||||
| CA签名服务商 | 电子签名 | 已有基础,扩展即可 |
|
||||
| HL7 FHIR认证 | 互联互通测评 | 参考国家标准实现 |
|
||||
|
||||
---
|
||||
|
||||
## 九、验证计划
|
||||
|
||||
### 9.1 每Phase验证
|
||||
|
||||
| Phase | 验证内容 | 验证方式 |
|
||||
|-------|---------|---------|
|
||||
| Phase 1 | 医嘱闭环→麻醉记录→病历留痕→病案首页 | 端到端流程测试 |
|
||||
| Phase 2 | 院感监测→护理评估→LIS/PACS→ESB集成 | 接口联通测试 |
|
||||
| Phase 3 | 空壳视图功能→统计报表→EMPI | 功能验收测试 |
|
||||
| Phase 4 | 壮医模块→传染病直报→电子票据→DRG | 地方标准对照 |
|
||||
|
||||
### 9.2 评审指标验证
|
||||
|
||||
| 指标 | 验证方法 | 目标值 |
|
||||
|------|---------|:------:|
|
||||
| 处方审核率 | 统计全院处方审核覆盖率 | 100% |
|
||||
| 首页编码正确率 | 抽样检查ICD-10编码 | ≥95% |
|
||||
| 病案24h归档率 | 统计出院后归档时间 | ≥90% |
|
||||
| 危急值处理及时率 | 统计危急值处理时间 | ≥95% |
|
||||
| 电子病历评级 | 对照4级评价标准自评 | ≥4级 |
|
||||
| 互联互通成熟度 | 对照四级甲等标准自评 | ≥四级甲等 |
|
||||
|
||||
---
|
||||
|
||||
## 十、与现有开发规范对齐
|
||||
|
||||
本计划严格遵循 `AGENTS.md` 中的开发规范:
|
||||
|
||||
| 规范 | 对齐方式 |
|
||||
|------|---------|
|
||||
| **铁律1: 修改完必须测试** | 每个Phase结束运行`mvn test`+`npm run build:dev` |
|
||||
| **铁律2: Flyway迁移** | 每个新模块创建`V{版本号}__{描述}.sql` |
|
||||
| **铁律5: 状态值一致性** | 新增状态值走完整链路检查 |
|
||||
| **铁律9: 先审核原有代码** | 每个模块开发前搜索已有代码 |
|
||||
| **铁律12: 按设计文档自主开发** | 本文档确认后直接执行 |
|
||||
| **铁律18: 禁止破坏原有功能** | 每次修改后编译验证 |
|
||||
| **全链路6环分析** | 每个缺失能力走完整链路 |
|
||||
| **Karpathy准则** | 简洁优先,精准修改 |
|
||||
|
||||
---
|
||||
|
||||
> **文档版本**: v1.0
|
||||
> **最后更新**: 2026-06-17
|
||||
> **下一步**: 确认本文档后,立即开始 Phase 1 Week 1 开发
|
||||
BIN
MD/HEALTHLINK_HIS_PRICING_PROPOSAL_0.2.docx
Normal file
BIN
MD/HEALTHLINK_HIS_PRICING_PROPOSAL_0.2.docx
Normal file
Binary file not shown.
724
MD/HEALTHLINK_HIS_PRICING_PROPOSAL_0.2.md
Normal file
724
MD/HEALTHLINK_HIS_PRICING_PROPOSAL_0.2.md
Normal file
@@ -0,0 +1,724 @@
|
||||
---
|
||||
文档类型: 公众号软文 / 产品报价方案
|
||||
版本: V4.0
|
||||
日期: 2026-06-16
|
||||
标题: 医院信息化到底要花多少钱?— HealthLink-HIS 按模块透明报价全公开
|
||||
---
|
||||
|
||||
# 医院信息化到底要花多少钱?— HealthLink-HIS 按模块透明报价全公开
|
||||
|
||||
> **上海经创贺联信息科技有限公司**
|
||||
|
||||
---
|
||||
|
||||
医院信息化建设,院长们最头疼的三个问题:
|
||||
|
||||
- **贵** — 传统 HIS 系统动辄百万起步,基层医院望而却步
|
||||
- **复杂** — 花了大价钱买全套系统,一半功能用不上,一半需求没覆盖
|
||||
- **不适配** — 大医院的系统搬到小医院水土不服,小医院的系统到大医院不够用
|
||||
|
||||
这三个问题的根源,其实是同一个:**HIS 系统的定价方式不透明**。你不知道自己为用不上的功能买了多少单,也不知道想加一个新模块到底要花多少钱。
|
||||
|
||||
**如果 HIS 系统能像搭积木一样,按需选配、逐个模块定价呢?**
|
||||
|
||||
今天,我们把 HealthLink-HIS 的 **108 个业务模块**全部拆开,让你清清楚楚看到:每一分钱,花在了哪里。
|
||||
|
||||
---
|
||||
|
||||
## 一、HealthLink-HIS 是什么来头?
|
||||
|
||||
先亮几个数据,让你对这套系统有个基本认知:
|
||||
|
||||
| 维度 | 数据 | 说明 |
|
||||
|------|------|------|
|
||||
| 代码提交 | **2,265 次** | 40+ 工程师半年密集迭代 |
|
||||
| 新增功能 | **111 项** | 覆盖门诊、住院、手术、检验等全业务 |
|
||||
| Bug 修复 | **1,400+** | 系统稳定性持续打磨 |
|
||||
| 业务模块 | **108 个** | 14 大业务域全覆盖 |
|
||||
| 数据库表 | **181 张** | 全业务域数据模型 |
|
||||
| 后端接口 | **230 个** | 45 个业务模块统一接口规范 |
|
||||
| 前端页面 | **209 个** | 42 个功能模块操作体验一致 |
|
||||
|
||||
**一句话总结**:这不是一套 PPT 产品,是一套已经在多家医院上线运行、经过 1,400+ 个 Bug 修复打磨的实战系统。
|
||||
|
||||
### 技术栈:走在行业前面
|
||||
|
||||
| 技术维度 | HealthLink-HIS | 行业主流 | 优势 |
|
||||
|---------|:-------------:|:--------:|------|
|
||||
| 后端框架 | **Spring Boot 4.0.6** | 2.x/3.x | 业内首批升级,性能与安全全面领先 |
|
||||
| 运行时 | **JDK 25** | 17/21 | 最新长期支持版 |
|
||||
| 前端框架 | **Vue 3 + Vite** | Vue 2/jQuery | 现代化体验,首屏加载快 3 倍 |
|
||||
| 高性能表格 | **VxeTable** | el-table | 万级数据量流畅渲染 |
|
||||
| 数据库 | **PostgreSQL 15+** | MySQL/Oracle | 企业级开源,零授权费 |
|
||||
| 工作流 | **Flowable BPMN** | 自研/无 | 国际标准流程引擎 |
|
||||
| 数据标准 | **HL7 FHIR R4** | 私有协议 | 互联互通标准协议 |
|
||||
| 电子签名 | **CA 认证** | 无/第三方 | 法律效力保障 |
|
||||
|
||||
### 资质与合规
|
||||
|
||||
- 符合《医院信息系统基本功能规范》(卫生部)
|
||||
- 支持**电子病历应用水平分级评价 4 级及以上**
|
||||
- 支持**医院信息互联互通标准化成熟度 4A 级**
|
||||
- 对标《三级医院评审标准(2022版)》
|
||||
- 符合 WS/T 447、WS/T 448、WS/T 500 行业标准
|
||||
- 支持广西地方标准(壮医/瑶医、疾控直报、电子健康卡)
|
||||
|
||||
---
|
||||
|
||||
## 二、部署方式:灵活适配您的基础设施
|
||||
|
||||
我们提供多种部署方式,适配不同医院的 IT 基础设施条件:
|
||||
|
||||
| 部署方式 | 适用场景 | 特点 | 参考周期 |
|
||||
|---------|---------|------|:------:|
|
||||
| **私有化部署** | 有自建机房的二/三级医院 | 数据完全自主可控,部署在院内服务器 | 1-2周 |
|
||||
| **混合云部署** | 希望兼顾安全与弹性的医院 | 核心数据院内存储,非核心业务上云 | 1-2周 |
|
||||
| **SaaS 托管** | 基层医疗机构、社区卫生中心 | 零运维、按年付费、快速上线 | 3-5天 |
|
||||
| **信创环境部署** | 有信创要求的公立医院 | 适配国产操作系统/数据库/中间件 | 2-3周 |
|
||||
|
||||
### 服务器配置参考
|
||||
|
||||
| 医院规模 | 推荐配置 | 并发用户 |
|
||||
|---------|---------|:------:|
|
||||
| 一级医院(<100 床) | 4核8G / 500G SSD | 50+ |
|
||||
| 二级医院(100-500 床) | 8核16G / 1T SSD + 数据库服务器 | 100+ |
|
||||
| 三级医院(500+ 床) | 集群部署 / 负载均衡 / 主从数据库 | 300+ |
|
||||
|
||||
> 具体配置根据实际业务量和并发需求调整,可提供免费评估服务。
|
||||
|
||||
---
|
||||
|
||||
## 三、108 个模块,逐个标价
|
||||
|
||||
> **计价基准**:工程师单价 **1,500 元/人天**
|
||||
>
|
||||
> 每个模块报价含:需求分析 + 设计 + 前端开发 + 后端开发 + 单元测试 + 联调
|
||||
>
|
||||
> 模块可单独选购,也可按下方套餐组合
|
||||
|
||||
### 系统平台层 — HIS 运行的基础设施
|
||||
|
||||
| 序号 | 模块 | 功能说明 | 人天 | 报价区间 |
|
||||
|:---:|------|---------|:---:|:------:|
|
||||
| P-01 | **系统管理** | 用户/角色/菜单/部门/岗位/字典/参数/公告/版本管理、多租户 | 10-15 | 1.5-2.5万 |
|
||||
| P-02 | **监控运维** | 缓存监控、服务器指标、登录日志、操作审计、在线用户追踪 | 5-8 | 0.8-1.2万 |
|
||||
| P-03 | **文件服务** | 统一文件上传/下载,多格式支持 | 3-5 | 0.3-0.8万 |
|
||||
| P-04 | **工作流引擎** | Flowable BPMN 流程定义/实例/任务/表单/表达式/监听器 | 10-15 | 1.5-2.5万 |
|
||||
| P-05 | **定时任务** | Cron 调度引擎,报表自动生成、数据同步 | 3-5 | 0.5-0.8万 |
|
||||
| P-06 | **代码生成器** | 数据库表→CRUD 代码自动生成 | 3-5 | 0.3-0.8万 |
|
||||
| P-07 | **数据导出** | Excel/PDF/CSV 多格式导出,定时推送 | 3-5 | 0.3-0.8万 |
|
||||
| P-08 | **首页仪表板** | 数据驾驶舱(处方统计/收入趋势/医生工作量/快捷入口) | 5-8 | 0.5-1.2万 |
|
||||
| | **平台层参考** | | **42-66** | **6-11万** |
|
||||
|
||||
### 门诊管理域 — 从挂号到完诊的完整闭环
|
||||
|
||||
| 序号 | 模块 | 功能说明 | 人天 | 报价区间 |
|
||||
|:---:|------|---------|:---:|:------:|
|
||||
| M-01 | **挂号预约** | 多渠道预约(窗口/自助机/线上)、退号退费、就诊卡管理、费用性质自动识别 | 10-15 | 1.5-2.5万 |
|
||||
| M-02 | **分诊叫号** | 智能分诊、排队管理、LCD/语音叫号、SSE 实时推送、等候时间预估 | 6-10 | 0.8-1.5万 |
|
||||
| M-03 | **门诊医生站** | 结构化病历、ICD-10 诊断(含中医体系)、处方(西药/中成药/中药饮片)、检验检查申请、手术申请、过敏史管理、传染病报卡 | 15-22 | 2-3.5万 |
|
||||
| M-04 | **门诊收费** | 多支付方式(现金/微信/支付宝/医保)、发票管理、退费、日终结算 | 10-15 | 1.5-2.5万 |
|
||||
| M-05 | **门诊药房** | 处方接收、发药、退药、处方审核、效期管理、管制药品管理 | 8-12 | 1-2万 |
|
||||
| M-06 | **门诊治疗** | 治疗执行、皮试记录、输液管理、处方拦截 | 6-10 | 0.8-1.5万 |
|
||||
| M-07 | **门诊手术** | 手术申请、术中临时医嘱、门诊手术计费 | 4-6 | 0.5-1万 |
|
||||
| | **门诊域参考** | | **59-90** | **9-14.5万** |
|
||||
|
||||
### 住院管理域 — 入出转全流程
|
||||
|
||||
| 序号 | 模块 | 功能说明 | 人天 | 报价区间 |
|
||||
|:---:|------|---------|:---:|:------:|
|
||||
| H-01 | **入院管理** | 入院登记(双入口)、床位分配、押金管理、预交金出入 | 10-15 | 1.5-2.5万 |
|
||||
| H-02 | **住院医生站** | 病程记录(8种模板)、医嘱(长期/临时)、诊断(西医+中医)、手术申请、会诊、输血、知情同意、临床路径、出院小结 | 18-28 | 3-4.5万 |
|
||||
| H-03 | **护士工作站** | 医嘱执行闭环、生命体征、体温单(D3.js)、护理记录、扫码执行、交接班、输液巡视、住院记账 | 14-20 | 2-3万 |
|
||||
| H-04 | **住院收费** | 费用聚合、中途结算、出院结算、每日费用清单 | 8-12 | 1-2万 |
|
||||
| H-05 | **床位管理** | 实时床位状态、出院自动转清洁、利用率统计 | 5-8 | 0.8-1.2万 |
|
||||
| H-06 | **医嘱闭环** | 医嘱全生命周期追踪、执行记录、超时提醒 | 5-8 | 0.8-1.2万 |
|
||||
| | **住院域参考** | | **60-91** | **10-14.4万** |
|
||||
|
||||
### 药品管理域 — 从采购到发药的全供应链
|
||||
|
||||
| 序号 | 模块 | 功能说明 | 人天 | 报价区间 |
|
||||
|:---:|------|---------|:---:|:------:|
|
||||
| D-01 | **药品目录** | 药品主数据、分类管理、医保目录对照 | 6-10 | 0.8-1.5万 |
|
||||
| D-02 | **药库管理** | 采购→验收→入库→退货→盘点→盈亏→调价,全流程单据审批 | 12-18 | 2-3万 |
|
||||
| D-03 | **药房管理** | 请领→入库→发药→退药→盘点→盈亏→退回药库 | 10-15 | 1.5-2.5万 |
|
||||
| D-04 | **科室物资管理** | 科室请领→发放→入库→转入/转出→盘点→盈亏→退库 | 8-12 | 1-2万 |
|
||||
| D-05 | **库存管理** | 实时库存、预警、调拨、盘点、报损、调价、追溯号 | 10-15 | 1.5-2.5万 |
|
||||
| D-06 | **药品追溯** | 一品一码扫码追溯、全供应链追踪、追溯预警 | 5-8 | 0.8-1.2万 |
|
||||
| D-07 | **合理用药** | 药物相互作用、过敏匹配、剂量审查、重复用药、配伍禁忌、妊娠/哺乳警示、儿童用药、处方前置拦截 | 10-15 | 1.5-2.5万 |
|
||||
| D-08 | **抗菌药物管控** | 三级分类、权限拦截、DDD 监测、审批流程 | 5-8 | 0.8-1.2万 |
|
||||
| D-09 | **处方点评** | 自动筛查+人工点评+科室排名+统计 | 4-6 | 0.5-1万 |
|
||||
| D-10 | **日终结算** | 药房日结/月结/年结 | 2-4 | 0.3-0.6万 |
|
||||
| D-11 | **药品效期管理** | 3/6/12 月效期预警、先进先出、过期自动拦截 | 3-5 | 0.5-0.8万 |
|
||||
| | **药品域参考** | | **75-116** | **11-18.8万** |
|
||||
|
||||
### 检验检查域 — LIS + PACS + 病理
|
||||
|
||||
| 序号 | 模块 | 功能说明 | 人天 | 报价区间 |
|
||||
|:---:|------|---------|:---:|:------:|
|
||||
| L-01 | **检验管理(LIS)** | 申请接收、条码管理、标本采集/接收、结果录入、报告审核/发布、参考范围、历史对比 | 14-20 | 2-3万 |
|
||||
| L-02 | **危急值管理** | 自动识别→弹窗通知→确认→处置→闭环追踪 | 4-6 | 0.5-1万 |
|
||||
| L-03 | **检验质控** | 室内质控(Westgard 规则)、室间质评 | 5-8 | 0.8-1.2万 |
|
||||
| L-04 | **检验增强** | 检验类型/套餐/活动定义管理、历史对比 | 5-8 | 0.8-1.2万 |
|
||||
| L-05 | **检查管理(PACS)** | 申请接收、预约排队、DICOM 图像采集、结构化图文报告、紧急报告、影像对比、DICOM 打印 | 12-18 | 2-3万 |
|
||||
| L-06 | **3D 影像重建** | DICOM 三维重建、多平面重建(MPR)、体积渲染 | 6-10 | 1-1.5万 |
|
||||
| L-07 | **病理管理** | 病理申请、标本追踪、制片流程、三级诊断、报告管理 | 8-12 | 1-2万 |
|
||||
| L-08 | **医技工作站** | 检验申请单号自动生成、套餐管理、执行科室智能匹配 | 5-8 | 0.8-1.2万 |
|
||||
| | **检验检查域参考** | | **59-90** | **9-14.1万** |
|
||||
|
||||
### 手术麻醉域 — 高风险高价值
|
||||
|
||||
| 序号 | 模块 | 功能说明 | 人天 | 报价区间 |
|
||||
|:---:|------|---------|:---:|:------:|
|
||||
| S-01 | **手术管理** | 手术申请、分级审批、手术室安排(冲突检查)、手术计费、手术统计 | 12-18 | 2-3万 |
|
||||
| S-02 | **术前讨论** | 三/四级手术强制讨论、讨论记录、签名审核 | 4-6 | 0.5-1万 |
|
||||
| S-03 | **麻醉管理** | 麻醉评估(ASA分级)、麻醉方案、术中记录(5分钟间隔生命体征)、复苏评估 | 8-12 | 1.2-2万 |
|
||||
| S-04 | **手术安全核查** | WS/T 313 三次核查(麻醉前/切皮前/离室前) | 3-5 | 0.5-0.8万 |
|
||||
| S-05 | **手术记录** | 手术团队、时间、植入物、标本、出血量、并发症 | 3-5 | 0.5-0.8万 |
|
||||
| S-06 | **术后随访** | 24h/48h/72h 术后随访 | 2-4 | 0.3-0.6万 |
|
||||
| S-07 | **麻醉质控** | 麻醉安全指标、不良事件上报 | 3-5 | 0.5-0.8万 |
|
||||
| | **手术麻醉域参考** | | **35-55** | **5.5-9万** |
|
||||
|
||||
### 电子病历域 — 直接影响电子病历评级
|
||||
|
||||
| 序号 | 模块 | 功能说明 | 人天 | 报价区间 |
|
||||
|:---:|------|---------|:---:|:------:|
|
||||
| E-01 | **结构化病历** | 结构化+自由文本混合录入、ICD-10 自动编码推荐 | 6-10 | 0.8-1.5万 |
|
||||
| E-02 | **模板管理** | 系统+科室+个人三级模板体系 | 4-6 | 0.5-1万 |
|
||||
| E-03 | **修改追踪** | 修改留痕(原文+修改人+时间)、差异对比 | 3-5 | 0.5-0.8万 |
|
||||
| E-04 | **版本管理** | 历史版本保存、版本对比 | 2-4 | 0.3-0.6万 |
|
||||
| E-05 | **完整性检查** | 必填项+逻辑一致性自动检查 | 3-5 | 0.5-0.8万 |
|
||||
| E-06 | **时效监控** | 入院记录 24h、首次病程 8h 等时限提醒 | 2-4 | 0.3-0.6万 |
|
||||
| E-07 | **CA 电子签名** | 文书电子签名、签名验证、历史、撤销 | 4-6 | 0.5-1万 |
|
||||
| E-08 | **病历检索** | 按诊断/时间/医生多维度检索 | 3-5 | 0.5-0.8万 |
|
||||
| E-09 | **知识库链接** | 病历中嵌入临床指南/药物信息 | 3-5 | 0.5-0.8万 |
|
||||
| E-10 | **打印归档** | 病历打印、出院自动归档、24h 归档率统计 | 3-5 | 0.5-0.8万 |
|
||||
| E-11 | **病程记录** | 首次/日常/上级查房/阶段小结/抢救/转科/出院/死亡记录模板 | 5-8 | 0.8-1.2万 |
|
||||
| E-12 | **知情同意** | 电子知情同意书模板+签名 | 3-5 | 0.5-0.8万 |
|
||||
| | **电子病历域参考** | | **41-68** | **6.2-10.7万** |
|
||||
|
||||
### 病案管理域 — DRG/DIP 分组质量的基础
|
||||
|
||||
| 序号 | 模块 | 功能说明 | 人天 | 报价区间 |
|
||||
|:---:|------|---------|:---:|:------:|
|
||||
| R-01 | **病案首页** | 数据自动采集、ICD-10 编码推荐与验证、ICD-9-CM-3 手术编码 | 8-12 | 1-2万 |
|
||||
| R-02 | **病案质控** | 首页数据质量检查、运行+终末病历质控 | 5-8 | 0.8-1.2万 |
|
||||
| R-03 | **DRG/DIP 分组** | 自动分组、费用预警、TOP-DRG 分析、优化建议 | 8-12 | 1-2万 |
|
||||
| R-04 | **病案归档** | 出院自动归档、24h 归档率追踪 | 3-5 | 0.5-0.8万 |
|
||||
| R-05 | **病案借阅/封存** | 借阅审批+超期提醒、纠纷封存、病案示踪 | 4-6 | 0.5-1万 |
|
||||
| R-06 | **死亡病历讨论** | 死亡病例 7 日内讨论记录 | 2-3 | 0.3-0.5万 |
|
||||
| R-07 | **病案评审** | 评审计划、记录、统计 | 3-5 | 0.5-0.8万 |
|
||||
| | **病案域参考** | | **33-51** | **5.1-8.3万** |
|
||||
|
||||
### 护理管理域 — 患者安全的最后防线
|
||||
|
||||
| 序号 | 模块 | 功能说明 | 人天 | 报价区间 |
|
||||
|:---:|------|---------|:---:|:------:|
|
||||
| N-01 | **护理评估** | Braden/Morse/NRS2002/NRS-VAS/Caprini/Barthel 六大评估量表,自动评分+预警 | 10-15 | 1.5-2.5万 |
|
||||
| N-02 | **护理计划** | 基于评估结果自动生成护理计划 | 4-6 | 0.5-1万 |
|
||||
| N-03 | **交班记录** | 护理交接班、重点患者提示 | 3-5 | 0.5-0.8万 |
|
||||
| N-04 | **移动护理** | 扫码执行医嘱(腕带/药品/标本) | 5-8 | 0.8-1.2万 |
|
||||
| N-05 | **输液管理** | 输液巡视记录、速度监控 | 3-5 | 0.5-0.8万 |
|
||||
| N-06 | **评估趋势** | 历次评估结果动态趋势图 | 3-5 | 0.5-0.8万 |
|
||||
| N-07 | **护理质控** | 护理敏感质量指标自动采集+上报 | 3-5 | 0.5-0.8万 |
|
||||
| N-08 | **护理文书** | 一般/危重护理记录单 | 3-5 | 0.5-0.8万 |
|
||||
| | **护理域参考** | | **34-54** | **5.3-8.7万** |
|
||||
|
||||
### 院感管理域 — 三甲评审重点检查项
|
||||
|
||||
| 序号 | 模块 | 功能说明 | 人天 | 报价区间 |
|
||||
|:---:|------|---------|:---:|:------:|
|
||||
| I-01 | **感染监测** | 自动筛查疑似感染病例、上报院感科、跟踪 | 5-8 | 0.8-1.2万 |
|
||||
| I-02 | **暴发预警** | 同科室短时间多例感染预警 | 3-5 | 0.5-0.8万 |
|
||||
| I-03 | **目标性监测** | ICU/手术部位/导管相关感染 | 3-5 | 0.5-0.8万 |
|
||||
| I-04 | **手卫生监测** | 手卫生依从性统计 | 2-4 | 0.3-0.6万 |
|
||||
| I-05 | **环境监测** | 空气/物表/手培养监测 | 2-4 | 0.3-0.6万 |
|
||||
| I-06 | **多重耐药菌** | 检出→隔离→跟踪→解除 | 3-5 | 0.5-0.8万 |
|
||||
| I-07 | **职业暴露** | 锐器伤/暴露事件上报+随访 | 2-4 | 0.3-0.6万 |
|
||||
| I-08 | **消毒供应(CSSD)** | 器械包追溯、灭菌批次、效期预警 | 5-8 | 0.8-1.2万 |
|
||||
| | **院感域参考** | | **25-43** | **4-7.2万** |
|
||||
|
||||
### 医保管理域 — 直接关系到医院收入
|
||||
|
||||
| 序号 | 模块 | 功能说明 | 人天 | 报价区间 |
|
||||
|:---:|------|---------|:---:|:------:|
|
||||
| Y-01 | **医保基础结算** | 门诊/住院基本医保结算 | 6-10 | 0.8-1.5万 |
|
||||
| Y-02 | **目录对照** | 药品/诊疗/耗材三目录对照 | 6-10 | 0.8-1.5万 |
|
||||
| Y-03 | **医保对账** | 财务对账/清算、差异处理 | 5-8 | 0.8-1.2万 |
|
||||
| Y-04 | **处方上传** | 门诊处方上传/拒收/撤销 | 4-6 | 0.5-1万 |
|
||||
| Y-05 | **住院医保** | 住院登记/出院结算、DRG/DIP 结算 | 6-10 | 0.8-1.5万 |
|
||||
| Y-06 | **跨省结算** | 跨省异地就医直接结算 | 4-6 | 0.5-1万 |
|
||||
| Y-07 | **智能审核** | 事前/事中/事后三阶段审核规则引擎 | 6-10 | 0.8-1.5万 |
|
||||
| Y-08 | **DRG/DIP 优化** | 优化建议、费用结构分析 | 4-6 | 0.5-1万 |
|
||||
| | **医保域参考** | | **41-66** | **5.5-10.2万** |
|
||||
|
||||
### 集成平台层 — 面向三级医院的互联互通
|
||||
|
||||
| 序号 | 模块 | 功能说明 | 人天 | 报价区间 |
|
||||
|:---:|------|---------|:---:|:------:|
|
||||
| J-01 | **ESB 集成平台** | 消息路由、服务注册、消息监控、死信队列 | 10-15 | 1.5-2.5万 |
|
||||
| J-02 | **HL7 FHIR R4** | FHIR R4 标准消息格式 | 5-8 | 0.8-1.2万 |
|
||||
| J-03 | **CDA 文档** | 临床文档架构(入院/出院/检验/处方/手术/护理) | 5-8 | 0.8-1.2万 |
|
||||
| J-04 | **代码映射** | 院内编码↔标准编码映射 | 3-5 | 0.5-0.8万 |
|
||||
| J-05 | **API 认证审计** | 接口调用认证+授权+审计日志 | 2-4 | 0.3-0.6万 |
|
||||
| J-06 | **EMPI 患者主索引** | 身份合并/拆分、重复检测、跨系统统一标识 | 6-10 | 0.8-1.5万 |
|
||||
| | **集成平台参考** | | **31-50** | **4.7-7.8万** |
|
||||
|
||||
### 其他业务模块
|
||||
|
||||
| 序号 | 模块 | 功能说明 | 人天 | 报价区间 |
|
||||
|:---:|------|---------|:---:|:------:|
|
||||
| O-01 | **急诊管理** | 四级分诊、绿色通道(胸痛/卒中/创伤)、抢救/留观、D2T 监控 | 8-12 | 1-2万 |
|
||||
| O-02 | **随访管理** | 随访计划自动生成、任务分配、满意度调查 | 6-10 | 0.8-1.5万 |
|
||||
| O-03 | **中医/壮医** | 中医处方、体质辨识、民族药目录(壮药/瑶药) | 5-8 | 0.8-1.2万 |
|
||||
| O-04 | **会诊管理** | 会诊申请/审批/确认、超时监控、结果反馈 | 5-8 | 0.8-1.2万 |
|
||||
| O-05 | **传染病报告** | 报卡新增/审核/退回、Word 导出、统计 | 5-8 | 0.8-1.2万 |
|
||||
| O-06 | **调价管理** | 药品/器械/服务调价、审批流程 | 4-6 | 0.5-1万 |
|
||||
| O-07 | **支付管理** | 收费账单、电子发票、第三方支付集成 | 6-10 | 0.8-1.5万 |
|
||||
| O-08 | **医嘱套餐** | 医嘱组套配置(组织级/医院级/个人级) | 4-6 | 0.5-1万 |
|
||||
| O-09 | **医嘱闭环追踪** | 医嘱全生命周期执行步骤记录 | 4-6 | 0.5-1万 |
|
||||
| O-10 | **跨模块集成** | 术-病理关联、会诊监控、DRG 绩效、危急值联动、手术全链路追踪 | 8-12 | 1-2万 |
|
||||
| O-11 | **质量管理** | 质控增强、业务分析大屏、EMR 质量检查 | 4-6 | 0.5-1万 |
|
||||
| O-12 | **食源性数据采集** | 食源性疾病数据外接采集 | 2-4 | 0.3-0.6万 |
|
||||
| | **其他模块参考** | | **61-96** | **9-15.2万** |
|
||||
|
||||
### 全模块汇总
|
||||
|
||||
| 业务域 | 模块数 | 人天区间 | 参考报价 |
|
||||
|--------|:-----:|:------:|:------:|
|
||||
| 系统平台层 | 8 | 42-66 | 6-11万 |
|
||||
| 门诊管理域 | 7 | 59-90 | 9-14.5万 |
|
||||
| 住院管理域 | 6 | 60-91 | 10-14.4万 |
|
||||
| 药品管理域 | 11 | 75-116 | 11-18.8万 |
|
||||
| 检验检查域 | 8 | 59-90 | 9-14.1万 |
|
||||
| 手术麻醉域 | 7 | 35-55 | 5.5-9万 |
|
||||
| 电子病历域 | 12 | 41-68 | 6.2-10.7万 |
|
||||
| 病案管理域 | 7 | 33-51 | 5.1-8.3万 |
|
||||
| 护理管理域 | 8 | 34-54 | 5.3-8.7万 |
|
||||
| 院感管理域 | 8 | 25-43 | 4-7.2万 |
|
||||
| 医保管理域 | 8 | 41-66 | 5.5-10.2万 |
|
||||
| 其他业务模块 | 12 | 61-96 | 9-15.2万 |
|
||||
| 集成平台层 | 6 | 31-50 | 4.7-7.8万 |
|
||||
| **全量参考** | **108** | **596-936** | **约90-150万** |
|
||||
|
||||
> 以上为软件开发的参考价格区间,实际报价根据医院具体需求、定制程度和接口数量确定。
|
||||
|
||||
---
|
||||
|
||||
## 四、三个版本,按需选配
|
||||
|
||||
不是每家医院都需要 108 个模块。我们根据医院等级,设计了三个标准版本:
|
||||
|
||||
| 方案 | 适用对象 | 模块数 | 软件参考报价 | 实施周期 |
|
||||
|------|---------|:-----:|:---------:|:------:|
|
||||
| **基础版** | 一级医院/社区卫生中心 | 18 | **18-25万** | 1-2月 |
|
||||
| **标准版** | 二级综合医院 | 52 | **55-70万** | 3-5月 |
|
||||
| **旗舰版** | 三级综合医院 | 108 | **90-120万** | 5-8月 |
|
||||
| **定制开发** | 特殊需求/已有HIS升级 | 按需 | **1,500元/人天起** | 按需 |
|
||||
|
||||
### 基础版 — 一级医院 / 社区卫生服务中心
|
||||
|
||||
**适合**:基层医疗机构、社区卫生服务中心、乡镇卫生院。快速上线、经济实惠。
|
||||
|
||||
| 业务域 | 包含模块 |
|
||||
|--------|---------|
|
||||
| 系统平台 | 系统管理、文件服务、定时任务、首页仪表板 |
|
||||
| 门诊管理 | 挂号预约、分诊叫号、门诊医生站、门诊收费、门诊药房 |
|
||||
| 住院管理 | 入院管理、护士工作站、住院收费、床位管理 |
|
||||
| 电子病历 | 结构化病历、模板管理 |
|
||||
| 医保管理 | 医保基础结算 |
|
||||
| 其他 | 调价管理、质量管理 |
|
||||
|
||||
**软件 + 实施 + 接口 + 首年维保,整体投入约 25-35 万。**
|
||||
|
||||
### 标准版 — 二级综合医院
|
||||
|
||||
**适合**:二级综合医院、中医医院、妇幼保健院。覆盖等级评审全部信息化条款。
|
||||
|
||||
在基础版之上新增:
|
||||
|
||||
| 业务域 | 新增模块 |
|
||||
|--------|---------|
|
||||
| 系统平台 | + 监控运维、工作流引擎、数据导出 |
|
||||
| 门诊管理 | + 门诊治疗、门诊手术 |
|
||||
| 住院管理 | + 住院医生站、医嘱闭环 |
|
||||
| 药品管理 | + 药品目录、药库、药房、科室物资、库存、合理用药、抗菌药物管控、处方点评、日终结算 |
|
||||
| 检验检查 | + 检验(LIS)、危急值、检查(PACS)、医技工作站 |
|
||||
| 手术麻醉 | + 手术管理、术前讨论、安全核查 |
|
||||
| 电子病历 | + 修改追踪、版本管理、完整性检查、时效监控、CA签名、检索、知识库、归档、病程记录、知情同意 |
|
||||
| 病案管理 | + 病案首页、病案质控、归档、借阅/封存 |
|
||||
| 护理管理 | + 护理评估、护理计划、交班记录、护理质控 |
|
||||
| 院感管理 | + 感染监测、暴发预警、多重耐药菌 |
|
||||
| 医保管理 | + 目录对照、对账、处方上传、住院医保 |
|
||||
| 其他 | + 急诊、随访、会诊、传染病报告、支付管理、医嘱套餐 |
|
||||
|
||||
**软件 + 实施 + 接口 + 首年维保,整体投入约 70-90 万。**
|
||||
|
||||
### 旗舰版 — 三级综合医院
|
||||
|
||||
**适合**:三级综合医院。全面覆盖三甲评审、DRG/DIP 支付改革、电子病历高等级评价、互联互通测评。
|
||||
|
||||
在标准版之上新增:
|
||||
|
||||
| 业务域 | 新增模块 |
|
||||
|--------|---------|
|
||||
| 药品管理 | + 药品追溯、药品效期管理 |
|
||||
| 检验检查 | + 检验质控、检验增强、3D影像重建、病理管理 |
|
||||
| 手术麻醉 | + 麻醉管理、手术记录、术后随访、麻醉质控 |
|
||||
| 病案管理 | + DRG/DIP分组、死亡病历讨论、病案评审 |
|
||||
| 护理管理 | + 移动护理、输液管理、评估趋势、护理文书 |
|
||||
| 院感管理 | + 目标性监测、手卫生、环境监测、职业暴露、CSSD |
|
||||
| 医保管理 | + 跨省结算、智能审核、DRG/DIP优化 |
|
||||
| 集成平台 | + ESB平台、FHIR R4、CDA文档、代码映射、API认证、EMPI |
|
||||
| 其他 | + 中医/壮医、医嘱闭环追踪、跨模块集成、食源性采集 |
|
||||
|
||||
**软件 + 实施 + 全量接口 + 评审支持 + 首年维保,整体投入约 130-160 万。**
|
||||
|
||||
---
|
||||
|
||||
## 五、几个值得重点关注的明星模块
|
||||
|
||||
在 108 个模块中,有几个模块是评审检查和日常运营中的"高频考点":
|
||||
|
||||
### 合理用药系统(1.5-2.5万)
|
||||
|
||||
12 项审核能力,让处方审核率 100% 不再是口号:
|
||||
- 药物相互作用检查(两药/三药配伍禁忌)
|
||||
- 过敏史自动匹配
|
||||
- 剂量范围审查(超/低剂量 + 肝肾功能自动调量)
|
||||
- 重复用药检查
|
||||
- 配伍禁忌审查
|
||||
- 妊娠/哺乳用药警示
|
||||
- 儿童用药按体重自动计算
|
||||
- **处方前置拦截**:不合理处方必须处理才能继续
|
||||
|
||||
### DRG/DIP 分组系统(1-2万)
|
||||
|
||||
医保付费改革的核心武器:
|
||||
- 主诊断+主手术 → 自动分组
|
||||
- 病组分布/费用结构/时间消耗分析
|
||||
- TOP-DRG 分析
|
||||
- 费用预警(入院即开始监控)
|
||||
- 优化建议(帮助医生在保证质量的前提下控制费用)
|
||||
|
||||
### 手术安全核查(0.5-0.8万)
|
||||
|
||||
符合 WS/T 313 标准的三次核查:麻醉前核查 → 切皮前核查 → 离室前核查。
|
||||
|
||||
看似价格最低的模块之一,却是手术安全最关键的防线。
|
||||
|
||||
### 护理评估系统(1.5-2.5万)
|
||||
|
||||
覆盖六大评估量表,自动评分+自动预警:
|
||||
- Braden 压疮评估 → 自动预警 → 干预 → 跟踪
|
||||
- Morse 跌倒评估 → 风险分级 → 防护措施
|
||||
- NRS2002 营养风险筛查
|
||||
- NRS/VAS 疼痛评估
|
||||
- Caprini VTE 风险评估
|
||||
- Barthel 自理能力评估
|
||||
|
||||
---
|
||||
|
||||
## 六、实施服务体系
|
||||
|
||||
### 6.1 标准实施流程
|
||||
|
||||
我们采用经过数十家医院验证的标准化实施流程:
|
||||
|
||||
| 阶段 | 内容 | 周期 | 交付物 |
|
||||
|------|------|:---:|-------|
|
||||
| **需求调研** | 现场调研、流程梳理、差距分析、需求确认 | 1-3周 | 需求确认书 |
|
||||
| **环境部署** | 服务器部署、网络配置、安全加固 | 3-5天 | 部署报告 |
|
||||
| **系统配置** | 参数配置、权限设置、字典维护、流程配置 | 1周 | 配置清单 |
|
||||
| **数据迁移** | 历史数据清洗、字段映射、数据导入、数据校验 | 1-3周 | 迁移报告 |
|
||||
| **用户培训** | 分角色培训、操作演练、考核通关 | 1-2周 | 培训签到表 |
|
||||
| **并行运行** | 新旧系统并行、问题修复、流程优化 | 2-4周 | 问题清单 |
|
||||
| **正式上线** | 切换上线、驻场陪跑、应急预案 | 1周 | 上线报告 |
|
||||
|
||||
### 6.2 数据迁移服务
|
||||
|
||||
| 服务项 | 说明 |
|
||||
|--------|------|
|
||||
| **数据评估** | 免费评估原系统数据结构和迁移可行性 |
|
||||
| **数据清洗** | 去重、纠错、标准化、编码映射 |
|
||||
| **字段映射** | 原系统字段→新系统字段自动+人工映射 |
|
||||
| **增量迁移** | 支持切换前最后一天的增量数据同步 |
|
||||
| **数据校验** | 迁移后逐条核对,确保数据完整性 |
|
||||
| **回滚预案** | 迁移失败可完整回滚,不影响业务 |
|
||||
|
||||
### 6.3 培训服务体系
|
||||
|
||||
| 培训对象 | 培训内容 | 课时 | 方式 |
|
||||
|---------|---------|:---:|------|
|
||||
| **系统管理员** | 系统配置、用户管理、字典维护、备份恢复 | 8-16h | 现场+远程 |
|
||||
| **医生** | 医生工作站、电子病历、处方、医嘱、手术申请 | 8-12h | 现场+视频 |
|
||||
| **护士** | 护士工作站、医嘱执行、护理评估、体温单 | 8-12h | 现场+视频 |
|
||||
| **收费员** | 挂号、收费、退费、日结、医保结算 | 4-8h | 现场 |
|
||||
| **药房人员** | 发药、退药、库存管理、盘点、日结 | 4-8h | 现场 |
|
||||
| **管理层** | 数据驾驶舱、统计报表、经营分析 | 2-4h | 现场+远程 |
|
||||
| **院感/质控** | 院感监测、病案管理、质控操作 | 4-8h | 现场+视频 |
|
||||
|
||||
> 提供培训视频和操作手册,支持新员工随时自主学习。
|
||||
|
||||
---
|
||||
|
||||
## 七、接口对接服务
|
||||
|
||||
| 接口类型 | 参考报价 | 说明 |
|
||||
|---------|:------:|------|
|
||||
| 检验设备对接(单台) | 0.3-0.8万 | LIS 仪器接口,支持主流品牌 |
|
||||
| 影像设备对接(单台) | 0.5-1.2万 | PACS/DICOM 设备 |
|
||||
| 医保平台对接 | 1-2万 | 省/国家医保平台 |
|
||||
| 卫健委数据上报 | 0.8-1.5万 | HQMS/传染病直报 |
|
||||
| 电子发票对接 | 0.5-1万 | 财政电子票据 |
|
||||
| 银行/第三方支付 | 0.5-1万 | 微信/支付宝/银联 |
|
||||
| 自助终端设备 | 0.5-1万 | 自助挂号机/取单机/报告打印机 |
|
||||
| 其他第三方系统 | 0.5-2万 | 按复杂度定价 |
|
||||
|
||||
---
|
||||
|
||||
## 八、售后服务分级
|
||||
|
||||
我们提供三级售后服务体系,满足不同医院的需求:
|
||||
|
||||
| 服务项目 | 标准服务 | 高级服务 | 尊享服务 |
|
||||
|---------|:------:|:------:|:------:|
|
||||
| 适用医院 | 一级 | 二级 | 三级 |
|
||||
| 首年维保 | **免费** | **免费** | **免费** |
|
||||
| 续费年维保 | 软件费×15% | 软件费×15% | 软件费×12% |
|
||||
| 远程支持 | 5×8h | 7×12h | 7×24h |
|
||||
| 故障响应 | 4小时 | 2小时 | 1小时 |
|
||||
| 现场支持 | 按需另计 | 2次/年 | 4次/年 |
|
||||
| 版本升级 | 小版本免费 | 大版本免费 | 全版本免费 |
|
||||
| 专属服务经理 | — | ✅ | ✅ |
|
||||
| 季度巡检 | — | — | ✅ |
|
||||
| 应急演练 | — | — | 1次/年 |
|
||||
| 重大活动保障 | — | — | 远程值守 |
|
||||
|
||||
### 服务等级协议(SLA)
|
||||
|
||||
| 故障等级 | 定义 | 响应时间 | 解决时间 |
|
||||
|:------:|------|:------:|:------:|
|
||||
| **P0 紧急** | 系统无法使用,业务完全中断 | 30分钟 | 4小时 |
|
||||
| **P1 严重** | 核心功能不可用,影响大量用户 | 1小时 | 8小时 |
|
||||
| **P2 一般** | 部分功能异常,有替代方案 | 4小时 | 24小时 |
|
||||
| **P3 轻微** | 界面/体验问题,不影响业务 | 8小时 | 72小时 |
|
||||
|
||||
---
|
||||
|
||||
## 九、定制开发服务
|
||||
|
||||
已有 HIS 系统?也没关系。我们提供模块化定制开发服务。
|
||||
|
||||
### 9.1 人员单价
|
||||
|
||||
| 角色 | 单价(元/人天) | 说明 |
|
||||
|------|:-------------:|------|
|
||||
| 开发工程师 | **1,500** | 需求分析+设计+开发+自测 |
|
||||
| 高级工程师 | **2,000** | 架构设计、性能优化、疑难问题 |
|
||||
| 项目经理 | **1,800** | 需求调研、项目管理、交付管理 |
|
||||
| 实施顾问 | **1,200** | 部署实施、培训、数据迁移 |
|
||||
|
||||
### 9.2 常见定制参考价
|
||||
|
||||
| 定制项目 | 预估人天 | 参考报价 |
|
||||
|---------|:------:|:------:|
|
||||
| 新增业务模块(中等复杂度) | 15-25 | 2-4万 |
|
||||
| 报表定制开发(单张) | 3-5 | 0.5-0.8万 |
|
||||
| 第三方系统接口对接(单个) | 5-10 | 0.8-1.5万 |
|
||||
| 已有模块功能增强 | 5-15 | 0.8-2.5万 |
|
||||
| 流程改造/优化 | 8-20 | 1-3万 |
|
||||
| 移动端功能开发 | 10-20 | 1.5-3万 |
|
||||
| 大屏可视化开发 | 8-15 | 1-2.5万 |
|
||||
| 单模块独立采购 | 见上方明细 | 0.3-3.5万/模块 |
|
||||
|
||||
### 9.3 定制开发流程
|
||||
|
||||
```
|
||||
需求沟通(1-2天) → 方案设计与报价(2-3天) → 合同签订 → 开发实施 → 内部测试 → 用户验收 → 上线交付
|
||||
```
|
||||
|
||||
### 9.4 交付标准
|
||||
|
||||
每次定制开发交付包含:
|
||||
- 功能代码(含单元测试)
|
||||
- 数据库迁移脚本(Flyway 版本化)
|
||||
- 接口文档(Swagger/OpenAPI 自动生成)
|
||||
- 用户操作说明
|
||||
- 测试报告
|
||||
|
||||
---
|
||||
|
||||
## 十、付款方式与验收
|
||||
|
||||
### 付款节奏
|
||||
|
||||
| 阶段 | 比例 | 条件 |
|
||||
|------|:---:|------|
|
||||
| 合同签订 | 30% | 合同签署后 5 个工作日 |
|
||||
| 系统开发完成进入测试 | 30% | 系统功能开发完成,进入内部测试阶段 |
|
||||
| 系统验收 | 30% | 系统上线并通过验收 |
|
||||
| 质保期满 | 10% | 首年维保期满后支付 |
|
||||
|
||||
### 验收标准
|
||||
|
||||
| 验收项 | 标准 |
|
||||
|--------|------|
|
||||
| 功能验收 | 合同约定的核心模块功能完整可用 |
|
||||
| 性能验收 | 核心页面加载 < 3秒,常规操作响应流畅 |
|
||||
| 数据验收 | 历史数据迁移完成,关键数据核对无误 |
|
||||
| 培训验收 | 主要岗位人员完成培训并能基本操作 |
|
||||
| 稳定性 | 连续运行 3 个工作日无阻断性故障 |
|
||||
|
||||
---
|
||||
|
||||
## 十一、为什么选择 HealthLink-HIS?
|
||||
|
||||
| 维度 | 选择理由 |
|
||||
|------|---------|
|
||||
| **技术领先** | Spring Boot 4.0 + JDK 25,业内首批升级 |
|
||||
| **架构扎实** | DDD 领域驱动 + Maven 多模块,业务独立演进 |
|
||||
| **功能完整** | 108 个模块,14 大业务域全覆盖 |
|
||||
| **质量可靠** | 2,265 次提交、1,400+ Bug 修复,持续打磨 |
|
||||
| **安全合规** | JWT + 多租户隔离 + CA 签名 + 数据加密 |
|
||||
| **达标有路** | 对标三甲评审标准,142 项必备能力已实现 59 项 |
|
||||
| **灵活选配** | 按需选配模块,从 18 万到 120 万自由组合 |
|
||||
| **灵活部署** | 支持私有云/混合云/SaaS/信创环境 |
|
||||
| **持续迭代** | 首年免费维保,版本升级持续获得新功能 |
|
||||
|
||||
---
|
||||
|
||||
## 联系我们
|
||||
|
||||
> **上海经创贺联信息科技有限公司**
|
||||
>
|
||||
> - 销售热线:18017857330
|
||||
> - 邮箱:chen.qi@jin-group.cn
|
||||
> - 官网:www.health-link.com.cn
|
||||
> - 地址:上海市闵行区甬虹路69号虹桥绿谷广场G座G栋505
|
||||
>
|
||||
> **支持免费远程演示,欢迎扫码预约体验!**
|
||||
>
|
||||
> *获取您医院的定制化报价方案,只需告诉我们医院等级和核心需求。*
|
||||
|
||||
---
|
||||
|
||||
## 附录:模块速查表
|
||||
|
||||
| 域 | 编号 | 模块 | 报价区间 | 基础版 | 标准版 | 旗舰版 |
|
||||
|----|:---:|------|:------:|:-----:|:-----:|:-----:|
|
||||
| 平台 | P-01 | 系统管理 | 1.5-2.5万 | ✅ | ✅ | ✅ |
|
||||
| 平台 | P-02 | 监控运维 | 0.8-1.2万 | | ✅ | ✅ |
|
||||
| 平台 | P-03 | 文件服务 | 0.3-0.8万 | ✅ | ✅ | ✅ |
|
||||
| 平台 | P-04 | 工作流引擎 | 1.5-2.5万 | | ✅ | ✅ |
|
||||
| 平台 | P-05 | 定时任务 | 0.5-0.8万 | ✅ | ✅ | ✅ |
|
||||
| 平台 | P-06 | 代码生成器 | 0.3-0.8万 | | | ✅ |
|
||||
| 平台 | P-07 | 数据导出 | 0.3-0.8万 | | ✅ | ✅ |
|
||||
| 平台 | P-08 | 首页仪表板 | 0.5-1.2万 | ✅ | ✅ | ✅ |
|
||||
| 门诊 | M-01 | 挂号预约 | 1.5-2.5万 | ✅ | ✅ | ✅ |
|
||||
| 门诊 | M-02 | 分诊叫号 | 0.8-1.5万 | ✅ | ✅ | ✅ |
|
||||
| 门诊 | M-03 | 门诊医生站 | 2-3.5万 | ✅ | ✅ | ✅ |
|
||||
| 门诊 | M-04 | 门诊收费 | 1.5-2.5万 | ✅ | ✅ | ✅ |
|
||||
| 门诊 | M-05 | 门诊药房 | 1-2万 | ✅ | ✅ | ✅ |
|
||||
| 门诊 | M-06 | 门诊治疗 | 0.8-1.5万 | | ✅ | ✅ |
|
||||
| 门诊 | M-07 | 门诊手术 | 0.5-1万 | | ✅ | ✅ |
|
||||
| 住院 | H-01 | 入院管理 | 1.5-2.5万 | ✅ | ✅ | ✅ |
|
||||
| 住院 | H-02 | 住院医生站 | 3-4.5万 | | ✅ | ✅ |
|
||||
| 住院 | H-03 | 护士工作站 | 2-3万 | ✅ | ✅ | ✅ |
|
||||
| 住院 | H-04 | 住院收费 | 1-2万 | ✅ | ✅ | ✅ |
|
||||
| 住院 | H-05 | 床位管理 | 0.8-1.2万 | ✅ | ✅ | ✅ |
|
||||
| 住院 | H-06 | 医嘱闭环 | 0.8-1.2万 | | ✅ | ✅ |
|
||||
| 药品 | D-01 | 药品目录 | 0.8-1.5万 | | ✅ | ✅ |
|
||||
| 药品 | D-02 | 药库管理 | 2-3万 | | ✅ | ✅ |
|
||||
| 药品 | D-03 | 药房管理 | 1.5-2.5万 | | ✅ | ✅ |
|
||||
| 药品 | D-04 | 科室物资 | 1-2万 | | ✅ | ✅ |
|
||||
| 药品 | D-05 | 库存管理 | 1.5-2.5万 | | ✅ | ✅ |
|
||||
| 药品 | D-06 | 药品追溯 | 0.8-1.2万 | | | ✅ |
|
||||
| 药品 | D-07 | 合理用药 | 1.5-2.5万 | | ✅ | ✅ |
|
||||
| 药品 | D-08 | 抗菌药物管控 | 0.8-1.2万 | | ✅ | ✅ |
|
||||
| 药品 | D-09 | 处方点评 | 0.5-1万 | | ✅ | ✅ |
|
||||
| 药品 | D-10 | 日终结算 | 0.3-0.6万 | | ✅ | ✅ |
|
||||
| 药品 | D-11 | 药品效期 | 0.5-0.8万 | | | ✅ |
|
||||
| 检验 | L-01 | 检验(LIS) | 2-3万 | | ✅ | ✅ |
|
||||
| 检验 | L-02 | 危急值 | 0.5-1万 | | ✅ | ✅ |
|
||||
| 检验 | L-03 | 检验质控 | 0.8-1.2万 | | | ✅ |
|
||||
| 检验 | L-04 | 检验增强 | 0.8-1.2万 | | | ✅ |
|
||||
| 检验 | L-05 | 检查(PACS) | 2-3万 | | ✅ | ✅ |
|
||||
| 检验 | L-06 | 3D重建 | 1-1.5万 | | | ✅ |
|
||||
| 检验 | L-07 | 病理 | 1-2万 | | | ✅ |
|
||||
| 检验 | L-08 | 医技工作站 | 0.8-1.2万 | | ✅ | ✅ |
|
||||
| 手术 | S-01 | 手术管理 | 2-3万 | | ✅ | ✅ |
|
||||
| 手术 | S-02 | 术前讨论 | 0.5-1万 | | ✅ | ✅ |
|
||||
| 手术 | S-03 | 麻醉管理 | 1.2-2万 | | | ✅ |
|
||||
| 手术 | S-04 | 安全核查 | 0.5-0.8万 | | ✅ | ✅ |
|
||||
| 手术 | S-05 | 手术记录 | 0.5-0.8万 | | | ✅ |
|
||||
| 手术 | S-06 | 术后随访 | 0.3-0.6万 | | | ✅ |
|
||||
| 手术 | S-07 | 麻醉质控 | 0.5-0.8万 | | | ✅ |
|
||||
| 病历 | E-01 | 结构化病历 | 0.8-1.5万 | ✅ | ✅ | ✅ |
|
||||
| 病历 | E-02 | 模板管理 | 0.5-1万 | ✅ | ✅ | ✅ |
|
||||
| 病历 | E-03 | 修改追踪 | 0.5-0.8万 | | ✅ | ✅ |
|
||||
| 病历 | E-04 | 版本管理 | 0.3-0.6万 | | ✅ | ✅ |
|
||||
| 病历 | E-05 | 完整性检查 | 0.5-0.8万 | | ✅ | ✅ |
|
||||
| 病历 | E-06 | 时效监控 | 0.3-0.6万 | | ✅ | ✅ |
|
||||
| 病历 | E-07 | CA签名 | 0.5-1万 | | ✅ | ✅ |
|
||||
| 病历 | E-08 | 病历检索 | 0.5-0.8万 | | ✅ | ✅ |
|
||||
| 病历 | E-09 | 知识库 | 0.5-0.8万 | | ✅ | ✅ |
|
||||
| 病历 | E-10 | 打印归档 | 0.5-0.8万 | | ✅ | ✅ |
|
||||
| 病历 | E-11 | 病程记录 | 0.8-1.2万 | | ✅ | ✅ |
|
||||
| 病历 | E-12 | 知情同意 | 0.5-0.8万 | | ✅ | ✅ |
|
||||
| 病案 | R-01 | 病案首页 | 1-2万 | | ✅ | ✅ |
|
||||
| 病案 | R-02 | 病案质控 | 0.8-1.2万 | | ✅ | ✅ |
|
||||
| 病案 | R-03 | DRG/DIP | 1-2万 | | | ✅ |
|
||||
| 病案 | R-04 | 归档 | 0.5-0.8万 | | ✅ | ✅ |
|
||||
| 病案 | R-05 | 借阅/封存 | 0.5-1万 | | ✅ | ✅ |
|
||||
| 病案 | R-06 | 死亡讨论 | 0.3-0.5万 | | | ✅ |
|
||||
| 病案 | R-07 | 病案评审 | 0.5-0.8万 | | | ✅ |
|
||||
| 护理 | N-01 | 护理评估 | 1.5-2.5万 | | ✅ | ✅ |
|
||||
| 护理 | N-02 | 护理计划 | 0.5-1万 | | ✅ | ✅ |
|
||||
| 护理 | N-03 | 交班记录 | 0.5-0.8万 | | ✅ | ✅ |
|
||||
| 护理 | N-04 | 移动护理 | 0.8-1.2万 | | | ✅ |
|
||||
| 护理 | N-05 | 输液管理 | 0.5-0.8万 | | | ✅ |
|
||||
| 护理 | N-06 | 评估趋势 | 0.5-0.8万 | | | ✅ |
|
||||
| 护理 | N-07 | 护理质控 | 0.5-0.8万 | | ✅ | ✅ |
|
||||
| 护理 | N-08 | 护理文书 | 0.5-0.8万 | | | ✅ |
|
||||
| 院感 | I-01 | 感染监测 | 0.8-1.2万 | | ✅ | ✅ |
|
||||
| 院感 | I-02 | 暴发预警 | 0.5-0.8万 | | ✅ | ✅ |
|
||||
| 院感 | I-03 | 目标监测 | 0.5-0.8万 | | | ✅ |
|
||||
| 院感 | I-04 | 手卫生 | 0.3-0.6万 | | | ✅ |
|
||||
| 院感 | I-05 | 环境监测 | 0.3-0.6万 | | | ✅ |
|
||||
| 院感 | I-06 | 耐药菌 | 0.5-0.8万 | | ✅ | ✅ |
|
||||
| 院感 | I-07 | 职业暴露 | 0.3-0.6万 | | | ✅ |
|
||||
| 院感 | I-08 | CSSD | 0.8-1.2万 | | | ✅ |
|
||||
| 医保 | Y-01 | 基础结算 | 0.8-1.5万 | ✅ | ✅ | ✅ |
|
||||
| 医保 | Y-02 | 目录对照 | 0.8-1.5万 | | ✅ | ✅ |
|
||||
| 医保 | Y-03 | 医保对账 | 0.8-1.2万 | | ✅ | ✅ |
|
||||
| 医保 | Y-04 | 处方上传 | 0.5-1万 | | ✅ | ✅ |
|
||||
| 医保 | Y-05 | 住院医保 | 0.8-1.5万 | | ✅ | ✅ |
|
||||
| 医保 | Y-06 | 跨省结算 | 0.5-1万 | | | ✅ |
|
||||
| 医保 | Y-07 | 智能审核 | 0.8-1.5万 | | | ✅ |
|
||||
| 医保 | Y-08 | DRG优化 | 0.5-1万 | | | ✅ |
|
||||
| 其他 | O-01 | 急诊管理 | 1-2万 | | ✅ | ✅ |
|
||||
| 其他 | O-02 | 随访管理 | 0.8-1.5万 | | ✅ | ✅ |
|
||||
| 其他 | O-03 | 中医/壮医 | 0.8-1.2万 | | | ✅ |
|
||||
| 其他 | O-04 | 会诊管理 | 0.8-1.2万 | | ✅ | ✅ |
|
||||
| 其他 | O-05 | 传染病 | 0.8-1.2万 | | ✅ | ✅ |
|
||||
| 其他 | O-06 | 调价管理 | 0.5-1万 | ✅ | ✅ | ✅ |
|
||||
| 其他 | O-07 | 支付管理 | 0.8-1.5万 | | ✅ | ✅ |
|
||||
| 其他 | O-08 | 医嘱套餐 | 0.5-1万 | | ✅ | ✅ |
|
||||
| 其他 | O-09 | 医嘱闭环 | 0.5-1万 | | | ✅ |
|
||||
| 其他 | O-10 | 跨模块集成 | 1-2万 | | | ✅ |
|
||||
| 其他 | O-11 | 质量管理 | 0.5-1万 | ✅ | ✅ | ✅ |
|
||||
| 其他 | O-12 | 食源性采集 | 0.3-0.6万 | | | ✅ |
|
||||
| 集成 | J-01 | ESB平台 | 1.5-2.5万 | | | ✅ |
|
||||
| 集成 | J-02 | FHIR R4 | 0.8-1.2万 | | | ✅ |
|
||||
| 集成 | J-03 | CDA文档 | 0.8-1.2万 | | | ✅ |
|
||||
| 集成 | J-04 | 代码映射 | 0.5-0.8万 | | | ✅ |
|
||||
| 集成 | J-05 | API认证 | 0.3-0.6万 | | | ✅ |
|
||||
| 集成 | J-06 | EMPI | 0.8-1.5万 | | | ✅ |
|
||||
|
||||
---
|
||||
|
||||
*HealthLink-HIS — 让医疗信息化更透明、更可靠、更智能。*
|
||||
|
||||
*基于代码库实际分析:108 个业务模块 | 181+ 数据库表 | 230+ 控制器 | 209+ 前端页面*
|
||||
*工程师单价基准:1,500 元/人天*
|
||||
BIN
MD/HEALTHLINK_HIS_PRICING_v0.1.docx
Normal file
BIN
MD/HEALTHLINK_HIS_PRICING_v0.1.docx
Normal file
Binary file not shown.
BIN
MD/HEALTHLINK_HIS_XINCHUANG_ARTICLE.docx
Normal file
BIN
MD/HEALTHLINK_HIS_XINCHUANG_ARTICLE.docx
Normal file
Binary file not shown.
279
MD/HEALTHLINK_HIS_XINCHUANG_ARTICLE.md
Normal file
279
MD/HEALTHLINK_HIS_XINCHUANG_ARTICLE.md
Normal file
@@ -0,0 +1,279 @@
|
||||
# 2027 信创大限倒计时,你的 HIS 系统准备好了吗?— HealthLink-HIS 信创合规实践
|
||||
|
||||
> **上海经创贺联信息科技有限公司**
|
||||
|
||||
---
|
||||
|
||||
距离 2027 年全面信创替代的最后期限,只剩不到一年半。
|
||||
|
||||
对于公立医院来说,这已经不是"要不要做"的问题,而是"来不来得及"的问题。从操作系统到数据库,从中间件到芯片,全栈国产化替代正在从党政领域向医疗、金融、电信等八大关键行业全面铺开。
|
||||
|
||||
**而在所有需要替代的系统中,HIS(医院信息系统)可能是最难啃的那块骨头。**
|
||||
|
||||
---
|
||||
|
||||
## 一、信创替代,到底在替代什么?
|
||||
|
||||
"信创"全称是**信息技术应用创新**,核心目标是实现关键信息系统的**自主可控**,摆脱对国外底层技术的依赖。
|
||||
|
||||
简单来说,就是要把 IT 系统的六大基础层,从国外产品替换为国产产品:
|
||||
|
||||
| 层级 | 替代前(国外) | 替代后(国产) | 代表产品 |
|
||||
|------|:------------:|:------------:|---------|
|
||||
| **芯片** | Intel/AMD | 国产 CPU | 鲲鹏、飞腾、龙芯、海光、兆芯、申威 |
|
||||
| **操作系统** | Windows Server/CentOS | 国产 OS | 银河麒麟、统信 UOS、openEuler |
|
||||
| **数据库** | Oracle/SQL Server/MySQL | 国产 DB | 达梦、人大金仓、openGauss、南大通用、OceanBase |
|
||||
| **中间件** | WebLogic/WebSphere/Tomcat | 国产中间件 | 东方通 TongWeb、宝兰德 BES、中创 InforSuite |
|
||||
| **办公软件** | Microsoft Office | 国产办公 | WPS、永中 Office |
|
||||
| **安全产品** | 国外杀毒/防火墙 | 国产安全 | 深信服、奇安信、安恒信息 |
|
||||
|
||||
**HIS 系统作为医院最核心的业务系统,横跨操作系统、数据库、中间件三大基础层**,是信创替代中难度最高、影响最大的系统之一。
|
||||
|
||||
---
|
||||
|
||||
## 二、医疗信创,时间线有多紧?
|
||||
|
||||
### 政策脉络
|
||||
|
||||
| 时间 | 事件 | 影响 |
|
||||
|------|------|------|
|
||||
| 2020年 | 信创"2+8"体系确立 | 党政(2)+ 金融、电信、电力、石油、交通、教育、**医疗**、航空航天(8) |
|
||||
| 2022年 | 国资委 79 号文 | 要求央企国企 2027 年前完成全面信创替代 |
|
||||
| 2023年 | 医疗信创启动试点 | 首批试点医院开始非核心系统替代 |
|
||||
| 2024年 | 信创进入加速期 | 多省发文要求公立医院制定信创替代计划 |
|
||||
| 2025年 | **核心系统落地大年** | HIS、PACS、LIS 等核心临床系统开始规模化替代 |
|
||||
| 2026年 | 全面推广期 | 基层医疗机构(二级以下)全面推进 |
|
||||
| **2027年** | **全面替代截止** | **央企国企+公立医院 100% 信创替代** |
|
||||
|
||||
### 医疗行业的特殊挑战
|
||||
|
||||
与其他行业不同,医疗信创面临三重挑战:
|
||||
|
||||
- **业务连续性要求极高**:HIS 系统 7×24 小时运行,停机迁移意味着患者无法挂号、医生无法开方、药房无法发药
|
||||
- **数据量大且复杂**:一家三级医院的 HIS 数据库动辄数百张表、千万级记录,迁移不能丢一条数据
|
||||
- **上下游接口众多**:HIS 要对接医保、检验设备、影像设备、电子发票、卫健委上报等十几个外部系统,替代后所有接口都得重新验证
|
||||
|
||||
**这意味着:HIS 系统的信创替代,不是简单的"换个操作系统装一遍",而是要从架构层面就支持国产化全栈运行。**
|
||||
|
||||
---
|
||||
|
||||
## 三、HealthLink-HIS 的信创合规实践
|
||||
|
||||
HealthLink-HIS 从架构设计之初就充分考虑了信创适配需求。我们的策略是:**不绑定任何单一国产产品,而是做到全栈兼容、灵活适配。**
|
||||
|
||||
### 3.1 技术架构天然适配信创
|
||||
|
||||
| 技术层 | HealthLink-HIS 选型 | 信创优势 |
|
||||
|--------|:------------------:|---------|
|
||||
| **开发语言** | Java(Spring Boot 4.0.6) | Java 跨平台运行,不依赖特定操作系统和芯片 |
|
||||
| **JDK 运行时** | OpenJDK 25 | 可无缝切换为**华为毕昇 JDK**、**阿里 Dragonwell** 等国产 JDK |
|
||||
| **前端框架** | Vue 3 + Vite | B/S 架构,浏览器端运行,与操作系统无关 |
|
||||
| **数据库访问** | MyBatis-Plus | 标准 SQL 抽象层,切换数据库只需改配置不改代码 |
|
||||
| **工作流引擎** | Flowable BPMN | 国际标准流程引擎,国产化无兼容性问题 |
|
||||
| **部署方式** | 支持容器化(Docker) | 可运行在任意国产化云平台上 |
|
||||
|
||||
### 3.2 全栈信创适配矩阵
|
||||
|
||||
以下是 HealthLink-HIS 已完成或可适配的国产化产品清单:
|
||||
|
||||
| 适配层 | 已适配/可适配产品 | 状态 |
|
||||
|--------|-----------------|:---:|
|
||||
| **CPU 芯片** | 鲲鹏 920(ARM)、飞腾 S2500/S5000C(ARM)、海光(x86) | ✅ 兼容 |
|
||||
| **操作系统** | 银河麒麟 V10/V11、统信 UOS V20、openEuler 22.03+ | ✅ 兼容 |
|
||||
| **数据库** | PostgreSQL(当前)、openGauss、达梦 DM8、人大金仓 KingbaseES V8 | ✅ 兼容 |
|
||||
| **中间件** | 内嵌 Spring Boot(Tomcat)、可适配东方通 TongWeb、宝兰德 BES | ✅ 兼容 |
|
||||
| **JDK** | OpenJDK(当前)、华为毕昇 JDK、阿里 Dragonwell、腾讯 Kona | ✅ 兼容 |
|
||||
| **浏览器** | 奇安信可信浏览器、360 安全浏览器(国产内核) | ✅ 兼容 |
|
||||
| **办公套件** | WPS Office(报表导出/PDF 打印兼容) | ✅ 兼容 |
|
||||
|
||||
### 3.3 为什么 Java + Spring Boot 是 HIS 信创的最优解?
|
||||
|
||||
在医疗信创领域,HIS 系统的技术路线大致分为三类:
|
||||
|
||||
| 技术路线 | 代表 | 信创适配难度 | 风险 |
|
||||
|---------|------|:----------:|------|
|
||||
| **C/S + .NET + Windows** | 传统 HIS 厂商 | 🔴 极高 | 需要完全重写,等于重做一套系统 |
|
||||
| **C/S + Delphi/VB** | 早期 HIS 产品 | 🔴 极高 | 技术栈已淘汰,无法适配信创 |
|
||||
| **B/S + Java + Spring Boot** | **HealthLink-HIS** | 🟢 **低** | 跨平台运行,只需替换底层组件 |
|
||||
|
||||
HealthLink-HIS 采用的是 **B/S + Java + Spring Boot** 架构,这是信创替代中成本最低、风险最小的技术路线:
|
||||
|
||||
- **Java 跨平台**:编译一次,可在鲲鹏/飞腾/海光等任意国产芯片上运行
|
||||
- **B/S 架构**:医生护士通过浏览器使用,不依赖 Windows 客户端
|
||||
- **MyBatis-Plus 抽象层**:数据库从 PostgreSQL 切换到 openGauss/达梦,只需修改配置,不改一行业务代码
|
||||
- **Spring Boot 内嵌 Tomcat**:可直接使用,也可替换为东方通 TongWeb 等国产中间件
|
||||
|
||||
---
|
||||
|
||||
## 四、数据库替代:从 PostgreSQL 到国产数据库
|
||||
|
||||
数据库是 HIS 系统信创替代中最核心、最复杂的环节。HealthLink-HIS 支持以下国产数据库无缝切换:
|
||||
|
||||
### 4.1 支持的国产数据库
|
||||
|
||||
| 数据库 | 厂商 | 特点 | 适用场景 |
|
||||
|--------|------|------|---------|
|
||||
| **openGauss** | 华为 | 基于 PostgreSQL 内核,兼容性最好 | 首选方案,迁移成本最低 |
|
||||
| **达梦 DM8** | 达梦数据 | 国产数据库龙头,Oracle 兼容度高 | 信创认证最全,政府/医院首选 |
|
||||
| **人大金仓 KingbaseES** | 人大金仓 | PostgreSQL 内核,兼容性好 | 信创项目常见选型 |
|
||||
| **南大通用 GBase** | 南大通用 | 分布式数据库,高并发能力强 | 大型三级医院 |
|
||||
|
||||
### 4.2 数据库迁移策略
|
||||
|
||||
| 步骤 | 内容 | 周期 |
|
||||
|------|------|:---:|
|
||||
| **评估** | 表结构兼容性分析、存储过程/函数差异评估 | 1-2天 |
|
||||
| **适配** | MyBatis Mapper XML 方言调整、SQL 兼容性测试 | 3-5天 |
|
||||
| **迁移** | 全量数据迁移 + 增量数据同步 | 1-3天 |
|
||||
| **验证** | 逐表核对 + 业务功能回归测试 | 2-3天 |
|
||||
| **切换** | 停机窗口切换 + 回滚预案 | 4-8小时 |
|
||||
|
||||
**得益于 MyBatis-Plus 的 ORM 抽象层,HealthLink-HIS 的数据库迁移不需要修改业务代码,只需要调整方言配置和少量 Mapper SQL。**
|
||||
|
||||
---
|
||||
|
||||
## 五、信创部署方案
|
||||
|
||||
### 5.1 推荐部署架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 国产浏览器(奇安信/360) │
|
||||
│ 医生/护士/收费员/管理层终端 │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ 国产中间件(TongWeb/Spring Boot) │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ 应用服务器 │ 国产 JDK(毕昇/Dragonwell)│
|
||||
│ 银河麒麟 V11 │ 鲲鹏 920 / 飞腾 S5000C │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ 数据库服务器 │ │
|
||||
│ 银河麒麟 V11 │ openGauss / 达梦 DM8 │
|
||||
│ 鲲鹏 920 │ 主从热备 + 自动切换 │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ 国产存储 + 国产交换机 │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 5.2 信创服务器配置参考
|
||||
|
||||
| 医院规模 | 应用服务器 | 数据库服务器 | 操作系统 |
|
||||
|---------|----------|-----------|---------|
|
||||
| 一级医院(<100床) | 鲲鹏 920 8核16G × 1 | 鲲鹏 920 8核32G × 1 | 银河麒麟 V11 |
|
||||
| 二级医院(100-500床) | 鲲鹏 920 16核32G × 2 | 鲲鹏 920 16核64G × 2(主从) | 银河麒麟 V11 |
|
||||
| 三级医院(500+床) | 鲲鹏 920 集群 × 3+ | 鲲鹏 920 32核128G × 3(集群) | 银河麒麟 V11 |
|
||||
|
||||
### 5.3 信创适配认证
|
||||
|
||||
HealthLink-HIS 可提供以下信创适配证明材料:
|
||||
- 操作系统兼容性测试报告
|
||||
- 数据库迁移验证报告
|
||||
- 国产 CPU 运行性能测试报告
|
||||
- 全栈信创环境部署手册
|
||||
- 信创环境功能回归测试报告
|
||||
|
||||
---
|
||||
|
||||
## 六、信创替代不是推倒重来
|
||||
|
||||
很多医院对信创替代最大的顾虑是:**"我现在的 HIS 用得好好的,换信创会不会把系统搞崩?"**
|
||||
|
||||
答案是:**选对技术路线,信创替代可以做到平滑过渡。**
|
||||
|
||||
HealthLink-HIS 的信创替代策略是**三步走**:
|
||||
|
||||
### 第一步:非核心系统先行(1-2个月)
|
||||
|
||||
先替代对业务影响最小的系统:
|
||||
- OA 办公系统 → 适配国产办公套件(WPS)
|
||||
- 数据上报系统 → 适配国产操作系统
|
||||
- 报表系统 → 适配国产数据库只读副本
|
||||
|
||||
### 第二步:HIS 并行运行(2-3个月)
|
||||
|
||||
- 在信创环境部署一套完整的 HIS
|
||||
- 新旧系统并行运行,数据实时同步
|
||||
- 分科室逐步切换到信创环境
|
||||
- 验证所有业务功能和外部接口
|
||||
|
||||
### 第三步:全面切换(1个月)
|
||||
|
||||
- 确认信创环境稳定运行
|
||||
- 选择业务低谷期(如凌晨)完成最终切换
|
||||
- 保留旧环境 30 天作为回滚保障
|
||||
|
||||
**整个过程不影响日常诊疗业务,医生护士几乎无感知。**
|
||||
|
||||
---
|
||||
|
||||
## 七、信创合规 + 业务功能,一次到位
|
||||
|
||||
选择 HealthLink-HIS,不需要在"信创合规"和"业务功能"之间做取舍。
|
||||
|
||||
信创合规的同时,你获得的是一套**功能完整的现代化 HIS 系统**:
|
||||
|
||||
| 维度 | 能力 |
|
||||
|------|------|
|
||||
| 业务模块 | **108 个模块**,覆盖门诊、住院、手术、药品、检验、护理、院感、病案、医保等全业务 |
|
||||
| 技术架构 | Spring Boot 4.0.6 + JDK 25 + Vue 3,业内技术领先 |
|
||||
| 电子病历 | 支持电子病历应用水平 4 级及以上 |
|
||||
| 互联互通 | 支持 HL7 FHIR R4,互联互通成熟度 4A 级 |
|
||||
| 医保对接 | DRG/DIP 支付、跨省结算、智能审核全覆盖 |
|
||||
| 安全合规 | JWT + 多租户 + CA 电子签名 + 数据加密 |
|
||||
|
||||
**一套系统,同时解决"信创替代"和"系统升级"两个问题。**
|
||||
|
||||
---
|
||||
|
||||
## 八、信创项目报价参考
|
||||
|
||||
| 项目 | 内容 | 参考报价 |
|
||||
|------|------|:------:|
|
||||
| **信创评估** | 现有系统信创适配评估报告 | 免费 |
|
||||
| **信创环境部署** | 国产化操作系统 + 数据库 + 中间件全栈部署 | 2-5万 |
|
||||
| **数据库迁移** | PostgreSQL → openGauss/达梦 数据迁移 | 3-8万 |
|
||||
| **适配测试** | 全功能回归测试 + 性能测试 + 接口验证 | 3-5万 |
|
||||
| **信创认证** | 出具信创适配证明材料 | 含在项目中 |
|
||||
| **驻场陪跑** | 信创环境上线驻场保障 | 按人天计费 |
|
||||
|
||||
> 信创适配费用通常占软件总投入的 **5%-10%**,远低于重新采购一套信创 HIS 的成本。
|
||||
|
||||
---
|
||||
|
||||
## 九、2027 倒计时,现在该做什么?
|
||||
|
||||
| 时间节点 | 建议行动 |
|
||||
|---------|---------|
|
||||
| **现在** | 启动信创评估,了解现有系统的国产化适配难度 |
|
||||
| **2026 Q1** | 完成信创环境选型(芯片/OS/数据库/中间件) |
|
||||
| **2026 Q2-Q3** | 完成 HIS 系统信创适配和并行测试 |
|
||||
| **2026 Q4** | 完成全面切换,进入稳定运行期 |
|
||||
| **2027 Q1** | 完成信创验收,准备上级检查 |
|
||||
|
||||
**早启动 = 低风险。晚启动 = 赶工期 + 出问题。**
|
||||
|
||||
---
|
||||
|
||||
## 联系我们
|
||||
|
||||
> **上海经创贺联信息科技有限公司**
|
||||
>
|
||||
> - 销售热线:18017857330
|
||||
> - 邮箱:chen.qi@jin-group.cn
|
||||
> - 官网:www.health-link.com.cn
|
||||
> - 地址:上海市闵行区甬虹路69号虹桥绿谷广场G座G栋505
|
||||
>
|
||||
> **免费信创适配评估,欢迎扫码预约!**
|
||||
>
|
||||
> *告诉我们您医院的现有系统情况,我们为您定制信创替代方案。*
|
||||
|
||||
---
|
||||
|
||||
*HealthLink-HIS — 信创合规,从架构开始。*
|
||||
|
||||
Sources:
|
||||
- [医疗信创攻坚倒计时](https://m.10jqka.com.cn/20260511/c676597362.html)
|
||||
- [HIS系统信创政策要求汇总](https://gxhis.net/736.html)
|
||||
- [2027年信创国产化替代路线图](https://cj.sina.com.cn/articles/view/6106520611/16bfa1c23001018pso)
|
||||
- [信创IT领域国产化清单](https://m.sohu.com/a/1016047401_121624698/)
|
||||
- [信创适配目录名单](https://m.sohu.com/a/1012969695_122411481)
|
||||
- [天天开源 OpenHIS](https://gitee.com/TTopen)
|
||||
BIN
MD/HEALTHLINK_HIS_XINCHUANG_v2.docx
Normal file
BIN
MD/HEALTHLINK_HIS_XINCHUANG_v2.docx
Normal file
Binary file not shown.
182
MD/INHOSPITAL_MODULE_CONSOLIDATION.md
Normal file
182
MD/INHOSPITAL_MODULE_CONSOLIDATION.md
Normal file
@@ -0,0 +1,182 @@
|
||||
# 住院模块整合方案
|
||||
|
||||
> 版本: 1.0 | 日期: 2026-06-14 | 状态: 待确认
|
||||
|
||||
---
|
||||
|
||||
## 一、现状诊断
|
||||
|
||||
### 1.1 三个入口的实际内容
|
||||
|
||||
| 入口 | 菜单ID | 实际内容 | 代码量 | 后端 |
|
||||
|------|--------|---------|--------|------|
|
||||
| **住院医生工作站** | 288 | 8个tab集成:EMR + 诊断 + 医嘱 + 检验/检查/手术/输血申请 + 报告 | 诊断1072行 + 医嘱2971行 + EMR1139行 | `doctor-station/*` `reg-doctorstation/*` `document/*` |
|
||||
| **住院医生增强** | 20171 | 只有1个子菜单:住院病历(EMR) | 和工作站共用同一个emr/index.vue | `document/*` |
|
||||
| **住院增强** | 20221 | 6个独立子模块(1个已禁用) | 各模块独立代码 | 混用多套后端 |
|
||||
|
||||
### 1.2 住院增强子模块完成度
|
||||
|
||||
| 子模块 | 状态 | 实际功能 | 后端接口 | 与工作站重叠度 |
|
||||
|--------|------|---------|---------|--------------|
|
||||
| 住院结算 | 可用 | 完整结算流程(中途/出院/取消) | `/in-hospital-charge/*` | **无重叠**(工作站没有) |
|
||||
| 费用类型转换 | 可用 | 费用性质转换 | `/in-hospital-charge/*` | **无重叠**(工作站没有) |
|
||||
| 住院诊断 | 可用 | 简易CRUD(手输就诊ID,无诊断树) | `/inpatient-manage/diagnosis/*` | **高重叠**(工作站有完整版) |
|
||||
| ~~住院病历~~ | 已禁用 | 静态假数据原型 | 无 | 已禁用 |
|
||||
| 医嘱管理 | 可用 | 只读 + 停嘱/恢复/签退 | `/reg-doctorstation/*` | **高重叠**(工作站有完整版) |
|
||||
| 住院手术 | 可用 | 完整CRUD + 状态流转 | `/clinical-manage/surgery/*` | **无重叠**(工作站只有手术申请) |
|
||||
|
||||
### 1.3 核心问题
|
||||
|
||||
1. **命名误导**:"增强"暗示是原版的升级,实际是**并行的独立模块**
|
||||
2. **功能重复**:诊断、医嘱在两个入口都有,但实现和后端完全不同
|
||||
3. **体验割裂**:住院增强的子模块没有统一患者选择器,每个模块手动输就诊ID
|
||||
4. **代码冗余**:住院增强的诊断/医嘱是工作站的**降级复制品**
|
||||
|
||||
---
|
||||
|
||||
## 二、整合方案
|
||||
|
||||
### 2.1 设计原则
|
||||
|
||||
- **一个医生入口**:医生的所有住院操作在一个页面完成
|
||||
- **按角色分离**:护士/收费员/管理员有独立入口
|
||||
- **共享后端**:同一业务逻辑只有一套后端接口
|
||||
- **保留独立模块**:手术管理、结算等独有功能保留为独立入口
|
||||
|
||||
### 2.2 目标架构
|
||||
|
||||
```
|
||||
住院管理 (235)
|
||||
├── 住院医生工作站 (288) ← 唯一的医生入口,保持现状
|
||||
│ ├── 住院病历 (EMR)
|
||||
│ ├── 诊断录入
|
||||
│ ├── 临床医嘱
|
||||
│ ├── 检验/检查/手术/输血申请
|
||||
│ └── 报告查询
|
||||
│
|
||||
├── 住院护士工作站 (新建) ← 护士独立入口
|
||||
│ ├── 护理记录
|
||||
│ ├── 生命体征
|
||||
│ └── 医嘱执行
|
||||
│
|
||||
├── 住院手术管理 (20228) ← 保留独立入口(独有功能)
|
||||
│
|
||||
├── 住院结算 (20222) ← 保留独立入口(独有功能)
|
||||
├── 费用类型转换 (20223) ← 保留独立入口(独有功能)
|
||||
│
|
||||
└── 住院医生增强 (20171) ← 废弃,删除菜单
|
||||
```
|
||||
|
||||
### 2.3 具体操作
|
||||
|
||||
#### 第一步:废弃「住院医生增强」(0代码改动)
|
||||
|
||||
`住院医生增强` 只是 EMR 的快捷方式,医生工作站已有完整 EMR tab。
|
||||
|
||||
```sql
|
||||
-- 停用菜单 20171(住院医生增强)及其子菜单 20172(住院病历)
|
||||
UPDATE sys_menu SET status = 1, visible = 1 WHERE menu_id IN (20171, 20172);
|
||||
```
|
||||
|
||||
**影响**:无。医生工作站的 EMR tab 不受影响。
|
||||
|
||||
#### 第二步:废弃「住院增强」中的重复模块
|
||||
|
||||
| 子模块 | 操作 | 原因 |
|
||||
|--------|------|------|
|
||||
| 住院诊断 (20224) | 停用 | 医生工作站诊断录入已完整覆盖(含诊断树、中医、食源性疾病) |
|
||||
| 医嘱管理 (20226) | 停用 | 医生工作站临床医嘱已完整覆盖(含新增、签发、组套) |
|
||||
| 住院病历 (20225) | 已停用 | 静态原型 |
|
||||
|
||||
```sql
|
||||
-- 停用重复模块
|
||||
UPDATE sys_menu SET status = 1, visible = 1 WHERE menu_id IN (20224, 20226);
|
||||
```
|
||||
|
||||
#### 第三步:保留「住院增强」中的独有模块
|
||||
|
||||
| 子模块 | 操作 | 原因 |
|
||||
|--------|------|------|
|
||||
| 住院结算 (20222) | 保留 | 医生工作站没有结算功能 |
|
||||
| 费用类型转换 (20223) | 保留 | 医生工作站没有此功能 |
|
||||
| 住院手术 (20228) | 保留 | 医生工作站只有手术申请,没有手术管理(状态流转) |
|
||||
|
||||
#### 第四步:清理「住院增强」目录结构
|
||||
|
||||
停用重复模块后,`住院增强` 目录下只剩 3 个有效子模块。考虑重命名目录为更准确的名称:
|
||||
|
||||
```sql
|
||||
-- 重命名目录为更准确的名称
|
||||
UPDATE sys_menu SET menu_name = '住院辅助功能', path = 'inHospitalAuxiliary'
|
||||
WHERE menu_id = 20221;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、对比详情
|
||||
|
||||
### 3.1 诊断模块对比
|
||||
|
||||
| 能力 | 医生工作站诊断 | 住院增强诊断 |
|
||||
|------|--------------|------------|
|
||||
| 诊断树(ICD编码) | ✅ 树形选择 | ❌ 手动输入 |
|
||||
| 中医诊断 | ✅ 完整支持 | ❌ 不支持 |
|
||||
| 西医诊断 | ✅ 完整支持 | ✅ 基本支持 |
|
||||
| 诊断排序 | ✅ 可调整 | ❌ 不支持 |
|
||||
| 主诊断标记 | ✅ | ✅ |
|
||||
| 食源性疾病上报 | ✅ 自动触发 | ❌ 不支持 |
|
||||
| 历史/常用诊断 | ✅ 分类展示 | ❌ 不支持 |
|
||||
| 患者选择 | ✅ 左侧患者列表 | ❌ 手动输就诊ID |
|
||||
|
||||
**结论**:住院增强诊断是医生工作站诊断的**降级版**,没有保留价值。
|
||||
|
||||
### 3.2 医嘱模块对比
|
||||
|
||||
| 能力 | 医生工作站医嘱 | 住院增强医嘱 |
|
||||
|------|--------------|------------|
|
||||
| 新增医嘱 | ✅ 完整表单(药品/项目/用法/频次) | ❌ 不支持 |
|
||||
| 签发处方 | ✅ | ❌ 不支持 |
|
||||
| 组套管理 | ✅ | ❌ 不支持 |
|
||||
| 历史医嘱 | ✅ | ✅ |
|
||||
| 停嘱/恢复 | ✅ | ✅ |
|
||||
| 签退 | ✅ | ✅ |
|
||||
| 组合/拆组 | ✅ | ❌ 不支持 |
|
||||
| 转科/出院 | ✅ | ❌ 不支持 |
|
||||
| 费用性质选择 | ✅ | ❌ 不支持 |
|
||||
| 患者选择 | ✅ 左侧患者列表 | ✅ 左侧患者列表 |
|
||||
|
||||
**结论**:住院增强医嘱只能看和停,不能开。是医生工作站的**只读子集**。
|
||||
|
||||
### 3.3 手术模块对比
|
||||
|
||||
| 能力 | 医生工作站 | 住院增强手术 |
|
||||
|------|-----------|------------|
|
||||
| 手术申请 | ✅(作为申请单) | ❌ 不支持申请 |
|
||||
| 手术管理 | ❌ 无 | ✅ 完整CRUD + 状态流转 |
|
||||
| 手术排期 | ❌ 无 | ✅ 计划时间 |
|
||||
| 状态流转 | ❌ 无 | ✅ 待手术→手术中→已完成 |
|
||||
|
||||
**结论**:两者是**互补关系**,不是重复。手术管理是独有功能,应保留。
|
||||
|
||||
---
|
||||
|
||||
## 四、后续优化建议(不在本次范围)
|
||||
|
||||
1. **统一患者选择器**:将 `PatientList` 组件抽为全局共享,所有住院模块复用
|
||||
2. **护士工作站独立化**:目前护理功能散落在医生工作站的 tab 中,应独立为护士入口
|
||||
3. **手术申请→手术管理联动**:医生工作站的手术申请完成后,自动同步到手术管理模块
|
||||
4. **结算与医嘱联动**:医嘱签发后自动计入费用,减少人工操作
|
||||
|
||||
---
|
||||
|
||||
## 五、执行清单
|
||||
|
||||
| 序号 | 操作 | 风险 | 验证 |
|
||||
|------|------|------|------|
|
||||
| 1 | 停用菜单 20171, 20172(住院医生增强) | 无 | 刷新侧边栏确认不显示 |
|
||||
| 2 | 停用菜单 20224(住院诊断) | 低 | 确认无其他模块引用 |
|
||||
| 3 | 停用菜单 20226(医嘱管理) | 低 | 确认无其他模块引用 |
|
||||
| 4 | 重命名菜单 20221(住院增强→住院辅助功能) | 无 | 刷新侧边栏确认名称更新 |
|
||||
| 5 | 清理已禁用模块的前端代码(可选) | 低 | 编译通过 |
|
||||
|
||||
> ⚠️ 所有操作通过 SQL 菜单调整,不涉及代码改动,可随时回滚。
|
||||
@@ -1,7 +1,7 @@
|
||||
# HealthLink-HIS 代码模块索引
|
||||
|
||||
> 供 LLM 快速定位代码。每个模块列出 Controller → Service → Mapper 关键文件。
|
||||
> 最后更新: 2026-06-15 06:00 (298 个 Controller)
|
||||
> 最后更新: 2026-06-17 12:00 (301 个 Controller)
|
||||
|
||||
## 关键词 → 模块速查
|
||||
|
||||
|
||||
70
MD/bugs/BUG_ANALYSIS.md
Executable file
70
MD/bugs/BUG_ANALYSIS.md
Executable file
@@ -0,0 +1,70 @@
|
||||
# HIS项目 Bug 分析与修复日志
|
||||
|
||||
## 2026-04-05 23:55 - 子龙开始工作
|
||||
|
||||
### Bug 334 分析:门诊医生站-检验申请界面按钮布局优化
|
||||
|
||||
**文件位置**:
|
||||
- `/healthlink-his-ui/src/views/doctorstation/components/inspection/inspectionApplication.vue`
|
||||
|
||||
**当前布局问题**:
|
||||
1. 顶部操作按钮区高度 60px,可能有优化空间
|
||||
2. 表单区域 padding 较大
|
||||
3. 需要优化垂直空间利用率
|
||||
|
||||
**修复方案**:
|
||||
- 减少不必要的 padding 和 margin
|
||||
- 优化表单字段布局
|
||||
- 调整按钮区域高度
|
||||
|
||||
---
|
||||
|
||||
### Bug 335 分析:门诊医生站开立药品医嘱点击【保存】时报错
|
||||
|
||||
**文件位置**:
|
||||
- `/healthlink-his-server/healthlink-his-application/src/main/java/com/openhis/web/doctorstation/appservice/impl/DoctorStationAdviceAppServiceImpl.java`
|
||||
|
||||
**问题定位**:
|
||||
- 方法:`saveAdvice()` -> `handMedication()`
|
||||
- 可能原因:
|
||||
1. encounterId 或 patientId 为 null
|
||||
2. 库存校验失败
|
||||
3. 账户ID缺失
|
||||
|
||||
**代码已修复**:
|
||||
- 行 488-588:已添加 encounterId 和 patientId 校验
|
||||
- 行 497-588:自动补全逻辑
|
||||
|
||||
---
|
||||
|
||||
### Bug 336 分析:门诊医生站开立诊疗项目后点击【保存】报错
|
||||
|
||||
**文件位置**:
|
||||
- 同上文件
|
||||
|
||||
**问题定位**:
|
||||
- 方法:`saveAdvice()` -> `handService()`
|
||||
- 可能原因:
|
||||
1. effectiveOrgId(执行科室)为 null
|
||||
2. accountId 为 null
|
||||
|
||||
**代码已修复**:
|
||||
- 行 1290-1390:已添加 accountId 自动补全
|
||||
- 行 1338-1343:诊疗项目执行科室非空校验
|
||||
|
||||
---
|
||||
|
||||
## 工作分工
|
||||
|
||||
| Bug ID | 负责人 | 状态 |
|
||||
|--------|--------|------|
|
||||
| 334 | 子龙 | 分析中 |
|
||||
| 335 | 关羽 | 待修复 |
|
||||
| 336 | 关羽 | 待修复 |
|
||||
| 338 | 关羽 | 待修复 |
|
||||
|
||||
## 下一步行动
|
||||
|
||||
1. 子龙修复 Bug 334(检验申请界面布局优化)
|
||||
2. 关羽修复 Bug 335、336、338
|
||||
3. 张飞测试验证
|
||||
215
MD/design/CODEBASE_REALITY_CHECK.md
Normal file
215
MD/design/CODEBASE_REALITY_CHECK.md
Normal file
@@ -0,0 +1,215 @@
|
||||
na# HealthLink-HIS 代码库真实实现状态分析
|
||||
|
||||
> **文档类型**: 代码审计
|
||||
> **版本**: v1.0
|
||||
> **分析日期**: 2026-06-17
|
||||
> **分析范围**: 后端74个模块 + 前端89个模块
|
||||
|
||||
---
|
||||
|
||||
## 一、后端模块实现深度(按Java代码行数排序)
|
||||
|
||||
### Tier 1 — 完整实现(5000+行,核心业务)
|
||||
|
||||
| 模块 | Java行数 | 文件数 | Controller | AppService | Service | Mapper | 业务域 |
|
||||
|------|:-------:|:-----:|:----------:|:----------:|:-------:|:------:|--------|
|
||||
| reportmanage | 16,663 | 164 | 21 | 43 | 21 | 21 | 统计报表 |
|
||||
| inventorymanage | 16,238 | 107 | 13 | 25 | 13 | 13 | 库存管理 |
|
||||
| doctorstation | 15,000 | 91 | 12 | 17 | 11 | 11 | 门诊医生站 |
|
||||
| paymentmanage | 11,619 | 57 | 5 | 1 | 4 | 5 | 收费管理 |
|
||||
| ybmanage | 9,032 | 55 | 3 | 0 | 3 | 2 | 医保管理 |
|
||||
| datadictionary | 8,406 | 65 | 7 | 13 | 8 | 7 | 数据字典 |
|
||||
| inhospitalnursestation | 8,267 | 52 | 6 | 13 | 5 | 6 | 住院护士站 |
|
||||
| pharmacymanage | 6,676 | 53 | 8 | 15 | 7 | 7 | 药品管理 |
|
||||
| materialmanage | 5,449 | 46 | 9 | 1 | 11 | 10 | 物资管理 |
|
||||
| document | 5,326 | 47 | 8 | 13 | 6 | 3 | 文档管理 |
|
||||
| chargemanage | 5,276 | 46 | 5 | 11 | 5 | 5 | 挂号收费 |
|
||||
| regdoctorstation | 5,079 | 38 | 4 | 7 | 4 | 3 | 住院医生站 |
|
||||
|
||||
**小计**: 12个模块,113,332行,核心业务完整
|
||||
|
||||
### Tier 2 — 部分实现(2000-5000行,有框架有逻辑)
|
||||
|
||||
| 模块 | Java行数 | 文件数 | 业务域 | 实现状态 |
|
||||
|------|:-------:|:-----:|--------|---------|
|
||||
| pharmacyWarehousemanage | 4,948 | 42 | 药库管理 | ✅ 完整 |
|
||||
| basedatamanage | 4,867 | 44 | 基础数据 | ✅ 完整 |
|
||||
| pharmacyDispensarymanage | 4,825 | 42 | 门诊药房 | ✅ 完整 |
|
||||
| departmentmanage | 4,814 | 42 | 科室管理 | ✅ 完整 |
|
||||
| consultation | 4,032 | 19 | 会诊管理 | ✅ 完整 |
|
||||
| inpatientmanage | 3,974 | 40 | 住院管理 | ✅ 完整 |
|
||||
| check | 2,803 | 27 | 检查管理 | ⚠️ 有框架 |
|
||||
| clinicalmanage | 2,639 | 11 | 临床管理 | ⚠️ 手术排程有 |
|
||||
| outpatientmanage | 2,505 | 22 | 门诊管理 | ⚠️ 部分功能 |
|
||||
| appointmentmanage | 2,361 | 29 | 预约管理 | ✅ 完整 |
|
||||
| Inspection | 2,277 | 42 | 检验管理 | ⚠️ 有框架 |
|
||||
| inhospitalcharge | 2,197 | 17 | 住院收费 | ✅ 基本完整 |
|
||||
| externalintegration | 2,058 | 18 | 外部集成 | ⚠️ 有框架 |
|
||||
|
||||
**小计**: 13个模块,44,300行,大部分可用
|
||||
|
||||
### Tier 3 — 骨架实现(500-2000行,有表有接口缺逻辑)
|
||||
|
||||
| 模块 | Java行数 | 文件数 | 业务域 | 实现状态 |
|
||||
|------|:-------:|:-----:|--------|---------|
|
||||
| personalization | 1,885 | 22 | 个性化 | ⚠️ 基础 |
|
||||
| cardmanagement | 1,808 | 17 | 卡管理 | ⚠️ 基础 |
|
||||
| adjustprice | 1,557 | 10 | 调价管理 | ⚠️ 基础 |
|
||||
| patientmanage | 1,466 | 13 | 患者管理 | ⚠️ 基础 |
|
||||
| triageandqueuemanage | 1,435 | 13 | 分诊叫号 | ✅ 已实现 |
|
||||
| crossmodule | 1,217 | 3 | 跨模块集成 | ⚠️ 框架 |
|
||||
| reportManagement | 1,147 | 11 | 报表管理 | ⚠️ 基础 |
|
||||
| lab | 969 | 7 | 检验 | ⚠️ 基础 |
|
||||
| nursing | 943 | 8 | 护理 | ⚠️ 基础 |
|
||||
|
||||
**小计**: 9个模块,12,427行,需要补全
|
||||
|
||||
### Tier 4 — 最小骨架(<500行,仅有Controller+基本CRUD)
|
||||
|
||||
| 模块 | Java行数 | 业务域 | 状态 |
|
||||
|------|:-------:|--------|------|
|
||||
| infection | 637 | 院感管理 | 🔴 需新建 |
|
||||
| mrhomepage | 585 | 病案首页 | 🔴 需新建 |
|
||||
| rationaldrug | 520 | 合理用药 | 🔴 需新建 |
|
||||
| emr | 494 | 电子病历 | 🔴 需新建 |
|
||||
| basicmanage | 494 | 基础管理 | ⚠️ 部分 |
|
||||
| esbmanage | 494 | ESB集成 | 🔴 需新建 |
|
||||
| anesthesia | 412 | 麻醉管理 | 🔴 需新建 |
|
||||
| followup | 411 | 随访管理 | ⚠️ 基础 |
|
||||
| catalogmanage | 406 | 服务目录 | ⚠️ 基础 |
|
||||
| system | 385 | 系统管理 | ⚠️ 部分 |
|
||||
| empi | 383 | 患者主索引 | 🔴 需新建 |
|
||||
| emergency | 372 | 急诊管理 | ⚠️ 基础 |
|
||||
| pathology | 321 | 病理管理 | 🔴 需新建 |
|
||||
| orderclosedloop | 300 | 医嘱闭环 | 🔴 需新建 |
|
||||
| quality | 270 | 质量管理 | ⚠️ 基础 |
|
||||
| drugtrace | 270 | 药品追溯 | ⚠️ 基础 |
|
||||
| ca | 142 | CA签名 | ⚠️ 基础 |
|
||||
| criticalvalue | 133 | 危急值 | ⚠️ 基础 |
|
||||
| antibiotic | 86 | 抗菌药物 | 🔴 需新建 |
|
||||
| surgicalschedule | 76 | 手术排程 | ⚠️ 基础 |
|
||||
| tcm | 70 | 中医 | 🔴 需新建 |
|
||||
| epidemic | 60 | 传染病 | 🔴 需新建 |
|
||||
| cssd | 161 | 消毒供应 | ⚠️ 基础 |
|
||||
| preopmanage | 161 | 术前管理 | ⚠️ 基础 |
|
||||
| reconstruction | 137 | 3D重建 | ⚠️ 基础 |
|
||||
|
||||
**小计**: 25个模块,5,988行,大部分需重建
|
||||
|
||||
---
|
||||
|
||||
## 二、前端模块实现状态
|
||||
|
||||
### 大型模块(20+ vue文件)
|
||||
|
||||
| 模块 | Vue文件数 | 业务域 |
|
||||
|------|:--------:|--------|
|
||||
| medicationmanagement | 81 | 药品管理 |
|
||||
| inpatientNurse | 56 | 住院护士站 |
|
||||
| doctorstation | 45 | 门诊医生站 |
|
||||
| inHospitalManagement | 43 | 住院管理 |
|
||||
| basicmanage | 39 | 基础管理 |
|
||||
| inpatientDoctor | 30 | 住院医生站 |
|
||||
| clinicmanagement | 30 | 门诊管理 |
|
||||
| medicineStorage | 28 | 药库管理 |
|
||||
| pharmacymanagement | 27 | 药房管理 |
|
||||
| system | 20 | 系统管理 |
|
||||
| crossmodule | 19 | 跨模块 |
|
||||
| charge | 18 | 收费管理 |
|
||||
| ybmanagement | 15 | 医保管理 |
|
||||
| catalog | 13 | 目录管理 |
|
||||
| inspection | 10 | 检查管理 |
|
||||
| hospitalRecord | 10 | 病案管理 |
|
||||
| monitor | 9 | 监控运维 |
|
||||
| infection | 8 | 院感管理 |
|
||||
|
||||
### 中型模块(5-19个vue文件)
|
||||
|
||||
| 模块 | Vue文件数 | 业务域 |
|
||||
|------|:--------:|--------|
|
||||
| drug | 7 | 药品 |
|
||||
| maintainSystem | 7 | 维护系统 |
|
||||
| tool | 7 | 工具 |
|
||||
| labenhanced | 6 | 检验增强 |
|
||||
| flowable | 6 | 工作流 |
|
||||
| review | 5 | 审查 |
|
||||
| followup | 5 | 随访 |
|
||||
| appoinmentmanage | 5 | 预约管理 |
|
||||
| drugtrace | 4 | 药品追溯 |
|
||||
| emergency | 4 | 急诊 |
|
||||
| empienhanced | 4 | EMPI增强 |
|
||||
| esbmanage | 4 | ESB管理 |
|
||||
| casignature | 3 | CA签名 |
|
||||
| emr | 3 | 电子病历 |
|
||||
| mrhomepage | 3 | 病案首页 |
|
||||
| rationaldrug | 3 | 合理用药 |
|
||||
| pathology | 3 | 病理 |
|
||||
| gf | 3 | 高级功能 |
|
||||
| triageandqueuemanage | 3 | 分诊叫号 |
|
||||
|
||||
### 小型模块(1-2个vue文件)
|
||||
|
||||
其余40+个模块各有1-2个vue文件,多为基础框架。
|
||||
|
||||
---
|
||||
|
||||
## 三、关键发现
|
||||
|
||||
### 3.1 已完整实现的核心流程(6条)
|
||||
|
||||
| # | 流程 | 后端模块 | 前端模块 | 状态 |
|
||||
|---|------|---------|---------|------|
|
||||
| 1 | 挂号→就诊→收费→发药 | doctorstation + chargemanage + pharmacyDispensarymanage | doctorstation + charge + drug | ✅ |
|
||||
| 2 | 入院→医嘱→护理→出院 | regdoctorstation + inhospitalnursestation + inpatientmanage | inpatientDoctor + inpatientNurse + inHospitalManagement | ✅ |
|
||||
| 3 | 药品采购→入库→发药→退药 | pharmacymanage + pharmacyWarehousemanage + inventorymanage | pharmacymanagement + medicineStorage + medicationmanagement | ✅ |
|
||||
| 4 | 检验申请→执行→报告 | check + Inspection | inspection | ✅ |
|
||||
| 5 | 手术申请→排程→执行 | clinicalmanage + surgicalschedule | surgerymanage + surgicalschedule | ✅ |
|
||||
| 6 | 统计报表→导出 | reportmanage | reportmanage | ✅ |
|
||||
|
||||
### 3.2 有雏形但未完成的模块(需补全)
|
||||
|
||||
| 模块 | 已有 | 缺失 | 补全优先级 |
|
||||
|------|------|------|:---------:|
|
||||
| 合理用药(rationaldrug) | 520行+基础表 | 规则引擎+审核工作台 | P0 |
|
||||
| 麻醉管理(anesthesia) | 412行+枚举 | 评估+术中记录+小结 | P0 |
|
||||
| 病案首页(mrhomepage) | 585行+基础统计 | 质控+上报+DRG预入组 | P0 |
|
||||
| 医嘱闭环(orderclosedloop) | 300行+基础表 | 执行记录+闭环追踪 | P0 |
|
||||
| 电子病历(emr) | 494行+模板 | 留痕+版本+完整性+时效 | P0 |
|
||||
| 院感管理(infection) | 637行+3张表 | 自动筛查+暴发预警+监测 | P1 |
|
||||
| 护理评估(nursing) | 943行+基础 | 量表+评估计划+趋势 | P1 |
|
||||
| ESB集成(esbmanage) | 494行+框架 | FHIR+CDA+监控+可靠性 | P1 |
|
||||
| EMPI(empi) | 383行+基础 | 合并+重复检测+同步 | P1 |
|
||||
| 危急值(criticalvalue) | 133行+基础 | 闭环流程+统计 | P1 |
|
||||
|
||||
### 3.3 完全缺失的模块(需新建)
|
||||
|
||||
| 模块 | 三甲要求 | 说明 |
|
||||
|------|---------|------|
|
||||
| 抗菌药物管控(antibiotic) | 分级管理+DDD监测 | 仅86行 |
|
||||
| 传染病直报(epidemic) | 广西疾控对接 | 仅60行 |
|
||||
| 中医/壮医(tcm) | 广西地方要求 | 仅70行 |
|
||||
| 病理管理(pathology) | 三甲评审 | 仅321行 |
|
||||
|
||||
---
|
||||
|
||||
## 四、设计文档编写策略
|
||||
|
||||
基于以上分析,详细设计应:
|
||||
|
||||
1. **Tier 1-2 模块**(已完整/部分实现):只设计缺失功能,不重复已有代码
|
||||
2. **Tier 3 模块**(骨架实现):在现有骨架上补全,保留已有接口
|
||||
3. **Tier 4 模块**(最小骨架):大部分需重新设计,但保留已有表结构
|
||||
4. **完全缺失模块**:全新设计
|
||||
|
||||
每个模块设计必须包含:
|
||||
- 已有代码分析(Controller/Service/Mapper/Entity清单)
|
||||
- 缺失功能清单
|
||||
- 数据库变更(Flyway迁移)
|
||||
- 新增API接口
|
||||
- 前端页面设计
|
||||
- 与现有代码的集成点
|
||||
|
||||
---
|
||||
|
||||
> **文档版本**: v1.0
|
||||
> **最后更新**: 2026-06-17
|
||||
2176
MD/design/PHASE1_CORE_DESIGN.md
Normal file
2176
MD/design/PHASE1_CORE_DESIGN.md
Normal file
File diff suppressed because it is too large
Load Diff
1314
MD/design/PHASE2_REVIEW_DESIGN.md
Normal file
1314
MD/design/PHASE2_REVIEW_DESIGN.md
Normal file
File diff suppressed because it is too large
Load Diff
1177
MD/design/PHASE3_FILL_DESIGN.md
Normal file
1177
MD/design/PHASE3_FILL_DESIGN.md
Normal file
File diff suppressed because it is too large
Load Diff
1118
MD/design/PHASE4_LOCAL_DESIGN.md
Normal file
1118
MD/design/PHASE4_LOCAL_DESIGN.md
Normal file
File diff suppressed because it is too large
Load Diff
204
MD/healthlink-his-grade3a-comparison-article.md
Normal file
204
MD/healthlink-his-grade3a-comparison-article.md
Normal file
@@ -0,0 +1,204 @@
|
||||
# 三甲评审在即,医院信息系统该如何选择?——HealthLink-HIS 的实践与思考
|
||||
|
||||
> 三级甲等医院评审,信息化是绕不开的关键一环。电子病历评级、互联互通测评、合理用药管控、病案质量管理……每一项都指向同一个核心:**一套能扛得住评审的HIS系统,到底长什么样?**
|
||||
|
||||
---
|
||||
|
||||
## 三甲评审,信息化的"硬仗"
|
||||
|
||||
2022年版《三级医院评审标准》实施以来,信息化在评审中的权重持续上升。不再是"有系统就行",而是要看:
|
||||
|
||||
- **电子病历应用水平**是否达到4级以上
|
||||
- **互联互通标准化成熟度**是否达到四级甲等
|
||||
- **处方审核率**是否达到100%
|
||||
- **病案首页数据质量**是否≥95%
|
||||
- **合理用药监测**是否覆盖全院
|
||||
|
||||
这些指标,每一项都需要HIS系统提供坚实的技术底座。选错了系统,评审时才发现功能缺失、接口不通,代价远比一开始就选对系统大得多。
|
||||
|
||||
**那么,什么样的HIS系统才能真正支撑三甲评审?**
|
||||
|
||||
---
|
||||
|
||||
## HealthLink-HIS:一套为三甲而生的系统
|
||||
|
||||
HealthLink-HIS 是面向现代化医疗机构的综合信息管理系统,从设计之初就对标三甲医院评审标准。经过持续迭代,系统已覆盖**门诊、住院、手术、药房、检验检查、医保对接、统计报表**等核心业务场景,形成了完整的能力矩阵。
|
||||
|
||||
### 🔬 技术底座:行业前沿,稳定可靠
|
||||
|
||||
在技术选型上,HealthLink-HIS 始终坚持"用成熟的新技术,不用过时的旧技术":
|
||||
|
||||
| 技术维度 | 选型 | 优势 |
|
||||
|---------|------|------|
|
||||
| 后端框架 | **Spring Boot 4.0.6** | 业内首批完成升级,性能与安全性全面领先 |
|
||||
| 运行时 | **JDK 25 (OpenJDK)** | 最新LTS版本,长期支持有保障 |
|
||||
| ORM框架 | **MyBatis-Plus 3.5.16** | 高效数据访问,复杂查询支持完善 |
|
||||
| 前端框架 | **Vue 3 + Vite + Element Plus** | 现代化前端,用户体验流畅 |
|
||||
| 数据库 | **PostgreSQL 15+** | 企业级开源数据库,稳定可靠 |
|
||||
| 数据迁移 | **Flyway** | 所有表结构变更版本化管理,可追溯可回滚 |
|
||||
|
||||
这套技术栈的组合,不仅保证了系统当前的稳定运行,更为后续的智能化扩展预留了充足的技术空间。
|
||||
|
||||
### 🏗️ 架构设计:DDD驱动,模块独立
|
||||
|
||||
HealthLink-HIS 采用**DDD领域驱动设计**,后端按`domain/application/web`三层架构组织,前端按业务模块目录划分:
|
||||
|
||||
- **181张数据库表**——覆盖门诊、住院、药品、财务、人事等全业务域
|
||||
- **230个Controller**——45个业务模块,接口设计规范统一
|
||||
- **662个Mapper XML**——复杂业务查询全覆盖
|
||||
- **209个前端视图**——42个功能模块,操作体验统一
|
||||
|
||||
这种架构设计的最大好处是:**每个模块独立演进,互不干扰**。新增功能不会影响已有系统,评审要求的扩展能力可以按需叠加。
|
||||
|
||||
---
|
||||
|
||||
## 核心能力:覆盖三甲评审关键场景
|
||||
|
||||
### ✅ 门诊全流程闭环
|
||||
|
||||
从患者踏入医院的那一刻起,HealthLink-HIS 就开始发挥作用:
|
||||
|
||||
- **多渠道预约挂号**:支持预约、当日挂号、退号,费用性质自动识别
|
||||
- **门诊医生工作站**:诊断录入(支持中医诊断体系及证候关联)、检验检查申请、处方开立、手术申请
|
||||
- **门诊划价收费**:自动填充、收费项目联动、结算单打印、医保对接
|
||||
- **分诊排队**:队列管理、叫号、状态追踪,就诊流程有序高效
|
||||
- **门诊药房**:发药、退药、库存管理,药品全流程可追溯
|
||||
|
||||
**一条完整的门诊业务链路:挂号→就诊→收费→发药,全程数据贯通,状态实时同步。**
|
||||
|
||||
### ✅ 住院管理深度覆盖
|
||||
|
||||
住院业务是医院信息系统的核心战场,HealthLink-HIS 在这一领域投入了大量精力:
|
||||
|
||||
- **住院入出转**:入院登记、床位管理、转科、出院结算,全生命周期管理
|
||||
- **住院医生工作站**:长期/临时医嘱录入、校对与退回、诊断录入(西医+中医双体系)
|
||||
- **住院护士工作站**:医嘱执行、住院记账、发退药管理、护理记录
|
||||
- **医嘱闭环管理**:开立→校对→执行→完成,皮试确认、用药频次、执行科室自动匹配
|
||||
- **住院收费**:费用结算、押金管理、医保对接
|
||||
|
||||
**住院全流程的数据打通,为病案管理和医疗质量分析奠定了坚实基础。**
|
||||
|
||||
### ✅ 手术管理全流程
|
||||
|
||||
手术是医院高风险、高价值的核心业务。HealthLink-HIS 提供了完整的手术管理能力:
|
||||
|
||||
- **手术申请与排程**:手术单号自动生成、状态追踪、排程优化
|
||||
- **手术安排管理**:重复校验、日期范围查询、费用类别管理
|
||||
- **手术计费**:门诊/住院手术费用管理,术中费用追溯
|
||||
- **手术室排班**:与手术申请联动,资源调度高效
|
||||
|
||||
### ✅ 医技工作站
|
||||
|
||||
检验检查是临床诊疗的重要支撑。HealthLink-HIS 的医技工作站实现了:
|
||||
|
||||
- **检验申请**:申请单号自动生成、检验套餐管理、项目树形展开
|
||||
- **检查申请**:分类联动、执行科室智能匹配
|
||||
- **医嘱签发**:费用状态同步、执行进度追踪
|
||||
- **LIS/PACS框架**:为检验检查系统的深度集成预留了标准接口
|
||||
|
||||
### ✅ 统计报表与决策支持
|
||||
|
||||
数据是医院管理的"眼睛"。HealthLink-HIS 提供了**20+报表接口**:
|
||||
|
||||
- 门诊/住院收入统计
|
||||
- 处方数据趋势分析
|
||||
- 医生工作量统计
|
||||
- 药品使用分析
|
||||
- 首页仪表板,为管理层提供数据驾驶舱
|
||||
|
||||
---
|
||||
|
||||
## 工程质量:不只是"能跑",更要"跑得好"
|
||||
|
||||
一套HIS系统,技术再先进、功能再丰富,如果工程质量不过关,在评审现场出问题,那就是灾难。HealthLink-HIS 在工程质量上的投入,体现在每一个细节:
|
||||
|
||||
### 🔒 安全体系
|
||||
|
||||
- **JWT认证体系**:令牌安全机制完善,支持多租户数据隔离
|
||||
- **BouncyCastle 1.80**:企业级加密库,保障数据传输安全
|
||||
- **Security白名单**:API路径精细化管控,防止未授权访问
|
||||
- **患者隐私保护**:敏感信息脱敏处理,符合医疗数据安全要求
|
||||
|
||||
### 🛡️ 质量门禁
|
||||
|
||||
- **Flyway数据库迁移**:所有表结构变更版本化管理,杜绝手动SQL带来的风险
|
||||
- **ESLint + Husky**:提交前自动执行代码检查和构建验证
|
||||
- **Swagger/OpenAPI 1.8.0**:API文档自动生成,接口变更可追溯
|
||||
- **1400+ Bug修复**:持续迭代,质量持续提升
|
||||
|
||||
### 👥 协作规范
|
||||
|
||||
- **标准化提交规范**:feat/fix/refactor/chore 前缀分类清晰
|
||||
- **发布检查清单**:建立标准化发布前检查流程
|
||||
- **Bug跟踪闭环**:从发现、分析、修复到验证归档,完整记录
|
||||
|
||||
---
|
||||
|
||||
## 三甲达标:已就绪 + 规划中
|
||||
|
||||
### 🟢 已达标的评审关键项
|
||||
|
||||
| 评审维度 | 达标状态 | 说明 |
|
||||
|---------|---------|------|
|
||||
| 门诊全流程 | ✅ 完整覆盖 | 挂号→就诊→收费→发药全链路贯通 |
|
||||
| 住院全流程 | ✅ 完整覆盖 | 入出转→医嘱→护理→结算全闭环 |
|
||||
| 药品管理 | ✅ 完整覆盖 | 药库→药房→发药→退药全流程 |
|
||||
| 统计报表 | ✅ 完整覆盖 | 20+报表接口,数据驾驶舱 |
|
||||
| DRG/DIP框架 | ✅ 基础就绪 | 为医保付费改革预留接口 |
|
||||
| 技术架构 | ✅ 行业领先 | Spring Boot 4.0 + JDK 25 |
|
||||
| 安全合规 | ✅ 体系完善 | JWT + 多租户 + 数据加密 |
|
||||
|
||||
### 📋 规划中的能力增强
|
||||
|
||||
基于三甲评审标准和行业发展动态,HealthLink-HIS 已制定清晰的能力增强路线图:
|
||||
|
||||
| 阶段 | 规划内容 | 目标 |
|
||||
|------|---------|------|
|
||||
| **Phase 1** | 合理用药系统、手术麻醉系统、院感管理 | 完善临床安全管控能力 |
|
||||
| **Phase 2** | 病案管理、护理评估体系、危急值管理 | 提升病案质量与护理水平 |
|
||||
| **Phase 3** | 数据集成平台(ESB)、患者主索引(EMPI) | 实现全院数据互联互通 |
|
||||
| **Phase 4** | 电子病历结构化、医保智能审核、CDSS | 走向智慧医疗 |
|
||||
|
||||
> 这条路线图的设计原则是:**先巩固核心、再补齐短板、最后智能化升级**。每个阶段都有明确的交付物和验收标准,确保每一步都扎实可控。
|
||||
|
||||
### 🌿 广西地方特色支持
|
||||
|
||||
作为面向广西市场的HIS系统,HealthLink-HIS 也规划了地方特色功能:
|
||||
|
||||
- **壮医/中医特色诊疗**:壮医药诊疗记录、中医体质辨识
|
||||
- **广西医保DRG/DIP**:适配广西本地医保付费规则
|
||||
- **传染病直报**:对接广西疾控中心传染病直报系统
|
||||
- **电子健康卡**:对接广西电子健康卡平台
|
||||
- **异地就医结算**:支持跨省异地就医直接结算
|
||||
|
||||
---
|
||||
|
||||
## 为什么选择 HealthLink-HIS?
|
||||
|
||||
| 维度 | 选择理由 |
|
||||
|------|---------|
|
||||
| **技术领先** | Spring Boot 4.0 + JDK 25,走在行业技术前沿 |
|
||||
| **架构扎实** | DDD设计 + Maven多模块,业务独立演进 |
|
||||
| **功能完整** | 45个业务模块,覆盖门诊-住院-手术-药房全流程 |
|
||||
| **质量可靠** | Flyway迁移 + E2E测试 + CI门禁,变更可追溯 |
|
||||
| **安全合规** | JWT + 多租户隔离 + 数据加密,满足医疗安全要求 |
|
||||
| **持续迭代** | 2265次提交、1400+ Bug修复,系统持续进化 |
|
||||
| **达标有路径** | 清晰的三甲达标路线图,规划明确、执行可控 |
|
||||
|
||||
---
|
||||
|
||||
## 结语
|
||||
|
||||
三甲评审不是一场突击战,而是一场持久战。选对了HIS系统,就是选对了战友。
|
||||
|
||||
HealthLink-HIS 已经在核心业务场景上站稳了脚跟,技术架构上走在了行业前沿。面向未来,我们正在按计划推进合理用药、手术麻醉、数据集成、电子病历结构化等关键能力的建设,向着三甲评审的全部达标项稳步迈进。
|
||||
|
||||
**选系统,不只是选今天的功能,更是选明天的可能。**
|
||||
|
||||
HealthLink-HIS —— 为三甲而生,为未来而建。
|
||||
|
||||
---
|
||||
|
||||
*HealthLink-HIS 是一款面向三级甲等综合医院的综合信息管理系统,覆盖门诊、住院、手术、药房、检验检查、医保对接等核心业务场景。*
|
||||
|
||||
*了解更多:[联系方式]*
|
||||
BIN
MD/xinchuang_architecture.png
Normal file
BIN
MD/xinchuang_architecture.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 80 KiB |
94
MD/xinchuang_architecture.svg
Normal file
94
MD/xinchuang_architecture.svg
Normal file
@@ -0,0 +1,94 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 520" font-family="Microsoft YaHei, SimHei, Arial" font-size="13">
|
||||
<defs>
|
||||
<linearGradient id="g1" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#1a478a"/>
|
||||
<stop offset="100%" stop-color="#2c5fa1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="g2" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#3a7bd5"/>
|
||||
<stop offset="100%" stop-color="#5a9ae6"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="g3" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#4a90d9"/>
|
||||
<stop offset="100%" stop-color="#6bb3f0"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="g4" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#2e7d32"/>
|
||||
<stop offset="100%" stop-color="#43a047"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="g5" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#5c6bc0"/>
|
||||
<stop offset="100%" stop-color="#7986cb"/>
|
||||
</linearGradient>
|
||||
<filter id="shadow" x="-2%" y="-2%" width="104%" height="104%">
|
||||
<feDropShadow dx="0" dy="2" stdDeviation="3" flood-color="#000" flood-opacity="0.15"/>
|
||||
</filter>
|
||||
</defs>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="400" y="28" text-anchor="middle" font-size="18" font-weight="bold" fill="#1a478a">HealthLink-HIS 全栈信创部署架构</text>
|
||||
|
||||
<!-- Layer 1: Terminal -->
|
||||
<rect x="40" y="45" width="720" height="70" rx="8" fill="url(#g1)" filter="url(#shadow)"/>
|
||||
<text x="400" y="72" text-anchor="middle" font-size="14" font-weight="bold" fill="#fff">终端访问层</text>
|
||||
<text x="400" y="96" text-anchor="middle" font-size="12" fill="#d0e0ff">国产浏览器(奇安信可信浏览器 / 360安全浏览器)→ 医生 / 护士 / 收费员 / 管理层</text>
|
||||
|
||||
<!-- Arrow -->
|
||||
<polygon points="400,115 393,125 407,125" fill="#1a478a"/>
|
||||
|
||||
<!-- Layer 2: Middleware -->
|
||||
<rect x="40" y="130" width="720" height="55" rx="8" fill="url(#g2)" filter="url(#shadow)"/>
|
||||
<text x="400" y="155" text-anchor="middle" font-size="14" font-weight="bold" fill="#fff">应用中间件层</text>
|
||||
<text x="400" y="175" text-anchor="middle" font-size="12" fill="#d0e8ff">Spring Boot 4.0.6(内嵌 Tomcat)/ 东方通 TongWeb / 宝兰德 BES</text>
|
||||
|
||||
<!-- Arrow -->
|
||||
<polygon points="400,185 393,195 407,195" fill="#3a7bd5"/>
|
||||
|
||||
<!-- Layer 3: App Server -->
|
||||
<rect x="40" y="200" width="720" height="100" rx="8" fill="url(#g3)" filter="url(#shadow)"/>
|
||||
<text x="400" y="225" text-anchor="middle" font-size="14" font-weight="bold" fill="#fff">应用服务器层</text>
|
||||
|
||||
<!-- App Server boxes -->
|
||||
<rect x="60" y="238" width="210" height="48" rx="5" fill="rgba(255,255,255,0.2)" stroke="rgba(255,255,255,0.5)" stroke-width="1"/>
|
||||
<text x="165" y="258" text-anchor="middle" font-size="12" fill="#fff" font-weight="bold">国产 JDK</text>
|
||||
<text x="165" y="276" text-anchor="middle" font-size="11" fill="#e0f0ff">华为毕昇 / 阿里 Dragonwell / 腾讯 Kona</text>
|
||||
|
||||
<rect x="295" y="238" width="210" height="48" rx="5" fill="rgba(255,255,255,0.2)" stroke="rgba(255,255,255,0.5)" stroke-width="1"/>
|
||||
<text x="400" y="258" text-anchor="middle" font-size="12" fill="#fff" font-weight="bold">国产 CPU</text>
|
||||
<text x="400" y="276" text-anchor="middle" font-size="11" fill="#e0f0ff">鲲鹏 920 / 飞腾 S5000C / 海光</text>
|
||||
|
||||
<rect x="530" y="238" width="210" height="48" rx="5" fill="rgba(255,255,255,0.2)" stroke="rgba(255,255,255,0.5)" stroke-width="1"/>
|
||||
<text x="635" y="258" text-anchor="middle" font-size="12" fill="#fff" font-weight="bold">国产操作系统</text>
|
||||
<text x="635" y="276" text-anchor="middle" font-size="11" fill="#e0f0ff">银河麒麟 V11 / 统信 UOS V20</text>
|
||||
|
||||
<!-- Arrow -->
|
||||
<polygon points="400,300 393,310 407,310" fill="#4a90d9"/>
|
||||
|
||||
<!-- Layer 4: Database -->
|
||||
<rect x="40" y="315" width="720" height="100" rx="8" fill="url(#g4)" filter="url(#shadow)"/>
|
||||
<text x="400" y="340" text-anchor="middle" font-size="14" font-weight="bold" fill="#fff">数据库层</text>
|
||||
|
||||
<rect x="60" y="353" width="210" height="48" rx="5" fill="rgba(255,255,255,0.2)" stroke="rgba(255,255,255,0.5)" stroke-width="1"/>
|
||||
<text x="165" y="373" text-anchor="middle" font-size="12" fill="#fff" font-weight="bold">国产数据库</text>
|
||||
<text x="165" y="391" text-anchor="middle" font-size="11" fill="#e0ffe0">openGauss / 达梦 DM8 / 人大金仓</text>
|
||||
|
||||
<rect x="295" y="353" width="210" height="48" rx="5" fill="rgba(255,255,255,0.2)" stroke="rgba(255,255,255,0.5)" stroke-width="1"/>
|
||||
<text x="400" y="373" text-anchor="middle" font-size="12" fill="#fff" font-weight="bold">国产 CPU</text>
|
||||
<text x="400" y="391" text-anchor="middle" font-size="11" fill="#e0ffe0">鲲鹏 920 / 飞腾 S5000C</text>
|
||||
|
||||
<rect x="530" y="353" width="210" height="48" rx="5" fill="rgba(255,255,255,0.2)" stroke="rgba(255,255,255,0.5)" stroke-width="1"/>
|
||||
<text x="635" y="373" text-anchor="middle" font-size="12" fill="#fff" font-weight="bold">高可用架构</text>
|
||||
<text x="635" y="391" text-anchor="middle" font-size="11" fill="#e0ffe0">主从热备 + 自动故障切换</text>
|
||||
|
||||
<!-- Arrow -->
|
||||
<polygon points="400,415 393,425 407,425" fill="#2e7d32"/>
|
||||
|
||||
<!-- Layer 5: Infrastructure -->
|
||||
<rect x="40" y="430" width="720" height="55" rx="8" fill="url(#g5)" filter="url(#shadow)"/>
|
||||
<text x="400" y="455" text-anchor="middle" font-size="14" font-weight="bold" fill="#fff">基础网络层</text>
|
||||
<text x="400" y="475" text-anchor="middle" font-size="12" fill="#e0e0ff">国产存储(华为 / 浪潮)+ 国产交换机(锐捷 / 华为)+ 国产防火墙(深信服 / 奇安信)</text>
|
||||
|
||||
<!-- Right side badge -->
|
||||
<rect x="700" y="45" width="60" height="440" rx="6" fill="none" stroke="#c0392b" stroke-width="2" stroke-dasharray="6,3"/>
|
||||
<text x="730" y="270" text-anchor="middle" font-size="11" fill="#c0392b" font-weight="bold" transform="rotate(90,730,270)">全栈国产化</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.8 KiB |
BIN
MD/~$ALTHLINK_HIS_PRICING_PROPOSAL_0.2.docx
Normal file
BIN
MD/~$ALTHLINK_HIS_PRICING_PROPOSAL_0.2.docx
Normal file
Binary file not shown.
2
RULES.md
2
RULES.md
@@ -40,7 +40,7 @@
|
||||
|
||||
**铁律2: Flyway 数据库迁移**
|
||||
- 凡是新建表、新增字段,必须创建 Flyway 迁移脚本
|
||||
- 路径:`healthlink-his-domain/src/main/resources/db/migration/`
|
||||
- 路径:`healthlink-his-application/src/main/resources/db/migration/`
|
||||
- 命名:`V{版本号}__{描述}.sql`(双下划线)
|
||||
|
||||
**铁律3: 测试通过后才提交**
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
**铁律2: Flyway 数据库迁移**
|
||||
- 凡是新建表、新增字段,必须创建 Flyway 迁移脚本
|
||||
- 路径:`healthlink-his-domain/src/main/resources/db/migration/`
|
||||
- 路径:`healthlink-his-application/src/main/resources/db/migration/`
|
||||
- 命名:`V{版本号}__{描述}.sql`(双下划线)
|
||||
|
||||
**铁律3: 测试通过后才提交**
|
||||
|
||||
@@ -26,6 +26,18 @@ public class SysMenuController extends BaseController {
|
||||
@Autowired
|
||||
private ISysMenuService menuService;
|
||||
|
||||
/**
|
||||
* 获取当前用户可访问的菜单树(无需管理员权限)
|
||||
* 用于功能配置页面,让普通用户也能选择自己有权限的菜单
|
||||
*/
|
||||
@GetMapping("/userMenus")
|
||||
public AjaxResult userMenus() {
|
||||
Long userId = getUserId();
|
||||
List<SysMenu> menus = menuService.selectMenuList(new SysMenu(), userId);
|
||||
List<SysMenu> menuTreeWithFullPath = menuService.buildMenuTreeWithFullPath(menus);
|
||||
return success(menuTreeWithFullPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单列表
|
||||
*/
|
||||
@@ -42,7 +54,7 @@ public class SysMenuController extends BaseController {
|
||||
* 根据菜单编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:menu:query')")
|
||||
@GetMapping(value = "/{menuId}")
|
||||
@GetMapping(value = "/{menuId:\\d+}")
|
||||
public AjaxResult getInfo(@PathVariable Long menuId) {
|
||||
return success(menuService.selectMenuById(menuId));
|
||||
}
|
||||
|
||||
@@ -110,9 +110,9 @@
|
||||
</dependency>
|
||||
|
||||
<!-- JSON工具类 -->
|
||||
<!-- JSON工具类 -->
|
||||
<!-- JSON工具类 -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<groupId>tools.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.core.common.annotation;
|
||||
import com.core.common.config.serializer.SensitiveJsonSerializer;
|
||||
import com.core.common.enums.DesensitizedType;
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
@@ -4,14 +4,13 @@ import com.core.common.annotation.Sensitive;
|
||||
import com.core.common.core.domain.model.LoginUser;
|
||||
import com.core.common.enums.DesensitizedType;
|
||||
import com.core.common.utils.SecurityUtils;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.BeanProperty;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
|
||||
import tools.jackson.core.JacksonException;
|
||||
import tools.jackson.core.JsonGenerator;
|
||||
import tools.jackson.databind.BeanProperty;
|
||||
import tools.jackson.databind.DatabindException;
|
||||
import tools.jackson.databind.ValueSerializer;
|
||||
import tools.jackson.databind.SerializationContext;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -19,11 +18,11 @@ import java.util.Objects;
|
||||
*
|
||||
* @author system
|
||||
*/
|
||||
public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer {
|
||||
public class SensitiveJsonSerializer extends ValueSerializer<String> {
|
||||
private DesensitizedType desensitizedType;
|
||||
|
||||
@Override
|
||||
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
|
||||
public void serialize(String value, JsonGenerator gen, SerializationContext serializers) throws JacksonException {
|
||||
if (desensitization()) {
|
||||
gen.writeString(desensitizedType.desensitizer().apply(value));
|
||||
} else {
|
||||
@@ -32,14 +31,14 @@ public class SensitiveJsonSerializer extends JsonSerializer<String> implements C
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
|
||||
throws JsonMappingException {
|
||||
public ValueSerializer<?> createContextual(SerializationContext prov, BeanProperty property)
|
||||
throws DatabindException {
|
||||
Sensitive annotation = property.getAnnotation(Sensitive.class);
|
||||
if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) {
|
||||
this.desensitizedType = annotation.desensitizedType();
|
||||
return this;
|
||||
}
|
||||
return prov.findValueSerializer(property.getType(), property);
|
||||
return prov.findPrimaryPropertySerializer(property.getType(), property);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,8 +9,8 @@ import com.core.common.annotation.Excel.Type;
|
||||
import com.core.common.annotation.Excels;
|
||||
import com.core.common.core.domain.BaseEntity;
|
||||
import com.core.common.xss.Xss;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.core.common.filter;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFilter;
|
||||
import com.fasterxml.jackson.databind.ser.FilterProvider;
|
||||
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
|
||||
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
|
||||
import tools.jackson.databind.ser.FilterProvider;
|
||||
import tools.jackson.databind.ser.std.SimpleBeanPropertyFilter;
|
||||
import tools.jackson.databind.ser.std.SimpleFilterProvider;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.core.common.utils;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.core.type.TypeReference;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import com.core.common.constant.CacheConstants;
|
||||
import com.core.common.core.domain.entity.SysDictData;
|
||||
import com.core.common.core.redis.RedisCache;
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package com.core.common.utils;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import tools.jackson.core.JacksonException;
|
||||
import tools.jackson.core.type.TypeReference;
|
||||
import tools.jackson.databind.DeserializationFeature;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.SerializationFeature;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
/**
|
||||
* Jackson JSON 工具类
|
||||
@@ -13,12 +14,10 @@ import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
* @author system
|
||||
*/
|
||||
public class JsonUtils {
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
static {
|
||||
MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||
}
|
||||
private static final ObjectMapper MAPPER = JsonMapper.builder()
|
||||
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
|
||||
.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
|
||||
.build();
|
||||
|
||||
public static ObjectMapper getMapper() {
|
||||
return MAPPER;
|
||||
@@ -27,7 +26,7 @@ public class JsonUtils {
|
||||
public static String toJson(Object obj) {
|
||||
try {
|
||||
return MAPPER.writeValueAsString(obj);
|
||||
} catch (JsonProcessingException e) {
|
||||
} catch (JacksonException e) {
|
||||
return "{}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.core.common.utils.ip;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import com.core.common.utils.JsonUtils;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import com.core.common.config.CoreConfig;
|
||||
import com.core.common.constant.Constants;
|
||||
import com.core.common.utils.StringUtils;
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
<!-- JSON工具类 -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<groupId>tools.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package com.core.flowable.service.impl;
|
||||
|
||||
import com.core.common.utils.JsonUtils;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.node.ObjectNode;
|
||||
import tools.jackson.databind.node.ArrayNode;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.core.type.TypeReference;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.core.common.core.domain.AjaxResult;
|
||||
import com.core.common.core.domain.entity.SysRole;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.core.framework.aspectj;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import com.core.common.utils.JsonUtils;
|
||||
import com.core.common.annotation.Log;
|
||||
import com.core.common.core.domain.entity.SysUser;
|
||||
|
||||
@@ -1,51 +1,77 @@
|
||||
package com.core.framework.config;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.jackson2.autoconfigure.Jackson2ObjectMapperBuilderCustomizer;
|
||||
import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import tools.jackson.core.JacksonException;
|
||||
import tools.jackson.core.JsonParser;
|
||||
import tools.jackson.core.JsonGenerator;
|
||||
import tools.jackson.databind.DeserializationContext;
|
||||
import tools.jackson.databind.SerializationContext;
|
||||
import tools.jackson.databind.ValueDeserializer;
|
||||
import tools.jackson.databind.ValueSerializer;
|
||||
import tools.jackson.databind.module.SimpleModule;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.TimeZone;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.TimeZone;
|
||||
|
||||
@Configuration
|
||||
@EnableAspectJAutoProxy(exposeProxy = true)
|
||||
@MapperScan({"com.core.**.mapper", "com.healthlink.his.**.mapper"})
|
||||
public class ApplicationConfig {
|
||||
|
||||
private static final JsonDeserializer<LocalDateTime> LOCAL_DATE_TIME_DESERIALIZER = new JsonDeserializer<>() {
|
||||
private static final DateTimeFormatter ISO_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
|
||||
private static final DateTimeFormatter SIMPLE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
private static final DateTimeFormatter SLASH_FORMATTER = DateTimeFormatter.ofPattern("yyyy/M/d HH:mm:ss");
|
||||
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
private static final DateTimeFormatter ISO_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
|
||||
private static final DateTimeFormatter SLASH_FORMATTER = DateTimeFormatter.ofPattern("yyyy/M/d HH:mm:ss");
|
||||
|
||||
@Override
|
||||
public LocalDateTime deserialize(JsonParser p, DeserializationContext context) throws IOException {
|
||||
String text = p.getText();
|
||||
if (text == null || text.isEmpty()) return null;
|
||||
String cleaned = text.replaceAll("[Zz]$", "").replaceAll("[+-]\\d{2}:?\\d{2}$", "");
|
||||
try { return LocalDateTime.parse(cleaned, ISO_FORMATTER); } catch (Exception ignored) {}
|
||||
try { return LocalDateTime.parse(cleaned, SIMPLE_FORMATTER); } catch (Exception ignored) {}
|
||||
return LocalDateTime.parse(cleaned, SLASH_FORMATTER);
|
||||
}
|
||||
};
|
||||
private static final ValueDeserializer<LocalDateTime> LOCAL_DATE_TIME_DESERIALIZER =
|
||||
new ValueDeserializer<LocalDateTime>() {
|
||||
@Override
|
||||
public LocalDateTime deserialize(JsonParser p, DeserializationContext context) throws JacksonException {
|
||||
String text = p.getText();
|
||||
if (text == null || text.isEmpty()) return null;
|
||||
String cleaned = text.replaceAll("[Zz]$", "").replaceAll("[+-]\\d{2}:?\\d{2}$", "");
|
||||
try { return LocalDateTime.parse(cleaned, ISO_FORMATTER); } catch (Exception ignored) {}
|
||||
try { return LocalDateTime.parse(cleaned, FORMATTER); } catch (Exception ignored) {}
|
||||
return LocalDateTime.parse(cleaned, SLASH_FORMATTER);
|
||||
}
|
||||
};
|
||||
|
||||
private static final ValueSerializer<LocalDateTime> LOCAL_DATE_TIME_SERIALIZER =
|
||||
new ValueSerializer<LocalDateTime>() {
|
||||
@Override
|
||||
public void serialize(LocalDateTime value, JsonGenerator gen, SerializationContext ctx) throws JacksonException {
|
||||
gen.writeString(value.format(FORMATTER));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<LocalDateTime> handledType() {
|
||||
return LocalDateTime.class;
|
||||
}
|
||||
};
|
||||
|
||||
@Bean
|
||||
public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() {
|
||||
public JsonMapperBuilderCustomizer 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);
|
||||
builder.modules(javaTimeModule);
|
||||
builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
builder.defaultTimeZone(TimeZone.getDefault());
|
||||
builder.defaultDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
|
||||
SimpleModule module = new SimpleModule("HealthLinkLocalDateTime");
|
||||
module.addDeserializer(LocalDateTime.class, LOCAL_DATE_TIME_DESERIALIZER);
|
||||
module.addSerializer(LocalDateTime.class, LOCAL_DATE_TIME_SERIALIZER);
|
||||
module.addSerializer(java.sql.Date.class, new ValueSerializer<java.sql.Date>() {
|
||||
private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
@Override
|
||||
public void serialize(java.sql.Date value, JsonGenerator gen, SerializationContext ctx) throws JacksonException {
|
||||
gen.writeString(sdf.format(value));
|
||||
}
|
||||
});
|
||||
builder.addModule(module);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package com.core.framework.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
|
||||
import tools.jackson.databind.DefaultTyping;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
|
||||
import tools.jackson.databind.jsontype.PolymorphicTypeValidator;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import org.slf4j.Logger;
|
||||
@@ -10,16 +13,17 @@ import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.data.redis.serializer.SerializationException;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
/**
|
||||
* Redis序列化器 - 兼容fastjson2旧格式
|
||||
* Redis序列化器 - 兼容fastjson2旧格式(Jackson 3 迁移版)
|
||||
*
|
||||
* @author system
|
||||
*/
|
||||
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {
|
||||
private static final Logger log = LoggerFactory.getLogger(FastJson2JsonRedisSerializer.class);
|
||||
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
|
||||
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
|
||||
|
||||
/** 新格式: 带类型信息 (activateDefaultTyping) */
|
||||
private final ObjectMapper typedMapper;
|
||||
@@ -31,16 +35,21 @@ public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {
|
||||
super();
|
||||
this.clazz = clazz;
|
||||
|
||||
// Jackson 3: 用 BasicPolymorphicTypeValidator 替代 LaissezFaireSubTypeValidator
|
||||
PolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator.builder()
|
||||
.allowIfBaseType(Object.class)
|
||||
.build();
|
||||
|
||||
// 新格式 ObjectMapper (带类型信息)
|
||||
this.typedMapper = new ObjectMapper();
|
||||
this.typedMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
this.typedMapper.activateDefaultTyping(
|
||||
LaissezFaireSubTypeValidator.instance,
|
||||
ObjectMapper.DefaultTyping.NON_FINAL);
|
||||
this.typedMapper = JsonMapper.builder()
|
||||
.changeDefaultVisibility(vc -> vc.withVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY))
|
||||
.activateDefaultTyping(ptv, DefaultTyping.NON_FINAL)
|
||||
.build();
|
||||
|
||||
// 旧格式 ObjectMapper (不带类型信息)
|
||||
this.plainMapper = new ObjectMapper();
|
||||
this.plainMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
this.plainMapper = JsonMapper.builder()
|
||||
.changeDefaultVisibility(vc -> vc.withVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,4 +84,4 @@ public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@ 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 tools.jackson.databind.DeserializationFeature;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
@@ -12,7 +14,7 @@ import org.springframework.data.redis.serializer.SerializationException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* Jackson Redis序列化器 - 兼容fastjson旧格式
|
||||
* Jackson Redis序列化器 - 兼容fastjson旧格式(Jackson 3 迁移版)
|
||||
*
|
||||
* 新数据: 纯JSON (无类型包装),调用方用 convertValue 转换
|
||||
* 旧fastjson: 去除L后缀后按JSON解析
|
||||
@@ -30,10 +32,10 @@ public class FastjsonCompatibleRedisSerializer implements RedisSerializer<Object
|
||||
}
|
||||
|
||||
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;
|
||||
return JsonMapper.builder()
|
||||
.changeDefaultVisibility(vc -> vc.withVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY))
|
||||
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
|
||||
.build();
|
||||
}
|
||||
|
||||
/** 获取共享ObjectMapper,供 DictUtils / TokenService 等做 convertValue */
|
||||
@@ -64,7 +66,7 @@ public class FastjsonCompatibleRedisSerializer implements RedisSerializer<Object
|
||||
try {
|
||||
// 处理旧Jackson activateDefaultTyping格式: ["className", {data}]
|
||||
if (cleaned.startsWith("[\"") && cleaned.length() > 10) {
|
||||
com.fasterxml.jackson.databind.JsonNode node = objectMapper.readTree(cleaned);
|
||||
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);
|
||||
@@ -76,4 +78,4 @@ public class FastjsonCompatibleRedisSerializer implements RedisSerializer<Object
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.core.framework.interceptor;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import com.core.common.utils.JsonUtils;
|
||||
import com.core.common.annotation.RepeatSubmit;
|
||||
import com.core.common.core.domain.AjaxResult;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.core.framework.interceptor.impl;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import com.core.common.utils.JsonUtils;
|
||||
import com.core.common.annotation.RepeatSubmit;
|
||||
import com.core.common.constant.CacheConstants;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.core.framework.security.handle;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import com.core.common.utils.JsonUtils;
|
||||
import com.core.common.constant.HttpStatus;
|
||||
import com.core.common.core.domain.AjaxResult;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.core.framework.security.handle;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import com.core.common.utils.JsonUtils;
|
||||
import com.core.common.constant.Constants;
|
||||
import com.core.common.core.domain.AjaxResult;
|
||||
|
||||
@@ -71,17 +71,19 @@ public class TokenService {
|
||||
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);
|
||||
tools.jackson.databind.ObjectMapper mapper =
|
||||
tools.jackson.databind.json.JsonMapper.builder()
|
||||
.disable(tools.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
|
||||
.build();
|
||||
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);
|
||||
tools.jackson.databind.ObjectMapper mapper =
|
||||
tools.jackson.databind.json.JsonMapper.builder()
|
||||
.disable(tools.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
|
||||
.build();
|
||||
return mapper.convertValue(cached, LoginUser.class);
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
|
||||
<!-- JSON工具类 -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<groupId>tools.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.core.generator.service;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import com.core.common.utils.JsonUtils;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import com.core.common.constant.Constants;
|
||||
import com.core.common.constant.GenConstants;
|
||||
import com.core.common.core.text.CharsetKit;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.core.generator.util;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import com.core.common.utils.JsonUtils;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import com.core.common.constant.GenConstants;
|
||||
import com.core.common.utils.DateUtils;
|
||||
import com.core.common.utils.StringUtils;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.core.system.domain;
|
||||
|
||||
import com.core.common.core.domain.BaseEntity;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
|
||||
/**
|
||||
* 公告/通知已读记录 sys_notice_read
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.healthlink.his.web.Inspection.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.annotation.Dict;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.Inspection.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.lab.domain.ActivityDefDeviceDef;
|
||||
import com.healthlink.his.lab.domain.ActivityDefObservationDef;
|
||||
import com.healthlink.his.lab.domain.ActivityDefSpecimenDef;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.Inspection.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.annotation.Dict;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.healthlink.his.web.Inspection.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.healthlink.his.web.Inspection.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.Inspection.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.adjustprice.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package com.healthlink.his.web.anesthesia.appservice;
|
||||
|
||||
import com.healthlink.his.anesthesia.domain.AnesAsaAssessment;
|
||||
import com.healthlink.his.anesthesia.domain.AnesSummary;
|
||||
import com.healthlink.his.anesthesia.domain.AnesthesiaFollowup;
|
||||
import com.healthlink.his.anesthesia.domain.AnesthesiaIoRecord;
|
||||
import com.healthlink.his.anesthesia.domain.AnesthesiaMedication;
|
||||
import com.healthlink.his.anesthesia.domain.AnesthesiaPostopFollowup;
|
||||
import com.healthlink.his.anesthesia.domain.AnesthesiaRecord;
|
||||
import com.healthlink.his.anesthesia.domain.AnesthesiaVitalSign;
|
||||
import com.healthlink.his.anesthesia.dto.AnesthesiaIoSummaryDto;
|
||||
@@ -31,4 +34,20 @@ public interface IAnesthesiaAppService {
|
||||
AnesthesiaIoSummaryDto getIoSummary(Long recordId);
|
||||
|
||||
void completeRecord(Long recordId);
|
||||
|
||||
AnesAsaAssessment saveAsaAssessment(AnesAsaAssessment assessment);
|
||||
|
||||
List<AnesAsaAssessment> getAsaAssessments(Long recordId);
|
||||
|
||||
AnesthesiaVitalSign recordVitalSign(AnesthesiaVitalSign vitalSign);
|
||||
|
||||
List<AnesthesiaVitalSign> getVitalSignTimeline(Long recordId);
|
||||
|
||||
AnesSummary saveSummary(AnesSummary summary);
|
||||
|
||||
AnesSummary getSummary(Long recordId);
|
||||
|
||||
AnesthesiaPostopFollowup recordFollowup(AnesthesiaPostopFollowup followup);
|
||||
|
||||
List<AnesthesiaPostopFollowup> getFollowups(Long encounterId);
|
||||
}
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
package com.healthlink.his.web.anesthesia.appservice.impl;
|
||||
|
||||
import com.healthlink.his.anesthesia.domain.AnesAsaAssessment;
|
||||
import com.healthlink.his.anesthesia.domain.AnesSummary;
|
||||
import com.healthlink.his.anesthesia.domain.AnesthesiaFollowup;
|
||||
import com.healthlink.his.anesthesia.domain.AnesthesiaIoRecord;
|
||||
import com.healthlink.his.anesthesia.domain.AnesthesiaMedication;
|
||||
import com.healthlink.his.anesthesia.domain.AnesthesiaPostopFollowup;
|
||||
import com.healthlink.his.anesthesia.domain.AnesthesiaRecord;
|
||||
import com.healthlink.his.anesthesia.domain.AnesthesiaVitalSign;
|
||||
import com.healthlink.his.anesthesia.dto.AnesthesiaIoSummaryDto;
|
||||
import com.healthlink.his.anesthesia.dto.AnesthesiaRecordDetailDto;
|
||||
import com.healthlink.his.anesthesia.service.IAnesAsaAssessmentService;
|
||||
import com.healthlink.his.anesthesia.service.IAnesSummaryService;
|
||||
import com.healthlink.his.anesthesia.service.IAnesthesiaFollowupService;
|
||||
import com.healthlink.his.anesthesia.service.IAnesthesiaIoRecordService;
|
||||
import com.healthlink.his.anesthesia.service.IAnesthesiaPostopFollowupService;
|
||||
import com.healthlink.his.anesthesia.service.IAnesthesiaMedicationService;
|
||||
import com.healthlink.his.anesthesia.service.IAnesthesiaRecordService;
|
||||
import com.healthlink.his.anesthesia.service.IAnesthesiaVitalSignService;
|
||||
import com.healthlink.his.web.anesthesia.appservice.IAnesthesiaAppService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -39,6 +46,15 @@ public class AnesthesiaAppServiceImpl implements IAnesthesiaAppService {
|
||||
@Resource
|
||||
private IAnesthesiaFollowupService anesthesiaFollowupService;
|
||||
|
||||
@Resource
|
||||
private IAnesAsaAssessmentService anesAsaAssessmentService;
|
||||
|
||||
@Resource
|
||||
private IAnesSummaryService anesSummaryService;
|
||||
|
||||
@Resource
|
||||
private IAnesthesiaPostopFollowupService anesthesiaPostopFollowupService;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public AnesthesiaRecord createRecord(AnesthesiaRecord record) {
|
||||
@@ -125,4 +141,74 @@ public class AnesthesiaAppServiceImpl implements IAnesthesiaAppService {
|
||||
record.setEndTime(new Date());
|
||||
anesthesiaRecordService.updateById(record);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public AnesAsaAssessment saveAsaAssessment(AnesAsaAssessment assessment) {
|
||||
if (assessment.getId() != null) {
|
||||
anesAsaAssessmentService.updateById(assessment);
|
||||
} else {
|
||||
anesAsaAssessmentService.save(assessment);
|
||||
}
|
||||
return assessment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AnesAsaAssessment> getAsaAssessments(Long recordId) {
|
||||
return anesAsaAssessmentService.selectByRecordId(recordId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public AnesthesiaVitalSign recordVitalSign(AnesthesiaVitalSign vitalSign) {
|
||||
anesthesiaVitalSignService.save(vitalSign);
|
||||
return vitalSign;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AnesthesiaVitalSign> getVitalSignTimeline(Long recordId) {
|
||||
return anesthesiaVitalSignService.selectByRecordId(recordId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public AnesSummary saveSummary(AnesSummary summary) {
|
||||
if (summary.getId() != null) {
|
||||
anesSummaryService.updateById(summary);
|
||||
} else {
|
||||
AnesSummary existing = anesSummaryService.selectByRecordId(summary.getRecordId());
|
||||
if (existing != null) {
|
||||
summary.setId(existing.getId());
|
||||
anesSummaryService.updateById(summary);
|
||||
} else {
|
||||
anesSummaryService.save(summary);
|
||||
}
|
||||
}
|
||||
return summary;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnesSummary getSummary(Long recordId) {
|
||||
return anesSummaryService.selectByRecordId(recordId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public AnesthesiaPostopFollowup recordFollowup(AnesthesiaPostopFollowup followup) {
|
||||
if (followup.getId() != null) {
|
||||
anesthesiaPostopFollowupService.updateById(followup);
|
||||
} else {
|
||||
followup.setStatus(0);
|
||||
anesthesiaPostopFollowupService.save(followup);
|
||||
}
|
||||
return followup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AnesthesiaPostopFollowup> getFollowups(Long encounterId) {
|
||||
LambdaQueryWrapper<AnesthesiaPostopFollowup> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AnesthesiaPostopFollowup::getEncounterId, encounterId)
|
||||
.orderByDesc(AnesthesiaPostopFollowup::getFollowupTime);
|
||||
return anesthesiaPostopFollowupService.list(wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package com.healthlink.his.web.anesthesia.controller;
|
||||
|
||||
import com.core.common.core.domain.R;
|
||||
import com.healthlink.his.anesthesia.domain.AnesAsaAssessment;
|
||||
import com.healthlink.his.anesthesia.domain.AnesSummary;
|
||||
import com.healthlink.his.anesthesia.domain.AnesthesiaFollowup;
|
||||
import com.healthlink.his.anesthesia.domain.AnesthesiaIoRecord;
|
||||
import com.healthlink.his.anesthesia.domain.AnesthesiaMedication;
|
||||
import com.healthlink.his.anesthesia.domain.AnesthesiaPostopFollowup;
|
||||
import com.healthlink.his.anesthesia.domain.AnesthesiaRecord;
|
||||
import com.healthlink.his.anesthesia.domain.AnesthesiaVitalSign;
|
||||
import com.healthlink.his.anesthesia.dto.AnesthesiaIoSummaryDto;
|
||||
@@ -17,6 +20,7 @@ import com.healthlink.his.web.anesthesia.appservice.IAnesthesiaAppService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
@@ -134,4 +138,60 @@ public class AnesthesiaController {
|
||||
anesthesiaAppService.completeRecord(id);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@PostMapping("/asa-assessment")
|
||||
@Operation(summary = "保存ASA评估")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:anesthesia:edit')")
|
||||
public R<AnesAsaAssessment> saveAsaAssessment(@RequestBody AnesAsaAssessment assessment) {
|
||||
return R.ok(anesthesiaAppService.saveAsaAssessment(assessment));
|
||||
}
|
||||
|
||||
@GetMapping("/asa-assessment/{recordId}")
|
||||
@Operation(summary = "查询ASA评估列表")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:anesthesia:list')")
|
||||
public R<List<AnesAsaAssessment>> getAsaAssessments(@PathVariable Long recordId) {
|
||||
return R.ok(anesthesiaAppService.getAsaAssessments(recordId));
|
||||
}
|
||||
|
||||
@PostMapping("/vital-sign/record")
|
||||
@Operation(summary = "记录术中生命体征")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:anesthesia:edit')")
|
||||
public R<AnesthesiaVitalSign> recordVitalSign(@RequestBody AnesthesiaVitalSign vitalSign) {
|
||||
return R.ok(anesthesiaAppService.recordVitalSign(vitalSign));
|
||||
}
|
||||
|
||||
@GetMapping("/vital-sign/timeline/{recordId}")
|
||||
@Operation(summary = "查询生命体征时间线")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:anesthesia:list')")
|
||||
public R<List<AnesthesiaVitalSign>> getVitalSignTimeline(@PathVariable Long recordId) {
|
||||
return R.ok(anesthesiaAppService.getVitalSignTimeline(recordId));
|
||||
}
|
||||
|
||||
@PostMapping("/summary")
|
||||
@Operation(summary = "保存麻醉小结")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:anesthesia:edit')")
|
||||
public R<AnesSummary> saveSummary(@RequestBody AnesSummary summary) {
|
||||
return R.ok(anesthesiaAppService.saveSummary(summary));
|
||||
}
|
||||
|
||||
@GetMapping("/summary/{recordId}")
|
||||
@Operation(summary = "获取麻醉小结")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:anesthesia:list')")
|
||||
public R<AnesSummary> getSummary(@PathVariable Long recordId) {
|
||||
return R.ok(anesthesiaAppService.getSummary(recordId));
|
||||
}
|
||||
|
||||
@PostMapping("/postop-followup")
|
||||
@Operation(summary = "记录术后随访")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:anesthesia:edit')")
|
||||
public R<AnesthesiaPostopFollowup> recordFollowup(@RequestBody AnesthesiaPostopFollowup followup) {
|
||||
return R.ok(anesthesiaAppService.recordFollowup(followup));
|
||||
}
|
||||
|
||||
@GetMapping("/postop-followup/{encounterId}")
|
||||
@Operation(summary = "查询术后随访列表")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:anesthesia:list')")
|
||||
public R<List<AnesthesiaPostopFollowup>> getPostopFollowups(@PathVariable Long encounterId) {
|
||||
return R.ok(anesthesiaAppService.getFollowups(encounterId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.appointmentmanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*/
|
||||
package com.healthlink.his.web.basedatamanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*/
|
||||
package com.healthlink.his.web.basedatamanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*/
|
||||
package com.healthlink.his.web.basedatamanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.annotation.Dict;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.basedatamanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.annotation.Dict;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*/
|
||||
package com.healthlink.his.web.basedatamanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*/
|
||||
package com.healthlink.his.web.basedatamanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.annotation.Dict;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
package com.healthlink.his.web.basedatamanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*/
|
||||
package com.healthlink.his.web.basedatamanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.basedatamanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.annotation.Dict;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*/
|
||||
package com.healthlink.his.web.basedatamanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.basedatamanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*/
|
||||
package com.healthlink.his.web.basedatamanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.basedatamanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.annotation.Dict;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.basicservice.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.annotation.Dict;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.healthlink.his.web.bloodtransfusion.appservice;
|
||||
import com.healthlink.his.bloodtransfusion.domain.BloodTransfusionRecord;
|
||||
import com.healthlink.his.bloodtransfusion.domain.BloodTransfusionObservation;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import java.util.Map;
|
||||
public interface IBloodTransfusionAppService {
|
||||
void apply(BloodTransfusionRecord record);
|
||||
IPage<BloodTransfusionRecord> page(String approvalStatus, String bloodComponent, Integer pageNum, Integer pageSize);
|
||||
void approve(Long id, String approvalStatus, String approverName);
|
||||
void observe(BloodTransfusionObservation observation);
|
||||
Map<String, Object> getRecordDetail(Long id);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.healthlink.his.web.bloodtransfusion.appservice.impl;
|
||||
import com.healthlink.his.bloodtransfusion.domain.BloodTransfusionRecord;
|
||||
import com.healthlink.his.bloodtransfusion.domain.BloodTransfusionObservation;
|
||||
import com.healthlink.his.bloodtransfusion.service.IBloodTransfusionRecordService;
|
||||
import com.healthlink.his.bloodtransfusion.service.IBloodTransfusionObservationService;
|
||||
import com.healthlink.his.web.bloodtransfusion.appservice.IBloodTransfusionAppService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.util.*;
|
||||
@Service
|
||||
public class BloodTransfusionAppServiceImpl implements IBloodTransfusionAppService {
|
||||
@Autowired
|
||||
private IBloodTransfusionRecordService recordService;
|
||||
@Autowired
|
||||
private IBloodTransfusionObservationService observationService;
|
||||
@Override
|
||||
public void apply(BloodTransfusionRecord record) {
|
||||
record.setStatus("SUBMITTED");
|
||||
record.setApprovalStatus("PENDING");
|
||||
record.setCreateTime(new Date());
|
||||
recordService.save(record);
|
||||
}
|
||||
@Override
|
||||
public IPage<BloodTransfusionRecord> page(String approvalStatus, String bloodComponent, Integer pageNum, Integer pageSize) {
|
||||
LambdaQueryWrapper<BloodTransfusionRecord> w = new LambdaQueryWrapper<>();
|
||||
if (approvalStatus != null && !approvalStatus.isEmpty()) {
|
||||
w.eq(BloodTransfusionRecord::getApprovalStatus, approvalStatus);
|
||||
}
|
||||
if (bloodComponent != null && !bloodComponent.isEmpty()) {
|
||||
w.eq(BloodTransfusionRecord::getBloodComponent, bloodComponent);
|
||||
}
|
||||
w.orderByDesc(BloodTransfusionRecord::getCreateTime);
|
||||
return recordService.page(new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageNum, pageSize), w);
|
||||
}
|
||||
@Override
|
||||
public void approve(Long id, String approvalStatus, String approverName) {
|
||||
BloodTransfusionRecord record = recordService.getById(id);
|
||||
if (record == null) {
|
||||
throw new RuntimeException("输血记录不存在");
|
||||
}
|
||||
record.setApprovalStatus(approvalStatus);
|
||||
record.setApproverName(approverName);
|
||||
record.setApproveTime(new Date());
|
||||
if ("APPROVED".equals(approvalStatus)) {
|
||||
record.setStatus("APPROVED");
|
||||
} else if ("REJECTED".equals(approvalStatus)) {
|
||||
record.setStatus("REJECTED");
|
||||
}
|
||||
recordService.updateById(record);
|
||||
}
|
||||
@Override
|
||||
public void observe(BloodTransfusionObservation observation) {
|
||||
observation.setCreateTime(new Date());
|
||||
observationService.save(observation);
|
||||
}
|
||||
@Override
|
||||
public Map<String, Object> getRecordDetail(Long id) {
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
BloodTransfusionRecord record = recordService.getById(id);
|
||||
if (record == null) {
|
||||
throw new RuntimeException("输血记录不存在");
|
||||
}
|
||||
result.put("record", record);
|
||||
List<BloodTransfusionObservation> observations = observationService.list(
|
||||
new LambdaQueryWrapper<BloodTransfusionObservation>()
|
||||
.eq(BloodTransfusionObservation::getRecordId, id)
|
||||
.orderByAsc(BloodTransfusionObservation::getObservationTime)
|
||||
);
|
||||
result.put("observations", observations);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.healthlink.his.web.bloodtransfusion.controller;
|
||||
import com.core.common.core.domain.AjaxResult;
|
||||
import com.healthlink.his.bloodtransfusion.domain.BloodTransfusionRecord;
|
||||
import com.healthlink.his.bloodtransfusion.domain.BloodTransfusionObservation;
|
||||
import com.healthlink.his.web.bloodtransfusion.appservice.IBloodTransfusionAppService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@Tag(name = "输血管理") @RestController @RequestMapping("/api/v1/blood-transfusion")
|
||||
public class BloodTransfusionController {
|
||||
@Autowired
|
||||
private IBloodTransfusionAppService appService;
|
||||
@Operation(summary = "申请输血")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:bloodtransfusion:edit')")
|
||||
@PostMapping("/apply")
|
||||
public AjaxResult apply(@RequestBody BloodTransfusionRecord record) {
|
||||
appService.apply(record);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
@Operation(summary = "输血申请分页")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:bloodtransfusion:list')")
|
||||
@GetMapping("/page")
|
||||
public AjaxResult page(@RequestParam(required = false) String approvalStatus,
|
||||
@RequestParam(required = false) String bloodComponent,
|
||||
@RequestParam(defaultValue = "1") Integer pageNum,
|
||||
@RequestParam(defaultValue = "10") Integer pageSize) {
|
||||
return AjaxResult.success(appService.page(approvalStatus, bloodComponent, pageNum, pageSize));
|
||||
}
|
||||
@Operation(summary = "审批输血")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:bloodtransfusion:edit')")
|
||||
@PutMapping("/approve/{id}")
|
||||
public AjaxResult approve(@PathVariable Long id,
|
||||
@RequestParam String approvalStatus,
|
||||
@RequestParam(required = false) String approverName) {
|
||||
appService.approve(id, approvalStatus, approverName);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
@Operation(summary = "输血观察记录")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:bloodtransfusion:edit')")
|
||||
@PostMapping("/observe")
|
||||
public AjaxResult observe(@RequestBody BloodTransfusionObservation observation) {
|
||||
appService.observe(observation);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
@Operation(summary = "输血记录详情")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:bloodtransfusion:list')")
|
||||
@GetMapping("/record/{id}")
|
||||
public AjaxResult recordDetail(@PathVariable Long id) {
|
||||
return AjaxResult.success(appService.getRecordDetail(id));
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,8 @@
|
||||
package com.healthlink.his.web.cardmanagement.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.chargemanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.constant.CommonConstants;
|
||||
import com.healthlink.his.common.enums.AccountBillingStatus;
|
||||
import com.healthlink.his.common.enums.AccountStatus;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.healthlink.his.web.chargemanage.dto;
|
||||
|
||||
import com.core.common.utils.SecurityUtils;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.constant.CommonConstants;
|
||||
import com.healthlink.his.common.enums.ChargeItemContext;
|
||||
import com.healthlink.his.common.enums.ChargeItemStatus;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.chargemanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.chargemanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.chargemanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.enums.*;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.chargemanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.enums.EncounterActivityStatus;
|
||||
import com.healthlink.his.common.enums.LocationForm;
|
||||
import lombok.Data;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.chargemanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.enums.ParticipantType;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
package com.healthlink.his.web.chargemanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
@@ -5,8 +5,8 @@ package com.healthlink.his.web.chargemanage.dto;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.annotation.Dict;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*/
|
||||
package com.healthlink.his.web.chargemanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.annotation.Dict;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
package com.healthlink.his.web.chargemanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.annotation.Dict;
|
||||
import com.healthlink.his.yb.dto.PaymentDetailDto;
|
||||
import lombok.Data;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.chargemanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.chargemanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.annotation.Dict;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.chargemanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.annotation.Dict;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.chargemanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.chargemanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
package com.healthlink.his.web.chargemanage.dto;
|
||||
|
||||
import com.core.common.utils.SecurityUtils;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.enums.EncounterClass;
|
||||
import com.healthlink.his.common.enums.RequestStatus;
|
||||
import com.healthlink.his.common.enums.TherapyTimeType;
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*/
|
||||
package com.healthlink.his.web.chargemanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.annotation.Dict;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.chargemanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ public class ExamApplyController extends BaseController {
|
||||
|
||||
for (ExamApplyItem item : items) {
|
||||
BigDecimal itemTotal = item.getItemFee() != null ? item.getItemFee() : BigDecimal.ZERO;
|
||||
BigDecimal methodFee = getMethodAdditionalFee(item.getExamMethodCode());
|
||||
BigDecimal methodFee = getMethodAdditionalFee(item.getExamMethodCode(), item.getBodyPartCode());
|
||||
totalAmount = totalAmount.add(itemTotal.add(methodFee));
|
||||
}
|
||||
|
||||
@@ -318,7 +318,7 @@ public class ExamApplyController extends BaseController {
|
||||
|
||||
// 金额:单价和总价取检查项目费用
|
||||
BigDecimal baseFee = itemDto.getItemFee() != null ? itemDto.getItemFee() : BigDecimal.ZERO;
|
||||
BigDecimal methodFee = getMethodAdditionalFee(itemDto.getExamMethodCode());
|
||||
BigDecimal methodFee = getMethodAdditionalFee(itemDto.getExamMethodCode(), itemDto.getBodyPartCode());
|
||||
BigDecimal fee = baseFee.add(methodFee);
|
||||
chargeItem.setQuantityValue(BigDecimal.ONE); // 数量
|
||||
chargeItem.setQuantityUnit("次"); // 单位
|
||||
@@ -506,7 +506,7 @@ public class ExamApplyController extends BaseController {
|
||||
chargeItem.setProductId(0L);
|
||||
|
||||
BigDecimal baseFee = itemDto.getItemFee() != null ? itemDto.getItemFee() : BigDecimal.ZERO;
|
||||
BigDecimal methodFee = getMethodAdditionalFee(itemDto.getExamMethodCode());
|
||||
BigDecimal methodFee = getMethodAdditionalFee(itemDto.getExamMethodCode(), itemDto.getBodyPartCode());
|
||||
BigDecimal fee = baseFee.add(methodFee);
|
||||
chargeItem.setQuantityValue(BigDecimal.ONE);
|
||||
chargeItem.setQuantityUnit("次");
|
||||
@@ -570,15 +570,17 @@ public class ExamApplyController extends BaseController {
|
||||
* Bug #655: 根据检查方法代码查询附加金额(套餐价格)
|
||||
* 查找链路:examMethodCode → CheckMethod → packageName → CheckPackage → packagePrice
|
||||
*/
|
||||
private BigDecimal getMethodAdditionalFee(String examMethodCode) {
|
||||
private BigDecimal getMethodAdditionalFee(String examMethodCode, String checkType) {
|
||||
if (examMethodCode == null || examMethodCode.isEmpty()) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
// 1. 根据 code 查找 CheckMethod
|
||||
CheckMethod method = checkMethodService.getOne(
|
||||
new LambdaQueryWrapper<CheckMethod>()
|
||||
.eq(CheckMethod::getCode, examMethodCode)
|
||||
.last("LIMIT 1"));
|
||||
// 1. 根据 code 和 checkType 查找 CheckMethod
|
||||
LambdaQueryWrapper<CheckMethod> wrapper = new LambdaQueryWrapper<CheckMethod>()
|
||||
.eq(CheckMethod::getCode, examMethodCode);
|
||||
if (checkType != null && !checkType.isEmpty()) {
|
||||
wrapper.eq(CheckMethod::getCheckType, checkType);
|
||||
}
|
||||
CheckMethod method = checkMethodService.getOne(wrapper.last("LIMIT 1"));
|
||||
if (method == null || method.getPackageName() == null || method.getPackageName().isEmpty()) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.healthlink.his.web.clinical.appservice;
|
||||
import com.healthlink.his.clinical.domain.ClinicalPathway;
|
||||
import com.healthlink.his.clinical.domain.ClinicalPathwayExecution;
|
||||
import com.healthlink.his.clinical.domain.ClinicalPathwayVariance;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import java.util.Map;
|
||||
public interface IClinicalPathwayAppService {
|
||||
Map<String, Object> evaluate(Long encounterId);
|
||||
void admit(ClinicalPathwayExecution execution);
|
||||
void recordExecution(ClinicalPathwayExecution execution);
|
||||
void recordVariance(ClinicalPathwayVariance variance);
|
||||
void discharge(Long executionId);
|
||||
Map<String, Object> getStatistics(String startDate, String endDate);
|
||||
IPage<ClinicalPathway> page(String diseaseCode, Integer pageNo, Integer pageSize);
|
||||
void add(ClinicalPathway pathway);
|
||||
IPage<Map<String, Object>> getExecutionPage(Long pathwayId, Integer pageNo, Integer pageSize);
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
package com.healthlink.his.web.clinical.appservice.impl;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.healthlink.his.clinical.domain.ClinicalPathway;
|
||||
import com.healthlink.his.clinical.domain.ClinicalPathwayExecution;
|
||||
import com.healthlink.his.clinical.domain.ClinicalPathwayVariance;
|
||||
import com.healthlink.his.clinical.service.IClinicalPathwayService;
|
||||
import com.healthlink.his.clinical.service.IClinicalPathwayExecutionService;
|
||||
import com.healthlink.his.clinical.service.IClinicalPathwayVarianceService;
|
||||
import com.healthlink.his.web.clinical.appservice.IClinicalPathwayAppService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.*;
|
||||
@Service
|
||||
public class ClinicalPathwayAppServiceImpl implements IClinicalPathwayAppService {
|
||||
@Autowired
|
||||
private IClinicalPathwayService pathwayService;
|
||||
@Autowired
|
||||
private IClinicalPathwayExecutionService executionService;
|
||||
@Autowired
|
||||
private IClinicalPathwayVarianceService varianceService;
|
||||
@Override
|
||||
public Map<String, Object> evaluate(Long encounterId) {
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
LambdaQueryWrapper<ClinicalPathwayExecution> qw = new LambdaQueryWrapper<>();
|
||||
qw.eq(ClinicalPathwayExecution::getEncounterId, encounterId)
|
||||
.eq(ClinicalPathwayExecution::getStatus, "IN_PATH");
|
||||
ClinicalPathwayExecution active = executionService.getOne(qw);
|
||||
result.put("hasActivePathway", active != null);
|
||||
if (active != null) {
|
||||
result.put("activeExecution", active);
|
||||
LambdaQueryWrapper<ClinicalPathway> pw = new LambdaQueryWrapper<>();
|
||||
pw.eq(ClinicalPathway::getId, active.getPathwayId());
|
||||
result.put("pathway", pathwayService.getOne(pw));
|
||||
}
|
||||
LambdaQueryWrapper<ClinicalPathwayExecution> allQw = new LambdaQueryWrapper<>();
|
||||
allQw.eq(ClinicalPathwayExecution::getEncounterId, encounterId);
|
||||
result.put("totalExecutions", executionService.count(allQw));
|
||||
return result;
|
||||
}
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void admit(ClinicalPathwayExecution execution) {
|
||||
execution.setStatus("IN_PATH");
|
||||
execution.setEnterDate(LocalDate.now());
|
||||
execution.setCreateTime(new Date());
|
||||
executionService.save(execution);
|
||||
}
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void recordExecution(ClinicalPathwayExecution execution) {
|
||||
LambdaQueryWrapper<ClinicalPathwayExecution> qw = new LambdaQueryWrapper<>();
|
||||
qw.eq(ClinicalPathwayExecution::getEncounterId, execution.getEncounterId())
|
||||
.eq(ClinicalPathwayExecution::getStatus, "IN_PATH");
|
||||
ClinicalPathwayExecution existing = executionService.getOne(qw);
|
||||
if (existing == null) {
|
||||
throw new RuntimeException("当前无在径执行记录");
|
||||
}
|
||||
if (execution.getActualDays() != null) {
|
||||
existing.setActualDays(execution.getActualDays());
|
||||
}
|
||||
if (execution.getActualCost() != null) {
|
||||
existing.setActualCost(execution.getActualCost());
|
||||
}
|
||||
existing.setUpdateTime(new Date());
|
||||
executionService.updateById(existing);
|
||||
}
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void recordVariance(ClinicalPathwayVariance variance) {
|
||||
variance.setCreateTime(new Date());
|
||||
varianceService.save(variance);
|
||||
LambdaQueryWrapper<ClinicalPathwayExecution> qw = new LambdaQueryWrapper<>();
|
||||
qw.eq(ClinicalPathwayExecution::getId, variance.getExecutionId());
|
||||
ClinicalPathwayExecution exec = executionService.getOne(qw);
|
||||
if (exec != null) {
|
||||
exec.setStatus("VARIATION");
|
||||
exec.setVariationReason(variance.getVarianceReason());
|
||||
exec.setUpdateTime(new Date());
|
||||
executionService.updateById(exec);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void discharge(Long executionId) {
|
||||
ClinicalPathwayExecution exec = executionService.getById(executionId);
|
||||
if (exec == null) {
|
||||
throw new RuntimeException("执行记录不存在");
|
||||
}
|
||||
exec.setStatus("COMPLETED");
|
||||
exec.setCompleteDate(LocalDate.now());
|
||||
if (exec.getEnterDate() != null) {
|
||||
long days = ChronoUnit.DAYS.between(exec.getEnterDate(), LocalDate.now());
|
||||
exec.setActualDays((int) days);
|
||||
}
|
||||
exec.setUpdateTime(new Date());
|
||||
executionService.updateById(exec);
|
||||
}
|
||||
@Override
|
||||
public Map<String, Object> getStatistics(String startDate, String endDate) {
|
||||
Map<String, Object> stats = new LinkedHashMap<>();
|
||||
stats.put("totalPathways", pathwayService.count());
|
||||
stats.put("totalExecutions", executionService.count());
|
||||
LambdaQueryWrapper<ClinicalPathwayExecution> inPathQw = new LambdaQueryWrapper<>();
|
||||
inPathQw.eq(ClinicalPathwayExecution::getStatus, "IN_PATH");
|
||||
stats.put("inPathCount", executionService.count(inPathQw));
|
||||
LambdaQueryWrapper<ClinicalPathwayExecution> completedQw = new LambdaQueryWrapper<>();
|
||||
completedQw.eq(ClinicalPathwayExecution::getStatus, "COMPLETED");
|
||||
stats.put("completedCount", executionService.count(completedQw));
|
||||
LambdaQueryWrapper<ClinicalPathwayExecution> variationQw = new LambdaQueryWrapper<>();
|
||||
variationQw.eq(ClinicalPathwayExecution::getStatus, "VARIATION");
|
||||
stats.put("variationCount", executionService.count(variationQw));
|
||||
LambdaQueryWrapper<ClinicalPathwayExecution> exitQw = new LambdaQueryWrapper<>();
|
||||
exitQw.eq(ClinicalPathwayExecution::getStatus, "EXIT");
|
||||
stats.put("exitCount", executionService.count(exitQw));
|
||||
long total = executionService.count();
|
||||
long completed = (long) stats.get("completedCount");
|
||||
stats.put("completionRate", total > 0 ? Math.round(completed * 100.0 / total) : 0);
|
||||
stats.put("totalVariances", varianceService.count());
|
||||
return stats;
|
||||
}
|
||||
@Override
|
||||
public IPage<ClinicalPathway> page(String diseaseCode, Integer pageNo, Integer pageSize) {
|
||||
LambdaQueryWrapper<ClinicalPathway> w = new LambdaQueryWrapper<>();
|
||||
w.eq(StringUtils.hasText(diseaseCode), ClinicalPathway::getDiseaseCode, diseaseCode)
|
||||
.eq(ClinicalPathway::getStatus, "ACTIVE");
|
||||
return pathwayService.page(new Page<>(pageNo, pageSize), w);
|
||||
}
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void add(ClinicalPathway pathway) {
|
||||
pathway.setVersion(1);
|
||||
pathway.setStatus("ACTIVE");
|
||||
pathway.setCreateTime(new Date());
|
||||
pathwayService.save(pathway);
|
||||
}
|
||||
@Override
|
||||
public IPage<Map<String, Object>> getExecutionPage(Long pathwayId, Integer pageNo, Integer pageSize) {
|
||||
LambdaQueryWrapper<ClinicalPathwayExecution> qw = new LambdaQueryWrapper<>();
|
||||
qw.eq(pathwayId != null, ClinicalPathwayExecution::getPathwayId, pathwayId)
|
||||
.orderByDesc(ClinicalPathwayExecution::getCreateTime);
|
||||
Page<ClinicalPathwayExecution> execPage = executionService.page(new Page<>(pageNo, pageSize), qw);
|
||||
Page<Map<String, Object>> result = new Page<>(execPage.getCurrent(), execPage.getSize(), execPage.getTotal());
|
||||
List<Map<String, Object>> records = new ArrayList<>();
|
||||
for (ClinicalPathwayExecution exec : execPage.getRecords()) {
|
||||
Map<String, Object> row = new LinkedHashMap<>();
|
||||
row.put("id", exec.getId());
|
||||
row.put("pathwayId", exec.getPathwayId());
|
||||
row.put("encounterId", exec.getEncounterId());
|
||||
row.put("patientId", exec.getPatientId());
|
||||
row.put("patientName", exec.getPatientName());
|
||||
row.put("enterDate", exec.getEnterDate());
|
||||
row.put("expectedDays", exec.getExpectedDays());
|
||||
row.put("actualDays", exec.getActualDays());
|
||||
row.put("expectedCost", exec.getExpectedCost());
|
||||
row.put("actualCost", exec.getActualCost());
|
||||
row.put("status", exec.getStatus());
|
||||
row.put("completeDate", exec.getCompleteDate());
|
||||
row.put("createTime", exec.getCreateTime());
|
||||
LambdaQueryWrapper<ClinicalPathway> pw = new LambdaQueryWrapper<>();
|
||||
pw.eq(ClinicalPathway::getId, exec.getPathwayId());
|
||||
ClinicalPathway pwObj = pathwayService.getOne(pw);
|
||||
if (pwObj != null) {
|
||||
row.put("pathwayName", pwObj.getPathwayName());
|
||||
row.put("diseaseCode", pwObj.getDiseaseCode());
|
||||
row.put("diseaseName", pwObj.getDiseaseName());
|
||||
}
|
||||
records.add(row);
|
||||
}
|
||||
result.setRecords(records);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,24 @@
|
||||
package com.healthlink.his.web.clinical.controller;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.core.common.core.domain.AjaxResult;
|
||||
import com.core.common.core.domain.R;
|
||||
import com.healthlink.his.clinical.domain.*;
|
||||
import com.healthlink.his.clinical.service.*;
|
||||
import com.healthlink.his.web.clinical.appservice.IClinicalPathwayAppService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.AllArgsConstructor;import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
@RestController @RequestMapping("/clinical-pathway") @Slf4j @AllArgsConstructor
|
||||
@Tag(name = "临床路径管理") @RestController @RequestMapping("/clinical-pathway") @Slf4j @AllArgsConstructor
|
||||
public class ClinicalPathwayController {
|
||||
private final IClinicalPathwayService pathwayService;
|
||||
private final IClinicalPathwayExecutionService executionService;
|
||||
private final IClinicalPathwayAppService clinicalPathwayAppService;
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:clinical:list')")
|
||||
@GetMapping("/page")
|
||||
public R<?> getPage(@RequestParam(value="diseaseCode",required=false) String diseaseCode,
|
||||
@RequestParam(value="pageNo",defaultValue="1") Integer pageNo,
|
||||
@@ -21,13 +28,16 @@ public class ClinicalPathwayController {
|
||||
.eq(ClinicalPathway::getStatus, "ACTIVE");
|
||||
return R.ok(pathwayService.page(new Page<>(pageNo, pageSize), w));
|
||||
}
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:clinical:edit')")
|
||||
@PostMapping("/add") @Transactional(rollbackFor=Exception.class)
|
||||
public R<?> add(@RequestBody ClinicalPathway p) { p.setVersion(1); p.setStatus("ACTIVE"); p.setCreateTime(new Date()); pathwayService.save(p); return R.ok(p); }
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:clinical:edit')")
|
||||
@PostMapping("/enter") @Transactional(rollbackFor=Exception.class)
|
||||
public R<?> enterPathway(@RequestBody ClinicalPathwayExecution e) {
|
||||
e.setStatus("IN_PATH"); e.setEnterDate(java.time.LocalDate.now()); e.setCreateTime(new Date());
|
||||
executionService.save(e); return R.ok(e);
|
||||
}
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:clinical:edit')")
|
||||
@PutMapping("/complete/{id}") @Transactional(rollbackFor=Exception.class)
|
||||
public R<?> completePathway(@PathVariable Long id) {
|
||||
LambdaQueryWrapper<ClinicalPathwayExecution> qw = new LambdaQueryWrapper<>();
|
||||
@@ -36,6 +46,7 @@ public class ClinicalPathwayController {
|
||||
e.setStatus("COMPLETED"); e.setCompleteDate(java.time.LocalDate.now());
|
||||
executionService.updateById(e); return R.ok();
|
||||
}
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:clinical:edit')")
|
||||
@PutMapping("/vary/{id}") @Transactional(rollbackFor=Exception.class)
|
||||
public R<?> varyPathway(@PathVariable Long id, @RequestParam("reason") String reason) {
|
||||
LambdaQueryWrapper<ClinicalPathwayExecution> qw = new LambdaQueryWrapper<>();
|
||||
@@ -43,6 +54,7 @@ public class ClinicalPathwayController {
|
||||
ClinicalPathwayExecution e = executionService.getOne(qw); if (e == null) return R.fail("执行记录不存在");
|
||||
e.setStatus("VARIATION"); e.setVariationReason(reason); executionService.updateById(e); return R.ok();
|
||||
}
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:clinical:list')")
|
||||
@GetMapping("/stats")
|
||||
public R<?> getStats() {
|
||||
Map<String, Object> stats = new HashMap<>();
|
||||
@@ -59,4 +71,53 @@ public class ClinicalPathwayController {
|
||||
stats.put("completionRate", total > 0 ? Math.round(completed * 100.0 / total) : 0);
|
||||
return R.ok(stats);
|
||||
}
|
||||
@Operation(summary = "入径评估")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:clinical:list')")
|
||||
@GetMapping("/evaluate/{encounterId}")
|
||||
public AjaxResult evaluate(@PathVariable Long encounterId) {
|
||||
return AjaxResult.success(clinicalPathwayAppService.evaluate(encounterId));
|
||||
}
|
||||
@Operation(summary = "入径")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:clinical:edit')")
|
||||
@PostMapping("/admission")
|
||||
public AjaxResult admission(@RequestBody ClinicalPathwayExecution execution) {
|
||||
clinicalPathwayAppService.admit(execution);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
@Operation(summary = "执行记录")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:clinical:edit')")
|
||||
@PostMapping("/execution/record")
|
||||
public AjaxResult executionRecord(@RequestBody ClinicalPathwayExecution execution) {
|
||||
clinicalPathwayAppService.recordExecution(execution);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
@Operation(summary = "变异记录")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:clinical:edit')")
|
||||
@PostMapping("/variance/record")
|
||||
public AjaxResult varianceRecord(@RequestBody ClinicalPathwayVariance variance) {
|
||||
clinicalPathwayAppService.recordVariance(variance);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
@Operation(summary = "出径")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:clinical:edit')")
|
||||
@PostMapping("/discharge")
|
||||
public AjaxResult discharge(@RequestParam Long executionId) {
|
||||
clinicalPathwayAppService.discharge(executionId);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
@Operation(summary = "路径统计")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:clinical:list')")
|
||||
@GetMapping("/statistics")
|
||||
public AjaxResult statistics(@RequestParam(required = false) String startDate,
|
||||
@RequestParam(required = false) String endDate) {
|
||||
return AjaxResult.success(clinicalPathwayAppService.getStatistics(startDate, endDate));
|
||||
}
|
||||
@Operation(summary = "执行记录分页")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:clinical:list')")
|
||||
@GetMapping("/execution/page")
|
||||
public AjaxResult getExecutionPage(@RequestParam(required = false) Long pathwayId,
|
||||
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
|
||||
@RequestParam(value = "pageSize", defaultValue = "20") Integer pageSize) {
|
||||
return AjaxResult.success(clinicalPathwayAppService.getExecutionPage(pathwayId, pageNo, pageSize));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import com.core.common.core.domain.entity.SysUser;
|
||||
import com.core.common.utils.MessageUtils;
|
||||
import com.core.common.utils.SecurityUtils;
|
||||
import com.core.system.service.ISysUserService;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import com.core.common.utils.JsonUtils;
|
||||
import com.healthlink.his.administration.domain.ChargeItem;
|
||||
import com.healthlink.his.administration.domain.Encounter;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.healthlink.his.web.clinicalmanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.healthlink.his.common.annotation.Dict;
|
||||
import lombok.Data;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user