feat(steady): 实现稳态校验任务功能重构

- 添加influxdb配置支持和资源文件打包
- 实现校验任务表格组件和相关工具函数
- 重构校验工作台为任务创建对话框模式
- 实现校验详情面板支持多种异常类型展示
- 更新校验概览表格显示任务基本信息
- 优化校验查询参数和API接口定义
- 实现搜索表单组件化和过滤功能增强
This commit is contained in:
2026-06-11 10:53:02 +08:00
parent 3dff953b8d
commit 8622f25048
25 changed files with 1675 additions and 486 deletions

View File

@@ -11,45 +11,40 @@ const { app } = require('electron');
function getScriptsPath(scriptName) {
const fs = require('fs');
// 判断是否是打包后的环境
// 只要 process.resourcesPath 存在,就是打包后的环境(无论在哪个目录)
const isProd = !!process.resourcesPath;
if (isProd) {
// 生产环境(打包后):从 resources 目录
if (process.resourcesPath) {
const prodPath = path.join(process.resourcesPath, 'scripts', scriptName);
const prodFile = `${prodPath}.js`;
if (fs.existsSync(prodFile)) {
console.log(`[getScriptsPath] Production mode, using: ${prodPath}`);
return prodPath;
} else {
// 开发环境:从项目根目录
// __dirname 是 electron/preload 或 public/electron/preload
// 需要找到项目根目录
let currentDir = __dirname;
let scriptsPath = null;
// 向上查找,直到找到 scripts 目录
for (let i = 0; i < 5; i++) {
currentDir = path.join(currentDir, '..');
const testPath = path.join(currentDir, 'scripts', scriptName + '.js');
if (fs.existsSync(testPath)) {
scriptsPath = path.join(currentDir, 'scripts', scriptName);
console.log(`[getScriptsPath] Development mode, found at: ${scriptsPath}`);
return scriptsPath;
}
}
// 如果找不到,返回一个默认路径
console.warn(`[getScriptsPath] Cannot find ${scriptName}, returning default path`);
return path.join(__dirname, '../../../scripts', scriptName);
}
// 开发环境:从项目根目录向上查找 scripts 目录,避免误用 Electron 安装目录 resources。
let currentDir = __dirname;
let scriptsPath = null;
for (let i = 0; i < 5; i++) {
currentDir = path.join(currentDir, '..');
const testPath = path.join(currentDir, 'scripts', scriptName + '.js');
if (fs.existsSync(testPath)) {
scriptsPath = path.join(currentDir, 'scripts', scriptName);
console.log(`[getScriptsPath] Development mode, found at: ${scriptsPath}`);
return scriptsPath;
}
}
console.warn(`[getScriptsPath] Cannot find ${scriptName}, returning default path`);
return path.join(__dirname, '../../../scripts', scriptName);
}
// 延迟加载 scripts
let MySQLProcessManager, JavaRunner, ConfigGenerator, PortChecker, StartupManager, LogWindowManager;
let MySQLProcessManager, InfluxDBProcessManager, JavaRunner, ConfigGenerator, PortChecker, StartupManager, LogWindowManager;
function loadScripts() {
if (!MySQLProcessManager) {
MySQLProcessManager = require(getScriptsPath('mysql-process-manager'));
InfluxDBProcessManager = require(getScriptsPath('influxdb-process-manager'));
JavaRunner = require(getScriptsPath('java-runner'));
ConfigGenerator = require(getScriptsPath('config-generator'));
PortChecker = require(getScriptsPath('port-checker'));
@@ -61,10 +56,12 @@ function loadScripts() {
class Lifecycle {
constructor() {
this.mysqlProcessManager = null;
this.influxdbProcessManager = null;
this.javaRunner = null;
this.startupManager = null;
this.logWindowManager = null;
this.mysqlPort = null;
this.influxdbPort = null;
this.javaPort = null;
this.autoRefreshTimer = null;
}
@@ -124,9 +121,38 @@ class Lifecycle {
}
}
// InfluxDB 用于稳态趋势、补数等时序数据能力,必须早于后端服务启动。
this.logWindowManager.addLog('system', '▶ 步骤7: 启动 InfluxDB 进程管理器...');
this.startupManager.updateProgress('check-influxdb-port', { mysqlPort: this.mysqlPort });
this.influxdbProcessManager = new InfluxDBProcessManager(this.logWindowManager);
this.logWindowManager.addLog('system', '正在检查 InfluxDB 进程状态...');
try {
this.influxdbPort = await this.influxdbProcessManager.ensureServiceRunning(
PortChecker.findAvailablePort.bind(PortChecker),
PortChecker.waitForPort.bind(PortChecker)
);
logger.info(`[lifecycle] InfluxDB process running on port: ${this.influxdbPort}`);
this.logWindowManager.addLog('success', `✅ InfluxDB 服务已就绪,端口: ${this.influxdbPort}`);
this.startupManager.updateProgress('wait-influxdb', {
mysqlPort: this.mysqlPort,
influxdbPort: this.influxdbPort
});
await this.sleep(500);
} catch (error) {
logger.error('[lifecycle] InfluxDB error:', error);
this.logWindowManager.addLog('error', `InfluxDB 错误: ${error.message}`);
throw error;
}
// 步骤5: 检测 Java 端口
this.logWindowManager.addLog('system', '▶ 步骤7: 检测可用的 Java 端口从18093开始...');
this.startupManager.updateProgress('check-java-port', { mysqlPort: this.mysqlPort });
this.logWindowManager.addLog('system', '▶ 步骤8: 检测可用的 Java 端口从18093开始...');
this.startupManager.updateProgress('check-java-port', {
mysqlPort: this.mysqlPort,
influxdbPort: this.influxdbPort
});
this.javaPort = await PortChecker.findAvailablePort(18093, 100);
@@ -136,7 +162,7 @@ class Lifecycle {
}
// 步骤5.5: 检测 WebSocket 端口
this.logWindowManager.addLog('system', '▶ 步骤8: 检测可用的 WebSocket 端口从7778开始...');
this.logWindowManager.addLog('system', '▶ 步骤9: 检测可用的 WebSocket 端口从7778开始...');
this.websocketPort = await PortChecker.findAvailablePort(7778, 100);
@@ -161,14 +187,16 @@ class Lifecycle {
logger.info(`[lifecycle] WebSocket will use port: ${this.websocketPort}`);
this.startupManager.updateProgress('check-java-port', {
mysqlPort: this.mysqlPort,
influxdbPort: this.influxdbPort,
javaPort: this.javaPort
});
await this.sleep(500);
// 步骤6: 生成配置文件
this.logWindowManager.addLog('system', '▶ 步骤9: 生成 Spring Boot 配置文件...');
this.logWindowManager.addLog('system', '▶ 步骤10: 生成 Spring Boot 配置文件...');
this.startupManager.updateProgress('generate-config', {
mysqlPort: this.mysqlPort,
influxdbPort: this.influxdbPort,
javaPort: this.javaPort,
websocketPort: this.websocketPort
});
@@ -176,6 +204,7 @@ class Lifecycle {
const configGenerator = new ConfigGenerator();
const { configPath, dataPath } = await configGenerator.generateConfig({
mysqlPort: this.mysqlPort,
influxdbPort: this.influxdbPort,
javaPort: this.javaPort,
websocketPort: this.websocketPort,
mysqlPassword: 'njcnpqs'
@@ -194,9 +223,10 @@ class Lifecycle {
await this.sleep(500);
// 步骤7: 启动 Spring Boot
this.logWindowManager.addLog('system', '▶ 步骤10: 启动 Spring Boot 应用...');
this.logWindowManager.addLog('system', '▶ 步骤11: 启动 Spring Boot 应用...');
this.startupManager.updateProgress('start-java', {
mysqlPort: this.mysqlPort,
influxdbPort: this.influxdbPort,
javaPort: this.javaPort,
dataPath: dataPath
});
@@ -204,9 +234,10 @@ class Lifecycle {
await this.startSpringBoot(configPath, dataPath);
// 步骤8: 等待 Spring Boot 就绪
this.logWindowManager.addLog('system', '▶ 步骤11: 等待 Spring Boot 就绪最多60秒...');
this.logWindowManager.addLog('system', '▶ 步骤12: 等待 Spring Boot 就绪最多60秒...');
this.startupManager.updateProgress('wait-java', {
mysqlPort: this.mysqlPort,
influxdbPort: this.influxdbPort,
javaPort: this.javaPort,
dataPath: dataPath
});
@@ -224,9 +255,10 @@ class Lifecycle {
await this.sleep(1000);
// 步骤9: 完成
this.logWindowManager.addLog('system', '▶ 步骤12: 启动完成,准备显示主窗口...');
this.logWindowManager.addLog('system', '▶ 步骤13: 启动完成,准备显示主窗口...');
this.startupManager.updateProgress('done', {
mysqlPort: this.mysqlPort,
influxdbPort: this.influxdbPort,
javaPort: this.javaPort,
dataPath: dataPath
});
@@ -235,6 +267,7 @@ class Lifecycle {
this.logWindowManager.addLog('system', '='.repeat(60));
this.logWindowManager.addLog('success', '✓ 电能质量运维工具 启动完成!所有服务正常运行');
this.logWindowManager.addLog('system', `✓ MySQL 端口: ${this.mysqlPort}`);
this.logWindowManager.addLog('system', `✓ InfluxDB 端口: ${this.influxdbPort}`);
this.logWindowManager.addLog('system', `✓ Java 端口: ${this.javaPort}`);
this.logWindowManager.addLog('system', `✓ WebSocket 端口: ${this.websocketPort}`);
this.logWindowManager.addLog('system', `✓ 数据目录: ${dataPath}`);
@@ -375,7 +408,26 @@ class Lifecycle {
}
}
// 停止 MySQL 进程(进程模式)
// 停止数据库进程(进程模式)
// InfluxDB 只清理当前应用记录的 PID避免影响用户本机其他 InfluxDB 实例。
if (this.influxdbProcessManager) {
try {
logger.info('[lifecycle] Stopping InfluxDB process...');
if (this.logWindowManager && this.logWindowManager.logWindow && !this.logWindowManager.logWindow.isDestroyed()) {
this.logWindowManager.addLog('system', '正在停止 InfluxDB...');
}
await this.influxdbProcessManager.stopInfluxDBProcess();
logger.info('[lifecycle] InfluxDB process stopped');
if (this.logWindowManager && this.logWindowManager.logWindow && !this.logWindowManager.logWindow.isDestroyed()) {
this.logWindowManager.addLog('success', 'InfluxDB 已停止');
}
} catch (error) {
logger.error('[lifecycle] Failed to stop InfluxDB:', error);
}
}
if (this.mysqlProcessManager) {
try {
logger.info('[lifecycle] Stopping MySQL process...');
@@ -427,12 +479,11 @@ class Lifecycle {
// 启动Java应用
this.javaRunner = new JavaRunner();
// 开发环境build/extraResources/java/entrance.jar
// 打包后resources/extraResources/java/entrance.jar
const isDev = !process.resourcesPath;
const jarPath = isDev
? path.join(__dirname, '..', 'build', 'extraResources', 'java', 'entrance.jar')
: path.join(process.resourcesPath, 'extraResources', 'java', 'entrance.jar');
const { resolvePackagedRuntime } = require(getScriptsPath('path-utils'));
const runtime = resolvePackagedRuntime();
const jarPath = runtime.isPackaged
? path.join(runtime.resourcesPath, 'extraResources', 'java', 'entrance.jar')
: path.join(runtime.baseDir, 'build', 'extraResources', 'java', 'entrance.jar');
const logPath = path.join(dataPath, 'logs');