1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182 |
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- 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 - 严格按照江苏医保规范v0.9.9.15实现
-
- /// <summary>
- /// 1.14.1 初始化
- /// </summary>
- /// <param name="pInitInfo">JSON格式的初始化参数</param>
- /// <param name="pErrMsg">错误信息输出缓冲区</param>
- /// <returns>0-成功,其他-失败</returns>
- [DllImport("HeaSecReadInfo.dll", EntryPoint = "Init", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
- private extern static Int32 Init(string pInitInfo, StringBuilder pErrMsg);
- /// <summary>
- /// 1.14.2 读社保卡基本信息
- /// </summary>
- /// <param name="pCardInfo">社保卡基本信息输出缓冲区</param>
- /// <param name="pBusiCardInfo">社保卡业务信息输出缓冲区</param>
- /// <returns>0-成功,其他-失败</returns>
- [DllImport("HeaSecReadInfo.dll", EntryPoint = "ReadCardBas", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
- private extern static Int32 ReadCardBas(StringBuilder pCardInfo, StringBuilder pBusiCardInfo);
- /// <summary>
- /// 1.14.3 检验PIN码
- /// </summary>
- /// <param name="pOutBuff">输出信息缓冲区</param>
- /// <returns>0-成功,其他-失败</returns>
- [DllImport("HeaSecReadInfo.dll", EntryPoint = "VerifyPIN", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
- private extern static Int32 VerifyPIN(StringBuilder pOutBuff);
- /// <summary>
- /// 1.14.4 修改PIN码
- /// </summary>
- /// <param name="pOutBuff">输出信息缓冲区</param>
- /// <returns>0-成功,其他-失败</returns>
- [DllImport("HeaSecReadInfo.dll", EntryPoint = "ChangePIN", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
- private extern static Int32 ChangePIN(StringBuilder pOutBuff);
- /// <summary>
- /// 1.14.6 电子凭证解码
- /// </summary>
- /// <param name="pInData">输入数据(JSON格式)</param>
- /// <param name="pOutData">输出数据缓冲区</param>
- /// <returns>0-成功,其他-失败</returns>
- [DllImport("HeaSecReadInfo.dll", EntryPoint = "EcQuery", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
- private extern static Int32 EcQuery(string pInData, StringBuilder pOutData);
- /// <summary>
- /// 1.14.8 四合一介质获得个人信息
- /// </summary>
- /// <param name="pInData">输入数据</param>
- /// <param name="pOutData">输出数据缓冲区</param>
- /// <returns>0-成功,其他-失败</returns>
- [DllImport("HeaSecReadInfo.dll", EntryPoint = "GetPersonInfo", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
- private extern static Int32 GetPersonInfo(string pInData, StringBuilder pOutData);
- #endregion
- #region 江苏医保刷脸DLL导入声明 (与泰和完全一致)
- /// <summary>
- /// 江苏医保刷脸功能:使用NationECCode.dll与泰和完全一致
- /// 唯一区别:URL参数格式为jiangsu_face_${biztype}
- /// </summary>
- /// <param name="strUrl">业务请求地址</param>
- /// <param name="InData">交易请求数据</param>
- /// <param name="OutData">交易返回数据</param>
- /// <returns>返回字符串指针</returns>
- [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)
- /// <summary>
- /// 江苏人社标准接口:读基本信息
- /// 按照江苏省人社一体化接口规范说明书标准实现
- /// 语法:long iReadCardBas(int iType, char *pOutInfo)
- /// </summary>
- /// <param name="iType">操作卡的类型:1-接触式,2-非接触式,3-自动寻卡接触式优先,4-自动寻卡非接触式优先</param>
- /// <param name="pOutInfo">输出信息缓冲区,成功时返回卡信息,失败时返回错误描述</param>
- /// <returns>0-成功,非0-失败</returns>
- [DllImport("SSCardDriver.dll", EntryPoint = "iReadCardBas", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
- private extern static long iReadCardBas(int iType, StringBuilder pOutInfo);
- #endregion
- #region 江苏人社标准接口业务方法
- /// <summary>
- /// 江苏人社标准接口:读取社保卡基本信息
- /// 按照江苏省人社一体化接口规范说明书标准实现
- /// 使用相同的初始化方法,但接口规范不同
- /// </summary>
- /// <param name="cardType">卡类型:1-接触式,2-非接触式,3-自动寻卡接触式优先,4-自动寻卡非接触式优先</param>
- /// <returns>读卡结果</returns>
- 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;
- }
- /// <summary>
- /// 解析江苏人社标准格式的社保卡信息
- /// </summary>
- /// <param name="rawData">原始数据(以|分割)</param>
- /// <returns>解析后的结构化数据</returns>
- 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;
- }
- /// <summary>
- /// 获取卡类型名称
- /// </summary>
- /// <param name="cardType">卡类型代码</param>
- /// <returns>卡类型名称</returns>
- private static string GetCardTypeName(int cardType)
- {
- switch (cardType)
- {
- case 1: return "接触式操作卡";
- case 2: return "非接触式操作卡";
- case 3: return "自动寻卡(接触式优先)";
- case 4: return "自动寻卡(非接触式优先)";
- default: return $"未知类型({cardType})";
- }
- }
- /// <summary>
- /// 根据错误码获取建议
- /// </summary>
- /// <param name="errorCode">错误码</param>
- /// <returns>错误建议</returns>
- 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 配置和状态管理
- /// <summary>
- /// 刷脸认证数据结构 - 与泰和保持一致
- /// </summary>
- public class FaceAuthData
- {
- public string authNo { get; set; }
- }
- private static bool isInitialized = false;
- private static JiangSuConfig currentConfig = null;
- /// <summary>
- /// 江苏医保配置类 - 严格按照规范v0.9.9.15定义的13个必需参数(全部大写)
- /// 支持从外部配置文件读取参数,打包后可直接修改配置文件
- /// </summary>
- public class JiangSuConfig
- {
- /// <summary>
- /// 1. 服务端IP地址 - 从外部配置文件读取
- /// </summary>
- public string IP { get; set; }
- /// <summary>
- /// 2. 服务端端口 - 从外部配置文件读取
- /// </summary>
- public int PORT { get; set; }
- /// <summary>
- /// 3. 超时时间(单位秒) - 从外部配置文件读取
- /// </summary>
- public int TIMEOUT { get; set; }
- /// <summary>
- /// 4. 动态库日志目录 - 从外部配置文件读取
- /// </summary>
- public string LOG_PATH { get; set; }
- /// <summary>
- /// 5. 电子凭证中台URL - 从外部配置文件读取
- /// </summary>
- public string EC_URL { get; set; }
- /// <summary>
- /// 6. 社保卡验证密码方式(1:验证卡pin,2:验证数据库密码) - 从外部配置文件读取
- /// 医院不需要输入密码,使用2:验证数据库密码
- /// </summary>
- public string CARD_PASSTYPE { get; set; }
- /// <summary>
- /// 7. CSB的_api_name - 从外部配置文件读取
- /// </summary>
- public string API_NAME { get; set; }
- /// <summary>
- /// 8. CSB的_api_version - 从外部配置文件读取
- /// </summary>
- public string API_VERSION { get; set; }
- /// <summary>
- /// 9. CSB的_api_access_key - 从外部配置文件读取
- /// </summary>
- public string ACCESS_KEY { get; set; }
- /// <summary>
- /// 10. CSB的secretKey - 从外部配置文件读取
- /// </summary>
- public string SECRETKEY { get; set; }
- /// <summary>
- /// 11. 定点编号 - 从外部配置文件读取
- /// </summary>
- public string ORG_ID { get; set; }
- /// <summary>
- /// 12. JSON对象字符串(预留) - 从外部配置文件读取
- /// </summary>
- public string EXT { get; set; }
- /// <summary>
- /// 13. 定点所属行政区划代码 - 从外部配置文件读取
- /// </summary>
- public string AREA_CODE { get; set; }
- /// <summary>
- /// 江苏医保刷脸专用:服务地址 - 从外部配置文件读取
- /// </summary>
- public string FACE_SERVICE_URL { get; set; }
- /// <summary>
- /// 江苏医保刷脸专用:机构编号 - 从外部配置文件读取
- /// </summary>
- public string FACE_ORG_ID { get; set; }
- /// <summary>
- /// 默认构造函数 - 从外部配置文件读取
- /// </summary>
- public JiangSuConfig()
- {
- LoadFromExternalConfig();
- }
- /// <summary>
- /// 从外部配置文件加载配置
- /// 优先级:外部配置文件 > 默认配置
- /// </summary>
- private void LoadFromExternalConfig()
- {
- try
- {
- // 首先尝试从外部配置文件读取
- string programDir = AppDomain.CurrentDomain.BaseDirectory;
- string externalConfigPath = Path.Combine(programDir, "jiangsu_config.txt");
-
- if (File.Exists(externalConfigPath))
- {
- try
- {
- LoadFromTextFile(externalConfigPath);
- System.Diagnostics.Debug.WriteLine($"配置已从外部文件加载: {externalConfigPath}");
- return;
- }
- catch (Exception ex)
- {
- System.Diagnostics.Debug.WriteLine($"外部配置文件加载失败: {ex.Message},使用默认配置");
- // 外部配置文件加载失败,使用默认配置
- SetDefaultValues();
- return;
- }
- }
- else
- {
- // 外部配置文件不存在,使用默认配置
- System.Diagnostics.Debug.WriteLine($"外部配置文件不存在: {externalConfigPath},使用默认配置");
- SetDefaultValues();
- return;
- }
- }
- catch (Exception ex)
- {
- System.Diagnostics.Debug.WriteLine($"配置加载异常: {ex.Message},使用默认配置");
- // 任何异常都使用默认配置
- SetDefaultValues();
- }
- }
- /// <summary>
- /// 从文本配置文件读取(用户可直接编辑)
- /// 格式:key=value,每行一个配置项
- /// 如果配置项缺失则使用默认值
- /// </summary>
- /// <param name="configPath">配置文件路径</param>
- private void LoadFromTextFile(string configPath)
- {
- var configLines = File.ReadAllLines(configPath);
- var configDict = new Dictionary<string, string>();
- foreach (var line in configLines)
- {
- var trimmedLine = line.Trim();
- if (string.IsNullOrEmpty(trimmedLine) || trimmedLine.StartsWith("#", StringComparison.Ordinal))
- continue;
- var parts = trimmedLine.Split(new char[] { '=' }, 2);
- if (parts.Length == 2)
- {
- configDict[parts[0].Trim()] = parts[1].Trim();
- }
- }
- // 从字典中读取配置值,如果缺失则使用默认值
- IP = GetConfigValue(configDict, "IP", "10.61.165.3");
- PORT = int.Parse(GetConfigValue(configDict, "PORT", "8086"));
- TIMEOUT = int.Parse(GetConfigValue(configDict, "TIMEOUT", "30"));
- LOG_PATH = GetConfigValue(configDict, "LOG_PATH", "E:\\huaihaiProject\\readCard\\ThCardReader\\logs\\");
- EC_URL = GetConfigValue(configDict, "EC_URL", "http://10.58.33.207:10086/localcfc/api/hsecfc/localQrCodeQuery");
- CARD_PASSTYPE = GetConfigValue(configDict, "CARD_PASSTYPE", "2");
- API_NAME = GetConfigValue(configDict, "API_NAME", "hssServives");
- API_VERSION = GetConfigValue(configDict, "API_VERSION", "1.0.0");
- ACCESS_KEY = GetConfigValue(configDict, "ACCESS_KEY", "090ea4c914324ee38b6978365df46a80");
- SECRETKEY = GetConfigValue(configDict, "SECRETKEY", "CMgTEMfftMP0EMMoliOs65wZmv8=");
- ORG_ID = GetConfigValue(configDict, "ORG_ID", "H32132200561");
- AREA_CODE = GetConfigValue(configDict, "AREA_CODE", "321322");
- EXT = GetConfigValue(configDict, "EXT", "{}");
- FACE_SERVICE_URL = GetConfigValue(configDict, "FACE_SERVICE_URL", "http://10.58.33.207:10086/localcfc/api/hsecfc/localQrCodeQuery");
- FACE_ORG_ID = GetConfigValue(configDict, "FACE_ORG_ID", "H32132200561");
- }
- /// <summary>
- /// 从字典获取配置值,如果不存在则使用默认值
- /// </summary>
- /// <param name="configDict">配置字典</param>
- /// <param name="key">配置键</param>
- /// <param name="defaultValue">默认值</param>
- /// <returns>配置值</returns>
- private string GetConfigValue(Dictionary<string, string> configDict, string key, string defaultValue)
- {
- return configDict.ContainsKey(key) ? configDict[key] : defaultValue;
- }
- /// <summary>
- /// 设置硬编码默认值(兜底方案)
- /// </summary>
- private void SetDefaultValues()
- {
- IP = "10.61.165.3";
- PORT = 8086;
- TIMEOUT = 30;
- LOG_PATH = "E:\\huaihaiProject\\readCard\\ThCardReader\\logs\\";
- EC_URL = "http://10.58.33.207:10086/localcfc/api/hsecfc/localQrCodeQuery";
- CARD_PASSTYPE = "2";
- API_NAME = "hssServives";
- API_VERSION = "1.0.0";
- ACCESS_KEY = "090ea4c914324ee38b6978365df46a80";
- SECRETKEY = "CMgTEMfftMP0EMMoliOs65wZmv8=";
- ORG_ID = "H32132200561";
- AREA_CODE = "321322";
- EXT = "{}";
- FACE_SERVICE_URL = "http://10.58.33.207:10086/localcfc/api/hsecfc/localQrCodeQuery";
- FACE_ORG_ID = "H32132200561";
- }
- /// <summary>
- /// 转换为JSON字符串(严格按照规范大写参数名格式)
- /// </summary>
- 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);
- }
- /// <summary>
- /// 生成默认的外部配置文件
- /// 注意:程序优先从外部配置文件读取,如果文件不存在或配置项缺失则使用默认配置
- /// </summary>
- /// <param name="configPath">配置文件路径</param>
- public static void GenerateDefaultConfigFile(string configPath)
- {
- var configContent = new List<string>
- {
- "# 江苏医保配置文件",
- "# 程序优先从外部配置文件读取配置",
- "# 如果文件不存在或配置项缺失,将使用默认配置",
- "# 修改此文件中的参数值,程序会自动读取",
- "# 格式:参数名=参数值",
- "# 以#开头的行为注释,会被忽略",
- "# 注意:如果配置项缺失,程序会使用默认值",
- "",
- "# 网络配置",
- "IP=10.61.165.3",
- "PORT=8086",
- "TIMEOUT=30",
- "",
- "# 日志配置",
- "LOG_PATH=E:\\huaihaiProject\\readCard\\ThCardReader\\logs\\",
- "",
- "# 电子凭证配置",
- "EC_URL=http://10.58.33.207:10086/localcfc/api/hsecfc/localQrCodeQuery",
- "",
- "# 社保卡验证配置",
- "CARD_PASSTYPE=2",
- "",
- "# CSB接口配置",
- "API_NAME=hssServives",
- "API_VERSION=1.0.0",
- "ACCESS_KEY=090ea4c914324ee38b6978365df46a80",
- "SECRETKEY=CMgTEMfftMP0EMMoliOs65wZmv8=",
- "",
- "# 机构配置",
- "ORG_ID=H32132200561",
- "AREA_CODE=321322",
- "EXT={}",
- "",
- "# 刷脸配置",
- "FACE_SERVICE_URL=http://10.58.33.207:10086/localcfc/api/hsecfc/localQrCodeQuery",
- "FACE_ORG_ID=H32132200561",
- "",
- "# 配置说明:",
- "# 1. 程序优先从外部配置文件读取配置",
- "# 2. 如果配置文件不存在,程序会使用默认配置",
- "# 3. 如果配置项缺失,程序会使用默认值",
- "# 4. 修改参数后保存文件,程序会自动重新加载配置",
- "# 5. 如果参数值包含特殊字符,请用引号包围",
- "# 6. 确保日志路径存在且有写入权限",
- "# 7. 生产环境请修改为实际的服务器地址和参数"
- };
- File.WriteAllLines(configPath, configContent);
- }
- }
- #endregion
- #region 核心业务方法
- /// <summary>
- /// 初始化江苏医保社保卡读取系统
- /// </summary>
- /// <param name="config">配置参数</param>
- /// <returns>初始化结果</returns>
- 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;
- }
- /// <summary>
- /// 读取社保卡基本信息
- /// 返回标准38号文格式数据
- /// </summary>
- /// <param name="autoVerifyPIN">是否自动验证PIN码</param>
- /// <param name="autoInit">是否自动初始化(默认false保持向后兼容)</param>
- /// <returns>读卡结果</returns>
- 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;
- }
- /// <summary>
- /// 验证社保卡PIN码
- /// </summary>
- /// <returns>验证结果</returns>
- 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;
- }
- /// <summary>
- /// 修改社保卡PIN码
- /// </summary>
- /// <returns>修改结果</returns>
- 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;
- }
- /// <summary>
- /// 四合一介质获取个人信息
- /// 支持社保卡、电子凭证、电子社保卡、身份证
- /// </summary>
- /// <param name="mediaType">介质类型</param>
- /// <param name="inputData">输入数据</param>
- /// <returns>个人信息</returns>
- 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;
- }
- /// <summary>
- /// 获取设备状态
- /// </summary>
- /// <returns>设备状态信息</returns>
- 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;
- }
- /// <summary>
- /// 重置系统内部状态
- /// </summary>
- /// <returns>重置结果</returns>
- 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;
- }
- /// <summary>
- /// 确保DLL文件在正确位置
- /// </summary>
- /// <returns>操作结果</returns>
- 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;
- }
- /// <summary>
- /// 检查DLL文件是否存在并可访问
- /// </summary>
- /// <returns>检查结果</returns>
- 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;
- }
- /// <summary>
- /// 诊断读卡器硬件和社保卡状态
- /// </summary>
- /// <returns>诊断结果</returns>
- 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;
- }
- /// <summary>
- /// 离线模式读取社保卡(跳过网络验证,仅测试本地读卡功能)
- /// </summary>
- /// <returns>读卡结果</returns>
- 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;
- }
- /// <summary>
- /// 测试不同网络配置对初始化的影响
- /// </summary>
- /// <returns>测试结果</returns>
- 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;
- }
-
- /// <summary>
- /// 测试单个配置
- /// </summary>
- 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实现)
- /// <summary>
- /// 江苏医保电子凭证解码
- /// 严格按照《医疗保障信息平台定点基线版医药机构接口规范 v0.9.9.15》中的1.14.6电子凭证解码接口实现
- /// </summary>
- /// <param name="businessType">用码业务类型,如:01101-门诊挂号,01301-门诊结算,02121-药店购药</param>
- /// <param name="operatorId">收款员编号</param>
- /// <param name="operatorName">收款员姓名</param>
- /// <param name="officeId">医保科室编号</param>
- /// <param name="officeName">科室名称</param>
- /// <returns>电子凭证解码结果</returns>
- 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;
- }
- /// <summary>
- /// 根据业务场景获取科室名称
- /// </summary>
- /// <param name="businessType">业务类型代码</param>
- /// <returns>科室名称</returns>
- 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 "医保科";
- }
- }
- /// <summary>
- /// 获取EcQuery错误码对应的建议
- /// </summary>
- /// <param name="errorCode">错误码</param>
- /// <returns>错误建议</returns>
- 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 "电子凭证解码失败,请检查设备连接和配置信息";
- }
- }
- /// <summary>
- /// 验证业务类型代码是否有效
- /// </summary>
- /// <param name="businessType">业务类型代码</param>
- /// <returns>是否有效</returns>
- 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 数据解析方法
- /// <summary>
- /// 解析38号文格式的社保卡数据
- /// </summary>
- /// <param name="cardData">卡基本信息</param>
- /// <param name="busiData">业务信息</param>
- /// <returns>解析后的数据</returns>
- 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;
- }
- /// <summary>
- /// 解析四合一介质的个人信息
- /// </summary>
- /// <param name="responseData">响应数据</param>
- /// <param name="mediaType">介质类型</param>
- /// <returns>解析后的个人信息</returns>
- private static JObject ParsePersonInfo(string responseData, string mediaType)
- {
- var result = new JObject();
- try
- {
- // 尝试解析JSON格式的响应
- if (responseData.StartsWith("{", StringComparison.Ordinal))
- {
- 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;
- }
- /// <summary>
- /// 格式化日期字符串
- /// </summary>
- /// <param name="dateStr">原始日期字符串</param>
- /// <returns>格式化后的日期</returns>
- 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与泰和完全一致)
- /// <summary>
- /// 江苏医保刷脸功能 - 使用NationECCode.dll与泰和完全一致
- /// 完全相同的实现:相同的DLL、相同的URL、相同的逻辑、相同的参数格式
- /// 唯一区别:使用写死的配置参数
- /// </summary>
- /// <param name="biztype">业务类型</param>
- /// <returns>刷脸结果</returns>
- 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<ReadCardResult>(outstr);
- if (tmp.code == 0)
- {
- FaceAuthData authData = Newtonsoft.Json.JsonConvert.DeserializeObject<FaceAuthData>(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;
- }
- }
- /// <summary>
- /// 根据authNo获取用户信息 - 使用NationECCode.dll与泰和完全一致
- /// </summary>
- /// <param name="biztype">业务类型</param>
- /// <param name="authNo">认证号</param>
- /// <returns>用户信息</returns>
- 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<ReadCardResult>(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
- }
- }
|