index.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. /* eslint-disable no-inner-declarations */
  2. process.on('message', async (message, setHandle) => {
  3. try {
  4. const [dllPath, port] = require('path').join(message).split('|')
  5. process.send({ rescode: 0, msg: [dllPath, port] })
  6. const ffi = require('ffi')
  7. const ref = require('ref')
  8. const Struct = require('ref-struct')
  9. const RefArray = require('ref-array')
  10. const bufferTrim = require('buffertrim')
  11. const rescode = {
  12. 65536: 'success',
  13. 65537: 'fail',
  14. 66306: 'timeout',
  15. 66305: 'cancel'
  16. }
  17. const Sodo_RequestCardAndQrcode = Struct({
  18. transType: 'char',
  19. transDate: RefArray(ref.types.char, 3),
  20. transTime: RefArray(ref.types.char, 3),
  21. transAmt: 'int',
  22. transNo: RefArray(ref.types.char, 4),
  23. transOutBuf: RefArray(ref.types.char, 4096),
  24. lenTransOutbuf: 'int'
  25. })
  26. const CardInfo = Struct({
  27. recvBuf: RefArray(ref.types.char, 4096),
  28. lenRecv: 'int'
  29. })
  30. const SfzInfo = Struct({
  31. cmdOp1: ref.types.byte,
  32. cmdOp2: ref.types.byte,
  33. dataSend: RefArray(ref.types.char, 1024),
  34. lendataSend: 'int',
  35. recvBuf: RefArray(ref.types.byte, 4096),
  36. lenRecv: 'int'
  37. })
  38. let program = ffi.Library(dllPath, {
  39. Sodo_InitSerialPort: ['void', ['int', 'int']],
  40. // Sodo_InitHttps: ["void", ["int"]],
  41. Sodo_Start: ['int', []],
  42. Sodo_Stop: ['int', []],
  43. // Sodo_Stop: ["int", []],
  44. Sodo_SB_Process: ['int', [ref.refType(CardInfo)]],
  45. Sodo_SB_Psam_Process_GetAllInfo: ['int', ['int*', 'int*', 'int']],
  46. '_Sodo_Sfz_Process@4': ['int', [ref.refType(SfzInfo)]],
  47. '_Sodo_RequestCardAndQrcode@4': [
  48. 'int',
  49. [ref.refType(Sodo_RequestCardAndQrcode)]
  50. ]
  51. })
  52. function search () {
  53. try {
  54. const cardAndQrcode = new Sodo_RequestCardAndQrcode()
  55. cardAndQrcode.transType = 0x60
  56. cardAndQrcode.transDate = [0x20, 0x12, 0x12]
  57. cardAndQrcode.transNo = [0x11, 0x22, 0x33, 0x44]
  58. cardAndQrcode.transAmt = 1
  59. const ret = program['_Sodo_RequestCardAndQrcode@4'](cardAndQrcode.ref())
  60. if (rescode[ret] === 'timeout' || rescode[ret] === 'cancel') {
  61. process.send({ rescode: 0, msg: '连接超时或设备出错' })
  62. exit()
  63. return
  64. }
  65. if (rescode[ret] === 'success') {
  66. process.send({ rescode: 0, ret, message: '查询成功' })
  67. const transOutBuf = bufferTrim
  68. .trimEnd(Buffer.from(cardAndQrcode.transOutBuf))
  69. .toString()
  70. process.send({ rescode: 2, ret, transOutBuf })
  71. const res = isJSON(transOutBuf) ? JSON.parse(transOutBuf) : {}
  72. console.log('寻卡结果', res)
  73. process.send({ rescode: 2, msg: '寻卡结果', data: res })
  74. let id
  75. switch (res.cardType) {
  76. case '1': // 社保卡
  77. id = getSBCard()
  78. break
  79. case '2': // 身份证
  80. id = getSFZCard()
  81. break
  82. case '187': // 扫码
  83. id = getQRcode(res)
  84. break
  85. }
  86. console.log('id', id)
  87. }
  88. setTimeout(() => {
  89. search()
  90. }, 500)
  91. } catch (e) {
  92. process.send(e)
  93. }
  94. }
  95. function getSBCard () {
  96. // console.log("sb");
  97. const cardInfo = new CardInfo()
  98. const ret0 = program.Sodo_SB_Process(cardInfo.ref())
  99. console.log('[ ret0 ]', ret0)
  100. console.log('cardInfo', cardInfo, Buffer.from(cardInfo.recvBuf).toString())
  101. const res = Buffer.alloc(512)
  102. const inp = Buffer.alloc(512)
  103. const ret = program.Sodo_SB_Psam_Process_GetAllInfo(res.ref(), inp.ref(), 4)
  104. if (rescode[ret] !== 'success') return
  105. const data = bufferTrim
  106. .trimEnd(Buffer.from(res))
  107. .toString()
  108. .trim()
  109. .split('|')
  110. // 返回:卡片发行机构代码|社保卡卡号|卡片识别码|卡复位的信息|卡片版本|发行日期|有效日期
  111. const params = {
  112. qrcode_info: data[2], // 必填,社保卡使用卡识别码,电子社保卡使用二维码原始字符串, (应该扫码或者读卡机自动获取)
  113. card_type: '01', // 社保卡01 , 二维码04
  114. card_number: data[1], // 9位社保卡号(当介质类型为社保卡时必填)
  115. card_version: data[4], // 卡规范版本
  116. publish_date: data[5], // 发卡日期
  117. expiry_date: data[6], // 卡有效期
  118. card_rest_info: data[3] // 卡复位信息
  119. }
  120. console.log('[ params ]', params)
  121. process.send({
  122. rescode: 1,
  123. msg: '社保卡',
  124. data: params,
  125. cardInfo: bufferTrim.trimEnd(Buffer.from(cardInfo.recvBuf)).toString()
  126. })
  127. return params
  128. }
  129. function getSFZCard () {
  130. const cardInfo = new SfzInfo()
  131. cardInfo.cmdOp1 = 0x03
  132. cardInfo.cmdOp2 = 0x00
  133. const ret = program['_Sodo_Sfz_Process@4'](cardInfo.ref())
  134. console.log('ret', ret)
  135. const idStr = Buffer.from(cardInfo.recvBuf)
  136. .slice(7, 263)
  137. .toString('ucs2')
  138. if (
  139. !idStr
  140. .slice(61, 79)
  141. .trim()
  142. .replace(/\0/g, '').length
  143. ) { return }
  144. // if (!bufferTrim.trim()) return;
  145. console.log('%c [ idStr ]-109', idStr)
  146. const res = {
  147. name: idStr.slice(0, 15).trim(),
  148. sex: getSex(idStr.slice(15, 16)),
  149. nation: getNation(idStr.slice(16, 18)),
  150. idNum: idStr.slice(61, 79).trim(),
  151. address: idStr.slice(26, 61).trim(),
  152. begin: idStr.slice(94, 102).trim(),
  153. end: idStr.slice(102, 110).trim()
  154. }
  155. process.send({ rescode: 1, msg: '身份证', res })
  156. console.log('%c [ res ]-112', res)
  157. }
  158. function getQRcode (res) {
  159. const qrcode = Buffer.from(res.ID, 'base64').toString()
  160. const params = {
  161. qrcode_info: qrcode,
  162. card_type: '04'
  163. }
  164. console.log('params', params)
  165. process.send({ rescode: 1, msg: '扫码', data: params })
  166. return params
  167. }
  168. function isJSON (str) {
  169. try {
  170. JSON.parse(str)
  171. } catch (e) {
  172. return false
  173. }
  174. return true
  175. }
  176. function getSex (code) {
  177. switch (parseInt(code)) {
  178. case 0:
  179. return '未知的性别'
  180. case 1:
  181. return '男'
  182. case 2:
  183. return '女'
  184. case 9:
  185. return '未说明的性别'
  186. }
  187. return '未定义的性别'
  188. }
  189. function getNation (code) {
  190. switch (parseInt(code)) {
  191. case 1:
  192. return '汉'
  193. case 2:
  194. return '蒙古'
  195. case 3:
  196. return '回'
  197. case 4:
  198. return '藏'
  199. case 5:
  200. return '维吾尔'
  201. case 6:
  202. return '苗'
  203. case 7:
  204. return '彝'
  205. case 8:
  206. return '壮'
  207. case 9:
  208. return '布依'
  209. case 10:
  210. return '朝鲜'
  211. case 11:
  212. return '满'
  213. case 12:
  214. return '侗'
  215. case 13:
  216. return '瑶'
  217. case 14:
  218. return '白'
  219. case 15:
  220. return '土家'
  221. case 16:
  222. return '哈尼'
  223. case 17:
  224. return '哈萨克'
  225. case 18:
  226. return '傣'
  227. case 19:
  228. return '黎'
  229. case 20:
  230. return '傈僳'
  231. case 21:
  232. return '佤'
  233. case 22:
  234. return '畲'
  235. case 23:
  236. return '高山'
  237. case 24:
  238. return '拉祜'
  239. case 25:
  240. return '水'
  241. case 26:
  242. return '东乡'
  243. case 27:
  244. return '纳西'
  245. case 28:
  246. return '景颇'
  247. case 29:
  248. return '柯尔克孜'
  249. case 30:
  250. return '土'
  251. case 31:
  252. return '达斡尔'
  253. case 32:
  254. return '仫佬'
  255. case 33:
  256. return '羌'
  257. case 34:
  258. return '布朗'
  259. case 35:
  260. return '撒拉'
  261. case 36:
  262. return '毛难'
  263. case 37:
  264. return '仡佬'
  265. case 38:
  266. return '锡伯'
  267. case 39:
  268. return '阿昌'
  269. case 40:
  270. return '普米'
  271. case 41:
  272. return '塔吉克'
  273. case 42:
  274. return '怒'
  275. case 43:
  276. return '乌孜别克'
  277. case 44:
  278. return '俄罗斯'
  279. case 45:
  280. return '鄂温克'
  281. case 46:
  282. return '崩龙'
  283. case 47:
  284. return '保安'
  285. case 48:
  286. return '裕固'
  287. case 49:
  288. return '京'
  289. case 50:
  290. return '塔塔尔'
  291. case 51:
  292. return '独龙'
  293. case 52:
  294. return '鄂伦春'
  295. case 53:
  296. return '赫哲'
  297. case 54:
  298. return '门巴'
  299. case 55:
  300. return '珞巴'
  301. case 56:
  302. return '基诺'
  303. }
  304. }
  305. function exit () {
  306. process.kill(process.pid)
  307. process.exit(0)
  308. }
  309. return new Promise((resolve, reject) => {
  310. program.Sodo_InitSerialPort(parseInt(port), 115200)
  311. console.log('已执行初始化串口', port)
  312. const ret = program.Sodo_Start()
  313. if (rescode[ret] !== 'success') {
  314. console.log('打开串口失败')
  315. process.send({ rescode: 0, msg: '打开串口失败' })
  316. exit()
  317. } else {
  318. process.send({ rescode: 0, ret })
  319. try {
  320. search()
  321. } catch (e) {
  322. process.send(e)
  323. }
  324. }
  325. })
  326. } catch (e) {
  327. process.send({ rescode: 0, e })
  328. }
  329. })