|
|
@@ -0,0 +1,247 @@
|
|
|
+<!--
|
|
|
+ * @Author: your name
|
|
|
+ * @Date: 2025-03-11 14:21:26
|
|
|
+ * @LastEditTime: 2025-03-11 14:21:29
|
|
|
+ * @LastEditors: milo-MacBook-Pro.local
|
|
|
+ * @Description: In User Settings Edit
|
|
|
+ * @FilePath: /exetest/readme1.md
|
|
|
+-->
|
|
|
+
|
|
|
+### **🎯 目标:用 Python 作为 EXE,暴露 /api/a1 和 /api/a2 两个 API**
|
|
|
+
|
|
|
+> **思路**:Electron **通过 `child_process.execFile` 运行 Python EXE**,Python **解析 API 名称和参数**,执行相应逻辑并返回 JSON 结果。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## **🔹 1️⃣ Python 代码**
|
|
|
+
|
|
|
+创建 `data_analyse.py`,用于处理 API 请求。
|
|
|
+
|
|
|
+```python
|
|
|
+import sys
|
|
|
+import json
|
|
|
+
|
|
|
+# **定义 API 处理函数**
|
|
|
+def api_a1():
|
|
|
+ return {"message": "Hello from API A1"}
|
|
|
+
|
|
|
+def api_a2(data):
|
|
|
+ return {"received": data}
|
|
|
+
|
|
|
+if __name__ == "__main__":
|
|
|
+ # **🔹 解析命令行参数**
|
|
|
+ if len(sys.argv) < 2:
|
|
|
+ print(json.dumps({"error": "No API specified"}))
|
|
|
+ sys.exit(1)
|
|
|
+
|
|
|
+ api_name = sys.argv[1] # 第一个参数是 API 名称
|
|
|
+
|
|
|
+ if api_name == "a1":
|
|
|
+ result = api_a1()
|
|
|
+ elif api_name == "a2":
|
|
|
+ if len(sys.argv) < 3:
|
|
|
+ print(json.dumps({"error": "No data for A2"}))
|
|
|
+ sys.exit(1)
|
|
|
+ data = json.loads(sys.argv[2]) # 解析 JSON 参数
|
|
|
+ result = api_a2(data)
|
|
|
+ else:
|
|
|
+ result = {"error": "Unknown API"}
|
|
|
+
|
|
|
+ print(json.dumps(result)) # **返回 JSON 格式数据**
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## **🔹 2️⃣ 将 Python 代码打包成 EXE**
|
|
|
+
|
|
|
+### **📌 安装 `pyinstaller`**
|
|
|
+
|
|
|
+```bash
|
|
|
+pip install pyinstaller
|
|
|
+```
|
|
|
+
|
|
|
+### **📌 生成 EXE**
|
|
|
+
|
|
|
+```bash
|
|
|
+pyinstaller --onefile data_analyse.py
|
|
|
+```
|
|
|
+
|
|
|
+成功后,你会在 `dist/` 目录下找到 `data_analyse.exe`。
|
|
|
+
|
|
|
+> **📌 复制 EXE 文件到 Electron 项目**
|
|
|
+> 将 `dist/data_analyse.exe` 复制到 `../severs/dist/data_analyse/`
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## **🔹 3️⃣ Electron 主进程调用 Python EXE**
|
|
|
+
|
|
|
+修改 `main.mjs`,让 Electron **监听渲染进程的请求** 并运行 Python EXE。
|
|
|
+
|
|
|
+```javascript
|
|
|
+import { app, BrowserWindow, ipcMain } from "electron";
|
|
|
+import { fileURLToPath } from "url";
|
|
|
+import path from "path";
|
|
|
+import { execFile } from "child_process";
|
|
|
+
|
|
|
+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: 1000,
|
|
|
+ height: 800,
|
|
|
+ webPreferences: {
|
|
|
+ preload: path.join(__dirname, "./preload.mjs"),
|
|
|
+ contextIsolation: true,
|
|
|
+ nodeIntegration: false,
|
|
|
+ allowRunningInsecureContent: false,
|
|
|
+ },
|
|
|
+ });
|
|
|
+
|
|
|
+ if (process.env.NODE_ENV === "development") {
|
|
|
+ mainWindow.loadURL("http://localhost:5173/home");
|
|
|
+ mainWindow.webContents.openDevTools();
|
|
|
+ } else {
|
|
|
+ mainWindow.loadFile(path.join(__dirname, "../dist/index.html"));
|
|
|
+ mainWindow.webContents.openDevTools();
|
|
|
+ }
|
|
|
+
|
|
|
+ mainWindow.on("closed", () => {
|
|
|
+ mainWindow = null;
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+// **🔹 监听渲染进程的请求,执行 Python EXE**
|
|
|
+ipcMain.handle("run-python-exe", async (event, apiName, params = {}) => {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ const pythonExePath = path.join(
|
|
|
+ __dirname,
|
|
|
+ "../severs/dist/data_analyse/data_analyse.exe"
|
|
|
+ ); // **Python EXE 路径**
|
|
|
+
|
|
|
+ // **传递 API 名称和参数**
|
|
|
+ const args = [apiName, JSON.stringify(params)];
|
|
|
+
|
|
|
+ const child = execFile(pythonExePath, args, (error, stdout, stderr) => {
|
|
|
+ if (error) {
|
|
|
+ console.error("❌ Python EXE 运行失败:", error);
|
|
|
+ reject(`Error: ${error.message}`);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (stderr) {
|
|
|
+ console.warn("⚠️ Python EXE 输出警告:", stderr);
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ resolve(JSON.parse(stdout)); // **解析 JSON 返回给前端**
|
|
|
+ } catch (parseError) {
|
|
|
+ reject("Invalid JSON response from Python");
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+});
|
|
|
+
|
|
|
+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 };
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## **🔹 4️⃣ 渲染进程(前端)调用 Python**
|
|
|
+
|
|
|
+修改 `preload.mjs`,暴露 API 让前端调用。
|
|
|
+
|
|
|
+```javascript
|
|
|
+import { contextBridge, ipcRenderer } from "electron";
|
|
|
+
|
|
|
+contextBridge.exposeInMainWorld("electronAPI", {
|
|
|
+ callPythonAPI: (apiName, params) =>
|
|
|
+ ipcRenderer.invoke("run-python-exe", apiName, params),
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## **🔹 5️⃣ 前端(Vue / React / HTML)调用 Python**
|
|
|
+
|
|
|
+```javascript
|
|
|
+async function fetchA1() {
|
|
|
+ try {
|
|
|
+ const result = await window.electronAPI.callPythonAPI("a1");
|
|
|
+ console.log("A1 API 响应:", result);
|
|
|
+ } catch (error) {
|
|
|
+ console.error("A1 API 失败:", error);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+async function fetchA2() {
|
|
|
+ try {
|
|
|
+ const result = await window.electronAPI.callPythonAPI("a2", {
|
|
|
+ name: "Alice",
|
|
|
+ });
|
|
|
+ console.log("A2 API 响应:", result);
|
|
|
+ } catch (error) {
|
|
|
+ console.error("A2 API 失败:", error);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+fetchA1();
|
|
|
+fetchA2();
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## **✅ 运行步骤**
|
|
|
+
|
|
|
+### **1️⃣ 先编译 Python 为 EXE**
|
|
|
+
|
|
|
+```bash
|
|
|
+pyinstaller --onefile data_analyse.py
|
|
|
+```
|
|
|
+
|
|
|
+然后把 `dist/data_analyse.exe` 复制到 `../severs/dist/data_analyse/`
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### **2️⃣ 运行 Electron**
|
|
|
+
|
|
|
+```bash
|
|
|
+npm run electron:dev
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## **🚀 运行结果**
|
|
|
+
|
|
|
+- **调用 `callPythonAPI("a1")`**
|
|
|
+ ```json
|
|
|
+ { "message": "Hello from API A1" }
|
|
|
+ ```
|
|
|
+- **调用 `callPythonAPI("a2", { "name": "Alice" })`**
|
|
|
+ ```json
|
|
|
+ { "received": { "name": "Alice" } }
|
|
|
+ ```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## **🎯 总结**
|
|
|
+
|
|
|
+1. **Python 解析 API 名称和参数**,执行相应逻辑,并返回 JSON 结果。
|
|
|
+2. **Electron 主进程监听前端的调用**,用 `execFile` 运行 Python EXE,并传递 API 名称和参数。
|
|
|
+3. **渲染进程(前端)使用 `window.electronAPI.callPythonAPI()`** 触发 Python 调用。
|
|
|
+4. **Electron 解析 Python 输出,并返回给前端**。
|
|
|
+
|
|
|
+这样你就成功在 **Electron 中调用 Python EXE,并通过 JSON 格式返回 API 数据**! 🚀🚀🚀
|