feat: add task management and progress reporting

- Implemented task and subtask structures with progress tracking.
- Added reporting functionality to log progress at various stages in hotel room status management scripts.
- Created a task store to manage tasks and their states, including persistence to local storage.
- Updated UI components to display task lists and handle task actions (retry, remove).
- Removed deprecated TaskCard and TaskList components, replacing them with a new structure for better maintainability.
- Enhanced script execution service to emit progress events for UI updates.
This commit is contained in:
DEV_DSW
2026-04-16 16:59:49 +08:00
parent b1f589a674
commit 210e8eb363
24 changed files with 788 additions and 237 deletions

View File

@@ -1,5 +1,5 @@
import { ipcMain, app } from 'electron';
import { ipcMain, app, BrowserWindow } from 'electron';
import { IPC_EVENTS } from '@lib/constants';
import { launchLocalChrome } from '@electron/utils/chrome/launchLocalChrome'
import { executeScriptService } from '@electron/service/execute-script-service';
@@ -15,6 +15,7 @@ import fs from 'fs'
import path from 'path'
import { spawn } from 'child_process'
import log from 'electron-log';
import { randomUUID } from 'crypto';
const openedTabIndexByChannelName = new Map<string, number>()
@@ -228,7 +229,7 @@ export function runTaskOperationService() {
// 执行脚本
ipcMain.handle(IPC_EVENTS.EXECUTE_SCRIPT, async (_event, options: any) => {
try {
// 从options.roomList列表中找到对应的名称
const taskId = options.taskId || randomUUID();
const roomType = options.roomList.find((item: any) => item.id === options.roomType);
const pairs: Array<[string, string]> = [
@@ -246,33 +247,82 @@ export function runTaskOperationService() {
if (!fs.existsSync(p)) {
throw new Error(`Script not found for channel ${channel}: ${p}`)
}
return { channel, scriptPath: p }
return { channel, fileName, scriptPath: p }
})
const channelNameMap: Record<string, string> = {
fzName: 'fliggy',
mtName: 'meituan',
dyHotelName: 'douyin',
dyHotSpringName: 'douyin',
}
const defaultTabIndexMap: Record<string, number> = {
fliggy: 0,
meituan: 1,
douyin: 2
}
const results: any[] = []
for (let i = 0; i < scriptPaths.length; i++) {
const item = scriptPaths[i]
const channelNameMap: Record<string, string> = {
fzName: 'fliggy',
mtName: 'meituan',
dyHotelName: 'douyin',
dyHotSpringName: 'douyin',
}
const defaultTabIndexMap: Record<string, number> = {
fliggy: 0,
meituan: 1,
douyin: 2
}
const subTaskId = `${taskId}_${item.channel}`;
const mappedName = channelNameMap[item.channel]
const tabIndex = mappedName ? (openedTabIndexByChannelName.get(mappedName) ?? defaultTabIndexMap[mappedName] ?? i) : i
const win = BrowserWindow.getAllWindows()[0];
win?.webContents.send(IPC_EVENTS.TASK_STARTED, {
taskId,
subTaskId,
scriptId: item.fileName,
name: item.channel,
});
const onProgress = (payload: any) => {
win?.webContents.send(IPC_EVENTS.TASK_PROGRESS, payload);
};
const onStdout = (payload: any) => {
win?.webContents.send(IPC_EVENTS.TASK_PROGRESS, {
...payload,
stdoutTail: payload.text,
});
};
const onStderr = (payload: any) => {
win?.webContents.send(IPC_EVENTS.TASK_PROGRESS, {
...payload,
stderrTail: payload.text,
});
};
executeScriptServiceInstance.on('progress', onProgress);
executeScriptServiceInstance.on('stdout', onStdout);
executeScriptServiceInstance.on('stderr', onStderr);
log.info(`Launching script for channel ${item.channel}: ${item.scriptPath} (tabIndex: ${tabIndex})`)
const result = await executeScriptServiceInstance.executeScript(item.scriptPath, {
roomType: roomType[item.channel],
startTime: options.startTime,
endTime: options.endTime,
operation: options.operation,
tabIndex,
})
const result = await executeScriptServiceInstance.executeScript(
item.scriptPath,
{
roomType: roomType[item.channel],
startTime: options.startTime,
endTime: options.endTime,
operation: options.operation,
tabIndex,
},
taskId,
subTaskId,
);
executeScriptServiceInstance.off('progress', onProgress);
executeScriptServiceInstance.off('stdout', onStdout);
executeScriptServiceInstance.off('stderr', onStderr);
win?.webContents.send(IPC_EVENTS.TASK_COMPLETED, {
taskId,
subTaskId,
success: result.success,
exitCode: result.exitCode,
error: result.error,
});
results.push({
channel: item.channel,
scriptPath: item.scriptPath,