feat: improve agent brand and store option editor
This commit is contained in:
parent
4f5d999ade
commit
eb56b7967d
@ -183,6 +183,8 @@ export function AgentWorkflowSettingsClient({
|
||||
const [uploadingKey, setUploadingKey] = useState<string | null>(null);
|
||||
const [expandedSteps, setExpandedSteps] = useState<Set<string>>(new Set());
|
||||
const [activeTab, setActiveTab] = useState("showcase");
|
||||
const [brandDraft, setBrandDraft] = useState("");
|
||||
const [storeDraft, setStoreDraft] = useState("");
|
||||
const fileInputRefs = useRef<Record<string, HTMLInputElement | null>>({});
|
||||
|
||||
useEffect(() => {
|
||||
@ -220,6 +222,60 @@ export function AgentWorkflowSettingsClient({
|
||||
() => [...config.steps].sort((left, right) => left.sortOrder - right.sortOrder),
|
||||
[config.steps]
|
||||
);
|
||||
const brandOptions = config.inputOptions?.brands || [];
|
||||
const storeOptions = config.inputOptions?.stores || [];
|
||||
|
||||
const updateInputOptions = (updates: Partial<{ brands: string[]; stores: string[] }>) => {
|
||||
setConfig((prev) => ({
|
||||
...prev,
|
||||
inputOptions: {
|
||||
brands: updates.brands ?? prev.inputOptions?.brands ?? [],
|
||||
stores: updates.stores ?? prev.inputOptions?.stores ?? [],
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
const normalizeInputOptionValue = (value: string) =>
|
||||
value
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
|
||||
const handleAddInputOption = (kind: "brands" | "stores") => {
|
||||
const draft = kind === "brands" ? brandDraft : storeDraft;
|
||||
const nextValue = normalizeInputOptionValue(draft);
|
||||
if (!nextValue) {
|
||||
toast.error(kind === "brands" ? "请输入品牌名称" : "请输入店铺名称");
|
||||
return;
|
||||
}
|
||||
|
||||
const currentList = kind === "brands" ? brandOptions : storeOptions;
|
||||
if (currentList.some((item) => item.toLowerCase() === nextValue.toLowerCase())) {
|
||||
toast.error(kind === "brands" ? "该品牌已存在" : "该店铺已存在");
|
||||
return;
|
||||
}
|
||||
|
||||
if (kind === "brands") {
|
||||
updateInputOptions({ brands: [...brandOptions, nextValue] });
|
||||
setBrandDraft("");
|
||||
return;
|
||||
}
|
||||
|
||||
updateInputOptions({ stores: [...storeOptions, nextValue] });
|
||||
setStoreDraft("");
|
||||
};
|
||||
|
||||
const handleRemoveInputOption = (kind: "brands" | "stores", value: string) => {
|
||||
if (kind === "brands") {
|
||||
updateInputOptions({
|
||||
brands: brandOptions.filter((item) => item !== value),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
updateInputOptions({
|
||||
stores: storeOptions.filter((item) => item !== value),
|
||||
});
|
||||
};
|
||||
|
||||
const enabledStepsCount = useMemo(
|
||||
() => sortedSteps.filter((s) => s.enabled).length,
|
||||
@ -961,48 +1017,114 @@ export function AgentWorkflowSettingsClient({
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="text-xs">品牌列表</Label>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{(config.inputOptions?.brands || []).length} 个品牌
|
||||
{brandOptions.length} 个品牌
|
||||
</span>
|
||||
</div>
|
||||
<Textarea
|
||||
value={(config.inputOptions?.brands || []).join("\n")}
|
||||
onChange={(e) =>
|
||||
setConfig((prev) => ({
|
||||
...prev,
|
||||
inputOptions: {
|
||||
brands: e.target.value.split("\n").map((s) => s.trim()).filter(Boolean),
|
||||
stores: prev.inputOptions?.stores || [],
|
||||
},
|
||||
}))
|
||||
}
|
||||
rows={8}
|
||||
placeholder="宜家\n顾家家居\n林氏家居"
|
||||
className="font-mono text-sm"
|
||||
/>
|
||||
<div className="rounded-xl border bg-muted/10 p-3">
|
||||
<div className="flex flex-col gap-2 sm:flex-row">
|
||||
<Input
|
||||
value={brandDraft}
|
||||
onChange={(e) => setBrandDraft(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
handleAddInputOption("brands");
|
||||
}
|
||||
}}
|
||||
placeholder="输入一个品牌名称后点击添加"
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => handleAddInputOption("brands")}
|
||||
className="shrink-0"
|
||||
>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
添加品牌
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{brandOptions.length > 0 ? (
|
||||
<div className="mt-3 flex flex-wrap gap-2">
|
||||
{brandOptions.map((brand) => (
|
||||
<div
|
||||
key={brand}
|
||||
className="inline-flex items-center gap-2 rounded-full border bg-background px-3 py-1.5 text-sm"
|
||||
>
|
||||
<span>{brand}</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleRemoveInputOption("brands", brand)}
|
||||
className="rounded-full p-0.5 text-muted-foreground transition-colors hover:bg-muted hover:text-destructive"
|
||||
aria-label={`删除品牌 ${brand}`}
|
||||
>
|
||||
<Trash2 className="h-3.5 w-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-3 rounded-lg border border-dashed bg-background/70 px-3 py-4 text-sm text-muted-foreground">
|
||||
还没有添加品牌,支持一条一条添加。
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<Separator />
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="text-xs">店铺列表</Label>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{(config.inputOptions?.stores || []).length} 个店铺
|
||||
{storeOptions.length} 个店铺
|
||||
</span>
|
||||
</div>
|
||||
<Textarea
|
||||
value={(config.inputOptions?.stores || []).join("\n")}
|
||||
onChange={(e) =>
|
||||
setConfig((prev) => ({
|
||||
...prev,
|
||||
inputOptions: {
|
||||
brands: prev.inputOptions?.brands || [],
|
||||
stores: e.target.value.split("\n").map((s) => s.trim()).filter(Boolean),
|
||||
},
|
||||
}))
|
||||
}
|
||||
rows={8}
|
||||
placeholder="天猫旗舰店\n京东自营店"
|
||||
className="font-mono text-sm"
|
||||
/>
|
||||
<div className="rounded-xl border bg-muted/10 p-3">
|
||||
<div className="flex flex-col gap-2 sm:flex-row">
|
||||
<Input
|
||||
value={storeDraft}
|
||||
onChange={(e) => setStoreDraft(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
handleAddInputOption("stores");
|
||||
}
|
||||
}}
|
||||
placeholder="输入一个店铺名称后点击添加"
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => handleAddInputOption("stores")}
|
||||
className="shrink-0"
|
||||
>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
添加店铺
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{storeOptions.length > 0 ? (
|
||||
<div className="mt-3 flex flex-wrap gap-2">
|
||||
{storeOptions.map((store) => (
|
||||
<div
|
||||
key={store}
|
||||
className="inline-flex items-center gap-2 rounded-full border bg-background px-3 py-1.5 text-sm"
|
||||
>
|
||||
<span>{store}</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleRemoveInputOption("stores", store)}
|
||||
className="rounded-full p-0.5 text-muted-foreground transition-colors hover:bg-muted hover:text-destructive"
|
||||
aria-label={`删除店铺 ${store}`}
|
||||
>
|
||||
<Trash2 className="h-3.5 w-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-3 rounded-lg border border-dashed bg-background/70 px-3 py-4 text-sm text-muted-foreground">
|
||||
还没有添加店铺,支持一条一条添加。
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@ -1108,7 +1230,7 @@ export function AgentWorkflowSettingsClient({
|
||||
>
|
||||
<img
|
||||
src={image.imageUrl}
|
||||
alt={image.displayName}
|
||||
alt={image.displayName || `${brandName} 模特图`}
|
||||
className="h-full w-full object-cover"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-black/0 transition-colors group-hover:bg-black/40" />
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user