diff --git a/admin/src/views/config/center/index.vue b/admin/src/views/config/center/index.vue index 2c7c573..1607968 100644 --- a/admin/src/views/config/center/index.vue +++ b/admin/src/views/config/center/index.vue @@ -65,6 +65,15 @@

按左侧分组编辑——保存后立即生效并产生新版本,历史可随时回滚

+ + 从网站导入 + 当前版本 v{{ version }}
+ + + + + diff --git a/admin/src/views/site-import/model.ts b/admin/src/views/site-import/model.ts index 9d4e8e5..799d46f 100644 --- a/admin/src/views/site-import/model.ts +++ b/admin/src/views/site-import/model.ts @@ -14,7 +14,8 @@ * (有则 dataURL→Blob→POST brand/avatar)→ PUT config/brand(读-改- * 写)→ PUT config/prompts → PUT config/wall(读-改-写,仅尾巴句)→ * PUT config/contact。本模块只构造步骤描述(kind/label/note),实际 - * 请求编排与部分失败重试在 Task 9 的 index.vue。 + * 请求编排与部分失败重试在 Task 9 的 index.vue;墙步的池形态分派由 + * wallPoolDispatch 纯函数承担(Task 9 备忘——保存时新鲜 GET 快照判断)。 */ import type { ApiError } from '@/api/client' @@ -218,6 +219,55 @@ export function buildSaveSequence(draft: SiteImportDraft): SaveStep[] { return steps } +// ---- 墙池形态分派(Task 9——保存时以新鲜 GET 快照判断替换/追加) ------------------------ + +/** 分派结果:mode=append 时 UI 提示「原池含人工编辑句,已追加而非替换」; + * pools 按语言给出目标池,null = 不触该语言(es 尾巴缺失的合法降级, + * 载荷保持 GET 快照原值) */ +export interface WallDispatch { + mode: 'replace' | 'append' + pools: Record<'en' | 'zh' | 'es', string[] | null> +} + +/** 现池语言槽防御归一:非数组值按空池对待(字符串项过滤) */ +function asStringList(value: unknown): string[] { + return Array.isArray(value) + ? value.filter((s): s is string => typeof s === 'string') + : [] +} + +/** + * deflections_contact 池形态分派(spec §3.2 / §5,Task 9 备忘升为纯函数): + * 保存时以**新鲜 GET** 的现池为判断基准,逐语言分派—— + * - 池内 >1 句 = 含人工编辑句 → 追加到末项(原句保留); + * - ≤1 句(出厂单句/空/缺键)→ 整句替换为新尾巴; + * - es 新尾巴 null → pools.es 为 null(不触该语言池)。 + * 任一语言走了追加 → mode='append'(调用方展示追加提示文案)。 + */ +export function wallPoolDispatch( + currentPools: Record, + newTails: { en: string; zh: string; es: string | null } +): WallDispatch { + let appended = false + const pools = {} as WallDispatch['pools'] + const current = currentPools ?? {} + for (const lang of ['en', 'zh', 'es'] as const) { + const tail = newTails[lang] + if (tail === null) { + pools[lang] = null + continue + } + const sentences = asStringList(current[lang]) + if (sentences.length > 1) { + appended = true + pools[lang] = [...sentences, tail] + } else { + pools[lang] = [tail] + } + } + return { mode: appended ? 'append' : 'replace', pools } +} + // ---- warnings 分级 ------------------------------------------------------------------- /** diff --git a/admin/src/views/tenants/list/index.vue b/admin/src/views/tenants/list/index.vue index aae9f60..8d26dde 100644 --- a/admin/src/views/tenants/list/index.vue +++ b/admin/src/views/tenants/list/index.vue @@ -121,6 +121,17 @@ {{ detail.status === 'active' ? '启用' : '停用' }} + + 从网站导入 + 绑定 + + +