feat: implement task management store with IPC integration

- Added a new task store in `src-react/stores/task.ts` to manage tasks and their statuses.
- Implemented functions for creating, executing, and retrying tasks, along with handling task progress and completion.
- Introduced persistence for tasks using IPC.
- Created utility functions for normalizing room types and building subtasks.
- Added a new CSS file for global styles in `src-react/styles.css`.
- Created runtime types in `src-react/types/runtime.ts` and exported them.
- Updated the main entry points for Vue and React applications to support dynamic framework loading.
- Refactored chat model interfaces and utility functions into `src/shared/chat-model.ts`.
- Updated TypeScript configuration to include paths for React components and types.
- Enhanced Vite configuration to support both Vue and React frameworks.
This commit is contained in:
duanshuwen
2026-04-17 07:09:56 +08:00
parent d233b94b2a
commit b1dea9a5c2
68 changed files with 5910 additions and 397 deletions

View File

@@ -3,7 +3,7 @@ import { createProvider } from '@electron/providers';
import type { BaseProvider } from '@electron/providers/BaseProvider';
import { providerApiService } from '@electron/service/provider-api-service';
import logManager from '@electron/service/logger';
import type { RawMessage } from '@src/pages/home/model/ChatModel';
import type { RawMessage } from '@shared/chat-model';
import { sessionStore } from '../session-store';
import type { GatewayEvent, GatewayRpcParams, GatewayRpcReturns } from '../types';
import { appendTranscriptLine } from '@electron/utils/token-usage-writer';
@@ -197,3 +197,10 @@ export function handleChatAbort(
export function handleSessionList(): GatewayRpcReturns['session.list'] {
return sessionStore.getAllKeys();
}
export function handleSessionDelete(
params: GatewayRpcParams['session.delete']
): GatewayRpcReturns['session.delete'] {
sessionStore.deleteSession(params.sessionKey);
return { success: true };
}

View File

@@ -31,6 +31,8 @@ class GatewayManager {
return chatHandlers.handleChatAbort(params, (event) => this.broadcast(event));
case 'session.list':
return chatHandlers.handleSessionList();
case 'session.delete':
return chatHandlers.handleSessionDelete(params);
case 'provider.list':
return providerHandlers.handleProviderList();
case 'provider.getDefault':

View File

@@ -2,7 +2,7 @@ import * as fs from 'fs';
import * as path from 'path';
import { app } from 'electron';
import logManager from '@electron/service/logger';
import type { RawMessage } from '@src/pages/home/model/ChatModel';
import type { RawMessage } from '@shared/chat-model';
let sessionsFilePath: string | null = null;

View File

@@ -1,4 +1,4 @@
import type { RawMessage } from '@src/pages/home/model/ChatModel';
import type { RawMessage } from '@shared/chat-model';
/// Gateway 向 Renderer 推送的事件类型
export type GatewayEvent =
@@ -47,6 +47,9 @@ export interface GatewayRpcParams {
sessionKey: string;
};
'session.list': Record<string, never>;
'session.delete': {
sessionKey: string;
};
'provider.list': Record<string, never>;
'provider.getDefault': Record<string, never>;
}
@@ -57,6 +60,7 @@ export interface GatewayRpcReturns {
'chat.history': RawMessage[];
'chat.abort': void;
'session.list': string[];
'session.delete': { success: boolean };
'provider.list': { accounts: any[]; defaultAccountId: string | null };
'provider.getDefault': { accountId: string | null };
}

View File

@@ -230,7 +230,14 @@ export function runTaskOperationService() {
ipcMain.handle(IPC_EVENTS.EXECUTE_SCRIPT, async (_event, options: any) => {
try {
const taskId = options.taskId || randomUUID();
const roomType = options.roomList.find((item: any) => item.id === options.roomType);
const roomTypeRaw = options.roomList.find((item: any) => item.id === options.roomType);
const roomType = roomTypeRaw
? {
...roomTypeRaw,
dyHotSpringName: roomTypeRaw.dyHotSpringName ?? roomTypeRaw.dyHotSrpingName,
dyHotSrpingName: roomTypeRaw.dyHotSrpingName ?? roomTypeRaw.dyHotSpringName,
}
: null;
const pairs: Array<[string, string]> = [
['fzName', 'fg_trace.js'],
@@ -238,7 +245,12 @@ export function runTaskOperationService() {
['dyHotelName', 'dy_hotel_trace.js'],
['dyHotSpringName', 'dy_hot_spring_trace.js']
]
const scriptEntries = pairs.filter(([prop]) => roomType?.[prop])
const scriptEntries = pairs.filter(([prop]) => {
if (prop === 'dyHotSpringName') {
return roomType?.dyHotSpringName || roomType?.dyHotSrpingName
}
return roomType?.[prop]
})
const scriptsDir = getScriptsDir()
@@ -301,7 +313,9 @@ export function runTaskOperationService() {
const result = await executeScriptServiceInstance.executeScript(
item.scriptPath,
{
roomType: roomType[item.channel],
roomType: item.channel === 'dyHotSpringName'
? (roomType.dyHotSpringName || roomType.dyHotSrpingName)
: roomType[item.channel],
startTime: options.startTime,
endTime: options.endTime,
operation: options.operation,