添加新中新二代证读取器支持
This commit is contained in:
File diff suppressed because one or more lines are too long
2
dist/index.html
vendored
2
dist/index.html
vendored
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Electron + React App</title>
|
<title>Electron + React App</title>
|
||||||
<script type="module" crossorigin src="./assets/index-d39aadb6.js"></script>
|
<script type="module" crossorigin src="./assets/index-3360d21b.js"></script>
|
||||||
<link rel="stylesheet" href="./assets/index-0c3a5195.css">
|
<link rel="stylesheet" href="./assets/index-0c3a5195.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
170
electron/idcard-worker.js
Normal file
170
electron/idcard-worker.js
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
const { parentPort } = require("worker_threads");
|
||||||
|
const koffi = require("koffi");
|
||||||
|
const path = require("path");
|
||||||
|
const iconv = require("iconv-lite");
|
||||||
|
|
||||||
|
// 定义结构体
|
||||||
|
const IDCardData = koffi.struct("IDCardData", {
|
||||||
|
Name: koffi.array("char", 32),
|
||||||
|
Sex: koffi.array("char", 6),
|
||||||
|
Nation: koffi.array("char", 20),
|
||||||
|
Born: koffi.array("char", 18),
|
||||||
|
Address: koffi.array("char", 72),
|
||||||
|
IDCardNo: koffi.array("char", 38),
|
||||||
|
GrantDept: koffi.array("char", 32),
|
||||||
|
UserLifeBegin: koffi.array("char", 18),
|
||||||
|
UserLifeEnd: koffi.array("char", 18),
|
||||||
|
reserved: koffi.array("char", 38),
|
||||||
|
PhotoFileName: koffi.array("char", 255),
|
||||||
|
});
|
||||||
|
|
||||||
|
let lib = null;
|
||||||
|
let running = false;
|
||||||
|
|
||||||
|
// 解码 GBK 字符串
|
||||||
|
function decodeGBK(buffer) {
|
||||||
|
// 找到第一个 null 字节 (0x00) 的位置
|
||||||
|
let nullIndex = -1;
|
||||||
|
for (let i = 0; i < buffer.length; i++) {
|
||||||
|
if (buffer[i] === 0) {
|
||||||
|
nullIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果找到了 null,截取前面的部分;否则使用整个 buffer
|
||||||
|
const validBuffer = nullIndex !== -1 ? buffer.slice(0, nullIndex) : buffer;
|
||||||
|
return iconv.decode(validBuffer, "gbk").trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载 DLL
|
||||||
|
function loadDll() {
|
||||||
|
if (lib) return true;
|
||||||
|
try {
|
||||||
|
const fs = require("fs");
|
||||||
|
const dllNames = ["Syn_IDCardRead.dll", "SynIDCardRead.dll"];
|
||||||
|
|
||||||
|
// 确定 DLL 目录:优先检查生产环境 resources/xzx,否则使用开发环境 resources/xzx
|
||||||
|
let dllDir = path.join(process.cwd(), "resources", "xzx");
|
||||||
|
if (process.resourcesPath) {
|
||||||
|
const prodDir = path.join(process.resourcesPath, "xzx");
|
||||||
|
if (fs.existsSync(prodDir)) {
|
||||||
|
dllDir = prodDir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let dllPath = null;
|
||||||
|
for (const name of dllNames) {
|
||||||
|
const p = path.join(dllDir, name);
|
||||||
|
if (fs.existsSync(p)) {
|
||||||
|
dllPath = p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dllPath) {
|
||||||
|
throw new Error(`DLL not found in ${dllDir}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
lib = koffi.load(dllPath);
|
||||||
|
|
||||||
|
return {
|
||||||
|
Syn_FindUSBReader: lib.func("int Syn_FindUSBReader()"),
|
||||||
|
Syn_USBOpenPort: lib.func("int Syn_USBOpenPort(int)"),
|
||||||
|
Syn_USBClosePort: lib.func("int Syn_USBClosePort(int)"),
|
||||||
|
Syn_USBStartFindIDCard: lib.func(
|
||||||
|
"int Syn_USBStartFindIDCard(int, uint8*, int)"
|
||||||
|
),
|
||||||
|
Syn_USBSelectIDCard: lib.func(
|
||||||
|
"int Syn_USBSelectIDCard(int, uint8*, int)"
|
||||||
|
),
|
||||||
|
Syn_ReadMsg: lib.func("int Syn_ReadMsg(int, int, _Out_ IDCardData*)"),
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
parentPort.postMessage({
|
||||||
|
type: "error",
|
||||||
|
payload: `Failed to load DLL: ${err.message}`,
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function startListen() {
|
||||||
|
if (running) return;
|
||||||
|
running = true;
|
||||||
|
|
||||||
|
const api = loadDll();
|
||||||
|
if (!api) {
|
||||||
|
running = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let port = api.Syn_FindUSBReader();
|
||||||
|
if (port <= 0) port = 1001;
|
||||||
|
|
||||||
|
const openRes = api.Syn_USBOpenPort(port);
|
||||||
|
if (openRes !== 0) {
|
||||||
|
parentPort.postMessage({
|
||||||
|
type: "error",
|
||||||
|
payload: `Open port ${port} failed: ${openRes}`,
|
||||||
|
});
|
||||||
|
running = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const iin = Buffer.alloc(4);
|
||||||
|
const sn = Buffer.alloc(8);
|
||||||
|
// IDCardData 结构体大小计算: 32+6+20+18+72+38+32+18+18+38+255 = 547 字节
|
||||||
|
// koffi 会自动处理结构体内存分配
|
||||||
|
|
||||||
|
while (running) {
|
||||||
|
// 寻卡
|
||||||
|
api.Syn_USBStartFindIDCard(port, iin, 0);
|
||||||
|
// 选卡
|
||||||
|
api.Syn_USBSelectIDCard(port, sn, 0);
|
||||||
|
|
||||||
|
// 读卡
|
||||||
|
const data = {}; // koffi 输出对象
|
||||||
|
const ret = api.Syn_ReadMsg(port, 0, data);
|
||||||
|
|
||||||
|
if (ret === 0 && data) {
|
||||||
|
const payload = {
|
||||||
|
name: decodeGBK(Buffer.from(data.Name)),
|
||||||
|
sex: decodeGBK(Buffer.from(data.Sex)),
|
||||||
|
nation: decodeGBK(Buffer.from(data.Nation)),
|
||||||
|
born: decodeGBK(Buffer.from(data.Born)),
|
||||||
|
address: decodeGBK(Buffer.from(data.Address)),
|
||||||
|
id_card_no: decodeGBK(Buffer.from(data.IDCardNo)),
|
||||||
|
grant_dept: decodeGBK(Buffer.from(data.GrantDept)),
|
||||||
|
life_begin: decodeGBK(Buffer.from(data.UserLifeBegin)),
|
||||||
|
life_end: decodeGBK(Buffer.from(data.UserLifeEnd)),
|
||||||
|
photo_path: decodeGBK(Buffer.from(data.PhotoFileName)),
|
||||||
|
};
|
||||||
|
|
||||||
|
parentPort.postMessage({ type: "data", payload });
|
||||||
|
|
||||||
|
// 读到卡后暂停一下,避免重复读取太快
|
||||||
|
await new Promise((r) => setTimeout(r, 500));
|
||||||
|
} else {
|
||||||
|
// 没读到卡,稍微等待
|
||||||
|
await new Promise((r) => setTimeout(r, 150));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
api.Syn_USBClosePort(port);
|
||||||
|
} catch (err) {
|
||||||
|
parentPort.postMessage({
|
||||||
|
type: "error",
|
||||||
|
payload: `Worker error: ${err.message}`,
|
||||||
|
});
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parentPort.on("message", (msg) => {
|
||||||
|
if (msg === "start") {
|
||||||
|
startListen();
|
||||||
|
} else if (msg === "stop") {
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -1,42 +1,95 @@
|
|||||||
const { app, BrowserWindow } = require("electron");
|
const { app, BrowserWindow, ipcMain } = require('electron');
|
||||||
const path = require("path");
|
const path = require('path');
|
||||||
|
const { Worker } = require('worker_threads');
|
||||||
|
|
||||||
|
let idCardWorker = null;
|
||||||
|
let mainWindow = null;
|
||||||
|
|
||||||
|
function createIdCardWorker() {
|
||||||
|
if (idCardWorker) return;
|
||||||
|
|
||||||
|
idCardWorker = new Worker(path.join(__dirname, 'idcard-worker.js'));
|
||||||
|
|
||||||
|
idCardWorker.on('message', (msg) => {
|
||||||
|
if (!mainWindow) return;
|
||||||
|
|
||||||
|
if (msg.type === 'data') {
|
||||||
|
mainWindow.webContents.send('idcard-data', { payload: msg.payload });
|
||||||
|
} else if (msg.type === 'error') {
|
||||||
|
mainWindow.webContents.send('idcard-error', { payload: msg.payload });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
idCardWorker.on('error', (err) => {
|
||||||
|
console.error('Worker error:', err);
|
||||||
|
});
|
||||||
|
|
||||||
|
idCardWorker.on('exit', (code) => {
|
||||||
|
if (code !== 0) console.error(`Worker stopped with exit code ${code}`);
|
||||||
|
idCardWorker = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function createWindow() {
|
function createWindow() {
|
||||||
const win = new BrowserWindow({
|
const win = new BrowserWindow({
|
||||||
width: 1080,
|
width: 1080,
|
||||||
height: 1920,
|
height: 1920,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
preload: path.join(__dirname, "preload.js"),
|
preload: path.join(__dirname, 'preload.js'),
|
||||||
nodeIntegration: false,
|
nodeIntegration: false,
|
||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mainWindow = win;
|
||||||
|
|
||||||
// 开发环境下加载 Vite 开发服务器地址
|
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD> Vite <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ
|
||||||
// 生产环境下加载打包后的 index.html
|
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD>ش<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> index.html
|
||||||
const isDev = !app.isPackaged;
|
const isDev = !app.isPackaged;
|
||||||
|
|
||||||
if (isDev) {
|
if (isDev) {
|
||||||
win.loadURL("http://localhost:5173");
|
win.loadURL('http://localhost:5173');
|
||||||
// 打开开发者工具
|
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߹<EFBFBD><EFBFBD><EFBFBD>
|
||||||
win.webContents.openDevTools();
|
win.webContents.openDevTools();
|
||||||
} else {
|
} else {
|
||||||
win.loadFile(path.join(__dirname, "../dist/index.html"));
|
win.loadFile(path.join(__dirname, '../dist/index.html'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
createWindow();
|
createWindow();
|
||||||
|
createIdCardWorker();
|
||||||
|
|
||||||
app.on("activate", () => {
|
// IPC <20><><EFBFBD><EFBFBD>
|
||||||
|
ipcMain.handle('start_idcard_listen', () => {
|
||||||
|
if (idCardWorker) {
|
||||||
|
idCardWorker.postMessage('start');
|
||||||
|
} else {
|
||||||
|
createIdCardWorker();
|
||||||
|
idCardWorker.postMessage('start');
|
||||||
|
}
|
||||||
|
return 'started';
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('stop_idcard_listen', () => {
|
||||||
|
if (idCardWorker) {
|
||||||
|
idCardWorker.postMessage('stop');
|
||||||
|
}
|
||||||
|
return 'stopped';
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
if (BrowserWindow.getAllWindows().length === 0) {
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
createWindow();
|
createWindow();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on("window-all-closed", () => {
|
app.on('window-all-closed', () => {
|
||||||
if (process.platform !== "darwin") {
|
if (idCardWorker) {
|
||||||
|
idCardWorker.terminate();
|
||||||
|
}
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
app.quit();
|
app.quit();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
const { contextBridge, ipcRenderer } = require("electron");
|
const { contextBridge, ipcRenderer } = require('electron');
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld("electronAPI", {
|
contextBridge.exposeInMainWorld('electronAPI', {
|
||||||
// 在这里暴露安全的 API 给渲染进程
|
startIdCardListen: () => ipcRenderer.invoke('start_idcard_listen'),
|
||||||
// example: sendMessage: (message) => ipcRenderer.send('message', message)
|
stopIdCardListen: () => ipcRenderer.invoke('stop_idcard_listen'),
|
||||||
|
onIdCardData: (callback) => ipcRenderer.on('idcard-data', (event, value) => callback(value)),
|
||||||
|
onIdCardError: (callback) => ipcRenderer.on('idcard-error', (event, value) => callback(value)),
|
||||||
|
removeIdCardListeners: () => {
|
||||||
|
ipcRenderer.removeAllListeners('idcard-data');
|
||||||
|
ipcRenderer.removeAllListeners('idcard-error');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
61
package-lock.json
generated
61
package-lock.json
generated
@@ -9,6 +9,8 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"iconv-lite": "^0.7.0",
|
||||||
|
"koffi": "^2.14.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-router-dom": "^7.9.6"
|
"react-router-dom": "^7.9.6"
|
||||||
@@ -2533,6 +2535,18 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dmg-builder/node_modules/iconv-lite": {
|
||||||
|
"version": "0.6.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||||
|
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dmg-builder/node_modules/jsonfile": {
|
"node_modules/dmg-builder/node_modules/jsonfile": {
|
||||||
"version": "6.2.0",
|
"version": "6.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz",
|
||||||
@@ -3514,15 +3528,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/iconv-lite": {
|
"node_modules/iconv-lite": {
|
||||||
"version": "0.6.3",
|
"version": "0.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
|
||||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
"integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/express"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ieee754": {
|
"node_modules/ieee754": {
|
||||||
@@ -3731,6 +3748,15 @@
|
|||||||
"json-buffer": "3.0.1"
|
"json-buffer": "3.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/koffi": {
|
||||||
|
"version": "2.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/koffi/-/koffi-2.14.1.tgz",
|
||||||
|
"integrity": "sha512-IMFL3IbRDXacSIjs7pPbPxgNlJ2hUtawQXU2QPdr6iw38jmv5AesAUG8HPX00xl0PPA2BbEa3noTw1YdHY+gHg==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"funding": {
|
||||||
|
"url": "https://buymeacoffee.com/koromix"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lazy-val": {
|
"node_modules/lazy-val": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz",
|
||||||
@@ -4456,8 +4482,7 @@
|
|||||||
"node_modules/safer-buffer": {
|
"node_modules/safer-buffer": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/sanitize-filename": {
|
"node_modules/sanitize-filename": {
|
||||||
"version": "1.6.3",
|
"version": "1.6.3",
|
||||||
@@ -7025,6 +7050,15 @@
|
|||||||
"universalify": "^2.0.0"
|
"universalify": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"iconv-lite": {
|
||||||
|
"version": "0.6.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||||
|
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"jsonfile": {
|
"jsonfile": {
|
||||||
"version": "6.2.0",
|
"version": "6.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz",
|
||||||
@@ -7776,10 +7810,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"iconv-lite": {
|
"iconv-lite": {
|
||||||
"version": "0.6.3",
|
"version": "0.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
|
||||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
"integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||||
}
|
}
|
||||||
@@ -7937,6 +7970,11 @@
|
|||||||
"json-buffer": "3.0.1"
|
"json-buffer": "3.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"koffi": {
|
||||||
|
"version": "2.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/koffi/-/koffi-2.14.1.tgz",
|
||||||
|
"integrity": "sha512-IMFL3IbRDXacSIjs7pPbPxgNlJ2hUtawQXU2QPdr6iw38jmv5AesAUG8HPX00xl0PPA2BbEa3noTw1YdHY+gHg=="
|
||||||
|
},
|
||||||
"lazy-val": {
|
"lazy-val": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz",
|
||||||
@@ -8476,8 +8514,7 @@
|
|||||||
"safer-buffer": {
|
"safer-buffer": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"sanitize-filename": {
|
"sanitize-filename": {
|
||||||
"version": "1.6.3",
|
"version": "1.6.3",
|
||||||
|
|||||||
10
package.json
10
package.json
@@ -14,6 +14,8 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"iconv-lite": "^0.7.0",
|
||||||
|
"koffi": "^2.14.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-router-dom": "^7.9.6"
|
"react-router-dom": "^7.9.6"
|
||||||
@@ -39,6 +41,12 @@
|
|||||||
"dist/**/*",
|
"dist/**/*",
|
||||||
"electron/**/*"
|
"electron/**/*"
|
||||||
],
|
],
|
||||||
|
"extraResources": [
|
||||||
|
{
|
||||||
|
"from": "resources/xzx",
|
||||||
|
"to": "xzx"
|
||||||
|
}
|
||||||
|
],
|
||||||
"win": {
|
"win": {
|
||||||
"target": [
|
"target": [
|
||||||
"nsis",
|
"nsis",
|
||||||
@@ -46,4 +54,4 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,9 @@ files:
|
|||||||
- filter:
|
- filter:
|
||||||
- dist/**/*
|
- dist/**/*
|
||||||
- electron/**/*
|
- electron/**/*
|
||||||
|
extraResources:
|
||||||
|
- from: resources/xzx
|
||||||
|
to: xzx
|
||||||
win:
|
win:
|
||||||
target:
|
target:
|
||||||
- nsis
|
- nsis
|
||||||
|
|||||||
Binary file not shown.
BIN
release/win-unpacked/resources/xzx/GetCursorPos.dll
Normal file
BIN
release/win-unpacked/resources/xzx/GetCursorPos.dll
Normal file
Binary file not shown.
1
release/win-unpacked/resources/xzx/License.dat
Normal file
1
release/win-unpacked/resources/xzx/License.dat
Normal file
@@ -0,0 +1 @@
|
|||||||
|
d8838bccad0c19e847b9e73f4432b951b6f035fd8c19f5474e30db5a0e4fa4c99b57c01af79161850b95d3f99a6b0b6074f18224ec7c44f28bc243be06f8f2b96e370f5ca724c01f1bd0e289afdd9eeef7e33d42a5113ddd4818a47b33449487baec2099a50d5e3dde32bdf66d979982a68d0d60a1200990ebf8a4827b7db3d1e83f9ad9d9946267fe830c48bbe025a5ebb99b85c7f1cf93de2beb22c8e9766e5ef526242b01f5251d8a768780026add2d2d8fb9ffccb86f8779221b01d206e586d96b83839b30006910a4bca6438fb5d5b2900431f8ecab50a9f18d0e7e8abec7b212fdc9ab667f08dd3eef14ecbdb24910466f45be92d0a085ff81d7362b828847c29be579942b63b9eb26b2441b5ef20f5a012431d263ded3f5fe434111b833612464bf4df18ae06c536b6895d240387774c3b438d5f0745c7a0d3ce963e82fc8df603f6fa526e8bd1fc51e2509e0840f3bbbde7bc3fec9e837b5aa744a9ae4449c974e26d787e475f73dbc3ee9c73cc258f38b79c413453fd4fe732bed57ba9d0312d2bcaf333a5c82d92a269a7ccaf27273a178feb95028f8f0805675a6199abbd8b47756b4543269a35025438794cd32410ac19c77526c4b94b93d091069056df1dda0f49298d753a317850c7104f94067ac9cc4d5b3d377f10627d21c12a4c066347eb05370fbe9e0658c1ec1803d43ed71509f5cdb25d60f505ef7527c405d3ea05bb381436dd3622484a1ff7263e4d93f275493332af3f77d28a13a0fa0eb810b7d25a378f6b8313ab3bcb44131ca3500670b0321aa95b077cef85d348e13315c2d2d42795e41569162986755709d099b59ee320e6caf422497234251d07d697bb3f3e5ad6d15d80fd85da016e7075bf84522aa6339e8b66ecd4b71d02fd01f4f57a0147ceaddbf9e5f32e7ec60ae35ff73d2f386d9d0133cb697731773b55fc2615c584e9f4013253d3fc53fa13a9e982a2493e1145861759c30cf9064d333bb184e378b52e7dd8bbbd0c17774549fabb44014dab2e0a903c53d0da1c9d3a223c69f3b9bcc7925ba21a464fc9fa43e20574ffedb7a27f2cd7ae7b6b46c5cb4e0b176ece7d59ff199b74b3436ead185df5c79d74b35d644bb02315130131772db21fcd1d535014b10c4cbbb8e1f847cd00be52992ab94a7b5a7b1c27d87abe3fc605972ceb3463a07924c816a04642adcabbc7b18a40a24a3af217d0390c1102cb5b4573b1816c76667f50d33631a97e986255644e8e0c26d63cd1f29f501ff51673509822c1bf8158ceee752024dcbe0e24941803ebd8afc0bded3598012ba5431060f0db7fad7fd4960972da9a6cfaa0850c43470498236ef7b22fbf79d491e054cf142815e6c04e573a52e22ccaa2d406167c6442db40456cd93752349b2968132388b51edbe13aa349abc34696453d1a4b39f8311284f8afbae
|
||||||
BIN
release/win-unpacked/resources/xzx/PassStr.dll
Normal file
BIN
release/win-unpacked/resources/xzx/PassStr.dll
Normal file
Binary file not shown.
BIN
release/win-unpacked/resources/xzx/Syn_IDCardRead.dll
Normal file
BIN
release/win-unpacked/resources/xzx/Syn_IDCardRead.dll
Normal file
Binary file not shown.
BIN
release/win-unpacked/resources/xzx/WltRS.dll
Normal file
BIN
release/win-unpacked/resources/xzx/WltRS.dll
Normal file
Binary file not shown.
BIN
release/win-unpacked/resources/xzx/cardprintlib.dll
Normal file
BIN
release/win-unpacked/resources/xzx/cardprintlib.dll
Normal file
Binary file not shown.
BIN
release/win-unpacked/resources/xzx/sdtapi.dll
Normal file
BIN
release/win-unpacked/resources/xzx/sdtapi.dll
Normal file
Binary file not shown.
BIN
release/win-unpacked/resources/xzx/synhelp.CHM
Normal file
BIN
release/win-unpacked/resources/xzx/synhelp.CHM
Normal file
Binary file not shown.
BIN
resources/xzx/GetCursorPos.dll
Normal file
BIN
resources/xzx/GetCursorPos.dll
Normal file
Binary file not shown.
1
resources/xzx/License.dat
Normal file
1
resources/xzx/License.dat
Normal file
@@ -0,0 +1 @@
|
|||||||
|
d8838bccad0c19e847b9e73f4432b951b6f035fd8c19f5474e30db5a0e4fa4c99b57c01af79161850b95d3f99a6b0b6074f18224ec7c44f28bc243be06f8f2b96e370f5ca724c01f1bd0e289afdd9eeef7e33d42a5113ddd4818a47b33449487baec2099a50d5e3dde32bdf66d979982a68d0d60a1200990ebf8a4827b7db3d1e83f9ad9d9946267fe830c48bbe025a5ebb99b85c7f1cf93de2beb22c8e9766e5ef526242b01f5251d8a768780026add2d2d8fb9ffccb86f8779221b01d206e586d96b83839b30006910a4bca6438fb5d5b2900431f8ecab50a9f18d0e7e8abec7b212fdc9ab667f08dd3eef14ecbdb24910466f45be92d0a085ff81d7362b828847c29be579942b63b9eb26b2441b5ef20f5a012431d263ded3f5fe434111b833612464bf4df18ae06c536b6895d240387774c3b438d5f0745c7a0d3ce963e82fc8df603f6fa526e8bd1fc51e2509e0840f3bbbde7bc3fec9e837b5aa744a9ae4449c974e26d787e475f73dbc3ee9c73cc258f38b79c413453fd4fe732bed57ba9d0312d2bcaf333a5c82d92a269a7ccaf27273a178feb95028f8f0805675a6199abbd8b47756b4543269a35025438794cd32410ac19c77526c4b94b93d091069056df1dda0f49298d753a317850c7104f94067ac9cc4d5b3d377f10627d21c12a4c066347eb05370fbe9e0658c1ec1803d43ed71509f5cdb25d60f505ef7527c405d3ea05bb381436dd3622484a1ff7263e4d93f275493332af3f77d28a13a0fa0eb810b7d25a378f6b8313ab3bcb44131ca3500670b0321aa95b077cef85d348e13315c2d2d42795e41569162986755709d099b59ee320e6caf422497234251d07d697bb3f3e5ad6d15d80fd85da016e7075bf84522aa6339e8b66ecd4b71d02fd01f4f57a0147ceaddbf9e5f32e7ec60ae35ff73d2f386d9d0133cb697731773b55fc2615c584e9f4013253d3fc53fa13a9e982a2493e1145861759c30cf9064d333bb184e378b52e7dd8bbbd0c17774549fabb44014dab2e0a903c53d0da1c9d3a223c69f3b9bcc7925ba21a464fc9fa43e20574ffedb7a27f2cd7ae7b6b46c5cb4e0b176ece7d59ff199b74b3436ead185df5c79d74b35d644bb02315130131772db21fcd1d535014b10c4cbbb8e1f847cd00be52992ab94a7b5a7b1c27d87abe3fc605972ceb3463a07924c816a04642adcabbc7b18a40a24a3af217d0390c1102cb5b4573b1816c76667f50d33631a97e986255644e8e0c26d63cd1f29f501ff51673509822c1bf8158ceee752024dcbe0e24941803ebd8afc0bded3598012ba5431060f0db7fad7fd4960972da9a6cfaa0850c43470498236ef7b22fbf79d491e054cf142815e6c04e573a52e22ccaa2d406167c6442db40456cd93752349b2968132388b51edbe13aa349abc34696453d1a4b39f8311284f8afbae
|
||||||
BIN
resources/xzx/PassStr.dll
Normal file
BIN
resources/xzx/PassStr.dll
Normal file
Binary file not shown.
BIN
resources/xzx/Syn_IDCardRead.dll
Normal file
BIN
resources/xzx/Syn_IDCardRead.dll
Normal file
Binary file not shown.
BIN
resources/xzx/WltRS.dll
Normal file
BIN
resources/xzx/WltRS.dll
Normal file
Binary file not shown.
BIN
resources/xzx/cardprintlib.dll
Normal file
BIN
resources/xzx/cardprintlib.dll
Normal file
Binary file not shown.
BIN
resources/xzx/sdtapi.dll
Normal file
BIN
resources/xzx/sdtapi.dll
Normal file
Binary file not shown.
BIN
resources/xzx/synhelp.CHM
Normal file
BIN
resources/xzx/synhelp.CHM
Normal file
Binary file not shown.
@@ -19,45 +19,45 @@ const U1: React.FC = () => {
|
|||||||
if (reading) return; // 避免重复点击
|
if (reading) return; // 避免重复点击
|
||||||
setReading(true);
|
setReading(true);
|
||||||
// 启动后端监听
|
// 启动后端监听
|
||||||
// invoke("start_idcard_listen").catch((e) => {
|
window.electronAPI.startIdCardListen().catch((e: any) => {
|
||||||
// console.error("start_idcard_listen failed", e);
|
console.error("start_idcard_listen failed", e);
|
||||||
// });
|
});
|
||||||
// 6 秒超时恢复
|
// 6 秒超时恢复
|
||||||
timerRef.current = window.setTimeout(() => {
|
timerRef.current = window.setTimeout(() => {
|
||||||
if (reading) {
|
if (reading) {
|
||||||
console.warn("未在 6 秒内读取到身份证信息,恢复初始状态");
|
console.warn("未在 6 秒内读取到身份证信息,恢复初始状态");
|
||||||
setReading(false);
|
setReading(false);
|
||||||
// invoke("stop_idcard_listen").catch(() => {});
|
window.electronAPI.stopIdCardListen().catch(() => {});
|
||||||
}
|
}
|
||||||
}, 6000);
|
}, 6000);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!reading) return;
|
if (!reading) return;
|
||||||
// let unlisten: (() => void) | null = null;
|
|
||||||
// (async () => {
|
// 监听数据
|
||||||
// try {
|
window.electronAPI.onIdCardData((e: any) => {
|
||||||
// const off = await listen("idcard-data", (e) => {
|
const payload = e.payload;
|
||||||
// const payload: any = e.payload;
|
console.log("[idcard-data]", payload);
|
||||||
// console.log("[idcard-data]", payload);
|
// 成功:清理定时器,停止监听,跳转并传递身份证号
|
||||||
// // 成功:清理定时器,停止监听,跳转并传递身份证号
|
if (timerRef.current) {
|
||||||
// if (timerRef.current) {
|
clearTimeout(timerRef.current);
|
||||||
// clearTimeout(timerRef.current);
|
timerRef.current = null;
|
||||||
// timerRef.current = null;
|
}
|
||||||
// }
|
window.electronAPI.stopIdCardListen().catch(() => {});
|
||||||
// invoke("stop_idcard_listen").catch(() => {});
|
setReading(false);
|
||||||
// setReading(false);
|
navigate("/u2", {
|
||||||
// navigate("/u2", {
|
state: { idCardNo: payload?.id_card_no, cardData: payload },
|
||||||
// state: { idCardNo: payload?.id_card_no, cardData: payload },
|
});
|
||||||
// });
|
});
|
||||||
// });
|
|
||||||
// unlisten = off;
|
// 监听错误 (可选)
|
||||||
// } catch (err) {
|
window.electronAPI.onIdCardError((e: any) => {
|
||||||
// console.error("listen idcard-data failed", err);
|
console.error("[idcard-error]", e.payload);
|
||||||
// }
|
});
|
||||||
// })();
|
|
||||||
return () => {
|
return () => {
|
||||||
// if (unlisten) unlisten();
|
window.electronAPI.removeIdCardListeners();
|
||||||
};
|
};
|
||||||
}, [reading, navigate]);
|
}, [reading, navigate]);
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ const U1: React.FC = () => {
|
|||||||
// 页面卸载时清理
|
// 页面卸载时清理
|
||||||
if (timerRef.current) clearTimeout(timerRef.current);
|
if (timerRef.current) clearTimeout(timerRef.current);
|
||||||
timerRef.current = null;
|
timerRef.current = null;
|
||||||
// if (reading) invoke("stop_idcard_listen").catch(() => {});
|
if (reading) window.electronAPI.stopIdCardListen().catch(() => {});
|
||||||
};
|
};
|
||||||
}, [reading]);
|
}, [reading]);
|
||||||
|
|
||||||
|
|||||||
10
src/vite-env.d.ts
vendored
10
src/vite-env.d.ts
vendored
@@ -1 +1,11 @@
|
|||||||
/// <reference types="vite/client" />
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
interface Window {
|
||||||
|
electronAPI: {
|
||||||
|
startIdCardListen: () => Promise<any>;
|
||||||
|
stopIdCardListen: () => Promise<any>;
|
||||||
|
onIdCardData: (callback: (data: any) => void) => void;
|
||||||
|
onIdCardError: (callback: (error: any) => void) => void;
|
||||||
|
removeIdCardListeners: () => void;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user