import { app, BrowserWindow, ipcMain, dialog } from "electron"; import { fileURLToPath } from "url"; import path from "path"; import { execFile, spawn } from "child_process"; import fs from "fs"; import Papa from "./libs/papaparse/papaparse.js"; process.env["ELECTRON_DISABLE_SECURITY_WARNINGS"] = "true"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); let mainWindow = null; function createWindow() { mainWindow = new BrowserWindow({ width: 1400, height: 900, minWidth: 800, minHeight: 600, webPreferences: { preload: path.join(__dirname, "./preload.mjs"), contextIsolation: true, nodeIntegration: false, allowRunningInsecureContent: false, }, icon: path.join(__dirname, "../src/assets/images/login/bg.png"), // 开发环境的图标 }); //环境判断引入不同的页面 if (process.env.NODE_ENV === "development") { mainWindow.loadURL("http://localhost:5173"); mainWindow.webContents.openDevTools(); } else { //生产环境将引入打包好的文件 mainWindow.loadFile(path.join(__dirname, "../dist/index.html")); mainWindow.webContents.openDevTools(); } // **🔹 监听渲染进程调用 Python EXE** ipcMain.handle("run-python-exe", async (event, apiName, params = {}) => { return new Promise((resolve, reject) => { let pythonExePath = null; if (process.env.NODE_ENV === "development") { pythonExePath = path.join(__dirname, "../serves/dist/api_test.exe"); } else { pythonExePath = path.join( process.resourcesPath, "app.asar.unpacked", "serves", "dist", "api_test.exe" ); } if (!fs.existsSync(pythonExePath)) { reject(`Python EXE 不存在: ${pythonExePath}`); return; } const args = [ apiName, Buffer.from(JSON.stringify(params)).toString("base64"), ]; const child = spawn(pythonExePath, args, { encoding: "utf8" }); let stdoutData = ""; let stderrData = ""; child.stdout.on("data", (data) => { const text = data.toString(); stdoutData += text; console.log("🐍 Python stdout:", text); }); child.stderr.on("data", (data) => { const text = data.toString(); stderrData += text; console.error("🐍 Python stderr:", text); }); child.on("close", (code) => { if (code !== 0) { reject(`Python EXE exited with code ${code}\n${stderrData}`); return; } try { resolve(JSON.parse(stdoutData)); } catch (err) { console.warn("⚠️ Python EXE 输出不是 JSON:", stdoutData); resolve(stdoutData.trim()); } }); }); }); // ipcMain.handle("run-python-exe", async (event, apiName, params = {}) => { // return new Promise((resolve, reject) => { // let pythonExePath = null; // if (process.env.NODE_ENV === "development") { // // **开发环境** // pythonExePath = path.join(__dirname, "../serves/dist/api_test.exe"); // } else { // //这里需要区分开发环境还是生产环境 生产环境用到这个路径 // pythonExePath = path.join( // process.resourcesPath, // `app.asar.unpacked` 的默认路径 // "app.asar.unpacked", // "serves", // "dist", // "api_test.exe" // ); // } // // **修改 Python EXE 的路径** // if (!fs.existsSync(pythonExePath)) { // reject(`Python EXE 不存在: ${pythonExePath}`); // return; // } // // **参数列表:API 名称 + JSON 格式参数** // // const args = [apiName, JSON.stringify(params)]; // // ✅ **解决中文乱码**:使用 Base64 进行参数传输 // const args = [ // apiName, // Buffer.from(JSON.stringify(params)).toString("base64"), // ]; // const res = execFile( // pythonExePath, // args, // { encoding: "utf8" }, // (error, stdout, stderr) => { // if (error) { // console.error("❌ Python EXE 运行失败:", error); // reject(`Error: ${error.message}`); // return; // } // if (stderr) { // console.warn("⚠️ Python EXE 输出警告:", stderr); // } // // **尝试解析 JSON** // try { // console.log("✅ Python EXE 输出:", stdout); // resolve(JSON.parse(stdout)); // 返回 JSON 数据 // } catch (parseError) { // console.warn("⚠️ Python EXE 返回的不是 JSON:", stdout); // resolve(stdout.trim()); // 返回原始文本 // } // } // ); // // **✅ 实时查看 Python print 的输出** // res.stdout.on("data", (data) => { // console.log("🐍 Python stdout:", data.toString()); // }); // res.stderr.on("data", (data) => { // console.error("🐍 Python stderr:", data.toString()); // }); // }); // }); ipcMain.handle("get-install-path", async () => { return process.execPath; // 获取可执行文件路径 }); // 监听前端请求,读取 CSV 文件 ipcMain.handle("read-csv", async (event, filePath) => { try { const csvData = fs.readFileSync(filePath, "utf-8"); const parsedData = Papa.parse(csvData, { header: true, skipEmptyLines: true, // ← 这个也可以帮助跳过完全空的行 transformHeader: (header) => header.trim(), // ← 这个也可以帮助跳过完全空的行 }); // 过滤掉所有字段都为空的行 const cleanData = parsedData.data.filter((row) => Object.values(row).some((val) => val && val.trim() !== "") ); return cleanData; // 返回解析后的数据 } catch (error) { console.error("读取 CSV 失败:", error); return { error: error.message }; } }); // 监听 get-file-path 事件 监听渲染进程请求文件路径 ipcMain.handle("get-file-path", async () => { try { const { filePaths } = await dialog.showOpenDialog({ properties: ["openFile", "multiSelections"], // ✅ 允许选择多个文件 }); if (filePaths.length > 0) { console.log("用户选择的文件路径:", filePaths[0]); return filePaths[0]; // 返回文件路径 } else { console.log("用户取消了选择"); return null; // 用户没有选择文件 } } catch (error) { console.error("获取文件路径失败:", error); return null; } }); mainWindow.on("close", (event) => { event.preventDefault(); // ✅ 阻止默认关闭行为 const choice = dialog.showMessageBoxSync(mainWindow, { type: "question", buttons: ["取消", "退出"], defaultId: 0, // 默认选中 "取消" title: "确认退出", message: "退出程序正在分析中的数据会丢失,确定要退出程序吗?", }); if (choice === 1) { // ✅ 直接移除监听器,允许窗口关闭 mainWindow.removeAllListeners("close"); mainWindow.close(); } }); mainWindow.on("closed", () => { mainWindow = null; // ✅ 窗口关闭后清空引用 }); } app.whenReady().then(createWindow); app.on("window-all-closed", () => { if (process.platform !== "darwin") app.quit(); }); app.on("activate", () => { if (BrowserWindow.getAllWindows().length === 0) createWindow(); }); export { createWindow };