版本号 | 修改内容 | 修改日期 | 修改人 |
---|---|---|---|
V1.0 | 初始版本设计 | 2024.12.19 | 系统 |
基于江苏省工伤机构联网结算接口开发手册(V2.1版本),设计一个统一的工伤联网接口对接业务类,实现与江苏省工伤联网系统的无缝对接。
JiangSuSocialCardBusiness.cs
的成功模式,提供统一的业务接口采用用户建议的实现方案:
┌─────────────────────────────────────────┐
│ HIS医院信息系统 │
├─────────────────────────────────────────┤
│ JiangSuWorkInjuryBusiness │
│ ┌─────────────┬─────────────────────┐ │
│ │ 初始化函数 │ 通用接口函数 │ │
│ │ Initialize │ ProcessTransaction │ │
│ └─────────────┴─────────────────────┘ │
├─────────────────────────────────────────┤
│ JSSiInterface.dll │
│ ┌─────────────┬─────────────────────┐ │
│ │ Si_INIT │ Si_Busi │ │
│ └─────────────┴─────────────────────┘ │
├─────────────────────────────────────────┤
│ HTTPS/SSL安全传输协议 │
├─────────────────────────────────────────┤
│ 江苏省工伤联网中心系统 │
└─────────────────────────────────────────┘
根据工伤文档,接口共分为4大类:
分类 | 交易编号范围 | 主要功能 | 实现策略 |
---|---|---|---|
对账类 | 1320-1321 | 总额对账、明细对账 | 统一对账处理 |
认证类 | 9001-9002 | 签到、签退 | 会话管理 |
业务类 | 1101, 22XX, 81XX, 23XX | 读卡、登记、结算、体检、转院 | 核心业务处理 |
下载类 | 1301, 91XX | 数据下载、查询 | 数据同步 |
/// <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
}
/// <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; } = "系统管理员";
}
/// <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; } = "";
}
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;
}
/// <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"} // 参保人近期就诊信息查询
};
/// <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;
}
/// <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;
}
/// <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;
}
// 为常用交易提供便捷方法,简化调用
/// <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);
}
/// <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;
}
/// <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"] = "重试机制异常" };
}
// 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}");
}
}
}
<!-- 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>
复制DLL文件
将 JSSiInterface.dll 复制到应用程序bin目录
确保DLL文件版本与接口文档版本一致
配置参数设置
根据医院实际情况修改配置文件中的参数
协议机构编号和名称需要与江苏人社备案信息一致
权限配置
确保应用程序有读取DLL文件的权限
配置网络访问权限
测试验证
先在测试环境验证接口连通性
执行签到/签退测试确认基础功能
进行完整业务流程测试
JiangSuSocialCardBusiness.cs
架构模式这个设计方案完全符合您的思路,提供了一个初始化函数和一个通用接口函数,通过参数来区分不同的交易类型,可以直接嵌套到HIS系统中使用,大大简化了工伤联网接口的集成复杂度。