using System; 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 - 仅包含核心必需函数 // 1.14.1 初始化 [DllImport("HeaSecReadInfo.dll", EntryPoint = "Init", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] private extern static Int32 Init(string pInitInfo, StringBuilder pErrMsg); // 1.14.2 读社保卡基本信息 [DllImport("HeaSecReadInfo.dll", EntryPoint = "ReadCardBas", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] private extern static Int32 ReadCardBas(StringBuilder pCardInfo, StringBuilder pBusiCardInfo); // 1.14.3 检验PIN码 [DllImport("HeaSecReadInfo.dll", EntryPoint = "VerifyPIN", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] private extern static Int32 VerifyPIN(StringBuilder pOutBuff); // 1.14.4 修改PIN码 [DllImport("HeaSecReadInfo.dll", EntryPoint = "ChangePIN", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] private extern static Int32 ChangePIN(StringBuilder pOutBuff); // 1.14.8 四合一介质获得个人信息 [DllImport("HeaSecReadInfo.dll", EntryPoint = "GetPersonInfo", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] private extern static Int32 GetPersonInfo(string pInData, StringBuilder pOutData); // 注意:已移除不存在的Close函数和其他非核心函数 // 如需要其他功能,可根据实际DLL文件情况后续添加 #endregion #region 配置和状态 private static bool isInitialized = false; private static JiangSuConfig currentConfig = null; public class JiangSuConfig { public string IP { get; set; } = "192.168.100.100"; public int PORT { get; set; } = 8080; public int TIMEOUT { get; set; } = 120; public string LOG_PATH { get; set; } = "C:\\logs\\jiangsu\\"; public string CARD_PASSTYPE { get; set; } = "1"; public string EC_URL { get; set; } = "https://fuwu-test.nhsa.gov.cn/localcfc/api/hsecfc/localQrCodeQuery"; public string API_NAME { get; set; } = "api-powersi-test-pri"; public string API_VERSION { get; set; } = "1.0.0"; public string ACCESS_KEY { get; set; } = ""; public string SECRETKEY { get; set; } = ""; public string ORG_ID { get; set; } = ""; public string AREA_CODE { get; set; } = "320100"; public string EXT { get; set; } = ""; public string ToJson() { return JsonConvert.SerializeObject(this, Formatting.None); } } #endregion #region 核心业务方法 /// /// 初始化江苏医保社保卡读取系统 /// 参考华视读卡器的初始化流程 /// public static JObject Initialize(JiangSuConfig config = null) { var result = new JObject(); try { // 使用默认配置或传入的配置 if (config == null) { config = new JiangSuConfig(); } // 构造初始化JSON参数 string initJson = config.ToJson(); StringBuilder errMsg = new StringBuilder(2048); // 调用DLL初始化函数 int initResult = Init(initJson, errMsg); if (initResult == 0) { isInitialized = true; currentConfig = config; result["code"] = 200; result["message"] = "江苏医保社保卡系统初始化成功"; result["device"] = "江苏医保社保卡读卡器"; result["config"] = JObject.FromObject(config); result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); } else { string errorMsg = errMsg.ToString(); result["code"] = 1000 + initResult; result["message"] = $"江苏医保系统初始化失败: {errorMsg}"; result["device"] = "江苏医保社保卡读卡器"; result["errorCode"] = initResult; } } catch (Exception ex) { result["code"] = 1001; result["message"] = $"江苏医保系统初始化异常: {ex.Message}"; result["device"] = "江苏医保社保卡读卡器"; result["exception"] = ex.GetType().Name; } return result; } /// /// 读取社保卡基本信息 /// 返回标准38号文格式数据 /// public static JObject ReadSocialCard(bool autoVerifyPIN = false) { var result = new JObject(); try { // 检查初始化状态 if (!isInitialized) { result["code"] = 1002; result["message"] = "江苏医保系统未初始化,请先调用初始化接口"; result["device"] = "江苏医保社保卡读卡器"; return result; } // 如果需要自动验证PIN码 if (autoVerifyPIN) { var pinResult = VerifyCardPIN(); if ((int)pinResult["code"] != 200) { 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["code"] = 200; result["message"] = "社保卡读取成功"; result["device"] = "江苏医保社保卡读卡器"; result["data"] = parsedData; result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); } else { result["code"] = 2000 + readResult; result["message"] = $"社保卡读取失败,错误码: {readResult}"; result["device"] = "江苏医保社保卡读卡器"; result["errorCode"] = readResult; } } catch (Exception ex) { result["code"] = 2001; result["message"] = $"社保卡读取异常: {ex.Message}"; result["device"] = "江苏医保社保卡读卡器"; result["exception"] = ex.GetType().Name; } return result; } /// /// 验证社保卡PIN码 /// public static JObject VerifyCardPIN() { var result = new JObject(); try { if (!isInitialized) { result["code"] = 1002; result["message"] = "江苏医保系统未初始化"; return result; } StringBuilder outBuff = new StringBuilder(1024); int pinResult = VerifyPIN(outBuff); if (pinResult == 0) { result["code"] = 200; result["message"] = "PIN码验证成功"; result["device"] = "江苏医保社保卡读卡器"; } else { string errorMsg = outBuff.ToString(); result["code"] = 3000 + pinResult; result["message"] = $"PIN码验证失败: {errorMsg}"; result["device"] = "江苏医保社保卡读卡器"; result["errorCode"] = pinResult; } } catch (Exception ex) { result["code"] = 3001; result["message"] = $"PIN码验证异常: {ex.Message}"; result["device"] = "江苏医保社保卡读卡器"; } return result; } /// /// 修改社保卡PIN码 /// public static JObject ChangeCardPIN() { var result = new JObject(); try { if (!isInitialized) { result["code"] = 1002; result["message"] = "江苏医保系统未初始化"; return result; } StringBuilder outBuff = new StringBuilder(1024); int changeResult = ChangePIN(outBuff); if (changeResult == 0) { result["code"] = 200; result["message"] = "PIN码修改成功"; result["device"] = "江苏医保社保卡读卡器"; } else { string errorMsg = outBuff.ToString(); result["code"] = 4000 + changeResult; result["message"] = $"PIN码修改失败: {errorMsg}"; result["device"] = "江苏医保社保卡读卡器"; result["errorCode"] = changeResult; } } catch (Exception ex) { result["code"] = 4001; result["message"] = $"PIN码修改异常: {ex.Message}"; result["device"] = "江苏医保社保卡读卡器"; } return result; } /// /// 四合一介质支持 - 获取个人信息 /// 按照官方规范1.14.8实现,支持:社保卡、电子凭证、电子社保卡、身份证 /// public static JObject GetPersonInfo(string mediaType = "socialcard", string inputData = "") { var result = new JObject(); try { if (!isInitialized) { result["code"] = 1002; result["message"] = "江苏医保系统未初始化"; return result; } // 按照官方规范1.14.8.4构造输入参数JSON string jsonInput = ""; if (!string.IsNullOrEmpty(inputData)) { // 使用提供的输入数据 jsonInput = inputData; } else { // 构造默认的输入参数 var defaultInput = new JObject { ["data"] = new JObject { ["orgId"] = currentConfig?.ORG_ID ?? "", ["businessType"] = "01101", // 默认:医院挂号 ["operatorId"] = "test001", ["operatorName"] = "操作员", ["officeId"] = "32760", ["officeName"] = "医保科" }, ["transType"] = "ec.query", ["orgId"] = currentConfig?.ORG_ID ?? "" }; jsonInput = defaultInput.ToString(Formatting.None); } StringBuilder outData = new StringBuilder(8192); int getResult = GetPersonInfo(jsonInput, outData); if (getResult == 0) { string responseData = outData.ToString(); result["code"] = 200; result["message"] = "个人信息获取成功"; result["device"] = "江苏医保社保卡读卡器"; result["mediaType"] = mediaType; result["data"] = ParsePersonInfo(responseData, mediaType); result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); } else { result["code"] = 5000 + getResult; result["message"] = $"个人信息获取失败,错误码: {getResult}"; result["device"] = "江苏医保社保卡读卡器"; result["errorCode"] = getResult; } } catch (Exception ex) { result["code"] = 5001; result["message"] = $"个人信息获取异常: {ex.Message}"; result["device"] = "江苏医保社保卡读卡器"; } return result; } /// /// 获取设备状态 /// public static JObject GetDeviceStatus() { var result = new JObject(); try { result["code"] = 200; result["message"] = "设备状态正常"; result["device"] = "江苏医保社保卡读卡器"; result["status"] = new JObject { ["initialized"] = isInitialized, ["config"] = currentConfig != null ? JObject.FromObject(currentConfig) : null, ["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }; } catch (Exception ex) { result["code"] = 7001; result["message"] = $"获取设备状态异常: {ex.Message}"; result["device"] = "江苏医保社保卡读卡器"; } return result; } /// /// 重置系统内部状态 /// 注意:江苏医保接口规范中没有Close函数,此方法仅重置本地缓存的状态信息 /// public static JObject ResetSystemState() { var result = new JObject(); try { // 江苏医保接口规范中没有Close函数,仅重置内部状态 // 这里不调用任何DLL函数,只是清理本地状态 isInitialized = false; currentConfig = null; result["code"] = 200; result["message"] = "江苏医保系统内部状态已重置"; result["device"] = "江苏医保社保卡读卡器"; result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); result["note"] = "此操作仅重置本地状态缓存,不调用DLL关闭函数(规范中不存在)"; } catch (Exception ex) { result["code"] = 6001; result["message"] = $"状态重置异常: {ex.Message}"; result["device"] = "江苏医保社保卡读卡器"; } return result; } #endregion #region 数据解析方法 /// /// 解析38号文格式数据 /// 格式:发卡地区|社保号|卡号|卡识别码|姓名|复位信息|版本|发卡日期|有效期|终端机号|设备号| /// private static JObject Parse38DocumentFormat(string cardData, string busiData) { var result = new JObject(); try { if (string.IsNullOrEmpty(cardData)) { result["error"] = "卡片数据为空"; return result; } string[] parts = cardData.Split('|'); if (parts.Length >= 11) { result["region"] = "JiangSu"; result["issueArea"] = parts[0]; // 发卡地区 result["socialSecurityNumber"] = parts[1]; // 社保号 result["cardNumber"] = parts[2]; // 卡号 result["cardIdentifier"] = parts[3]; // 卡识别码 result["name"] = parts[4]; // 姓名 result["resetInfo"] = parts[5]; // 复位信息 result["version"] = parts[6]; // 版本 result["issueDate"] = FormatDate(parts[7]); // 发卡日期 result["validDate"] = FormatDate(parts[8]); // 有效期 result["terminalId"] = parts[9]; // 终端机号 result["deviceId"] = parts[10]; // 设备号 // 业务数据 result["busiCardInfo"] = busiData; result["rawData"] = cardData; // 提取身份证号(如果可能) result["idNumber"] = ExtractIdFromSSN(parts[1]); } else { result["error"] = $"数据格式不正确,期望11个字段,实际{parts.Length}个字段"; result["rawData"] = cardData; } } catch (Exception ex) { result["error"] = $"数据解析异常: {ex.Message}"; result["rawData"] = cardData; } return result; } /// /// 解析个人信息数据 /// 按照官方规范1.14.8不同介质的输出格式解析 /// private static JObject ParsePersonInfo(string responseData, string mediaType) { var result = new JObject(); try { // 首先尝试解析为JSON格式(官方规范要求的输出格式) try { var jsonData = JObject.Parse(responseData); // 检查是否有code字段表示成功 if (jsonData["code"] != null && jsonData["code"].Value() == 0) { var data = jsonData["data"]; if (data != null) { // 根据数据内容判断实际的介质类型 if (data["CardInfo"] != null && data["BusiCardInfo"] != null) { // 社保卡格式:包含CardInfo和BusiCardInfo result = Parse38DocumentFormat(data["CardInfo"].ToString(), data["BusiCardInfo"].ToString()); result["mediaType"] = "社保卡"; } else if (data["idNo"] != null && data["ecToken"] != null) { // 电子凭证格式:包含idNo和ecToken result["mediaType"] = "电子凭证"; result["idNo"] = data["idNo"]; result["userName"] = data["userName"]; result["idType"] = data["idType"]; result["ecToken"] = data["ecToken"]; result["insuOrg"] = data["insuOrg"]; result["ecIndexNo"] = data["ecIndexNo"]; result["gender"] = data["gender"]; result["birthday"] = data["birthday"]; result["nationality"] = data["nationality"]; result["email"] = data["email"]; result["extra"] = data["extra"]; } else if (data["si_no"] != null && data["ecCardToken"] != null) { // 电子社保卡格式:包含si_no和ecCardToken result["mediaType"] = "电子社保卡"; result["si_no"] = data["si_no"]; result["si_card_no"] = data["si_card_no"]; result["si_card_issue_area"] = data["si_card_issue_area"]; result["name"] = data["name"]; result["gender"] = data["gender"]; result["id_type"] = data["id_type"]; result["id_no"] = data["id_no"]; result["ecCardToken"] = data["ecCardToken"]; } else if (data["SFZInfo"] != null && data["BusiSFZInfo"] != null) { // 身份证格式:包含SFZInfo和BusiSFZInfo result["mediaType"] = "身份证"; result["SFZInfo"] = data["SFZInfo"]; result["BusiSFZInfo"] = data["BusiSFZInfo"]; // 解析身份证信息字符串 string[] sfzParts = data["SFZInfo"].ToString().Split('|'); if (sfzParts.Length >= 9) { result["idNumber"] = sfzParts[0]; result["name"] = sfzParts[1]; result["gender"] = sfzParts[2]; result["nation"] = sfzParts[3]; result["birthday"] = FormatDate(sfzParts[4]); result["address"] = sfzParts[5]; result["issueOrg"] = sfzParts[6]; result["validFrom"] = FormatDate(sfzParts[7]); result["validTo"] = FormatDate(sfzParts[8]); } } else { // 未知格式,保存原始数据 result["mediaType"] = "未知"; result["data"] = data; } } result["code"] = jsonData["code"]; result["message"] = jsonData["message"]; } else { // DLL返回错误 result["error"] = jsonData["message"]?.ToString() ?? "获取个人信息失败"; result["code"] = jsonData["code"]; } } catch (JsonException) { // 不是JSON格式,按照传统字符串格式处理 switch (mediaType.ToLower()) { case "socialcard": result = Parse38DocumentFormat(responseData, ""); result["mediaType"] = "社保卡"; break; default: result["mediaType"] = mediaType; result["rawData"] = responseData; break; } } result["rawData"] = responseData; } catch (Exception ex) { result["error"] = $"个人信息解析异常: {ex.Message}"; result["mediaType"] = mediaType; result["rawData"] = responseData; } return result; } /// /// 从社保号提取身份证号 /// private static string ExtractIdFromSSN(string ssn) { if (string.IsNullOrEmpty(ssn) || ssn.Length < 18) return ""; // 简单假设:如果社保号是18位,可能就是身份证号 if (ssn.Length == 18) return ssn; return ""; } /// /// 格式化日期 YYYYMMDD -> YYYY-MM-DD /// private static string FormatDate(string dateStr) { if (string.IsNullOrEmpty(dateStr) || dateStr.Length != 8) return dateStr; try { return $"{dateStr.Substring(0, 4)}-{dateStr.Substring(4, 2)}-{dateStr.Substring(6, 2)}"; } catch { return dateStr; } } #endregion } }