feat: refine agent generation workflow ui
This commit is contained in:
parent
8d2066a3bf
commit
c754383ffc
@ -298,6 +298,8 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
onResultPreviewUrlsChange,
|
||||
topNavRightSlot,
|
||||
}: AgentGenerationWorkspaceDarkV2Props) {
|
||||
const darkSelectContentClass =
|
||||
"border-white/10 bg-zinc-950 text-white shadow-2xl [--popover:hsl(240_10%_3.9%)] [--popover-foreground:hsl(0_0%_98%)] [--accent:rgba(255,255,255,0.08)] [--accent-foreground:hsl(0_0%_98%)] [--muted:rgba(255,255,255,0.04)] [--muted-foreground:rgba(255,255,255,0.56)]";
|
||||
const rawChatId = useMemo(
|
||||
() => (chatId.startsWith("canvas-") ? chatId.replace("canvas-", "") : chatId),
|
||||
[chatId]
|
||||
@ -769,6 +771,10 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
(image) => image.source === "primary" || image.source === "secondary"
|
||||
);
|
||||
const hasSatisfiedSlotRequirement = !hasAgentUploadSlots || attachmentCount >= requiredUploadCount;
|
||||
const mergedSettingsStepLabel = hasMaterialStep ? "选图与生成" : "生成参数";
|
||||
const mergedSettingsStepDescription = hasMaterialStep
|
||||
? "搜索素材、补充要求、确认槽位并开始生成"
|
||||
: "补充要求并开始生成";
|
||||
|
||||
const toolSteps = useMemo(
|
||||
() => [
|
||||
@ -794,35 +800,15 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(hasMaterialStep
|
||||
? [
|
||||
{
|
||||
key: "materials" as const,
|
||||
label: "SKU / SPU 选图",
|
||||
description: "搜索主图和搭配图",
|
||||
icon: Upload,
|
||||
disabled: !selectedAgentPresetId,
|
||||
completed: hasMaterialSelections,
|
||||
optional: true,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
key: "prompt" as const,
|
||||
label: "补充要求",
|
||||
description: "补充风格、构图和细节要求",
|
||||
icon: Sparkles,
|
||||
disabled: !selectedAgentPresetId,
|
||||
completed: Boolean(input.trim()),
|
||||
optional: true,
|
||||
},
|
||||
{
|
||||
key: "settings" as const,
|
||||
label: "生成参数",
|
||||
description: "选择模型并开始生成",
|
||||
label: mergedSettingsStepLabel,
|
||||
description: mergedSettingsStepDescription,
|
||||
icon: Settings2,
|
||||
disabled: !selectedAgentPresetId,
|
||||
completed: Boolean(selectedAgentPresetId),
|
||||
completed:
|
||||
Boolean(selectedAgentPresetId) &&
|
||||
(Boolean(input.trim()) || hasMaterialSelections || hasSatisfiedSlotRequirement),
|
||||
optional: false,
|
||||
},
|
||||
],
|
||||
@ -830,8 +816,10 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
hasBrandModelSelection,
|
||||
hasBrandModelStep,
|
||||
hasMaterialSelections,
|
||||
hasMaterialStep,
|
||||
hasSatisfiedSlotRequirement,
|
||||
mergedSettingsStepDescription,
|
||||
mergedSettingsStepLabel,
|
||||
hasMaterialStep,
|
||||
input,
|
||||
selectedAgentPresetId,
|
||||
]
|
||||
@ -943,28 +931,27 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
}
|
||||
|
||||
setActiveToolStep((current) => {
|
||||
if (current !== "preset") return current;
|
||||
if (isDetailReplacementPreset || isSkuReplacementPreset) {
|
||||
if (hasMaterialStep) return "materials";
|
||||
return "prompt";
|
||||
if (
|
||||
current !== "preset" &&
|
||||
current !== "materials" &&
|
||||
current !== "prompt"
|
||||
) {
|
||||
return current;
|
||||
}
|
||||
|
||||
if (hasBrandModelStep) return "brand-model";
|
||||
if (hasMaterialStep) return "materials";
|
||||
return "prompt";
|
||||
return "settings";
|
||||
});
|
||||
}, [
|
||||
hasBrandModelStep,
|
||||
hasMaterialStep,
|
||||
isDetailReplacementPreset,
|
||||
isSkuReplacementPreset,
|
||||
selectedAgentPresetId,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!toolSteps.some((step) => step.key === activeToolStep)) {
|
||||
setActiveToolStep("preset");
|
||||
setActiveToolStep(selectedAgentPresetId ? "settings" : "preset");
|
||||
}
|
||||
}, [activeToolStep, toolSteps]);
|
||||
}, [activeToolStep, selectedAgentPresetId, toolSteps]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!syncGeneratedResultsToCanvas) {
|
||||
@ -1581,7 +1568,7 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
</div>
|
||||
|
||||
{assignableSourceLibrary.length > 0 ? (
|
||||
<div className="grid grid-cols-2 gap-3 xl:grid-cols-4">
|
||||
<div className="grid grid-cols-1 gap-3 md:grid-cols-3">
|
||||
{assignableSourceLibrary.map((source) => {
|
||||
const assignedToActiveSlot =
|
||||
activeAssignmentSlotIndex !== null &&
|
||||
@ -1613,7 +1600,7 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
{source.sourceLabel}
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-1 px-3 py-2">
|
||||
<div className="space-y-1 border-t border-white/10 px-3 py-2">
|
||||
<div className="truncate text-xs font-medium text-white/88">
|
||||
{source.label}
|
||||
</div>
|
||||
@ -1629,7 +1616,7 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
<div className="flex min-h-[92px] items-center justify-center rounded-[20px] border border-dashed border-white/10 bg-white/[0.02] px-4 text-center text-xs text-white/40">
|
||||
{activeAssignmentIsModelSlot
|
||||
? "当前模特槽位还没有可分配的品牌模特图,请先在“品牌模特”步骤里选择。"
|
||||
: "当前产品槽位还没有来自已选素材区的图片,请先到“SKU / SPU 选图”里完成选择。"}
|
||||
: "当前产品槽位还没有来自已选素材区的图片,请先在当前页上方完成 SKU / SPU 选图。"}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -1733,29 +1720,21 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{hasMaterialStep ? (
|
||||
<div className={cn(activeToolStep === "materials" ? "block" : "hidden")}>
|
||||
{materialSelectionPanel}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className={cn(activeToolStep === "prompt" ? "block" : "hidden")}>
|
||||
<div className="rounded-[28px] border border-white/12 bg-white/[0.02] p-4">
|
||||
<h3 className="mb-3 flex items-center gap-2 text-sm font-semibold text-white">
|
||||
<Sparkles className="h-4 w-4 text-emerald-300" />
|
||||
补充要求
|
||||
</h3>
|
||||
<Textarea
|
||||
value={input}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
placeholder="描述你想要的风格、氛围、构图..."
|
||||
className="min-h-[160px] resize-none rounded-[24px] border-white/12 bg-black text-sm text-white placeholder:text-white/20 focus:border-emerald-400/30"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={cn(activeToolStep === "settings" ? "block" : "hidden")}>
|
||||
<div className="space-y-4">
|
||||
{hasMaterialStep ? materialSelectionPanel : null}
|
||||
<div className="rounded-[28px] border border-white/12 bg-white/[0.02] p-4">
|
||||
<h3 className="mb-3 flex items-center gap-2 text-sm font-semibold text-white">
|
||||
<Sparkles className="h-4 w-4 text-emerald-300" />
|
||||
补充要求
|
||||
</h3>
|
||||
<Textarea
|
||||
value={input}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
placeholder="描述你想要的风格、氛围、构图..."
|
||||
className="min-h-[160px] resize-none rounded-[24px] border-white/12 bg-black text-sm text-white placeholder:text-white/20 focus:border-emerald-400/30"
|
||||
/>
|
||||
</div>
|
||||
{attachmentSlotPanel}
|
||||
<div className="rounded-[28px] border border-white/12 bg-white/[0.02] p-4">
|
||||
<h3 className="mb-3 flex items-center gap-2 text-sm font-semibold text-white">
|
||||
@ -1776,9 +1755,13 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
<SelectTrigger className="h-10 rounded-[24px] border-white/12 bg-black text-white">
|
||||
<SelectValue placeholder="选择模型" />
|
||||
</SelectTrigger>
|
||||
<SelectContent className="border-white/10 bg-zinc-900">
|
||||
<SelectContent className={darkSelectContentClass}>
|
||||
{selectableModels.map((model) => (
|
||||
<SelectItem key={model.id} value={model.id} className="text-white">
|
||||
<SelectItem
|
||||
key={model.id}
|
||||
value={model.id}
|
||||
className="text-white focus:bg-white/10 focus:text-white"
|
||||
>
|
||||
{model.displayName}
|
||||
</SelectItem>
|
||||
))}
|
||||
@ -1836,7 +1819,9 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
|
||||
<div className="mt-5 flex flex-wrap items-center justify-between gap-3 border-t border-white/10 pt-4">
|
||||
<div className="text-xs text-white/40">
|
||||
完成当前模块后,可点击下一步继续,也可以直接点击顶部流程线跳转。
|
||||
{hasMaterialStep
|
||||
? "当前页已合并 SKU / SPU 选图、补充要求、槽位确认和生成参数,可在这里直接完成后开始生成。"
|
||||
: "当前页已集中补充要求与生成参数,确认后即可直接开始生成。"}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
@ -1993,7 +1978,7 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
))
|
||||
) : (
|
||||
<div className="flex min-h-[160px] flex-col items-center justify-center rounded-[22px] border border-dashed border-white/12 bg-black/20 px-4 text-center text-sm text-white/42">
|
||||
请先在“生成参数”里的输入图槽位中确认用于详情替换的白底输入图。
|
||||
请先在当前“选图与生成”页的输入图槽位中确认用于详情替换的白底输入图。
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -2300,7 +2285,7 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
))
|
||||
) : (
|
||||
<div className="flex min-h-[160px] flex-col items-center justify-center rounded-[22px] border border-dashed border-white/12 bg-black/20 px-4 text-center text-sm text-white/42">
|
||||
请先在“生成参数”里的输入图槽位中确认用于 SKU 替换的白底输入图。
|
||||
请先在当前“选图与生成”页的输入图槽位中确认用于 SKU 替换的白底输入图。
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -2671,7 +2656,9 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
</p>
|
||||
<p className="mt-2 text-sm text-white/30">
|
||||
{selectedAgentPresetId
|
||||
? "顶部流程线配置完成后,切到“生成参数”即可开始生成"
|
||||
? hasMaterialStep
|
||||
? "在“选图与生成”页完成搜图、槽位确认和参数设置后,即可开始生成"
|
||||
: "在当前页补充要求并确认参数后,即可开始生成"
|
||||
: "请先从顶部流程线选择一个生图模式"}
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
@ -149,6 +149,9 @@ export function AgentPresetDialog({
|
||||
const dialogTitle = initialPreset ? `编辑${entityLabel}` : `新建${entityLabel}`;
|
||||
const dialogDescription = `配置${entityLabel}名称、预览图、模型和槽位提示词。`;
|
||||
const submitLabel = initialPreset ? `保存${entityLabel}` : `创建${entityLabel}`;
|
||||
const darkSelectContentClass = isDark
|
||||
? "border-white/10 bg-zinc-950 text-white shadow-2xl [--popover:hsl(240_10%_3.9%)] [--popover-foreground:hsl(0_0%_98%)] [--accent:rgba(255,255,255,0.08)] [--accent-foreground:hsl(0_0%_98%)] [--muted:rgba(255,255,255,0.04)] [--muted-foreground:rgba(255,255,255,0.56)]"
|
||||
: "";
|
||||
const isStructuredImageModeBuilder = type === "image" && modeConfig.modeType !== "legacy";
|
||||
const isSceneModeBuilder = type === "image" && modeConfig.modeType === "scene_generation";
|
||||
const isDetailReplacementModeBuilder =
|
||||
@ -716,7 +719,7 @@ export function AgentPresetDialog({
|
||||
>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent className={cn(isDark ? "border-white/10 bg-zinc-950 text-white" : "")}>
|
||||
<SelectContent className={darkSelectContentClass}>
|
||||
<SelectItem value="private" className={cn(isDark ? "text-white focus:bg-white/10 focus:text-white" : "")}>私有</SelectItem>
|
||||
<SelectItem value="public" className={cn(isDark ? "text-white focus:bg-white/10 focus:text-white" : "")}>公开</SelectItem>
|
||||
</SelectContent>
|
||||
@ -744,7 +747,7 @@ export function AgentPresetDialog({
|
||||
>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent className={cn(isDark ? "border-white/10 bg-zinc-950 text-white" : "")}>
|
||||
<SelectContent className={darkSelectContentClass}>
|
||||
{imageModeSelectOptions.map((option) => (
|
||||
<SelectItem
|
||||
key={option.value}
|
||||
@ -777,7 +780,7 @@ export function AgentPresetDialog({
|
||||
>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent className={cn(isDark ? "border-white/10 bg-zinc-950 text-white" : "")}>
|
||||
<SelectContent className={darkSelectContentClass}>
|
||||
<SelectItem value="image" className={cn(isDark ? "text-white focus:bg-white/10 focus:text-white" : "")}>生图</SelectItem>
|
||||
<SelectItem value="video" className={cn(isDark ? "text-white focus:bg-white/10 focus:text-white" : "")}>视频</SelectItem>
|
||||
<SelectItem value="text" className={cn(isDark ? "text-white focus:bg-white/10 focus:text-white" : "")}>生文</SelectItem>
|
||||
@ -797,7 +800,7 @@ export function AgentPresetDialog({
|
||||
>
|
||||
<SelectValue placeholder="选择模型" />
|
||||
</SelectTrigger>
|
||||
<SelectContent className={cn(isDark ? "border-white/10 bg-zinc-950 text-white" : "")}>
|
||||
<SelectContent className={darkSelectContentClass}>
|
||||
{filteredModels.map((model) => (
|
||||
<SelectItem
|
||||
key={model.id}
|
||||
@ -852,7 +855,7 @@ export function AgentPresetDialog({
|
||||
>
|
||||
<SelectValue placeholder="选择顶部分类页" />
|
||||
</SelectTrigger>
|
||||
<SelectContent className={cn(isDark ? "border-white/10 bg-zinc-950 text-white" : "")}>
|
||||
<SelectContent className={darkSelectContentClass}>
|
||||
<SelectItem value="__none__" className={cn(isDark ? "text-white focus:bg-white/10 focus:text-white" : "")}>
|
||||
不分类
|
||||
</SelectItem>
|
||||
@ -891,7 +894,7 @@ export function AgentPresetDialog({
|
||||
>
|
||||
<SelectValue placeholder="选择一级分类" />
|
||||
</SelectTrigger>
|
||||
<SelectContent className={cn(isDark ? "border-white/10 bg-zinc-950 text-white" : "")}>
|
||||
<SelectContent className={darkSelectContentClass}>
|
||||
<SelectItem value="__none__" className={cn(isDark ? "text-white focus:bg-white/10 focus:text-white" : "")}>
|
||||
不选择
|
||||
</SelectItem>
|
||||
@ -929,7 +932,7 @@ export function AgentPresetDialog({
|
||||
>
|
||||
<SelectValue placeholder="选择二级分类" />
|
||||
</SelectTrigger>
|
||||
<SelectContent className={cn(isDark ? "border-white/10 bg-zinc-950 text-white" : "")}>
|
||||
<SelectContent className={darkSelectContentClass}>
|
||||
<SelectItem value="__none__" className={cn(isDark ? "text-white focus:bg-white/10 focus:text-white" : "")}>
|
||||
不选择
|
||||
</SelectItem>
|
||||
@ -965,7 +968,7 @@ export function AgentPresetDialog({
|
||||
>
|
||||
<SelectValue placeholder="选择三级分类" />
|
||||
</SelectTrigger>
|
||||
<SelectContent className={cn(isDark ? "border-white/10 bg-zinc-950 text-white" : "")}>
|
||||
<SelectContent className={darkSelectContentClass}>
|
||||
<SelectItem value="__none__" className={cn(isDark ? "text-white focus:bg-white/10 focus:text-white" : "")}>
|
||||
不选择
|
||||
</SelectItem>
|
||||
@ -1055,7 +1058,7 @@ export function AgentPresetDialog({
|
||||
>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent className={cn(isDark ? "border-white/10 bg-zinc-950 text-white" : "")}>
|
||||
<SelectContent className={darkSelectContentClass}>
|
||||
{[1, 2, 3, 4].map((count) => (
|
||||
<SelectItem
|
||||
key={count}
|
||||
@ -1192,7 +1195,7 @@ export function AgentPresetDialog({
|
||||
>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent className={cn(isDark ? "border-white/10 bg-zinc-950 text-white" : "")}>
|
||||
<SelectContent className={darkSelectContentClass}>
|
||||
{[1, 2, 3, 4].map((count) => (
|
||||
<SelectItem
|
||||
key={count}
|
||||
|
||||
@ -164,6 +164,11 @@ export function AgentWorkflowBrandModelPicker({
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className={cn(
|
||||
isDark
|
||||
? "border-white/14 bg-white/[0.03] text-white/82 hover:border-white/22 hover:bg-white/[0.08] hover:text-white disabled:border-white/8 disabled:bg-white/[0.02] disabled:text-white/28"
|
||||
: ""
|
||||
)}
|
||||
onClick={() => onSelectBrandModel(null)}
|
||||
disabled={!selectedBrandModel}
|
||||
>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user