# 江苏工伤联网结算接口对接实现逻辑设计
## 版本信息
| 版本号 | 修改内容 | 修改日期 | 修改人 |
|--------|----------|----------|--------|
| 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
///
/// 江苏工伤联网结算业务类
/// 基于JSSiInterface.dll动态库,严格按照江苏工伤联网接口规范v2.1实现
/// 参考JiangSuSocialCardBusiness.cs的成功架构模式
///
public class JiangSuWorkInjuryBusiness
{
#region DLL导入声明 - 严格按照工伤文档规范
///
/// 初始化函数 - 检查整个运行环境
///
/// 错误信息
/// 成功:0,失败:-1
[DllImport("JSSiInterface.dll", EntryPoint = "Si_INIT", CharSet = CharSet.Ansi)]
private extern static int Si_INIT(StringBuilder pErrMsg);
///
/// 交易函数 - 处理所有业务交易
///
/// 输入参数JSON字符串
/// 输出参数JSON字符串
/// 成功:0,失败:<0
[DllImport("JSSiInterface.dll", EntryPoint = "Si_Busi", CharSet = CharSet.Ansi)]
private extern static int Si_Busi(string inputdata, StringBuilder outputdata);
#endregion
#region 状态管理和内部变量
///
/// 系统初始化状态
///
private static bool isInitialized = false;
///
/// 当前配置信息
///
private static WorkInjuryConfig currentConfig = null;
///
/// 当前签到流水号
///
private static string currentSignNo = "";
///
/// 签到时间
///
private static DateTime signInTime = DateTime.MinValue;
///
/// 签到操作员
///
private static string signInOperator = "";
///
/// 报文ID缓存(用于冲正交易)
///
private static readonly Dictionary transactionRecords = new Dictionary();
///
/// 序列号计数器(用于生成唯一报文ID)
///
private static int sequenceCounter = 0;
private static readonly object sequenceLock = new object();
///
/// 交易记录类
///
private class TransactionRecord
{
public string MessageId { get; set; }
public string TransactionCode { get; set; }
public DateTime TransactionTime { get; set; }
public string OperatorId { get; set; }
}
#endregion
}
```
### 3.2 配置管理类
```csharp
///
/// 江苏工伤联网配置类 - 严格按照工伤文档规范定义
///
public class WorkInjuryConfig
{
///
/// 协议机构编号 - 由江苏人社分配
///
public string FixmedinsCode { get; set; } = "H00001";
///
/// 协议机构名称
///
public string FixmedinsName { get; set; } = "第一人民医院";
///
/// 接收方系统代码 - 默认"JSYTH"
///
public string ReceiverSysCode { get; set; } = "JSYTH";
///
/// 接口版本号 - 如"V2.1"
///
public string InterfaceVersion { get; set; } = "V2.1";
///
/// 经办人类别 - 1:经办人 2:自助终端 3:移动终端
///
public string OperatorType { get; set; } = "1";
///
/// 默认经办人编号
///
public string DefaultOperator { get; set; } = "001";
///
/// 默认经办人姓名
///
public string DefaultOperatorName { get; set; } = "系统管理员";
}
```
### 3.3 交易请求参数类
```csharp
///
/// 工伤联网交易请求参数 - 按照工伤文档标准格式
///
public class WorkInjuryTransactionRequest
{
///
/// 交易编号 - 4位数字
///
public string TransactionCode { get; set; }
///
/// 业务参数 - 具体交易的输入参数
///
public object BusinessParams { get; set; }
///
/// 识别方式 - 1:实体社保卡 2:电子凭证
///
public string IdentifyMode { get; set; } = "1";
///
/// 电子社保卡二维码(识别方式为2时必填)
///
public string QrCodeInfo { get; set; } = "";
///
/// 经办人编号(可选,使用默认值)
///
public string OperatorId { get; set; } = "";
///
/// 经办人姓名(可选,使用默认值)
///
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
///
/// 交易代码映射表 - 基于工伤文档接口列表
///
private static readonly Dictionary TransactionMapping = new Dictionary
{
// 认证类
{"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
///
/// 初始化江苏工伤联网系统
/// 参考JiangSuSocialCardBusiness的Initialize方法,但适配工伤业务
///
/// 配置参数
/// 初始化结果
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
///
/// 通用工伤联网交易处理接口
/// 支持所有工伤文档定义的交易类型
///
/// 交易名称(可使用中文名称或交易编号)
/// 业务参数对象
/// 识别方式:1-实体社保卡,2-电子凭证
/// 电子社保卡二维码(识别方式为2时必填)
/// 经办人编号(可选)
/// 经办人姓名(可选)
/// 交易处理结果
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;
}
///
/// 特殊交易后处理逻辑
///
private static void PostProcessTransaction(string transactionCode, JObject result)
{
if ((bool)result["success"])
{
switch (transactionCode)
{
case "9001": // 签到交易成功
var signData = result["data"];
if (signData != null)
{
currentSignNo = signData["sign_no"]?.ToString() ?? "";
signInTime = DateTime.Now;
signInOperator = currentConfig?.DefaultOperator ?? "";
// 记录签到成功日志
LogInfo($"签到成功,流水号: {currentSignNo}, 时间: {signInTime:yyyy-MM-dd HH:mm:ss}");
}
break;
case "9002": // 签退交易成功
// 清除签到状态
currentSignNo = "";
signInTime = DateTime.MinValue;
signInOperator = "";
LogInfo($"签退成功,时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
break;
}
}
}
```
### 5.3 标准输入参数构造
```csharp
///
/// 构造标准的工伤联网交易输入参数
/// 严格按照工伤文档表2格式构造,支持特殊交易格式
///
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 baseInputData = 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 // 电子社保卡二维码
};
// 处理特殊交易格式
object finalInputData = BuildSpecialTransactionInput(baseInputData, transactionCode, businessParams);
// 保存发送方报文ID用于可能的冲正操作
SaveMessageId(msgId, transactionCode);
return finalInputData;
}
///
/// 处理特殊交易的输入格式
/// 按照工伤文档要求,某些交易需要特殊的参数格式
///
private static object BuildSpecialTransactionInput(object baseInputData, string transactionCode, object businessParams)
{
switch (transactionCode)
{
case "2204": // 处方明细上报 - 使用feedetail代替input
return new
{
// 复制基础参数
infno = ((dynamic)baseInputData).infno,
msgid = ((dynamic)baseInputData).msgid,
recer_sys_code = ((dynamic)baseInputData).recer_sys_code,
infver = ((dynamic)baseInputData).infver,
opter_type = ((dynamic)baseInputData).opter_type,
opter = ((dynamic)baseInputData).opter,
opter_name = ((dynamic)baseInputData).opter_name,
inf_time = ((dynamic)baseInputData).inf_time,
fixmedins_code = ((dynamic)baseInputData).fixmedins_code,
fixmedins_name = ((dynamic)baseInputData).fixmedins_name,
sign_no = ((dynamic)baseInputData).sign_no,
idfi_mode = ((dynamic)baseInputData).idfi_mode,
qrcode_info = ((dynamic)baseInputData).qrcode_info,
// 特殊格式:使用feedetail替代input
feedetail = businessParams ?? new object[] { }
};
case "8105": // 上传体检明细 - 使用tjfeedetail代替input
return new
{
// 复制基础参数
infno = ((dynamic)baseInputData).infno,
msgid = ((dynamic)baseInputData).msgid,
recer_sys_code = ((dynamic)baseInputData).recer_sys_code,
infver = ((dynamic)baseInputData).infver,
opter_type = ((dynamic)baseInputData).opter_type,
opter = ((dynamic)baseInputData).opter,
opter_name = ((dynamic)baseInputData).opter_name,
inf_time = ((dynamic)baseInputData).inf_time,
fixmedins_code = ((dynamic)baseInputData).fixmedins_code,
fixmedins_name = ((dynamic)baseInputData).fixmedins_name,
sign_no = ((dynamic)baseInputData).sign_no,
idfi_mode = ((dynamic)baseInputData).idfi_mode,
qrcode_info = ((dynamic)baseInputData).qrcode_info,
// 特殊格式:使用tjfeedetail替代input
tjfeedetail = businessParams ?? new object[] { }
};
default: // 标准交易格式
return new
{
// 复制基础参数
infno = ((dynamic)baseInputData).infno,
msgid = ((dynamic)baseInputData).msgid,
recer_sys_code = ((dynamic)baseInputData).recer_sys_code,
infver = ((dynamic)baseInputData).infver,
opter_type = ((dynamic)baseInputData).opter_type,
opter = ((dynamic)baseInputData).opter,
opter_name = ((dynamic)baseInputData).opter_name,
inf_time = ((dynamic)baseInputData).inf_time,
fixmedins_code = ((dynamic)baseInputData).fixmedins_code,
fixmedins_name = ((dynamic)baseInputData).fixmedins_name,
sign_no = ((dynamic)baseInputData).sign_no,
idfi_mode = ((dynamic)baseInputData).idfi_mode,
qrcode_info = ((dynamic)baseInputData).qrcode_info,
// 标准格式:使用input
input = businessParams ?? new { }
};
}
}
```
### 5.4 便捷方法封装
```csharp
// 为常用交易提供便捷方法,简化调用
///
/// 读卡交易 - 获取工伤人员基本信息
///
public static JObject ReadWorkInjuryCard(string identifyMode = "1", string qrCodeInfo = "")
{
return ProcessWorkInjuryTransaction("ReadCard", null, identifyMode, qrCodeInfo);
}
///
/// 门诊/住院登记
///
public static JObject RegisterPatient(object registerParams, string identifyMode = "1")
{
return ProcessWorkInjuryTransaction("RegisterPatient", registerParams, identifyMode);
}
///
/// 费用预结算
///
public static JObject PreSettlement(object settlementParams)
{
return ProcessWorkInjuryTransaction("PreSettle", settlementParams);
}
///
/// 费用结算
///
public static JObject Settlement(object settlementParams)
{
return ProcessWorkInjuryTransaction("Settle", settlementParams);
}
///
/// 处方明细上传
///
public static JObject UploadPrescription(object prescriptionDetails)
{
return ProcessWorkInjuryTransaction("UploadPrescription", prescriptionDetails);
}
///
/// 签到交易
///
public static JObject SignIn()
{
return ProcessWorkInjuryTransaction("SignIn");
}
///
/// 签退交易
///
public static JObject SignOut()
{
return ProcessWorkInjuryTransaction("SignOut");
}
///
/// 冲正交易
///
public static JObject ReverseTransaction(string originalTransactionCode, string originalMessageId)
{
var reverseParams = new
{
infno = originalTransactionCode,
msgid = originalMessageId
};
return ProcessWorkInjuryTransaction("ReverseTransaction", reverseParams);
}
///
/// 根据交易记录进行冲正(便捷方法)
///
public static JObject ReverseTransactionByRecord(string messageId)
{
if (transactionRecords.ContainsKey(messageId))
{
var record = transactionRecords[messageId];
return ReverseTransaction(record.TransactionCode, record.MessageId);
}
else
{
return new JObject
{
["success"] = false,
["code"] = 1006,
["message"] = $"未找到报文ID对应的交易记录: {messageId}",
["device"] = "江苏工伤联网接口"
};
}
}
///
/// 获取当前签到状态
///
public static JObject GetSignInStatus()
{
return new JObject
{
["success"] = true,
["code"] = 200,
["message"] = "签到状态查询成功",
["data"] = new JObject
{
["isSignedIn"] = !string.IsNullOrEmpty(currentSignNo),
["signNo"] = currentSignNo,
["signInTime"] = signInTime == DateTime.MinValue ? "" : signInTime.ToString("yyyy-MM-dd HH:mm:ss"),
["signInOperator"] = signInOperator,
["isInitialized"] = isInitialized
}
};
}
///
/// 批量处方明细上传 - 便捷方法
///
public static JObject BatchUploadPrescriptions(List