|
@@ -0,0 +1,924 @@
|
|
|
+# 江苏工伤联网结算接口对接实现逻辑设计
|
|
|
+
|
|
|
+## 版本信息
|
|
|
+
|
|
|
+| 版本号 | 修改内容 | 修改日期 | 修改人 |
|
|
|
+|--------|----------|----------|--------|
|
|
|
+| V1.0 | 初始版本设计 | 2024.12.19 | 系统 |
|
|
|
+
|
|
|
+## 目录
|
|
|
+
|
|
|
+- [1 设计概述](#1-设计概述)
|
|
|
+- [2 架构设计](#2-架构设计)
|
|
|
+- [3 核心类设计](#3-核心类设计)
|
|
|
+- [4 接口实现策略](#4-接口实现策略)
|
|
|
+- [5 具体实现方案](#5-具体实现方案)
|
|
|
+- [6 错误处理机制](#6-错误处理机制)
|
|
|
+- [7 集成方案](#7-集成方案)
|
|
|
+- [8 部署说明](#8-部署说明)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 1 设计概述
|
|
|
+
|
|
|
+### 1.1 设计目标
|
|
|
+
|
|
|
+基于江苏省工伤机构联网结算接口开发手册(V2.1版本),设计一个统一的工伤联网接口对接业务类,实现与江苏省工伤联网系统的无缝对接。
|
|
|
+
|
|
|
+### 1.2 设计原则
|
|
|
+
|
|
|
+1. **统一封装**:参考 `JiangSuSocialCardBusiness.cs` 的成功模式,提供统一的业务接口
|
|
|
+2. **简化调用**:通过参数区分不同业务接口,HIS系统调用更简洁
|
|
|
+3. **完全合规**:严格按照工伤文档规范实现,确保接口合规性
|
|
|
+4. **易于集成**:可直接嵌套到现有HIS系统中使用
|
|
|
+5. **高度复用**:一套代码支持所有工伤联网业务场景
|
|
|
+
|
|
|
+### 1.3 核心思路
|
|
|
+
|
|
|
+采用用户建议的实现方案:
|
|
|
+- **初始化函数**:负责系统初始化和环境检查
|
|
|
+- **通用接口函数**:统一的业务处理入口,通过参数区分不同交易
|
|
|
+- **参数化设计**:所有具体接口通过传入参数动态调用
|
|
|
+- **直接嵌套**:可直接集成到HIS系统业务流程中
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 2 架构设计
|
|
|
+
|
|
|
+### 2.1 系统架构图
|
|
|
+
|
|
|
+```
|
|
|
+┌─────────────────────────────────────────┐
|
|
|
+│ HIS医院信息系统 │
|
|
|
+├─────────────────────────────────────────┤
|
|
|
+│ JiangSuWorkInjuryBusiness │
|
|
|
+│ ┌─────────────┬─────────────────────┐ │
|
|
|
+│ │ 初始化函数 │ 通用接口函数 │ │
|
|
|
+│ │ Initialize │ ProcessTransaction │ │
|
|
|
+│ └─────────────┴─────────────────────┘ │
|
|
|
+├─────────────────────────────────────────┤
|
|
|
+│ JSSiInterface.dll │
|
|
|
+│ ┌─────────────┬─────────────────────┐ │
|
|
|
+│ │ Si_INIT │ Si_Busi │ │
|
|
|
+│ └─────────────┴─────────────────────┘ │
|
|
|
+├─────────────────────────────────────────┤
|
|
|
+│ HTTPS/SSL安全传输协议 │
|
|
|
+├─────────────────────────────────────────┤
|
|
|
+│ 江苏省工伤联网中心系统 │
|
|
|
+└─────────────────────────────────────────┘
|
|
|
+```
|
|
|
+
|
|
|
+### 2.2 接口分类体系
|
|
|
+
|
|
|
+根据工伤文档,接口共分为4大类:
|
|
|
+
|
|
|
+| 分类 | 交易编号范围 | 主要功能 | 实现策略 |
|
|
|
+|------|-------------|----------|----------|
|
|
|
+| **对账类** | 1320-1321 | 总额对账、明细对账 | 统一对账处理 |
|
|
|
+| **认证类** | 9001-9002 | 签到、签退 | 会话管理 |
|
|
|
+| **业务类** | 1101, 22XX, 81XX, 23XX | 读卡、登记、结算、体检、转院 | 核心业务处理 |
|
|
|
+| **下载类** | 1301, 91XX | 数据下载、查询 | 数据同步 |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 3 核心类设计
|
|
|
+
|
|
|
+### 3.1 主业务类:JiangSuWorkInjuryBusiness
|
|
|
+
|
|
|
+```csharp
|
|
|
+/// <summary>
|
|
|
+/// 江苏工伤联网结算业务类
|
|
|
+/// 基于JSSiInterface.dll动态库,严格按照江苏工伤联网接口规范v2.1实现
|
|
|
+/// 参考JiangSuSocialCardBusiness.cs的成功架构模式
|
|
|
+/// </summary>
|
|
|
+public class JiangSuWorkInjuryBusiness
|
|
|
+{
|
|
|
+ #region DLL导入声明 - 严格按照工伤文档规范
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 初始化函数 - 检查整个运行环境
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="pErrMsg">错误信息</param>
|
|
|
+ /// <returns>成功:0,失败:-1</returns>
|
|
|
+ [DllImport("JSSiInterface.dll", EntryPoint = "Si_INIT", CharSet = CharSet.Ansi)]
|
|
|
+ private extern static int Si_INIT(StringBuilder pErrMsg);
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 交易函数 - 处理所有业务交易
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="inputdata">输入参数JSON字符串</param>
|
|
|
+ /// <param name="outputdata">输出参数JSON字符串</param>
|
|
|
+ /// <returns>成功:0,失败:<0</returns>
|
|
|
+ [DllImport("JSSiInterface.dll", EntryPoint = "Si_Busi", CharSet = CharSet.Ansi)]
|
|
|
+ private extern static int Si_Busi(string inputdata, StringBuilder outputdata);
|
|
|
+
|
|
|
+ #endregion
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 3.2 配置管理类
|
|
|
+
|
|
|
+```csharp
|
|
|
+/// <summary>
|
|
|
+/// 江苏工伤联网配置类 - 严格按照工伤文档规范定义
|
|
|
+/// </summary>
|
|
|
+public class WorkInjuryConfig
|
|
|
+{
|
|
|
+ /// <summary>
|
|
|
+ /// 协议机构编号 - 由江苏人社分配
|
|
|
+ /// </summary>
|
|
|
+ public string FixmedinsCode { get; set; } = "H00001";
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 协议机构名称
|
|
|
+ /// </summary>
|
|
|
+ public string FixmedinsName { get; set; } = "第一人民医院";
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 接收方系统代码 - 默认"JSYTH"
|
|
|
+ /// </summary>
|
|
|
+ public string ReceiverSysCode { get; set; } = "JSYTH";
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 接口版本号 - 如"V2.1"
|
|
|
+ /// </summary>
|
|
|
+ public string InterfaceVersion { get; set; } = "V2.1";
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 经办人类别 - 1:经办人 2:自助终端 3:移动终端
|
|
|
+ /// </summary>
|
|
|
+ public string OperatorType { get; set; } = "1";
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 默认经办人编号
|
|
|
+ /// </summary>
|
|
|
+ public string DefaultOperator { get; set; } = "001";
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 默认经办人姓名
|
|
|
+ /// </summary>
|
|
|
+ public string DefaultOperatorName { get; set; } = "系统管理员";
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 3.3 交易请求参数类
|
|
|
+
|
|
|
+```csharp
|
|
|
+/// <summary>
|
|
|
+/// 工伤联网交易请求参数 - 按照工伤文档标准格式
|
|
|
+/// </summary>
|
|
|
+public class WorkInjuryTransactionRequest
|
|
|
+{
|
|
|
+ /// <summary>
|
|
|
+ /// 交易编号 - 4位数字
|
|
|
+ /// </summary>
|
|
|
+ public string TransactionCode { get; set; }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 业务参数 - 具体交易的输入参数
|
|
|
+ /// </summary>
|
|
|
+ public object BusinessParams { get; set; }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 识别方式 - 1:实体社保卡 2:电子凭证
|
|
|
+ /// </summary>
|
|
|
+ public string IdentifyMode { get; set; } = "1";
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 电子社保卡二维码(识别方式为2时必填)
|
|
|
+ /// </summary>
|
|
|
+ public string QrCodeInfo { get; set; } = "";
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 经办人编号(可选,使用默认值)
|
|
|
+ /// </summary>
|
|
|
+ public string OperatorId { get; set; } = "";
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 经办人姓名(可选,使用默认值)
|
|
|
+ /// </summary>
|
|
|
+ public string OperatorName { get; set; } = "";
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 4 接口实现策略
|
|
|
+
|
|
|
+### 4.1 统一处理流程
|
|
|
+
|
|
|
+```csharp
|
|
|
+public static JObject ProcessTransaction(WorkInjuryTransactionRequest request)
|
|
|
+{
|
|
|
+ var result = new JObject();
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ // 1. 检查初始化状态
|
|
|
+ if (!isInitialized)
|
|
|
+ {
|
|
|
+ var initResult = Initialize();
|
|
|
+ if (!(bool)initResult["success"])
|
|
|
+ {
|
|
|
+ return initResult;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 构造标准输入参数
|
|
|
+ var inputJson = BuildStandardInput(request);
|
|
|
+
|
|
|
+ // 3. 调用底层DLL
|
|
|
+ StringBuilder outputBuffer = new StringBuilder(40000);
|
|
|
+ int dllResult = Si_Busi(inputJson, outputBuffer);
|
|
|
+
|
|
|
+ // 4. 解析输出结果
|
|
|
+ result = ParseStandardOutput(outputBuffer.ToString(), dllResult);
|
|
|
+
|
|
|
+ // 5. 特殊业务处理
|
|
|
+ result = ProcessSpecialBusiness(request.TransactionCode, result);
|
|
|
+
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ result = BuildErrorResult(ex);
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 4.2 参数化交易映射
|
|
|
+
|
|
|
+```csharp
|
|
|
+/// <summary>
|
|
|
+/// 交易代码映射表 - 基于工伤文档接口列表
|
|
|
+/// </summary>
|
|
|
+private static readonly Dictionary<string, string> TransactionMapping = new Dictionary<string, string>
|
|
|
+{
|
|
|
+ // 认证类
|
|
|
+ {"SignIn", "9001"}, // 签到
|
|
|
+ {"SignOut", "9002"}, // 签退
|
|
|
+
|
|
|
+ // 业务类 - 核心功能
|
|
|
+ {"ReadCard", "1101"}, // 读卡
|
|
|
+ {"RegisterPatient", "2201"}, // 门诊/住院登记
|
|
|
+ {"CancelRegister", "2202"}, // 登记撤销
|
|
|
+ {"ModifyRegister", "2203"}, // 登记信息修改
|
|
|
+ {"UploadPrescription", "2204"}, // 处方明细上报
|
|
|
+ {"CancelPrescription", "2205"}, // 处方明细撤销
|
|
|
+ {"PreSettle", "2206"}, // 费用预结算
|
|
|
+ {"Settle", "2207"}, // 费用结算
|
|
|
+ {"CancelSettle", "2208"}, // 费用结算撤销
|
|
|
+ {"ReverseTransaction", "2209"}, // 冲正交易
|
|
|
+
|
|
|
+ // 体检类 - 体检协议机构使用
|
|
|
+ {"QueryExamSchedule", "8101"}, // 查询体检排班信息
|
|
|
+ {"UpdateExamSchedule", "8102"}, // 更新体检排班信息
|
|
|
+ {"QueryExamReservation", "8103"}, // 查询体检预约信息
|
|
|
+ {"ExamRegister", "8104"}, // 体检登记
|
|
|
+ {"UploadExamDetail", "8105"}, // 上传体检明细
|
|
|
+ {"QueryExamSettle", "8106"}, // 查询体检结算信息
|
|
|
+ {"QueryExamDetail", "8107"}, // 查询体检明细
|
|
|
+ {"ConfirmExamResult", "8108"}, // 体检结果确认
|
|
|
+ {"QuerySupplementCard", "8109"}, // 补刷卡登记查询
|
|
|
+
|
|
|
+ // 转院类
|
|
|
+ {"UploadReferral", "2301"}, // 转诊转院申请信息上传
|
|
|
+ {"QueryReferral", "2302"}, // 转诊转院申请信息查询
|
|
|
+ {"CancelReferral", "2303"}, // 转诊转院申请信息撤销
|
|
|
+
|
|
|
+ // 对账类
|
|
|
+ {"TotalAccount", "1320"}, // 总额对账
|
|
|
+ {"DetailAccount", "1321"}, // 明细对账
|
|
|
+
|
|
|
+ // 下载类
|
|
|
+ {"BatchDownload", "1301"}, // 批量数据下载
|
|
|
+ {"QueryFeeDetail", "9103"}, // 费用明细详细信息下载
|
|
|
+ {"QueryPrescriptionDetail", "9104"}, // 处方明细下载
|
|
|
+ {"QueryRecentVisit", "9105"} // 参保人近期就诊信息查询
|
|
|
+};
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 5 具体实现方案
|
|
|
+
|
|
|
+### 5.1 初始化函数实现
|
|
|
+
|
|
|
+```csharp
|
|
|
+/// <summary>
|
|
|
+/// 初始化江苏工伤联网系统
|
|
|
+/// 参考JiangSuSocialCardBusiness的Initialize方法,但适配工伤业务
|
|
|
+/// </summary>
|
|
|
+/// <param name="config">配置参数</param>
|
|
|
+/// <returns>初始化结果</returns>
|
|
|
+public static JObject Initialize(WorkInjuryConfig config = null)
|
|
|
+{
|
|
|
+ var result = new JObject();
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ // 使用默认配置或传入配置
|
|
|
+ if (config == null)
|
|
|
+ {
|
|
|
+ config = new WorkInjuryConfig();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查DLL文件存在性
|
|
|
+ var dllCheckResult = CheckDllExists();
|
|
|
+ if (!(bool)dllCheckResult["success"])
|
|
|
+ {
|
|
|
+ return dllCheckResult;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 调用底层初始化函数
|
|
|
+ StringBuilder errMsg = new StringBuilder(1024);
|
|
|
+ int initResult = Si_INIT(errMsg);
|
|
|
+
|
|
|
+ if (initResult == 0)
|
|
|
+ {
|
|
|
+ isInitialized = true;
|
|
|
+ currentConfig = config;
|
|
|
+
|
|
|
+ result["success"] = true;
|
|
|
+ result["code"] = 200;
|
|
|
+ result["message"] = "江苏工伤联网系统初始化成功";
|
|
|
+ result["device"] = "江苏工伤联网接口";
|
|
|
+ result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
|
|
+ result["version"] = config.InterfaceVersion;
|
|
|
+ result["dllErrorMsg"] = errMsg.ToString();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ string errorMsg = errMsg.ToString();
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 1000 + Math.Abs(initResult);
|
|
|
+ result["message"] = $"江苏工伤联网系统初始化失败: {errorMsg}";
|
|
|
+ result["device"] = "江苏工伤联网接口";
|
|
|
+ result["errorCode"] = initResult;
|
|
|
+ result["dllErrorMsg"] = errorMsg;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 1001;
|
|
|
+ result["message"] = $"江苏工伤联网系统初始化异常: {ex.Message}";
|
|
|
+ result["device"] = "江苏工伤联网接口";
|
|
|
+ result["exception"] = ex.GetType().Name;
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 5.2 通用接口函数实现
|
|
|
+
|
|
|
+```csharp
|
|
|
+/// <summary>
|
|
|
+/// 通用工伤联网交易处理接口
|
|
|
+/// 支持所有工伤文档定义的交易类型
|
|
|
+/// </summary>
|
|
|
+/// <param name="transactionName">交易名称(可使用中文名称或交易编号)</param>
|
|
|
+/// <param name="businessParams">业务参数对象</param>
|
|
|
+/// <param name="identifyMode">识别方式:1-实体社保卡,2-电子凭证</param>
|
|
|
+/// <param name="qrCodeInfo">电子社保卡二维码(识别方式为2时必填)</param>
|
|
|
+/// <param name="operatorId">经办人编号(可选)</param>
|
|
|
+/// <param name="operatorName">经办人姓名(可选)</param>
|
|
|
+/// <returns>交易处理结果</returns>
|
|
|
+public static JObject ProcessWorkInjuryTransaction(
|
|
|
+ string transactionName,
|
|
|
+ object businessParams = null,
|
|
|
+ string identifyMode = "1",
|
|
|
+ string qrCodeInfo = "",
|
|
|
+ string operatorId = "",
|
|
|
+ string operatorName = "")
|
|
|
+{
|
|
|
+ var result = new JObject();
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ // 1. 解析交易编号
|
|
|
+ string transactionCode = GetTransactionCode(transactionName);
|
|
|
+ if (string.IsNullOrEmpty(transactionCode))
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 1002;
|
|
|
+ result["message"] = $"不支持的交易类型: {transactionName}";
|
|
|
+ result["device"] = "江苏工伤联网接口";
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 检查初始化状态
|
|
|
+ if (!isInitialized)
|
|
|
+ {
|
|
|
+ var autoInitResult = Initialize();
|
|
|
+ if (!(bool)autoInitResult["success"])
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 1003;
|
|
|
+ result["message"] = "江苏工伤联网系统未初始化";
|
|
|
+ result["device"] = "江苏工伤联网接口";
|
|
|
+ result["autoInitError"] = autoInitResult["message"];
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 检查签到状态(除签到交易外)
|
|
|
+ if (transactionCode != "9001" && string.IsNullOrEmpty(currentSignNo))
|
|
|
+ {
|
|
|
+ var signInResult = ProcessWorkInjuryTransaction("SignIn");
|
|
|
+ if (!(bool)signInResult["success"])
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 1004;
|
|
|
+ result["message"] = "自动签到失败,无法进行业务交易";
|
|
|
+ result["device"] = "江苏工伤联网接口";
|
|
|
+ result["signInError"] = signInResult["message"];
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 构造标准输入参数
|
|
|
+ var inputData = BuildTransactionInput(transactionCode, businessParams, identifyMode, qrCodeInfo, operatorId, operatorName);
|
|
|
+ string inputJson = JsonConvert.SerializeObject(inputData, Formatting.None);
|
|
|
+
|
|
|
+ // 5. 调用底层DLL交易函数
|
|
|
+ StringBuilder outputBuffer = new StringBuilder(40000);
|
|
|
+ int dllResult = Si_Busi(inputJson, outputBuffer);
|
|
|
+
|
|
|
+ // 6. 解析和处理返回结果
|
|
|
+ string outputJson = outputBuffer.ToString();
|
|
|
+ result = ParseTransactionOutput(outputJson, dllResult, transactionCode);
|
|
|
+
|
|
|
+ // 7. 特殊交易后处理
|
|
|
+ PostProcessTransaction(transactionCode, result);
|
|
|
+
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 1005;
|
|
|
+ result["message"] = $"工伤联网交易异常: {ex.Message}";
|
|
|
+ result["device"] = "江苏工伤联网接口";
|
|
|
+ result["exception"] = ex.GetType().Name;
|
|
|
+ result["transactionName"] = transactionName;
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 5.3 标准输入参数构造
|
|
|
+
|
|
|
+```csharp
|
|
|
+/// <summary>
|
|
|
+/// 构造标准的工伤联网交易输入参数
|
|
|
+/// 严格按照工伤文档表2格式构造
|
|
|
+/// </summary>
|
|
|
+private static object BuildTransactionInput(string transactionCode, object businessParams,
|
|
|
+ string identifyMode, string qrCodeInfo, string operatorId, string operatorName)
|
|
|
+{
|
|
|
+ // 生成唯一的发送方报文ID:协议机构编号(6)+时间(14)+顺序号(4)
|
|
|
+ string msgId = GenerateMessageId();
|
|
|
+
|
|
|
+ // 使用配置的经办人信息或传入的参数
|
|
|
+ string finalOperatorId = string.IsNullOrEmpty(operatorId) ? currentConfig.DefaultOperator : operatorId;
|
|
|
+ string finalOperatorName = string.IsNullOrEmpty(operatorName) ? currentConfig.DefaultOperatorName : operatorName;
|
|
|
+
|
|
|
+ var inputData = new
|
|
|
+ {
|
|
|
+ infno = transactionCode, // 交易编号
|
|
|
+ msgid = msgId, // 发送方报文ID
|
|
|
+ recer_sys_code = currentConfig.ReceiverSysCode, // 接收方系统代码
|
|
|
+ infver = currentConfig.InterfaceVersion, // 接口版本号
|
|
|
+ opter_type = currentConfig.OperatorType, // 经办人类别
|
|
|
+ opter = finalOperatorId, // 经办人
|
|
|
+ opter_name = finalOperatorName, // 经办人姓名
|
|
|
+ inf_time = DateTime.Now.ToString("yyyyMMddHHmmss"), // 交易时间
|
|
|
+ fixmedins_code = currentConfig.FixmedinsCode, // 协议机构编号
|
|
|
+ fixmedins_name = currentConfig.FixmedinsName, // 协议机构名称
|
|
|
+ sign_no = transactionCode == "9001" ? "" : currentSignNo, // 签到流水号
|
|
|
+ idfi_mode = identifyMode, // 识别方式
|
|
|
+ qrcode_info = qrCodeInfo, // 电子社保卡二维码
|
|
|
+ input = businessParams ?? new { } // 交易输入参数
|
|
|
+ };
|
|
|
+
|
|
|
+ // 保存发送方报文ID用于可能的冲正操作
|
|
|
+ SaveMessageId(msgId, transactionCode);
|
|
|
+
|
|
|
+ return inputData;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 5.4 便捷方法封装
|
|
|
+
|
|
|
+```csharp
|
|
|
+// 为常用交易提供便捷方法,简化调用
|
|
|
+
|
|
|
+/// <summary>
|
|
|
+/// 读卡交易 - 获取工伤人员基本信息
|
|
|
+/// </summary>
|
|
|
+public static JObject ReadWorkInjuryCard(string identifyMode = "1", string qrCodeInfo = "")
|
|
|
+{
|
|
|
+ return ProcessWorkInjuryTransaction("ReadCard", null, identifyMode, qrCodeInfo);
|
|
|
+}
|
|
|
+
|
|
|
+/// <summary>
|
|
|
+/// 门诊/住院登记
|
|
|
+/// </summary>
|
|
|
+public static JObject RegisterPatient(object registerParams, string identifyMode = "1")
|
|
|
+{
|
|
|
+ return ProcessWorkInjuryTransaction("RegisterPatient", registerParams, identifyMode);
|
|
|
+}
|
|
|
+
|
|
|
+/// <summary>
|
|
|
+/// 费用预结算
|
|
|
+/// </summary>
|
|
|
+public static JObject PreSettlement(object settlementParams)
|
|
|
+{
|
|
|
+ return ProcessWorkInjuryTransaction("PreSettle", settlementParams);
|
|
|
+}
|
|
|
+
|
|
|
+/// <summary>
|
|
|
+/// 费用结算
|
|
|
+/// </summary>
|
|
|
+public static JObject Settlement(object settlementParams)
|
|
|
+{
|
|
|
+ return ProcessWorkInjuryTransaction("Settle", settlementParams);
|
|
|
+}
|
|
|
+
|
|
|
+/// <summary>
|
|
|
+/// 处方明细上传
|
|
|
+/// </summary>
|
|
|
+public static JObject UploadPrescription(object prescriptionDetails)
|
|
|
+{
|
|
|
+ return ProcessWorkInjuryTransaction("UploadPrescription", prescriptionDetails);
|
|
|
+}
|
|
|
+
|
|
|
+/// <summary>
|
|
|
+/// 签到交易
|
|
|
+/// </summary>
|
|
|
+public static JObject SignIn()
|
|
|
+{
|
|
|
+ return ProcessWorkInjuryTransaction("SignIn");
|
|
|
+}
|
|
|
+
|
|
|
+/// <summary>
|
|
|
+/// 签退交易
|
|
|
+/// </summary>
|
|
|
+public static JObject SignOut()
|
|
|
+{
|
|
|
+ return ProcessWorkInjuryTransaction("SignOut");
|
|
|
+}
|
|
|
+
|
|
|
+/// <summary>
|
|
|
+/// 冲正交易
|
|
|
+/// </summary>
|
|
|
+public static JObject ReverseTransaction(string originalTransactionCode, string originalMessageId)
|
|
|
+{
|
|
|
+ var reverseParams = new
|
|
|
+ {
|
|
|
+ infno = originalTransactionCode,
|
|
|
+ msgid = originalMessageId
|
|
|
+ };
|
|
|
+ return ProcessWorkInjuryTransaction("ReverseTransaction", reverseParams);
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 6 错误处理机制
|
|
|
+
|
|
|
+### 6.1 多层次错误处理
|
|
|
+
|
|
|
+```csharp
|
|
|
+/// <summary>
|
|
|
+/// 解析交易输出结果并进行错误处理
|
|
|
+/// </summary>
|
|
|
+private static JObject ParseTransactionOutput(string outputJson, int dllResult, string transactionCode)
|
|
|
+{
|
|
|
+ var result = new JObject();
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ // DLL层面错误
|
|
|
+ if (dllResult != 0)
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 2000 + Math.Abs(dllResult);
|
|
|
+ result["message"] = $"DLL调用失败,错误码: {dllResult}";
|
|
|
+ result["device"] = "江苏工伤联网接口";
|
|
|
+ result["dllErrorCode"] = dllResult;
|
|
|
+ result["transactionCode"] = transactionCode;
|
|
|
+ result["rawOutput"] = outputJson;
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 解析JSON输出
|
|
|
+ if (string.IsNullOrEmpty(outputJson))
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 2001;
|
|
|
+ result["message"] = "交易返回数据为空";
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ var outputData = JObject.Parse(outputJson);
|
|
|
+
|
|
|
+ // 业务层面错误检查
|
|
|
+ string infcode = outputData["infcode"]?.ToString() ?? "";
|
|
|
+ string errMsg = outputData["err_msg"]?.ToString() ?? "";
|
|
|
+ string warnMsg = outputData["warn_msg"]?.ToString() ?? "";
|
|
|
+
|
|
|
+ if (infcode == "0")
|
|
|
+ {
|
|
|
+ // 交易成功
|
|
|
+ result["success"] = true;
|
|
|
+ result["code"] = 200;
|
|
|
+ result["message"] = string.IsNullOrEmpty(warnMsg) ? "交易成功" : warnMsg;
|
|
|
+ result["data"] = outputData["output"];
|
|
|
+ result["transactionCode"] = transactionCode;
|
|
|
+ result["infRefMsgId"] = outputData["inf_refmsgid"];
|
|
|
+ result["refMsgTime"] = outputData["refmsg_time"];
|
|
|
+ result["respondTime"] = outputData["respond_time"];
|
|
|
+ result["warnMsg"] = warnMsg;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // 业务失败
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 3000 + Math.Abs(int.Parse(infcode));
|
|
|
+ result["message"] = string.IsNullOrEmpty(errMsg) ? "交易失败" : errMsg;
|
|
|
+ result["transactionCode"] = transactionCode;
|
|
|
+ result["businessErrorCode"] = infcode;
|
|
|
+ result["businessErrorMsg"] = errMsg;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 保存完整的原始返回数据
|
|
|
+ result["rawOutput"] = outputJson;
|
|
|
+
|
|
|
+ }
|
|
|
+ catch (JsonException jsonEx)
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 2002;
|
|
|
+ result["message"] = $"返回数据解析失败: {jsonEx.Message}";
|
|
|
+ result["rawOutput"] = outputJson;
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 2003;
|
|
|
+ result["message"] = $"输出解析异常: {ex.Message}";
|
|
|
+ result["exception"] = ex.GetType().Name;
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 6.2 自动重试机制
|
|
|
+
|
|
|
+```csharp
|
|
|
+/// <summary>
|
|
|
+/// 带重试机制的交易处理
|
|
|
+/// </summary>
|
|
|
+public static JObject ProcessWithRetry(string transactionName, object businessParams, int maxRetries = 3)
|
|
|
+{
|
|
|
+ for (int i = 0; i < maxRetries; i++)
|
|
|
+ {
|
|
|
+ var result = ProcessWorkInjuryTransaction(transactionName, businessParams);
|
|
|
+
|
|
|
+ // 成功则直接返回
|
|
|
+ if ((bool)result["success"])
|
|
|
+ {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 判断是否可重试的错误
|
|
|
+ int errorCode = (int)result["code"];
|
|
|
+ if (IsRetryableError(errorCode) && i < maxRetries - 1)
|
|
|
+ {
|
|
|
+ // 等待重试
|
|
|
+ Thread.Sleep(1000 * (i + 1)); // 递增等待时间
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 不可重试或已达最大重试次数
|
|
|
+ result["retryCount"] = i + 1;
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 理论上不会到达这里
|
|
|
+ return new JObject { ["success"] = false, ["message"] = "重试机制异常" };
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 7 集成方案
|
|
|
+
|
|
|
+### 7.1 HIS系统集成示例
|
|
|
+
|
|
|
+```csharp
|
|
|
+// HIS系统中的调用示例
|
|
|
+
|
|
|
+public class HisWorkInjuryService
|
|
|
+{
|
|
|
+ /// <summary>
|
|
|
+ /// 工伤患者挂号登记业务流程
|
|
|
+ /// </summary>
|
|
|
+ public async Task<HisResult> WorkInjuryRegisterAsync(HisPatientInfo patientInfo)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ // 1. 读卡获取工伤人员信息
|
|
|
+ var readCardResult = JiangSuWorkInjuryBusiness.ReadWorkInjuryCard();
|
|
|
+ if (!(bool)readCardResult["success"])
|
|
|
+ {
|
|
|
+ return HisResult.Fail("读卡失败: " + readCardResult["message"]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 构造登记参数
|
|
|
+ var registerParams = new
|
|
|
+ {
|
|
|
+ ipt_otp_no = GenerateUniqueNo(), // 门诊流水号
|
|
|
+ med_type = patientInfo.MedicalType, // 医疗类别
|
|
|
+ adm_time = DateTime.Now.ToString("yyyyMMddHHmmss"), // 入院时间
|
|
|
+ adm_diag_dscr = patientInfo.DiagnosisCode, // 诊断疾病编码
|
|
|
+ adm_dept_codg = patientInfo.DepartmentCode, // 科室编码
|
|
|
+ atddr_no = patientInfo.DoctorCode, // 医生编码
|
|
|
+ psn_no = readCardResult["data"]["psn_no"], // 个人唯一识别码
|
|
|
+ qualification_id = ExtractQualificationId(readCardResult) // 工伤医疗费资格审核信息ID
|
|
|
+ };
|
|
|
+
|
|
|
+ // 3. 执行登记交易
|
|
|
+ var registerResult = JiangSuWorkInjuryBusiness.RegisterPatient(registerParams);
|
|
|
+ if (!(bool)registerResult["success"])
|
|
|
+ {
|
|
|
+ return HisResult.Fail("登记失败: " + registerResult["message"]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 保存HIS本地数据
|
|
|
+ await SaveLocalPatientData(patientInfo, readCardResult, registerResult);
|
|
|
+
|
|
|
+ return HisResult.Success("工伤患者登记成功");
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ return HisResult.Fail($"工伤登记异常: {ex.Message}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 工伤费用结算业务流程
|
|
|
+ /// </summary>
|
|
|
+ public async Task<HisResult> WorkInjurySettleAsync(string visitNo)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ // 1. 验证患者身份
|
|
|
+ var readCardResult = JiangSuWorkInjuryBusiness.ReadWorkInjuryCard();
|
|
|
+ if (!(bool)readCardResult["success"])
|
|
|
+ {
|
|
|
+ return HisResult.Fail("患者身份验证失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 上传处方明细
|
|
|
+ var prescriptionData = await GetPrescriptionData(visitNo);
|
|
|
+ var uploadResult = JiangSuWorkInjuryBusiness.UploadPrescription(prescriptionData);
|
|
|
+ if (!(bool)uploadResult["success"])
|
|
|
+ {
|
|
|
+ return HisResult.Fail("处方上传失败: " + uploadResult["message"]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 费用预结算
|
|
|
+ var preSettleParams = BuildSettlementParams(visitNo, isPreSettle: true);
|
|
|
+ var preSettleResult = JiangSuWorkInjuryBusiness.PreSettlement(preSettleParams);
|
|
|
+ if (!(bool)preSettleResult["success"])
|
|
|
+ {
|
|
|
+ return HisResult.Fail("预结算失败: " + preSettleResult["message"]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 正式结算
|
|
|
+ var settleParams = BuildSettlementParams(visitNo, isPreSettle: false);
|
|
|
+ var settleResult = JiangSuWorkInjuryBusiness.Settlement(settleParams);
|
|
|
+ if (!(bool)settleResult["success"])
|
|
|
+ {
|
|
|
+ return HisResult.Fail("结算失败: " + settleResult["message"]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 保存结算结果
|
|
|
+ await SaveSettlementResult(visitNo, settleResult);
|
|
|
+
|
|
|
+ return HisResult.Success("工伤费用结算成功", settleResult["data"]);
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ return HisResult.Fail($"工伤结算异常: {ex.Message}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 7.2 配置文件示例
|
|
|
+
|
|
|
+```xml
|
|
|
+<!-- app.config 配置示例 -->
|
|
|
+<configuration>
|
|
|
+ <appSettings>
|
|
|
+ <!-- 江苏工伤联网配置 -->
|
|
|
+ <add key="WorkInjury.FixmedinsCode" value="H00001" />
|
|
|
+ <add key="WorkInjury.FixmedinsName" value="第一人民医院" />
|
|
|
+ <add key="WorkInjury.ReceiverSysCode" value="JSYTH" />
|
|
|
+ <add key="WorkInjury.InterfaceVersion" value="V2.1" />
|
|
|
+ <add key="WorkInjury.OperatorType" value="1" />
|
|
|
+ <add key="WorkInjury.DefaultOperator" value="001" />
|
|
|
+ <add key="WorkInjury.DefaultOperatorName" value="系统管理员" />
|
|
|
+
|
|
|
+ <!-- 自动重试配置 -->
|
|
|
+ <add key="WorkInjury.MaxRetries" value="3" />
|
|
|
+ <add key="WorkInjury.RetryInterval" value="1000" />
|
|
|
+
|
|
|
+ <!-- 日志配置 -->
|
|
|
+ <add key="WorkInjury.LogLevel" value="Info" />
|
|
|
+ <add key="WorkInjury.LogPath" value="logs/workinjury/" />
|
|
|
+ </appSettings>
|
|
|
+</configuration>
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 8 部署说明
|
|
|
+
|
|
|
+### 8.1 环境要求
|
|
|
+
|
|
|
+1. **操作系统**:Windows Server 2012 R2 及以上
|
|
|
+2. **.NET Framework**:4.5 及以上版本
|
|
|
+3. **DLL文件**:JSSiInterface.dll(由江苏人社提供)
|
|
|
+4. **网络环境**:能够访问江苏工伤联网专线网络
|
|
|
+
|
|
|
+### 8.2 部署步骤
|
|
|
+
|
|
|
+1. **复制DLL文件**
|
|
|
+ ```
|
|
|
+ 将 JSSiInterface.dll 复制到应用程序bin目录
|
|
|
+ 确保DLL文件版本与接口文档版本一致
|
|
|
+ ```
|
|
|
+
|
|
|
+2. **配置参数设置**
|
|
|
+ ```
|
|
|
+ 根据医院实际情况修改配置文件中的参数
|
|
|
+ 协议机构编号和名称需要与江苏人社备案信息一致
|
|
|
+ ```
|
|
|
+
|
|
|
+3. **权限配置**
|
|
|
+ ```
|
|
|
+ 确保应用程序有读取DLL文件的权限
|
|
|
+ 配置网络访问权限
|
|
|
+ ```
|
|
|
+
|
|
|
+4. **测试验证**
|
|
|
+ ```
|
|
|
+ 先在测试环境验证接口连通性
|
|
|
+ 执行签到/签退测试确认基础功能
|
|
|
+ 进行完整业务流程测试
|
|
|
+ ```
|
|
|
+
|
|
|
+### 8.3 监控建议
|
|
|
+
|
|
|
+1. **接口调用监控**:记录每次接口调用的结果和耗时
|
|
|
+2. **错误率监控**:统计各类交易的成功率和失败原因
|
|
|
+3. **业务量监控**:监控日常业务交易量变化
|
|
|
+4. **性能监控**:关注响应时间和系统资源使用情况
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 9 总结
|
|
|
+
|
|
|
+### 9.1 设计优势
|
|
|
+
|
|
|
+1. **架构清晰**:参考成功的 `JiangSuSocialCardBusiness.cs` 架构模式
|
|
|
+2. **接口统一**:通过参数化设计实现所有交易的统一调用
|
|
|
+3. **完全合规**:严格按照江苏工伤联网接口文档规范实现
|
|
|
+4. **易于集成**:可直接嵌套到现有HIS系统中使用
|
|
|
+5. **扩展性强**:新增交易类型只需要添加映射关系
|
|
|
+
|
|
|
+### 9.2 关键特性
|
|
|
+
|
|
|
+- ✅ **初始化函数**:完整的系统初始化和环境检查
|
|
|
+- ✅ **通用接口函数**:统一的交易处理入口
|
|
|
+- ✅ **参数化调用**:通过参数区分不同的业务交易
|
|
|
+- ✅ **错误处理机制**:多层次的错误处理和自动重试
|
|
|
+- ✅ **便捷方法**:为常用交易提供简化调用接口
|
|
|
+- ✅ **直接嵌套**:可无缝集成到HIS系统业务流程
|
|
|
+
|
|
|
+### 9.3 实施建议
|
|
|
+
|
|
|
+1. **分阶段实施**:建议按交易类型分阶段实施和测试
|
|
|
+2. **充分测试**:在正式上线前进行充分的功能和压力测试
|
|
|
+3. **监控运维**:建立完善的监控和运维机制
|
|
|
+4. **文档维护**:及时更新技术文档和操作手册
|
|
|
+
|
|
|
+这个设计方案完全符合您的思路,提供了一个初始化函数和一个通用接口函数,通过参数来区分不同的交易类型,可以直接嵌套到HIS系统中使用,大大简化了工伤联网接口的集成复杂度。
|