ChooseCardNew.cs 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068
  1. using Newtonsoft.Json.Linq;
  2. using NPOI.SS.UserModel;
  3. using PTMedicalInsurance.CardReaders;
  4. using PTMedicalInsurance.Common;
  5. using PTMedicalInsurance.Forms;
  6. using PTMedicalInsurance.Helper;
  7. using PTMedicalInsurance.Variables;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.ComponentModel;
  11. using System.Data;
  12. using System.Drawing;
  13. using System.Linq;
  14. using System.Runtime.InteropServices;
  15. using System.Text;
  16. using System.Threading;
  17. using System.Threading.Tasks;
  18. using System.Windows.Forms;
  19. namespace PTMedicalInsurance.Forms
  20. {
  21. public partial class ChooseCardNew : Form
  22. {
  23. #region Windows API
  24. [DllImport("user32.dll")]
  25. private static extern bool SetForegroundWindow(IntPtr hWnd);
  26. [DllImport("user32.dll")]
  27. private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
  28. [DllImport("user32.dll")]
  29. private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
  30. [DllImport("user32.dll")]
  31. private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
  32. [DllImport("user32.dll")]
  33. private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
  34. private const int SW_MINIMIZE = 6;
  35. private const int SW_RESTORE = 9;
  36. private const int SW_SHOW = 5;
  37. private const int WM_SYSCOMMAND = 0x0112;
  38. private const int SC_MINIMIZE = 0xF020;
  39. private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
  40. private static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
  41. private const uint SWP_NOMOVE = 0x0002;
  42. private const uint SWP_NOSIZE = 0x0001;
  43. private const uint SWP_SHOWWINDOW = 0x0040;
  44. #endregion
  45. #region 属性定义
  46. /// <summary>
  47. /// 证件类型:01 医保电子凭证 02 居民身份证 03 社会保障卡 05 终端扫脸
  48. /// </summary>
  49. public string CertType { get; set; }
  50. /// <summary>
  51. /// 证件号码
  52. /// </summary>
  53. public string CertNo { get; set; }
  54. /// <summary>
  55. /// 业务类型编码
  56. /// </summary>
  57. public string BusinessType { get; set; }
  58. /// <summary>
  59. /// 是否工伤
  60. /// </summary>
  61. public bool IsWorkInjury { get; set; }
  62. /// <summary>
  63. /// 读卡Invoker
  64. /// </summary>
  65. private readonly InvokeHelper _invoker = new InvokeHelper();
  66. #endregion
  67. public ChooseCardNew()
  68. {
  69. InitializeComponent();
  70. }
  71. private void ChooseCardNew_Load(object sender, EventArgs e)
  72. {
  73. // 初始化默认选项
  74. rbSocialCard.Checked = true;
  75. rbMedicalInsurance.Checked = true;
  76. // 初始化患者信息表格
  77. InitPatientInfoGrid();
  78. InitBusinessType();
  79. InitCertType();
  80. // 初始化无卡结算控件状态
  81. cbxNoCardTag_CheckedChanged(null, null);
  82. }
  83. private void InitBusinessType()
  84. {
  85. // 使用字典初始化业务类型
  86. DictionaryHelper dicHelper = new DictionaryHelper();
  87. dicHelper.SetComboxDatasource(cbBusinessType, "business_type");
  88. }
  89. private void InitCertType()
  90. {
  91. // 使用字典初始化证件类型
  92. DictionaryHelper dicHelper = new DictionaryHelper();
  93. dicHelper.SetComboxDatasource(cbCertType, "psn_cert_type");
  94. }
  95. /// <summary>
  96. /// 初始化患者信息表格(多行选择模式)
  97. /// </summary>
  98. private void InitPatientInfoGrid()
  99. {
  100. dgvPatientInfo.Columns.Clear();
  101. dgvPatientInfo.Columns.Add("psnName", "姓名");
  102. dgvPatientInfo.Columns.Add("gend", "性别");
  103. dgvPatientInfo.Columns.Add("certno", "身份证号");
  104. dgvPatientInfo.Columns.Add("psnNo", "人员编号");
  105. dgvPatientInfo.Columns.Add("insuplcAdmdvs", "参保地");
  106. dgvPatientInfo.Columns.Add("psnType", "人员类别");
  107. // 设置列宽
  108. dgvPatientInfo.Columns["psnName"].Width = 100;
  109. dgvPatientInfo.Columns["gend"].Width = 60;
  110. dgvPatientInfo.Columns["certno"].Width = 180;
  111. dgvPatientInfo.Columns["psnNo"].Width = 150;
  112. dgvPatientInfo.Columns["insuplcAdmdvs"].Width = 150;
  113. dgvPatientInfo.Columns["psnType"].Width = 100;
  114. // 设置表格属性
  115. dgvPatientInfo.AllowUserToAddRows = false;
  116. dgvPatientInfo.AllowUserToDeleteRows = false;
  117. dgvPatientInfo.RowHeadersVisible = false;
  118. dgvPatientInfo.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
  119. dgvPatientInfo.MultiSelect = false;
  120. dgvPatientInfo.ReadOnly = true;
  121. dgvPatientInfo.BackgroundColor = System.Drawing.Color.White;
  122. dgvPatientInfo.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
  123. dgvPatientInfo.RowTemplate.Height = 35;
  124. }
  125. private void dgvPatientInfo_ColumnAdded(object sender, DataGridViewColumnEventArgs e)
  126. {
  127. e.Column.SortMode = DataGridViewColumnSortMode.NotSortable;
  128. }
  129. #region 读卡按钮事件
  130. /// <summary>
  131. /// 读卡按钮 - 根据选择的证件类型读取
  132. /// </summary>
  133. private void btnReadCard_Click(object sender, EventArgs e)
  134. {
  135. // 根据选择的证件类型确定证件类型码
  136. string readType;
  137. if (rbSocialCard.Checked)
  138. {
  139. // 社会保障卡
  140. Global.pat.mdtrtcertType = "03";
  141. readType = "社会保障卡";
  142. }
  143. else if (rbIDCard.Checked)
  144. {
  145. // 居民身份证
  146. Global.pat.mdtrtcertType = "02";
  147. readType = "居民身份证";
  148. }
  149. else if (rbECToken.Checked)
  150. {
  151. // 医保电子凭证
  152. Global.pat.mdtrtcertType = "01";
  153. readType = "医保电子凭证";
  154. }
  155. else if (rbFace.Checked)
  156. {
  157. // 终端扫脸
  158. Global.pat.mdtrtcertType = "05";
  159. readType = "终端扫脸";
  160. }
  161. else
  162. {
  163. MessageBox.Show("请先选择证件类型!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  164. return;
  165. }
  166. // 根据证件类型调用读卡
  167. ReadCard(Global.pat.mdtrtcertType, "1001", readType);
  168. }
  169. /// <summary>
  170. /// 修改密码
  171. /// </summary>
  172. private void btnPasswordModify_Click(object sender, EventArgs e)
  173. {
  174. try
  175. {
  176. string errorMsg = "";
  177. string sInput = JsonHelper.setCenterInpar("1193", "");
  178. JObject joRtn = _invoker.invokeCenterService("1193", sInput);
  179. if (JsonHelper.parseCenterRtnValue(joRtn, out errorMsg) != 0)
  180. {
  181. MessageBox.Show("修改卡密码失败:" + errorMsg, "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  182. }
  183. else
  184. {
  185. MessageBox.Show("修改卡密码成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
  186. }
  187. }
  188. catch (Exception ex)
  189. {
  190. MessageBox.Show("修改密码失败:" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
  191. }
  192. }
  193. #endregion
  194. #region 读卡核心方法
  195. /// <summary>
  196. /// 读卡并获取信息
  197. /// </summary>
  198. /// <param name="certType">证件类型</param>
  199. /// <param name="tradeCode">交易码</param>
  200. /// <param name="readType">读卡类型描述</param>
  201. private void ReadCard(string certType, string tradeCode, string readType)
  202. {
  203. // 先禁用读卡按钮,防止重复点击
  204. btnReadCard.Enabled = false;
  205. btnReadCard.Text = "读卡中...";
  206. CertType = certType;
  207. // 根据证件类型选择不同的读卡方式
  208. switch (certType)
  209. {
  210. case "01":
  211. case "02":
  212. case "03":
  213. // 电子凭证、身份证、社保卡:都走COM组件调用方式
  214. ReadSocialCardNewTwo(certType);
  215. break;
  216. case "05":
  217. // 扫脸:使用 CardReader.FaceRecognition
  218. ReadFaceCard();
  219. break;
  220. default:
  221. MessageBox.Show("不支持的证件类型!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
  222. btnReadCard.Enabled = true;
  223. btnReadCard.Text = "读 卡";
  224. break;
  225. }
  226. }
  227. /// <summary>
  228. /// 读取社保卡(使用COM控件)
  229. /// </summary>
  230. /// <param name="certType">证件类型:01电子凭证 02身份证 03社保卡</param>
  231. private void ReadSocialCard(string certType)
  232. {
  233. // 在后台线程执行COM控件调用,避免阻塞UI
  234. Task.Run(() =>
  235. {
  236. try
  237. {
  238. string errorMsg = "";
  239. // 从UI控件获取参数值(需要Invoke确保线程安全)
  240. string certNo = "";
  241. string certTypeCode = "";
  242. string betaFlag = "";
  243. string noCardTag = "";
  244. this.Invoke(new Action(() =>
  245. {
  246. certNo = txtCertNo.Text.Trim();
  247. certTypeCode = cbCertType.SelectedValue?.ToString() ?? "";
  248. // 如果用户勾选了无卡结算,使用用户选择;否则根据证件类型自动判断
  249. if (cbxNoCardTag.Checked)
  250. {
  251. noCardTag = "1";
  252. }
  253. else
  254. {
  255. // 根据证件类型设置 no_card_tag
  256. // 01-电子凭证 02-身份证 03-社保卡
  257. switch (certType)
  258. {
  259. case "01":
  260. noCardTag = "1";
  261. break;
  262. case "02":
  263. noCardTag = "2";
  264. break;
  265. default:
  266. noCardTag = "";
  267. break;
  268. }
  269. }
  270. }));
  271. // COM控件调用需要在STA线程
  272. string input = "{" +
  273. "\"begntime\": \"\"," +
  274. "\"no_card_tag\": \"" + noCardTag + "\"," +
  275. "\"certno\": \"" + certNo + "\"," +
  276. "\"psn_cert_typ\": \"" + certTypeCode + "\"," +
  277. "\"beta_flag\": \"" + betaFlag + "\"," +
  278. "\"cro_prov_flag\": \"\"" +
  279. "}";
  280. int result = -1;
  281. InvokeComCenter2026 carder = new InvokeComCenter2026();
  282. // 获取当前窗口句柄
  283. IntPtr thisHandle = this.Handle;
  284. // 使用 STA 线程调用 COM 控件
  285. Thread staThread = new Thread(() =>
  286. {
  287. // 先将当前窗口最小化(使用 SendMessage 避免焦点问题)
  288. SendMessage(thisHandle, WM_SYSCOMMAND, (IntPtr)SC_MINIMIZE, IntPtr.Zero);
  289. // 等待最小化完成
  290. Thread.Sleep(200);
  291. // 调用读卡
  292. result = carder.Business("1001", ref input, ref errorMsg);
  293. // 读卡完成后恢复窗口
  294. ShowWindow(thisHandle, SW_RESTORE);
  295. SetWindowPos(thisHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
  296. });
  297. staThread.SetApartmentState(ApartmentState.STA);
  298. staThread.Start();
  299. staThread.Join();
  300. // 回到UI线程更新界面
  301. this.Invoke(new Action(() =>
  302. {
  303. // 取消置顶
  304. SetWindowPos(thisHandle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
  305. this.BringToFront();
  306. this.Activate();
  307. btnReadCard.Enabled = true;
  308. btnReadCard.Text = "读 卡";
  309. if (result != 0)
  310. {
  311. MessageBox.Show("读社保卡失败:" + errorMsg, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
  312. return;
  313. }
  314. // 更新界面上的单选按钮
  315. UpdateRadioButton(CertType);
  316. // 解析1001返回的多行数据
  317. JObject joRtn = JObject.Parse(errorMsg);
  318. ParseAndShowPatientList(joRtn);
  319. }));
  320. }
  321. catch (Exception ex)
  322. {
  323. this.Invoke(new Action(() =>
  324. {
  325. // 恢复窗口
  326. ShowWindow(this.Handle, SW_RESTORE);
  327. this.BringToFront();
  328. btnReadCard.Enabled = true;
  329. btnReadCard.Text = "读 卡";
  330. MessageBox.Show("读社保卡失败:" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
  331. }));
  332. }
  333. });
  334. }
  335. /// <summary>
  336. /// 读取社保卡(使用COM控件,支持CEF环境模态效果)
  337. /// 签名与ReadSocialCard相同
  338. /// </summary>
  339. /// <param name="certType">证件类型:01电子凭证 02身份证 03社保卡</param>
  340. private void ReadSocialCardNew(string certType)
  341. {
  342. // 获取CEF Browser窗口句柄并禁用
  343. IntPtr cefHwnd = IntPtr.Zero;
  344. try
  345. {
  346. cefHwnd = WinApi.GetWindowsHandle("prBrowser");
  347. Global.writeLog("ReadSocialCardNew", "1-获取CEF窗口", $"hwnd={cefHwnd}");
  348. }
  349. catch (Exception ex)
  350. {
  351. Global.writeLog("ReadSocialCardNew", "1-获取CEF窗口失败", ex.Message);
  352. }
  353. // 禁用CEF Browser窗口
  354. if (cefHwnd != IntPtr.Zero)
  355. {
  356. WinApi.EnableWindow(cefHwnd, false);
  357. Global.writeLog("ReadSocialCardNew", "2-禁用CEF窗口", $"Enabled={WinApi.IsWindowEnabled(cefHwnd)}");
  358. }
  359. // 禁用当前窗口
  360. this.Enabled = false;
  361. Global.writeLog("ReadSocialCardNew", "3-禁用当前窗口", $"this.Enabled={this.Enabled}");
  362. // 将当前窗口置顶并激活(确保COM窗口在它前面弹出)
  363. this.TopMost = true;
  364. this.BringToFront();
  365. this.Activate();
  366. Application.DoEvents();
  367. Thread.Sleep(100);
  368. Global.writeLog("ReadSocialCardNew", "4-置顶当前窗口", $"hwnd={this.Handle}");
  369. this.TopMost = false; // 临时置顶后立即取消,让COM窗口有机会置顶
  370. // 在后台线程执行COM控件调用
  371. Task.Run(() =>
  372. {
  373. try
  374. {
  375. string errorMsg = "";
  376. Global.writeLog("ReadSocialCardNew", "5-后台线程开始", "");
  377. // 从UI控件获取参数值(需要Invoke确保线程安全)
  378. string certNo = "";
  379. string certTypeCode = "";
  380. string betaFlag = "";
  381. string noCardTag = "";
  382. this.Invoke(new Action(() =>
  383. {
  384. certNo = txtCertNo.Text.Trim();
  385. certTypeCode = cbCertType.SelectedValue?.ToString() ?? "";
  386. if (cbxNoCardTag.Checked)
  387. {
  388. noCardTag = "1";
  389. }
  390. else
  391. {
  392. switch (certType)
  393. {
  394. case "01":
  395. noCardTag = "1";
  396. break;
  397. case "02":
  398. noCardTag = "2";
  399. break;
  400. default:
  401. noCardTag = "";
  402. break;
  403. }
  404. }
  405. }));
  406. // COM控件调用需要在STA线程
  407. string input = "{" +
  408. "\"begntime\": \"\"," +
  409. "\"no_card_tag\": \"" + noCardTag + "\"," +
  410. "\"certno\": \"" + certNo + "\"," +
  411. "\"psn_cert_typ\": \"" + certTypeCode + "\"," +
  412. "\"beta_flag\": \"" + betaFlag + "\"," +
  413. "\"cro_prov_flag\": \"\"" +
  414. "}";
  415. int result = -1;
  416. InvokeComCenter2026 carder = new InvokeComCenter2026();
  417. // 使用 STA 线程调用 COM 控件
  418. Global.writeLog("ReadSocialCardNew", "6-准备启动STA线程", input);
  419. Thread staThread = new Thread(() =>
  420. {
  421. Global.writeLog("ReadSocialCardNew", "7-STA线程开始", "");
  422. // 调用读卡
  423. result = carder.Business("1001", ref input, ref errorMsg);
  424. Global.writeLog("ReadSocialCardNew", "8-读卡完成", $"result={result}");
  425. });
  426. staThread.SetApartmentState(ApartmentState.STA);
  427. staThread.Start();
  428. staThread.Join();
  429. Global.writeLog("ReadSocialCardNew", "9-后台线程结束", "");
  430. // 回到UI线程更新界面
  431. this.Invoke(new Action(() =>
  432. {
  433. Global.writeLog("ReadSocialCardNew", "10-恢复窗口", "");
  434. // 恢复CEF Browser窗口
  435. if (cefHwnd != IntPtr.Zero)
  436. {
  437. WinApi.EnableWindow(cefHwnd, true);
  438. Global.writeLog("ReadSocialCardNew", "11-CEF窗口已恢复", $"Enabled={WinApi.IsWindowEnabled(cefHwnd)}");
  439. }
  440. // 恢复当前窗口
  441. this.Enabled = true;
  442. this.BringToFront();
  443. this.Activate();
  444. btnReadCard.Enabled = true;
  445. btnReadCard.Text = "读 卡";
  446. if (result != 0)
  447. {
  448. MessageBox.Show("读社保卡失败:" + errorMsg, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
  449. return;
  450. }
  451. // 更新界面上的单选按钮
  452. UpdateRadioButton(CertType);
  453. // 解析1001返回的多行数据
  454. JObject joRtn = JObject.Parse(errorMsg);
  455. ParseAndShowPatientList(joRtn);
  456. }));
  457. }
  458. catch (Exception ex)
  459. {
  460. this.Invoke(new Action(() =>
  461. {
  462. // 恢复CEF Browser窗口
  463. if (cefHwnd != IntPtr.Zero)
  464. {
  465. WinApi.EnableWindow(cefHwnd, true);
  466. }
  467. // 恢复当前窗口
  468. this.Enabled = true;
  469. this.BringToFront();
  470. btnReadCard.Enabled = true;
  471. btnReadCard.Text = "读 卡";
  472. MessageBox.Show("读社保卡失败:" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
  473. }));
  474. }
  475. });
  476. }
  477. /// <summary>
  478. /// 读取社保卡(方法二:找到COM窗口并置顶)
  479. /// </summary>
  480. /// <param name="certType">证件类型</param>
  481. private void ReadSocialCardNewTwo(string certType)
  482. {
  483. // 获取CEF Browser窗口句柄并禁用
  484. IntPtr cefHwnd = IntPtr.Zero;
  485. try
  486. {
  487. cefHwnd = WinApi.GetWindowsHandle("prBrowser");
  488. Global.writeLog("ReadSocialCardNewTwo", "1-获取CEF窗口", $"hwnd={cefHwnd}");
  489. }
  490. catch (Exception ex)
  491. {
  492. Global.writeLog("ReadSocialCardNewTwo", "1-获取CEF窗口失败", ex.Message);
  493. }
  494. // 禁用CEF Browser窗口
  495. if (cefHwnd != IntPtr.Zero)
  496. {
  497. WinApi.EnableWindow(cefHwnd, false);
  498. Global.writeLog("ReadSocialCardNewTwo", "2-禁用CEF窗口", "");
  499. }
  500. // 禁用当前窗口
  501. this.Enabled = false;
  502. Global.writeLog("ReadSocialCardNewTwo", "3-禁用当前窗口", "");
  503. // 给系统时间完成禁用操作
  504. Application.DoEvents();
  505. Thread.Sleep(100);
  506. Global.writeLog("ReadSocialCardNewTwo", "4-准备调用COM", "");
  507. // 在后台线程执行COM控件调用
  508. Task.Run(() =>
  509. {
  510. try
  511. {
  512. string errorMsg = "";
  513. Global.writeLog("ReadSocialCardNewTwo", "5-后台线程开始", "");
  514. // 从UI控件获取参数值
  515. string certNo = "";
  516. string certTypeCode = "";
  517. string betaFlag = "";
  518. string noCardTag = "";
  519. this.Invoke(new Action(() =>
  520. {
  521. certNo = txtCertNo.Text.Trim();
  522. certTypeCode = cbCertType.SelectedValue?.ToString() ?? "";
  523. if (cbxNoCardTag.Checked)
  524. {
  525. noCardTag = "1";
  526. }
  527. else
  528. {
  529. switch (certType)
  530. {
  531. case "01":
  532. noCardTag = "1";
  533. break;
  534. case "02":
  535. noCardTag = "2";
  536. break;
  537. default:
  538. noCardTag = "";
  539. break;
  540. }
  541. }
  542. }));
  543. string input = "{" +
  544. "\"begntime\": \"\"," +
  545. "\"no_card_tag\": \"" + noCardTag + "\"," +
  546. "\"certno\": \"" + certNo + "\"," +
  547. "\"psn_cert_typ\": \"" + certTypeCode + "\"," +
  548. "\"beta_flag\": \"" + betaFlag + "\"," +
  549. "\"cro_prov_flag\": \"\"" +
  550. "}";
  551. int result = -1;
  552. InvokeComCenter2026 carder = new InvokeComCenter2026();
  553. // 使用 STA 线程调用 COM 控件
  554. Thread staThread = new Thread(() =>
  555. {
  556. Global.writeLog("ReadSocialCardNewTwo", "6-STA线程开始", "开始调用COM");
  557. // 在单独的线程中循环查找并置顶COM窗口(枚举所有窗口)
  558. Thread searchThread = new Thread(() =>
  559. {
  560. int count = 0;
  561. while (count < 50) // 最多等待5秒
  562. {
  563. IntPtr comHwnd = WinApi.FindAndSetTopComWindowAll(this.Handle);
  564. if (comHwnd != IntPtr.Zero)
  565. {
  566. string comTitle = WinApi.GetComWindowTitle();
  567. Global.writeLog("ReadSocialCardNewTwo", "6.5-找到COM窗口", $"hwnd={comHwnd}, 窗口标题={comTitle}");
  568. break;
  569. }
  570. Thread.Sleep(100);
  571. count++;
  572. }
  573. if (count >= 50)
  574. {
  575. Global.writeLog("ReadSocialCardNewTwo", "6.5-未找到COM窗口", "超时未找到");
  576. }
  577. });
  578. searchThread.IsBackground = true;
  579. searchThread.Start();
  580. // 调用读卡
  581. result = carder.Business("1001", ref input, ref errorMsg);
  582. Global.writeLog("ReadSocialCardNewTwo", "7-读卡完成", $"result={result}");
  583. });
  584. staThread.SetApartmentState(ApartmentState.STA);
  585. staThread.Start();
  586. staThread.Join();
  587. Global.writeLog("ReadSocialCardNewTwo", "8-后台线程结束", "");
  588. // 回到UI线程更新界面
  589. this.Invoke(new Action(() =>
  590. {
  591. Global.writeLog("ReadSocialCardNewTwo", "9-恢复窗口", "");
  592. // 恢复CEF Browser窗口
  593. if (cefHwnd != IntPtr.Zero)
  594. {
  595. WinApi.EnableWindow(cefHwnd, true);
  596. Global.writeLog("ReadSocialCardNewTwo", "10-CEF窗口已恢复", "");
  597. }
  598. // 恢复当前窗口
  599. this.Enabled = true;
  600. this.BringToFront();
  601. this.Activate();
  602. btnReadCard.Enabled = true;
  603. btnReadCard.Text = "读 卡";
  604. if (result != 0)
  605. {
  606. MessageBox.Show("读社保卡失败:" + errorMsg, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
  607. return;
  608. }
  609. UpdateRadioButton(CertType);
  610. JObject joRtn = JObject.Parse(errorMsg);
  611. ParseAndShowPatientList(joRtn);
  612. }));
  613. }
  614. catch (Exception ex)
  615. {
  616. this.Invoke(new Action(() =>
  617. {
  618. if (cefHwnd != IntPtr.Zero)
  619. {
  620. WinApi.EnableWindow(cefHwnd, true);
  621. }
  622. this.Enabled = true;
  623. this.BringToFront();
  624. btnReadCard.Enabled = true;
  625. btnReadCard.Text = "读 卡";
  626. MessageBox.Show("读社保卡失败:" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
  627. }));
  628. }
  629. });
  630. }
  631. /// <summary>
  632. /// 读取扫脸
  633. /// </summary>
  634. private void ReadFaceCard()
  635. {
  636. try
  637. {
  638. CardReader reader = new CardReader();
  639. string msg;
  640. int result = reader.FaceRecognition(out msg);
  641. btnReadCard.Enabled = true;
  642. btnReadCard.Text = "读 卡";
  643. if (result != 0)
  644. {
  645. MessageBox.Show("人脸识别失败:" + msg, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
  646. return;
  647. }
  648. // 解析人脸识别返回的JSON数据
  649. JObject joRtn = JObject.Parse(msg);
  650. string code = JsonHelper.getDestValue(joRtn, "code");
  651. if (code != "0")
  652. {
  653. string errorMsg = JsonHelper.getDestValue(joRtn, "message");
  654. MessageBox.Show("人脸识别失败:" + errorMsg, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
  655. return;
  656. }
  657. // 获取 data 对象
  658. JObject dataObj = joRtn.SelectToken("data") as JObject;
  659. if (dataObj == null)
  660. {
  661. MessageBox.Show("未获取到人脸识别数据!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
  662. return;
  663. }
  664. // 提取关键信息
  665. string userName = JsonHelper.getDestValue(dataObj, "userName");
  666. string idNo = JsonHelper.getDestValue(dataObj, "idNo");
  667. string idType = JsonHelper.getDestValue(dataObj, "idType");
  668. string insuOrg = JsonHelper.getDestValue(dataObj, "insuOrg");
  669. string ecToken = JsonHelper.getDestValue(dataObj, "ecToken");
  670. string birthday = JsonHelper.getDestValue(dataObj, "birthday");
  671. string gender = JsonHelper.getDestValue(dataObj, "gender");
  672. // 清空现有数据
  673. dgvPatientInfo.DataSource = null;
  674. dgvPatientInfo.Rows.Clear();
  675. dgvPatientInfo.Columns.Clear();
  676. InitPatientInfoGrid();
  677. // 添加人脸识别数据到表格(只显示单条)
  678. int rowIndex = dgvPatientInfo.Rows.Add(userName, gender, idNo, "", insuOrg, "");
  679. // 保存原始数据到行标签
  680. JObject rowData = new JObject();
  681. rowData.Add("userName", userName);
  682. rowData.Add("idNo", idNo);
  683. rowData.Add("idType", idType);
  684. rowData.Add("insuOrg", insuOrg);
  685. rowData.Add("ecToken", ecToken);
  686. rowData.Add("birthday", birthday);
  687. rowData.Add("gender", gender);
  688. rowData.Add("certType", "05"); // 扫脸类型
  689. dgvPatientInfo.Rows[rowIndex].Tag = rowData;
  690. // 设置证件类型
  691. CertType = "05";
  692. // 更新单选按钮
  693. rbFace.Checked = true;
  694. MessageBox.Show("人脸识别成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
  695. }
  696. catch (Exception ex)
  697. {
  698. btnReadCard.Enabled = true;
  699. btnReadCard.Text = "读 卡";
  700. MessageBox.Show("人脸识别失败:" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
  701. }
  702. }
  703. /// <summary>
  704. /// 解析并显示患者列表(多行)
  705. /// </summary>
  706. private void ParseAndShowPatientList(JObject joRtn)
  707. {
  708. try
  709. {
  710. // 清空现有数据
  711. dgvPatientInfo.DataSource = null;
  712. dgvPatientInfo.Rows.Clear();
  713. // 获取返回代码
  714. string rtnCode = JsonHelper.getDestValue(joRtn, "code");
  715. string message = JsonHelper.getDestValue(joRtn, "message");
  716. // 检查返回状态
  717. if (rtnCode != "1" && rtnCode != "0")
  718. {
  719. MessageBox.Show("读卡失败:" + message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
  720. return;
  721. }
  722. // 获取 data 对象
  723. JObject dataObj = joRtn.SelectToken("data") as JObject;
  724. if (dataObj == null)
  725. {
  726. MessageBox.Show("未获取到数据!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
  727. return;
  728. }
  729. // 获取基本信息
  730. string certno = JsonHelper.getDestValue(dataObj, "certno");
  731. string psnName = JsonHelper.getDestValue(dataObj, "psn_name");
  732. string insuinfoCnt = JsonHelper.getDestValue(dataObj, "insuinfo_cnt");
  733. string cardSn = JsonHelper.getDestValue(dataObj, "card_sn");
  734. // 获取参保信息列表(insuinfo)
  735. JArray insuinfoList = dataObj.SelectToken("insuinfo") as JArray;
  736. if (insuinfoList == null || insuinfoList.Count == 0)
  737. {
  738. MessageBox.Show("未获取到参保信息!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  739. return;
  740. }
  741. // 清除现有列并重新设置
  742. dgvPatientInfo.Columns.Clear();
  743. InitPatientInfoGrid();
  744. // 填充数据 - 根据实际的JSON字段名
  745. foreach (JObject insuinfo in insuinfoList)
  746. {
  747. string insuplcAdmdvs = JsonHelper.getDestValue(insuinfo, "insuplc_admdvs");
  748. string insuplcAdmdvsName = JsonHelper.getDestValue(insuinfo, "insuplc_admdvs_name");
  749. string psnType = JsonHelper.getDestValue(insuinfo, "psn_type");
  750. string psnNo = JsonHelper.getDestValue(insuinfo, "psn_insu_rlts_id");
  751. string empName = JsonHelper.getDestValue(insuinfo, "emp_name");
  752. // 合并参保地和名称
  753. string insuplcFull = string.IsNullOrEmpty(insuplcAdmdvsName)
  754. ? insuplcAdmdvs
  755. : insuplcAdmdvs + " " + insuplcAdmdvsName;
  756. int rowIndex = dgvPatientInfo.Rows.Add(psnName, "", certno, psnNo, insuplcFull, psnType);
  757. // 保存原始数据到行标签
  758. JObject rowData = new JObject();
  759. rowData.Add("psn_name", psnName);
  760. rowData.Add("certno", certno);
  761. rowData.Add("card_sn", cardSn);
  762. rowData.Add("insuplc_admdvs", insuplcAdmdvs);
  763. rowData.Add("insuplc_admdvs_name", insuplcAdmdvsName);
  764. rowData.Add("psn_type", psnType);
  765. rowData.Add("psn_no", psnNo);
  766. rowData.Add("emp_name", empName);
  767. rowData.Add("insuinfo", insuinfo);
  768. rowData.Add("data", dataObj);
  769. dgvPatientInfo.Rows[rowIndex].Tag = rowData;
  770. }
  771. // 如果只有一条记录,自动选中
  772. if (dgvPatientInfo.Rows.Count == 1)
  773. {
  774. dgvPatientInfo.Rows[0].Selected = true;
  775. SelectPatientAndFillInfo(0);
  776. }
  777. }
  778. catch (Exception ex)
  779. {
  780. MessageBox.Show("解析患者列表失败:" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
  781. }
  782. }
  783. /// <summary>
  784. /// 选中患者并填充信息到全局变量
  785. /// </summary>
  786. private void SelectPatientAndFillInfo(int rowIndex)
  787. {
  788. if (rowIndex < 0 || rowIndex >= dgvPatientInfo.Rows.Count)
  789. return;
  790. JObject item = dgvPatientInfo.Rows[rowIndex].Tag as JObject;
  791. if (item == null)
  792. return;
  793. // 根据证件类型选择不同的读卡方式
  794. switch (CertType)
  795. {
  796. case "01":
  797. case "02":
  798. case "03":
  799. // 电子凭证、身份证、社保卡:都走COM组件调用方式
  800. // 获取data对象(包含基础信息)
  801. JObject dataObj = item.SelectToken("data") as JObject;
  802. // 获取insuinfo对象(包含参保信息)
  803. JObject insuinfo = item.SelectToken("insuinfo") as JObject;
  804. // 填充基础信息
  805. Global.pat.name = JsonHelper.getDestValue(item, "psn_name");
  806. Global.pat.certNO = JsonHelper.getDestValue(item, "certno");
  807. Global.pat.card.SN = JsonHelper.getDestValue(item, "card_sn");
  808. Global.pat.card.NO = JsonHelper.getDestValue(item, "card_sn");
  809. // 填充参保信息
  810. Global.pat.insuplc_admdvs = JsonHelper.getDestValue(insuinfo, "insuplc_admdvs");
  811. //Global.pat.psn_no = JsonHelper.getDestValue(insuinfo, "psn_insu_rlts_id");
  812. // 填充证件类型(从data中获取)
  813. Global.pat.mdtrtcertType = JsonHelper.getDestValue(dataObj, "mdtrt_cert_type");
  814. Global.pat.mdtrtcertNO = JsonHelper.getDestValue(dataObj, "mdtrt_cert_no");
  815. Global.pat.certType = JsonHelper.getDestValue(dataObj, "psn_cert_type");
  816. break;
  817. case "05":
  818. // 填充基础信息
  819. Global.pat.name = JsonHelper.getDestValue(item, "userName");
  820. Global.pat.certNO = JsonHelper.getDestValue(item, "idNo");
  821. Global.pat.IDType = JsonHelper.getDestValue(item, "idType");
  822. Global.pat.card.SN = "";
  823. Global.pat.card.NO = "";
  824. // 填充参保信息
  825. Global.pat.insuplc_admdvs = JsonHelper.getDestValue(item, "insuOrg");
  826. Global.pat.psn_no = "";
  827. // 填充证件类型(从data中获取)
  828. Global.pat.mdtrtcertType = "05";
  829. Global.pat.mdtrtcertNO = JsonHelper.getDestValue(item, "ecToken");
  830. Global.pat.certType = JsonHelper.getDestValue(item, "idType");
  831. break;
  832. default:
  833. MessageBox.Show("不支持的证件类型!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
  834. break;
  835. }
  836. }
  837. /// <summary>
  838. /// 更新证件类型单选按钮
  839. /// </summary>
  840. private void UpdateRadioButton(string certType)
  841. {
  842. switch (certType)
  843. {
  844. case "01":
  845. rbECToken.Checked = true;
  846. break;
  847. case "02":
  848. rbIDCard.Checked = true;
  849. break;
  850. case "03":
  851. rbSocialCard.Checked = true;
  852. break;
  853. case "05":
  854. rbFace.Checked = true;
  855. break;
  856. }
  857. }
  858. /// <summary>
  859. /// DataGridView行选择变化事件
  860. /// </summary>
  861. private void dgvPatientInfo_SelectionChanged(object sender, EventArgs e)
  862. {
  863. if (dgvPatientInfo.SelectedRows.Count > 0)
  864. {
  865. int selectedIndex = dgvPatientInfo.SelectedRows[0].Index;
  866. SelectPatientAndFillInfo(selectedIndex);
  867. }
  868. }
  869. #endregion
  870. #region 确定取消按钮事件
  871. /// <summary>
  872. /// 确定按钮
  873. /// </summary>
  874. private void btnConfirm_Click(object sender, EventArgs e)
  875. {
  876. // 检查是否已选择患者
  877. if (dgvPatientInfo.SelectedRows.Count == 0)
  878. {
  879. MessageBox.Show("请先读卡并选择患者信息!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  880. return;
  881. }
  882. // 获取选中的患者信息
  883. int selectedIndex = dgvPatientInfo.SelectedRows[0].Index;
  884. SelectPatientAndFillInfo(selectedIndex);
  885. // 获取业务类型编码(从ComboBox获取代码)
  886. if (cbBusinessType.SelectedItem != null)
  887. {
  888. DataRowView drv = cbBusinessType.SelectedItem as DataRowView;
  889. if (drv != null)
  890. {
  891. BusinessType = drv["code"].ToString();
  892. }
  893. else
  894. {
  895. }
  896. }
  897. // 设置工伤标志
  898. IsWorkInjury = rbWorkInjury.Checked;
  899. // 保存到全局变量
  900. Global.pat.card.ecBizType = BusinessType;
  901. Global.pat.isWorkInjury = IsWorkInjury;
  902. this.DialogResult = DialogResult.OK;
  903. this.Close();
  904. }
  905. /// <summary>
  906. /// 取消按钮
  907. /// </summary>
  908. private void btnCancel_Click(object sender, EventArgs e)
  909. {
  910. this.DialogResult = DialogResult.Cancel;
  911. this.Close();
  912. }
  913. #endregion
  914. private void uiPanel5_Click(object sender, EventArgs e)
  915. {
  916. }
  917. private void rbFace_CheckedChanged(object sender, EventArgs e)
  918. {
  919. }
  920. private void cbxNoCardTag_CheckedChanged(object sender, EventArgs e)
  921. {
  922. // 根据无卡结算CheckBox状态控制证件号和证件类型控件的可用性
  923. bool isEnabled = cbxNoCardTag.Checked;
  924. txtCertNo.Enabled = isEnabled;
  925. cbCertType.Enabled = isEnabled;
  926. Global.pat.isNoCardSettle = cbxNoCardTag.Checked;
  927. }
  928. private void dgvPatientInfo_CellContentClick(object sender, DataGridViewCellEventArgs e)
  929. {
  930. }
  931. }
  932. }