Files
yuanhe-checkin-electron/electron/main.js
2025-11-21 10:36:00 +08:00

259 lines
7.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const { app, BrowserWindow, ipcMain } = require("electron");
const path = require("path");
const https = require("https");
const http = require("http");
const fs = require("fs");
const os = require("os");
let mainWindow = null;
const { Worker } = require("worker_threads");
const log = require("electron-log");
// 配置日志输出
log.transports.file.level = "info";
log.transports.file.resolvePath = () =>
path.join(path.dirname(app.getPath("exe")), "logs", "main.log");
log.info("App starting...");
// 监听渲染进程日志
ipcMain.on("log-message", (event, { level, message }) => {
if (log[level]) {
log[level](`[Renderer] ${message}`);
} else {
log.info(`[Renderer] ${message}`);
}
});
let idCardWorker = null;
function createIdCardWorker() {
if (idCardWorker) return;
log.info("Creating IDCard Worker...");
idCardWorker = new Worker(path.join(__dirname, "idcard-worker.js"));
idCardWorker.on("message", (msg) => {
if (!mainWindow) return;
if (msg.type === "data") {
log.info("IDCard data received");
mainWindow.webContents.send("idcard-data", { payload: msg.payload });
} else if (msg.type === "error") {
log.error("IDCard worker error message:", msg.payload);
mainWindow.webContents.send("idcard-error", { payload: msg.payload });
} else if (msg.type === "log") {
log.info("[Worker]", msg.payload);
}
});
idCardWorker.on("error", (err) => {
log.error("Worker thread error:", err);
});
idCardWorker.on("exit", (code) => {
if (code !== 0) log.error(`Worker stopped with exit code ${code}`);
else log.info("Worker stopped gracefully");
idCardWorker = null;
});
}
function createWindow() {
mainWindow = new BrowserWindow({
width: 1080,
height: 1920,
webPreferences: {
preload: path.join(__dirname, "preload.js"),
nodeIntegration: false,
contextIsolation: true,
},
});
const isDev = !app.isPackaged;
if (isDev) {
mainWindow.loadURL("http://localhost:5173");
// 打开开发者工具
mainWindow.webContents.openDevTools();
} else {
mainWindow.loadFile(path.join(__dirname, "../dist/index.html"));
}
}
// 处理PDF获取请求绕过CORS
ipcMain.handle("fetch-pdf", async (event, pdfUrl) => {
return new Promise((resolve, reject) => {
const protocol = pdfUrl.startsWith("https") ? https : http;
protocol
.get(pdfUrl, (response) => {
// 处理重定向
if (response.statusCode === 301 || response.statusCode === 302) {
const redirectUrl = response.headers.location;
protocol
.get(redirectUrl, (redirectResponse) => {
const chunks = [];
redirectResponse.on("data", (chunk) => chunks.push(chunk));
redirectResponse.on("end", () => {
const buffer = Buffer.concat(chunks);
resolve({
success: true,
data: buffer.toString("base64"),
});
});
redirectResponse.on("error", (error) => {
reject({ success: false, error: error.message });
});
})
.on("error", (error) => {
reject({ success: false, error: error.message });
});
} else {
const chunks = [];
response.on("data", (chunk) => chunks.push(chunk));
response.on("end", () => {
const buffer = Buffer.concat(chunks);
resolve({
success: true,
data: buffer.toString("base64"),
});
});
response.on("error", (error) => {
reject({ success: false, error: error.message });
});
}
})
.on("error", (error) => {
reject({ success: false, error: error.message });
});
});
});
// 处理PDF打印请求
ipcMain.handle("print-pdf", async (event, pdfDataOrUrl) => {
let printWindow = null;
let tempFilePath = null;
try {
// 如果是 base64 data URI转换为临时文件
let pdfPath = pdfDataOrUrl;
if (pdfDataOrUrl.startsWith("data:application/pdf;base64,")) {
const base64Data = pdfDataOrUrl.replace("data:application/pdf;base64,", "");
const buffer = Buffer.from(base64Data, "base64");
// 创建临时文件
tempFilePath = path.join(os.tmpdir(), `print_${Date.now()}.pdf`);
fs.writeFileSync(tempFilePath, buffer);
pdfPath = `file://${tempFilePath}`;
log.info("PDF written to temp file:", tempFilePath);
}
// 创建一个隐藏的窗口用于加载PDF
printWindow = new BrowserWindow({
width: 800,
height: 600,
show: false,
webPreferences: {
plugins: true, // 启用插件以支持 PDF 查看
},
});
// 加载PDF
await printWindow.loadURL(pdfPath);
log.info("PDF loaded for printing");
// 等待更长时间确保 PDF 完全渲染
await new Promise(resolve => setTimeout(resolve, 2000));
// 静默打印(直接调用系统打印对话框)
return new Promise((resolve) => {
printWindow.webContents.print(
{
silent: false, // 显示打印对话框
printBackground: true,
margins: {
marginType: "none",
},
},
(success, errorType) => {
// 清理临时文件
if (tempFilePath && fs.existsSync(tempFilePath)) {
try {
fs.unlinkSync(tempFilePath);
log.info("Temp file deleted");
} catch (err) {
log.error("Failed to delete temp file:", err);
}
}
// 关闭窗口
if (printWindow && !printWindow.isDestroyed()) {
printWindow.close();
}
if (!success) {
log.error("Print failed:", errorType);
resolve({ success: false, error: errorType });
} else {
log.info("Print completed");
resolve({ success: true });
}
}
);
});
} catch (error) {
log.error("Print error:", error);
// 清理临时文件
if (tempFilePath && fs.existsSync(tempFilePath)) {
try {
fs.unlinkSync(tempFilePath);
} catch (err) {
log.error("Failed to delete temp file:", err);
}
}
if (printWindow && !printWindow.isDestroyed()) {
printWindow.close();
}
return { success: false, error: error.message };
}
});
app.whenReady().then(() => {
createWindow();
createIdCardWorker();
// 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) {
createWindow();
}
});
});
app.on("window-all-closed", () => {
if (idCardWorker) {
idCardWorker.terminate();
}
if (process.platform !== "darwin") {
app.quit();
}
});