From 76f090d2afb9d36f43eff52950c80c88925f62bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=8E=E4=BD=97?= Date: Sat, 6 Jun 2026 14:11:50 +0800 Subject: [PATCH] =?UTF-8?q?docs(iron-rules):=20=E6=96=B0=E5=A2=9E=E9=93=81?= =?UTF-8?q?=E5=BE=8B15+16=20+=20=E4=B8=9A=E5=8A=A1=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E8=AE=BE=E8=AE=A1=E6=96=87=E6=A1=A3=20+=20=E5=90=8E=E7=AB=AF?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 铁律15: 模块设计必须分析业务逻辑,不能只做CRUD - 必须查阅标准规范、梳理业务流程、设计状态流转、定义业务规则 - 附设计文档模板和医疗HIS参考标准清单 铁律16: 模块优化必须分析现有业务流并说明促进作用 - 必须回答5个问题:位置/关联/促进/兼容/冲突 - 附业务逻辑分析文档模板 业务逻辑设计文档: - MD/specs/SURGERY_MANAGEMENT_DESIGN.md (139行) - 状态机: 待申请→待审批→已审批→待手术→手术中→已完成 - 7条业务规则: 分级权限/术前讨论/术前评估/手术室冲突/禁食/随访/安全核查 - MD/specs/ORDER_MANAGEMENT_DESIGN.md - 状态机: 新开→签发→执行中→已完成/已停止/已签退 - 6条业务规则: 停止时限/用药审核/查对/紧急标识/修改限制/皮试联动 - MD/specs/BED_MANAGEMENT_DESIGN.md - 状态机: 空闲↔占用↔清洁中↔维修中 - 5条业务规则: 分配校验/科室匹配/自动清洁/使用率统计/预约 后端业务逻辑增强: - SurgeryAppService: +手术室冲突校验 +手术统计 - BedController: +床位使用率统计 +分配校验 +出院自动清洁 - EsbMessageController: +消息路由校验 +消息轨迹 +死信队列处理 --- .clinerules | 2 +- .cursorrules | 2 +- .github/copilot-instructions.md | 2 +- .qwenrules | 2 +- .windsurfrules | 2 +- AGENTS.md | 2 +- MD/specs/BED_MANAGEMENT_DESIGN.md | 72 +++++++++ MD/specs/IRON_RULES.md | 125 ++++++++++++++++ MD/specs/ORDER_MANAGEMENT_DESIGN.md | 91 ++++++++++++ MD/specs/SURGERY_MANAGEMENT_DESIGN.md | 139 ++++++++++++++++++ .../basicmanage/controller/BedController.java | 54 ++++++- .../appservice/ISurgeryAppService.java | 21 +++ .../impl/SurgeryAppServiceImpl.java | 40 +++++ .../controller/SurgeryController.java | 24 ++- .../controller/EsbMessageController.java | 104 +++++++++++++ .../EsbServiceRegistryController.java | 52 +++++++ .../V13__esb_integration_platform.sql | 39 +++++ .../healthlink/his/esb/domain/EsbMessage.java | 26 ++++ .../his/esb/domain/EsbServiceRegistry.java | 21 +++ .../his/esb/mapper/EsbMessageMapper.java | 6 + .../esb/mapper/EsbServiceRegistryMapper.java | 6 + .../his/esb/service/IEsbMessageService.java | 4 + .../service/IEsbServiceRegistryService.java | 4 + .../service/impl/EsbMessageServiceImpl.java | 8 + .../impl/EsbServiceRegistryServiceImpl.java | 8 + .../views/esbmanage/message/components/api.js | 5 + .../src/views/esbmanage/message/index.vue | 98 ++++++++++++ .../src/views/esbmanage/monitor/index.vue | 69 +++++++++ .../esbmanage/registry/components/api.js | 6 + .../src/views/esbmanage/registry/index.vue | 91 ++++++++++++ .../ybmanagement/catalogManagement/index.vue | 59 +++++++- .../ybmanagement/medicalInsurance/index.vue | 76 +++++++++- .../views/ybmanagement/settlement/index.vue | 76 +++++++++- 33 files changed, 1313 insertions(+), 23 deletions(-) create mode 100644 MD/specs/BED_MANAGEMENT_DESIGN.md create mode 100644 MD/specs/ORDER_MANAGEMENT_DESIGN.md create mode 100644 MD/specs/SURGERY_MANAGEMENT_DESIGN.md create mode 100644 healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/controller/EsbMessageController.java create mode 100644 healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/controller/EsbServiceRegistryController.java create mode 100644 healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V13__esb_integration_platform.sql create mode 100644 healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/domain/EsbMessage.java create mode 100644 healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/domain/EsbServiceRegistry.java create mode 100644 healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/mapper/EsbMessageMapper.java create mode 100644 healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/mapper/EsbServiceRegistryMapper.java create mode 100644 healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/IEsbMessageService.java create mode 100644 healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/IEsbServiceRegistryService.java create mode 100644 healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/impl/EsbMessageServiceImpl.java create mode 100644 healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/impl/EsbServiceRegistryServiceImpl.java create mode 100644 healthlink-his-ui/src/views/esbmanage/message/components/api.js create mode 100644 healthlink-his-ui/src/views/esbmanage/message/index.vue create mode 100644 healthlink-his-ui/src/views/esbmanage/monitor/index.vue create mode 100644 healthlink-his-ui/src/views/esbmanage/registry/components/api.js create mode 100644 healthlink-his-ui/src/views/esbmanage/registry/index.vue diff --git a/.clinerules b/.clinerules index 53b54cab6..232b1affb 100644 --- a/.clinerules +++ b/.clinerules @@ -496,4 +496,4 @@ git status && git add -A && git commit -m "feat(module): desc" && git push origi --- -> 📅 最后同步: 2026-06-06 11:19 | 源文件: RULES.md | 重新同步: `bash scripts/sync-ai-rules.sh` +> 📅 最后同步: 2026-06-06 14:02 | 源文件: RULES.md | 重新同步: `bash scripts/sync-ai-rules.sh` diff --git a/.cursorrules b/.cursorrules index 6dabd52a5..92d0aa0b5 100644 --- a/.cursorrules +++ b/.cursorrules @@ -496,4 +496,4 @@ git status && git add -A && git commit -m "feat(module): desc" && git push origi --- -> 📅 最后同步: 2026-06-06 11:19 | 源文件: RULES.md | 重新同步: `bash scripts/sync-ai-rules.sh` +> 📅 最后同步: 2026-06-06 14:02 | 源文件: RULES.md | 重新同步: `bash scripts/sync-ai-rules.sh` diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 1494f3504..d47e2a35d 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -496,4 +496,4 @@ git status && git add -A && git commit -m "feat(module): desc" && git push origi --- -> 📅 最后同步: 2026-06-06 11:19 | 源文件: RULES.md | 重新同步: `bash scripts/sync-ai-rules.sh` +> 📅 最后同步: 2026-06-06 14:02 | 源文件: RULES.md | 重新同步: `bash scripts/sync-ai-rules.sh` diff --git a/.qwenrules b/.qwenrules index 30e38545c..8456b5dfb 100644 --- a/.qwenrules +++ b/.qwenrules @@ -496,4 +496,4 @@ git status && git add -A && git commit -m "feat(module): desc" && git push origi --- -> 📅 最后同步: 2026-06-06 11:19 | 源文件: RULES.md | 重新同步: `bash scripts/sync-ai-rules.sh` +> 📅 最后同步: 2026-06-06 14:02 | 源文件: RULES.md | 重新同步: `bash scripts/sync-ai-rules.sh` diff --git a/.windsurfrules b/.windsurfrules index 91668a839..98a7c27e2 100644 --- a/.windsurfrules +++ b/.windsurfrules @@ -496,4 +496,4 @@ git status && git add -A && git commit -m "feat(module): desc" && git push origi --- -> 📅 最后同步: 2026-06-06 11:19 | 源文件: RULES.md | 重新同步: `bash scripts/sync-ai-rules.sh` +> 📅 最后同步: 2026-06-06 14:02 | 源文件: RULES.md | 重新同步: `bash scripts/sync-ai-rules.sh` diff --git a/AGENTS.md b/AGENTS.md index 861d754e0..c75ea09ae 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -497,4 +497,4 @@ git status && git add -A && git commit -m "feat(module): desc" && git push origi --- -> 📅 最后同步: 2026-06-06 11:19 | 源文件: RULES.md | 重新同步: `bash scripts/sync-ai-rules.sh` +> 📅 最后同步: 2026-06-06 14:02 | 源文件: RULES.md | 重新同步: `bash scripts/sync-ai-rules.sh` diff --git a/MD/specs/BED_MANAGEMENT_DESIGN.md b/MD/specs/BED_MANAGEMENT_DESIGN.md new file mode 100644 index 000000000..41d867b78 --- /dev/null +++ b/MD/specs/BED_MANAGEMENT_DESIGN.md @@ -0,0 +1,72 @@ +# 床位管理模块设计文档 + +> **文档类型**: 业务设计 +> **版本**: v1.0 +> **编制日期**: 2026-06-06 +> **依据标准**: 《三级医院评审标准(2022版)》床位使用率指标 + +--- + +## 一、业务背景 + +床位管理直接影响医院运营效率。三甲医院评审要求床位使用率≥85%,床位周转次数达标。需要实时掌握床位状态,支持智能分配。 + +--- + +## 二、状态流转 + +### 2.1 床位状态机 + +``` +空闲(0) → 占用(1) → 清洁中(2) → 空闲(0) + ↓ + 维修中(3) → 空闲(0) +``` + +| 状态 | 值 | 触发条件 | 允许操作 | +|------|-----|---------|---------| +| 空闲 | 0 | 清洁完成/新床 | 分配患者 | +| 占用 | 1 | 患者入院分配 | 患者转科/出院 | +| 清洁中 | 2 | 患者出院后 | 清洁完成→空闲 | +| 维修中 | 3 | 设备故障 | 维修完成→空闲 | + +--- + +## 三、业务规则 + +| 规则编号 | 规则名称 | 规则描述 | 触发时机 | +|---------|---------|---------|---------| +| BR-001 | 床位分配校验 | 只有"空闲"状态的床位才能分配 | 入院登记时 | +| BR-002 | 科室匹配 | 床位所属科室必须与患者入院科室一致 | 入院登记时 | +| BR-003 | 出院自动清洁 | 患者出院后床位自动变为"清洁中" | 出院结算时 | +| BR-004 | 使用率统计 | 实时计算科室/全院床位使用率 | 定时任务 | +| BR-005 | 床位预约 | 支持预约指定床位(限时保留) | 预约住院时 | + +--- + +## 四、数据模型 + +### 床位使用率计算公式 +``` +科室床位使用率 = (占用床位数 / 总床位数) × 100% +全院床位使用率 = (全院占用床位数 / 全院总床位数) × 100% +床位周转次数 = 出院人次 / 平均开放床位数 +``` + +### 床位占用时长统计 +``` +平均住院天数 = Σ(出院日期 - 入院日期) / 出院人次 +``` + +--- + +## 五、测试用例 + +| 用例编号 | 场景 | 预期结果 | +|---------|------|---------| +| TC-B001 | 正常分配 | 空闲床位→占用,状态正确 | +| TC-B002 | 分配已占用床位 | 返回"该床位已被占用" | +| TC-B003 | 出院自动清洁 | 出院后床位变为"清洁中" | +| TC-B004 | 使用率计算 | 数据准确反映实际使用情况 | +| TC-B005 | 维修中分配 | 返回"该床位维修中" | + diff --git a/MD/specs/IRON_RULES.md b/MD/specs/IRON_RULES.md index 8ccf7f7dd..1e4e560b8 100644 --- a/MD/specs/IRON_RULES.md +++ b/MD/specs/IRON_RULES.md @@ -22,6 +22,8 @@ | #8 | 铁律和规范文档放MD目录 | P1 | 规范文档 | | #9 | 开发前必须审核原有代码 | P0 | 全量开发 | | #10 | 设计文档必须包含UI设计和调用流程 | P0 | 设计文档/前端开发 | +| #11 | 模块设计必须分析业务逻辑,不能只做CRUD | P0 | 全量模块设计 | +| #12 | 模块优化必须分析现有业务流并说明促进作用 | P0 | 全量模块优化 | --- @@ -309,6 +311,129 @@ npm run lint --- +--- + +--- + +### 铁律 #12: 模块优化必须分析现有业务流并说明促进作用 + +**任何模块新增/优化前,必须先分析现有业务流程全貌。** + +#### 必须回答的5个问题 + +| # | 问题 | 说明 | +|---|------|------| +| 1 | 该模块在整体业务流中处于什么位置? | 上游/下游/并行 | +| 2 | 该模块与哪些现有模块有数据流转关系? | 列出所有关联模块 | +| 3 | 优化对上下游模块有什么促进作用? | 减少重复、提升一致性、加快流程 | +| 4 | 变更是否影响现有业务流程? | 兼容性评估 | +| 5 | 业务规则是否与现有模块冲突? | 规则一致性检查 | + +#### 业务逻辑分析文档模板 + +``` +# 模块名 — 业务逻辑分析 + +## 1. 整体业务流程定位 +[该模块在HIS系统中的位置,上下游关系图] + +## 2. 关联模块分析 +| 关联模块 | 数据流向 | 交互方式 | 影响程度 | +|---------|---------|---------|---------| + +## 3. 优化促进作用 +| 维度 | 优化前 | 优化后 | 提升效果 | +|------|--------|--------|---------| + +## 4. 兼容性评估 +- 对现有模块的影响 +- 数据迁移需求 +- 接口变更影响 + +## 5. 规则一致性检查 +- 新增规则是否与现有规则冲突 +- 状态流转是否与现有状态机兼容 +``` + +--- + +### 铁律 #11: 模块设计必须分析业务逻辑,不能只做CRUD + +**任何新模块/功能开发前,必须先进行业务逻辑分析和梳理。** + +#### 禁止行为 +- ❌ 拿到需求就直接写CRUD,不思考业务流程 +- ❌ 不查阅标准规范就开发医疗业务模块 +- ❌ 没有设计文档就直接编码 +- ❌ 把"能增删改查"当成"功能完成" + +#### 必须完成的设计步骤 + +| # | 步骤 | 产出物 | 说明 | +|---|------|--------|------| +| 1 | 查阅标准规范 | 参考文档清单 | 国家卫健委标准、医保局规范、HL7/FHIR、三甲评审标准 | +| 2 | 梳理业务流程 | 流程图/文字描述 | 正常流程 + 异常流程 + 边界场景 | +| 3 | 设计状态流转 | 状态机图 | 每个实体的生命周期、状态转换条件 | +| 4 | 定义业务规则 | 规则清单 | 如:药品相互作用规则、医保审核规则、危急值判定规则 | +| 5 | 设计交互时序 | 时序图 | 用户操作 → 前端事件 → API → 后端处理 → 持久化 → 响应 | +| 6 | 编写设计文档 | MD文件 | 保存到 `MD/specs/` 或 `MD/architecture/` | + +#### 医疗HIS业务逻辑参考标准 + +| 标准/规范 | 适用模块 | 获取途径 | +|----------|---------|---------| +| 三级医院评审标准(2022版) | 全量 | 卫健委官网 | +| 电子病历应用水平分级评价 | 电子病历/质控 | 卫健委官网 | +| 互联互通标准化成熟度测评 | ESB/集成平台 | 卫健委官网 | +| 医保基金使用监督管理条例 | 医保审核/结算 | 医保局官网 | +| HL7 FHIR R4 | 数据交换/ESB | hl7.org | +| 处方管理办法 | 合理用药/处方 | 卫健委官网 | +| 抗菌药物临床应用管理办法 | 抗菌药物管理 | 卫健委官网 | +| 医院感染管理办法 | 院感管理 | 卫健委官网 | +| 病案管理与质量控制标准 | 病案管理 | 卫健委官网 | + +#### 设计文档模板 + +``` +# 模块名 设计文档 + +## 1. 业务背景 +- 依据什么标准/规范 +- 解决什么业务问题 + +## 2. 业务流程 +### 2.1 正常流程 +[流程描述/流程图] + +### 2.2 异常流程 +[异常场景及处理方式] + +### 2.3 边界场景 +[特殊情况处理] + +## 3. 状态流转 +| 状态 | 值 | 触发条件 | 下一状态 | +|------|-----|---------|---------| + +## 4. 业务规则 +| 规则编号 | 规则名称 | 规则描述 | 触发时机 | +|---------|---------|---------|---------| + +## 5. 数据模型 +[实体关系图/表结构设计] + +## 6. 接口设计 +[API列表+参数+返回值] + +## 7. 前端页面设计 +[UI布局+交互+调用流程] + +## 8. 测试用例 +[关键业务场景测试] +``` + +--- + ### 铁律 #10: 设计文档必须包含UI设计和调用流程 **所有新模块/页面的设计文档必须包含以下要素,缺一不可:** diff --git a/MD/specs/ORDER_MANAGEMENT_DESIGN.md b/MD/specs/ORDER_MANAGEMENT_DESIGN.md new file mode 100644 index 000000000..d2f2bf122 --- /dev/null +++ b/MD/specs/ORDER_MANAGEMENT_DESIGN.md @@ -0,0 +1,91 @@ +# 医嘱管理模块设计文档 + +> **文档类型**: 业务设计 +> **版本**: v1.0 +> **编制日期**: 2026-06-06 +> **依据标准**: 《三级医院评审标准(2022版)》医嘱管理制度 + +--- + +## 一、业务背景 + +医嘱管理是住院诊疗的核心环节。依据《病历书写基本规范》和《处方管理办法》,医嘱必须经过开具→审核→执行→完成的完整闭环。 + +--- + +## 二、状态流转 + +### 2.1 医嘱状态机 + +``` +新开(0) → 已签发(1) → 执行中(2) → 已完成(3) + ↓ + 已停止(4) → 已取消停嘱(恢复)(2) + ↓ + 已签退(5) +``` + +| 状态 | 值 | 触发条件 | 允许操作 | +|------|-----|---------|---------| +| 新开 | 0 | 医生新开医嘱 | 签发/删除 | +| 已签发 | 1 | 医生签发 | 护士执行/签退 | +| 执行中 | 2 | 护士开始执行 | 停止/完成 | +| 已完成 | 3 | 执行完毕 | 查看 | +| 已停止 | 4 | 医生停止医嘱 | 恢复(取消停嘱) | +| 已签退 | 5 | 护士签退 | 查看 | + +--- + +## 三、业务规则 + +| 规则编号 | 规则名称 | 规则描述 | 触发时机 | +|---------|---------|---------|---------| +| OR-001 | 长期医嘱停止时限 | 长期医嘱停止必须在执行时间之前2小时 | 停止医嘱时 | +| OR-002 | 用药医嘱审核 | 用药医嘱必须经过合理用药系统审核 | 签发用药医嘱时 | +| OR-003 | 医嘱查对 | 执行医嘱前必须双人查对 | 护士执行时 | +| OR-004 | 紧急医嘱标识 | 紧急医嘱需要特殊标识和优先执行 | 开具医嘱时 | +| OR-005 | 医嘱修改限制 | 已签发的医嘱不能修改,只能停止后新开 | 修改医嘱时 | +| OR-006 | 皮试医嘱联动 | 需要皮试的药物必须关联皮试医嘱 | 开具需皮试药物时 | + +--- + +## 四、前后端交互时序 + +### 4.1 签发医嘱 +``` +用户操作: 医生点击"签发医嘱" + → 前端: 收集选中医嘱列表 + → API: POST /reg-doctorstation/advice-manage/sign-reg-advice + → 后端: AdviceManageController.signRegAdvice() + → 校验医嘱状态必须为"新开"(OR-005) + → 用药医嘱调用合理用药系统审核(OR-002) + → 设置签发时间+签发人 + → 更新状态=已签发(1) + → 返回: {code:200, msg:"签发成功"} + → 前端: 刷新医嘱列表 +``` + +### 4.2 停止医嘱 +``` +用户操作: 医生点击"停止医嘱" + → 前端: 弹出确认框+填写停嘱原因 + → API: POST /reg-doctorstation/advice-manage/stop-reg-advice + → 后端: 校验医嘱状态必须为"执行中" + → 长期医嘱校验停止时限(OR-001) + → 设置停嘱时间+停嘱原因 + → 更新状态=已停止(4) + → 返回: {code:200, msg:"停嘱成功"} +``` + +--- + +## 五、测试用例 + +| 用例编号 | 场景 | 预期结果 | +|---------|------|---------| +| TC-O001 | 正常签发流程 | 新开→签发→执行→完成 | +| TC-O002 | 签发后修改 | 返回"已签发医嘱不能修改" | +| TC-O003 | 停止后恢复 | 已停止→恢复→执行中 | +| TC-O004 | 用药审核拦截 | 有相互作用的药物签发时被拦截 | +| TC-O005 | 紧急医嘱优先 | 紧急医嘱在列表中高亮显示 | + diff --git a/MD/specs/SURGERY_MANAGEMENT_DESIGN.md b/MD/specs/SURGERY_MANAGEMENT_DESIGN.md new file mode 100644 index 000000000..5968454b5 --- /dev/null +++ b/MD/specs/SURGERY_MANAGEMENT_DESIGN.md @@ -0,0 +1,139 @@ +# 手术管理模块设计文档 + +> **文档类型**: 业务设计 +> **版本**: v1.0 +> **编制日期**: 2026-06-06 +> **依据标准**: 《三级医院评审标准(2022版)》手术质量安全核心制度 + +--- + +## 一、业务背景 + +手术管理是三甲医院评审的核心检查项。依据《医疗质量安全核心制度》中的"手术分级管理制度"和"术前讨论制度",手术必须经过完整的术前评估→审批→执行→术后跟踪流程。 + +### 参考标准 +- 三级医院评审标准(2022版) — 手术质量安全核心指标 +- 电子病历应用水平分级评价 — 4级要求手术信息全院共享 +- 《手术分级管理办法》— 手术分级授权管理 +- 《病案管理与质量控制标准》— 手术记录规范 + +--- + +## 二、状态流转 + +### 2.1 手术状态机 + +``` +待申请(0) → 待审批(1) → 已审批(2) → 待手术(3) → 手术中(4) → 已完成(5) + ↓ ↓ + 已驳回(6) 已取消(7) +``` + +| 状态 | 值 | 触发条件 | 允许操作 | +|------|-----|---------|---------| +| 待申请 | 0 | 医生提交手术申请 | 编辑/删除/提交审批 | +| 待审批 | 1 | 提交审批 | 审批/驳回 | +| 已审批 | 2 | 科主任审批通过 | 安排手术室/取消 | +| 待手术 | 3 | 安排手术室和时间 | 开始手术/取消 | +| 手术中 | 4 | 主刀医生确认开始 | 记录术中事件/完成 | +| 已完成 | 5 | 主刀医生确认完成 | 查看/打印记录 | +| 已驳回 | 6 | 科主任驳回 | 编辑后重新提交 | +| 已取消 | 7 | 任意阶段取消 | 查看 | + +### 2.2 手术分级 + +| 级别 | 名称 | 审批权限 | 示例 | +|------|------|---------|------| +| 一级 | 一级手术 | 住院医师可独立完成 | 阑尾切除术 | +| 二级 | 二级手术 | 主治医师以上 | 胃大部切除术 | +| 三级 | 三级手术 | 副主任医师以上 | 心脏搭桥术 | +| 四级 | 四级手术 | 科主任审批+医务部备案 | 器官移植术 | + +--- + +## 三、业务规则 + +| 规则编号 | 规则名称 | 规则描述 | 触发时机 | +|---------|---------|---------|---------| +| SR-001 | 手术分级权限校验 | 医生只能申请其权限范围内的手术级别 | 提交申请时 | +| SR-002 | 术前讨论记录 | 三级/四级手术必须有术前讨论记录 | 提交审批时 | +| SR-003 | 术前评估 | 必须完成麻醉评估和手术风险评估 | 安排手术时 | +| SR-004 | 手术室冲突检查 | 同一手术室同一时间不能安排两台手术 | 安排手术室时 | +| SR-005 | 术前禁食提醒 | 手术前8小时禁止进食,4小时禁止饮水 | 手术前1天 | +| SR-006 | 术后随访 | 手术后24h/48h/72h必须有随访记录 | 完成手术后 | +| SR-007 | 手术安全核查 | 术前/术中/术后三次安全核查(WS/T 313) | 手术各阶段 | + +--- + +## 四、前后端交互时序 + +### 4.1 提交手术申请 +``` +用户操作: 医生点击"提交手术申请" + → 前端: 校验表单(必填项+业务规则前端预检) + → API: POST /clinical-manage/surgery/surgery + → 后端: SurgeryController.addSurgery() + → SurgeryAppService.addSurgery() + → 校验手术分级权限(SR-001) + → 校验三级/四级手术术前讨论(SR-002) + → 设置状态=待申请(0) + → 保存到数据库 + → 返回: {code:200, msg:"申请已提交"} + → 前端: ElMessage.success → 刷新列表 +``` + +### 4.2 安排手术室 +``` +用户操作: 护士长点击"安排手术" + → 前端: 弹出安排弹窗(选择手术室/时间/麻醉医生) + → API: PUT /clinical-manage/surgery/surgery (携带手术室+时间信息) + → 后端: 校验手术室冲突(SR-004) + → 校验术前评估完成(SR-003) + → 更新状态=待手术(3) + → 返回: {code:200, msg:"安排成功"} +``` + +### 4.3 开始/完成手术 +``` +用户操作: 主刀医生点击"开始手术" + → API: PUT /clinical-manage/surgery/surgery-status?id=&statusEnum=4 + → 后端: 更新状态=手术中(4), 记录开始时间 + +用户操作: 主刀医生点击"完成手术" + → API: PUT /clinical-manage/surgery/surgery-status?id=&statusEnum=5 + → 后端: 更新状态=已完成(5), 记录结束时间 + → 触发术后随访提醒(SR-006) +``` + +--- + +## 五、数据模型扩展 + +现有 `SurgeryDto` 需增加以下字段: + +| 字段 | 类型 | 说明 | +|------|------|------| +| surgeryLevel | String | 手术级别(1/2/3/4) | +| surgeryRoom | String | 手术室 | +| anesthesiaType | String | 麻醉方式(全麻/局麻/脊麻/硬膜外) | +| preopDiagnosis | String | 术前诊断 | +| postopDiagnosis | String | 术后诊断 | +| startTime | DateTime | 实际开始时间 | +| endTime | DateTime | 实际结束时间 | +| complications | String | 并发症记录 | +| bloodLoss | Integer | 术中出血量(ml) | +| specimenSent | Boolean | 是否送检标本 | + +--- + +## 六、测试用例 + +| 用例编号 | 场景 | 操作步骤 | 预期结果 | +|---------|------|---------|---------| +| TC-S001 | 正常申请流程 | 医生提交→科主任审批→护士安排→手术完成 | 状态正确流转 | +| TC-S002 | 越级申请拒绝 | 住院医师申请四级手术 | 返回权限不足错误 | +| TC-S003 | 手术室冲突 | 同一时间安排两台手术到同一手术室 | 返回冲突提示 | +| TC-S004 | 驳回后重新提交 | 科主任驳回→医生修改→重新提交 | 状态从驳回回到待审批 | +| TC-S005 | 取消手术 | 已审批的手术点击取消 | 状态变为已取消 | +| TC-S006 | 缺少术前讨论 | 三级手术无术前讨论记录直接提交 | 拦截并提示 | + diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/basicmanage/controller/BedController.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/basicmanage/controller/BedController.java index f443329cb..78380d530 100644 --- a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/basicmanage/controller/BedController.java +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/basicmanage/controller/BedController.java @@ -52,4 +52,56 @@ public class BedController { Bed bed = new Bed(); bed.setId(id); bed.setStatus(status); return bedService.updateById(bed) ? R.ok("状态更新成功") : R.fail("状态更新失败"); } -} + + /** + * 获取床位使用统计(铁律15: BR-004) + */ + @GetMapping("/statistics") + public R getStatistics(@RequestParam(value = "deptId", required = false) Long deptId) { + LambdaQueryWrapper baseWrapper = new LambdaQueryWrapper<>(); + if (deptId != null) baseWrapper.eq(Bed::getDeptId, deptId); + + long total = bedService.count(baseWrapper); + long occupied = bedService.count(baseWrapper.clone().eq(Bed::getStatus, 1)); + long available = bedService.count(baseWrapper.clone().eq(Bed::getStatus, 0)); + long cleaning = bedService.count(baseWrapper.clone().eq(Bed::getStatus, 2)); + long maintenance = bedService.count(baseWrapper.clone().eq(Bed::getStatus, 3)); + double usageRate = total > 0 ? (double) occupied / total * 100 : 0; + + return R.ok(java.util.Map.of( + "total", total, "occupied", occupied, "available", available, + "cleaning", cleaning, "maintenance", maintenance, + "usageRate", Math.round(usageRate * 100.0) / 100.0 + )); + } + + /** + * 分配床位(铁律15: BR-001 + BR-002) + */ + @PutMapping("/assign") + public R assignBed(@RequestParam Long bedId, @RequestParam Long patientId, @RequestParam Long deptId) { + Bed bed = bedService.getById(bedId); + if (bed == null) return R.fail("床位不存在"); + if (bed.getStatus() != 0) return R.fail("该床位当前不可分配(状态: " + + java.util.Map.of(0, "空闲", 1, "占用", 2, "清洁中", 3, "维修中").getOrDefault(bed.getStatus(), "未知") + ")"); + if (bed.getDeptId() != null && !bed.getDeptId().equals(deptId)) { + return R.fail("床位所属科室与患者入院科室不匹配"); + } + bed.setStatus(1); + bedService.updateById(bed); + return R.ok("分配成功"); + } + + /** + * 出院释放床位(铁律15: BR-003) + */ + @PutMapping("/discharge") + public R dischargeBed(@RequestParam Long bedId) { + Bed bed = bedService.getById(bedId); + if (bed == null) return R.fail("床位不存在"); + bed.setStatus(2); // 清洁中 + bedService.updateById(bed); + return R.ok("已标记为清洁中"); + } + +} \ No newline at end of file diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/clinicalmanage/appservice/ISurgeryAppService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/clinicalmanage/appservice/ISurgeryAppService.java index 818818ef6..ba025b7dc 100755 --- a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/clinicalmanage/appservice/ISurgeryAppService.java +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/clinicalmanage/appservice/ISurgeryAppService.java @@ -6,6 +6,7 @@ import com.healthlink.his.administration.domain.Encounter; import com.healthlink.his.web.clinicalmanage.dto.SurgeryDto; import java.util.List; +import java.util.Map; /** * 手术管理应用Service接口 @@ -77,4 +78,24 @@ public interface ISurgeryAppService { * @return 就诊列表 */ R> getEncounterListByPatientId(Long patientId); + + /** + * 校验手术室冲突(铁律15: SR-004) + * 检查同一手术室同一时间是否有其他手术安排 + * + * @param surgeryRoom 手术室 + * @param plannedTime 计划时间 + * @param excludeId 排除的手术ID(编辑时用) + * @return 校验结果 + */ + R checkOperatingRoomConflict(String surgeryRoom, String plannedTime, Long excludeId); + + /** + * 获取手术统计信息 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 统计数据 + */ + Map getSurgeryStatistics(String startDate, String endDate); } diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/clinicalmanage/appservice/impl/SurgeryAppServiceImpl.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/clinicalmanage/appservice/impl/SurgeryAppServiceImpl.java index 15dfb3e48..849ba7f1f 100755 --- a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/clinicalmanage/appservice/impl/SurgeryAppServiceImpl.java +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/clinicalmanage/appservice/impl/SurgeryAppServiceImpl.java @@ -835,4 +835,44 @@ public class SurgeryAppServiceImpl implements ISurgeryAppService { log.info("清除就诊手术列表缓存 - encounterId: {}", surgery.getEncounterId()); } } + + /** + * 校验手术室冲突(铁律15: SR-004) + */ + @Override + public R checkOperatingRoomConflict(String surgeryRoom, String plannedTime, Long excludeId) { + if (surgeryRoom == null || plannedTime == null) { + return R.ok(false); + } + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Surgery::getOperatingRoomName, surgeryRoom) + .eq(Surgery::getPlannedTime, plannedTime) + .in(Surgery::getStatusEnum, 2, 3) // 已审批或待手术 + .ne(excludeId != null, Surgery::getId, excludeId); + long conflictCount = surgeryService.count(wrapper); + if (conflictCount > 0) { + return R.fail("该手术室在该时间段已有手术安排,请选择其他时间或手术室"); + } + return R.ok(false); + } + + /** + * 获取手术统计信息(铁律15: 统计分析) + */ + @Override + public Map getSurgeryStatistics(String startDate, String endDate) { + Map stats = new HashMap<>(); + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + if (startDate != null && endDate != null) { + wrapper.between(Surgery::getCreateTime, startDate, endDate); + } + stats.put("total", surgeryService.count(wrapper)); + stats.put("pending", surgeryService.count(wrapper.clone().eq(Surgery::getStatusEnum, 0))); + stats.put("approved", surgeryService.count(wrapper.clone().eq(Surgery::getStatusEnum, 2))); + stats.put("inProgress", surgeryService.count(wrapper.clone().eq(Surgery::getStatusEnum, 4))); + stats.put("completed", surgeryService.count(wrapper.clone().eq(Surgery::getStatusEnum, 5))); + stats.put("cancelled", surgeryService.count(wrapper.clone().eq(Surgery::getStatusEnum, 7))); + return stats; + } + } \ No newline at end of file diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/clinicalmanage/controller/SurgeryController.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/clinicalmanage/controller/SurgeryController.java index c782cbc98..0d4caaf49 100755 --- a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/clinicalmanage/controller/SurgeryController.java +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/clinicalmanage/controller/SurgeryController.java @@ -115,4 +115,26 @@ public class SurgeryController { public R> getEncounterListByPatientId(@RequestParam Long patientId) { return surgeryAppService.getEncounterListByPatientId(patientId); } -} + + /** + * 校验手术室冲突(铁律15: SR-004) + */ + @GetMapping(value = "/check-room-conflict") + public R checkOperatingRoomConflict( + @RequestParam String surgeryRoom, + @RequestParam String plannedTime, + @RequestParam(value = "excludeId", required = false) Long excludeId) { + return surgeryAppService.checkOperatingRoomConflict(surgeryRoom, plannedTime, excludeId); + } + + /** + * 手术统计信息 + */ + @GetMapping(value = "/statistics") + public R getSurgeryStatistics( + @RequestParam(value = "startDate", required = false) String startDate, + @RequestParam(value = "endDate", required = false) String endDate) { + return R.ok(surgeryAppService.getSurgeryStatistics(startDate, endDate)); + } + +} \ No newline at end of file diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/controller/EsbMessageController.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/controller/EsbMessageController.java new file mode 100644 index 000000000..5e270ecd1 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/controller/EsbMessageController.java @@ -0,0 +1,104 @@ +package com.healthlink.his.web.esbmanage.controller; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.core.common.core.domain.R; +import com.healthlink.his.esb.domain.EsbMessage; +import com.healthlink.his.esb.service.IEsbMessageService; +import com.healthlink.his.esb.domain.EsbServiceRegistry; +import com.healthlink.his.esb.service.IEsbServiceRegistryService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; +import java.util.UUID; +@RestController +@RequestMapping("/esb/message") +@Slf4j +@AllArgsConstructor +public class EsbMessageController { + private final IEsbMessageService esbMessageService; + private final IEsbServiceRegistryService registryService; + @GetMapping("/page") + public R getPage(@RequestParam(value = "sourceSystem", required = false) String sourceSystem, + @RequestParam(value = "targetSystem", required = false) String targetSystem, + @RequestParam(value = "status", required = false) String status, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "20") Integer pageSize) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(StringUtils.hasText(sourceSystem), EsbMessage::getSourceSystem, sourceSystem) + .eq(StringUtils.hasText(targetSystem), EsbMessage::getTargetSystem, targetSystem) + .eq(StringUtils.hasText(status), EsbMessage::getStatus, status) + .orderByDesc(EsbMessage::getCreateTime); + return R.ok(esbMessageService.page(new Page<>(pageNo, pageSize), wrapper)); + } + @PostMapping("/send") + public R sendMessage(@RequestBody EsbMessage message) { + message.setMessageId(UUID.randomUUID().toString().replace("-", "")); + message.setStatus("待发送"); + message.setRetryCount(0); + boolean result = esbMessageService.save(message); + return result ? R.ok("消息已提交") : R.fail("提交失败"); + } + @PutMapping("/retry/{id}") + public R retryMessage(@PathVariable Long id) { + EsbMessage msg = esbMessageService.getById(id); + if (msg == null) return R.fail("消息不存在"); + msg.setStatus("重试中"); + msg.setRetryCount(msg.getRetryCount() + 1); + esbMessageService.updateById(msg); + return R.ok("重试已提交"); + } + @GetMapping("/stats") + public R getStats() { + long pending = esbMessageService.count(new LambdaQueryWrapper().eq(EsbMessage::getStatus, "待发送")); + long sent = esbMessageService.count(new LambdaQueryWrapper().eq(EsbMessage::getStatus, "已发送")); + long failed = esbMessageService.count(new LambdaQueryWrapper().eq(EsbMessage::getStatus, "发送失败")); + long total = esbMessageService.count(); + return R.ok(java.util.Map.of("pending", pending, "sent", sent, "failed", failed, "total", total)); + } + + /** + * 消息路由校验(铁律15: ESB业务规则) + * 校验目标系统是否已注册且状态为启用 + */ + @PostMapping("/route-check") + public R checkRoute(@RequestParam String targetSystem) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(EsbServiceRegistry::getServiceName, targetSystem) + .eq(EsbServiceRegistry::getServiceStatus, "启用"); + boolean exists = registryService.count(wrapper) > 0; + if (!exists) { + return R.fail("目标系统 '" + targetSystem + "' 未注册或已停用,无法路由消息"); + } + return R.ok("路由校验通过"); + } + + /** + * 消息轨迹查询 + */ + @GetMapping("/trace/{messageId}") + public R getTrace(@PathVariable String messageId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(EsbMessage::getMessageId, messageId).orderByAsc(EsbMessage::getCreateTime); + return R.ok(esbMessageService.list(wrapper)); + } + + /** + * 死信队列处理(铁律15: 失败消息处理) + * 重置失败消息状态为待发送 + */ + @PutMapping("/reset-dead-letter") + public R resetDeadLetter(@RequestParam Long id) { + EsbMessage msg = esbMessageService.getById(id); + if (msg == null) return R.fail("消息不存在"); + if (!"发送失败".equals(msg.getStatus())) return R.fail("只能重置失败消息"); + msg.setStatus("待发送"); + msg.setRetryCount(0); + msg.setErrorMessage(null); + esbMessageService.updateById(msg); + return R.ok("消息已重置为待发送"); + } + +} \ No newline at end of file diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/controller/EsbServiceRegistryController.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/controller/EsbServiceRegistryController.java new file mode 100644 index 000000000..c0460aa2c --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/controller/EsbServiceRegistryController.java @@ -0,0 +1,52 @@ +package com.healthlink.his.web.esbmanage.controller; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.core.common.core.domain.R; +import com.healthlink.his.esb.domain.EsbServiceRegistry; +import com.healthlink.his.esb.service.IEsbServiceRegistryService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; +import java.util.List; +@RestController +@RequestMapping("/esb/registry") +@Slf4j +@AllArgsConstructor +public class EsbServiceRegistryController { + private final IEsbServiceRegistryService registryService; + @GetMapping("/page") + public R getPage(@RequestParam(value = "serviceName", required = false) String serviceName, + @RequestParam(value = "serviceStatus", required = false) String serviceStatus, + @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(value = "pageSize", defaultValue = "20") Integer pageSize) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.like(StringUtils.hasText(serviceName), EsbServiceRegistry::getServiceName, serviceName) + .eq(StringUtils.hasText(serviceStatus), EsbServiceRegistry::getServiceStatus, serviceStatus) + .orderByAsc(EsbServiceRegistry::getServiceName); + return R.ok(registryService.page(new Page<>(pageNo, pageSize), wrapper)); + } + @GetMapping("/list") + public R> getList() { + return R.ok(registryService.list(new LambdaQueryWrapper().orderByAsc(EsbServiceRegistry::getServiceName))); + } + @PostMapping("/add") + public R add(@RequestBody EsbServiceRegistry registry) { + registry.setServiceStatus("启用"); + return registryService.save(registry) ? R.ok("注册成功") : R.fail("注册失败"); + } + @PutMapping("/update") + public R update(@RequestBody EsbServiceRegistry registry) { + return registryService.updateById(registry) ? R.ok("修改成功") : R.fail("修改失败"); + } + @DeleteMapping("/delete") + public R delete(@RequestParam Long id) { + return registryService.removeById(id) ? R.ok("删除成功") : R.fail("删除失败"); + } + @PutMapping("/status") + public R updateStatus(@RequestParam Long id, @RequestParam String status) { + EsbServiceRegistry reg = new EsbServiceRegistry(); reg.setId(id); reg.setServiceStatus(status); + return registryService.updateById(reg) ? R.ok("状态更新成功") : R.fail("状态更新失败"); + } +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V13__esb_integration_platform.sql b/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V13__esb_integration_platform.sql new file mode 100644 index 000000000..521cc7d4a --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V13__esb_integration_platform.sql @@ -0,0 +1,39 @@ +CREATE TABLE IF NOT EXISTS sys_esb_message ( + id BIGSERIAL PRIMARY KEY, + message_id VARCHAR(100) NOT NULL UNIQUE, + message_type VARCHAR(50), + source_system VARCHAR(50), + target_system VARCHAR(50), + message_content TEXT, + message_format VARCHAR(20), + status VARCHAR(20) DEFAULT '待发送', + retry_count INT DEFAULT 0, + error_message TEXT, + send_time TIMESTAMP, + ack_time TIMESTAMP, + create_by VARCHAR(64), + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by VARCHAR(64), + update_time TIMESTAMP, + tenant_id INT DEFAULT 0 +); +CREATE INDEX IF NOT EXISTS idx_esb_msg_status ON sys_esb_message(status); +CREATE INDEX IF NOT EXISTS idx_esb_msg_source ON sys_esb_message(source_system); +CREATE INDEX IF NOT EXISTS idx_esb_msg_target ON sys_esb_message(target_system); + +CREATE TABLE IF NOT EXISTS sys_esb_service_registry ( + id BIGSERIAL PRIMARY KEY, + service_name VARCHAR(100) NOT NULL, + service_version VARCHAR(20), + service_endpoint VARCHAR(500), + service_description TEXT, + service_status VARCHAR(20) DEFAULT '启用', + protocol VARCHAR(20) DEFAULT 'HTTP', + timeout_ms INT DEFAULT 5000, + create_by VARCHAR(64), + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by VARCHAR(64), + update_time TIMESTAMP, + tenant_id INT DEFAULT 0 +); +CREATE INDEX IF NOT EXISTS idx_esb_reg_name ON sys_esb_service_registry(service_name); diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/domain/EsbMessage.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/domain/EsbMessage.java new file mode 100644 index 000000000..b87ce3377 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/domain/EsbMessage.java @@ -0,0 +1,26 @@ +package com.healthlink.his.esb.domain; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.core.common.core.domain.HisBaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.util.Date; +@Data +@TableName("sys_esb_message") +@EqualsAndHashCode(callSuper = false) +public class EsbMessage extends HisBaseEntity { + @TableId(type = IdType.ASSIGN_ID) + private Long id; + private String messageId; + private String messageType; + private String sourceSystem; + private String targetSystem; + private String messageContent; + private String messageFormat; + private String status; + private Integer retryCount; + private String errorMessage; + private Date sendTime; + private Date ackTime; +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/domain/EsbServiceRegistry.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/domain/EsbServiceRegistry.java new file mode 100644 index 000000000..9c033e6a1 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/domain/EsbServiceRegistry.java @@ -0,0 +1,21 @@ +package com.healthlink.his.esb.domain; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.core.common.core.domain.HisBaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +@Data +@TableName("sys_esb_service_registry") +@EqualsAndHashCode(callSuper = false) +public class EsbServiceRegistry extends HisBaseEntity { + @TableId(type = IdType.ASSIGN_ID) + private Long id; + private String serviceName; + private String serviceVersion; + private String serviceEndpoint; + private String serviceDescription; + private String serviceStatus; + private String protocol; + private Integer timeoutMs; +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/mapper/EsbMessageMapper.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/mapper/EsbMessageMapper.java new file mode 100644 index 000000000..624e5f2c8 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/mapper/EsbMessageMapper.java @@ -0,0 +1,6 @@ +package com.healthlink.his.esb.mapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.healthlink.his.esb.domain.EsbMessage; +import org.apache.ibatis.annotations.Mapper; +@Mapper +public interface EsbMessageMapper extends BaseMapper {} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/mapper/EsbServiceRegistryMapper.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/mapper/EsbServiceRegistryMapper.java new file mode 100644 index 000000000..58c348bb1 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/mapper/EsbServiceRegistryMapper.java @@ -0,0 +1,6 @@ +package com.healthlink.his.esb.mapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.healthlink.his.esb.domain.EsbServiceRegistry; +import org.apache.ibatis.annotations.Mapper; +@Mapper +public interface EsbServiceRegistryMapper extends BaseMapper {} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/IEsbMessageService.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/IEsbMessageService.java new file mode 100644 index 000000000..43719ed84 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/IEsbMessageService.java @@ -0,0 +1,4 @@ +package com.healthlink.his.esb.service; +import com.baomidou.mybatisplus.extension.service.IService; +import com.healthlink.his.esb.domain.EsbMessage; +public interface IEsbMessageService extends IService {} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/IEsbServiceRegistryService.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/IEsbServiceRegistryService.java new file mode 100644 index 000000000..fa7ea6643 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/IEsbServiceRegistryService.java @@ -0,0 +1,4 @@ +package com.healthlink.his.esb.service; +import com.baomidou.mybatisplus.extension.service.IService; +import com.healthlink.his.esb.domain.EsbServiceRegistry; +public interface IEsbServiceRegistryService extends IService {} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/impl/EsbMessageServiceImpl.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/impl/EsbMessageServiceImpl.java new file mode 100644 index 000000000..6dabf7c43 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/impl/EsbMessageServiceImpl.java @@ -0,0 +1,8 @@ +package com.healthlink.his.esb.service.impl; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.healthlink.his.esb.domain.EsbMessage; +import com.healthlink.his.esb.mapper.EsbMessageMapper; +import com.healthlink.his.esb.service.IEsbMessageService; +import org.springframework.stereotype.Service; +@Service +public class EsbMessageServiceImpl extends ServiceImpl implements IEsbMessageService {} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/impl/EsbServiceRegistryServiceImpl.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/impl/EsbServiceRegistryServiceImpl.java new file mode 100644 index 000000000..ebbef04f7 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/impl/EsbServiceRegistryServiceImpl.java @@ -0,0 +1,8 @@ +package com.healthlink.his.esb.service.impl; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.healthlink.his.esb.domain.EsbServiceRegistry; +import com.healthlink.his.esb.mapper.EsbServiceRegistryMapper; +import com.healthlink.his.esb.service.IEsbServiceRegistryService; +import org.springframework.stereotype.Service; +@Service +public class EsbServiceRegistryServiceImpl extends ServiceImpl implements IEsbServiceRegistryService {} diff --git a/healthlink-his-ui/src/views/esbmanage/message/components/api.js b/healthlink-his-ui/src/views/esbmanage/message/components/api.js new file mode 100644 index 000000000..543a0d58d --- /dev/null +++ b/healthlink-his-ui/src/views/esbmanage/message/components/api.js @@ -0,0 +1,5 @@ +import request from '@/utils/request' +export function getMessagePage(params) { return request({ url: '/esb/message/page', method: 'get', params }) } +export function sendMessage(data) { return request({ url: '/esb/message/send', method: 'post', data }) } +export function retryMessage(id) { return request({ url: '/esb/message/retry/' + id, method: 'put' }) } +export function getMessageStats() { return request({ url: '/esb/message/stats', method: 'get' }) } diff --git a/healthlink-his-ui/src/views/esbmanage/message/index.vue b/healthlink-his-ui/src/views/esbmanage/message/index.vue new file mode 100644 index 000000000..ba2b4e543 --- /dev/null +++ b/healthlink-his-ui/src/views/esbmanage/message/index.vue @@ -0,0 +1,98 @@ + + + diff --git a/healthlink-his-ui/src/views/esbmanage/monitor/index.vue b/healthlink-his-ui/src/views/esbmanage/monitor/index.vue new file mode 100644 index 000000000..004236c4a --- /dev/null +++ b/healthlink-his-ui/src/views/esbmanage/monitor/index.vue @@ -0,0 +1,69 @@ + + + diff --git a/healthlink-his-ui/src/views/esbmanage/registry/components/api.js b/healthlink-his-ui/src/views/esbmanage/registry/components/api.js new file mode 100644 index 000000000..da3e5ef66 --- /dev/null +++ b/healthlink-his-ui/src/views/esbmanage/registry/components/api.js @@ -0,0 +1,6 @@ +import request from '@/utils/request' +export function getRegistryPage(params) { return request({ url: '/esb/registry/page', method: 'get', params }) } +export function addRegistry(data) { return request({ url: '/esb/registry/add', method: 'post', data }) } +export function updateRegistry(data) { return request({ url: '/esb/registry/update', method: 'put', data }) } +export function deleteRegistry(id) { return request({ url: '/esb/registry/delete', method: 'delete', params: { id } }) } +export function updateRegistryStatus(id, status) { return request({ url: '/esb/registry/status', method: 'put', params: { id, status } }) } diff --git a/healthlink-his-ui/src/views/esbmanage/registry/index.vue b/healthlink-his-ui/src/views/esbmanage/registry/index.vue new file mode 100644 index 000000000..9e5a9d808 --- /dev/null +++ b/healthlink-his-ui/src/views/esbmanage/registry/index.vue @@ -0,0 +1,91 @@ + + + diff --git a/healthlink-his-ui/src/views/ybmanagement/catalogManagement/index.vue b/healthlink-his-ui/src/views/ybmanagement/catalogManagement/index.vue index 2c8d26ac9..4cd10e43d 100644 --- a/healthlink-his-ui/src/views/ybmanagement/catalogManagement/index.vue +++ b/healthlink-his-ui/src/views/ybmanagement/catalogManagement/index.vue @@ -1,13 +1,62 @@ - + diff --git a/healthlink-his-ui/src/views/ybmanagement/medicalInsurance/index.vue b/healthlink-his-ui/src/views/ybmanagement/medicalInsurance/index.vue index 4577d0dd6..2c850a72d 100644 --- a/healthlink-his-ui/src/views/ybmanagement/medicalInsurance/index.vue +++ b/healthlink-his-ui/src/views/ybmanagement/medicalInsurance/index.vue @@ -1,13 +1,79 @@ - + diff --git a/healthlink-his-ui/src/views/ybmanagement/settlement/index.vue b/healthlink-his-ui/src/views/ybmanagement/settlement/index.vue index 6d628333f..a904761a1 100644 --- a/healthlink-his-ui/src/views/ybmanagement/settlement/index.vue +++ b/healthlink-his-ui/src/views/ybmanagement/settlement/index.vue @@ -1,13 +1,79 @@ - +