Files
omniai-ds-code-package/src/hooks/useGenerationTasks.ts
T
stringadmin 6d93c2b9b8 refactor: 清理未使用参数、移除死代码、聚焦电商核心模块
主要变更概述:
================

1. 清理未使用的函数参数 (TypeScript noUnusedParameters)
------------------------------------------------------
- AppShell.tsx: 移除未使用的 backendHealth prop 及 ServerConnectionHealth 导入
- canvasUtils.ts: 移除 resolveWorkflowVideoModel 的 workflowModel 参数
- canvasWorkflowDeserialize.ts: 同步更新调用方
- CanvasPage.tsx: 移除 resolveWorkflowVideoModel 未使用导入
- HomePage.tsx: 移除 onOpenTokenMonitor、onOpenImageTool 未使用 props
- ToolboxSection.tsx: 移除 onOpenImageTool 未使用 prop 及 WebImageWorkbenchTool 类型导入
- ScriptTokensPage.tsx: 移除 formatReportMarkdown 的 script 参数,更新 2 处调用
- TokenUsagePage.tsx: 移除 onOpenImageTool、onSelectView 未使用 props
- WorkbenchPage.tsx: 移除 renderComposerToolbar 的 showStop 参数,更新 2 处调用

2. 移除未使用的模块和死代码
--------------------------
删除以下未在电商模块中使用的功能模块:
- 画布模块 (canvas/): CanvasPage, canvasUtils, canvasWorkflow* 等
- 主页模块 (home/): HomePage, ToolboxSection, WelcomeSplash 等
- 工作台模块 (workbench/): WorkbenchPage, ConversationSidebar 等
- 社区模块 (community/, community-review/)
- 数字人模块 (digital-human/)
- 图片工作台 (image-workbench/)
- 其他独立工具页: agent, assets, beta-applications, character-mix,
  compliance, dialog-generator, more, profile, provider-health,
  report, resolution-upscale, script-tokens, settings, size-template,
  subtitle-removal, watermark-removal

3. 移除未使用的公共组件
----------------------
- AnimatedPanel, BeforeAfterCompare, BetaApplicationModal
- CookieConsentBanner, DropZone, EmptyState, NotFoundPage
- NotificationCenter, OnboardingTour, OptimizedImage
- PageTransition, RechargeModal, ShellIcon, Skeleton
- StudioToolLayout, TaskStatusBar, WorkspacePageShell

4. 移除未使用的 API 客户端
--------------------------
- betaApplicationClient, communityClient, conversationClient
- draftClient, modelCapabilitiesClient, notificationClient
- projectTaskClient, providerHealthClient, publicConfigClient
- referenceUploadService, reportClient, scriptEvalClient
- uploadWithProgress

5. 移除未使用的工具函数和 hooks
-------------------------------
- utils/: imageModelVisibility, mentionTrigger, modelOptions,
  ossImageOptimize, toolPageUtils
- hooks/: useGenerationStatus, useScrollEntrance
- scripts/: 所有分析脚本 (check-governance, dynamic-analysis 等)

6. 移除未使用的样式文件
----------------------
删除与已移除模块对应的 CSS 文件,保留电商模块专用样式

7. 新增电商模块功能文件
----------------------
+ src/api/generationRecordClient.ts (生成记录客户端)
+ src/features/ecommerce/ecommerceGenerationPersistence.ts (生成持久化)

验证:
- TypeScript 编译 (tsc --noEmit --noUnusedParameters) 零错误通过
- 所有保留文件的功能完整性未受影响
2026-06-12 11:12:55 +08:00

177 lines
5.4 KiB
TypeScript

import { useEffect, useMemo, useRef, useCallback } from "react";
import { useShallow } from "zustand/react/shallow";
import type { GenerationQueueItem } from "../stores/useGenerationStore";
import { useGenerationStore } from "../stores/useGenerationStore";
import { saveGenerationRecord, type GenerationRecordStatus } from "../api/generationRecordClient";
import {
startBackgroundPolling,
subscribeToTaskUpdates,
} from "../services/backgroundTaskRunner";
interface UseGenerationTasksOptions {
sourceView: string;
autoResume?: boolean;
}
type TerminalGenerationRecordStatus = Extract<GenerationRecordStatus, GenerationQueueItem["status"]>;
function isTerminalStatus(status: GenerationQueueItem["status"] | undefined): status is TerminalGenerationRecordStatus {
return status === "completed" || status === "failed" || status === "cancelled";
}
function persistUnifiedTaskRecord(task: GenerationQueueItem): void {
if (!isTerminalStatus(task.status)) return;
void saveGenerationRecord({
clientRecordId: task.id,
tool: task.sourceView,
mode: task.type,
title: task.title,
status: task.status,
prompt: task.prompt,
taskIds: task.taskId ? [task.taskId] : [],
assets: task.resultUrl
? [{
role: "result",
mediaType: task.type === "video" || task.type === "ecommerce-video" ? "video" : "image",
url: task.resultUrl,
taskId: task.taskId,
scope: `${task.sourceView}/result/${task.type}`,
}]
: [],
config: task.params,
result: {
resultUrl: task.resultUrl,
error: task.error,
progress: task.progress,
},
metadata: {
queueCreatedAt: task.createdAt,
source: "generation-queue",
},
createdAt: new Date(task.createdAt).toISOString(),
});
}
export function useGenerationTasks(options: UseGenerationTasksOptions) {
const { sourceView, autoResume = true } = options;
const {
queue,
addTask,
updateTask: updateStoredTask,
getRunningTasks,
} = useGenerationStore(useShallow((s) => ({
queue: s.queue,
addTask: s.addTask,
updateTask: s.updateTask,
getRunningTasks: s.getRunningTasks,
})));
const pollingStartedRef = useRef(false);
// ── Auto-resume: re-subscribe to running tasks on mount ────
useEffect(() => {
if (!autoResume || pollingStartedRef.current) return;
pollingStartedRef.current = true;
const active = getRunningTasks().filter((t) => t.sourceView === sourceView);
if (active.length > 0) {
startBackgroundPolling();
}
return () => {
pollingStartedRef.current = false;
};
}, [autoResume, sourceView, getRunningTasks]);
// ── Subscribe to live updates ───────────────────────────
useEffect(() => {
return subscribeToTaskUpdates((updated) => {
updateStoredTask(updated.id, updated);
});
}, [updateStoredTask]);
// ── View-scoped computed lists ──────────────────────────
const myTasks = useMemo(
() => queue.filter((t) => t.sourceView === sourceView),
[queue, sourceView],
);
const activeTasks = useMemo(
() => myTasks.filter((t) => t.status === "running" || t.status === "pending"),
[myTasks],
);
const completedTasks = useMemo(
() => myTasks.filter((t) => t.status === "completed"),
[myTasks],
);
const failedTasks = useMemo(
() => myTasks.filter((t) => t.status === "failed"),
[myTasks],
);
// ── Actions ─────────────────────────────────────────────
const submitTask = useCallback(
(task: Omit<GenerationQueueItem, "id" | "createdAt">) => {
const id = `gen-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
addTask({ ...task, id, createdAt: Date.now() });
return id;
},
[addTask],
);
const updateTask = useCallback(
(id: string, patch: Partial<GenerationQueueItem>) => {
if (isTerminalStatus(patch.status)) {
const current = queue.find((task) => task.id === id);
if (current) persistUnifiedTaskRecord({ ...current, ...patch });
}
updateStoredTask(id, patch);
},
[queue, updateStoredTask],
);
const markCompleted = useCallback(
(id: string, resultUrl: string) => {
const current = queue.find((task) => task.id === id);
const patch: Partial<GenerationQueueItem> = { status: "completed", progress: 100, resultUrl };
if (current) persistUnifiedTaskRecord({ ...current, ...patch });
updateStoredTask(id, patch);
},
[queue, updateStoredTask],
);
const markFailed = useCallback(
(id: string, error: string) => {
const current = queue.find((task) => task.id === id);
const patch: Partial<GenerationQueueItem> = { status: "failed", error };
if (current) persistUnifiedTaskRecord({ ...current, ...patch });
updateStoredTask(id, patch);
},
[queue, updateStoredTask],
);
const retryTask = useCallback(
(id: string) => {
const task = queue.find((t) => t.id === id);
if (task) {
updateStoredTask(id, { status: "pending", progress: 0, error: null });
}
},
[queue, updateStoredTask],
);
return {
tasks: myTasks,
activeTasks,
completedTasks,
failedTasks,
submitTask,
updateTask,
markCompleted,
markFailed,
retryTask,
hasActiveTasks: activeTasks.length > 0,
};
}