diff --git a/apps/web/src/pages/generate/hooks/useGenerateFormState/useTemplateSelection.ts b/apps/web/src/pages/generate/hooks/useGenerateFormState/useTemplateSelection.ts deleted file mode 100755 index 2fe7a8c24..000000000 --- a/apps/web/src/pages/generate/hooks/useGenerateFormState/useTemplateSelection.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { useState, useEffect, useRef, useCallback, useMemo } from "react" -import { useQuery } from "@tanstack/react-query" -import { message } from "antd" -import { getEditingTemplates } from "@/api/editing-planner" -import type { EditingTemplate } from "@/api/editing-planner" -import { findFirstValidTemplate, isValidTemplate } from "./templateFallback" - -/** 失效模板自动切换的提示文案 */ -export const INVALID_TEMPLATE_FALLBACK_TOAST = "原模板已失效,已自动切换" - -export function useTemplateSelection() { - // selectedTemplate 纯内存状态,绝不写入 localStorage/sessionStorage/URL, - // 因此失效模板 ID 不会被持久化、刷新后也不会恢复(#1777 要求 4) - const [selectedTemplate, setSelectedTemplate] = useState("") - - const { data: allTemplates = [] } = useQuery({ - queryKey: ["generate-templates"], - // valid_only:后端过滤掉没有片段配置的无效模板(#1769/#1772)。 - // 旧后端忽略该 query 参数时,下方 isValidTemplate 前端兜底再过滤一次。 - queryFn: () => getEditingTemplates({ validOnly: true }), - staleTime: 60_000, - }) - - // 双保险:后端 valid_only 已过滤,前端再按 is_active + segments 兜底, - // 保证下拉/自动选择只包含可用于生成的有效模板。 - // 用 useMemo 缓存引用,避免每次渲染都 .filter 创建新数组, - // 导致下游 useTitleCoverSync effect 无限触发、覆盖用户手动修改(#1789) - const validTemplates = useMemo(() => allTemplates.filter(isValidTemplate), [allTemplates]) - const userTemplates = validTemplates - - // 用 ref 持有最新值,供稳定回调 handleInvalidTemplate 使用(避免闭包拿到旧值) - const templatesRef = useRef(validTemplates) - templatesRef.current = validTemplates - const selectedRef = useRef(selectedTemplate) - selectedRef.current = selectedTemplate - // 已提示过失效的模板 ID,避免用户停留在失效模板上时 clips 防抖请求反复弹 toast; - // 用户手动切换/成功切换后重置,保证下一个失效模板仍能提示 - const fallbackNotifiedRef = useRef("") - - /* 自动选择:模板加载完成且当前未选中时,自动选中第一个有效模板。 - * 用户手动选择(setSelectedTemplate 被显式调用)后 selectedTemplate 非空, - * 本 effect 直接 return,绝不覆盖用户的手动选择(#1777 要求 4:手动优先)。 */ - useEffect(() => { - if (selectedTemplate) return - const firstValid = validTemplates[0] - if (firstValid) { - setSelectedTemplate(firstValid.id) - } - }, [validTemplates, selectedTemplate]) - - /** 用户手动选择模板:优先级最高,重置失效提示标记 */ - const handleSelectTemplate = useCallback((id: string) => { - fallbackNotifiedRef.current = "" - setSelectedTemplate(id) - }, []) - - /** - * 运行时失效回退(#1777 要求 3): - * 创建片段接口返回 404(模板不存在)/ 400/422(模板无片段配置)时调用。 - * - 清除失效选择,自动切换到第一个有效模板,并 toast 提示; - * - 没有有效模板时清空选择,Step1 展示明确的「暂无可用模板」空状态引导, - * 不让用户卡在失效模板上。 - * 返回 true 表示已按「模板失效」处理(调用方可据此静默原始错误提示)。 - */ - const handleInvalidTemplate = useCallback((): boolean => { - const current = selectedRef.current - // 同一个失效模板只提示一次(clips 防抖 effect 在素材/模板变化时会反复触发) - if (current && fallbackNotifiedRef.current === current) return true - - const fallback = findFirstValidTemplate(templatesRef.current) - fallbackNotifiedRef.current = current || "__empty__" - if (fallback) { - setSelectedTemplate(fallback.id) - message.warning(INVALID_TEMPLATE_FALLBACK_TOAST) - } else { - // 没有任何有效模板:清空选择,交由 Step1 空状态引导用户去模板编辑器创建 - setSelectedTemplate("") - message.warning("当前没有可用模板,请先在「模板编辑器」中创建并配置片段") - } - return true - }, []) - - return { - selectedTemplate, - setSelectedTemplate: handleSelectTemplate, - userTemplates, - handleInvalidTemplate, - } -}