using System; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace ThCardReader { /// /// 江苏医保社保卡读取业务类 /// 基于HeaSecReadInfo.dll作为主DLL,严格按照江苏医保规范实现 /// public class JiangSuSocialCardBusiness { #region DLL导入声明 // 主DLL: HeaSecReadInfo.dll - 严格按照江苏医保规范v0.9.9.15实现 /// /// 1.14.1 初始化 /// /// JSON格式的初始化参数 /// 错误信息输出缓冲区 /// 0-成功,其他-失败 [DllImport("HeaSecReadInfo.dll", EntryPoint = "Init", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] private extern static Int32 Init(string pInitInfo, StringBuilder pErrMsg); /// /// 1.14.2 读社保卡基本信息 /// /// 社保卡基本信息输出缓冲区 /// 社保卡业务信息输出缓冲区 /// 0-成功,其他-失败 [DllImport("HeaSecReadInfo.dll", EntryPoint = "ReadCardBas", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] private extern static Int32 ReadCardBas(StringBuilder pCardInfo, StringBuilder pBusiCardInfo); /// /// 1.14.3 检验PIN码 /// /// 输出信息缓冲区 /// 0-成功,其他-失败 [DllImport("HeaSecReadInfo.dll", EntryPoint = "VerifyPIN", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] private extern static Int32 VerifyPIN(StringBuilder pOutBuff); /// /// 1.14.4 修改PIN码 /// /// 输出信息缓冲区 /// 0-成功,其他-失败 [DllImport("HeaSecReadInfo.dll", EntryPoint = "ChangePIN", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] private extern static Int32 ChangePIN(StringBuilder pOutBuff); /// /// 1.14.6 电子凭证解码 /// /// 输入数据(JSON格式) /// 输出数据缓冲区 /// 0-成功,其他-失败 [DllImport("HeaSecReadInfo.dll", EntryPoint = "EcQuery", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] private extern static Int32 EcQuery(string pInData, StringBuilder pOutData); /// /// 1.14.8 四合一介质获得个人信息 /// /// 输入数据 /// 输出数据缓冲区 /// 0-成功,其他-失败 [DllImport("HeaSecReadInfo.dll", EntryPoint = "GetPersonInfo", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] private extern static Int32 GetPersonInfo(string pInData, StringBuilder pOutData); #endregion #region 江苏医保刷脸DLL导入声明 (与泰和完全一致) /// /// 江苏医保刷脸功能:使用NationECCode.dll与泰和完全一致 /// 唯一区别:URL参数格式为jiangsu_face_${biztype} /// /// 业务请求地址 /// 交易请求数据 /// 交易返回数据 /// 返回字符串指针 [DllImport("FaceNationECCode.dll", EntryPoint = "NationEcTrans", CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] private extern static IntPtr NationEcTrans(string strUrl, string InData, ref byte OutData); #endregion #region 江苏人社标准接口DLL导入声明 (按照官方规范v2.1.1) /// /// 江苏人社标准接口:读基本信息 /// 按照江苏省人社一体化接口规范说明书标准实现 /// 语法:long iReadCardBas(int iType, char *pOutInfo) /// /// 操作卡的类型:1-接触式,2-非接触式,3-自动寻卡接触式优先,4-自动寻卡非接触式优先 /// 输出信息缓冲区,成功时返回卡信息,失败时返回错误描述 /// 0-成功,非0-失败 [DllImport("SSCardDriver.dll", EntryPoint = "iReadCardBas", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] private extern static long iReadCardBas(int iType, StringBuilder pOutInfo); #endregion #region 江苏人社标准接口业务方法 /// /// 江苏人社标准接口:读取社保卡基本信息 /// 按照江苏省人社一体化接口规范说明书标准实现 /// 使用相同的初始化方法,但接口规范不同 /// /// 卡类型:1-接触式,2-非接触式,3-自动寻卡接触式优先,4-自动寻卡非接触式优先 /// 读卡结果 public static JObject ReadSocialCardByStandard(int cardType = 3) { var result = new JObject(); try { // 检查初始化状态 - 使用相同的初始化检查 if (!isInitialized) { // 如果未初始化,自动使用默认配置初始化 var autoInitResult = Initialize(); if (!(bool)autoInitResult["success"]) { result["success"] = false; result["code"] = 1002; result["message"] = "江苏人社系统自动初始化失败,请检查设备连接"; result["device"] = "江苏人社标准社保卡读卡器"; result["autoInitError"] = autoInitResult["message"]; result["interface"] = "江苏人社标准接口 v2.1.1"; return result; } } // 按照规范要求分配1024字节缓冲区 StringBuilder outInfo = new StringBuilder(1024); // 调用江苏人社标准接口 long readResult = iReadCardBas(cardType, outInfo); if (readResult == 0) { string rawData = outInfo.ToString(); // 解析标准格式的社保卡信息(以|分割的格式) var parsedData = ParseStandardCardInfo(rawData); result["success"] = true; result["code"] = 200; result["message"] = "江苏人社标准接口读卡成功"; result["device"] = "江苏人社标准社保卡读卡器"; result["data"] = parsedData; result["cardType"] = GetCardTypeName(cardType); result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); result["rawData"] = rawData; // 原始数据 result["interface"] = "江苏人社标准接口 v2.1.1"; result["interfaceType"] = "standard"; // 标记为标准接口 // 添加原始读卡数据字段(与医保接口保持一致) result["rawCardData"] = rawData; result["rawBusiData"] = ""; // 人社标准接口只返回一个数据流 } else { string errorInfo = outInfo.ToString(); result["success"] = false; result["code"] = 3000 + (int)readResult; result["message"] = $"江苏人社标准接口读卡失败,错误码: {readResult}"; result["device"] = "江苏人社标准社保卡读卡器"; result["errorCode"] = readResult; result["cardType"] = GetCardTypeName(cardType); result["rawErrorInfo"] = errorInfo; // DLL返回的原始错误信息 result["interface"] = "江苏人社标准接口 v2.1.1"; result["interfaceType"] = "standard"; // 标记为标准接口 result["dllErrorMsg"] = errorInfo; // 与医保接口保持一致的字段名 // 添加原始读卡数据字段(失败时为空) result["rawCardData"] = errorInfo; result["rawBusiData"] = ""; // 根据错误码提供建议 result["suggestion"] = GetErrorSuggestion(readResult); } } catch (Exception ex) { result["success"] = false; result["code"] = 3001; result["message"] = $"江苏人社标准接口读卡异常: {ex.Message}"; result["device"] = "江苏人社标准社保卡读卡器"; result["exception"] = ex.GetType().Name; result["interface"] = "江苏人社标准接口 v2.1.1"; result["interfaceType"] = "standard"; // 标记为标准接口 result["dllErrorMsg"] = $"系统异常: {ex.Message}"; // 与医保接口保持一致 // 添加原始读卡数据字段(异常时为空) result["rawCardData"] = ""; result["rawBusiData"] = ""; } return result; } /// /// 解析江苏人社标准格式的社保卡信息 /// /// 原始数据(以|分割) /// 解析后的结构化数据 private static JObject ParseStandardCardInfo(string rawData) { var result = new JObject(); try { if (string.IsNullOrEmpty(rawData)) { result["error"] = "原始数据为空"; return result; } // 按照规范:发卡地区行政区划代码、社会保障号码、卡号、卡识别码、姓名、卡复位信息、规范版本、发卡日期、卡有效期、终端机编号、终端设备号、省人员识别号 string[] fields = rawData.Split('|'); if (fields.Length >= 12) { result["areaCode"] = fields[0]; // 发卡地区行政区划代码 result["socialSecurityNumber"] = fields[1]; // 社会保障号码 result["cardNumber"] = fields[2]; // 卡号 result["cardId"] = fields[3]; // 卡识别码 result["name"] = fields[4]; // 姓名 result["cardResetInfo"] = fields[5]; // 卡复位信息 result["specVersion"] = fields[6]; // 规范版本 result["issueDate"] = FormatDate(fields[7]); // 发卡日期 result["expireDate"] = FormatDate(fields[8]); // 卡有效期 result["terminalNumber"] = fields[9]; // 终端机编号 result["terminalDevice"] = fields[10]; // 终端设备号 result["provincePersonId"] = fields[11]; // 省人员识别号 result["parseStatus"] = "success"; result["fieldCount"] = fields.Length; } else { result["error"] = $"数据字段不足,期望12个字段,实际{fields.Length}个"; result["rawFields"] = new JArray(fields); result["parseStatus"] = "partial"; } } catch (Exception ex) { result["error"] = $"解析异常: {ex.Message}"; result["parseStatus"] = "failed"; } return result; } /// /// 获取卡类型名称 /// /// 卡类型代码 /// 卡类型名称 private static string GetCardTypeName(int cardType) { switch (cardType) { case 1: return "接触式操作卡"; case 2: return "非接触式操作卡"; case 3: return "自动寻卡(接触式优先)"; case 4: return "自动寻卡(非接触式优先)"; default: return $"未知类型({cardType})"; } } /// /// 根据错误码获取建议 /// /// 错误码 /// 错误建议 private static string GetErrorSuggestion(long errorCode) { switch (errorCode) { case -11: return "请检查社保卡是否正确插入读卡器,确保卡片与读卡器接触良好"; case -1: return "读卡器硬件可能未正确连接或驱动问题,请检查设备连接"; case -2: return "卡片认证失败,请确认卡片为有效的社保卡"; case -3: return "PSAM卡认证失败,请检查PSAM卡是否正确安装"; default: return $"未知错误码 {errorCode},请联系技术支持"; } } #endregion #region 配置和状态管理 /// /// 刷脸认证数据结构 - 与泰和保持一致 /// public class FaceAuthData { public string authNo { get; set; } } private static bool isInitialized = false; private static JiangSuConfig currentConfig = null; /// /// 江苏医保配置类 - 严格按照规范v0.9.9.15定义的13个必需参数(全部大写) /// 注意:这里写死了测试参数,生产环境请修改为实际值 /// public class JiangSuConfig { /// /// 1. 服务端IP地址 - 写死测试值 /// public string IP { get; set; } = "10.61.165.3"; /// /// 2. 服务端端口 - 写死测试值 /// public int PORT { get; set; } = 8086; /// /// 3. 超时时间(单位秒) - 写死测试值 /// public int TIMEOUT { get; set; } = 30; /// /// 4. 动态库日志目录 - 写死测试值,确保目录存在 /// public string LOG_PATH { get; set; } = "E:\\huaihaiProject\\readCard\\ThCardReader\\logs\\"; /// /// 5. 电子凭证中台URL - 写死测试值 /// // public string EC_URL { get; set; } = "http://10.61.165.3:8086/localcfc/api/hsecfc/localQrCodeQuery"; public string EC_URL { get; set; } = "http://10.58.33.207:10086/localcfc/api/hsecfc/localQrCodeQuery"; /// /// 6. 社保卡验证密码方式(1:验证卡pin,2:验证数据库密码) - 写死测试值 /// 医院不需要输入密码,使用2:验证数据库密码 /// public string CARD_PASSTYPE { get; set; } = "2"; /// /// 7. CSB的_api_name - 写死测试值,请替换为实际申请的值 /// public string API_NAME { get; set; } = "hssServives"; /// /// 8. CSB的_api_version - 写死测试值 /// public string API_VERSION { get; set; } = "1.0.0"; /// /// 9. CSB的_api_access_key - 写死测试值,请替换为实际申请的值 /// public string ACCESS_KEY { get; set; } = "090ea4c914324ee38b6978365df46a80"; /// /// 10. CSB的secretKey - 写死测试值,请替换为实际申请的值 /// public string SECRETKEY { get; set; } = "CMgTEMfftMP0EMMoliOs65wZmv8="; /// /// 11. 定点编号 - 写死测试值,请替换为医院实际编号 /// public string ORG_ID { get; set; } = "H32132200561"; /// /// 12. JSON对象字符串(预留) - 写死测试值 /// public string EXT { get; set; } = "{}"; /// /// 13. 定点所属行政区划代码 - 写死测试值(江苏宿迁沭阳) /// public string AREA_CODE { get; set; } = "321322"; /// /// 江苏医保刷脸专用:写死的服务地址 - 与泰和完全一致的配置 /// public string FACE_SERVICE_URL { get; set; } = "http://10.58.33.207:10086/localcfc/api/hsecfc/localQrCodeQuery"; /// /// 江苏医保刷脸专用:写死的机构编号 - 与泰和完全一致的配置 /// public string FACE_ORG_ID { get; set; } = "H32132200561"; /// /// 转换为JSON字符串(严格按照规范大写参数名格式) /// public string ToJson() { var configObject = new { IP = this.IP, PORT = this.PORT, TIMEOUT = this.TIMEOUT, LOG_PATH = this.LOG_PATH, EC_URL = this.EC_URL, CARD_PASSTYPE = this.CARD_PASSTYPE, API_NAME = this.API_NAME, API_VERSION = this.API_VERSION, ACCESS_KEY = this.ACCESS_KEY, SECRETKEY = this.SECRETKEY, ORG_ID = this.ORG_ID, EXT = this.EXT, AREA_CODE = this.AREA_CODE }; return JsonConvert.SerializeObject(configObject, Formatting.None); } } #endregion #region 核心业务方法 /// /// 初始化江苏医保社保卡读取系统 /// /// 配置参数 /// 初始化结果 public static JObject Initialize(JiangSuConfig config = null) { var result = new JObject(); try { // 先检查DLL文件并确保其在正确位置 var dllCheckResult = EnsureDllExists(); if (!(bool)dllCheckResult["success"]) { // 如果DLL检查失败,直接返回错误 return dllCheckResult; } // 使用默认配置或传入的配置 if (config == null) { config = new JiangSuConfig(); } // 确保日志目录存在 if (!Directory.Exists(config.LOG_PATH)) { Directory.CreateDirectory(config.LOG_PATH); } // 构造初始化JSON参数 string initJson = config.ToJson(); StringBuilder errMsg = new StringBuilder(2048); // 调用DLL初始化函数 int initResult = Init(initJson, 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["dllErrorMsg"] = ""; // 成功时错误信息为空 result["errMsgErrorMsg"] = errMsg.ToString(); // 输出参数pErrMsg初始化错误时候返回错误信息,成功时候返回空。 result["initJsonMsg"] = initJson; // 初始化JSON参数 result["initResultMsg"] = initResult; // 0表示成功;非0表示失败。 } else { string errorMsg = errMsg.ToString(); result["success"] = false; result["code"] = 1000 + initResult; result["message"] = $"江苏医保系统初始化失败: {errorMsg}"; result["device"] = "江苏医保社保卡读卡器"; result["errorCode"] = initResult; result["dllErrorMsg"] = errorMsg; // 原始DLL错误信息 result["errMsgErrorMsg"] = errMsg.ToString(); // 输出参数pErrMsg初始化错误时候返回错误信息,成功时候返回空。 result["initJsonMsg"] = initJson; // 初始化JSON参数 result["initResultMsg"] = initResult; // 0表示成功;非0表示失败。 } } catch (Exception ex) { result["success"] = false; result["code"] = 1001; result["message"] = $"江苏医保系统初始化异常: {ex.Message}"; result["device"] = "江苏医保社保卡读卡器"; result["exception"] = ex.GetType().Name; result["dllErrorMsg"] = $"系统异常: {ex.Message}"; // 异常时的错误信息 } return result; } /// /// 读取社保卡基本信息 /// 返回标准38号文格式数据 /// /// 是否自动验证PIN码 /// 是否自动初始化(默认false保持向后兼容) /// 读卡结果 public static JObject ReadSocialCard(bool autoVerifyPIN = false, bool autoInit = false) { var result = new JObject(); try { // 检查初始化状态 if (!isInitialized) { if (autoInit) { // 智能初始化模式:自动使用默认配置初始化 var autoInitResult = Initialize(); if (!(bool)autoInitResult["success"]) { result["success"] = false; result["code"] = 1002; result["message"] = "江苏医保系统自动初始化失败,请检查设备连接"; result["device"] = "江苏医保社保卡读卡器"; result["autoInitError"] = autoInitResult["message"]; result["interface"] = "江苏医保接口 v0.9.9.15"; result["interfaceType"] = "medical"; result["initMode"] = "auto"; return result; } else { // 自动初始化成功,记录日志 result["autoInitSuccess"] = true; result["initMode"] = "auto"; } } else { // 严格模式:保持原有行为,要求用户先初始化 result["success"] = false; result["code"] = 1002; result["message"] = "江苏医保系统未初始化,请先调用初始化接口"; result["device"] = "江苏医保社保卡读卡器"; result["interface"] = "江苏医保接口 v0.9.9.15"; result["interfaceType"] = "medical"; result["initMode"] = "strict"; result["suggestion"] = "请先调用 Initialize() 方法或设置 autoInit=true 启用自动初始化"; return result; } } // 如果需要自动验证PIN码 if (autoVerifyPIN) { var pinResult = VerifyCardPIN(); if (!(bool)pinResult["success"]) { return pinResult; // 返回PIN验证失败结果 } } // 读取社保卡信息 - 按规范要求分配内存 StringBuilder cardInfo = new StringBuilder(2048); // 基本信息缓冲区 StringBuilder busiCardInfo = new StringBuilder(8192); // 业务信息缓冲区 int readResult = ReadCardBas(cardInfo, busiCardInfo); if (readResult == 0) { string rawCardData = cardInfo.ToString(); string rawBusiData = busiCardInfo.ToString(); // 解析38号文格式数据 var parsedData = Parse38DocumentFormat(rawCardData, rawBusiData); result["success"] = true; result["code"] = 200; result["message"] = "社保卡读取成功"; result["device"] = "江苏医保社保卡读卡器"; result["data"] = parsedData; result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); result["interface"] = "江苏医保接口 v0.9.9.15"; result["interfaceType"] = "medical"; // 标记为医保接口 result["initMode"] = autoInit ? "auto" : "manual"; // 记录初始化模式 // 添加原始读卡数据 result["rawCardData"] = rawCardData; result["rawBusiData"] = rawBusiData; } else { result["success"] = false; result["code"] = 2000 + readResult; result["message"] = $"社保卡读取失败,错误码: {readResult}"; result["device"] = "江苏医保社保卡读卡器"; result["errorCode"] = readResult; result["interface"] = "江苏医保接口 v0.9.9.15"; result["interfaceType"] = "medical"; // 标记为医保接口 result["initMode"] = autoInit ? "auto" : "manual"; // 记录初始化模式 // 读卡失败时也记录原始数据(可能为空) result["rawCardData"] = cardInfo.ToString(); result["rawBusiData"] = busiCardInfo.ToString(); } } catch (Exception ex) { result["success"] = false; result["code"] = 2001; result["message"] = $"社保卡读取异常: {ex.Message}"; result["device"] = "江苏医保社保卡读卡器"; result["exception"] = ex.GetType().Name; result["interface"] = "江苏医保接口 v0.9.9.15"; result["interfaceType"] = "medical"; // 标记为医保接口 result["initMode"] = autoInit ? "auto" : "manual"; // 记录初始化模式 } return result; } /// /// 验证社保卡PIN码 /// /// 验证结果 public static JObject VerifyCardPIN() { var result = new JObject(); try { if (!isInitialized) { result["success"] = false; result["code"] = 1002; result["message"] = "江苏医保系统未初始化"; return result; } StringBuilder outBuff = new StringBuilder(1024); int verifyResult = VerifyPIN(outBuff); if (verifyResult == 0) { result["success"] = true; result["code"] = 200; result["message"] = "PIN码验证成功"; result["device"] = "江苏医保社保卡读卡器"; result["data"] = outBuff.ToString(); } else { result["success"] = false; result["code"] = 3000 + verifyResult; result["message"] = $"PIN码验证失败,错误码: {verifyResult}"; result["errorCode"] = verifyResult; } } catch (Exception ex) { result["success"] = false; result["code"] = 3001; result["message"] = $"PIN码验证异常: {ex.Message}"; result["exception"] = ex.GetType().Name; } return result; } /// /// 修改社保卡PIN码 /// /// 修改结果 public static JObject ChangeCardPIN() { var result = new JObject(); try { if (!isInitialized) { result["success"] = false; result["code"] = 1002; result["message"] = "江苏医保系统未初始化"; return result; } StringBuilder outBuff = new StringBuilder(1024); int changeResult = ChangePIN(outBuff); if (changeResult == 0) { result["success"] = true; result["code"] = 200; result["message"] = "PIN码修改成功"; result["device"] = "江苏医保社保卡读卡器"; result["data"] = outBuff.ToString(); } else { result["success"] = false; result["code"] = 4000 + changeResult; result["message"] = $"PIN码修改失败,错误码: {changeResult}"; result["errorCode"] = changeResult; } } catch (Exception ex) { result["success"] = false; result["code"] = 4001; result["message"] = $"PIN码修改异常: {ex.Message}"; result["exception"] = ex.GetType().Name; } return result; } /// /// 四合一介质获取个人信息 /// 支持社保卡、电子凭证、电子社保卡、身份证 /// /// 介质类型 /// 输入数据 /// 个人信息 public static JObject GetPersonInfo(string mediaType = "socialcard", string inputData = "") { var result = new JObject(); try { if (!isInitialized) { result["success"] = false; result["code"] = 1002; result["message"] = "江苏医保系统未初始化"; return result; } // 构造输入参数JSON var inputObject = new { mediaType = mediaType, inputData = inputData }; string inputJson = JsonConvert.SerializeObject(inputObject); StringBuilder outData = new StringBuilder(8192); int getResult = GetPersonInfo(inputJson, outData); if (getResult == 0) { string responseData = outData.ToString(); var parsedInfo = ParsePersonInfo(responseData, mediaType); result["success"] = true; result["code"] = 200; result["message"] = "个人信息获取成功"; result["device"] = "江苏医保社保卡读卡器"; result["mediaType"] = mediaType; result["data"] = parsedInfo; } else { result["success"] = false; result["code"] = 5000 + getResult; result["message"] = $"个人信息获取失败,错误码: {getResult}"; result["errorCode"] = getResult; } } catch (Exception ex) { result["success"] = false; result["code"] = 5001; result["message"] = $"个人信息获取异常: {ex.Message}"; result["exception"] = ex.GetType().Name; } return result; } /// /// 获取设备状态 /// /// 设备状态信息 public static JObject GetDeviceStatus() { var result = new JObject(); try { result["success"] = true; result["code"] = 200; result["message"] = "设备状态获取成功"; result["device"] = "江苏医保社保卡读卡器"; result["data"] = new JObject { ["initialized"] = isInitialized, ["configLoaded"] = currentConfig != null, ["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }; } catch (Exception ex) { result["success"] = false; result["code"] = 7001; result["message"] = $"设备状态获取异常: {ex.Message}"; } return result; } /// /// 重置系统内部状态 /// /// 重置结果 public static JObject ResetSystemState() { var result = new JObject(); try { // 重置内部状态(不调用DLL函数) isInitialized = false; currentConfig = null; result["success"] = true; result["code"] = 200; result["message"] = "系统状态重置成功"; result["device"] = "江苏医保社保卡读卡器"; result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); } catch (Exception ex) { result["success"] = false; result["code"] = 8001; result["message"] = $"系统状态重置异常: {ex.Message}"; } return result; } /// /// 确保DLL文件在正确位置 /// /// 操作结果 private static JObject EnsureDllExists() { var result = new JObject(); try { string programDir = AppDomain.CurrentDomain.BaseDirectory; string targetDllPath = Path.Combine(programDir, "HeaSecReadInfo.dll"); // 如果目标位置已经有DLL文件,直接返回成功 if (File.Exists(targetDllPath)) { result["success"] = true; result["code"] = 200; result["message"] = "HeaSecReadInfo.dll文件已就绪"; result["device"] = "江苏医保社保卡读卡器"; return result; } // 尝试从可能的位置复制DLL文件 string[] possiblePaths = { // 当前目录及其子目录 Path.Combine(programDir, "HeaSecReadInfo.dll"), Path.Combine(programDir, "bin", "Debug", "HeaSecReadInfo.dll"), Path.Combine(programDir, "bin", "Release", "HeaSecReadInfo.dll"), // 上级目录搜索 Path.Combine(programDir, "..", "HeaSecReadInfo.dll"), Path.Combine(programDir, "..", "bin", "Debug", "HeaSecReadInfo.dll"), Path.Combine(programDir, "..", "bin", "Release", "HeaSecReadInfo.dll"), Path.Combine(programDir, "..", "..", "bin", "Debug", "HeaSecReadInfo.dll"), Path.Combine(programDir, "..", "..", "bin", "Release", "HeaSecReadInfo.dll"), // ThCardReader项目目录 Path.Combine(programDir, "..", "..", "ThCardReader", "bin", "Debug", "HeaSecReadInfo.dll"), Path.Combine(programDir, "..", "..", "ThCardReader", "bin", "Release", "HeaSecReadInfo.dll"), // 当前工作目录 Path.Combine(Directory.GetCurrentDirectory(), "HeaSecReadInfo.dll"), Path.Combine(Directory.GetCurrentDirectory(), "bin", "Debug", "HeaSecReadInfo.dll"), Path.Combine(Directory.GetCurrentDirectory(), "bin", "Release", "HeaSecReadInfo.dll"), // 绝对路径搜索(根据错误信息中的路径) @"E:\huaihaiProject\readCard\ThCardReader\ThCardReader\bin\Debug\HeaSecReadInfo.dll", @"E:\huaihaiProject\readCard\ThCardReader\bin\Debug\HeaSecReadInfo.dll" }; string sourcePath = null; foreach (string path in possiblePaths) { if (File.Exists(path)) { sourcePath = path; break; } } if (sourcePath != null) { // 复制DLL文件到程序目录 File.Copy(sourcePath, targetDllPath, true); result["success"] = true; result["code"] = 200; result["message"] = "HeaSecReadInfo.dll文件已复制到位"; result["device"] = "江苏医保社保卡读卡器"; result["data"] = new JObject { ["sourcePath"] = sourcePath, ["targetPath"] = targetDllPath }; } else { result["success"] = false; result["code"] = 8001; result["message"] = "找不到HeaSecReadInfo.dll文件"; result["device"] = "江苏医保社保卡读卡器"; result["data"] = new JObject { ["searchedPaths"] = string.Join("; ", possiblePaths), ["programDirectory"] = programDir, ["suggestion"] = "请确保HeaSecReadInfo.dll文件在程序目录或bin/Debug目录中" }; } } catch (Exception ex) { result["success"] = false; result["code"] = 8002; result["message"] = $"DLL文件检查异常: {ex.Message}"; result["device"] = "江苏医保社保卡读卡器"; result["exception"] = ex.GetType().Name; } return result; } /// /// 检查DLL文件是否存在并可访问 /// /// 检查结果 public static JObject CheckDllExists() { var result = new JObject(); try { // 检查程序目录下的DLL文件 string programDir = AppDomain.CurrentDomain.BaseDirectory; string dllPath = Path.Combine(programDir, "HeaSecReadInfo.dll"); if (File.Exists(dllPath)) { FileInfo fileInfo = new FileInfo(dllPath); result["success"] = true; result["code"] = 200; result["message"] = "HeaSecReadInfo.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"] = "HeaSecReadInfo.dll文件不存在"; result["device"] = "江苏医保社保卡读卡器"; result["data"] = new JObject { ["expectedPath"] = dllPath, ["programDirectory"] = programDir, ["suggestion"] = "请将HeaSecReadInfo.dll文件复制到程序目录" }; } } catch (Exception ex) { result["success"] = false; result["code"] = 8002; result["message"] = $"DLL文件检查异常: {ex.Message}"; result["device"] = "江苏医保社保卡读卡器"; result["exception"] = ex.GetType().Name; } return result; } /// /// 诊断读卡器硬件和社保卡状态 /// /// 诊断结果 public static JObject DiagnoseCardReader() { var result = new JObject(); try { result["device"] = "江苏医保社保卡读卡器"; result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); var diagnostics = new JObject(); // 1. 检查DLL状态 var dllCheck = CheckDllExists(); diagnostics["dllStatus"] = dllCheck; // 2. 检查初始化状态 diagnostics["initStatus"] = new JObject { ["isInitialized"] = isInitialized, ["hasConfig"] = currentConfig != null, ["configDetails"] = currentConfig?.ToJson() ?? "未配置" }; // 3. 尝试不同的读卡配置 var cardTests = new JObject(); // 测试无PIN模式 try { var config = new JiangSuConfig(); config.CARD_PASSTYPE = "2"; // 验证数据库密码(跳过PIN) var initResult = Initialize(config); var readResult = ReadSocialCard(false); // 不验证PIN cardTests["noPinTest"] = new JObject { ["config"] = "CARD_PASSTYPE=2(跳过PIN验证)", ["initResult"] = initResult, ["readResult"] = readResult }; } catch (Exception ex) { cardTests["noPinTest"] = new JObject { ["config"] = "CARD_PASSTYPE=2(跳过PIN验证)", ["error"] = ex.Message }; } // 测试PIN模式 try { var config = new JiangSuConfig(); config.CARD_PASSTYPE = "1"; // 验证卡PIN var initResult = Initialize(config); var readResult = ReadSocialCard(false); // 不自动验证PIN cardTests["pinTest"] = new JObject { ["config"] = "CARD_PASSTYPE=1(需要PIN验证)", ["initResult"] = initResult, ["readResult"] = readResult }; } catch (Exception ex) { cardTests["pinTest"] = new JObject { ["config"] = "CARD_PASSTYPE=1(需要PIN验证)", ["error"] = ex.Message }; } diagnostics["cardTests"] = cardTests; // 4. 分析结果 var analysis = new JObject(); analysis["recommendations"] = new JArray(); // 检查是否有成功的读卡 bool hasSuccessfulRead = false; if (cardTests["noPinTest"] != null && cardTests["noPinTest"]["readResult"] != null) { var noPinResult = (JObject)cardTests["noPinTest"]["readResult"]; if (noPinResult["success"] != null && (bool)noPinResult["success"]) { hasSuccessfulRead = true; ((JArray)analysis["recommendations"]).Add("✅ 使用CARD_PASSTYPE=2可以成功读卡"); } else if (noPinResult["errorCode"] != null) { int errorCode = (int)noPinResult["errorCode"]; if (errorCode == -11) { ((JArray)analysis["recommendations"]).Add("⚠️ 错误码-11:请检查社保卡是否正确插入并接触良好"); } } } if (cardTests["pinTest"] != null && cardTests["pinTest"]["readResult"] != null) { var pinResult = (JObject)cardTests["pinTest"]["readResult"]; if (pinResult["success"] != null && (bool)pinResult["success"]) { hasSuccessfulRead = true; ((JArray)analysis["recommendations"]).Add("✅ 使用CARD_PASSTYPE=1可以成功读卡"); } } if (!hasSuccessfulRead) { ((JArray)analysis["recommendations"]).Add("❌ 两种模式都无法读卡,可能的原因:"); ((JArray)analysis["recommendations"]).Add(" 1. 社保卡未正确插入或损坏"); ((JArray)analysis["recommendations"]).Add(" 2. 读卡器硬件故障或驱动问题"); ((JArray)analysis["recommendations"]).Add(" 3. 网络配置参数错误"); ((JArray)analysis["recommendations"]).Add(" 4. DLL文件版本不匹配"); } analysis["overallStatus"] = hasSuccessfulRead ? "正常" : "异常"; diagnostics["analysis"] = analysis; result["success"] = true; result["code"] = 200; result["message"] = "读卡器诊断完成"; result["data"] = diagnostics; } catch (Exception ex) { result["success"] = false; result["code"] = 9001; result["message"] = $"读卡器诊断异常: {ex.Message}"; result["device"] = "江苏医保社保卡读卡器"; result["exception"] = ex.GetType().Name; } return result; } /// /// 离线模式读取社保卡(跳过网络验证,仅测试本地读卡功能) /// /// 读卡结果 public static JObject ReadSocialCardOffline() { var result = new JObject(); try { // 使用最简配置进行本地测试 var offlineConfig = new JiangSuConfig(); offlineConfig.IP = "127.0.0.1"; // 本地IP offlineConfig.PORT = 8080; // 本地端口 offlineConfig.EC_URL = ""; // 空URL跳过网络验证 offlineConfig.ACCESS_KEY = ""; // 空密钥 offlineConfig.SECRETKEY = ""; // 空密钥 // 构造最简初始化参数 var simpleConfig = new { IP = "127.0.0.1", PORT = 8080, TIMEOUT = 5, LOG_PATH = offlineConfig.LOG_PATH, CARD_PASSTYPE = "2", // 跳过PIN验证 EC_URL = "", API_NAME = "", API_VERSION = "", ACCESS_KEY = "", SECRETKEY = "", ORG_ID = "", EXT = "{}", AREA_CODE = "" }; string initJson = JsonConvert.SerializeObject(simpleConfig, Formatting.None); StringBuilder errMsg = new StringBuilder(2048); // 尝试离线初始化 int initResult = Init(initJson, errMsg); if (initResult == 0) { // 初始化成功,尝试读卡 isInitialized = true; currentConfig = offlineConfig; StringBuilder cardInfo = new StringBuilder(2048); StringBuilder busiCardInfo = new StringBuilder(8192); int readResult = ReadCardBas(cardInfo, busiCardInfo); if (readResult == 0) { string rawCardData = cardInfo.ToString(); string rawBusiData = busiCardInfo.ToString(); var parsedData = Parse38DocumentFormat(rawCardData, rawBusiData); result["success"] = true; result["code"] = 200; result["message"] = "离线模式读卡成功"; result["device"] = "江苏医保社保卡读卡器(离线模式)"; result["data"] = parsedData; result["mode"] = "offline"; result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); result["dllErrorMsg"] = ""; // 成功时错误信息为空 // 添加原始读卡数据 result["rawCardData"] = rawCardData; result["rawBusiData"] = rawBusiData; } else { result["success"] = false; result["code"] = 2000 + readResult; result["message"] = $"离线模式读卡失败,错误码: {readResult}"; result["device"] = "江苏医保社保卡读卡器(离线模式)"; result["mode"] = "offline"; result["errorCode"] = readResult; result["dllErrorMsg"] = ""; // 读卡失败,但初始化成功 // 读卡失败时也记录原始数据(可能为空) result["rawCardData"] = cardInfo.ToString(); result["rawBusiData"] = busiCardInfo.ToString(); if (readResult == -11) { result["suggestion"] = "请检查社保卡是否正确插入读卡器"; } else if (readResult == -1) { result["suggestion"] = "读卡器硬件可能未正确连接或驱动问题"; } } } else { string errorMsg = errMsg.ToString(); result["success"] = false; result["code"] = 1000 + initResult; result["message"] = $"离线模式初始化失败: {errorMsg}"; result["device"] = "江苏医保社保卡读卡器(离线模式)"; result["mode"] = "offline"; result["errorCode"] = initResult; result["dllErrorMsg"] = errorMsg; // 原始DLL错误信息 } } catch (Exception ex) { result["success"] = false; result["code"] = 9999; result["message"] = $"离线模式异常: {ex.Message}"; result["device"] = "江苏医保社保卡读卡器(离线模式)"; result["mode"] = "offline"; result["exception"] = ex.GetType().Name; result["dllErrorMsg"] = $"离线模式异常: {ex.Message}"; // 异常时的错误信息 } return result; } /// /// 测试不同网络配置对初始化的影响 /// /// 测试结果 public static JObject TestNetworkConfigurations() { var result = new JObject(); var tests = new JObject(); try { // 测试1:使用原始配置(10.61.165.3:8086) var config1 = new JiangSuConfig(); config1.IP = "10.61.165.3"; config1.PORT = 8086; config1.EC_URL = "http://10.61.165.3:8086/localcfc/api/hsecfc/localQrCodeQuery"; var test1 = TestSingleConfig(config1, "原始配置(10.61.165.3:8086)"); tests["originalConfig"] = test1; // 测试2:使用HSM配置(10.79.157.29:8089) var config2 = new JiangSuConfig(); config2.IP = "10.79.157.29"; config2.PORT = 8089; config2.EC_URL = "http://10.79.157.29:8089/encryptionMachine/encryptionMachineBusiness"; var test2 = TestSingleConfig(config2, "HSM配置(10.79.157.29:8089)"); tests["hsmConfig"] = test2; // 测试3:使用无效配置 var config3 = new JiangSuConfig(); config3.IP = "192.168.1.1"; config3.PORT = 9999; config3.EC_URL = "http://192.168.1.1:9999/invalid"; var test3 = TestSingleConfig(config3, "无效配置(192.168.1.1:9999)"); tests["invalidConfig"] = test3; // 测试4:空配置 var config4 = new JiangSuConfig(); config4.IP = ""; config4.PORT = 0; config4.EC_URL = ""; config4.ACCESS_KEY = ""; config4.SECRETKEY = ""; var test4 = TestSingleConfig(config4, "空配置"); tests["emptyConfig"] = test4; result["success"] = true; result["code"] = 200; result["message"] = "网络配置测试完成"; result["tests"] = tests; result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); // 分析结果 var analysis = new JArray(); foreach (var test in tests) { var testResult = (JObject)test.Value; var errorCode = testResult["errorCode"]?.ToString() ?? "无"; var config = testResult["configName"]?.ToString() ?? "未知"; analysis.Add($"{config}: 错误码 {errorCode}"); } result["analysis"] = analysis; } catch (Exception ex) { result["success"] = false; result["code"] = 9001; result["message"] = $"网络配置测试异常: {ex.Message}"; result["exception"] = ex.GetType().Name; } return result; } /// /// 测试单个配置 /// private static JObject TestSingleConfig(JiangSuConfig config, string configName) { var testResult = new JObject(); testResult["configName"] = configName; testResult["config"] = JObject.Parse(config.ToJson()); try { string initJson = config.ToJson(); StringBuilder errMsg = new StringBuilder(2048); int initResult = Init(initJson, errMsg); testResult["initResult"] = initResult; testResult["errorMessage"] = errMsg.ToString(); testResult["errorCode"] = initResult; testResult["dllErrorMsg"] = errMsg.ToString(); // 原始DLL错误信息 if (initResult == 0) { testResult["status"] = "初始化成功"; // 如果初始化成功,尝试读卡 StringBuilder cardInfo = new StringBuilder(2048); StringBuilder busiCardInfo = new StringBuilder(8192); int readResult = ReadCardBas(cardInfo, busiCardInfo); testResult["readResult"] = readResult; testResult["readStatus"] = readResult == 0 ? "读卡成功" : $"读卡失败,错误码: {readResult}"; } else { testResult["status"] = $"初始化失败,错误码: {initResult}"; } } catch (Exception ex) { testResult["status"] = "测试异常"; testResult["error"] = ex.Message; testResult["errorCode"] = -999; testResult["dllErrorMsg"] = $"测试异常: {ex.Message}"; // 异常时的错误信息 } return testResult; } #endregion #region 电子凭证解码功能 (按照江苏医保接口规范v0.9.9.15实现) /// /// 江苏医保电子凭证解码 /// 严格按照《医疗保障信息平台定点基线版医药机构接口规范 v0.9.9.15》中的1.14.6电子凭证解码接口实现 /// /// 用码业务类型,如:01101-门诊挂号,01301-门诊结算,02121-药店购药 /// 收款员编号 /// 收款员姓名 /// 医保科室编号 /// 科室名称 /// 电子凭证解码结果 public static JObject ReadElectronicCertificate(string businessType = "01101", string operatorId = "system001", string operatorName = "系统管理员", string officeId = "32760", string officeName = "医保科") { var result = new JObject(); try { // 检查初始化状态 if (!isInitialized) { // 自动初始化 var autoInitResult = Initialize(); if (!(bool)autoInitResult["success"]) { result["success"] = false; result["code"] = 1002; result["message"] = "江苏医保系统未初始化,电子凭证解码失败"; result["device"] = "江苏医保电子凭证解码器"; result["autoInitError"] = autoInitResult["message"]; result["type"] = "qrcode"; return result; } } // 获取当前配置 if (currentConfig == null) { result["success"] = false; result["code"] = 1003; result["message"] = "江苏医保配置信息为空"; result["device"] = "江苏医保电子凭证解码器"; result["type"] = "qrcode"; return result; } // 按照江苏医保接口规范1.14.6构造输入参数 var inputData = new { data = new { orgId = currentConfig.ORG_ID, // 定点编号 businessType = businessType, // 用码业务类型 operatorId = operatorId, // 收款员编号 operatorName = operatorName, // 收款员姓名 officeId = officeId, // 医保科室编号 officeName = officeName // 科室名称 }, transType = "ec.query", // 固定值:ec.query orgId = currentConfig.ORG_ID // 定点编号 }; // JSON序列化输入参数 string jsonInput = JsonConvert.SerializeObject(inputData, Formatting.None); // 按照规范分配8192字节输出缓冲区 StringBuilder outputBuffer = new StringBuilder(8192); // 调用江苏医保DLL的EcQuery函数 int dllResult = EcQuery(jsonInput, outputBuffer); if (dllResult == 0) { // 解析DLL返回的JSON数据 string responseJson = outputBuffer.ToString(); if (string.IsNullOrEmpty(responseJson)) { result["success"] = false; result["code"] = 1004; result["message"] = "电子凭证解码返回数据为空"; result["device"] = "江苏医保电子凭证解码器"; result["type"] = "qrcode"; return result; } // 解析江苏医保返回的JSON数据 var jiangsuResponse = JObject.Parse(responseJson); // 检查江苏医保接口返回的code字段 int responseCode = (int)(jiangsuResponse["code"] ?? -1); if (responseCode == 0) { // 成功:提取患者信息 var patientData = jiangsuResponse["data"]; if (patientData != null) { result["success"] = true; result["code"] = 200; result["message"] = "江苏医保电子凭证解码成功"; result["device"] = "江苏医保电子凭证解码器"; result["type"] = "qrcode"; result["originalType"] = "jiangsu_ec"; result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); // 按照文档规范提取患者信息 var patientInfo = new { idNo = patientData["idNo"]?.ToString() ?? "", // 身份证号 userName = patientData["userName"]?.ToString() ?? "", // 姓名 idType = patientData["idType"]?.ToString() ?? "", // 证件类型 ecToken = patientData["ecToken"]?.ToString() ?? "", // 令牌 insuOrg = patientData["insuOrg"]?.ToString() ?? "", // 参保地区编码 ecIndexNo = patientData["ecIndexNo"]?.ToString() ?? "", // 电子凭证索引号 gender = patientData["gender"]?.ToString() ?? "", // 性别 birthday = patientData["birthday"]?.ToString() ?? "", // 出生日期 nationality = patientData["nationality"]?.ToString() ?? "", // 国籍 email = patientData["email"]?.ToString() ?? "", // 邮箱 extra = patientData["extra"]?.ToString() ?? "" // 扩展参数 }; // 按照泰和医院格式构造data字段(包含code/data/message结构) var dllResponseFormat = new { code = 0, data = patientInfo, message = "交易成功" }; result["data"] = JsonConvert.SerializeObject(dllResponseFormat); // 保存原始江苏医保返回数据(用于调试和日志) result["jiangsuOriginalData"] = responseJson; result["businessType"] = businessType; result["interfaceVersion"] = "v0.9.9.15"; // 添加兼容字段(与前端保持一致,采用泰和医院格式) result["readCardResult"] = JsonConvert.SerializeObject(dllResponseFormat); } else { result["success"] = false; result["code"] = 1005; result["message"] = "电子凭证解码成功,但患者数据为空"; result["device"] = "江苏医保电子凭证解码器"; result["type"] = "qrcode"; result["jiangsuOriginalData"] = responseJson; } } else { // 江苏医保接口返回失败 string errorMessage = jiangsuResponse["message"]?.ToString() ?? "电子凭证解码失败"; result["success"] = false; result["code"] = 2000 + responseCode; // 使用2xxx系列表示江苏医保接口错误 result["message"] = $"江苏医保电子凭证解码失败: {errorMessage}"; result["device"] = "江苏医保电子凭证解码器"; result["type"] = "qrcode"; result["jiangsuErrorCode"] = responseCode; result["jiangsuErrorMessage"] = errorMessage; result["jiangsuOriginalData"] = responseJson; result["businessType"] = businessType; } } else { // DLL函数调用失败 string errorInfo = outputBuffer.ToString(); result["success"] = false; result["code"] = 3000 + dllResult; // 使用3xxx系列表示DLL调用错误 result["message"] = $"江苏医保DLL调用失败,错误码: {dllResult}"; result["device"] = "江苏医保电子凭证解码器"; result["type"] = "qrcode"; result["dllErrorCode"] = dllResult; result["dllErrorMessage"] = errorInfo; result["businessType"] = businessType; result["suggestion"] = GetEcQueryErrorSuggestion(dllResult); } } catch (JsonException jsonEx) { result["success"] = false; result["code"] = 1006; result["message"] = $"电子凭证解码数据解析异常: {jsonEx.Message}"; result["device"] = "江苏医保电子凭证解码器"; result["type"] = "qrcode"; result["exception"] = jsonEx.GetType().Name; result["businessType"] = businessType; } catch (Exception ex) { result["success"] = false; result["code"] = 1007; result["message"] = $"电子凭证解码系统异常: {ex.Message}"; result["device"] = "江苏医保电子凭证解码器"; result["type"] = "qrcode"; result["exception"] = ex.GetType().Name; result["businessType"] = businessType; } return result; } /// /// 根据业务场景获取科室名称 /// /// 业务类型代码 /// 科室名称 private static string GetDepartmentNameByBusinessType(string businessType) { switch (businessType) { case "01101": // 门诊挂号 return "挂号处"; case "01201": // 门诊问诊 case "01202": // 预约检查 case "01203": // 检查 case "01204": // 治疗 return "门诊科室"; case "01301": // 门诊结算 return "门诊收费处"; case "01302": // 取药 return "门诊药房"; case "01102": // 住院建档 case "01103": // 入院登记 case "01104": // 缴纳预缴金 return "住院处"; case "02121": // 药店购药 case "02122": // 下载外购处方 return "药店"; default: return "医保科"; } } /// /// 获取EcQuery错误码对应的建议 /// /// 错误码 /// 错误建议 private static string GetEcQueryErrorSuggestion(int errorCode) { switch (errorCode) { case -1: return "网络连接失败,请检查网络连接和医保平台服务状态"; case -2: return "身份认证失败,请检查ACCESS_KEY和SECRET_KEY配置"; case -3: return "参数格式错误,请检查业务类型和定点编号配置"; case -4: return "电子凭证已过期,请提示患者刷新电子凭证"; case -5: return "参保地不匹配,请确认患者参保地信息"; default: return "电子凭证解码失败,请检查设备连接和配置信息"; } } /// /// 验证业务类型代码是否有效 /// /// 业务类型代码 /// 是否有效 public static bool IsValidBusinessType(string businessType) { if (string.IsNullOrEmpty(businessType) || businessType.Length != 5) return false; // 按照江苏医保规范检查业务类型 string[] validTypes = { // 医院业务类型 "01101", "01102", "01103", "01104", // 挂号、住院建档、入院登记、缴纳预缴金 "01201", "01202", "01203", "01204", // 问诊、预约检查、检查、治疗 "01301", "01302", "01303", "01304", "01305", // 结算、取药、取报告、打印票据和清单、病历材料复印 // 药店业务类型 "02121", "02122" // 药店购药、下载外购处方 }; return validTypes.Contains(businessType); } #endregion #region 数据解析方法 /// /// 解析38号文格式的社保卡数据 /// /// 卡基本信息 /// 业务信息 /// 解析后的数据 private static JObject Parse38DocumentFormat(string cardData, string busiData) { var result = new JObject(); try { // 按照38号文格式解析,使用管道符"|"分隔 string[] cardFields = cardData.Split('|'); if (cardFields.Length >= 11) { result["areaCode"] = cardFields[0]; // 发卡地区行政区划代码 result["socialSecurityNumber"] = cardFields[1]; // 社会保障号码 result["cardNumber"] = cardFields[2]; // 卡号 result["cardId"] = cardFields[3]; // 卡识别码 result["name"] = cardFields[4]; // 姓名 result["cardResetInfo"] = cardFields[5]; // 卡复位信息 result["specVersion"] = cardFields[6]; // 规范版本 result["issueDate"] = FormatDate(cardFields[7]); // 发卡日期 result["expireDate"] = FormatDate(cardFields[8]); // 卡有效期 result["terminalNumber"] = cardFields[9]; // 终端机编号 result["terminalDevice"] = cardFields[10]; // 终端设备号 } // 解析业务信息(如果有) if (!string.IsNullOrEmpty(busiData)) { result["businessInfo"] = busiData; } result["format"] = "38号文标准格式"; result["parseTime"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); } catch (Exception ex) { result["error"] = $"数据解析失败: {ex.Message}"; } return result; } /// /// 解析四合一介质的个人信息 /// /// 响应数据 /// 介质类型 /// 解析后的个人信息 private static JObject ParsePersonInfo(string responseData, string mediaType) { var result = new JObject(); try { // 尝试解析JSON格式的响应 if (responseData.StartsWith("{")) { var jsonData = JObject.Parse(responseData); result = jsonData; } else { // 如果不是JSON,按不同介质类型解析 switch (mediaType.ToLower()) { case "socialcard": // 社保卡:按38号文格式解析 result = Parse38DocumentFormat(responseData, ""); break; case "idcard": // 身份证:按身份证格式解析 string[] idFields = responseData.Split('|'); if (idFields.Length >= 8) { result["idNumber"] = idFields[0]; result["name"] = idFields[1]; result["sex"] = idFields[2]; result["nation"] = idFields[3]; result["birthday"] = FormatDate(idFields[4]); result["address"] = idFields[5]; result["issueDate"] = FormatDate(idFields[6]); result["validDate"] = FormatDate(idFields[7]); } break; case "electronic": case "esocialcard": // 电子凭证/电子社保卡:通常为JSON格式 result["rawData"] = responseData; break; default: result["rawData"] = responseData; break; } } result["mediaType"] = mediaType; result["parseTime"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); } catch (Exception ex) { result["error"] = $"个人信息解析失败: {ex.Message}"; result["rawData"] = responseData; } return result; } /// /// 格式化日期字符串 /// /// 原始日期字符串 /// 格式化后的日期 private static string FormatDate(string dateStr) { if (string.IsNullOrEmpty(dateStr) || dateStr.Length < 8) return dateStr; // 尝试格式化YYYYMMDD为YYYY-MM-DD if (dateStr.Length == 8 && dateStr.All(char.IsDigit)) { return $"{dateStr.Substring(0, 4)}-{dateStr.Substring(4, 2)}-{dateStr.Substring(6, 2)}"; } return dateStr; } #endregion #region 江苏医保刷脸功能 (使用NationECCode.dll与泰和完全一致) /// /// 江苏医保刷脸功能 - 使用NationECCode.dll与泰和完全一致 /// 完全相同的实现:相同的DLL、相同的URL、相同的逻辑、相同的参数格式 /// 唯一区别:使用写死的配置参数 /// /// 业务类型 /// 刷脸结果 public static JObject ReadFace(string biztype) { JObject result = new JObject(); try { // 使用写死的江苏医保刷脸配置参数 if (null == currentConfig) { currentConfig = new JiangSuConfig(); } // 第一步:获取授权码(cn.nhsa.ec.auth) // 补全所有参数,即使为空也带上 var data = new { businessType = biztype, deviceType = "", orgId = currentConfig.FACE_ORG_ID, outBizNo = "", operatorId = "", operatorName = "", officeId = "", officeName = "" }; var authRequest = new { data = data, orgId = currentConfig.FACE_ORG_ID, transType = "cn.nhsa.ec.auth" }; string pindata = JsonConvert.SerializeObject(authRequest, Formatting.None); byte[] outinfo = new byte[4096]; IntPtr retPtr = NationEcTrans(currentConfig.FACE_SERVICE_URL, pindata, ref outinfo[0]); string businessResultCode = Marshal.PtrToStringAnsi(retPtr).Trim().Replace("\u0000", ""); string outstr = Encoding.Default.GetString(outinfo).Trim().Replace("\u0000", ""); // 检查DLL调用是否成功 if (businessResultCode != "0000") { result.Add("code", 1001); result.Add("message", $"DLL调用失败,返回码: {businessResultCode}"); result.Add("type", "face"); result.Add("device", "江苏医保刷脸认证器(NationECCode.dll)"); result.Add("businessType", biztype); result.Add("timestamp", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); result.Add("interfaceVersion", "江苏医保刷脸v1.0(与泰和完全一致)"); result.Add("dllReturnCode", businessResultCode); result.Add("dllRawResponse", outstr); return result; } ReadCardResult tmp = Newtonsoft.Json.JsonConvert.DeserializeObject(outstr); if (tmp.code == 0) { FaceAuthData authData = Newtonsoft.Json.JsonConvert.DeserializeObject(tmp.data.ToString()); return getUserInfoByAuthNo(biztype, authData.authNo); } else { result.Add("code", 1001); result.Add("message", tmp.message ?? "刷脸授权获取失败"); result.Add("type", "face"); result.Add("device", "江苏医保刷脸认证器(NationECCode.dll)"); result.Add("businessType", biztype); result.Add("timestamp", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); result.Add("interfaceVersion", "江苏医保刷脸v1.0(与泰和完全一致)"); result.Add("dllReturnCode", businessResultCode); result.Add("dllRawResponse", outstr); result.Add("authStep", "第一步:获取授权码失败"); return result; } } catch (Exception ex) { result.Add("code", 1001); result.Add("message", $"江苏医保刷脸操作异常: {ex.Message}"); result.Add("type", "face"); result.Add("device", "江苏医保刷脸认证器(NationECCode.dll)"); result.Add("businessType", biztype); result.Add("timestamp", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); result.Add("interfaceVersion", "江苏医保刷脸v1.0(与泰和完全一致)"); result.Add("exception", ex.GetType().Name); result.Add("exceptionMessage", ex.Message); return result; } } /// /// 根据authNo获取用户信息 - 使用NationECCode.dll与泰和完全一致 /// /// 业务类型 /// 认证号 /// 用户信息 private static JObject getUserInfoByAuthNo(string biztype, string authNo) { JObject result = new JObject(); try { // 使用写死的江苏医保刷脸配置参数 if (null == currentConfig) { currentConfig = new JiangSuConfig(); } // 第二步:根据authNo获取医保身份(cn.nhsa.auth.check) // 补全所有参数,即使为空也带上 var data = new { businessType = biztype, authNo = authNo, deviceType = "", orgId = currentConfig.FACE_ORG_ID, outBizNo = "", operatorId = "", operatorName = "", officeId = "", officeName = "" }; var checkRequest = new { data = data, orgId = currentConfig.FACE_ORG_ID, transType = "cn.nhsa.auth.check" }; string pindata = JsonConvert.SerializeObject(checkRequest, Formatting.None); byte[] outinfo = new byte[4096]; IntPtr retPtr = NationEcTrans(currentConfig.FACE_SERVICE_URL, pindata, ref outinfo[0]); string businessResultCode = Marshal.PtrToStringAnsi(retPtr).Trim().Replace("\u0000", ""); string outstr = Encoding.Default.GetString(outinfo).Trim().Replace("\u0000", ""); ReadCardResult tmp = Newtonsoft.Json.JsonConvert.DeserializeObject(outstr); if (tmp.code == 0) { result.Add("code", 200); result.Add("message", "刷脸获取医保身份成功。"); result.Add("type", "face"); result.Add("data", outstr); result.Add("sign", null); } else { result.Add("code", 1001); result.Add("message", tmp.message ?? "获取医保身份失败"); } } catch (Exception ex) { result.Add("code", 1001); result.Add("message", $"获取医保身份异常: {ex.Message}"); } return result; } #endregion } }