# 工伤联网接口数据库设计文档 ## 版本信息 | 版本号 | 修改内容 | 修改日期 | 修改人 | |--------|----------|----------|--------| | V1.0 | 初始版本设计 | 2024.12.19 | 系统架构师 | ## 目录 - [1 设计概述](#1-设计概述) - [2 数据库表设计](#2-数据库表设计) - [3 表关联关系](#3-表关联关系) - [4 使用案例](#4-使用案例) - [5 前端示例代码](#5-前端示例代码) - [6 后端示例代码](#6-后端示例代码) --- ## 1 设计概述 ### 1.1 业务需求 1. **工伤病人流程**:先调用工伤接口 → 存储调用记录 → 再调用HIS接口 → 存储HIS数据 2. **非工伤病人流程**:只调用HIS接口 → 存储HIS数据 3. **接口类型支持**:认证类、业务类、体检类、转院类、对账类、下载类 4. **设计原则**:简单、实用、可靠、通用、不为每个接口单独设计 ### 1.2 设计思路 采用**3表设计**方案,通过通用化设计支持所有工伤接口类型: - **工伤接口调用记录表**:记录所有工伤接口的调用情况 - **工伤病人关联信息表**:管理HIS病人与工伤系统的对应关系 - **工伤业务数据记录表**:存储具体的业务数据和结果 --- ## 2 数据库表设计 ### 2.1 工伤接口调用记录表 (WorkInjury_Interface_Log) > **作用**:记录每一次工伤接口的调用情况,包括请求参数、响应结果、调用状态等 > **应用场景**:所有工伤接口调用都要记录,用于日志追踪、问题排查、数据分析 ```sql CREATE TABLE WorkInjury_Interface_Log ( -- 主键信息 LogId BIGINT IDENTITY(1,1) PRIMARY KEY, -- 业务关联信息(用于关联HIS系统的病人和就诊) HisPatientId VARCHAR(50), -- HIS系统病人ID(病人表主键) HisVisitNo VARCHAR(50), -- HIS系统就诊流水号/住院号 WorkInjuryTransactionId VARCHAR(50), -- 工伤系统交易流水号 -- 接口调用信息(标识调用的是哪个工伤接口) InterfaceCode VARCHAR(10) NOT NULL, -- 接口编号:9001签到,2201登记,2207结算等 InterfaceName VARCHAR(100), -- 接口名称:签到,门诊登记,费用结算等 InterfaceCategory VARCHAR(20), -- 接口分类:认证类,业务类,体检类,对账类,下载类 -- 调用参数记录(完整保存调用的入参和返回参数) RequestData NTEXT, -- 请求参数JSON:调用工伤接口时的完整入参 ResponseData NTEXT, -- 响应参数JSON:工伤接口返回的完整数据 -- 调用结果信息(判断接口调用是否成功) CallResult BIT NOT NULL DEFAULT 0, -- 调用结果:0失败,1成功 ResultCode VARCHAR(20), -- 结果编码:工伤接口返回的错误码 ResultMessage NVARCHAR(500), -- 结果描述:错误信息或成功提示 -- 工伤系统返回的关键信息(用于后续业务关联) WorkInjuryMsgId VARCHAR(50), -- 工伤系统报文ID:用于冲正等操作 WorkInjurySignNo VARCHAR(50), -- 工伤系统签到流水号:业务操作必需 WorkInjuryQualificationId VARCHAR(50), -- 工伤资格审核ID:登记时返回的资格ID -- 时间和操作信息(记录操作过程信息) CallTime DATETIME NOT NULL DEFAULT GETDATE(), -- 调用时间:接口实际调用的时间 OperatorId VARCHAR(50), -- 操作员ID:谁操作的 OperatorName NVARCHAR(50), -- 操作员姓名:操作员中文名 TerminalId VARCHAR(50), -- 终端ID:哪台机器操作的 -- 扩展字段(用于存储特殊数据) Remark NVARCHAR(500), -- 备注:额外说明信息 ExtendData NTEXT, -- 扩展数据JSON:特殊业务数据 -- 创建和修改信息 CreateTime DATETIME NOT NULL DEFAULT GETDATE(), UpdateTime DATETIME NOT NULL DEFAULT GETDATE() ); -- 创建索引(提高查询性能) CREATE INDEX IX_WorkInjury_Interface_Log_Patient ON WorkInjury_Interface_Log(HisPatientId, CallTime); CREATE INDEX IX_WorkInjury_Interface_Log_Visit ON WorkInjury_Interface_Log(HisVisitNo, InterfaceCode); CREATE INDEX IX_WorkInjury_Interface_Log_Interface ON WorkInjury_Interface_Log(InterfaceCode, CallTime); CREATE INDEX IX_WorkInjury_Interface_Log_MsgId ON WorkInjury_Interface_Log(WorkInjuryMsgId); ``` ### 2.2 工伤病人关联信息表 (WorkInjury_Patient_Relation) > **作用**:管理HIS系统病人与工伤系统的对应关系,判断病人是否为工伤性质 > **应用场景**:病人登记时判断是否需要调用工伤接口,读卡时建立关联关系 ```sql CREATE TABLE WorkInjury_Patient_Relation ( -- 主键信息 RelationId BIGINT IDENTITY(1,1) PRIMARY KEY, -- HIS系统病人信息(关联HIS病人表) HisPatientId VARCHAR(50) NOT NULL, -- HIS系统病人ID:HIS病人表主键 HisCardNo VARCHAR(50), -- HIS病人卡号:院内就诊卡号 HisPatientName NVARCHAR(50), -- HIS病人姓名:在HIS中的姓名 HisIdCard VARCHAR(30), -- HIS身份证号:HIS中的身份证 -- 工伤系统病人信息(来自工伤读卡接口返回数据) WorkInjuryCardNo VARCHAR(50), -- 工伤社保卡号:工伤系统的卡号 WorkInjuryPsnNo VARCHAR(50), -- 工伤个人唯一识别码:工伤系统病人标识 WorkInjuryPsnName NVARCHAR(50), -- 工伤系统病人姓名:工伤系统中的姓名 WorkInjuryIdCard VARCHAR(30), -- 工伤系统身份证号:可能与HIS不完全一致 WorkInjuryInsuranceArea VARCHAR(20), -- 工伤保险统筹区:如"宿迁市" -- 工伤资格信息(判断病人工伤性质和资格) IsWorkInjuryPatient BIT NOT NULL DEFAULT 0, -- 是否工伤病人:0否,1是 WorkInjuryType VARCHAR(20), -- 工伤类型:门诊,住院,体检等 QualificationId VARCHAR(50), -- 工伤医疗费资格审核信息ID QualificationStatus VARCHAR(20), -- 资格审核状态:有效,过期,暂停等 QualificationExpireDate DATETIME, -- 资格有效期:过期需重新审核 -- 最近读卡信息(记录最新的工伤读卡数据) LastReadCardTime DATETIME, -- 最后读卡时间:最近一次成功读卡时间 LastReadCardData NTEXT, -- 最后读卡返回数据JSON:完整的读卡结果 -- 状态信息 Status CHAR(1) NOT NULL DEFAULT '1', -- 状态:1有效,0无效,2暂停 -- 扩展字段 Remark NVARCHAR(500), -- 备注:特殊说明 ExtendData NTEXT, -- 扩展数据JSON:其他相关数据 -- 创建和修改信息 CreateTime DATETIME NOT NULL DEFAULT GETDATE(), UpdateTime DATETIME NOT NULL DEFAULT GETDATE() ); -- 创建索引和约束 CREATE UNIQUE INDEX IX_WorkInjury_Patient_Relation_HisPatient ON WorkInjury_Patient_Relation(HisPatientId); CREATE INDEX IX_WorkInjury_Patient_Relation_WorkInjury ON WorkInjury_Patient_Relation(WorkInjuryPsnNo, WorkInjuryCardNo); CREATE INDEX IX_WorkInjury_Patient_Relation_IdCard ON WorkInjury_Patient_Relation(WorkInjuryIdCard); ``` ### 2.3 工伤业务数据记录表 (WorkInjury_Business_Data) > **作用**:存储具体的工伤业务数据,如登记信息、结算信息、处方明细、体检数据等 > **应用场景**:保存业务办理的详细数据,用于业务查询、数据统计、单据打印等 ```sql CREATE TABLE WorkInjury_Business_Data ( -- 主键信息 BusinessId BIGINT IDENTITY(1,1) PRIMARY KEY, -- 关联信息(与前两个表关联) LogId BIGINT, -- 关联接口调用记录表ID:哪次接口调用产生的数据 HisPatientId VARCHAR(50), -- HIS系统病人ID:对应病人表 HisVisitNo VARCHAR(50), -- HIS系统就诊号:门诊号或住院号 -- 业务类型信息(标识业务类型) BusinessType VARCHAR(20) NOT NULL, -- 业务类型:登记,结算,处方,体检,对账,下载等 BusinessCode VARCHAR(10), -- 业务编码:2201,2207,2204,8104,1320等 BusinessStatus VARCHAR(20), -- 业务状态:成功,失败,撤销,已冲正等 -- 工伤系统业务关键信息(来自工伤接口返回) WorkInjuryRegisterNo VARCHAR(50), -- 工伤登记流水号:登记成功后返回 WorkInjurySettleNo VARCHAR(50), -- 工伤结算流水号:结算成功后返回 WorkInjuryPreSettleId VARCHAR(50), -- 工伤预结算ID:预结算返回的ID -- 费用信息(结算相关业务使用) TotalFee DECIMAL(15,2), -- 总费用:本次业务涉及的总金额 WorkInjuryFee DECIMAL(15,2), -- 工伤基金支付:工伤保险支付金额 PersonalFee DECIMAL(15,2), -- 个人支付:病人自付金额 HospitalFee DECIMAL(15,2), -- 医院垫付:医院需要垫付的金额 -- 业务详细数据(JSON格式存储复杂数据) BusinessDetailData NTEXT, -- 业务明细数据JSON:处方明细,费用明细,体检项目等 HisBusinessData NTEXT, -- HIS系统业务数据JSON:HIS相关的业务数据 WorkInjuryResponseData NTEXT, -- 工伤接口完整返回JSON:完整的工伤接口返回数据 -- 相关单据信息(用于单据管理) HisReceiptNo VARCHAR(50), -- HIS发票号:HIS系统生成的发票号 WorkInjuryReceiptNo VARCHAR(50), -- 工伤结算单号:工伤系统的结算单号 HisPrescriptionNo VARCHAR(50), -- HIS处方号:处方相关业务使用 -- 时间信息 BusinessTime DATETIME, -- 业务发生时间:实际业务办理时间 -- 撤销和冲正信息(业务可能需要撤销) IsReversed BIT DEFAULT 0, -- 是否已冲正:0否,1是 ReversedLogId BIGINT, -- 冲正操作的日志ID:关联到冲正接口调用记录 ReversedTime DATETIME, -- 冲正时间:什么时候冲正的 ReversedReason NVARCHAR(200), -- 冲正原因:为什么要冲正 -- 扩展字段 Remark NVARCHAR(500), -- 备注:业务特殊说明 ExtendData NTEXT, -- 扩展数据JSON:其他业务数据 -- 创建和修改信息 CreateTime DATETIME NOT NULL DEFAULT GETDATE(), UpdateTime DATETIME NOT NULL DEFAULT GETDATE() ); -- 创建索引 CREATE INDEX IX_WorkInjury_Business_Data_LogId ON WorkInjury_Business_Data(LogId); CREATE INDEX IX_WorkInjury_Business_Data_Patient ON WorkInjury_Business_Data(HisPatientId, BusinessTime); CREATE INDEX IX_WorkInjury_Business_Data_Visit ON WorkInjury_Business_Data(HisVisitNo, BusinessType); CREATE INDEX IX_WorkInjury_Business_Data_WorkInjury ON WorkInjury_Business_Data(WorkInjuryRegisterNo, WorkInjurySettleNo); CREATE INDEX IX_WorkInjury_Business_Data_Business ON WorkInjury_Business_Data(BusinessType, BusinessStatus, BusinessTime); ``` --- ## 3 表关联关系 ### 3.1 表关系图 ``` HIS病人表 (His_Patient) ↓ (1:1) 工伤病人关联表 (WorkInjury_Patient_Relation) ↓ (1:N) 工伤接口调用记录表 (WorkInjury_Interface_Log) ↓ (1:N) 工伤业务数据记录表 (WorkInjury_Business_Data) ``` ### 3.2 关联说明 1. **HIS病人表 ← → 工伤病人关联表** - 关联字段:`HisPatientId` - 关系:一对一,一个HIS病人对应一条工伤关联记录 - 用途:判断病人是否为工伤性质 2. **工伤病人关联表 → 工伤接口调用记录表** - 关联字段:`HisPatientId` - 关系:一对多,一个病人可以有多次接口调用 - 用途:追踪病人的所有工伤接口调用历史 3. **工伤接口调用记录表 → 工伤业务数据记录表** - 关联字段:`LogId` - 关系:一对多,一次接口调用可能产生多条业务数据 - 用途:存储接口调用产生的具体业务数据 ### 3.3 数据流向 ``` 病人挂号/就诊 ↓ 判断是否工伤病人 (查询WorkInjury_Patient_Relation) ↓ (是工伤) 调用工伤接口 → 记录到WorkInjury_Interface_Log ↓ (成功) 解析业务数据 → 存储到WorkInjury_Business_Data ↓ 调用HIS接口 → 存储HIS业务数据 ``` --- ## 4 使用案例 ### 4.1 典型业务场景案例 #### 4.1.1 工伤病人门诊登记流程 **场景描述**:工伤病人来医院看门诊,需要先在工伤系统登记,再在HIS系统登记 **数据操作流程**: ```sql -- 1. 判断是否工伤病人 SELECT IsWorkInjuryPatient, WorkInjuryPsnNo, QualificationId FROM WorkInjury_Patient_Relation WHERE HisPatientId = 'P12345' AND Status = '1'; -- 如果是工伤病人,继续以下步骤: -- 2. 调用工伤登记接口后,记录接口调用日志 INSERT INTO WorkInjury_Interface_Log ( HisPatientId, HisVisitNo, InterfaceCode, InterfaceName, InterfaceCategory, RequestData, ResponseData, CallResult, ResultCode, ResultMessage, WorkInjuryMsgId, WorkInjuryQualificationId, CallTime, OperatorId, OperatorName ) VALUES ( 'P12345', 'MZ2024120100001', '2201', '门诊/住院登记', '业务类', '{"infno":"2201","psn_no":"32123456789","med_type":"11",...}', '{"infcode":"0","output":{"ipt_otp_no":"WS2024120100001"},...}', 1, '0', '登记成功', 'SQ201348202412011030001', 'WS2024120100001', GETDATE(), 'DOC001', '张医生' ); -- 3. 记录业务数据 INSERT INTO WorkInjury_Business_Data ( LogId, HisPatientId, HisVisitNo, BusinessType, BusinessCode, BusinessStatus, WorkInjuryRegisterNo, BusinessDetailData, BusinessTime ) VALUES ( @@IDENTITY, 'P12345', 'MZ2024120100001', '登记', '2201', '成功', 'WS2024120100001', '{"med_type":"11","adm_dept":"内科",...}', GETDATE() ); ``` #### 4.1.2 工伤费用结算流程 **场景描述**:工伤病人看完病,需要先在工伤系统结算,确定报销金额,再在HIS收费 ```sql -- 1. 处方明细上传 INSERT INTO WorkInjury_Interface_Log (...) VALUES (...); -- 接口调用日志 INSERT INTO WorkInjury_Business_Data ( LogId, HisPatientId, HisVisitNo, BusinessType, BusinessCode, BusinessDetailData, BusinessTime ) VALUES ( @@IDENTITY, 'P12345', 'MZ2024120100001', '处方', '2204', '{"feedetail":[{"med_list_codg":"A01.01.001","med_name":"阿莫西林",...}]}', GETDATE() ); -- 2. 费用预结算 INSERT INTO WorkInjury_Interface_Log (...) VALUES (...); INSERT INTO WorkInjury_Business_Data ( LogId, HisPatientId, HisVisitNo, BusinessType, BusinessCode, WorkInjuryPreSettleId, TotalFee, WorkInjuryFee, PersonalFee, BusinessDetailData, BusinessTime ) VALUES ( @@IDENTITY, 'P12345', 'MZ2024120100001', '预结算', '2206', 'PRE20241201001', 150.00, 120.00, 30.00, '{"pre_settle_data":{"psn_part_amt":30.00,"fund_pay_amt":120.00}}', GETDATE() ); -- 3. 正式结算 INSERT INTO WorkInjury_Interface_Log (...) VALUES (...); INSERT INTO WorkInjury_Business_Data ( LogId, HisPatientId, HisVisitNo, BusinessType, BusinessCode, WorkInjurySettleNo, TotalFee, WorkInjuryFee, PersonalFee, WorkInjuryReceiptNo, BusinessTime ) VALUES ( @@IDENTITY, 'P12345', 'MZ2024120100001', '结算', '2207', 'SET20241201001', 150.00, 120.00, 30.00, 'WS2024120100001', GETDATE() ); ``` #### 4.1.3 对账类接口使用 **场景描述**:每日对账,下载工伤系统的结算汇总数据 ```sql -- 总额对账接口调用 INSERT INTO WorkInjury_Interface_Log ( InterfaceCode, InterfaceName, InterfaceCategory, RequestData, ResponseData, CallResult, BusinessDetailData, CallTime, OperatorId ) VALUES ( '1320', '总额对账', '对账类', '{"stmt_begndate":"20241201","stmt_enddate":"20241201"}', '{"infcode":"0","output":{"total_cnt":15,"total_amt":2250.00}}', 1, '{"account_date":"20241201","total_count":15,"total_amount":2250.00}', GETDATE(), 'SYS001' ); -- 对账业务数据记录 INSERT INTO WorkInjury_Business_Data ( LogId, BusinessType, BusinessCode, BusinessStatus, TotalFee, BusinessDetailData, BusinessTime ) VALUES ( @@IDENTITY, '对账', '1320', '成功', 2250.00, '{"account_date":"20241201","detail_count":15}', GETDATE() ); ``` #### 4.1.4 下载类接口使用 **场景描述**:下载费用明细数据,用于对账核实 ```sql -- 费用明细下载 INSERT INTO WorkInjury_Interface_Log ( InterfaceCode, InterfaceName, InterfaceCategory, RequestData, ResponseData, CallResult, BusinessDetailData, CallTime ) VALUES ( '9103', '费用明细详细信息下载', '下载类', '{"queryCond":{"stmt_begndate":"20241201","stmt_enddate":"20241201"}}', '{"infcode":"0","output":{"feedetail":[...]}}', 1, '{"download_date":"20241201","record_count":156}', GETDATE() ); ``` --- ## 5 前端示例代码 ### 5.1 jQuery 示例 - 工伤病人登记 ```html 工伤病人登记

工伤病人登记

HIS系统登记

``` ### 5.2 Vue 3.0 示例 - 工伤费用结算 ```vue ``` --- ## 6 后端示例代码 ### 6.1 Spring Boot 示例 - 工伤接口服务 ```java package com.hospital.workinjury.service; import com.fasterxml.jackson.databind.ObjectMapper; import com.hospital.workinjury.entity.*; import com.hospital.workinjury.repository.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.client.RestTemplate; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.HashMap; import java.util.Map; /** * 工伤联网接口服务类 * 负责工伤接口调用和数据存储的核心业务逻辑 */ @Slf4j @Service @RequiredArgsConstructor public class WorkInjuryService { private final WorkInjuryInterfaceLogRepository logRepository; private final WorkInjuryPatientRelationRepository relationRepository; private final WorkInjuryBusinessDataRepository businessRepository; private final RestTemplate restTemplate; private final ObjectMapper objectMapper; // 工伤接口地址配置 private static final String WORK_INJURY_API_URL = "http://localhost:8321/api/workinjury/transaction"; /** * 检查病人工伤性质 * @param patientId HIS病人ID * @return 工伤病人信息 */ public WorkInjuryPatientInfo checkWorkInjuryPatient(String patientId) { log.info("检查病人工伤性质, patientId: {}", patientId); WorkInjuryPatientRelation relation = relationRepository.findByHisPatientId(patientId); WorkInjuryPatientInfo info = new WorkInjuryPatientInfo(); info.setPatientId(patientId); if (relation != null && relation.getIsWorkInjuryPatient()) { info.setWorkInjuryPatient(true); info.setWorkInjuryCardNo(relation.getWorkInjuryCardNo()); info.setWorkInjuryPsnNo(relation.getWorkInjuryPsnNo()); info.setQualificationId(relation.getQualificationId()); info.setQualificationStatus(relation.getQualificationStatus()); info.setQualificationExpireDate(relation.getQualificationExpireDate()); } else { info.setWorkInjuryPatient(false); } return info; } /** * 工伤病人登记流程 * 先调用工伤接口,成功后记录数据,再调用HIS接口 */ @Transactional public WorkInjuryRegisterResult registerWorkInjuryPatient(WorkInjuryRegisterRequest request) { log.info("开始工伤病人登记流程, patientId: {}, visitNo: {}", request.getPatientId(), request.getVisitNo()); WorkInjuryRegisterResult result = new WorkInjuryRegisterResult(); try { // 1. 检查是否工伤病人 WorkInjuryPatientRelation relation = relationRepository.findByHisPatientId(request.getPatientId()); if (relation == null || !relation.getIsWorkInjuryPatient()) { // 非工伤病人,直接调用HIS登记 return registerHisPatientOnly(request); } // 2. 调用工伤登记接口 WorkInjuryApiResult workInjuryResult = callWorkInjuryRegisterApi(request, relation); // 3. 记录工伤接口调用日志 Long logId = saveInterfaceLog(request, workInjuryResult, "2201", "门诊/住院登记", "业务类"); if (workInjuryResult.isSuccess()) { // 4. 记录工伤业务数据 saveBusinessData(logId, request, workInjuryResult, "登记", "2201"); // 5. 调用HIS登记接口 HisRegisterResult hisResult = callHisRegisterApi(request); // 6. 组装返回结果 result.setSuccess(true); result.setMessage("工伤病人登记成功"); result.setWorkInjuryRegisterNo(workInjuryResult.getData().get("ipt_otp_no").toString()); result.setHisVisitNo(hisResult.getVisitNo()); result.setQualificationId(workInjuryResult.getData().get("qualification_id").toString()); log.info("工伤病人登记成功, 工伤登记号: {}, HIS就诊号: {}", result.getWorkInjuryRegisterNo(), result.getHisVisitNo()); } else { result.setSuccess(false); result.setMessage("工伤登记失败: " + workInjuryResult.getMessage()); log.error("工伤登记失败: {}", workInjuryResult.getMessage()); } } catch (Exception e) { log.error("工伤病人登记异常", e); result.setSuccess(false); result.setMessage("登记异常: " + e.getMessage()); } return result; } /** * 工伤费用结算流程 * 处方上传 -> 预结算 -> 正式结算 -> HIS收费 */ @Transactional public WorkInjurySettlementResult settleWorkInjuryFee(WorkInjurySettlementRequest request) { log.info("开始工伤费用结算流程, visitNo: {}", request.getVisitNo()); WorkInjurySettlementResult result = new WorkInjurySettlementResult(); try { // 1. 检查病人工伤性质 WorkInjuryPatientRelation relation = relationRepository.findByHisPatientId(request.getPatientId()); if (relation == null || !relation.getIsWorkInjuryPatient()) { // 非工伤病人,直接HIS收费 return settleHisFeeOnly(request); } // 2. 上传处方明细 WorkInjuryApiResult uploadResult = uploadPrescriptionDetail(request); if (!uploadResult.isSuccess()) { result.setSuccess(false); result.setMessage("处方上传失败: " + uploadResult.getMessage()); return result; } // 3. 费用预结算 WorkInjuryApiResult preSettleResult = preSettleFee(request); if (!preSettleResult.isSuccess()) { result.setSuccess(false); result.setMessage("预结算失败: " + preSettleResult.getMessage()); return result; } // 4. 正式结算 WorkInjuryApiResult settleResult = settleFee(request); if (!settleResult.isSuccess()) { result.setSuccess(false); result.setMessage("工伤结算失败: " + settleResult.getMessage()); return result; } // 5. 解析结算结果 Map settleData = settleResult.getData(); BigDecimal totalFee = new BigDecimal(settleData.get("medfee_sumamt").toString()); BigDecimal workInjuryFee = new BigDecimal(settleData.get("fund_pay_amt").toString()); BigDecimal personalFee = new BigDecimal(settleData.get("psn_part_amt").toString()); // 6. 记录结算业务数据 Long logId = saveInterfaceLog(request, settleResult, "2207", "费用结算", "业务类"); saveSettlementBusinessData(logId, request, settleResult, totalFee, workInjuryFee, personalFee); // 7. HIS收费(只收个人支付部分) HisSettlementResult hisResult = callHisSettlementApi(request, personalFee); // 8. 组装返回结果 result.setSuccess(true); result.setMessage("工伤费用结算成功"); result.setWorkInjurySettleNo(settleData.get("setl_id").toString()); result.setTotalFee(totalFee); result.setWorkInjuryFee(workInjuryFee); result.setPersonalFee(personalFee); result.setHisReceiptNo(hisResult.getReceiptNo()); log.info("工伤费用结算成功, 结算号: {}, 总费用: {}, 个人支付: {}", result.getWorkInjurySettleNo(), totalFee, personalFee); } catch (Exception e) { log.error("工伤费用结算异常", e); result.setSuccess(false); result.setMessage("结算异常: " + e.getMessage()); } return result; } /** * 对账接口调用 * 用于每日对账核对数据 */ public WorkInjuryAccountResult dailyAccount(String accountDate) { log.info("开始工伤对账, 对账日期: {}", accountDate); WorkInjuryAccountResult result = new WorkInjuryAccountResult(); try { // 1. 构造对账请求参数 Map accountParams = new HashMap<>(); accountParams.put("stmt_begndate", accountDate); accountParams.put("stmt_enddate", accountDate); WorkInjuryApiRequest apiRequest = new WorkInjuryApiRequest(); apiRequest.setAction("TotalAccount"); apiRequest.setBusinessParams(accountParams); // 2. 调用工伤总额对账接口 WorkInjuryApiResult apiResult = callWorkInjuryApi(apiRequest); // 3. 记录接口调用日志 Long logId = saveAccountInterfaceLog(apiRequest, apiResult, "1320", "总额对账", "对账类"); if (apiResult.isSuccess()) { // 4. 解析对账结果 Map accountData = apiResult.getData(); int totalCount = Integer.parseInt(accountData.get("total_cnt").toString()); BigDecimal totalAmount = new BigDecimal(accountData.get("total_amt").toString()); // 5. 记录对账业务数据 saveAccountBusinessData(logId, accountDate, totalCount, totalAmount); // 6. 组装返回结果 result.setSuccess(true); result.setMessage("对账成功"); result.setAccountDate(accountDate); result.setTotalCount(totalCount); result.setTotalAmount(totalAmount); log.info("工伤对账成功, 日期: {}, 笔数: {}, 金额: {}", accountDate, totalCount, totalAmount); } else { result.setSuccess(false); result.setMessage("对账失败: " + apiResult.getMessage()); log.error("工伤对账失败: {}", apiResult.getMessage()); } } catch (Exception e) { log.error("工伤对账异常", e); result.setSuccess(false); result.setMessage("对账异常: " + e.getMessage()); } return result; } /** * 下载费用明细数据 * 用于对账核实和数据分析 */ public WorkInjuryDownloadResult downloadFeeDetail(String beginDate, String endDate) { log.info("开始下载工伤费用明细, 开始日期: {}, 结束日期: {}", beginDate, endDate); WorkInjuryDownloadResult result = new WorkInjuryDownloadResult(); try { // 1. 构造下载请求参数 Map queryCondition = new HashMap<>(); queryCondition.put("stmt_begndate", beginDate); queryCondition.put("stmt_enddate", endDate); Map downloadParams = new HashMap<>(); downloadParams.put("queryCond", queryCondition); WorkInjuryApiRequest apiRequest = new WorkInjuryApiRequest(); apiRequest.setAction("QueryFeeDetail"); apiRequest.setBusinessParams(downloadParams); // 2. 调用工伤费用明细下载接口 WorkInjuryApiResult apiResult = callWorkInjuryApi(apiRequest); // 3. 记录接口调用日志 Long logId = saveDownloadInterfaceLog(apiRequest, apiResult, "9103", "费用明细详细信息下载", "下载类"); if (apiResult.isSuccess()) { // 4. 解析下载结果 Map downloadData = apiResult.getData(); @SuppressWarnings("unchecked") java.util.List> feeDetailList = (java.util.List>) downloadData.get("feedetail"); int recordCount = feeDetailList != null ? feeDetailList.size() : 0; // 5. 记录下载业务数据 saveDownloadBusinessData(logId, beginDate, endDate, recordCount, feeDetailList); // 6. 组装返回结果 result.setSuccess(true); result.setMessage("下载成功"); result.setBeginDate(beginDate); result.setEndDate(endDate); result.setRecordCount(recordCount); result.setFeeDetailList(feeDetailList); log.info("工伤费用明细下载成功, 记录数: {}", recordCount); } else { result.setSuccess(false); result.setMessage("下载失败: " + apiResult.getMessage()); log.error("工伤费用明细下载失败: {}", apiResult.getMessage()); } } catch (Exception e) { log.error("工伤费用明细下载异常", e); result.setSuccess(false); result.setMessage("下载异常: " + e.getMessage()); } return result; } // ==================== 私有辅助方法 ==================== /** * 调用工伤登记接口 */ private WorkInjuryApiResult callWorkInjuryRegisterApi( WorkInjuryRegisterRequest request, WorkInjuryPatientRelation relation) throws Exception { Map businessParams = new HashMap<>(); businessParams.put("ipt_otp_no", request.getVisitNo()); businessParams.put("med_type", "11"); // 门诊 businessParams.put("adm_time", LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); businessParams.put("adm_dept_codg", request.getDepartmentCode()); businessParams.put("atddr_no", request.getDoctorCode()); businessParams.put("psn_no", relation.getWorkInjuryPsnNo()); businessParams.put("qualification_id", relation.getQualificationId()); WorkInjuryApiRequest apiRequest = new WorkInjuryApiRequest(); apiRequest.setAction("RegisterPatient"); apiRequest.setBusinessParams(businessParams); apiRequest.setIdentifyMode("1"); return callWorkInjuryApi(apiRequest); } /** * 统一的工伤接口调用方法 */ private WorkInjuryApiResult callWorkInjuryApi(WorkInjuryApiRequest request) throws Exception { log.debug("调用工伤接口, action: {}", request.getAction()); ResponseEntity response = restTemplate.postForEntity( WORK_INJURY_API_URL, request, Map.class ); Map responseBody = response.getBody(); WorkInjuryApiResult result = new WorkInjuryApiResult(); result.setSuccess((Boolean) responseBody.get("success")); result.setCode((String) responseBody.get("code")); result.setMessage((String) responseBody.get("message")); if (result.isSuccess()) { @SuppressWarnings("unchecked") Map data = (Map) responseBody.get("data"); result.setData(data); } return result; } /** * 保存接口调用日志 */ private Long saveInterfaceLog( Object request, WorkInjuryApiResult apiResult, String interfaceCode, String interfaceName, String interfaceCategory) { try { WorkInjuryInterfaceLog log = new WorkInjuryInterfaceLog(); // 设置基本信息 if (request instanceof WorkInjuryRegisterRequest) { WorkInjuryRegisterRequest registerRequest = (WorkInjuryRegisterRequest) request; log.setHisPatientId(registerRequest.getPatientId()); log.setHisVisitNo(registerRequest.getVisitNo()); } else if (request instanceof WorkInjurySettlementRequest) { WorkInjurySettlementRequest settlementRequest = (WorkInjurySettlementRequest) request; log.setHisPatientId(settlementRequest.getPatientId()); log.setHisVisitNo(settlementRequest.getVisitNo()); } log.setInterfaceCode(interfaceCode); log.setInterfaceName(interfaceName); log.setInterfaceCategory(interfaceCategory); // 设置请求和响应数据 log.setRequestData(objectMapper.writeValueAsString(request)); log.setResponseData(objectMapper.writeValueAsString(apiResult)); // 设置调用结果 log.setCallResult(apiResult.isSuccess()); log.setResultCode(apiResult.getCode()); log.setResultMessage(apiResult.getMessage()); // 设置工伤系统关键信息 if (apiResult.isSuccess() && apiResult.getData() != null) { Map data = apiResult.getData(); log.setWorkInjuryMsgId((String) data.get("inf_refmsgid")); log.setWorkInjuryQualificationId((String) data.get("qualification_id")); } // 设置时间和操作信息 log.setCallTime(LocalDateTime.now()); log.setOperatorId("SYSTEM"); log.setOperatorName("系统自动"); WorkInjuryInterfaceLog savedLog = logRepository.save(log); return savedLog.getLogId(); } catch (Exception e) { log.error("保存接口调用日志失败", e); return null; } } /** * 保存业务数据 */ private void saveBusinessData( Long logId, WorkInjuryRegisterRequest request, WorkInjuryApiResult apiResult, String businessType, String businessCode) { try { WorkInjuryBusinessData businessData = new WorkInjuryBusinessData(); businessData.setLogId(logId); businessData.setHisPatientId(request.getPatientId()); businessData.setHisVisitNo(request.getVisitNo()); businessData.setBusinessType(businessType); businessData.setBusinessCode(businessCode); businessData.setBusinessStatus("成功"); if (apiResult.getData() != null) { Map data = apiResult.getData(); businessData.setWorkInjuryRegisterNo((String) data.get("ipt_otp_no")); businessData.setBusinessDetailData(objectMapper.writeValueAsString(data)); } businessData.setBusinessTime(LocalDateTime.now()); businessRepository.save(businessData); } catch (Exception e) { log.error("保存业务数据失败", e); } } /** * 保存结算业务数据 */ private void saveSettlementBusinessData( Long logId, WorkInjurySettlementRequest request, WorkInjuryApiResult apiResult, BigDecimal totalFee, BigDecimal workInjuryFee, BigDecimal personalFee) { try { WorkInjuryBusinessData businessData = new WorkInjuryBusinessData(); businessData.setLogId(logId); businessData.setHisPatientId(request.getPatientId()); businessData.setHisVisitNo(request.getVisitNo()); businessData.setBusinessType("结算"); businessData.setBusinessCode("2207"); businessData.setBusinessStatus("成功"); // 设置费用信息 businessData.setTotalFee(totalFee); businessData.setWorkInjuryFee(workInjuryFee); businessData.setPersonalFee(personalFee); if (apiResult.getData() != null) { Map data = apiResult.getData(); businessData.setWorkInjurySettleNo((String) data.get("setl_id")); businessData.setWorkInjuryReceiptNo((String) data.get("setl_detail_id")); businessData.setBusinessDetailData(objectMapper.writeValueAsString(data)); } businessData.setBusinessTime(LocalDateTime.now()); businessRepository.save(businessData); } catch (Exception e) { log.error("保存结算业务数据失败", e); } } // 其他辅助方法... (uploadPrescriptionDetail, preSettleFee, settleFee, callHisApi等) // 为了节省篇幅,这里省略了部分辅助方法的实现 } ``` 这个完整的文档涵盖了: 1. **数据库表设计**:3个通用表支持所有工伤接口类型 2. **详细注释说明**:每个字段都有明确的用途说明 3. **表关联关系**:清晰的关联逻辑和数据流向 4. **使用案例**:典型业务场景的数据操作示例 5. **前端代码**:jQuery和Vue 3.0的完整实现示例 6. **后端代码**:Spring Boot的服务层实现 这套设计方案能够完美实现您的需求:**工伤病人先调用工伤接口存储数据,再调用HIS接口;非工伤病人直接调用HIS接口**,同时通过通用化设计支持所有类型的工伤接口,简单实用可靠。