123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644 |
- using System;
- using System.Runtime.InteropServices;
- using System.Text;
- using Newtonsoft.Json;
- using Newtonsoft.Json.Linq;
- namespace ThCardReader
- {
- /// <summary>
- /// 江苏医保社保卡读取业务类
- /// 基于HeaSecReadInfo.dll作为主DLL,参考华视读卡器流程
- /// </summary>
- 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 核心业务方法
- /// <summary>
- /// 初始化江苏医保社保卡读取系统
- /// 参考华视读卡器的初始化流程
- /// </summary>
- 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;
- }
- /// <summary>
- /// 读取社保卡基本信息
- /// 返回标准38号文格式数据
- /// </summary>
- 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;
- }
- /// <summary>
- /// 验证社保卡PIN码
- /// </summary>
- 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;
- }
- /// <summary>
- /// 修改社保卡PIN码
- /// </summary>
- 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;
- }
- /// <summary>
- /// 四合一介质支持 - 获取个人信息
- /// 按照官方规范1.14.8实现,支持:社保卡、电子凭证、电子社保卡、身份证
- /// </summary>
- 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;
- }
- /// <summary>
- /// 获取设备状态
- /// </summary>
- 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;
- }
- /// <summary>
- /// 重置系统内部状态
- /// 注意:江苏医保接口规范中没有Close函数,此方法仅重置本地缓存的状态信息
- /// </summary>
- 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 数据解析方法
- /// <summary>
- /// 解析38号文格式数据
- /// 格式:发卡地区|社保号|卡号|卡识别码|姓名|复位信息|版本|发卡日期|有效期|终端机号|设备号|
- /// </summary>
- 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;
- }
- /// <summary>
- /// 解析个人信息数据
- /// 按照官方规范1.14.8不同介质的输出格式解析
- /// </summary>
- 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<int>() == 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;
- }
- /// <summary>
- /// 从社保号提取身份证号
- /// </summary>
- private static string ExtractIdFromSSN(string ssn)
- {
- if (string.IsNullOrEmpty(ssn) || ssn.Length < 18)
- return "";
- // 简单假设:如果社保号是18位,可能就是身份证号
- if (ssn.Length == 18)
- return ssn;
- return "";
- }
- /// <summary>
- /// 格式化日期 YYYYMMDD -> YYYY-MM-DD
- /// </summary>
- 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
- }
- }
|