"use client"; import Link from "next/link"; import { startTransition, useDeferredValue, useEffect, useMemo, useRef, useState, type ChangeEvent, type ComponentProps, type DragEvent, type ReactNode, } from "react"; import useSWR from "swr"; import { toast } from "sonner"; import { motion, AnimatePresence } from "framer-motion"; import { ArrowDown, ArrowLeft, ArrowUp, ChevronDown, ChevronRight, ClipboardPaste, Copy, Download, GripVertical, Image as ImageIcon, Layers, Loader2, MonitorPlay, Package, Plus, Save, Search, Settings2, Sparkles, Trash2, Upload, UserCircle, Video, } from "lucide-react"; import { AGENT_WORKFLOW_PROMPT_FRAGMENT_MAX_LENGTH, defaultAgentWorkflowConstraintSettings, defaultAgentWorkflowPageFeatureSettings, AGENT_WORKFLOW_MAX_OPTION_DEPTH, AGENT_WORKFLOW_MAX_TREE_DEPTH, countAgentWorkflowOptions, countAgentWorkflowOptionTree, countAgentWorkflowSteps, defaultAgentWorkflowCategoryLabels, defaultAgentWorkflowUiConfig, findAgentWorkflowOptionByKey, findAgentWorkflowStepByKey, flattenAgentWorkflowOptionTree, getEnabledAgentWorkflowOptionTree, getAgentWorkflowCategoryLabels, getAgentWorkflowConstraintSettings, getAgentWorkflowPageFeatureSettings, normalizeAgentWorkflowOptionOrdering, flattenAgentWorkflowSteps, normalizeAgentWorkflowStepOrdering, normalizeAgentWorkflowUiConfig, } from "@/lib/agents/workflow-ui-config"; import { defaultAgentWorkflowBrandModelConfig, normalizeAgentWorkflowBrandModelConfig, } from "@/lib/agents/workflow-brand-model-config"; import { AGENT_PRESET_LIBRARY_DEFAULT_SECTION_ID, AGENT_PRESET_LIBRARY_MAX_DEPTH, defaultAgentPresetLibraryConfig, normalizeAgentPresetLibraryConfig, } from "@/lib/agents/preset-library-config"; import { defaultAgentWorkflowShowcaseConfig, normalizeAgentWorkflowShowcaseConfig, } from "@/lib/agents/workflow-showcase-config"; import { defaultAgentWorkflowMaterialApiConfig, normalizeAgentWorkflowMaterialApiConfig, } from "@/lib/agents/workflow-material-config"; import { defaultAgentWorkflowGoodsInfoApiConfig, normalizeAgentWorkflowGoodsInfoApiConfig, } from "@/lib/agents/workflow-goods-info-config"; import { defaultAgentPsdTextColorConfig, normalizeAgentPsdTextColorConfig, resolveAgentPsdTextColorConfigForBrand, } from "@/lib/agents/psd-text-color-config"; import { defaultAgentPsdTemplateSecondaryCategoryConfig, type AgentPsdTemplateSecondaryCategoryConfig, normalizeAgentPsdTemplateSecondaryCategoryConfig, } from "@/lib/agents/psd-template-secondary-category-config"; import { AGENT_WORKFLOW_BRAND_IMPORT_ACCEPT, downloadAgentWorkflowBrandImportTemplate, parseAgentWorkflowBrandImportFile, } from "@/lib/agents/workflow-brand-import"; import { normalizeHexColor } from "@/lib/agents/psd-text-layout"; import { fetchUploadWithRetry } from "@/lib/client/upload-with-retry"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Switch } from "@/components/ui/switch"; import { Badge } from "@/components/ui/badge"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"; import { Separator } from "@/components/ui/separator"; import { SearchableSelect } from "@/components/ui/searchable-select"; import { cn } from "@/lib/utils"; import type { AgentPresetLibraryCategoryNode, AgentPresetLibraryConfig, AgentPsdTextColorBrandConfig, AgentPresetLibrarySection, AgentWorkflowBrandModelConfig, AgentWorkflowBrandStoreEntry, AgentWorkflowCategoryLabels, AgentWorkflowFourthCategoryEntry, AgentWorkflowGoodsInfoApiConfig, AgentWorkflowMaterialApiConfig, AgentWorkflowOptionUiConfig, AgentPsdTextColorConfig, AgentWorkflowStoreEntry, AgentWorkflowThirdCategoryEntry, AgentWorkflowShowcaseConfig, AgentWorkflowStepUiConfig, AgentWorkflowUiConfig, } from "@/types/agent"; const fetcher = (url: string) => fetch(url, { cache: "no-store" }).then((res) => res.json()); // Animation variants const containerVariants = { hidden: { opacity: 0 }, visible: { opacity: 1, transition: { staggerChildren: 0.05 } } }; const itemVariants = { hidden: { opacity: 0, y: 10 }, visible: { opacity: 1, y: 0 } }; const CHINESE_LEVEL_NUMERALS = ["一", "二", "三", "四", "五", "六", "七", "八"]; const WORKFLOW_LEVEL_LABELS = CHINESE_LEVEL_NUMERALS.map((item) => `${item}级模块`); const WORKFLOW_OPTION_LEVEL_LABELS = CHINESE_LEVEL_NUMERALS.map((item) => `${item}级卡片`); const PRESET_LIBRARY_LEVEL_LABELS = ["一级分类", "二级分类", "三级分类"]; const WORKFLOW_STEP_DRAG_DATA_TYPE = "application/x-agent-workflow-step"; const WORKFLOW_SETTINGS_DRAFT_STORAGE_KEY = "agent-workflow-settings-draft:v1"; const WORKFLOW_SETTINGS_STALE_DRAFT_STORAGE_KEY = "agent-workflow-settings-stale-draft:v1"; const WORKFLOW_SETTINGS_DRAFT_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000; const WORKFLOW_BLOCKED_CANDIDATE_RENDER_LIMIT = 60; type WorkflowStepDropPosition = "before" | "after" | "inside"; interface WorkflowStepDropTarget { stepKey: string | null; position: WorkflowStepDropPosition; } interface AgentWorkflowSettingsDraftState { presetLibraryConfig: AgentPresetLibraryConfig; config: AgentWorkflowUiConfig; materialApiConfig: AgentWorkflowMaterialApiConfig; goodsInfoApiConfig: AgentWorkflowGoodsInfoApiConfig; brandModelConfig: AgentWorkflowBrandModelConfig; showcaseConfig: AgentWorkflowShowcaseConfig; psdTextColorConfig: AgentPsdTextColorConfig; psdTemplateSecondaryCategoryConfig: AgentPsdTemplateSecondaryCategoryConfig; } interface AgentWorkflowSettingsDraft { version: 1 | 2; updatedAt: number; baseSignature?: string; baseSignatures?: Partial>; state: AgentWorkflowSettingsDraftState; } type BufferedInputProps = Omit< ComponentProps, "defaultValue" | "onChange" | "value" > & { commitDelayMs?: number; onValueCommit: (value: string) => void; value: string; }; type BufferedTextareaProps = Omit< ComponentProps, "defaultValue" | "onChange" | "value" > & { commitDelayMs?: number; onValueCommit: (value: string) => void; value: string; }; function scheduleWorkflowIdleTask(callback: () => void, timeoutMs = 2000) { if (typeof window === "undefined") { return () => {}; } if ("requestIdleCallback" in window && "cancelIdleCallback" in window) { const idleId = window.requestIdleCallback(callback, { timeout: timeoutMs }); return () => window.cancelIdleCallback(idleId); } const timer = window.setTimeout(callback, timeoutMs); return () => window.clearTimeout(timer); } function BufferedInput({ commitDelayMs = 450, onBlur, onValueCommit, value, ...props }: BufferedInputProps) { const [draftValue, setDraftValue] = useState(value); const committedValueRef = useRef(value); useEffect(() => { setDraftValue(value); committedValueRef.current = value; }, [value]); const commitValue = (nextValue: string, options?: { immediate?: boolean }) => { if (nextValue === committedValueRef.current) { return; } committedValueRef.current = nextValue; if (options?.immediate) { onValueCommit(nextValue); return; } startTransition(() => { onValueCommit(nextValue); }); }; useEffect(() => { if (draftValue === committedValueRef.current) { return; } const timer = window.setTimeout(() => { commitValue(draftValue); }, commitDelayMs); return () => window.clearTimeout(timer); }, [commitDelayMs, draftValue]); return ( setDraftValue(event.target.value)} onBlur={(event) => { commitValue(draftValue, { immediate: true }); onBlur?.(event); }} /> ); } function BufferedTextarea({ commitDelayMs = 450, onBlur, onValueCommit, value, ...props }: BufferedTextareaProps) { const [draftValue, setDraftValue] = useState(value); const committedValueRef = useRef(value); useEffect(() => { setDraftValue(value); committedValueRef.current = value; }, [value]); const commitValue = (nextValue: string, options?: { immediate?: boolean }) => { if (nextValue === committedValueRef.current) { return; } committedValueRef.current = nextValue; if (options?.immediate) { onValueCommit(nextValue); return; } startTransition(() => { onValueCommit(nextValue); }); }; useEffect(() => { if (draftValue === committedValueRef.current) { return; } const timer = window.setTimeout(() => { commitValue(draftValue); }, commitDelayMs); return () => window.clearTimeout(timer); }, [commitDelayMs, draftValue]); return (