diff --git a/src/features/ecommerce/EcommercePage.tsx b/src/features/ecommerce/EcommercePage.tsx index 8561020..81d5cc7 100644 --- a/src/features/ecommerce/EcommercePage.tsx +++ b/src/features/ecommerce/EcommercePage.tsx @@ -32,6 +32,7 @@ import { Gift, MagicWand, Mountains, + PaperPlaneRight, ShoppingBag, User, VideoCamera, @@ -289,7 +290,9 @@ type CloneModelPanelTab = "scene" | "model"; type CloneVideoQualityKey = "standard" | "high" | "ultra"; type ProductSetStatus = "idle" | "ready" | "generating" | "done" | "failed"; type ProductKitToolKey = "set" | "detail" | "wear" | "clone"; -type ComposerMenuKey = "mode" | "platform" | "language" | "ratio" | "settings"; +type ComposerMenuKey = "mode" | "platform" | "language" | "ratio" | "settings" | "assetLibrary" | "workMode" | "aiWrite"; +type ComposerAssetTabKey = "recent" | "recipe" | "model"; +type ComposerWorkModeKey = "quick" | "think"; type CloneBasicSelectKey = "platform" | "market" | "language" | "ratio"; type CloneModelSelectKey = "gender" | "age" | "ethnicity" | "body"; type CloneReferenceMode = "upload" | "link"; @@ -1062,11 +1065,13 @@ const commerceScenarioOptions: Array<{ key: CommerceScenarioKey; label: string; { key: "model", label: "模特图", desc: "真人展示", icon: 🕴️ }, { key: "scene", label: "场景图", desc: "生活氛围", icon: 🌅 }, { key: "festival", label: "节日风格图", desc: "节点营销", icon: 🎉 }, + { key: "salesVideo", label: "带货视频", desc: "短视频脚本", icon: 🎬 }, { key: "background", label: "更换背景", desc: "背景重构", icon: }, { key: "retouch", label: "无痕改图", desc: "精修优化", icon: 🪄 }, - { key: "salesVideo", label: "带货视频", desc: "短视频脚本", icon: 🎬 }, ]; const primaryCommerceScenarioKeys: CommerceScenarioKey[] = ["popular", "poster", "mainImage", "model"]; +const scenarioSettingsKeys: CommerceScenarioKey[] = ["poster", "mainImage", "model", "scene", "festival", "salesVideo"]; +const scenarioAdvancedSettingsKeys: CommerceScenarioKey[] = ["model", "salesVideo"]; const commerceScenarioOutputMap: Record, ProductSetOutputKey> = { poster: "set", mainImage: "set", @@ -1937,6 +1942,10 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { const [isComposerMenuClosing, setIsComposerMenuClosing] = useState(false); const [composerPopoverLeft, setComposerPopoverLeft] = useState(0); const [composerPopoverTop, setComposerPopoverTop] = useState(0); + const [composerTooltip, setComposerTooltip] = useState<{ text: string; left: number; top: number } | null>(null); + const [composerAssetTab, setComposerAssetTab] = useState("recent"); + const [composerWorkMode, setComposerWorkMode] = useState("quick"); + const [aiWriteDraft, setAiWriteDraft] = useState(""); const [isCommandHistoryCollapsed, setIsCommandHistoryCollapsed] = useState(true); const [inspirationPreview, setInspirationPreview] = useState<{ mediaUrl: string; mediaType: "image" | "video"; prompt: string } | null>(null); const [isQuickPanelCollapsed, setIsQuickPanelCollapsed] = useState(false); @@ -2400,6 +2409,18 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { [cloneOutput, platform], ); const cloneRatioOptions = baseCloneRatioOptions; + const composerRatioOptions = useMemo( + () => [ + "1000×1000px 1:1", + "800×1200px 2:3", + "1200×800px 3:2", + "1200×900px 4:3", + "900×1200px 3:4", + "1080×1920px 9:16", + "1920×1080px 16:9", + ], + [], + ); const productSetLanguageOptions = useMemo( () => getPlatformLanguageOptions(productSetPlatform, productSetMarket), [productSetMarket, productSetPlatform], @@ -2445,6 +2466,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { : activeCommerceScenario === "popular" ? popularCommerceScenarioTemplates : commerceScenarioTemplates.filter((template) => template.scenario === activeCommerceScenario); + const shouldShowScenarioSettings = activeCommerceScenario !== null && scenarioSettingsKeys.includes(activeCommerceScenario); useEffect(() => { templateStripRef.current?.scrollTo({ left: 0, behavior: "auto" }); }, [activeCommerceScenario, isCloneTemplateStripVisible]); @@ -3844,7 +3866,8 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { const handleCommerceScenarioClick = (nextScenario: CommerceScenarioKey) => { if (nextScenario === activeCommerceScenario) { - setIsCloneTemplateStripVisible((visible) => !visible); + setActiveCommerceScenario(null); + setIsCloneTemplateStripVisible(false); setComposerMenu(null); return; } @@ -5803,6 +5826,96 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { ? String(cloneVideoDuration) + "秒 " + (cloneVideoQuality === "standard" ? "720P" : "1080P") : "换装素材"; + const composerAssetTabs: Array<{ key: ComposerAssetTabKey; label: string }> = [ + { key: "recent", label: "最近保存" }, + { key: "recipe", label: "套图配方" }, + { key: "model", label: "模特库" }, + ]; + const composerWorkModeOptions: Array<{ key: ComposerWorkModeKey; label: string; desc: string }> = [ + { key: "quick", label: "快捷", desc: "快速整理提示词,适合常规商品图生成。" }, + { key: "think", label: "思考", desc: "更强调卖点拆解、场景规划和图文一致性。" }, + ]; + + const applyAiWriteSuggestion = () => { + const keyword = aiWriteDraft.trim(); + if (!keyword) { + toast.info("请输入产品关键词或卖点"); + return; + } + const modeHint = composerWorkMode === "think" ? "先拆解目标人群、核心卖点和使用场景," : ""; + const nextValue = `${keyword}。${modeHint}请生成适合${platform}的高转化电商素材,画面干净高级,突出产品主体、核心卖点、使用场景和购买理由。`.slice(0, 500); + setRequirement(nextValue); + setComposerMenu(null); + }; + + const renderComposerAssetPanel = () => { + const renderEmpty = (label: string) => ( +
+ + 暂无数据 + {label} +
+ ); + + let content: ReactNode; + if (composerAssetTab === "recent") { + content = ecommerceHistoryRecords.length ? ( +
+ {ecommerceHistoryRecords.slice(0, 4).map((record) => { + const outputLabel = cloneOutputOptions.find((option) => option.key === record.output)?.label || "生成记录"; + return ( + + ); + })} +
+ ) : renderEmpty("生成后保存的素材会沉淀在这里"); + } else if (composerAssetTab === "recipe") { + content = ( +
+ {commerceScenarioTemplates.slice(0, 4).map((template) => ( + + ))} +
+ ); + } else { + content = ( +
+ {tryOnScenes.slice(0, 4).map((scene) => ( + + ))} +
+ ); + } + + return ( + <> +
+ 资产库 + +
+
+ {composerAssetTabs.map((tab) => ( + + ))} +
+ {content} + + ); + }; + const renderComposerMenu = () => { const composerLanguageOptions = Array.from(new Set(marketLanguageOptions.flatMap((option) => option.languages))).map((item) => ({ language: item, @@ -5816,6 +5929,37 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { if (!menuToRender) return null; const popoverClosingClass = !composerMenu && isComposerMenuClosing ? " is-closing" : ""; const composerPopoverKey = `${menuToRender}-${cloneOutput}-${popoverClosingClass ? "closing" : "open"}`; + if (menuToRender === "assetLibrary") { + return ( +
+ {renderComposerAssetPanel()} +
+ ); + } + if (menuToRender === "workMode") { + return ( +
+
模式仅调整创作体验,不改变接口
+ {composerWorkModeOptions.map((option) => ( + + ))} +
+ ); + } + if (menuToRender === "aiWrite") { + return ( +
+
AI 帮写把关键词扩写成商业提示词
+