diff --git a/app/(admin)/settings/agent-workflow/agent-workflow-settings-client.tsx b/app/(admin)/settings/agent-workflow/agent-workflow-settings-client.tsx
index fd907f28b..85bb360cc 100644
--- a/app/(admin)/settings/agent-workflow/agent-workflow-settings-client.tsx
+++ b/app/(admin)/settings/agent-workflow/agent-workflow-settings-client.tsx
@@ -913,6 +913,8 @@ export function AgentWorkflowSettingsClient({
() => getAgentWorkflowCategoryLabels(config),
[config]
);
+ const firstCategoryLabel = categoryLabels.firstCategory;
+ const secondCategoryLabel = categoryLabels.secondCategory;
const thirdCategoryLabel = categoryLabels.thirdCategory;
const fourthCategoryLabel = categoryLabels.fourthCategory;
const fifthCategoryLabel = categoryLabels.fifthCategory;
@@ -1013,12 +1015,12 @@ export function AgentWorkflowSettingsClient({
const handleAddBrandEntry = () => {
const nextValue = normalizeInputOptionValue(brandDraft);
if (!nextValue) {
- toast.error("请输入品牌名称");
+ toast.error(`请输入${firstCategoryLabel}名称`);
return;
}
if (brandStoreEntries.some((item) => item.brandName.toLowerCase() === nextValue.toLowerCase())) {
- toast.error("该品牌已存在");
+ toast.error(`该${firstCategoryLabel}已存在`);
return;
}
@@ -1074,7 +1076,7 @@ export function AgentWorkflowSettingsClient({
const draft = storeDrafts[brandName] || "";
const nextValue = normalizeInputOptionValue(draft);
if (!nextValue) {
- toast.error("请输入店铺名称");
+ toast.error(`请输入${secondCategoryLabel}名称`);
return;
}
@@ -1085,7 +1087,7 @@ export function AgentWorkflowSettingsClient({
) ||
targetEntry?.stores.some((store) => store.toLowerCase() === nextValue.toLowerCase())
) {
- toast.error("该店铺已存在");
+ toast.error(`该${secondCategoryLabel}已存在`);
return;
}
@@ -2014,7 +2016,7 @@ export function AgentWorkflowSettingsClient({
const handleDownloadBrandTemplate = async () => {
try {
await downloadAgentWorkflowBrandImportTemplate(categoryLabels);
- toast.success("品牌导入模板已开始下载");
+ toast.success("层级导入模板已开始下载");
} catch (error) {
toast.error(error instanceof Error ? error.message : "下载模板失败");
}
@@ -2031,7 +2033,7 @@ export function AgentWorkflowSettingsClient({
setIsImportingBrandSheet(true);
const { entries, rowCount } = await parseAgentWorkflowBrandImportFile(file, categoryLabels);
updateInputOptions([...brandStoreEntries, ...entries]);
- toast.success(`已从表格导入 ${rowCount} 行,品牌树已自动合并去重`);
+ toast.success(`已从表格导入 ${rowCount} 行,层级树已自动合并去重`);
} catch (error) {
toast.error(error instanceof Error ? error.message : "导入表格失败");
} finally {
@@ -3477,7 +3479,9 @@ export function AgentWorkflowSettingsClient({
基础下拉选项
- 配置品牌、店铺与分类层级关系,以及第一页可选的价格带区间
+
+ 配置{firstCategoryLabel}、{secondCategoryLabel}与分类层级关系,以及第一页可选的价格带区间
+
@@ -3485,14 +3489,14 @@ export function AgentWorkflowSettingsClient({
-
+
- 支持一键下载模板并导入品牌、店铺、{thirdCategoryLabel}、{fourthCategoryLabel}、{fifthCategoryLabel}表格
+ 支持一键下载模板并导入{firstCategoryLabel}、{secondCategoryLabel}、{thirdCategoryLabel}、{fourthCategoryLabel}、{fifthCategoryLabel}表格
- {brandStoreEntries.length} 个品牌
+ {brandStoreEntries.length} 个{firstCategoryLabel}
-
+
- {(entry.storeEntries || []).length} 个店铺
+ {(entry.storeEntries || []).length} 个{secondCategoryLabel}
@@ -3614,7 +3634,7 @@ export function AgentWorkflowSettingsClient({
handleAddStoreToBrand(entry.brandName);
}
}}
- placeholder={`给品牌“${entry.brandName}”添加店铺`}
+ placeholder={`给${firstCategoryLabel}“${entry.brandName}”添加${secondCategoryLabel}`}
/>
@@ -3649,7 +3669,7 @@ export function AgentWorkflowSettingsClient({
)
}
className="rounded-full p-0.5 text-muted-foreground transition-colors hover:bg-muted hover:text-destructive"
- aria-label={`删除店铺 ${storeEntry.storeName}`}
+ aria-label={`删除${secondCategoryLabel} ${storeEntry.storeName}`}
>
@@ -3679,7 +3699,7 @@ export function AgentWorkflowSettingsClient({
);
}
}}
- placeholder={`给店铺“${storeEntry.storeName}”添加${thirdCategoryLabel}`}
+ placeholder={`给${secondCategoryLabel}“${storeEntry.storeName}”添加${thirdCategoryLabel}`}
/>
@@ -3918,7 +3938,7 @@ export function AgentWorkflowSettingsClient({
) : (
- 这个品牌下还没有添加任何店铺。
+ 这个{firstCategoryLabel}下还没有添加任何{secondCategoryLabel}。
)}
@@ -3927,7 +3947,7 @@ export function AgentWorkflowSettingsClient({
) : (
- 还没有添加品牌。先添加品牌,再在每个品牌下继续添加店铺以及{thirdCategoryLabel}到{fifthCategoryLabel}。
+ 还没有添加{firstCategoryLabel}。先添加{firstCategoryLabel},再在每个{firstCategoryLabel}下继续添加{secondCategoryLabel}以及{thirdCategoryLabel}到{fifthCategoryLabel}。
)}
@@ -3985,7 +4005,7 @@ export function AgentWorkflowSettingsClient({
) : (
- 还没有添加价格带。添加后,第一页品牌和店铺右侧会显示价格带下拉框。
+ 还没有添加价格带。添加后,第一页{firstCategoryLabel}和{secondCategoryLabel}右侧会显示价格带下拉框。
)}
@@ -4036,7 +4056,7 @@ export function AgentWorkflowSettingsClient({
PSD 文字颜色选项
- 按品牌配置套用 PSD 模板时可选的两组文字颜色,前台会跟随当前品牌读取。
+ 按{firstCategoryLabel}配置套用 PSD 模板时可选的两组文字颜色,前台会跟随当前{firstCategoryLabel}读取。
@@ -4044,22 +4064,22 @@ export function AgentWorkflowSettingsClient({
{psdTextColorBrandOptions.length > 0 ? (
-
+
- 未单独配置的品牌会回退系统默认颜色;当前编辑品牌:{selectedPsdTextColorBrand}
+ 未单独配置的{firstCategoryLabel}会回退系统默认颜色;当前编辑{firstCategoryLabel}:{selectedPsdTextColorBrand}
) : (
- 请先在上方“品牌树”里配置品牌,再按品牌设置 PSD 文字颜色。
+ 请先在上方“层级树”里配置{firstCategoryLabel},再按{firstCategoryLabel}设置 PSD 文字颜色。
)}
@@ -4146,14 +4166,14 @@ export function AgentWorkflowSettingsClient({
- 品牌模特图库
+ {firstCategoryLabel}模特图库
- 为每个品牌配置模特图,第二步会按品牌展示供用户选择
+ 为每个{firstCategoryLabel}配置模特图,第二步会按{firstCategoryLabel}展示供用户选择
- {brandModelConfig.entries.length} 个品牌
+ {brandModelConfig.entries.length} 个{firstCategoryLabel}
@@ -4254,7 +4274,7 @@ export function AgentWorkflowSettingsClient({
- 先在"基础配置"中添加品牌,然后为每个品牌上传模特图
+ 先在“基础配置”中添加{firstCategoryLabel},然后为每个{firstCategoryLabel}上传模特图
)}
diff --git a/app/api/site-settings/route.ts b/app/api/site-settings/route.ts
index 75aad7178..464b1fcbf 100644
--- a/app/api/site-settings/route.ts
+++ b/app/api/site-settings/route.ts
@@ -740,6 +740,8 @@ const updateSchema = z.object({
.optional(),
categoryLabels: z
.object({
+ firstCategory: z.string().trim().min(1).max(24).optional(),
+ secondCategory: z.string().trim().min(1).max(24).optional(),
thirdCategory: z.string().trim().min(1).max(24).optional(),
fourthCategory: z.string().trim().min(1).max(24).optional(),
fifthCategory: z.string().trim().min(1).max(24).optional(),
diff --git a/components/agents/AgentWorkflowPanel.tsx b/components/agents/AgentWorkflowPanel.tsx
index 5ab639283..62aea9a31 100644
--- a/components/agents/AgentWorkflowPanel.tsx
+++ b/components/agents/AgentWorkflowPanel.tsx
@@ -10,6 +10,7 @@ import { Textarea } from "@/components/ui/textarea";
import { cn } from "@/lib/utils";
import {
defaultAgentWorkflowUiConfig,
+ getAgentWorkflowCategoryLabels,
getAgentWorkflowBrandStoreEntries,
getAgentWorkflowFifthCategoryOptionsByBrandStoreThirdFourth,
getAgentWorkflowFourthCategoryOptionsByBrandStoreThirdCategory,
@@ -92,6 +93,15 @@ export function AgentWorkflowPanel({
onNextStep,
onSkipStep,
}: AgentWorkflowPanelProps) {
+ const categoryLabels = useMemo(
+ () => getAgentWorkflowCategoryLabels(config),
+ [config]
+ );
+ const firstCategoryLabel = categoryLabels.firstCategory;
+ const secondCategoryLabel = categoryLabels.secondCategory;
+ const thirdCategoryLabel = categoryLabels.thirdCategory;
+ const fourthCategoryLabel = categoryLabels.fourthCategory;
+ const fifthCategoryLabel = categoryLabels.fifthCategory;
const brandOptions = useMemo(
() => config?.inputOptions?.brands || defaultAgentWorkflowUiConfig.inputOptions?.brands || [],
[config?.inputOptions?.brands]
@@ -248,9 +258,9 @@ export function AgentWorkflowPanel({
onInputsChange({
...inputs,
@@ -271,9 +281,13 @@ export function AgentWorkflowPanel({
0 && storeOptions.length === 0)}
onValueChange={(value) =>
onInputsChange({
@@ -291,9 +305,13 @@ export function AgentWorkflowPanel({
onInputsChange({
@@ -310,9 +328,13 @@ export function AgentWorkflowPanel({
onInputsChange({
@@ -328,9 +350,13 @@ export function AgentWorkflowPanel({
onInputsChange({ ...inputs, fifthCategory: value })}
/>
@@ -346,7 +372,7 @@ export function AgentWorkflowPanel({
{(brandOptions.length > 0 || storeOptions.length > 0) && (
- 品牌和店铺支持输入关键字匹配下拉选择,候选列表由系统设置配置。
+ {firstCategoryLabel}和{secondCategoryLabel}支持输入关键字匹配下拉选择,候选列表由系统设置配置。
)}
@@ -438,19 +464,19 @@ export function AgentWorkflowPanel({
搭配SKU:{inputs.secondarySku}
) : null}
{inputs.brand ? (
-
品牌:{inputs.brand}
+
{firstCategoryLabel}:{inputs.brand}
) : null}
{inputs.store ? (
-
店铺:{inputs.store}
+
{secondCategoryLabel}:{inputs.store}
) : null}
{inputs.thirdCategory ? (
-
三级分类:{inputs.thirdCategory}
+
{thirdCategoryLabel}:{inputs.thirdCategory}
) : null}
{inputs.fourthCategory ? (
-
四级分类:{inputs.fourthCategory}
+
{fourthCategoryLabel}:{inputs.fourthCategory}
) : null}
{inputs.fifthCategory ? (
-
五级分类:{inputs.fifthCategory}
+
{fifthCategoryLabel}:{inputs.fifthCategory}
) : null}
{inputs.priceBand ? (
价格带:{inputs.priceBand}
diff --git a/components/agents/AgentWorkflowPanelDark.tsx b/components/agents/AgentWorkflowPanelDark.tsx
index 850ccc390..46aef13fe 100644
--- a/components/agents/AgentWorkflowPanelDark.tsx
+++ b/components/agents/AgentWorkflowPanelDark.tsx
@@ -11,6 +11,7 @@ import { Textarea } from "@/components/ui/textarea";
import { cn } from "@/lib/utils";
import {
defaultAgentWorkflowUiConfig,
+ getAgentWorkflowCategoryLabels,
getAgentWorkflowBrandStoreEntries,
getAgentWorkflowFifthCategoryOptionsByBrandStoreThirdFourth,
getAgentWorkflowFourthCategoryOptionsByBrandStoreThirdCategory,
@@ -174,6 +175,15 @@ export function AgentWorkflowPanelDark({
onNextStep,
onSkipStep,
}: AgentWorkflowPanelDarkProps) {
+ const categoryLabels = useMemo(
+ () => getAgentWorkflowCategoryLabels(config),
+ [config]
+ );
+ const firstCategoryLabel = categoryLabels.firstCategory;
+ const secondCategoryLabel = categoryLabels.secondCategory;
+ const thirdCategoryLabel = categoryLabels.thirdCategory;
+ const fourthCategoryLabel = categoryLabels.fourthCategory;
+ const fifthCategoryLabel = categoryLabels.fifthCategory;
const brandOptions = useMemo(
() => config?.inputOptions?.brands || defaultAgentWorkflowUiConfig.inputOptions?.brands || [],
[config?.inputOptions?.brands]
@@ -351,9 +361,9 @@ export function AgentWorkflowPanelDark({
onInputsChange({
...inputs,
@@ -374,9 +384,13 @@ export function AgentWorkflowPanelDark({
0 && storeOptions.length === 0)}
onValueChange={(value) =>
onInputsChange({
@@ -394,9 +408,13 @@ export function AgentWorkflowPanelDark({
onInputsChange({
@@ -413,9 +431,13 @@ export function AgentWorkflowPanelDark({
onInputsChange({
@@ -431,9 +453,13 @@ export function AgentWorkflowPanelDark({
onInputsChange({ ...inputs, fifthCategory: value })}
/>
diff --git a/components/agents/AgentWorkflowPanelDarkV2.tsx b/components/agents/AgentWorkflowPanelDarkV2.tsx
index 1fc35406e..972cf7568 100644
--- a/components/agents/AgentWorkflowPanelDarkV2.tsx
+++ b/components/agents/AgentWorkflowPanelDarkV2.tsx
@@ -285,9 +285,17 @@ export function AgentWorkflowBrandStorePanel({
() => getAgentWorkflowCategoryLabels(config),
[config]
);
+ const firstCategoryLabel = categoryLabels.firstCategory;
+ const secondCategoryLabel = categoryLabels.secondCategory;
const thirdCategoryLabel = categoryLabels.thirdCategory;
const fourthCategoryLabel = categoryLabels.fourthCategory;
const fifthCategoryLabel = categoryLabels.fifthCategory;
+ const resolvedTitle =
+ title === "品牌层级选择" ? `${firstCategoryLabel}层级选择` : title;
+ const resolvedDescription =
+ description === "先选择品牌、店铺、分类层级和价格带,后续品牌模特与风格步骤会按这里的选择联动。"
+ ? `先选择${firstCategoryLabel}、${secondCategoryLabel}、分类层级和价格带,后续品牌模特与风格步骤会按这里的选择联动。`
+ : description;
const brandOptions = useMemo(
() => config?.inputOptions?.brands || defaultAgentWorkflowUiConfig.inputOptions?.brands || [],
[config?.inputOptions?.brands]
@@ -422,19 +430,19 @@ export function AgentWorkflowBrandStorePanel({
>
- {title}
+ {resolvedTitle}
- {description}
+ {resolvedDescription}
onInputsChange({
@@ -456,9 +464,13 @@ export function AgentWorkflowBrandStorePanel({
0 && storeOptions.length === 0)}
onValueChange={(value) =>
@@ -480,7 +492,11 @@ export function AgentWorkflowBrandStorePanel({
options={thirdCategoryOptions}
placeholder={`选择${thirdCategoryLabel}`}
searchPlaceholder={`输入${thirdCategoryLabel}筛选`}
- emptyText={inputs.store ? `当前店铺下暂无${thirdCategoryLabel}` : "请先选择店铺"}
+ emptyText={
+ inputs.store
+ ? `当前${secondCategoryLabel}下暂无${thirdCategoryLabel}`
+ : `请先选择${secondCategoryLabel}`
+ }
theme={theme}
disabled={!inputs.store || thirdCategoryOptions.length === 0}
onValueChange={(value) =>
@@ -570,6 +586,12 @@ export function AgentWorkflowPanelDarkV2({
embedded = false,
showBrandStoreSection = true,
}: AgentWorkflowPanelDarkV2Props) {
+ const categoryLabels = useMemo(
+ () => getAgentWorkflowCategoryLabels(config),
+ [config]
+ );
+ const firstCategoryLabel = categoryLabels.firstCategory;
+ const secondCategoryLabel = categoryLabels.secondCategory;
const resolvedConfig = useMemo(() => {
const source = config || defaultAgentWorkflowUiConfig;
return {
@@ -866,7 +888,7 @@ export function AgentWorkflowPanelDarkV2({
1
- 品牌和店铺选择
+ {firstCategoryLabel}和{secondCategoryLabel}选择
getAgentWorkflowCategoryLabels(config),
+ [config]
+ );
+ const firstCategoryLabel = categoryLabels.firstCategory;
+ const secondCategoryLabel = categoryLabels.secondCategory;
+ const thirdCategoryLabel = categoryLabels.thirdCategory;
+ const fourthCategoryLabel = categoryLabels.fourthCategory;
+ const fifthCategoryLabel = categoryLabels.fifthCategory;
const brandOptions = useMemo(
() => config?.inputOptions?.brands || defaultAgentWorkflowUiConfig.inputOptions?.brands || [],
[config?.inputOptions?.brands]
@@ -386,9 +396,9 @@ export function AgentWorkflowPanelNew({
onInputsChange({
...inputs,
@@ -409,9 +419,13 @@ export function AgentWorkflowPanelNew({
0 && storeOptions.length === 0)}
onValueChange={(value) =>
onInputsChange({
@@ -429,9 +443,13 @@ export function AgentWorkflowPanelNew({
onInputsChange({
@@ -448,9 +466,13 @@ export function AgentWorkflowPanelNew({
onInputsChange({
@@ -466,9 +488,13 @@ export function AgentWorkflowPanelNew({
onInputsChange({ ...inputs, fifthCategory: value })}
/>
diff --git a/lib/agents/workflow-brand-import.ts b/lib/agents/workflow-brand-import.ts
index 15540b2e1..bb64c5c0a 100644
--- a/lib/agents/workflow-brand-import.ts
+++ b/lib/agents/workflow-brand-import.ts
@@ -60,8 +60,8 @@ const TEMPLATE_SAMPLE_ROWS = [
function getTemplateHeaders(labels?: Partial) {
const resolvedLabels = normalizeAgentWorkflowCategoryLabels(labels);
return {
- brandName: "品牌",
- storeName: "店铺",
+ brandName: resolvedLabels.firstCategory,
+ storeName: resolvedLabels.secondCategory,
thirdCategory: resolvedLabels.thirdCategory,
fourthCategory: resolvedLabels.fourthCategory,
fifthCategory: resolvedLabels.fifthCategory,
@@ -71,8 +71,12 @@ function getTemplateHeaders(labels?: Partial) {
function getHeaderAliases(labels?: Partial) {
const headers = getTemplateHeaders(labels);
return {
- brandName: STATIC_HEADER_ALIASES.brandName,
- storeName: STATIC_HEADER_ALIASES.storeName,
+ brandName: Array.from(
+ new Set([headers.brandName, ...STATIC_HEADER_ALIASES.brandName].filter(Boolean))
+ ),
+ storeName: Array.from(
+ new Set([headers.storeName, ...STATIC_HEADER_ALIASES.storeName].filter(Boolean))
+ ),
thirdCategory: Array.from(
new Set([headers.thirdCategory, ...STATIC_HEADER_ALIASES.thirdCategory].filter(Boolean))
),
@@ -230,21 +234,21 @@ export async function downloadAgentWorkflowBrandImportTemplate(
instructionSheet.views = [{ state: "frozen", ySplit: 1 }];
instructionSheet.addRows([
{
- field: "品牌",
+ field: resolvedLabels.firstCategory,
required: "是",
- description: "每一行都必须填写品牌名称;相同品牌会自动合并。",
+ description: `每一行都必须填写${resolvedLabels.firstCategory}名称;相同${resolvedLabels.firstCategory}会自动合并。`,
example: "朴美",
},
{
- field: "店铺",
+ field: resolvedLabels.secondCategory,
required: "否",
- description: "不填时只导入品牌;填写后会挂到对应品牌下。",
+ description: `不填时只导入${resolvedLabels.firstCategory};填写后会挂到对应${resolvedLabels.firstCategory}下。`,
example: "天猫朴美家居旗舰店",
},
{
field: resolvedLabels.thirdCategory,
required: "否",
- description: `填写后会挂到对应店铺下;如果不填,${resolvedLabels.fourthCategory}/${resolvedLabels.fifthCategory}也必须留空。`,
+ description: `填写后会挂到对应${resolvedLabels.secondCategory}下;如果不填,${resolvedLabels.fourthCategory}/${resolvedLabels.fifthCategory}也必须留空。`,
example: "桌类",
},
{
@@ -290,7 +294,7 @@ export async function parseAgentWorkflowBrandImportFile(
matchColumn(firstRecord, headerAliases.brandName) ||
Object.keys(firstRecord).find((key) => normalizeHeader(key) === normalizeHeader(templateHeaders.brandName));
if (!brandColumn) {
- throw new Error("未找到品牌列,请使用模板文件填写");
+ throw new Error(`未找到${templateHeaders.brandName}列,请使用模板文件填写`);
}
const storeColumn = matchColumn(firstRecord, headerAliases.storeName);
@@ -373,10 +377,12 @@ export async function parseAgentWorkflowBrandImportFile(
}
if (!brandName) {
- throw new Error(`第 ${lineNumber} 行缺少品牌名称`);
+ throw new Error(`第 ${lineNumber} 行缺少${resolvedLabels.firstCategory}名称`);
}
if (!storeName && (thirdCategory || fourthCategory || fifthCategory)) {
- throw new Error(`第 ${lineNumber} 行缺少店铺名称,不能直接填写分类`);
+ throw new Error(
+ `第 ${lineNumber} 行缺少${resolvedLabels.secondCategory}名称,不能直接填写分类`
+ );
}
if (!thirdCategory && (fourthCategory || fifthCategory)) {
throw new Error(
diff --git a/lib/agents/workflow-ui-config.ts b/lib/agents/workflow-ui-config.ts
index 6b06057bf..e77521087 100644
--- a/lib/agents/workflow-ui-config.ts
+++ b/lib/agents/workflow-ui-config.ts
@@ -14,6 +14,8 @@ export const AGENT_WORKFLOW_UI_CONFIG_KEY = "agent_workflow_ui_config";
export const AGENT_WORKFLOW_MAX_TREE_DEPTH = 8;
export const AGENT_WORKFLOW_MAX_OPTION_DEPTH = 8;
export const defaultAgentWorkflowCategoryLabels: AgentWorkflowCategoryLabels = {
+ firstCategory: "品牌",
+ secondCategory: "店铺",
thirdCategory: "三级分类",
fourthCategory: "四级分类",
fifthCategory: "五级分类",
@@ -183,6 +185,14 @@ export function normalizeAgentWorkflowCategoryLabels(
};
return {
+ firstCategory: normalizeLabel(
+ record.firstCategory ?? record.firstCategoryLabel ?? record.brand ?? record.brandLabel,
+ defaultAgentWorkflowCategoryLabels.firstCategory
+ ),
+ secondCategory: normalizeLabel(
+ record.secondCategory ?? record.secondCategoryLabel ?? record.store ?? record.storeLabel,
+ defaultAgentWorkflowCategoryLabels.secondCategory
+ ),
thirdCategory: normalizeLabel(
record.thirdCategory ?? record.thirdCategoryLabel,
defaultAgentWorkflowCategoryLabels.thirdCategory
diff --git a/types/agent.ts b/types/agent.ts
index 3776f0d95..a66ece22d 100644
--- a/types/agent.ts
+++ b/types/agent.ts
@@ -116,6 +116,8 @@ export interface AgentWorkflowUiConfig {
}
export interface AgentWorkflowCategoryLabels {
+ firstCategory: string;
+ secondCategory: string;
thirdCategory: string;
fourthCategory: string;
fifthCategory: string;