refactor(api): parsing out of runtime — pure-mirror sync, explicit organize, auto aggregate recompute
解析去运行时化(三层架构,plans/refactor/organize-script-refactor.md): - 同步 = 纯镜像:upsertOriginGood 不再写解析列、不再自动挂族;详情同步仍触发重算 - 整理 = 显式人工动作(OrganizeService):解析列回填 → 派生标签(人工接管永不 覆盖)→ auto-group 建族 → 全量重算;入口 CLI(pnpm --filter @inkreach/api organize)+ POST /product-families/organize + 后台「整理」按钮 - 重算 = 纯结构化聚合:不再按名称重派生标签(防上游改名倒灌,回归测试覆盖); 矩阵维度只认标签/CUSTOM 显式标签,未整理成员不进矩阵;工艺=不打印时 印花数量以单面占位(纯结构化规则);「恢复自动」走整理的单链接派生 - 派生默认补齐(脚本层假设):名称无单/双面且工艺非不打印 → 印花数量单面印花 - goods 服务建品/更新后仅镜像标签+重算(不派生);含商品名入库规范化 (normalizeGoodName,管理员输入边界质检) - organize.service.spec 由 tag-sync spec 迁移 + 防倒灌回归;sync/recompute/ public/families spec 全部适配;API 173/173,admin typecheck+22/22
This commit is contained in:
@@ -16,6 +16,7 @@ import { categoriesApi } from '@/api/categories'
|
||||
import { tagsApi } from '@/api/tags'
|
||||
import { tagGroupsApi } from '@/api/tag-groups'
|
||||
import { originGoodsApi } from '@/api/origin-goods'
|
||||
import { productFamiliesApi } from '@/api/product-families'
|
||||
import { syncApi } from '@/api/sync'
|
||||
import { sameFamily } from '@/utils/family-match'
|
||||
import { sameOriginGroup } from '@/utils/origin-name'
|
||||
@@ -999,6 +1000,32 @@ function onSearch() {
|
||||
rightTreeRef.value?.filter?.('')
|
||||
}
|
||||
|
||||
/** 整理原产品库:解析列回填 → 派生标签 → 自动建族 → 全量重算(显式人工动作) */
|
||||
const organizing = ref(false)
|
||||
async function onOrganize() {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
'将执行:回填解析列 → 派生标签(人工接管不动)→ 自动建族 → 全量重算矩阵。可能耗时较长,继续?',
|
||||
'整理原产品库',
|
||||
{ confirmButtonText: '整理', cancelButtonText: '取消' },
|
||||
)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
organizing.value = true
|
||||
try {
|
||||
const r = await productFamiliesApi.organize()
|
||||
ElMessage.success(
|
||||
`整理完成:解析 ${r.labelsParsed} 条 / 标签更新 ${r.linksUpdated} 链接 / 新建族 ${r.familiesCreated} / 重算 ${r.familiesRecomputed} 族`,
|
||||
)
|
||||
await loadAll()
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e?.response?.data?.message || '整理失败')
|
||||
} finally {
|
||||
organizing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => loadAll())
|
||||
</script>
|
||||
|
||||
@@ -1036,6 +1063,7 @@ onMounted(() => loadAll())
|
||||
</el-input>
|
||||
<el-button size="small" type="primary" :icon="Search" @click="onSearch">搜索</el-button>
|
||||
<div class="gv-filter-spacer" />
|
||||
<el-button size="small" :loading="organizing" @click="onOrganize">整理</el-button>
|
||||
<el-button size="small" type="success" :icon="Plus" @click="openCustomCreate">新增自定义商品</el-button>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user