EntryController.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. using Newtonsoft.Json.Linq;
  2. using System.Web.Http;
  3. namespace ThCardReader
  4. {
  5. public class EntryController : ApiController
  6. {
  7. public JObject Get(string param)
  8. {
  9. JObject result = new JObject();
  10. if (param == null)
  11. {
  12. result.Add("code", 1001);
  13. result.Add("message", "参数为空!");
  14. return result;
  15. }
  16. string[] temps = param.Split(new char[] { '_' });
  17. // 检查两段式前缀(如 jiangsu_face、jiangsu_qrcode)
  18. string type;
  19. if (temps.Length >= 2 && temps[0].Equals("jiangsu") &&
  20. (temps[1].Equals("face") || temps[1].Equals("qrcode")))
  21. {
  22. type = temps[0] + "_" + temps[1]; // 组合成 jiangsu_face 或 jiangsu_qrcode
  23. }
  24. else
  25. {
  26. type = temps[0]; // 单段前缀
  27. }
  28. if (type.Equals("qrcode"))
  29. {
  30. result = NationalEcBusiness.ReadQrCode(temps[1]);
  31. }
  32. else if (type.Equals("qrcode2"))
  33. {
  34. result = NationalEcBusiness.ReadQrCode2(temps[1]);
  35. }
  36. else if (type.Equals("face"))
  37. {
  38. result = NationalEcBusiness.ReadFace(temps[1]);
  39. }
  40. else if (type.Equals("sicard"))
  41. {
  42. result = SsCardBusiness.ReadSiCard();
  43. }
  44. else if (type.Equals("idcard"))
  45. {
  46. result = SsCardBusiness.ReadIdCard();
  47. }
  48. else if (type.Equals("idcard2"))
  49. {
  50. result = NationalEcBusiness.ReadIdCard(temps[1]);
  51. }
  52. else if (type.Equals("huashi"))
  53. {
  54. // 华视读卡器调用
  55. string action = temps.Length > 1 ? temps[1] : "readcard";
  56. // 检查是否是业务代码格式(5位数字),如果是则默认为readcard操作
  57. if (temps.Length > 1 && IsBusinessCode(temps[1]))
  58. {
  59. action = "readcard"; // 业务代码不影响华视读卡器操作,默认读卡
  60. }
  61. if (action.Equals("init"))
  62. {
  63. int port = temps.Length > 2 ? int.Parse(temps[2]) : 1001;
  64. result = HuaShiIdCardBusiness.Initialize(port);
  65. }
  66. else if (action.Equals("readcard"))
  67. {
  68. // URL调用时启用自动关闭,模拟SSCard.dll的无状态行为
  69. var huashiResult = HuaShiIdCardBusiness.ReadIdCard("", true);
  70. result = ConvertHuaShiDataToStandardFormat(huashiResult);
  71. }
  72. else if (action.Equals("continuous"))
  73. {
  74. // URL调用时启用自动关闭,模拟SSCard.dll的无状态行为
  75. var huashiResult = HuaShiIdCardBusiness.ReadIdCardContinuous("", true);
  76. result = ConvertHuaShiDataToStandardFormat(huashiResult);
  77. }
  78. else if (action.Equals("status"))
  79. {
  80. result = HuaShiIdCardBusiness.GetDeviceStatus();
  81. }
  82. else if (action.Equals("close"))
  83. {
  84. result = HuaShiIdCardBusiness.Close();
  85. }
  86. else
  87. {
  88. result.Add("code", 1001);
  89. result.Add("message", "华视读卡器操作【" + action + "】错误!允许的操作为【init、readcard、continuous、status、close】");
  90. }
  91. }
  92. else if (type.Equals("jiangsu_face"))
  93. {
  94. // 江苏医保刷脸授权获取医保身份 - 使用NationECCode.dll与泰和完全一致
  95. // URL格式: http://localhost:8321/readcard/entry?param=jiangsu_face_${nowbiztype}
  96. string businessType = temps.Length > 2 ? temps[2] : "01101"; // 从URL参数获取业务类型(第3段)
  97. // 验证业务类型格式
  98. if (!JiangSuSocialCardBusiness.IsValidBusinessType(businessType))
  99. {
  100. result.Add("success", false);
  101. result.Add("code", 1001);
  102. result.Add("message", $"江苏医保刷脸业务类型【{businessType}】无效!支持的业务类型:01101(门诊挂号)、01301(门诊结算)、02121(药店购药)等");
  103. result.Add("type", "face");
  104. result.Add("device", "江苏医保刷脸认证器(NationECCode.dll)");
  105. result.Add("businessType", businessType);
  106. }
  107. else
  108. {
  109. result = JiangSuSocialCardBusiness.ReadFace(businessType); // 使用NationECCode.dll与泰和完全一致
  110. // 转换为前端期望的格式
  111. result = ConvertJiangSuFaceAuthToStandardFormat(result);
  112. }
  113. }
  114. else if (type.Equals("jiangsu_qrcode"))
  115. {
  116. // 江苏医保电子凭证解码(独立入口)
  117. string businessType = temps.Length > 2 ? temps[2] : "01101"; // 从URL参数获取业务类型(第3段)
  118. // 验证业务类型格式
  119. if (!JiangSuSocialCardBusiness.IsValidBusinessType(businessType))
  120. {
  121. result.Add("success", false);
  122. result.Add("code", 1001);
  123. result.Add("message", $"江苏医保电子凭证业务类型【{businessType}】无效!支持的业务类型:01101(门诊挂号)、01301(门诊结算)、02121(药店购药)等");
  124. result.Add("type", "qrcode");
  125. result.Add("device", "江苏医保电子凭证解码器");
  126. }
  127. else
  128. {
  129. result = JiangSuSocialCardBusiness.ReadElectronicCertificate(businessType);
  130. // 转换为前端期望的格式
  131. result = ConvertJiangSuElectronicCertificateToStandardFormat(result);
  132. }
  133. }
  134. else if (type.Equals("jiangsu"))
  135. {
  136. // 江苏医保社保卡读取
  137. string action = temps.Length > 1 ? temps[1] : "readcard";
  138. // 检查是否是业务代码格式(5位数字),如果是则默认为readcard操作
  139. if (temps.Length > 1 && IsBusinessCode(temps[1]))
  140. {
  141. action = "readcard"; // 业务代码不影响江苏医保读卡操作,默认读卡
  142. }
  143. if (action.Equals("init"))
  144. {
  145. result = JiangSuSocialCardBusiness.Initialize();
  146. }
  147. else if (action.Equals("readcard"))
  148. {
  149. result = JiangSuSocialCardBusiness.ReadSocialCard(false);
  150. // 转换为前端期望的格式
  151. result = ConvertJiangSuDataToStandardFormat(result);
  152. }
  153. else if (action.Equals("readcard_pin"))
  154. {
  155. result = JiangSuSocialCardBusiness.ReadSocialCard(true);
  156. result = ConvertJiangSuDataToStandardFormat(result);
  157. }
  158. else if (action.Equals("verifypin"))
  159. {
  160. result = JiangSuSocialCardBusiness.VerifyCardPIN();
  161. }
  162. else if (action.Equals("changepin"))
  163. {
  164. result = JiangSuSocialCardBusiness.ChangeCardPIN();
  165. }
  166. else if (action.Equals("status"))
  167. {
  168. result = JiangSuSocialCardBusiness.GetDeviceStatus();
  169. }
  170. else if (action.Equals("reset"))
  171. {
  172. result = JiangSuSocialCardBusiness.ResetSystemState();
  173. }
  174. else if (action.Equals("getpersoninfo"))
  175. {
  176. result = JiangSuSocialCardBusiness.GetPersonInfo("socialcard", "");
  177. }
  178. else if (action.Equals("checkdll"))
  179. {
  180. result = JiangSuSocialCardBusiness.CheckDllExists();
  181. }
  182. else if (action.Equals("qrcode") || action.Equals("ec"))
  183. {
  184. // 江苏医保电子凭证解码
  185. string businessType = temps.Length > 2 ? temps[2] : "01101"; // 默认门诊挂号
  186. // 验证业务类型格式
  187. if (!JiangSuSocialCardBusiness.IsValidBusinessType(businessType))
  188. {
  189. result.Add("success", false);
  190. result.Add("code", 1001);
  191. result.Add("message", $"江苏医保电子凭证业务类型【{businessType}】无效!支持的业务类型:01101(门诊挂号)、01301(门诊结算)、02121(药店购药)等");
  192. result.Add("type", "qrcode");
  193. result.Add("device", "江苏医保电子凭证解码器");
  194. }
  195. else
  196. {
  197. result = JiangSuSocialCardBusiness.ReadElectronicCertificate(businessType);
  198. // 转换为前端期望的格式(电子凭证不需要特殊转换,保持原格式)
  199. result = ConvertJiangSuElectronicCertificateToStandardFormat(result);
  200. }
  201. }
  202. else
  203. {
  204. result.Add("success", false);
  205. result.Add("code", 1001);
  206. result.Add("message", "江苏医保操作【" + action + "】错误!允许的操作为【init、readcard、readcard_pin、verifypin、changepin、status、reset、getpersoninfo、checkdll、qrcode、ec】");
  207. }
  208. }
  209. else
  210. {
  211. result.Add("code", 1001);
  212. result.Add("message", "读卡类别【" + type + "】错误!允许的类别为【sicard、idcard、idcard2、qrcode、qrcode2、face、huashi、jiangsu、jiangsu_qrcode、jiangsu_face】");
  213. }
  214. return result;
  215. }
  216. /// <summary>
  217. /// 判断字符串是否是业务代码格式(5位数字)
  218. /// </summary>
  219. /// <param name="code">要检查的字符串</param>
  220. /// <returns>是否是业务代码</returns>
  221. private bool IsBusinessCode(string code)
  222. {
  223. if (string.IsNullOrEmpty(code) || code.Length != 5)
  224. {
  225. return false;
  226. }
  227. // 检查是否是5位数字
  228. foreach (char c in code)
  229. {
  230. if (!char.IsDigit(c))
  231. {
  232. return false;
  233. }
  234. }
  235. return true;
  236. }
  237. /// <summary>
  238. /// 将华视读卡器的数据格式转换为前端期望的"^"分隔字符串格式
  239. /// </summary>
  240. /// <param name="huashiResult">华视读卡器返回的JSON数据</param>
  241. /// <returns>转换后的标准格式</returns>
  242. private JObject ConvertHuaShiDataToStandardFormat(JObject huashiResult)
  243. {
  244. JObject result = new JObject();
  245. try
  246. {
  247. // 如果华视读卡器返回错误,直接返回错误信息
  248. if ((int)huashiResult["code"] != 200)
  249. {
  250. return huashiResult;
  251. }
  252. // 提取华视读卡器返回的数据
  253. var data = huashiResult["data"];
  254. if (data == null)
  255. {
  256. result.Add("code", 1001);
  257. result.Add("message", "华视读卡器返回数据为空");
  258. return result;
  259. }
  260. // 按照前端期望的顺序组装数据:
  261. // str1[0] = IDNumber (身份证号)
  262. // str1[1] = Name (姓名)
  263. // str1[2] = Sex (性别)
  264. // str1[3] = Nation (民族)
  265. // str1[4] = Birthday (生日)
  266. // str1[5] = Address (地址)
  267. // str1[6] = IDIssued (签发机关)
  268. // str1[7] = IssuedData + ValidDate (签发日期+有效期,连续)
  269. // str1[8] = Base64Photo (照片Base64)
  270. string idNumber = data["idCode"]?.ToString() ?? "";
  271. string name = data["name"]?.ToString() ?? "";
  272. string sex = data["sex"]?.ToString() ?? "";
  273. string nation = data["nation"]?.ToString() ?? "";
  274. string birthday = data["birthday"]?.ToString() ?? "";
  275. string address = data["address"]?.ToString() ?? "";
  276. string department = data["department"]?.ToString() ?? "";
  277. string startDate = data["startDate"]?.ToString() ?? "";
  278. string endDate = data["endDate"]?.ToString() ?? "";
  279. // 组合签发日期和有效期 (前端会用substring分割)
  280. string dateInfo = startDate + endDate;
  281. // 获取照片的Base64数据
  282. string base64Photo = data["photoBase64"]?.ToString() ?? "";
  283. // 按照前端期望的顺序用"^"连接
  284. string formattedData = string.Join("^", new string[] {
  285. idNumber, // [0] 身份证号
  286. name, // [1] 姓名
  287. sex, // [2] 性别
  288. nation, // [3] 民族
  289. birthday, // [4] 生日
  290. address, // [5] 地址
  291. department, // [6] 签发机关
  292. dateInfo, // [7] 签发日期+有效期
  293. base64Photo, // [8] 照片Base64
  294. "", // [9] 预留空位,确保split后数组有足够元素
  295. "" // [10] 预留空位
  296. });
  297. result.Add("code", 200);
  298. result.Add("message", "华视读卡器读取成功(已转换为标准格式)");
  299. result.Add("data", formattedData);
  300. result.Add("device", "华视电子身份证读卡器");
  301. result.Add("originalType", "huashi_idcard");
  302. }
  303. catch (System.Exception ex)
  304. {
  305. result.Add("code", 1001);
  306. result.Add("message", $"华视数据格式转换异常: {ex.Message}");
  307. }
  308. return result;
  309. }
  310. /// <summary>
  311. /// 将江苏医保社保卡的数据格式转换为前端期望的"^"分隔字符串格式
  312. /// </summary>
  313. /// <param name="jiangsuResult">江苏医保返回的JSON数据</param>
  314. /// <returns>转换后的标准格式</returns>
  315. private JObject ConvertJiangSuDataToStandardFormat(JObject jiangsuResult)
  316. {
  317. JObject result = new JObject();
  318. try
  319. {
  320. // 如果江苏医保返回错误,直接返回错误信息
  321. if (!(bool)jiangsuResult["success"] || (int)jiangsuResult["code"] != 200)
  322. {
  323. // 保持原有的success和code字段,但调整为前端期望的格式
  324. result.Add("code", jiangsuResult["code"]);
  325. result.Add("message", jiangsuResult["message"]);
  326. result.Add("device", "江苏医保社保卡读卡器");
  327. return result;
  328. }
  329. // 提取江苏医保返回的数据
  330. var data = jiangsuResult["data"];
  331. if (data == null)
  332. {
  333. result.Add("code", 1001);
  334. result.Add("message", "江苏医保返回数据为空");
  335. return result;
  336. }
  337. // 按照前端期望的顺序组装社保卡数据:
  338. // str1[0] = CardNumber (社保卡号)
  339. // str1[1] = Name (姓名)
  340. // str1[2] = IDNumber (身份证号)
  341. // str1[3] = Sex (性别)
  342. // str1[4] = Nation (民族)
  343. // str1[5] = Birthday (生日)
  344. // str1[6] = Address (地址)
  345. // str1[7] = IssueDate (发卡日期)
  346. // str1[8] = ValidDate (有效期)
  347. // str1[9] = Department (发卡机构)
  348. // str1[10] = Photo (照片Base64)
  349. string cardNumber = data["cardNumber"]?.ToString() ?? "";
  350. string name = data["name"]?.ToString() ?? "";
  351. string idNumber = data["idNumber"]?.ToString() ?? "";
  352. string sex = data["sex"]?.ToString() ?? "";
  353. string nation = data["nation"]?.ToString() ?? "";
  354. string birthday = data["birthday"]?.ToString() ?? "";
  355. string address = data["address"]?.ToString() ?? "";
  356. string issueDate = data["issueDate"]?.ToString() ?? "";
  357. string validDate = data["validDate"]?.ToString() ?? "";
  358. string department = data["department"]?.ToString() ?? "";
  359. string photo = data["photo"]?.ToString() ?? "";
  360. // 按照前端期望的顺序用"^"连接(社保卡格式)
  361. string formattedData = string.Join("^", new string[] {
  362. cardNumber, // [0] 社保卡号
  363. name, // [1] 姓名
  364. idNumber, // [2] 身份证号
  365. sex, // [3] 性别
  366. nation, // [4] 民族
  367. birthday, // [5] 生日
  368. address, // [6] 地址
  369. issueDate, // [7] 发卡日期
  370. validDate, // [8] 有效期
  371. department, // [9] 发卡机构
  372. photo, // [10] 照片Base64
  373. "", // [11] 预留空位
  374. "" // [12] 预留空位
  375. });
  376. result.Add("code", 200);
  377. result.Add("message", "江苏医保社保卡读取成功(已转换为标准格式)");
  378. result.Add("data", formattedData);
  379. result.Add("device", "江苏医保社保卡读卡器");
  380. result.Add("originalType", "jiangsu_socialcard");
  381. }
  382. catch (System.Exception ex)
  383. {
  384. result.Add("code", 1001);
  385. result.Add("message", $"江苏医保数据格式转换异常: {ex.Message}");
  386. }
  387. return result;
  388. }
  389. /// <summary>
  390. /// 将江苏医保电子凭证解码结果转换为前端期望的格式
  391. /// </summary>
  392. /// <param name="jiangsuEcResult">江苏医保电子凭证解码返回的JSON数据</param>
  393. /// <returns>转换后的标准格式</returns>
  394. private JObject ConvertJiangSuElectronicCertificateToStandardFormat(JObject jiangsuEcResult)
  395. {
  396. JObject result = new JObject();
  397. try
  398. {
  399. // 如果江苏医保电子凭证解码返回错误,直接返回错误信息
  400. if (!(bool)jiangsuEcResult["success"] || (int)jiangsuEcResult["code"] != 200)
  401. {
  402. // 保持原有的字段,确保前端能正确处理
  403. result.Add("code", jiangsuEcResult["code"]);
  404. result.Add("message", jiangsuEcResult["message"]);
  405. result.Add("device", jiangsuEcResult["device"]);
  406. result.Add("type", jiangsuEcResult["type"]);
  407. // 添加其他可能的错误信息字段
  408. if (jiangsuEcResult["jiangsuErrorCode"] != null)
  409. result.Add("jiangsuErrorCode", jiangsuEcResult["jiangsuErrorCode"]);
  410. if (jiangsuEcResult["jiangsuErrorMessage"] != null)
  411. result.Add("jiangsuErrorMessage", jiangsuEcResult["jiangsuErrorMessage"]);
  412. if (jiangsuEcResult["suggestion"] != null)
  413. result.Add("suggestion", jiangsuEcResult["suggestion"]);
  414. return result;
  415. }
  416. // 电子凭证解码成功,保持原格式返回(前端直接使用JSON格式)
  417. result.Add("code", jiangsuEcResult["code"]);
  418. result.Add("message", jiangsuEcResult["message"]);
  419. result.Add("device", jiangsuEcResult["device"]);
  420. result.Add("type", jiangsuEcResult["type"]);
  421. result.Add("originalType", jiangsuEcResult["originalType"]);
  422. result.Add("timestamp", jiangsuEcResult["timestamp"]);
  423. // 保持电子凭证的JSON数据格式(前端期望JSON而不是^分隔的字符串)
  424. result.Add("data", jiangsuEcResult["data"]);
  425. // 添加兼容字段:让前端可以统一处理
  426. result.Add("readCardResult", jiangsuEcResult["readCardResult"]);
  427. // 保留江苏医保相关信息
  428. if (jiangsuEcResult["businessType"] != null)
  429. result.Add("businessType", jiangsuEcResult["businessType"]);
  430. if (jiangsuEcResult["interfaceVersion"] != null)
  431. result.Add("interfaceVersion", jiangsuEcResult["interfaceVersion"]);
  432. if (jiangsuEcResult["jiangsuOriginalData"] != null)
  433. result.Add("jiangsuOriginalData", jiangsuEcResult["jiangsuOriginalData"]);
  434. }
  435. catch (System.Exception ex)
  436. {
  437. result.Add("code", 1001);
  438. result.Add("message", $"江苏医保电子凭证数据格式转换异常: {ex.Message}");
  439. result.Add("device", "江苏医保电子凭证解码器");
  440. result.Add("type", "qrcode");
  441. result.Add("exception", ex.GetType().Name);
  442. }
  443. return result;
  444. }
  445. /// <summary>
  446. /// 将江苏医保刷脸授权结果转换为前端期望的格式
  447. /// </summary>
  448. /// <param name="jiangsuFaceAuthResult">江苏医保刷脸授权返回的JSON数据</param>
  449. /// <returns>转换后的标准格式</returns>
  450. private JObject ConvertJiangSuFaceAuthToStandardFormat(JObject jiangsuFaceAuthResult)
  451. {
  452. JObject result = new JObject();
  453. try
  454. {
  455. // 刷脸授权直接返回原JSON格式,不需要转换为^分隔字符串
  456. // 因为刷脸返回的是结构化的医保身份信息,前端期望JSON格式
  457. result.Add("code", jiangsuFaceAuthResult["code"]);
  458. result.Add("message", jiangsuFaceAuthResult["message"]);
  459. result.Add("type", "face");
  460. result.Add("data", jiangsuFaceAuthResult["data"]?.ToString());
  461. result.Add("sign", jiangsuFaceAuthResult["sign"]);
  462. // 保留江苏医保特有字段
  463. if (jiangsuFaceAuthResult["device"] != null)
  464. result.Add("device", jiangsuFaceAuthResult["device"]);
  465. if (jiangsuFaceAuthResult["businessType"] != null)
  466. result.Add("businessType", jiangsuFaceAuthResult["businessType"]);
  467. if (jiangsuFaceAuthResult["timestamp"] != null)
  468. result.Add("timestamp", jiangsuFaceAuthResult["timestamp"]);
  469. if (jiangsuFaceAuthResult["authNo"] != null)
  470. result.Add("authNo", jiangsuFaceAuthResult["authNo"]);
  471. if (jiangsuFaceAuthResult["interfaceVersion"] != null)
  472. result.Add("interfaceVersion", jiangsuFaceAuthResult["interfaceVersion"]);
  473. }
  474. catch (System.Exception ex)
  475. {
  476. result.Add("code", 1001);
  477. result.Add("message", $"江苏医保刷脸授权数据格式转换异常: {ex.Message}");
  478. result.Add("device", "江苏医保刷脸认证器");
  479. result.Add("type", "face");
  480. result.Add("exception", ex.GetType().Name);
  481. }
  482. return result;
  483. }
  484. }
  485. }