diff --git a/build/extraResources/dll/myDllDemo.dll b/build/extraResources/dll/myDllDemo.dll deleted file mode 100644 index ffd5446..0000000 Binary files a/build/extraResources/dll/myDllDemo.dll and /dev/null differ diff --git a/build/extraResources/java/.gitignore b/build/extraResources/java/.gitignore deleted file mode 100644 index 70572cc..0000000 --- a/build/extraResources/java/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# 自动生成的配置文件 -application.yml - -# 运行时端口记录 -.running-port - -# 日志文件 -logs/ -*.log - diff --git a/build/extraResources/java/README.txt b/build/extraResources/java/README.txt index da00319..96a5cb1 100644 --- a/build/extraResources/java/README.txt +++ b/build/extraResources/java/README.txt @@ -1,71 +1,20 @@ ========================================== - NPQS9100 Java 后端服务说明 + NPQS9100 Java 后端服务 ========================================== -一、目录结构 +目录说明 ---------------------------------------- entrance.jar - Spring Boot 应用程序 application.yml - 应用配置文件(自动生成) application.yml.template - 配置模板 -kill-java-port.bat - 智能清理Java端口占用(紧急用) -.running-port - 运行时端口记录(自动生成,勿删除) -二、自动管理 +服务管理 ---------------------------------------- -正常情况下,Java 后端服务由主应用自动管理: -- 应用启动时自动启动 Java 服务 -- 应用关闭时自动停止 Java 服务 -- 无需手动操作 - - -三、端口智能管理 ----------------------------------------- -- Java 服务默认使用端口:18092 -- 如果 18092 被占用,自动尝试:18093, 18094, ... -- 启动成功后会记录实际端口到 .running-port 文件 -- kill-java-port.bat 会自动识别正确的端口进行清理 - - -四、手动清理工具 ----------------------------------------- -如果应用异常退出,Java 进程可能残留,导致: -- 端口被占用,无法再次启动 -- 可以运行 kill-java-port.bat 清理残留进程 - -使用方法: -1. 双击运行:kill-java-port.bat -2. 脚本会自动识别实际使用的端口 -3. 清理完成后即可重新启动应用 - - -五、安全说明 ----------------------------------------- -⚠️ 进程停止安全性: -- 应用自动停止时,只会停止应用自己启动的 Java 进程 -- 通过进程引用精确停止,不会影响其他 Java 应用 -- kill-java-port.bat 只清理占用特定端口的进程 -- 完全不会影响您电脑上的其他 Java 程序 - -⭐ 端口冲突处理: -- 如果您的电脑上有其他应用占用了 18092 端口 -- 本应用会自动切换到其他端口(18093, 18094...) -- kill-java-port.bat 会自动识别实际端口,精确清理 - - -六、常见问题 ----------------------------------------- -Q: Java 服务无法启动? -A: 运行 kill-java-port.bat 清理残留进程 - -Q: 端口被占用怎么办? -A: 应用会自动切换端口,无需手动处理 - -Q: 如何查看 Java 日志? -A: 启动应用后,日志窗口会实时显示 Java 输出 - -Q: 配置文件在哪里? -A: application.yml 由应用自动生成,请勿手动修改 +Java 后端服务由主应用自动管理: +- 应用启动时自动启动 +- 应用关闭时自动停止 +- 默认端口:18092(如被占用会自动切换) ========================================== diff --git a/build/extraResources/java/kill-java-port.bat b/build/extraResources/java/kill-java-port.bat deleted file mode 100644 index b96b371..0000000 --- a/build/extraResources/java/kill-java-port.bat +++ /dev/null @@ -1,115 +0,0 @@ -@echo off -chcp 65001 >nul -color 0E -title 清理NPQS9100 Java端口占用 -cls -echo ========================================== -echo 清理 NPQS9100 Java 端口占用 -echo ========================================== -echo. - -REM 获取Java目录(脚本所在目录) -set JAVA_HOME=%~dp0 -cd /d "%JAVA_HOME%" - -REM 读取实际运行的端口 -set PORT_FILE=.running-port -set JAVA_PORT= - -if exist "%PORT_FILE%" ( - set /p JAVA_PORT=<"%PORT_FILE%" - echo [√] 检测到运行记录:端口 %JAVA_PORT% - echo. -) else ( - echo [!] 未找到运行记录文件,使用默认端口 18092 - echo. - set JAVA_PORT=18092 -) - -echo [1] 检查端口 %JAVA_PORT% 占用情况... -echo. - -REM 查找占用该端口的连接 -netstat -ano | findstr ":%JAVA_PORT%" > "%TEMP%\java_port.txt" - -if %errorlevel% equ 0 ( - echo 发现以下端口 %JAVA_PORT% 连接: - echo ---------------------------------------- - type "%TEMP%\java_port.txt" - echo ---------------------------------------- - echo. - - echo [2] 提取进程ID并结束进程... - echo. - - REM 提取所有LISTENING状态的PID - for /f "tokens=5" %%a in ('netstat -ano ^| findstr ":%JAVA_PORT%" ^| findstr "LISTENING"') do ( - if not "%%a"=="0" ( - echo 正在结束进程 PID: %%a - taskkill /F /PID %%a 2>nul - if errorlevel 1 ( - echo [失败] 无法结束进程 %%a - ) else ( - echo [成功] 已结束进程 %%a - ) - ) - ) - - REM 如果还有其他状态的连接,也尝试结束 - for /f "tokens=5" %%a in ('netstat -ano ^| findstr ":%JAVA_PORT%" ^| findstr /V "LISTENING"') do ( - if not "%%a"=="0" ( - echo 正在结束进程 PID: %%a - taskkill /F /PID %%a 2>nul - if errorlevel 1 ( - echo [已结束或无权限] 进程 %%a - ) else ( - echo [成功] 已结束进程 %%a - ) - ) - ) - - echo. - echo [3] 清理完成 - - REM 等待2秒让进程完全释放 - timeout /t 2 /nobreak >nul - - echo. - echo [4] 再次检查端口 %JAVA_PORT%... - netstat -ano | findstr ":%JAVA_PORT%" - if errorlevel 1 ( - echo [√] 端口 %JAVA_PORT% 已完全释放 - - REM 删除端口记录文件 - if exist "%PORT_FILE%" ( - del "%PORT_FILE%" - echo [√] 已清理端口记录文件 - ) - ) else ( - echo [!] 仍有连接存在(可能是TIME_WAIT状态,会自动释放) - ) - -) else ( - echo [√] 没有发现占用端口 %JAVA_PORT% 的进程 - - REM 删除端口记录文件 - if exist "%PORT_FILE%" ( - del "%PORT_FILE%" - echo [√] 已清理端口记录文件 - ) -) - -REM 清理临时文件 -if exist "%TEMP%\java_port.txt" del "%TEMP%\java_port.txt" - -echo. -echo ========================================== -echo 清理完成 -echo ========================================== -echo. -echo 说明: -echo - 此脚本只清理 NPQS9100 应用使用的 Java 端口 -echo - 不会影响您电脑上的其他 Java 应用 -echo. -pause - diff --git a/cmd/builder.json b/cmd/builder.json index 9e12e05..8e161e5 100644 --- a/cmd/builder.json +++ b/cmd/builder.json @@ -57,8 +57,8 @@ "filter": ["**/*"] }, { - "from": "build/NPQS9100-启动器.bat", - "to": "NPQS9100-启动器.bat" + "from": "build/NPQS9100.bat", + "to": "NPQS9100.bat" }, { "from": "build/extraResources/使用说明.txt", @@ -91,4 +91,4 @@ ] }, "compression": "store" -} \ No newline at end of file +} diff --git a/electron/config/config.default.js b/electron/config/config.default.js index 7a3e982..3a9f88d 100644 --- a/electron/config/config.default.js +++ b/electron/config/config.default.js @@ -12,7 +12,7 @@ module.exports = () => { singleLock: true, windowsOption: { title: 'NPQS9100-自动检测平台', - menuBarVisible: true, // 显示菜单栏,方便查看日志 + menuBarVisible: false, // 隐藏菜单栏 width: 1920, height: 1000, minWidth: 1024, diff --git a/electron/main.js b/electron/main.js index c506dfc..5ce4e28 100644 --- a/electron/main.js +++ b/electron/main.js @@ -118,6 +118,11 @@ function createTray() { // 创建应用菜单 function createApplicationMenu() { + // 生产环境隐藏菜单栏 + Menu.setApplicationMenu(null); + + // 调试时可以使用下面的菜单(取消注释) + /* const template = [ { label: '查看', @@ -147,9 +152,10 @@ function createApplicationMenu() { ] } ]; - + const menu = Menu.buildFromTemplate(template); Menu.setApplicationMenu(menu); + */ } // 注册 IPC 处理器 diff --git a/electron/preload/lifecycle.js b/electron/preload/lifecycle.js index 6360b0e..3a8b2c5 100644 --- a/electron/preload/lifecycle.js +++ b/electron/preload/lifecycle.js @@ -267,40 +267,41 @@ class Lifecycle { const win = getMainWindow(); win.show(); win.focus(); - - // 添加主窗口关闭事件监听 + + // 窗口关闭时,使用 Electron 原生对话框确认 win.on('close', async (event) => { - // 总是弹出确认对话框 + if (global.isConfirmedExit) { + logger.info('[lifecycle] Exit already confirmed, proceeding'); + return; + } + event.preventDefault(); - + logger.info('[lifecycle] Window close intercepted, showing exit confirm dialog'); + const { dialog } = require('electron'); - const { app } = require('electron'); - - const response = await dialog.showMessageBox(win, { + const { response } = await dialog.showMessageBox(win, { type: 'question', + buttons: ['取消', '退出'], + defaultId: 1, + cancelId: 0, title: '退出确认', message: '确定要退出应用吗?', - buttons: ['取消', '退出'], - defaultId: 0, - cancelId: 0 + noLink: true }); - - if (response.response === 1) { - // 用户确认退出 + + if (response === 1) { logger.info('[lifecycle] User confirmed exit'); - - // 移除所有监听器避免循环 - win.removeAllListeners('close'); - - // 执行清理 + global.isConfirmedExit = true; await this.cleanup(); - - // 退出应用 + if (win && !win.isDestroyed()) { + win.destroy(); + } app.quit(); + } else { + logger.info('[lifecycle] User cancelled exit'); } - // 用户取消,什么都不做(已经 preventDefault) }); - + // 立即刷新一次,确保显示最新内容 setTimeout(() => { if (win && !win.isDestroyed()) { @@ -496,22 +497,14 @@ class Lifecycle { try { // 显示提示对话框 - const { response } = await dialog.showMessageBox({ + await dialog.showMessageBox({ type: 'warning', - title: '需要管理员权限', - message: '安装 MySQL 服务需要管理员权限', - detail: '应用将以管理员身份重新启动', - buttons: ['取消', '确定'], - defaultId: 1, - cancelId: 0 + title: '告警', + message: '需要管理员权限', + buttons: ['确定'] }); - - if (response === 0) { - // 用户取消,关闭应用 - logger.info('[lifecycle] User cancelled admin elevation'); - app.quit(); - return; - } + + // 用户点击确定,以管理员身份重启 // 获取应用可执行文件路径 const exePath = app.getPath('exe'); @@ -588,63 +581,6 @@ class Lifecycle { */ async electronAppReady() { logger.info('[lifecycle] electron-app-ready'); - - // 检查管理员权限 - const hasAdminPrivileges = this.checkAdminPrivileges(); - logger.info('[lifecycle] Has admin privileges:', hasAdminPrivileges); - - if (!hasAdminPrivileges) { - logger.warn('[lifecycle] No admin privileges, will request elevation when needed'); - - // 立即请求管理员权限 - const { dialog, app } = require('electron'); - const { spawn } = require('child_process'); - - setTimeout(async () => { - const { response } = await dialog.showMessageBox({ - type: 'warning', - title: '需要管理员权限', - message: 'NPQS9100 需要管理员权限来管理 MySQL 服务', - detail: '应用将以管理员身份重新启动。\n\n如果您拒绝,应用可能无法正常工作。', - buttons: ['退出应用', '以管理员身份启动'], - defaultId: 1, - cancelId: 0 - }); - - if (response === 0) { - logger.info('[lifecycle] User declined admin elevation, quitting'); - app.quit(); - return; - } - - // 以管理员身份重启 - try { - const exePath = app.getPath('exe'); - logger.info('[lifecycle] Restarting with admin privileges:', exePath); - - const psCommand = `Start-Process -FilePath "${exePath}" -Verb RunAs`; - const child = spawn('powershell.exe', ['-Command', psCommand], { - detached: true, - stdio: 'ignore', - windowsHide: true - }); - - child.unref(); - - // 设置标记,跳过清理 - this.isRestartingForAdmin = true; - - // 退出当前实例 - setTimeout(() => { - app.quit(); - }, 500); - } catch (error) { - logger.error('[lifecycle] Failed to restart as admin:', error); - dialog.showErrorBox('启动失败', '无法以管理员身份启动应用,请手动右键选择"以管理员身份运行"'); - app.quit(); - } - }, 1000); - } } /** @@ -653,6 +589,17 @@ class Lifecycle { async windowReady() { logger.info('[lifecycle] window-ready hook triggered'); + // 在创建任何窗口之前,先检查管理员权限 + const hasAdminPrivileges = this.checkAdminPrivileges(); + logger.info('[lifecycle] Has admin privileges:', hasAdminPrivileges); + + if (!hasAdminPrivileges) { + logger.warn('[lifecycle] No admin privileges, requesting elevation'); + // 调用已有的 restartAsAdmin 方法,避免代码重复 + await this.restartAsAdmin(); + return; // 阻止后续代码执行 + } + // 创建日志管理器(但不显示窗口,仅用于写日志文件) logger.info('[lifecycle] Creating log window manager...'); this.logWindowManager = new LogWindowManager(); diff --git a/frontend/src/App.vue b/frontend/src/App.vue index b39c68c..8d37c8c 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -32,14 +32,6 @@ onMounted(() => { const language = globalStore.language ?? getBrowserLang() i18n.locale.value = language globalStore.setGlobalState('language', language as LanguageType) - // 移除 autofit,使用 CSS 自适应 - // autofit.init({ - // el: '#app', - // dw: 1440, - // dh: 900, - // resize: true, - // limit: 0.1 - // }) }) // element language diff --git a/package.json b/package.json index 73c20a6..e220862 100644 --- a/package.json +++ b/package.json @@ -14,11 +14,12 @@ "encrypt": "ee-bin encrypt", "icon": "ee-bin icon", "re-sqlite": "electron-rebuild -f -w better-sqlite3", - "build-w": "ee-bin build --cmds=win64", + "build-w": "ee-bin build --cmds=win64 && npm run rename-output", "build-we": "ee-bin build --cmds=win_e", "build-m": "ee-bin build --cmds=mac", "build-m-arm64": "ee-bin build --cmds=mac_arm64", - "build-l": "ee-bin build --cmds=linux" + "build-l": "ee-bin build --cmds=linux", + "rename-output": "node -e \"const fs=require('fs'); const oldPath='out/win-unpacked'; const newPath='out/NPQS-9100'; if(fs.existsSync(oldPath)){if(fs.existsSync(newPath)) fs.rmSync(newPath,{recursive:true}); fs.renameSync(oldPath, newPath); console.log('Renamed to NPQS-9100');}\"" }, "repository": "https://github.com/dromara/electron-egg.git", "keywords": [