Compare commits

..

134 Commits

Author SHA1 Message Date
d21a2f49c1 fix(#786): zhaoyun (文件合入) 2026-06-17 23:35:11 +08:00
767619e308 fix(#783): zhaoyun (文件合入) 2026-06-17 22:53:07 +08:00
1911278570 fix(#783): zhaoyun (文件合入) 2026-06-17 22:33:57 +08:00
f0f4a95fe9 fix(#774): zhaoyun (文件合入) 2026-06-17 21:39:36 +08:00
3a454189b0 fix(#791): zhaoyun (文件合入) 2026-06-17 19:53:53 +08:00
51acc3f91c fix(#783): zhaoyun (文件合入) 2026-06-17 19:39:28 +08:00
5ec3c8425a fix(#791): zhaoyun (文件合入) 2026-06-17 18:52:09 +08:00
dbb4504be9 fix(#783): zhaoyun (文件合入) 2026-06-17 18:03:51 +08:00
wangjian963
a380ad93d9 fix: 修复 vxe-table 列宽 px 单位导致宽度失效
vxe-table 的 min-width/width 仅接受纯数字,带 px/% 单位的设置会被
  静默忽略。统一去掉 vxe-column/vxe-table 上的 px 后缀,将百分比
  min-width 改为 width(vxe 的 width 支持百分比字符串)。
2026-06-17 18:03:29 +08:00
wangjian963
ad90af44a2 783 【住院医生工作站-诊断录入】新增诊断时,可以不保存一直新增诊断,不符合逻辑 2026-06-17 16:47:29 +08:00
86cb6be013 fix(#786): zhaoyun (文件合入) 2026-06-17 16:35:11 +08:00
06111ef284 fix(#784): guanyu (文件合入) 2026-06-17 16:28:55 +08:00
wangjian963
f56aa2ad2e 780 【护士工作站-已出院】列表上的【特级】【一级】【二级】【三级】的筛选查询无响应 2026-06-17 16:18:34 +08:00
84cc974597 在 mrhomepage.js 中补了缺失的三个 API 函数导出:saveDeathDiscussion、listDeathDiscussions、getPendingDeadline 2026-06-17 16:00:26 +08:00
36acf6c513 补充"vxe-pc-ui"依赖 2026-06-17 15:43:20 +08:00
808c0305c9 Merge remote-tracking branch 'origin/develop' into develop 2026-06-17 15:19:58 +08:00
d5f177ae56 refactor(diagnosistreatment): 优化诊断治疗对话框组件结构
- 移除未使用的 title 响应式变量
- 移除未使用的下拉选项响应式变量(diagnosisCategoryOptions、statusFlagOptions、exeOrganizations、typeEnumOptions)
- 简化组件初始化逻辑,直接使用 props 数据
- 清理多余的赋值操作,提高代码可读性
- 优化图标SVG路径定义,调整矩形绘制方式
2026-06-17 15:19:33 +08:00
wangjian963
d7d76c922e 712 【收费工作站-预交金管理】“预交金管理”页面缺失展示“支付方式”列及患者“床号”、“费用类型” 2026-06-17 15:18:48 +08:00
wangjian963
b6eec300a9 696 [收费工作站-住院登记] 优化姓名搜索框,增设“身份证号”与“申请时间段”检索条件,及列表字段补充显示 2026-06-17 15:01:38 +08:00
52b94b9df4 refactor(icons): 优化SVG图标路径结构
- 移除多余的垂直线条路径定义
- 简化为三个水平条形路径,减少重复代码
- 保持图标的视觉表现一致性

fix(device): 修复设备对话框标题和选项初始化问题

- 移除冗余的标题赋值操作
- 删除未使用的分类、状态和供应商选项属性
- 保留必要的表单重置和树形结构加载逻辑
2026-06-17 15:00:54 +08:00
c49c9229a8 refactor(device): 优化设备对话框组件并添加SVG图标
- 移除未使用的title、deviceCategories、statusFlagOptions和supplierListOptions变量
- 保留必要的deptOptions、locationOptions和unitCode相关变量
- 添加analyze.svg、approve-check.svg、assess.svg等多个SVG图标文件
- 新增图标包括审核、评估、认证等相关功能图标
- 优化组件代码结构,减少不必要的响应式数据声明
- 添加包装单位选项和加载状态管理功能
2026-06-17 14:54:21 +08:00
eccc0ec7cf refactor(device): 优化设备对话框组件并添加SVG图标
- 移除未使用的title、deviceCategories、statusFlagOptions和supplierListOptions变量
- 保留必要的deptOptions、locationOptions和unitCode相关变量
- 添加analyze.svg、approve-check.svg、assess.svg等多个SVG图标文件
- 新增图标包括审核、评估、认证等相关功能图标
- 优化组件代码结构,减少不必要的响应式数据声明
- 添加包装单位选项和加载状态管理功能
2026-06-17 14:54:14 +08:00
84c0f6a43d feat(mrhomepage): 死亡病例讨论记录 2026-06-17 14:50:25 +08:00
f1a8fafb72 feat(mrhomepage): 病案示踪管理 2026-06-17 14:46:17 +08:00
786fc14147 Merge remote-tracking branch 'origin/develop' into develop 2026-06-17 14:43:53 +08:00
5cd42a3253 feat(mrhomepage): 添加病历主页跟踪和借阅归还功能
- 新增trackStatus函数用于获取病历主页跟踪状态
- 新增borrowRecord函数用于记录病历借阅操作
- 新增returnRecord函数用于记录病历归还操作
2026-06-17 14:43:34 +08:00
b5f83b96e6 feat(icons): 添加多种SVG图标资源
- 新增amethyst.svg图标文件
- 新增ash.svg图标文件
- 新增aurora.svg图标文件
- 新增basalt.svg图标文件
- 新增beryl.svg图标文件
- 新增chalk.svg图标文件
- 新增citrine.svg图标文件
- 新增clay.svg图标文件
- 新增condensation.svg图标文件
- 新增coral.svg图标文件
- 新增crystal.svg图标文件
- 新增current.svg图标文件
- 新增dew.svg图标文件
- 新增diamond.svg图标文件
- 新增drop.svg图标文件
- 新增dust.svg图标文件
- 新增emerald.svg图标文件
- 新增fog.svg图标文件
- 新增frost.svg图标文件
- 新增garnet.svg图标文件
- 新增gem.svg图标文件
- 新增glint.svg图标文件
- 新增glow.svg图标文件
- 新增granite.svg图标文件
- 新增gravel.svg图标文件
- 新增halo.svg图标文件
- 新增haze.svg图标文件
2026-06-17 14:43:23 +08:00
9694184748 feat(icons): 添加天气和自然灾害相关的SVG图标
- 添加cloud-rain.svg云雨图标
- 添加cloud-sun.svg晴云图标
- 添加compost.svg堆肥图标
- 添加cyclone.svg气旋图标
- 添加drought.svg干旱图标
- 添加earthquake.svg地震图标
- 添加fertilizer.svg肥料图标
- 添加fire.svg火灾图标
- 添加flood.svg洪水图标
- 添加hurricane.svg飓风图标
- 添加land.svg土地图标
- 添加landslide.svg滑坡图标
- 添加lightning.svg闪电图标
- 添加mud.svg泥浆图标
- 添加plant.svg植物图标
- 添加rain.svg降雨图标
- 添加seed.svg种子图标
- 添加snow.svg降雪图标
- 添加soil.svg土壤图标
- 添加storm.svg风暴图标
- 添加sun.svg太阳图标
- 添加thunder.svg雷声图标
- 添加tornado.svg龙卷风图标
- 添加tsunami.svg海啸图标
- 添加typhoon.svg台风图标
- 添加vol
2026-06-17 14:37:26 +08:00
e7bdf4e5ac fix(#790): zhaoyun (文件合入) 2026-06-17 14:36:23 +08:00
0156884099 Merge remote-tracking branch 'origin/develop' into develop 2026-06-17 14:35:19 +08:00
d6e64e5019 feat(icons): 添加奖励和荣誉相关SVG图标
- 添加 accolade.svg 图标用于表彰功能
- 添加 achievement.svg 图标用于成就展示
- 添加 allowance.svg 图标用于津贴相关界面
- 添加 appreciate.svg 图标用于感谢和赞赏功能
- 添加 bloom.svg 图标用于成长和绽放主题
- 添加 blossom.svg 图标用于花朵绽放效果
- 添加 bounty.svg 图标用于奖励和赏金功能
- 添加 bouquet.svg 图标用于花束相关界面
- 添加 bud.svg 图标用于花蕾和新芽概念
- 添加 cape.svg 图标用于披风和特殊权限标识
- 添加 certificate-award.svg 图标用于证书和奖项
- 添加 champion.svg 图标用于冠军和优胜者标识
- 添加 commend.svg 图标用于表扬和推荐功能
- 添加 commendation.svg 图标用于嘉奖和赞扬
- 添加 crown.svg 图标用于皇冠和等级象征
- 添加 cultivate.svg 图标用于培育和种植功能
- 添加 distinction.svg 图标用于区分和卓越标识
- 添加 excellence.svg 图标用于优秀和杰出展示
- 添加 first-place.svg 图标用于第一名和获胜标识
- 添加 flourish.svg 图标用于繁荣和发展展示
- 添加 flower.svg 图标用于花朵和装饰元素
- 添加 gown.svg 图标用于礼服和正式场合
- 添加 grant.svg 图标用于资助和授予功能
- 添加 gratitude.svg 图标用于感恩和感谢展示
- 添加 growth.svg 图标用于成长和发育过程
- 添加 honor.svg 图标用于荣誉和尊敬标识
- 添加 laurel.svg 图标用于月桂叶和胜利象征
2026-06-17 14:34:51 +08:00
9ea5830095 feat(icons): 添加奖励和荣誉相关SVG图标
- 添加 accolade.svg 图标用于表彰功能
- 添加 achievement.svg 图标用于成就展示
- 添加 allowance.svg 图标用于津贴相关界面
- 添加 appreciate.svg 图标用于感谢和赞赏功能
- 添加 bloom.svg 图标用于成长和绽放主题
- 添加 blossom.svg 图标用于花朵绽放效果
- 添加 bounty.svg 图标用于奖励和赏金功能
- 添加 bouquet.svg 图标用于花束相关界面
- 添加 bud.svg 图标用于花蕾和新芽概念
- 添加 cape.svg 图标用于披风和特殊权限标识
- 添加 certificate-award.svg 图标用于证书和奖项
- 添加 champion.svg 图标用于冠军和优胜者标识
- 添加 commend.svg 图标用于表扬和推荐功能
- 添加 commendation.svg 图标用于嘉奖和赞扬
- 添加 crown.svg 图标用于皇冠和等级象征
- 添加 cultivate.svg 图标用于培育和种植功能
- 添加 distinction.svg 图标用于区分和卓越标识
- 添加 excellence.svg 图标用于优秀和杰出展示
- 添加 first-place.svg 图标用于第一名和获胜标识
- 添加 flourish.svg 图标用于繁荣和发展展示
- 添加 flower.svg 图标用于花朵和装饰元素
- 添加 gown.svg 图标用于礼服和正式场合
- 添加 grant.svg 图标用于资助和授予功能
- 添加 gratitude.svg 图标用于感恩和感谢展示
- 添加 growth.svg 图标用于成长和发育过程
- 添加 honor.svg 图标用于荣誉和尊敬标识
- 添加 laurel.svg 图标用于月桂叶和胜利象征
2026-06-17 14:34:45 +08:00
7b912ee96c fix(#784): guanyu (文件合入) 2026-06-17 14:31:26 +08:00
9d4c0b6b2a feat(quality): 病案终末质控 2026-06-17 14:29:42 +08:00
52377d7529 feat(icons): 添加医疗信息系统所需SVG图标
- 添加accelerate.svg加速功能图标
- 添加access-control.svg访问控制图标
- 添加accounting.svg会计功能图标
- 添加adjustment.svg调整功能图标
- 添加admission.svg入院功能图标
- 添加advise.svg咨询功能图标
- 添加affiliation.svg关联功能图标
- 添加agreement.svg协议功能图标
- 添加agreement-vote.svg协议投票图标
- 添加alert.svg警告功能图标
- 添加allergy.svg过敏功能图标
- 添加alliance.svg联盟功能图标
- 添加analytics.svg分析功能图标
- 添加anesthesia.svg麻醉功能图标
- 添加approval.svg审批功能图标
- 添加arbitration.svg仲裁功能图标
- 添加archive.svg归档功能图标
- 添加asset.svg资产功能图标
- 添加attendance.svg考勤功能图标
- 添加audit.svg审计功能图标
- 添加audit-log.svg审计日志图标
- 添加audit-report.svg审计报告图标
- 添加audit-trail.svg审计轨迹图标
- 添加backup.svg备份功能图标
- 添加band.svg标签
2026-06-17 14:27:45 +08:00
5100237faf fix(database): 修复数据库字典重复和表结构缺失问题
- 删除手术状态下拉框的重复字典数据,保留每组中dict_code最小的记录
- 修复HisBaseEntity列缺失问题,为多个表添加create_by、update_by、update_time等基础字段
- 为adm_patient表添加邮政编码、户籍地址、监护人信息、患者来源等缺失字段
- 添加文化程度字典类型和相关字典数据,补充3919到3914等10个学历级别选项
- 为adm_patient_identifier表创建tenant_id和patient_id的联合索引以提升查询性能
- 修复prescription_intercept_log和clinical_pathway_execution表的基础实体字段缺失
- 为wor_device_request表增加医嘱退回相关的back_reason、performer_check_id等字段
- 创建EMPI核心表empi_person和empi_person_id_mapping用于全局患者主
2026-06-17 14:27:36 +08:00
e344091a41 fix(database): 修复数据库字典重复和表结构缺失问题
- 删除手术状态下拉框的重复字典数据,保留每组中dict_code最小的记录
- 修复HisBaseEntity列缺失问题,为多个表添加create_by、update_by、update_time等基础字段
- 为adm_patient表添加邮政编码、户籍地址、监护人信息、患者来源等缺失字段
- 添加文化程度字典类型和相关字典数据,补充3919到3914等10个学历级别选项
- 为adm_patient_identifier表创建tenant_id和patient_id的联合索引以提升查询性能
- 修复prescription_intercept_log和clinical_pathway_execution表的基础实体字段缺失
- 为wor_device_request表增加医嘱退回相关的back_reason、performer_check_id等字段
- 创建EMPI核心表empi_person和empi_person_id_mapping用于全局患者主
2026-06-17 14:25:50 +08:00
73aa812544 fix(database): 修复数据库字典重复和表结构缺失问题
- 删除手术状态下拉框的重复字典数据,保留每组中dict_code最小的记录
- 修复HisBaseEntity列缺失问题,为多个表添加create_by、update_by、update_time等基础字段
- 为adm_patient表添加邮政编码、户籍地址、监护人信息、患者来源等缺失字段
- 添加文化程度字典类型和相关字典数据,补充3919到3914等10个学历级别选项
- 为adm_patient_identifier表创建tenant_id和patient_id的联合索引以提升查询性能
- 修复prescription_intercept_log和clinical_pathway_execution表的基础实体字段缺失
- 为wor_device_request表增加医嘱退回相关的back_reason、performer_check_id等字段
- 创建EMPI核心表empi_person和empi_person_id_mapping用于全局患者主
2026-06-17 14:25:32 +08:00
de6d6a2b51 fix(mrhomepage): 修复HQMS Mapper XML缺失 2026-06-17 14:19:47 +08:00
wangjian963
57d14603ee 669 [门诊医生站-中医处方] 中医处方头信息(费用性质、频次、天数、付数等)在保存并重新进入后回显为空 2026-06-17 14:16:07 +08:00
1df1f0d1ad feat(mrhomepage): HQMS首页上报 2026-06-17 14:14:45 +08:00
00604b2d01 feat(mrhomepage): 病案首页质量校验
- 新增 IMrHomepageQualityAppService + impl,实现 checkQuality/getQualityResults
- 新增 MrHomepageQualityController (POST /quality/check, GET /quality/results/{id})
- 增强 MrHomepageQualityCheckServiceImpl:必填项+逻辑校验+ICD编码+费用一致性
- 新增 MrHomepageQualityCheck.vue 校验结果展示页面
- 更新前端 API 文件添加 checkQuality/getQualityResults 接口
2026-06-17 14:02:42 +08:00
wangjian963
a58168c6de Merge remote-tracking branch 'origin/develop' into develop 2026-06-17 13:52:42 +08:00
wangjian963
7f1f3e1a3b 617 [住院登记] “费用性质”字段保存逻辑错误(登记选择医保保存后变为全自费 2026-06-17 13:52:20 +08:00
09e43e4b8c feat(emr): 病历时效监控 2026-06-17 13:47:02 +08:00
9673c0ed80 feat(emr): 病历完整性检查
- 创建 IEmrCompletenessAppService + impl,实现 checkCompleteness() 和 getCheckResults()
- 创建 EmrCompletenessController,POST /emr/completeness/check 和 GET /emr/completeness/results/{emrId}
- 新建 EmrCompletenessCheck.vue 检查结果展示 + 不合格项提醒
- 添加前端 API 函数 checkCompleteness / getCompletenessResults
2026-06-17 13:37:53 +08:00
f3a24a9129 feat(emr): 病历版本管理
- V64 Flyway迁移: emr_version表(不可删除, 三甲评审)
- EmrVersion实体: 版本号递增, 内容快照, 差异记录
- EmrVersionMapper + XML: selectByEmrId/selectLatest
- IEmrVersionService + impl: 基础CRUD
- IEmrVersionAppService + impl: saveVersion/getVersions/compareVersions
- EmrVersionController: POST /emr/version/save, GET /emr/version/list/{emrId}, GET /emr/version/compare
- 前端API: saveEmrVersion/getEmrVersionList/compareEmrVersions
- EmrVersionCompare.vue: 版本列表+对比视图
2026-06-17 13:28:34 +08:00
6184ed262f feat(emr): 病历修改留痕 — AppService/Controller/前端组件 2026-06-17 13:22:02 +08:00
f0d20a8d79 Merge remote-tracking branch 'origin/develop' into develop 2026-06-17 13:14:43 +08:00
694935b648 feat(anesthesia): 术后随访记录 2026-06-17 13:00:50 +08:00
Ranyunqiao
5801fec21c bug 789 2026-06-17 12:53:47 +08:00
b3800b7ae0 feat(anesthesia): 麻醉小结功能
- V63 Flyway migration: anes_summary table
- Entity, Mapper, Service, AppService, Controller
- POST /anesthesia/summary, GET /anesthesia/summary/{recordId}
- Frontend AnesthesiaSummary.vue with form and display
2026-06-17 12:53:11 +08:00
557263875b feat(anesthesia): 术中生命体征5min间隔监测 2026-06-17 12:48:18 +08:00
8adee630fb fix(anesthesia): 修复Mapper XML缺失+recordId硬编码 2026-06-17 12:40:11 +08:00
f444584908 feat(anesthesia): ASA麻醉评估 2026-06-17 12:35:45 +08:00
0ec77ab89c Merge remote-tracking branch 'origin/develop' into develop 2026-06-17 12:32:16 +08:00
e8356f5f83 fix(critical-value): 修复handler_id约束+补全update_time/update_by列 2026-06-17 12:30:07 +08:00
fc892e96dc feat(critical-value): 危急值处理记录闭环 2026-06-17 12:25:27 +08:00
58238e6b25 fix(#788): zhaoyun (文件合入) 2026-06-17 12:20:32 +08:00
f79c5a2c26 fix(clinical-pathway): 修复P0问题 - delete_flag/权限控制/缺失端点/tenant_id类型 2026-06-17 12:20:11 +08:00
815b80437e feat(clinical-pathway): 临床路径执行管理 2026-06-17 12:12:41 +08:00
4385472f26 fix(#778): zhaoyun (文件合入) 2026-06-17 12:07:15 +08:00
5ef05b9b55 fix(blood-transfusion): 修复P0/P1问题 - 字段映射/参数清理/tenant_id/Flyway版本 2026-06-17 12:02:38 +08:00
d7455684db feat(blood-transfusion): 输血管理全流程 2026-06-17 11:51:35 +08:00
d8e9da965b Merge remote-tracking branch 'origin/develop' into develop 2026-06-17 11:48:46 +08:00
575f5d6c32 fix(database): 修复数据库字典重复和表结构缺失问题
- 删除手术状态下拉框的重复字典数据,保留每组中dict_code最小的记录
- 修复HisBaseEntity列缺失问题,为多个表添加create_by、update_by、update_time等基础字段
- 为adm_patient表添加邮政编码、户籍地址、监护人信息、患者来源等缺失字段
- 添加文化程度字典类型和相关字典数据,补充3919到3914等10个学历级别选项
- 为adm_patient_identifier表创建tenant_id和patient_id的联合索引以提升查询性能
- 修复prescription_intercept_log和clinical_pathway_execution表的基础实体字段缺失
- 为wor_device_request表增加医嘱退回相关的back_reason、performer_check_id等字段
- 创建EMPI核心表empi_person和empi_person_id_mapping用于全局患者主索引管理
- 为empi_merge_log表添加create_time字段以完善审计信息
- 更新院感管理和评审保障模块的设计文档,明确各模块实现状态和缺失功能
2026-06-17 11:46:56 +08:00
3fd7862a85 fix(#778): zhaoyun (文件合入) 2026-06-17 11:45:45 +08:00
892890b59f fix(order-closed-loop): 修复P0问题 - deptId过滤/权限控制/死代码 2026-06-17 11:44:49 +08:00
621bc27267 Merge remote-tracking branch 'origin/develop' into develop 2026-06-17 11:43:18 +08:00
Ranyunqiao
62c1b4278b Merge remote-tracking branch 'origin/develop' into develop 2026-06-17 11:39:11 +08:00
Ranyunqiao
690486084e 112 【住院护士站-护理记录】功能重构升级(参考开源系统信创版本) 2026-06-17 11:38:41 +08:00
wangjian963
d792f03bbd fix(ui): 已登记入院表格事件修复与布局优化
- handleRadioChange({newValue}→{row}): 修复 vxe-table radio-change
    事件参数错误,selectedRow 始终为 undefined,打印住院证功能失效
  - queryParams 初始定义与 resetQuery 对齐,补全缺失字段
  - 表格布局重构:
    · 移除 height="100%"(解除横向滚动条位置漂移)
    · table min-width="1600px" + 容器 overflow-x:auto
    · 固定列 width / 信息列 min-width 差异化约束
2026-06-17 11:37:14 +08:00
6a4545c240 feat(order-closed-loop): 医嘱执行闭环追踪
- AppService: 添加 getTrace(adviceId) 查询医嘱全生命周期时间轴
- AppService: 添加 getStatisticsWithParams(deptId, startDate, endDate) 执行统计
- Controller: 添加 GET /trace/{adviceId} 和 GET /statistics/summary 端点
- 前端: 新建 OrderExecuteTrace.vue 时间轴视图 + 执行统计面板
- API: 添加 getOrderExecuteTrace 和 getExecuteStatistics 接口
2026-06-17 11:34:24 +08:00
a2e607caf4 chore(db): 移除多个数据库迁移脚本
- 移除患者管理字段缺失修复脚本 V2026_0608_1
- 移除文化程度字典类型添加脚本 V2026_0608_2
- 移除HisBaseEntity列缺失修复脚本 V2026_0608
- 移除处方拦截日志表修复脚本 V2026_0611
- 移除临床路径执行表修复脚本 V2026_0612
- 移除EMPI核心表创建脚本 V2026_0616_1
- 移除EMPI合并日志时间字段修复脚本 V2026_0616_2
- 移除手术状态字典重复数据修复脚本 V2026_0617
- 移除医嘱退回流程设备请求字段添加脚本 V20260615
2026-06-17 11:24:16 +08:00
wangjian963
cfc7ca9b4e 676 [住院医生站-临床医嘱] 勾选“待签发”临时医嘱后,点击【签发】按钮无响应 2026-06-17 11:13:11 +08:00
wangjian963
bdb7d978fb fix(ui): 修复住院医生站与护士站临床医嘱若干稳定性问题
医生站:
    - 修复类型切换后编辑表单残留、blur/click竞态致选中无效、批量保存缺patientId
    - 修复filterPrescriptionList.find过滤下展开失败、popover溢出、表格塌陷
    - 提取resolveCategoryCode/getAdviceTableRef消除重复, 优化adviceTableRef类型
    - 修复adviceBaseList keyField、选中残留、TS类型声明

  护士站:
    - 校对: 新增已执行状态判定+退回拦截, 修复状态标签颜色不一致
    - 执行: 修复长期医嘱dayTimes为空被静默丢弃
    - 双模块: 新增keep-alive重激活刷新+患者列表自动加载

  配置:
    - eslint.config.js 新增 @typescript-eslint/parser 支持Vue TS解析
2026-06-17 11:06:45 +08:00
5a227014fe fix(surgery): #684 手术状态下拉框重复 - 清理字典重复数据 2026-06-17 11:02:18 +08:00
1c68860541 ```
feat(patient): 移除门诊记录组件

- 删除了 OutpatientRecord.vue 组件文件
- 移除了门诊记录表格显示功能
- 清理了相关的数据获取和状态管理逻辑
- 移除了查看门诊详情的路由跳转功能
```
2026-06-17 10:40:34 +08:00
2a0303d0e6 fix(regdoctorstation): RegPrescriptionUtils groupingBy null key保护
Bug #674: 住院签发长期医嘱时 conditionDefinitionId/pharmacologyCategoryCode/therapyEnum 为 null
导致 Collectors.groupingBy 抛出 NPE 'element cannot be mapped to a null key'

修复:对齐门诊版 PrescriptionUtils 的 null 处理逻辑
- getConditionDefinitionId null -> 默认 0L
- getPharmacologyCategoryCode null -> 默认 '0'
- getTherapyEnum null -> 默认 0
- generatePrescriptionNo null/空 -> 走普通处方号
2026-06-17 09:32:46 +08:00
81d5c99a35 fix(#769): zhaoyun (文件合入) 2026-06-17 09:08:16 +08:00
8258d3e2da fix(#774): zhaoyun (文件合入) 2026-06-17 08:54:39 +08:00
3812561ede fix(#766): zhaoyun (文件合入) 2026-06-16 20:42:43 +08:00
wangjian963
48189a075f fix(智能分诊排队管理): 修复表格事件参数Bug及清理硬编码假数据和死代码
- 修复 cell-click 事件参数Bug:vxe-table 的 cell-click 回调为 { row, ... } 对象,
    未解构导致 selectedQueueRow 被赋值为事件对象,row.id 始终为 undefined,
    造成移出队列、选呼、上移/下移等所有操作报"缺少ID"
  - 修复 checkbox-change 事件参数Bug:同样需解构 { records } 才能获取选中数组,
    否则 selectedCandidates 为事件对象,"加入队列"按钮永久禁用
  - 移除候选池/队列硬编码假数据,ref 初始化为空数组,消除页面加载时的数据闪
  - 移除死代码:formatMinutesToMmSs、mapStatusToFrontend、
    getNextQueueOrder、recalculateQueueOrders
  - 修复 getRowClassName/canMoveUp/canMoveDown 使用 id 替代 queueOrder 匹配,
    避免不同诊室同序号误高亮/误判
  - 修复 filterTodayData:registerTime 缺失时保留数据而非全部丢弃
  - 移除候选池表格无用的 :row-config
2026-06-16 16:35:20 +08:00
wangjian963
c26b458298 Merge remote-tracking branch 'origin/develop' into develop 2026-06-16 16:21:58 +08:00
e38c5993a0 fix(#770): zhaoyun (文件合入) 2026-06-16 16:21:49 +08:00
Ranyunqiao
cb82f8d5bf bug 673 761 719 754 728 727 763 2026-06-16 16:16:09 +08:00
wangjian963
ea8dca058a fix(智能分诊排队管理): 移除候选池和队列的硬编码假数据,消除页面加载时的数据闪现问题
- 删除 getInitialCandidatePoolList() 和 getInitialQueueList() 两个硬编码函数(共8条虚构患者/队列记录)
  - 候选池和队列 ref 初始值由硬编码假数据改为空数组 []
  - currentDate 初始值由固定日期改为空字符串,由 loadDataFromApi 动态计算
  - currentCall 初始值由假数据(郑华/4号诊室)改为占位符(-/-/-),由 syncCurrentCallFromQueue 动态同步
  - loadDataFromApi 异常回退不再注入假数据,统一清空为 []
2026-06-16 16:15:13 +08:00
deb5683ca6 Merge remote-tracking branch 'origin/develop' into develop 2026-06-16 16:12:16 +08:00
c4ca097bf6 feat(menu): 添加用户可访问菜单树接口并优化界面展示
- 新增 /userMenus 接口供普通用户获取自身权限范围内的菜单树
- 修复菜单ID路径参数正则表达式匹配问题
- 优化门诊挂号患者列表表格列宽和滚动显示
- 更新患者主索引界面搜索表单和表格展示逻辑
- 调整挂号记录表格高度计算和列固定布局
- 更新未闭环医嘱统计界面提示信息和分页功能
- 修复用户医院名称获取逻辑优先级问题
- 添加EMPI合并日志创建时间字段迁移脚本
2026-06-16 16:08:40 +08:00
wangjian963
8b6265801d fix(门诊医生站): 修复中医tab页药品医嘱搜索选中后不填充及展开行不渲染的问题
vxe-table v4 中 expandRowKeys 仅在初始化时生效,后续变更必须通过实例方法
  setRowExpand/clearRowExpand 控制展开行。同时 vxe-table 浅监听 data prop,
  替换行对象引用会导致 slot scope 响应链路断裂。
2026-06-16 16:05:36 +08:00
wangjian963
bf5a9674df fix(门诊医生站): 修复中医诊断弹窗选择后诊断详情不显示的问题
- addDiagnosisDialog: 修复 vxe-table v4 cell-click 事件未解构 row 导致
    conditionName/syndromeName 为 undefined,右侧详情始终为空
  - diagnosislist: 新增 medTypeCode prop 按诊断类型过滤列表,避免中/西医错选
  - diagnosis: 保存时排除中医诊断(已通过独立接口保存),防止重复提交
2026-06-16 14:30:39 +08:00
954462272e feat(empi): 添加EMPI合并日志记录功能
- 引入EmpiMergeLog实体类和IEmpiMergeLogService服务接口
- 在EmpiAppServiceImpl中注入mergeLogService依赖
- 实现合并操作时自动创建合并日志记录
- 记录合并的源患者ID、目标患者ID和合并类型
- 添加合并原因、操作人和合并时间等关键信息
- 确保每次患者合并操作都有完整的审计日志
2026-06-16 14:10:37 +08:00
9a5d772c72 Merge remote-tracking branch 'origin/develop' into develop 2026-06-16 13:38:18 +08:00
d861c20d5e feat(empi): 实现EMPI患者主索引系统核心功能
- 新增EMPI核心数据表:empi_person和empi_person_id_mapping
- 实现EMPI服务层接口,支持患者注册、合并、查询等功能
- 集成EMPI与院内患者系统的双向关联查询
- 添加患者保存事件监听器,实现EMPI数据自动同步
- 开发EMPI管理界面,支持患者合并操作和数据展示
- 优化EMPI统计功能,增加重复率和待合并患者统计
- 完善EMPI ID映射机制,支持多系统患者标识关联
2026-06-16 13:38:05 +08:00
488573a51b fix(#663): guanyu (文件合入) 2026-06-16 13:37:38 +08:00
wangjian963
259a5946c2 667 [门诊收费-业务流程] 医嘱未挂钩【完诊】状态,医生未终结门诊即可提前在收费端结算,存在漏开/错开费用风险
- @select → @checkbox-change,适配新事件签名
  - 新增 collapseAllExpanded() 使用 setRowExpand/clearRowExpand 兼容 v4 expand
  - setNewRow/setValue 保持行引用不变,原地更新数据
  - 所有医嘱类型编辑模板新增"取消"按钮
  - 内联布局样式抽取为 .edit-form-row 类,四种医嘱类型布局统一
  - 列宽、间距、备注框宽度等样式微调
  - requiredProps 空安全检查、handleBlur 修复、ref 名称修复
2026-06-16 13:33:42 +08:00
d0d6cf3533 fix(#770): zhaoyun (文件合入) 2026-06-16 13:30:49 +08:00
Ranyunqiao
fef1ca6637 Merge remote-tracking branch 'origin/develop' into develop 2026-06-16 13:06:40 +08:00
Ranyunqiao
fca3d0ca86 style: add el-tag styling to order status in transfer out list to match doctor station 2026-06-16 12:34:30 +08:00
193a08acbd fix(#776): guanyu (文件合入) 2026-06-16 12:01:52 +08:00
Ranyunqiao
41d05a1629 fix(ui): use dict text from frontend for accurate display of frequency, usage, amount, dose and ordering doctor 2026-06-16 11:55:41 +08:00
wangjian963
8cfa6fe05e fix(门诊医生站-医嘱列表): vxe-table v4适配及编辑区UI优化
- @select → @checkbox-change,适配新事件签名
  - 新增 collapseAllExpanded() 使用 setRowExpand/clearRowExpand 兼容 v4 expand
  - setNewRow/setValue 保持行引用不变,原地更新数据
  - 所有医嘱类型编辑模板新增"取消"按钮
  - 内联布局样式抽取为 .edit-form-row 类,四种医嘱类型布局统一
  - 列宽、间距、备注框宽度等样式微调
  - requiredProps 空安全检查、handleBlur 修复、ref 名称修复
2026-06-16 11:52:11 +08:00
wangjian963
8eb6feb70d 修复门诊医生站,医嘱tab表格布局错误问题。 2026-06-16 10:35:09 +08:00
Ranyunqiao
f93bec967a Merge remote-tracking branch 'origin/develop' into develop 2026-06-16 10:21:42 +08:00
Ranyunqiao
020d1be4be bug 716 718 2026-06-16 10:21:26 +08:00
wangjian963
f7f037aee9 656 [门诊医生站-检查申请] 单击已保存记录回显异常:自动跳转页签错误且“检查方法”数据未回显 2026-06-16 10:14:56 +08:00
6c77ee8f84 fix(#776): guanyu (文件合入) 2026-06-16 09:38:40 +08:00
0855d1153b fix(#776): guanyu (文件合入) 2026-06-16 08:50:32 +08:00
wangjian963
168961e656 654
[住院医生站-手术申请] 申请单保存成功后弹窗未自动关闭
2026-06-15 17:14:46 +08:00
wangjian963
9dc4a12339 Merge remote-tracking branch 'origin/develop' into develop 2026-06-15 16:55:47 +08:00
wangjian963
9bbf7c6c08 651 [住院医生站-手术申请] 无法检索出已启用的手术项目(如:“血管闭合切割刀”) 2026-06-15 16:55:17 +08:00
05088a1d1a fix(#734): guanyu (文件合入) 2026-06-15 16:53:01 +08:00
Ranyunqiao
5e9dbb2f1b Merge remote-tracking branch 'origin/develop' into develop 2026-06-15 16:48:48 +08:00
Ranyunqiao
b25d2fbaa9 bug 588 628 642 700 714 715 2026-06-15 16:48:27 +08:00
690e7ca22c fix(charge): 门诊日结 groupingBy null key 修复
Collectors.groupingBy 遇到 contractNo/busNo 为 null 的元素会抛
NullPointerException: Element cannot be mapped to a null key

修复: 在 groupingBy 前增加 .filter(e -> key != null && !key.isEmpty())
2026-06-15 16:47:44 +08:00
43ab5b4498 fix(flyway): 解除 V42 版本号冲突
merge PR #11 时带入 guanyu commit 01e8cc459 错误恢复的已废弃 V42__bug745
文件(该文件内容本已迁移到 V45,原 V42 应删除)。两个 V42 并存导致 Flyway
启动阻塞:"Found more than one migration with version 42"。

修复:删除冗余的 V42__bug745_fix_mr_sealing_medical_record_id.sql(空 deprecated
文件,实际逻辑在 V45)。保留 V42__add_delete_flag_columns.sql(原始文件,2026-06-11)。

验证:
- mvn clean package 通过
- 后端启动成功(HTTP 404 根路径,Flyway 无冲突)
- 登录 API + 门诊收费列表 API 正常响应
- Jackson 3 Long→String 序列化仍生效
2026-06-15 16:18:00 +08:00
219ac30dc5 fix(#763): guanyu (文件合入) 2026-06-15 15:46:59 +08:00
20f71ec5d9 Merge PR #11: refactor(jackson): Jackson 2 → 3 全项目迁移 2026-06-15 15:43:23 +08:00
601be0d66b style(App): 统一代码风格和导入语句格式
- 调整 import 语句的格式,统一使用分号结尾
- 规范化 handleThemeStyle 函数导入的括号和空格
- 在 handleThemeStyle 函数调用后添加分号
- 为 nextTick 回调函数末尾添加分号
- 移除文件末尾的多余空行
2026-06-15 15:40:27 +08:00
e825f5fb33 test(e2e): 清理 debug 测试 + 修 bug-630 端口 + 新增 #681 E2E
- 删除开发遗留的 debug 测试文件:
  - debug-console.spec.ts
  - debug-login.spec.ts
  - debug-page.spec.ts
- bug-630.spec.ts: 后端端口 18082 → 18080(匹配 application.yml)
- 新增 bug-681-e2e.spec.ts: 真实登录+fetch+proxy 混合 E2E
  验证 Jackson 3 迁移后 Long 字段以字符串形式返回
2026-06-15 15:40:27 +08:00
97827b6ff0 refactor(jackson): Jackson 2 → Jackson 3 全项目迁移
Spring Boot 4.0.6 默认引入 Jackson 3.1.2,但项目中 1018 处 @JsonSerialize
注解使用的是 Jackson 2 的 com.fasterxml.jackson.* 包,导致注解被忽略,
Long 字段序列化为裸数字,引发前端 JS Number 精度丢失(Bug #681 的根因)。

- com.fasterxml.jackson.databind.* → tools.jackson.databind.*
- com.fasterxml.jackson.core.* → tools.jackson.core.*
- com.fasterxml.jackson.annotation.* 保留(Jackson 3 仍用同包名)
- com.fasterxml.jackson.datatype.jsr310.* 保留(不再需要,Jackson 3 内置 JavaTime 支持)

- JsonSerializer<T> → ValueSerializer<T>
- JsonDeserializer<T> → ValueDeserializer<T>
- SerializerProvider → SerializationContext
- JsonMappingException → DatabindException
- JsonProcessingException → JacksonException(变 RuntimeException)
- ContextualSerializer → 合并入 ValueSerializer(createContextual 成 default 方法)
- LaissezFaireSubTypeValidator → BasicPolymorphicTypeValidator.builder()
- Jackson2ObjectMapperBuilderCustomizer → JsonMapperBuilderCustomizer

- ObjectMapper.configure() 返回 void → JsonMapper.builder().disable(...).build()
- ObjectMapper.setPropertyNamingStrategy() → JsonMapper.builder().propertyNamingStrategy()
- ObjectMapper.setDateFormat() → JsonMapper.builder().defaultDateFormat()
- ObjectNode.fieldNames() → JsonNode.propertyNames()(返回 Collection<String>)
- SerializationFeature.WRITE_DATES_AS_TIMESTAMPS 已移除(JavaTime 自动处理)
- ObjectMapper 的 JavaTimeModule 注册不再需要(Jackson 3 内置)

- core-framework/.../ApplicationConfig.java:重写为 JsonMapperBuilderCustomizer +
  自定义 LocalDateTime 序列化(Jackson 3 内置 ext.javatime.*)
- core-framework/.../FastJson2JsonRedisSerializer.java:用 BasicPolymorphicTypeValidator
  替代 LaissezFaireSubTypeValidator
- core-common/.../JsonUtils.java:改为 JsonMapper.builder() 模式
- core-common/.../SensitiveJsonSerializer.java:JsonSerializer → ValueSerializer

- 5 个模块 jackson-databind groupId 改为 tools.jackson.core(版本由 Spring Boot BOM 管理)
- jackson-annotations 保留 com.fasterxml.jackson.core(Jackson 3 仍用同包名)

-  mvn compile 全 11 模块通过
-  mvn package 成功生成 fat JAR
-  后端启动正常(JDK 25,Spring Boot 4.0.6)
-  登录 API 返回 JWT token
-  /charge-manage/charge/encounter-patient-page 响应:
    - encounterId: "2032288214655660033"(字符串,@JsonSerialize 生效)
    - patientId: "2026486681850499074"(字符串,@JsonSerialize 生效)
-  Bug #681 根因彻底解决(Long 精度丢失)

- Bug #681(前端兜底 fix: acf685fba)+ 本 commit(后端根治)
- Bug #281(历史 jsr310 模块问题)随 Jackson 3 内置 JavaTime 一并解决

- Playwright E2E 全量回归(51 个 spec)
- 时间字段序列化专项测试(LocalDateTime 格式验证)
- 删除 Jackson 2 starter(spring-boot-jackson2)的可行性评估
2026-06-15 15:40:26 +08:00
01e8cc459c fix(#748): guanyu (文件合入) 2026-06-15 15:37:12 +08:00
wangjian963
cc7c669fc1 Merge remote-tracking branch 'origin/develop' into develop 2026-06-15 15:28:05 +08:00
wangjian963
5c73cc6987 fix(#643): 门诊手术安排-术中医嘱删除改为状态回退,修复刷新后医嘱重现
- 前端:删除操作改为 UPDATE 状态回退(statusEnum ACTIVE→DRAFT),清除签发人/签发时间
  - 后端:回退时跳过发放/计费/绑耗逻辑,清除 signCode,回退 chargeItem 状态为 DRAFT
  - 后端:回退时保持原始 generateSourceEnum,避免刷新查询不到记录
  - 安全:回退前校验 encounterId 所有权,防止跨就诊 IDOR
2026-06-15 15:27:31 +08:00
cb792684e2 Merge branch 'develop' of https://gitea.gentronhealth.com/wangyizhe/his into develop 2026-06-15 15:22:50 +08:00
871690848e fix(#738): guanyu (文件合入) 2026-06-15 15:18:48 +08:00
17616a32cb fix(#749): guanyu (文件合入) 2026-06-15 15:01:52 +08:00
wangjian963
2609791b62 637 [住院护士站-体温单] 选中患者后系统上下文不同步,导致无法触发“变更体温单”录入弹窗 2026-06-15 14:29:40 +08:00
wangjian963
c7ae277613 fix(#773): 门诊医生工作站新增医嘱单次剂量/总量列缺min-width导致输入框重叠
vxe-table中"单次剂量"和"总量"两个vxe-column未设置min-width,
  其他13列均为固定宽度,剩余空间不足导致编辑模式下el-input-number
  与单位文本溢出到相邻列。添加min-width="130"和min-width="110"修复。
2026-06-15 14:15:16 +08:00
wangjian963
6882085d69 fix(#613): 医嘱退回流程增加退回原因录入与展示
护士端退回操作已有退回原因弹窗(prescriptionList.vue),本次主要补齐:

  后端:
  - DeviceRequest 实体新增 backReason/performerCheckId/checkTime 三个字段
  - IDeviceRequestService/Impl 新增含退回信息的 updateDraftStatusBatch 重载
  - AdviceProcessAppServiceImpl 退回耗材医嘱时传入退回原因/护士/时间
  - InpatientAdviceDto 新增 reasonText/checkTime 字段
  - AdviceProcessAppMapper.xml(护士站查询):3路 UNION ALL 均新增 reason_text + check_time
  - AdviceManageAppMapper.xml(医生站查询):3路 UNION ALL 均新增 reason_text

  前端:
  - 住院医生站 order/index.vue:医嘱列表新增"退回原因"列(诊断列前面)
  - 住院护士站 prescriptionList.vue:医嘱列表新增"退回原因"列

  数据库:
  - V20260615__bug613_add_return_fields_to_device_request.sql:wor_device_request 表新增 3 列
2026-06-15 14:04:52 +08:00
Ranyunqiao
b1391afcd8 bug 657 713 2026-06-15 13:30:20 +08:00
d12b77f81a test(#681): 添加 Playwright E2E 验证 clickRow 兜底逻辑
- 6 种场景:有 encounterId / 仅 id(兜底)/ 全无 / undefined / null / 空串
- 修复前会发出 encounterId=undefined 请求(复现 bug)
- 修复后所有缺失场景触发 msgError 而非发请求
- Playwright + Vitest 全绿(51/51 + 2/2)
2026-06-15 12:43:13 +08:00
acf685fbaf fix(#681): 门诊收费点击已收费患者增加 encounterId 兜底
- 问题:已收费列表点击患者行时报错"参数[encounterId]要求类型为
  Long,但输入值为'undefined'",导致右侧基本信息为空、收费项目一直 Loading
- 根因:row.encounterId 为 undefined 时直接拼入 URL,后端类型校验拒绝
- 修复:clickRow 加 encounterId ?? id 兜底;无 ID 时 msgError 提示并中止调用;
  同步写入 patientInfo.value 防止 handleClose/confirmCharge/changePayType 等
  后续路径再次读到 undefined
- 风格对齐 clinicrefund/index.vue、outpatientregistration/reprintDialog.vue
  已有的 encounterId || id 防御模式
- 编译:npm run build:dev ✓
2026-06-15 12:24:45 +08:00
wangjian963
dfce7d0332 606 门诊术中安排-医嘱】预览列表字段显示及逻辑异常(涉及单位、频次、执行时间) 2026-06-15 11:44:39 +08:00
1657 changed files with 62259 additions and 12320 deletions

View File

@@ -47,7 +47,7 @@
**铁律2: Flyway 数据库迁移** **铁律2: Flyway 数据库迁移**
- 凡是新建表、新增字段,必须创建 Flyway 迁移脚本 - 凡是新建表、新增字段,必须创建 Flyway 迁移脚本
- 路径:`healthlink-his-domain/src/main/resources/db/migration/` - 路径:`healthlink-his-application/src/main/resources/db/migration/`
- 命名:`V{版本号}__{描述}.sql`(双下划线) - 命名:`V{版本号}__{描述}.sql`(双下划线)
**铁律3: 测试通过后才提交** **铁律3: 测试通过后才提交**
@@ -184,7 +184,7 @@
**铁律2: Flyway 数据库迁移** **铁律2: Flyway 数据库迁移**
- 凡是新建表、新增字段,必须创建 Flyway 迁移脚本 - 凡是新建表、新增字段,必须创建 Flyway 迁移脚本
- 路径:`healthlink-his-domain/src/main/resources/db/migration/` - 路径:`healthlink-his-application/src/main/resources/db/migration/`
- 命名:`V{版本号}__{描述}.sql`(双下划线) - 命名:`V{版本号}__{描述}.sql`(双下划线)
**铁律3: 测试通过后才提交** **铁律3: 测试通过后才提交**

View 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 检验系统LIS3项缺失
| # | 缺失能力 | 三甲依据 | 实现方案 | 预估工时 |
|---|---------|---------|---------|:-------:|
| 24 | **室内质控(Westgard规则)** | 质量管理 | 质控图+Westgard规则+失控处理 | 3天 |
| 25 | **室间质评** | 质量管理 | 参加省级/国家级室间质评 | 2天 |
| 26 | **检验报告标准格式打印** | 基本功能规范 | 标准检验报告单模板 | 1天 |
**小计**: 6天
### 2.7 检查系统PACS4项缺失
| # | 缺失能力 | 三甲依据 | 实现方案 | 预估工时 |
|---|---------|---------|---------|:-------:|
| 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-44周
**目标**: 补齐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-84周
**目标**: 补齐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-124周
**目标**: 补全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-153周
**目标**: 满足广西地方要求
```
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 开发

Binary file not shown.

View 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 R4CDA文档代码映射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 元/人天*

Binary file not shown.

Binary file not shown.

View 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 选型 | 信创优势 |
|--------|:------------------:|---------|
| **开发语言** | JavaSpring 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 芯片** | 鲲鹏 920ARM、飞腾 S2500/S5000CARM、海光x86 | ✅ 兼容 |
| **操作系统** | 银河麒麟 V10/V11、统信 UOS V20、openEuler 22.03+ | ✅ 兼容 |
| **数据库** | PostgreSQL当前、openGauss、达梦 DM8、人大金仓 KingbaseES V8 | ✅ 兼容 |
| **中间件** | 内嵌 Spring BootTomcat、可适配东方通 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)

Binary file not shown.

View 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 菜单调整,不涉及代码改动,可随时回滚。

View File

@@ -1,7 +1,7 @@
# HealthLink-HIS 代码模块索引 # HealthLink-HIS 代码模块索引
> 供 LLM 快速定位代码。每个模块列出 Controller → Service → Mapper 关键文件。 > 供 LLM 快速定位代码。每个模块列出 Controller → Service → Mapper 关键文件。
> 最后更新: 2026-06-15 06:00 (298 个 Controller) > 最后更新: 2026-06-17 18:00 (309 个 Controller)
## 关键词 → 模块速查 ## 关键词 → 模块速查

70
MD/bugs/BUG_ANALYSIS.md Executable file
View 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. 张飞测试验证

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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 是一款面向三级甲等综合医院的综合信息管理系统,覆盖门诊、住院、手术、药房、检验检查、医保对接等核心业务场景。*
*了解更多:[联系方式]*

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

View 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

Binary file not shown.

View File

@@ -40,7 +40,7 @@
**铁律2: Flyway 数据库迁移** **铁律2: Flyway 数据库迁移**
- 凡是新建表、新增字段,必须创建 Flyway 迁移脚本 - 凡是新建表、新增字段,必须创建 Flyway 迁移脚本
- 路径:`healthlink-his-domain/src/main/resources/db/migration/` - 路径:`healthlink-his-application/src/main/resources/db/migration/`
- 命名:`V{版本号}__{描述}.sql`(双下划线) - 命名:`V{版本号}__{描述}.sql`(双下划线)
**铁律3: 测试通过后才提交** **铁律3: 测试通过后才提交**

View File

@@ -40,7 +40,7 @@
**铁律2: Flyway 数据库迁移** **铁律2: Flyway 数据库迁移**
- 凡是新建表、新增字段,必须创建 Flyway 迁移脚本 - 凡是新建表、新增字段,必须创建 Flyway 迁移脚本
- 路径:`healthlink-his-domain/src/main/resources/db/migration/` - 路径:`healthlink-his-application/src/main/resources/db/migration/`
- 命名:`V{版本号}__{描述}.sql`(双下划线) - 命名:`V{版本号}__{描述}.sql`(双下划线)
**铁律3: 测试通过后才提交** **铁律3: 测试通过后才提交**

View File

@@ -26,6 +26,18 @@ public class SysMenuController extends BaseController {
@Autowired @Autowired
private ISysMenuService menuService; 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')") @PreAuthorize("@ss.hasPermi('system:menu:query')")
@GetMapping(value = "/{menuId}") @GetMapping(value = "/{menuId:\\d+}")
public AjaxResult getInfo(@PathVariable Long menuId) { public AjaxResult getInfo(@PathVariable Long menuId) {
return success(menuService.selectMenuById(menuId)); return success(menuService.selectMenuById(menuId));
} }

View File

@@ -110,9 +110,9 @@
</dependency> </dependency>
<!-- JSONå÷ååââ¬Â¦Ã·Ã§Ã±Ã» --> <!-- JSONå÷ååââ¬Â¦Ã·Ã§Ã±Ã» -->
<!-- JSON工具类 --> <!-- JSON工具类 -->
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>tools.jackson.core</groupId>
<artifactId>jackson-databind</artifactId> <artifactId>jackson-databind</artifactId>
</dependency> </dependency>

View File

@@ -3,7 +3,7 @@ package com.core.common.annotation;
import com.core.common.config.serializer.SensitiveJsonSerializer; import com.core.common.config.serializer.SensitiveJsonSerializer;
import com.core.common.enums.DesensitizedType; import com.core.common.enums.DesensitizedType;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; 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.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;

View File

@@ -4,14 +4,13 @@ import com.core.common.annotation.Sensitive;
import com.core.common.core.domain.model.LoginUser; import com.core.common.core.domain.model.LoginUser;
import com.core.common.enums.DesensitizedType; import com.core.common.enums.DesensitizedType;
import com.core.common.utils.SecurityUtils; import com.core.common.utils.SecurityUtils;
import com.fasterxml.jackson.core.JsonGenerator; import tools.jackson.core.JacksonException;
import com.fasterxml.jackson.databind.BeanProperty; import tools.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonMappingException; import tools.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonSerializer; import tools.jackson.databind.DatabindException;
import com.fasterxml.jackson.databind.SerializerProvider; import tools.jackson.databind.ValueSerializer;
import com.fasterxml.jackson.databind.ser.ContextualSerializer; import tools.jackson.databind.SerializationContext;
import java.io.IOException;
import java.util.Objects; import java.util.Objects;
/** /**
@@ -19,11 +18,11 @@ import java.util.Objects;
* *
* @author system * @author system
*/ */
public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer { public class SensitiveJsonSerializer extends ValueSerializer<String> {
private DesensitizedType desensitizedType; private DesensitizedType desensitizedType;
@Override @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()) { if (desensitization()) {
gen.writeString(desensitizedType.desensitizer().apply(value)); gen.writeString(desensitizedType.desensitizer().apply(value));
} else { } else {
@@ -32,14 +31,14 @@ public class SensitiveJsonSerializer extends JsonSerializer<String> implements C
} }
@Override @Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) public ValueSerializer<?> createContextual(SerializationContext prov, BeanProperty property)
throws JsonMappingException { throws DatabindException {
Sensitive annotation = property.getAnnotation(Sensitive.class); Sensitive annotation = property.getAnnotation(Sensitive.class);
if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) { if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) {
this.desensitizedType = annotation.desensitizedType(); this.desensitizedType = annotation.desensitizedType();
return this; return this;
} }
return prov.findValueSerializer(property.getType(), property); return prov.findPrimaryPropertySerializer(property.getType(), property);
} }
/** /**

View File

@@ -9,8 +9,8 @@ import com.core.common.annotation.Excel.Type;
import com.core.common.annotation.Excels; import com.core.common.annotation.Excels;
import com.core.common.core.domain.BaseEntity; import com.core.common.core.domain.BaseEntity;
import com.core.common.xss.Xss; import com.core.common.xss.Xss;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;

View File

@@ -1,9 +1,9 @@
package com.core.common.filter; package com.core.common.filter;
import com.fasterxml.jackson.annotation.JsonFilter; import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.databind.ser.FilterProvider; import tools.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; import tools.jackson.databind.ser.std.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; import tools.jackson.databind.ser.std.SimpleFilterProvider;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import java.util.HashSet; import java.util.HashSet;

View File

@@ -1,7 +1,7 @@
package com.core.common.utils; package com.core.common.utils;
import com.fasterxml.jackson.core.type.TypeReference; import tools.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import tools.jackson.databind.ObjectMapper;
import com.core.common.constant.CacheConstants; import com.core.common.constant.CacheConstants;
import com.core.common.core.domain.entity.SysDictData; import com.core.common.core.domain.entity.SysDictData;
import com.core.common.core.redis.RedisCache; import com.core.common.core.redis.RedisCache;

View File

@@ -1,11 +1,12 @@
package com.core.common.utils; package com.core.common.utils;
import com.fasterxml.jackson.core.JsonProcessingException; import tools.jackson.core.JacksonException;
import com.fasterxml.jackson.core.type.TypeReference; import tools.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature; import tools.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode; import tools.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import tools.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature; import tools.jackson.databind.SerializationFeature;
import tools.jackson.databind.json.JsonMapper;
/** /**
* Jackson JSON 工具类 * Jackson JSON 工具类
@@ -13,12 +14,10 @@ import com.fasterxml.jackson.databind.SerializationFeature;
* @author system * @author system
*/ */
public class JsonUtils { public class JsonUtils {
private static final ObjectMapper MAPPER = new ObjectMapper(); private static final ObjectMapper MAPPER = JsonMapper.builder()
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
static { .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); .build();
MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
}
public static ObjectMapper getMapper() { public static ObjectMapper getMapper() {
return MAPPER; return MAPPER;
@@ -27,7 +26,7 @@ public class JsonUtils {
public static String toJson(Object obj) { public static String toJson(Object obj) {
try { try {
return MAPPER.writeValueAsString(obj); return MAPPER.writeValueAsString(obj);
} catch (JsonProcessingException e) { } catch (JacksonException e) {
return "{}"; return "{}";
} }
} }

View File

@@ -1,8 +1,8 @@
package com.core.common.utils.ip; 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.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.config.CoreConfig;
import com.core.common.constant.Constants; import com.core.common.constant.Constants;
import com.core.common.utils.StringUtils; import com.core.common.utils.StringUtils;

View File

@@ -34,7 +34,7 @@
<!-- JSON工具类 --> <!-- JSON工具类 -->
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>tools.jackson.core</groupId>
<artifactId>jackson-databind</artifactId> <artifactId>jackson-databind</artifactId>
</dependency> </dependency>

View File

@@ -1,11 +1,11 @@
package com.core.flowable.service.impl; package com.core.flowable.service.impl;
import com.core.common.utils.JsonUtils; import com.core.common.utils.JsonUtils;
import com.fasterxml.jackson.databind.ObjectMapper; import tools.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode; import tools.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ArrayNode; import tools.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.JsonNode; import tools.jackson.databind.JsonNode;
import com.fasterxml.jackson.core.type.TypeReference; import tools.jackson.core.type.TypeReference;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.core.domain.AjaxResult; import com.core.common.core.domain.AjaxResult;
import com.core.common.core.domain.entity.SysRole; import com.core.common.core.domain.entity.SysRole;

View File

@@ -1,6 +1,6 @@
package com.core.framework.aspectj; 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.utils.JsonUtils;
import com.core.common.annotation.Log; import com.core.common.annotation.Log;
import com.core.common.core.domain.entity.SysUser; import com.core.common.core.domain.entity.SysUser;

View File

@@ -1,51 +1,77 @@
package com.core.framework.config; 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.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.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.EnableAspectJAutoProxy;
import 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.io.IOException;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.TimeZone;
@Configuration @Configuration
@EnableAspectJAutoProxy(exposeProxy = true) @EnableAspectJAutoProxy(exposeProxy = true)
@MapperScan({"com.core.**.mapper", "com.healthlink.his.**.mapper"}) @MapperScan({"com.core.**.mapper", "com.healthlink.his.**.mapper"})
public class ApplicationConfig { public class ApplicationConfig {
private static final JsonDeserializer<LocalDateTime> LOCAL_DATE_TIME_DESERIALIZER = new JsonDeserializer<>() { 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 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 SLASH_FORMATTER = DateTimeFormatter.ofPattern("yyyy/M/d HH:mm:ss");
@Override private static final ValueDeserializer<LocalDateTime> LOCAL_DATE_TIME_DESERIALIZER =
public LocalDateTime deserialize(JsonParser p, DeserializationContext context) throws IOException { new ValueDeserializer<LocalDateTime>() {
String text = p.getText(); @Override
if (text == null || text.isEmpty()) return null; public LocalDateTime deserialize(JsonParser p, DeserializationContext context) throws JacksonException {
String cleaned = text.replaceAll("[Zz]$", "").replaceAll("[+-]\\d{2}:?\\d{2}$", ""); String text = p.getText();
try { return LocalDateTime.parse(cleaned, ISO_FORMATTER); } catch (Exception ignored) {} if (text == null || text.isEmpty()) return null;
try { return LocalDateTime.parse(cleaned, SIMPLE_FORMATTER); } catch (Exception ignored) {} String cleaned = text.replaceAll("[Zz]$", "").replaceAll("[+-]\\d{2}:?\\d{2}$", "");
return LocalDateTime.parse(cleaned, SLASH_FORMATTER); 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 @Bean
public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() { public JsonMapperBuilderCustomizer jacksonObjectMapperCustomization() {
return builder -> { return builder -> {
builder.timeZone(TimeZone.getDefault()); builder.defaultTimeZone(TimeZone.getDefault());
builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss"); builder.defaultDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
JavaTimeModule javaTimeModule = new JavaTimeModule(); SimpleModule module = new SimpleModule("HealthLinkLocalDateTime");
javaTimeModule.addDeserializer(LocalDateTime.class, LOCAL_DATE_TIME_DESERIALIZER); module.addDeserializer(LocalDateTime.class, LOCAL_DATE_TIME_DESERIALIZER);
builder.modules(javaTimeModule); module.addSerializer(LocalDateTime.class, LOCAL_DATE_TIME_SERIALIZER);
builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); 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);
}; };
} }
} }

View File

@@ -1,7 +1,10 @@
package com.core.framework.config; package com.core.framework.config;
import com.fasterxml.jackson.databind.ObjectMapper; import tools.jackson.databind.DefaultTyping;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; 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.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.annotation.PropertyAccessor;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -10,16 +13,17 @@ import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException; import org.springframework.data.redis.serializer.SerializationException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
/** /**
* Redis序列化器 - 兼容fastjson2旧格式 * Redis序列化器 - 兼容fastjson2旧格式Jackson 3 迁移版)
* *
* @author system * @author system
*/ */
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> { public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {
private static final Logger log = LoggerFactory.getLogger(FastJson2JsonRedisSerializer.class); 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) */ /** 新格式: 带类型信息 (activateDefaultTyping) */
private final ObjectMapper typedMapper; private final ObjectMapper typedMapper;
@@ -31,16 +35,21 @@ public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {
super(); super();
this.clazz = clazz; this.clazz = clazz;
// Jackson 3: 用 BasicPolymorphicTypeValidator 替代 LaissezFaireSubTypeValidator
PolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator.builder()
.allowIfBaseType(Object.class)
.build();
// 新格式 ObjectMapper (带类型信息) // 新格式 ObjectMapper (带类型信息)
this.typedMapper = new ObjectMapper(); this.typedMapper = JsonMapper.builder()
this.typedMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); .changeDefaultVisibility(vc -> vc.withVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY))
this.typedMapper.activateDefaultTyping( .activateDefaultTyping(ptv, DefaultTyping.NON_FINAL)
LaissezFaireSubTypeValidator.instance, .build();
ObjectMapper.DefaultTyping.NON_FINAL);
// 旧格式 ObjectMapper (不带类型信息) // 旧格式 ObjectMapper (不带类型信息)
this.plainMapper = new ObjectMapper(); this.plainMapper = JsonMapper.builder()
this.plainMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); .changeDefaultVisibility(vc -> vc.withVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY))
.build();
} }
@Override @Override
@@ -75,4 +84,4 @@ public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {
return null; return null;
} }
} }
} }

View File

@@ -2,8 +2,10 @@ package com.core.framework.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature; import tools.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper; import tools.jackson.databind.JsonNode;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.json.JsonMapper;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer;
@@ -12,7 +14,7 @@ import org.springframework.data.redis.serializer.SerializationException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
/** /**
* Jackson Redis序列化器 - 兼容fastjson旧格式 * Jackson Redis序列化器 - 兼容fastjson旧格式Jackson 3 迁移版)
* *
* 新数据: 纯JSON (无类型包装),调用方用 convertValue 转换 * 新数据: 纯JSON (无类型包装),调用方用 convertValue 转换
* 旧fastjson: 去除L后缀后按JSON解析 * 旧fastjson: 去除L后缀后按JSON解析
@@ -30,10 +32,10 @@ public class FastjsonCompatibleRedisSerializer implements RedisSerializer<Object
} }
private static ObjectMapper createMapper() { private static ObjectMapper createMapper() {
ObjectMapper mapper = new ObjectMapper(); return JsonMapper.builder()
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); .changeDefaultVisibility(vc -> vc.withVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY))
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
return mapper; .build();
} }
/** 获取共享ObjectMapper供 DictUtils / TokenService 等做 convertValue */ /** 获取共享ObjectMapper供 DictUtils / TokenService 等做 convertValue */
@@ -64,7 +66,7 @@ public class FastjsonCompatibleRedisSerializer implements RedisSerializer<Object
try { try {
// 处理旧Jackson activateDefaultTyping格式: ["className", {data}] // 处理旧Jackson activateDefaultTyping格式: ["className", {data}]
if (cleaned.startsWith("[\"") && cleaned.length() > 10) { 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()) { if (node.isArray() && node.size() >= 2 && node.get(0).isTextual()) {
// 取data部分第2个元素忽略className // 取data部分第2个元素忽略className
return objectMapper.treeToValue(node.get(1), Object.class); return objectMapper.treeToValue(node.get(1), Object.class);
@@ -76,4 +78,4 @@ public class FastjsonCompatibleRedisSerializer implements RedisSerializer<Object
return null; return null;
} }
} }
} }

View File

@@ -1,6 +1,6 @@
package com.core.framework.interceptor; 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.utils.JsonUtils;
import com.core.common.annotation.RepeatSubmit; import com.core.common.annotation.RepeatSubmit;
import com.core.common.core.domain.AjaxResult; import com.core.common.core.domain.AjaxResult;

View File

@@ -1,6 +1,6 @@
package com.core.framework.interceptor.impl; 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.utils.JsonUtils;
import com.core.common.annotation.RepeatSubmit; import com.core.common.annotation.RepeatSubmit;
import com.core.common.constant.CacheConstants; import com.core.common.constant.CacheConstants;

View File

@@ -1,6 +1,6 @@
package com.core.framework.security.handle; 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.utils.JsonUtils;
import com.core.common.constant.HttpStatus; import com.core.common.constant.HttpStatus;
import com.core.common.core.domain.AjaxResult; import com.core.common.core.domain.AjaxResult;

View File

@@ -1,6 +1,6 @@
package com.core.framework.security.handle; 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.utils.JsonUtils;
import com.core.common.constant.Constants; import com.core.common.constant.Constants;
import com.core.common.core.domain.AjaxResult; import com.core.common.core.domain.AjaxResult;

View File

@@ -71,17 +71,19 @@ public class TokenService {
if (cached instanceof java.util.List<?> list && list.size() >= 2 && list.get(0) instanceof String) { if (cached instanceof java.util.List<?> list && list.size() >= 2 && list.get(0) instanceof String) {
Object data = list.get(1); Object data = list.get(1);
if (data instanceof java.util.Map) { if (data instanceof java.util.Map) {
com.fasterxml.jackson.databind.ObjectMapper mapper = tools.jackson.databind.ObjectMapper mapper =
new com.fasterxml.jackson.databind.ObjectMapper(); tools.jackson.databind.json.JsonMapper.builder()
mapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); .disable(tools.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.build();
return mapper.convertValue(data, LoginUser.class); return mapper.convertValue(data, LoginUser.class);
} }
} }
// 兼容纯JSON格式: LinkedHashMap -> LoginUser // 兼容纯JSON格式: LinkedHashMap -> LoginUser
if (cached instanceof java.util.Map) { if (cached instanceof java.util.Map) {
com.fasterxml.jackson.databind.ObjectMapper mapper = tools.jackson.databind.ObjectMapper mapper =
new com.fasterxml.jackson.databind.ObjectMapper(); tools.jackson.databind.json.JsonMapper.builder()
mapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); .disable(tools.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.build();
return mapper.convertValue(cached, LoginUser.class); return mapper.convertValue(cached, LoginUser.class);
} }
return null; return null;

View File

@@ -61,7 +61,7 @@
<!-- JSON工具类 --> <!-- JSON工具类 -->
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>tools.jackson.core</groupId>
<artifactId>jackson-databind</artifactId> <artifactId>jackson-databind</artifactId>
</dependency> </dependency>

View File

@@ -1,8 +1,8 @@
package com.core.generator.service; package com.core.generator.service;
import com.fasterxml.jackson.databind.ObjectMapper; import tools.jackson.databind.ObjectMapper;
import com.core.common.utils.JsonUtils; 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.Constants;
import com.core.common.constant.GenConstants; import com.core.common.constant.GenConstants;
import com.core.common.core.text.CharsetKit; import com.core.common.core.text.CharsetKit;

View File

@@ -1,8 +1,8 @@
package com.core.generator.util; package com.core.generator.util;
import com.fasterxml.jackson.databind.ObjectMapper; import tools.jackson.databind.ObjectMapper;
import com.core.common.utils.JsonUtils; 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.constant.GenConstants;
import com.core.common.utils.DateUtils; import com.core.common.utils.DateUtils;
import com.core.common.utils.StringUtils; import com.core.common.utils.StringUtils;

View File

@@ -1,8 +1,8 @@
package com.core.system.domain; package com.core.system.domain;
import com.core.common.core.domain.BaseEntity; import com.core.common.core.domain.BaseEntity;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
/** /**
* 公告/通知已读记录 sys_notice_read * 公告/通知已读记录 sys_notice_read

View File

@@ -1,8 +1,8 @@
package com.healthlink.his.web.Inspection.dto; package com.healthlink.his.web.Inspection.dto;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.common.annotation.Dict; import com.healthlink.his.common.annotation.Dict;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.Inspection.dto; package com.healthlink.his.web.Inspection.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.lab.domain.ActivityDefDeviceDef; import com.healthlink.his.lab.domain.ActivityDefDeviceDef;
import com.healthlink.his.lab.domain.ActivityDefObservationDef; import com.healthlink.his.lab.domain.ActivityDefObservationDef;
import com.healthlink.his.lab.domain.ActivityDefSpecimenDef; import com.healthlink.his.lab.domain.ActivityDefSpecimenDef;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.Inspection.dto; package com.healthlink.his.web.Inspection.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.common.annotation.Dict; import com.healthlink.his.common.annotation.Dict;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -1,8 +1,8 @@
package com.healthlink.his.web.Inspection.dto; package com.healthlink.his.web.Inspection.dto;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
/** /**

View File

@@ -1,8 +1,8 @@
package com.healthlink.his.web.Inspection.dto; package com.healthlink.his.web.Inspection.dto;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import java.util.Date; import java.util.Date;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.Inspection.dto; package com.healthlink.his.web.Inspection.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.adjustprice.dto; package com.healthlink.his.web.adjustprice.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import java.math.BigDecimal; import java.math.BigDecimal;

View File

@@ -1,8 +1,11 @@
package com.healthlink.his.web.anesthesia.appservice; 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.AnesthesiaFollowup;
import com.healthlink.his.anesthesia.domain.AnesthesiaIoRecord; import com.healthlink.his.anesthesia.domain.AnesthesiaIoRecord;
import com.healthlink.his.anesthesia.domain.AnesthesiaMedication; 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.AnesthesiaRecord;
import com.healthlink.his.anesthesia.domain.AnesthesiaVitalSign; import com.healthlink.his.anesthesia.domain.AnesthesiaVitalSign;
import com.healthlink.his.anesthesia.dto.AnesthesiaIoSummaryDto; import com.healthlink.his.anesthesia.dto.AnesthesiaIoSummaryDto;
@@ -31,4 +34,20 @@ public interface IAnesthesiaAppService {
AnesthesiaIoSummaryDto getIoSummary(Long recordId); AnesthesiaIoSummaryDto getIoSummary(Long recordId);
void completeRecord(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);
} }

View File

@@ -1,18 +1,25 @@
package com.healthlink.his.web.anesthesia.appservice.impl; 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.AnesthesiaFollowup;
import com.healthlink.his.anesthesia.domain.AnesthesiaIoRecord; import com.healthlink.his.anesthesia.domain.AnesthesiaIoRecord;
import com.healthlink.his.anesthesia.domain.AnesthesiaMedication; 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.AnesthesiaRecord;
import com.healthlink.his.anesthesia.domain.AnesthesiaVitalSign; import com.healthlink.his.anesthesia.domain.AnesthesiaVitalSign;
import com.healthlink.his.anesthesia.dto.AnesthesiaIoSummaryDto; import com.healthlink.his.anesthesia.dto.AnesthesiaIoSummaryDto;
import com.healthlink.his.anesthesia.dto.AnesthesiaRecordDetailDto; 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.IAnesthesiaFollowupService;
import com.healthlink.his.anesthesia.service.IAnesthesiaIoRecordService; 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.IAnesthesiaMedicationService;
import com.healthlink.his.anesthesia.service.IAnesthesiaRecordService; import com.healthlink.his.anesthesia.service.IAnesthesiaRecordService;
import com.healthlink.his.anesthesia.service.IAnesthesiaVitalSignService; import com.healthlink.his.anesthesia.service.IAnesthesiaVitalSignService;
import com.healthlink.his.web.anesthesia.appservice.IAnesthesiaAppService; import com.healthlink.his.web.anesthesia.appservice.IAnesthesiaAppService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -39,6 +46,15 @@ public class AnesthesiaAppServiceImpl implements IAnesthesiaAppService {
@Resource @Resource
private IAnesthesiaFollowupService anesthesiaFollowupService; private IAnesthesiaFollowupService anesthesiaFollowupService;
@Resource
private IAnesAsaAssessmentService anesAsaAssessmentService;
@Resource
private IAnesSummaryService anesSummaryService;
@Resource
private IAnesthesiaPostopFollowupService anesthesiaPostopFollowupService;
@Override @Override
@Transactional @Transactional
public AnesthesiaRecord createRecord(AnesthesiaRecord record) { public AnesthesiaRecord createRecord(AnesthesiaRecord record) {
@@ -125,4 +141,74 @@ public class AnesthesiaAppServiceImpl implements IAnesthesiaAppService {
record.setEndTime(new Date()); record.setEndTime(new Date());
anesthesiaRecordService.updateById(record); 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);
}
} }

View File

@@ -1,9 +1,12 @@
package com.healthlink.his.web.anesthesia.controller; package com.healthlink.his.web.anesthesia.controller;
import com.core.common.core.domain.R; 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.AnesthesiaFollowup;
import com.healthlink.his.anesthesia.domain.AnesthesiaIoRecord; import com.healthlink.his.anesthesia.domain.AnesthesiaIoRecord;
import com.healthlink.his.anesthesia.domain.AnesthesiaMedication; 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.AnesthesiaRecord;
import com.healthlink.his.anesthesia.domain.AnesthesiaVitalSign; import com.healthlink.his.anesthesia.domain.AnesthesiaVitalSign;
import com.healthlink.his.anesthesia.dto.AnesthesiaIoSummaryDto; 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.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List; import java.util.List;
@@ -134,4 +138,60 @@ public class AnesthesiaController {
anesthesiaAppService.completeRecord(id); anesthesiaAppService.completeRecord(id);
return R.ok(); 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));
}
} }

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.appointmentmanage.dto; package com.healthlink.his.web.appointmentmanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -3,8 +3,8 @@
*/ */
package com.healthlink.his.web.basedatamanage.dto; package com.healthlink.his.web.basedatamanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -3,8 +3,8 @@
*/ */
package com.healthlink.his.web.basedatamanage.dto; package com.healthlink.his.web.basedatamanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -3,8 +3,8 @@
*/ */
package com.healthlink.his.web.basedatamanage.dto; package com.healthlink.his.web.basedatamanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.common.annotation.Dict; import com.healthlink.his.common.annotation.Dict;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.basedatamanage.dto; package com.healthlink.his.web.basedatamanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.common.annotation.Dict; import com.healthlink.his.common.annotation.Dict;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -3,8 +3,8 @@
*/ */
package com.healthlink.his.web.basedatamanage.dto; package com.healthlink.his.web.basedatamanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -3,8 +3,8 @@
*/ */
package com.healthlink.his.web.basedatamanage.dto; package com.healthlink.his.web.basedatamanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.common.annotation.Dict; import com.healthlink.his.common.annotation.Dict;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -4,8 +4,8 @@
package com.healthlink.his.web.basedatamanage.dto; package com.healthlink.his.web.basedatamanage.dto;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -3,8 +3,8 @@
*/ */
package com.healthlink.his.web.basedatamanage.dto; package com.healthlink.his.web.basedatamanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.basedatamanage.dto; package com.healthlink.his.web.basedatamanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.common.annotation.Dict; import com.healthlink.his.common.annotation.Dict;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -3,8 +3,8 @@
*/ */
package com.healthlink.his.web.basedatamanage.dto; package com.healthlink.his.web.basedatamanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.basedatamanage.dto; package com.healthlink.his.web.basedatamanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -3,8 +3,8 @@
*/ */
package com.healthlink.his.web.basedatamanage.dto; package com.healthlink.his.web.basedatamanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.basedatamanage.dto; package com.healthlink.his.web.basedatamanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.common.annotation.Dict; import com.healthlink.his.common.annotation.Dict;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.basicservice.dto; package com.healthlink.his.web.basicservice.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.common.annotation.Dict; import com.healthlink.his.common.annotation.Dict;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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));
}
}

View File

@@ -4,8 +4,8 @@
package com.healthlink.his.web.cardmanagement.dto; package com.healthlink.his.web.cardmanagement.dto;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import java.time.LocalDate; import java.time.LocalDate;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.chargemanage.dto; package com.healthlink.his.web.chargemanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.common.constant.CommonConstants; import com.healthlink.his.common.constant.CommonConstants;
import com.healthlink.his.common.enums.AccountBillingStatus; import com.healthlink.his.common.enums.AccountBillingStatus;
import com.healthlink.his.common.enums.AccountStatus; import com.healthlink.his.common.enums.AccountStatus;

View File

@@ -1,8 +1,8 @@
package com.healthlink.his.web.chargemanage.dto; package com.healthlink.his.web.chargemanage.dto;
import com.core.common.utils.SecurityUtils; import com.core.common.utils.SecurityUtils;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.common.constant.CommonConstants; import com.healthlink.his.common.constant.CommonConstants;
import com.healthlink.his.common.enums.ChargeItemContext; import com.healthlink.his.common.enums.ChargeItemContext;
import com.healthlink.his.common.enums.ChargeItemStatus; import com.healthlink.his.common.enums.ChargeItemStatus;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.chargemanage.dto; package com.healthlink.his.web.chargemanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.chargemanage.dto; package com.healthlink.his.web.chargemanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.chargemanage.dto; package com.healthlink.his.web.chargemanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.common.enums.*; import com.healthlink.his.common.enums.*;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.chargemanage.dto; package com.healthlink.his.web.chargemanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.common.enums.EncounterActivityStatus; import com.healthlink.his.common.enums.EncounterActivityStatus;
import com.healthlink.his.common.enums.LocationForm; import com.healthlink.his.common.enums.LocationForm;
import lombok.Data; import lombok.Data;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.chargemanage.dto; package com.healthlink.his.web.chargemanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.common.enums.ParticipantType; import com.healthlink.his.common.enums.ParticipantType;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -4,8 +4,8 @@
package com.healthlink.his.web.chargemanage.dto; package com.healthlink.his.web.chargemanage.dto;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;

View File

@@ -5,8 +5,8 @@ package com.healthlink.his.web.chargemanage.dto;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.common.annotation.Dict; import com.healthlink.his.common.annotation.Dict;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -3,8 +3,8 @@
*/ */
package com.healthlink.his.web.chargemanage.dto; package com.healthlink.his.web.chargemanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.common.annotation.Dict; import com.healthlink.his.common.annotation.Dict;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -4,8 +4,8 @@
package com.healthlink.his.web.chargemanage.dto; package com.healthlink.his.web.chargemanage.dto;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.common.annotation.Dict; import com.healthlink.his.common.annotation.Dict;
import com.healthlink.his.yb.dto.PaymentDetailDto; import com.healthlink.his.yb.dto.PaymentDetailDto;
import lombok.Data; import lombok.Data;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.chargemanage.dto; package com.healthlink.his.web.chargemanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.chargemanage.dto; package com.healthlink.his.web.chargemanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.common.annotation.Dict; import com.healthlink.his.common.annotation.Dict;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.chargemanage.dto; package com.healthlink.his.web.chargemanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.common.annotation.Dict; import com.healthlink.his.common.annotation.Dict;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.chargemanage.dto; package com.healthlink.his.web.chargemanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.chargemanage.dto; package com.healthlink.his.web.chargemanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -4,8 +4,8 @@
package com.healthlink.his.web.chargemanage.dto; package com.healthlink.his.web.chargemanage.dto;
import com.core.common.utils.SecurityUtils; import com.core.common.utils.SecurityUtils;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.common.enums.EncounterClass; import com.healthlink.his.common.enums.EncounterClass;
import com.healthlink.his.common.enums.RequestStatus; import com.healthlink.his.common.enums.RequestStatus;
import com.healthlink.his.common.enums.TherapyTimeType; import com.healthlink.his.common.enums.TherapyTimeType;

View File

@@ -3,8 +3,8 @@
*/ */
package com.healthlink.his.web.chargemanage.dto; package com.healthlink.his.web.chargemanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.healthlink.his.common.annotation.Dict; import com.healthlink.his.common.annotation.Dict;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.chargemanage.dto; package com.healthlink.his.web.chargemanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;

View File

@@ -123,7 +123,7 @@ public class ExamApplyController extends BaseController {
for (ExamApplyItem item : items) { for (ExamApplyItem item : items) {
BigDecimal itemTotal = item.getItemFee() != null ? item.getItemFee() : BigDecimal.ZERO; 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)); 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 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); BigDecimal fee = baseFee.add(methodFee);
chargeItem.setQuantityValue(BigDecimal.ONE); // 数量 chargeItem.setQuantityValue(BigDecimal.ONE); // 数量
chargeItem.setQuantityUnit(""); // 单位 chargeItem.setQuantityUnit(""); // 单位
@@ -506,7 +506,7 @@ public class ExamApplyController extends BaseController {
chargeItem.setProductId(0L); chargeItem.setProductId(0L);
BigDecimal baseFee = itemDto.getItemFee() != null ? itemDto.getItemFee() : BigDecimal.ZERO; 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); BigDecimal fee = baseFee.add(methodFee);
chargeItem.setQuantityValue(BigDecimal.ONE); chargeItem.setQuantityValue(BigDecimal.ONE);
chargeItem.setQuantityUnit(""); chargeItem.setQuantityUnit("");
@@ -570,15 +570,17 @@ public class ExamApplyController extends BaseController {
* Bug #655: 根据检查方法代码查询附加金额(套餐价格) * Bug #655: 根据检查方法代码查询附加金额(套餐价格)
* 查找链路examMethodCode → CheckMethod → packageName → CheckPackage → packagePrice * 查找链路examMethodCode → CheckMethod → packageName → CheckPackage → packagePrice
*/ */
private BigDecimal getMethodAdditionalFee(String examMethodCode) { private BigDecimal getMethodAdditionalFee(String examMethodCode, String checkType) {
if (examMethodCode == null || examMethodCode.isEmpty()) { if (examMethodCode == null || examMethodCode.isEmpty()) {
return BigDecimal.ZERO; return BigDecimal.ZERO;
} }
// 1. 根据 code 查找 CheckMethod // 1. 根据 code 和 checkType 查找 CheckMethod
CheckMethod method = checkMethodService.getOne( LambdaQueryWrapper<CheckMethod> wrapper = new LambdaQueryWrapper<CheckMethod>()
new LambdaQueryWrapper<CheckMethod>() .eq(CheckMethod::getCode, examMethodCode);
.eq(CheckMethod::getCode, examMethodCode) if (checkType != null && !checkType.isEmpty()) {
.last("LIMIT 1")); wrapper.eq(CheckMethod::getCheckType, checkType);
}
CheckMethod method = checkMethodService.getOne(wrapper.last("LIMIT 1"));
if (method == null || method.getPackageName() == null || method.getPackageName().isEmpty()) { if (method == null || method.getPackageName() == null || method.getPackageName().isEmpty()) {
return BigDecimal.ZERO; return BigDecimal.ZERO;
} }

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -1,17 +1,24 @@
package com.healthlink.his.web.clinical.controller; package com.healthlink.his.web.clinical.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.core.domain.AjaxResult;
import com.core.common.core.domain.R; import com.core.common.core.domain.R;
import com.healthlink.his.clinical.domain.*; import com.healthlink.his.clinical.domain.*;
import com.healthlink.his.clinical.service.*; 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 lombok.AllArgsConstructor;import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;import org.springframework.web.bind.annotation.*; import org.springframework.util.StringUtils;import org.springframework.web.bind.annotation.*;
import java.util.*; import java.util.*;
@RestController @RequestMapping("/clinical-pathway") @Slf4j @AllArgsConstructor @Tag(name = "临床路径管理") @RestController @RequestMapping("/clinical-pathway") @Slf4j @AllArgsConstructor
public class ClinicalPathwayController { public class ClinicalPathwayController {
private final IClinicalPathwayService pathwayService; private final IClinicalPathwayService pathwayService;
private final IClinicalPathwayExecutionService executionService; private final IClinicalPathwayExecutionService executionService;
private final IClinicalPathwayAppService clinicalPathwayAppService;
@PreAuthorize("@ss.hasPermi('inpatient:clinical:list')")
@GetMapping("/page") @GetMapping("/page")
public R<?> getPage(@RequestParam(value="diseaseCode",required=false) String diseaseCode, public R<?> getPage(@RequestParam(value="diseaseCode",required=false) String diseaseCode,
@RequestParam(value="pageNo",defaultValue="1") Integer pageNo, @RequestParam(value="pageNo",defaultValue="1") Integer pageNo,
@@ -21,13 +28,16 @@ public class ClinicalPathwayController {
.eq(ClinicalPathway::getStatus, "ACTIVE"); .eq(ClinicalPathway::getStatus, "ACTIVE");
return R.ok(pathwayService.page(new Page<>(pageNo, pageSize), w)); return R.ok(pathwayService.page(new Page<>(pageNo, pageSize), w));
} }
@PreAuthorize("@ss.hasPermi('inpatient:clinical:edit')")
@PostMapping("/add") @Transactional(rollbackFor=Exception.class) @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); } 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) @PostMapping("/enter") @Transactional(rollbackFor=Exception.class)
public R<?> enterPathway(@RequestBody ClinicalPathwayExecution e) { public R<?> enterPathway(@RequestBody ClinicalPathwayExecution e) {
e.setStatus("IN_PATH"); e.setEnterDate(java.time.LocalDate.now()); e.setCreateTime(new Date()); e.setStatus("IN_PATH"); e.setEnterDate(java.time.LocalDate.now()); e.setCreateTime(new Date());
executionService.save(e); return R.ok(e); executionService.save(e); return R.ok(e);
} }
@PreAuthorize("@ss.hasPermi('inpatient:clinical:edit')")
@PutMapping("/complete/{id}") @Transactional(rollbackFor=Exception.class) @PutMapping("/complete/{id}") @Transactional(rollbackFor=Exception.class)
public R<?> completePathway(@PathVariable Long id) { public R<?> completePathway(@PathVariable Long id) {
LambdaQueryWrapper<ClinicalPathwayExecution> qw = new LambdaQueryWrapper<>(); LambdaQueryWrapper<ClinicalPathwayExecution> qw = new LambdaQueryWrapper<>();
@@ -36,6 +46,7 @@ public class ClinicalPathwayController {
e.setStatus("COMPLETED"); e.setCompleteDate(java.time.LocalDate.now()); e.setStatus("COMPLETED"); e.setCompleteDate(java.time.LocalDate.now());
executionService.updateById(e); return R.ok(); executionService.updateById(e); return R.ok();
} }
@PreAuthorize("@ss.hasPermi('inpatient:clinical:edit')")
@PutMapping("/vary/{id}") @Transactional(rollbackFor=Exception.class) @PutMapping("/vary/{id}") @Transactional(rollbackFor=Exception.class)
public R<?> varyPathway(@PathVariable Long id, @RequestParam("reason") String reason) { public R<?> varyPathway(@PathVariable Long id, @RequestParam("reason") String reason) {
LambdaQueryWrapper<ClinicalPathwayExecution> qw = new LambdaQueryWrapper<>(); LambdaQueryWrapper<ClinicalPathwayExecution> qw = new LambdaQueryWrapper<>();
@@ -43,6 +54,7 @@ public class ClinicalPathwayController {
ClinicalPathwayExecution e = executionService.getOne(qw); if (e == null) return R.fail("执行记录不存在"); ClinicalPathwayExecution e = executionService.getOne(qw); if (e == null) return R.fail("执行记录不存在");
e.setStatus("VARIATION"); e.setVariationReason(reason); executionService.updateById(e); return R.ok(); e.setStatus("VARIATION"); e.setVariationReason(reason); executionService.updateById(e); return R.ok();
} }
@PreAuthorize("@ss.hasPermi('inpatient:clinical:list')")
@GetMapping("/stats") @GetMapping("/stats")
public R<?> getStats() { public R<?> getStats() {
Map<String, Object> stats = new HashMap<>(); 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); stats.put("completionRate", total > 0 ? Math.round(completed * 100.0 / total) : 0);
return R.ok(stats); 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));
}
} }

View File

@@ -9,7 +9,7 @@ import com.core.common.core.domain.entity.SysUser;
import com.core.common.utils.MessageUtils; import com.core.common.utils.MessageUtils;
import com.core.common.utils.SecurityUtils; import com.core.common.utils.SecurityUtils;
import com.core.system.service.ISysUserService; 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.core.common.utils.JsonUtils;
import com.healthlink.his.administration.domain.ChargeItem; import com.healthlink.his.administration.domain.ChargeItem;
import com.healthlink.his.administration.domain.Encounter; import com.healthlink.his.administration.domain.Encounter;

View File

@@ -1,7 +1,7 @@
package com.healthlink.his.web.clinicalmanage.dto; package com.healthlink.his.web.clinicalmanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import tools.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import tools.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.healthlink.his.common.annotation.Dict; import com.healthlink.his.common.annotation.Dict;
import lombok.Data; import lombok.Data;

Some files were not shown because too many files have changed in this diff Show More