|
|
@@ -0,0 +1,1313 @@
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.IO;
|
|
|
+using System.Linq;
|
|
|
+using System.Runtime.InteropServices;
|
|
|
+using System.Text;
|
|
|
+using System.Threading;
|
|
|
+using Newtonsoft.Json;
|
|
|
+using Newtonsoft.Json.Linq;
|
|
|
+
|
|
|
+namespace ThCardReader
|
|
|
+{
|
|
|
+ /// <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
|
|
|
+
|
|
|
+ #region 状态管理和内部变量
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 系统初始化状态
|
|
|
+ /// </summary>
|
|
|
+ private static bool isInitialized = false;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 当前配置信息
|
|
|
+ /// </summary>
|
|
|
+ private static WorkInjuryConfig currentConfig = null;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 当前签到流水号
|
|
|
+ /// </summary>
|
|
|
+ private static string currentSignNo = "";
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 签到时间
|
|
|
+ /// </summary>
|
|
|
+ private static DateTime signInTime = DateTime.MinValue;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 签到操作员
|
|
|
+ /// </summary>
|
|
|
+ private static string signInOperator = "";
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 报文ID缓存(用于冲正交易)
|
|
|
+ /// </summary>
|
|
|
+ private static readonly Dictionary<string, TransactionRecord> transactionRecords = new Dictionary<string, TransactionRecord>();
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 序列号计数器(用于生成唯一报文ID)
|
|
|
+ /// </summary>
|
|
|
+ private static int sequenceCounter = 0;
|
|
|
+ private static readonly object sequenceLock = new object();
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 交易记录类
|
|
|
+ /// </summary>
|
|
|
+ private class TransactionRecord
|
|
|
+ {
|
|
|
+ public string MessageId { get; set; }
|
|
|
+ public string TransactionCode { get; set; }
|
|
|
+ public DateTime TransactionTime { get; set; }
|
|
|
+ public string OperatorId { get; set; }
|
|
|
+ }
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 配置管理类
|
|
|
+
|
|
|
+ /// <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 string LogPath { get; set; } = "logs/workinjury/";
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <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; } = "";
|
|
|
+ }
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 交易代码映射表
|
|
|
+
|
|
|
+ /// <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"} // 参保人近期就诊信息查询
|
|
|
+ };
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 核心业务方法 - 初始化函数
|
|
|
+
|
|
|
+ /// <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;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 确保日志目录存在
|
|
|
+ if (!Directory.Exists(config.LogPath))
|
|
|
+ {
|
|
|
+ Directory.CreateDirectory(config.LogPath);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 调用底层初始化函数
|
|
|
+ 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();
|
|
|
+
|
|
|
+ LogInfo($"系统初始化成功,版本: {config.InterfaceVersion}");
|
|
|
+ }
|
|
|
+ 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;
|
|
|
+
|
|
|
+ LogError($"系统初始化失败,错误码: {initResult}, 错误信息: {errorMsg}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 1001;
|
|
|
+ result["message"] = $"江苏工伤联网系统初始化异常: {ex.Message}";
|
|
|
+ result["device"] = "江苏工伤联网接口";
|
|
|
+ result["exception"] = ex.GetType().Name;
|
|
|
+
|
|
|
+ LogError($"系统初始化异常: {ex.Message}");
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 核心业务方法 - 通用接口函数
|
|
|
+
|
|
|
+ /// <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);
|
|
|
+
|
|
|
+ LogInfo($"交易 {transactionName}({transactionCode}) 完成,结果: {result["success"]}");
|
|
|
+
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 1005;
|
|
|
+ result["message"] = $"工伤联网交易异常: {ex.Message}";
|
|
|
+ result["device"] = "江苏工伤联网接口";
|
|
|
+ result["exception"] = ex.GetType().Name;
|
|
|
+ result["transactionName"] = transactionName;
|
|
|
+
|
|
|
+ LogError($"交易 {transactionName} 异常: {ex.Message}");
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 输入输出处理方法
|
|
|
+
|
|
|
+ /// <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 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 处理特殊交易的输入格式
|
|
|
+ /// 按照工伤文档要求,某些交易需要特殊的参数格式
|
|
|
+ /// </summary>
|
|
|
+ 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 { }
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <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>
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 辅助工具方法
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 获取交易编号
|
|
|
+ /// 支持中文名称、英文名称和直接的数字编号
|
|
|
+ /// </summary>
|
|
|
+ private static string GetTransactionCode(string transactionName)
|
|
|
+ {
|
|
|
+ if (string.IsNullOrEmpty(transactionName))
|
|
|
+ return "";
|
|
|
+
|
|
|
+ // 如果直接是4位数字编号,直接返回
|
|
|
+ if (transactionName.Length == 4 && transactionName.All(char.IsDigit))
|
|
|
+ return transactionName;
|
|
|
+
|
|
|
+ // 从映射表中查找
|
|
|
+ if (TransactionMapping.ContainsKey(transactionName))
|
|
|
+ return TransactionMapping[transactionName];
|
|
|
+
|
|
|
+ // 支持中文名称映射
|
|
|
+ var chineseMapping = new Dictionary<string, string>
|
|
|
+ {
|
|
|
+ {"签到", "9001"}, {"签退", "9002"},
|
|
|
+ {"读卡", "1101"}, {"登记", "2201"}, {"结算", "2207"},
|
|
|
+ {"撤销", "2208"}, {"冲正", "2209"}, {"预结算", "2206"},
|
|
|
+ {"处方上报", "2204"}, {"处方撤销", "2205"},
|
|
|
+ {"总额对账", "1320"}, {"明细对账", "1321"},
|
|
|
+ {"批量下载", "1301"}
|
|
|
+ };
|
|
|
+
|
|
|
+ if (chineseMapping.ContainsKey(transactionName))
|
|
|
+ return chineseMapping[transactionName];
|
|
|
+
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 生成唯一的发送方报文ID
|
|
|
+ /// 格式:协议机构编号(6位) + 时间戳(14位) + 序列号(4位) = 24位
|
|
|
+ /// </summary>
|
|
|
+ private static string GenerateMessageId()
|
|
|
+ {
|
|
|
+ lock (sequenceLock)
|
|
|
+ {
|
|
|
+ string institutionCode = currentConfig?.FixmedinsCode ?? "H00001";
|
|
|
+ if (institutionCode.Length > 6)
|
|
|
+ institutionCode = institutionCode.Substring(0, 6);
|
|
|
+ else
|
|
|
+ institutionCode = institutionCode.PadRight(6, '0');
|
|
|
+
|
|
|
+ string timestamp = DateTime.Now.ToString("yyyyMMddHHmmss");
|
|
|
+
|
|
|
+ sequenceCounter = (sequenceCounter + 1) % 10000; // 保持4位数字
|
|
|
+ string sequence = sequenceCounter.ToString("D4");
|
|
|
+
|
|
|
+ return institutionCode + timestamp + sequence;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 保存发送方报文ID用于冲正交易
|
|
|
+ /// </summary>
|
|
|
+ private static void SaveMessageId(string msgId, string transactionCode)
|
|
|
+ {
|
|
|
+ var record = new TransactionRecord
|
|
|
+ {
|
|
|
+ MessageId = msgId,
|
|
|
+ TransactionCode = transactionCode,
|
|
|
+ TransactionTime = DateTime.Now,
|
|
|
+ OperatorId = currentConfig?.DefaultOperator ?? ""
|
|
|
+ };
|
|
|
+
|
|
|
+ transactionRecords[msgId] = record;
|
|
|
+
|
|
|
+ // 清理过期记录(7天前的)
|
|
|
+ var expireTime = DateTime.Now.AddDays(-7);
|
|
|
+ var expiredKeys = transactionRecords
|
|
|
+ .Where(kv => kv.Value.TransactionTime < expireTime)
|
|
|
+ .Select(kv => kv.Key)
|
|
|
+ .ToList();
|
|
|
+
|
|
|
+ foreach (var key in expiredKeys)
|
|
|
+ {
|
|
|
+ transactionRecords.Remove(key);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 检查DLL文件是否存在
|
|
|
+ /// </summary>
|
|
|
+ private static JObject CheckDllExists()
|
|
|
+ {
|
|
|
+ var result = new JObject();
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ string programDir = AppDomain.CurrentDomain.BaseDirectory;
|
|
|
+ string dllPath = Path.Combine(programDir, "JSSiInterface.dll");
|
|
|
+
|
|
|
+ if (File.Exists(dllPath))
|
|
|
+ {
|
|
|
+ FileInfo fileInfo = new FileInfo(dllPath);
|
|
|
+
|
|
|
+ result["success"] = true;
|
|
|
+ result["code"] = 200;
|
|
|
+ result["message"] = "JSSiInterface.dll文件检查通过";
|
|
|
+ result["device"] = "江苏工伤联网接口";
|
|
|
+ result["data"] = new JObject
|
|
|
+ {
|
|
|
+ ["dllPath"] = dllPath,
|
|
|
+ ["fileSize"] = fileInfo.Length,
|
|
|
+ ["lastModified"] = fileInfo.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss"),
|
|
|
+ ["programDirectory"] = programDir
|
|
|
+ };
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 8001;
|
|
|
+ result["message"] = "JSSiInterface.dll文件不存在";
|
|
|
+ result["device"] = "江苏工伤联网接口";
|
|
|
+ result["data"] = new JObject
|
|
|
+ {
|
|
|
+ ["expectedPath"] = dllPath,
|
|
|
+ ["programDirectory"] = programDir,
|
|
|
+ ["suggestion"] = "请将JSSiInterface.dll文件复制到程序目录"
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 8002;
|
|
|
+ result["message"] = $"DLL文件检查异常: {ex.Message}";
|
|
|
+ result["device"] = "江苏工伤联网接口";
|
|
|
+ result["exception"] = ex.GetType().Name;
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 记录信息日志
|
|
|
+ /// </summary>
|
|
|
+ private static void LogInfo(string message)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (currentConfig != null)
|
|
|
+ {
|
|
|
+ string logPath = Path.Combine(currentConfig.LogPath, $"workinjury_{DateTime.Now:yyyyMMdd}.log");
|
|
|
+ string logEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [INFO] {message}{Environment.NewLine}";
|
|
|
+ File.AppendAllText(logPath, logEntry);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch
|
|
|
+ {
|
|
|
+ // 日志记录失败不影响主要业务
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 记录错误日志
|
|
|
+ /// </summary>
|
|
|
+ private static void LogError(string message)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (currentConfig != null)
|
|
|
+ {
|
|
|
+ string logPath = Path.Combine(currentConfig.LogPath, $"workinjury_{DateTime.Now:yyyyMMdd}.log");
|
|
|
+ string logEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [ERROR] {message}{Environment.NewLine}";
|
|
|
+ File.AppendAllText(logPath, logEntry);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch
|
|
|
+ {
|
|
|
+ // 日志记录失败不影响主要业务
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 便民方法集合 - 按照设计文档要求
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 批量上传处方明细
|
|
|
+ /// 自动处理大量处方的分批上传(每批最多50条)
|
|
|
+ /// </summary>
|
|
|
+ public static JObject BatchUploadPrescriptions(object[] prescriptions, string patientId = "", string visitNo = "")
|
|
|
+ {
|
|
|
+ var result = new JObject();
|
|
|
+ var results = new JArray();
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (prescriptions == null || prescriptions.Length == 0)
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 1006;
|
|
|
+ result["message"] = "处方明细不能为空";
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 分批处理(每批50条)
|
|
|
+ const int batchSize = 50;
|
|
|
+ int totalBatches = (int)Math.Ceiling((double)prescriptions.Length / batchSize);
|
|
|
+ int successCount = 0;
|
|
|
+ int failureCount = 0;
|
|
|
+
|
|
|
+ for (int i = 0; i < totalBatches; i++)
|
|
|
+ {
|
|
|
+ var batch = prescriptions.Skip(i * batchSize).Take(batchSize).ToArray();
|
|
|
+
|
|
|
+ var batchParams = new
|
|
|
+ {
|
|
|
+ patient_id = patientId,
|
|
|
+ visit_no = visitNo,
|
|
|
+ batch_no = (i + 1).ToString(),
|
|
|
+ prescriptions = batch
|
|
|
+ };
|
|
|
+
|
|
|
+ var batchResult = ProcessWorkInjuryTransaction("UploadPrescription", batchParams);
|
|
|
+
|
|
|
+ if ((bool)batchResult["success"])
|
|
|
+ {
|
|
|
+ successCount++;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ failureCount++;
|
|
|
+ }
|
|
|
+
|
|
|
+ results.Add(new JObject
|
|
|
+ {
|
|
|
+ ["batchNo"] = i + 1,
|
|
|
+ ["itemCount"] = batch.Length,
|
|
|
+ ["success"] = batchResult["success"],
|
|
|
+ ["message"] = batchResult["message"],
|
|
|
+ ["code"] = batchResult["code"]
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ result["success"] = failureCount == 0;
|
|
|
+ result["code"] = failureCount == 0 ? 200 : 1007;
|
|
|
+ result["message"] = $"批量上传完成,成功{successCount}批,失败{failureCount}批";
|
|
|
+ result["data"] = new JObject
|
|
|
+ {
|
|
|
+ ["totalBatches"] = totalBatches,
|
|
|
+ ["totalItems"] = prescriptions.Length,
|
|
|
+ ["successCount"] = successCount,
|
|
|
+ ["failureCount"] = failureCount,
|
|
|
+ ["batchResults"] = results
|
|
|
+ };
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 1008;
|
|
|
+ result["message"] = $"批量上传异常: {ex.Message}";
|
|
|
+ result["exception"] = ex.GetType().Name;
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 完整的工伤就医流程
|
|
|
+ /// 自动完成:读卡 -> 登记 -> 预结算 -> 结算 的完整流程
|
|
|
+ /// </summary>
|
|
|
+ public static JObject CompleteWorkInjuryProcess(object patientInfo = null, object[] feeDetails = null)
|
|
|
+ {
|
|
|
+ var result = new JObject();
|
|
|
+ var processSteps = new JArray();
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ // 第1步:读卡
|
|
|
+ var readCardResult = ProcessWorkInjuryTransaction("ReadCard");
|
|
|
+ processSteps.Add(new JObject
|
|
|
+ {
|
|
|
+ ["step"] = 1,
|
|
|
+ ["name"] = "读卡",
|
|
|
+ ["success"] = readCardResult["success"],
|
|
|
+ ["message"] = readCardResult["message"],
|
|
|
+ ["data"] = readCardResult["data"]
|
|
|
+ });
|
|
|
+
|
|
|
+ if (!(bool)readCardResult["success"])
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["message"] = "读卡失败,流程终止";
|
|
|
+ result["processSteps"] = processSteps;
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 第2步:登记
|
|
|
+ var registerParams = patientInfo ?? new
|
|
|
+ {
|
|
|
+ visit_type = "1", // 门诊
|
|
|
+ dept_code = "001",
|
|
|
+ dept_name = "内科",
|
|
|
+ doctor_code = "DOC001",
|
|
|
+ doctor_name = "张医生"
|
|
|
+ };
|
|
|
+
|
|
|
+ var registerResult = ProcessWorkInjuryTransaction("RegisterPatient", registerParams);
|
|
|
+ processSteps.Add(new JObject
|
|
|
+ {
|
|
|
+ ["step"] = 2,
|
|
|
+ ["name"] = "登记",
|
|
|
+ ["success"] = registerResult["success"],
|
|
|
+ ["message"] = registerResult["message"],
|
|
|
+ ["data"] = registerResult["data"]
|
|
|
+ });
|
|
|
+
|
|
|
+ if (!(bool)registerResult["success"])
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["message"] = "登记失败,流程终止";
|
|
|
+ result["processSteps"] = processSteps;
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果有费用明细,进行预结算和结算
|
|
|
+ if (feeDetails != null && feeDetails.Length > 0)
|
|
|
+ {
|
|
|
+ // 第3步:预结算
|
|
|
+ var preSettleParams = new
|
|
|
+ {
|
|
|
+ visit_no = registerResult["data"]?["visit_no"]?.ToString() ?? "",
|
|
|
+ fee_details = feeDetails
|
|
|
+ };
|
|
|
+
|
|
|
+ var preSettleResult = ProcessWorkInjuryTransaction("PreSettle", preSettleParams);
|
|
|
+ processSteps.Add(new JObject
|
|
|
+ {
|
|
|
+ ["step"] = 3,
|
|
|
+ ["name"] = "预结算",
|
|
|
+ ["success"] = preSettleResult["success"],
|
|
|
+ ["message"] = preSettleResult["message"],
|
|
|
+ ["data"] = preSettleResult["data"]
|
|
|
+ });
|
|
|
+
|
|
|
+ if ((bool)preSettleResult["success"])
|
|
|
+ {
|
|
|
+ // 第4步:正式结算
|
|
|
+ var settleParams = new
|
|
|
+ {
|
|
|
+ visit_no = registerResult["data"]?["visit_no"]?.ToString() ?? "",
|
|
|
+ pre_settle_id = preSettleResult["data"]?["pre_settle_id"]?.ToString() ?? ""
|
|
|
+ };
|
|
|
+
|
|
|
+ var settleResult = ProcessWorkInjuryTransaction("Settle", settleParams);
|
|
|
+ processSteps.Add(new JObject
|
|
|
+ {
|
|
|
+ ["step"] = 4,
|
|
|
+ ["name"] = "结算",
|
|
|
+ ["success"] = settleResult["success"],
|
|
|
+ ["message"] = settleResult["message"],
|
|
|
+ ["data"] = settleResult["data"]
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ result["success"] = true;
|
|
|
+ result["code"] = 200;
|
|
|
+ result["message"] = "工伤就医流程完成";
|
|
|
+ result["processSteps"] = processSteps;
|
|
|
+
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 1009;
|
|
|
+ result["message"] = $"工伤就医流程异常: {ex.Message}";
|
|
|
+ result["exception"] = ex.GetType().Name;
|
|
|
+ result["processSteps"] = processSteps;
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 智能重试交易
|
|
|
+ /// 自动重试失败的交易,使用指数退避算法
|
|
|
+ /// </summary>
|
|
|
+ public static JObject SmartRetryTransaction(string transactionName, object businessParams = null,
|
|
|
+ int maxRetries = 3, int baseDelayMs = 1000)
|
|
|
+ {
|
|
|
+ var result = new JObject();
|
|
|
+ var retryAttempts = new JArray();
|
|
|
+
|
|
|
+ for (int attempt = 1; attempt <= maxRetries; attempt++)
|
|
|
+ {
|
|
|
+ var attemptResult = ProcessWorkInjuryTransaction(transactionName, businessParams);
|
|
|
+
|
|
|
+ retryAttempts.Add(new JObject
|
|
|
+ {
|
|
|
+ ["attempt"] = attempt,
|
|
|
+ ["success"] = attemptResult["success"],
|
|
|
+ ["message"] = attemptResult["message"],
|
|
|
+ ["code"] = attemptResult["code"],
|
|
|
+ ["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")
|
|
|
+ });
|
|
|
+
|
|
|
+ if ((bool)attemptResult["success"])
|
|
|
+ {
|
|
|
+ result = attemptResult; // 成功时返回最后一次的结果
|
|
|
+ result["retryInfo"] = new JObject
|
|
|
+ {
|
|
|
+ ["totalAttempts"] = attempt,
|
|
|
+ ["success"] = true,
|
|
|
+ ["retryAttempts"] = retryAttempts
|
|
|
+ };
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果不是最后一次尝试,等待后重试
|
|
|
+ if (attempt < maxRetries)
|
|
|
+ {
|
|
|
+ int delay = baseDelayMs * (int)Math.Pow(2, attempt - 1); // 指数退避
|
|
|
+ Thread.Sleep(delay);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 所有重试都失败了
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 1010;
|
|
|
+ result["message"] = $"交易{transactionName}经过{maxRetries}次重试后仍然失败";
|
|
|
+ result["retryInfo"] = new JObject
|
|
|
+ {
|
|
|
+ ["totalAttempts"] = maxRetries,
|
|
|
+ ["success"] = false,
|
|
|
+ ["retryAttempts"] = retryAttempts
|
|
|
+ };
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 获取交易统计信息
|
|
|
+ /// 提供系统性能和健康状况监控
|
|
|
+ /// </summary>
|
|
|
+ public static JObject GetTransactionStatistics()
|
|
|
+ {
|
|
|
+ var result = new JObject();
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var stats = new JObject
|
|
|
+ {
|
|
|
+ ["currentTime"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
|
|
|
+ ["systemStatus"] = new JObject
|
|
|
+ {
|
|
|
+ ["initialized"] = isInitialized,
|
|
|
+ ["signedIn"] = !string.IsNullOrEmpty(currentSignNo),
|
|
|
+ ["signInTime"] = signInTime == DateTime.MinValue ? null : signInTime.ToString("yyyy-MM-dd HH:mm:ss"),
|
|
|
+ ["currentSignNo"] = currentSignNo,
|
|
|
+ ["signInOperator"] = signInOperator
|
|
|
+ },
|
|
|
+ ["transactionRecords"] = new JObject
|
|
|
+ {
|
|
|
+ ["totalCount"] = transactionRecords.Count,
|
|
|
+ ["oldestRecord"] = transactionRecords.Count > 0 ?
|
|
|
+ transactionRecords.Values.Min(r => r.TransactionTime).ToString("yyyy-MM-dd HH:mm:ss") : null,
|
|
|
+ ["newestRecord"] = transactionRecords.Count > 0 ?
|
|
|
+ transactionRecords.Values.Max(r => r.TransactionTime).ToString("yyyy-MM-dd HH:mm:ss") : null
|
|
|
+ },
|
|
|
+ ["configuration"] = currentConfig != null ? new JObject
|
|
|
+ {
|
|
|
+ ["fixmedinsCode"] = currentConfig.FixmedinsCode,
|
|
|
+ ["fixmedinsName"] = currentConfig.FixmedinsName,
|
|
|
+ ["interfaceVersion"] = currentConfig.InterfaceVersion,
|
|
|
+ ["logPath"] = currentConfig.LogPath
|
|
|
+ } : null
|
|
|
+ };
|
|
|
+
|
|
|
+ result["success"] = true;
|
|
|
+ result["code"] = 200;
|
|
|
+ result["message"] = "统计信息获取成功";
|
|
|
+ result["data"] = stats;
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 1011;
|
|
|
+ result["message"] = $"获取统计信息异常: {ex.Message}";
|
|
|
+ result["exception"] = ex.GetType().Name;
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 系统健康检查
|
|
|
+ /// 全面检查系统状态和连接性
|
|
|
+ /// </summary>
|
|
|
+ public static JObject HealthCheck()
|
|
|
+ {
|
|
|
+ var result = new JObject();
|
|
|
+ var checks = new JObject();
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ // 1. 检查DLL文件
|
|
|
+ var dllCheck = CheckDllExists();
|
|
|
+ checks["dllStatus"] = new JObject
|
|
|
+ {
|
|
|
+ ["success"] = dllCheck["success"],
|
|
|
+ ["message"] = dllCheck["message"]
|
|
|
+ };
|
|
|
+
|
|
|
+ // 2. 检查初始化状态
|
|
|
+ checks["initStatus"] = new JObject
|
|
|
+ {
|
|
|
+ ["initialized"] = isInitialized,
|
|
|
+ ["hasConfig"] = currentConfig != null
|
|
|
+ };
|
|
|
+
|
|
|
+ // 3. 检查签到状态
|
|
|
+ checks["signInStatus"] = new JObject
|
|
|
+ {
|
|
|
+ ["signedIn"] = !string.IsNullOrEmpty(currentSignNo),
|
|
|
+ ["signNo"] = currentSignNo,
|
|
|
+ ["signInTime"] = signInTime == DateTime.MinValue ? null : signInTime.ToString("yyyy-MM-dd HH:mm:ss")
|
|
|
+ };
|
|
|
+
|
|
|
+ // 4. 尝试调用系统函数(如果已初始化)
|
|
|
+ if (isInitialized)
|
|
|
+ {
|
|
|
+ var testResult = ProcessWorkInjuryTransaction("SignIn");
|
|
|
+ checks["connectionTest"] = new JObject
|
|
|
+ {
|
|
|
+ ["success"] = testResult["success"],
|
|
|
+ ["message"] = testResult["message"]
|
|
|
+ };
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ checks["connectionTest"] = new JObject
|
|
|
+ {
|
|
|
+ ["success"] = false,
|
|
|
+ ["message"] = "系统未初始化,无法测试连接"
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 检查日志目录
|
|
|
+ if (currentConfig != null)
|
|
|
+ {
|
|
|
+ checks["logStatus"] = new JObject
|
|
|
+ {
|
|
|
+ ["pathExists"] = Directory.Exists(currentConfig.LogPath),
|
|
|
+ ["logPath"] = currentConfig.LogPath,
|
|
|
+ ["writable"] = true // 简化检查,实际可以尝试写入测试
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ // 综合评估健康状态
|
|
|
+ bool overallHealth = (bool)checks["dllStatus"]["success"] &&
|
|
|
+ (bool)checks["initStatus"]["initialized"];
|
|
|
+
|
|
|
+ result["success"] = true;
|
|
|
+ result["code"] = 200;
|
|
|
+ result["message"] = overallHealth ? "系统健康状态良好" : "系统存在问题";
|
|
|
+ result["data"] = new JObject
|
|
|
+ {
|
|
|
+ ["overallHealth"] = overallHealth,
|
|
|
+ ["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
|
|
|
+ ["checks"] = checks
|
|
|
+ };
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 1012;
|
|
|
+ result["message"] = $"健康检查异常: {ex.Message}";
|
|
|
+ result["exception"] = ex.GetType().Name;
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 获取当前签到状态
|
|
|
+ /// </summary>
|
|
|
+ public static JObject GetSignInStatus()
|
|
|
+ {
|
|
|
+ var result = new JObject();
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ result["success"] = true;
|
|
|
+ result["code"] = 200;
|
|
|
+ result["message"] = "签到状态获取成功";
|
|
|
+ result["data"] = new JObject
|
|
|
+ {
|
|
|
+ ["signedIn"] = !string.IsNullOrEmpty(currentSignNo),
|
|
|
+ ["signNo"] = currentSignNo,
|
|
|
+ ["signInTime"] = signInTime == DateTime.MinValue ? null : signInTime.ToString("yyyy-MM-dd HH:mm:ss"),
|
|
|
+ ["signInOperator"] = signInOperator,
|
|
|
+ ["sessionDuration"] = signInTime == DateTime.MinValue ? null :
|
|
|
+ ((int)(DateTime.Now - signInTime).TotalMinutes).ToString() + "分钟"
|
|
|
+ };
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 1013;
|
|
|
+ result["message"] = $"获取签到状态异常: {ex.Message}";
|
|
|
+ result["exception"] = ex.GetType().Name;
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 根据交易记录进行冲正操作
|
|
|
+ /// </summary>
|
|
|
+ public static JObject ReverseTransactionByRecord(string originalMessageId)
|
|
|
+ {
|
|
|
+ var result = new JObject();
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (!transactionRecords.ContainsKey(originalMessageId))
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 1014;
|
|
|
+ result["message"] = $"找不到原交易记录: {originalMessageId}";
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ var originalRecord = transactionRecords[originalMessageId];
|
|
|
+
|
|
|
+ var reverseParams = new
|
|
|
+ {
|
|
|
+ original_msg_id = originalMessageId,
|
|
|
+ original_transaction_code = originalRecord.TransactionCode,
|
|
|
+ original_transaction_time = originalRecord.TransactionTime.ToString("yyyyMMddHHmmss"),
|
|
|
+ reverse_reason = "系统冲正"
|
|
|
+ };
|
|
|
+
|
|
|
+ result = ProcessWorkInjuryTransaction("ReverseTransaction", reverseParams);
|
|
|
+
|
|
|
+ if ((bool)result["success"])
|
|
|
+ {
|
|
|
+ // 冲正成功后,可以选择移除原记录
|
|
|
+ // transactionRecords.Remove(originalMessageId);
|
|
|
+ LogInfo($"冲正交易成功,原交易ID: {originalMessageId}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ result["success"] = false;
|
|
|
+ result["code"] = 1015;
|
|
|
+ result["message"] = $"冲正交易异常: {ex.Message}";
|
|
|
+ result["exception"] = ex.GetType().Name;
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ #endregion
|
|
|
+ }
|
|
|
+}
|