fix: 全站页面保活机制、登录拦截优化、UI修复与功能完善
- 移除未登录全页面拦截,改为浏览自由 + 功能使用时弹窗 - 修复PageTransition退出动画卡死导致黑屏的bug - CanvasPage添加加载中状态避免首次访问黑屏假死 - 全站7个工具页添加页面保活机制,切页后台任务不中断 - 修复未登录时401误触发"用户已在别处登录"弹窗 - 删除MorePage模板板块、微信登录、EcommerceTemplates/SizeTemplate路由 - 剧本评分接入DashScope qwen3.7-max直连API - 电商视频生成重构为3阶段可视管线(策划→生成图片→生成视频) - 电商视频保活增强:异步函数直接写localStorage避免卸载丢失 - Workbench侧边栏移除mode过滤,三模式共用同一对话列表 - 首页更新轮播图/背景视频、按钮跳转修正、文案优化 - AppShell顶栏新增网站备案信息按钮 - 多个页面的terminate/cancel按钮覆盖、单镜头重试、批量保存下载 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -280,6 +280,7 @@ function WorkbenchPage({
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isAuthenticated) return;
|
||||
let cancelled = false;
|
||||
assetClient
|
||||
.list()
|
||||
@@ -2429,7 +2430,6 @@ function WorkbenchPage({
|
||||
projects={conversationRecords}
|
||||
activeId={activeConversationId ? String(activeConversationId) : null}
|
||||
collapsed={sidebarCollapsed}
|
||||
filterMode={activeMode}
|
||||
loading={false}
|
||||
error={projectError}
|
||||
onToggle={() => setSidebarCollapsed((v) => (hasSidebarRecords ? !v : true))}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Generic single-task keep-alive for tool pages.
|
||||
* Persists task state to localStorage so in-progress tasks survive page switches.
|
||||
*/
|
||||
|
||||
const KEEPALIVE_PREFIX = "omniai:tool-task:";
|
||||
|
||||
interface ToolTaskKeepalive {
|
||||
taskId: string;
|
||||
resultUrl: string;
|
||||
resultPreview: string;
|
||||
status: string;
|
||||
progress: number;
|
||||
sourceName: string;
|
||||
sourceUrl: string;
|
||||
savedAt: number;
|
||||
}
|
||||
|
||||
export function saveToolTaskState(key: string, state: {
|
||||
taskId: string;
|
||||
resultUrl?: string;
|
||||
resultPreview?: string;
|
||||
status?: string;
|
||||
progress?: number;
|
||||
sourceName?: string;
|
||||
sourceUrl?: string;
|
||||
}): void {
|
||||
if (!state.taskId) return;
|
||||
try {
|
||||
const entry: ToolTaskKeepalive = {
|
||||
taskId: state.taskId,
|
||||
resultUrl: state.resultUrl || "",
|
||||
resultPreview: state.resultPreview || "",
|
||||
status: state.status || "",
|
||||
progress: state.progress || 0,
|
||||
sourceName: state.sourceName || "",
|
||||
sourceUrl: state.sourceUrl || "",
|
||||
savedAt: Date.now(),
|
||||
};
|
||||
window.localStorage.setItem(KEEPALIVE_PREFIX + key, JSON.stringify(entry));
|
||||
} catch { /* quota */ }
|
||||
}
|
||||
|
||||
export function loadToolTaskState(key: string): ToolTaskKeepalive | null {
|
||||
try {
|
||||
const raw = window.localStorage.getItem(KEEPALIVE_PREFIX + key);
|
||||
if (!raw) return null;
|
||||
const parsed = JSON.parse(raw) as ToolTaskKeepalive;
|
||||
if (Date.now() - (parsed.savedAt || 0) > 2 * 60 * 60 * 1000) {
|
||||
clearToolTaskState(key);
|
||||
return null;
|
||||
}
|
||||
if (!parsed.taskId) return null;
|
||||
return parsed;
|
||||
} catch { return null; }
|
||||
}
|
||||
|
||||
export function clearToolTaskState(key: string): void {
|
||||
try { window.localStorage.removeItem(KEEPALIVE_PREFIX + key); } catch { /* ignore */ }
|
||||
}
|
||||
|
||||
const TASK_POLL_INTERVAL = 3000;
|
||||
const TASK_POLL_TIMEOUT = 30 * 60 * 1000;
|
||||
|
||||
export async function pollTaskUntilDone(
|
||||
taskId: string,
|
||||
onProgress?: (progress: number) => void,
|
||||
abortRef?: { current: boolean },
|
||||
): Promise<string | null> {
|
||||
const startTime = Date.now();
|
||||
const { aiGenerationClient } = await import("../../api/aiGenerationClient");
|
||||
|
||||
while (true) {
|
||||
if (abortRef?.current) return null;
|
||||
if (Date.now() - startTime > TASK_POLL_TIMEOUT) return null;
|
||||
|
||||
try {
|
||||
const task = await aiGenerationClient.getTaskStatus(taskId);
|
||||
if (!task) return null;
|
||||
|
||||
const progress = Math.min(99, task.progress || 0);
|
||||
onProgress?.(progress);
|
||||
|
||||
if (task.status === "completed") {
|
||||
return task.resultUrl || null;
|
||||
}
|
||||
if (task.status === "failed" || task.status === "cancelled") {
|
||||
return null;
|
||||
}
|
||||
} catch {
|
||||
// retry on next poll
|
||||
}
|
||||
|
||||
await new Promise((r) => setTimeout(r, TASK_POLL_INTERVAL));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user