Files
inkreach-official-website/apps/api/prisma/backfill-product-families.ts
T
yeuimu 93ac525c55 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
2026-08-30 01:27:01 +08:00

36 lines
1.6 KiB
TypeScript

/**
* 整理脚本(幂等 / 显式人工触发)——解析去运行时化后的唯一解析入口:
* 1. 回填结构化解析列(只补 NULL,不覆盖存量);
* 2. 派生链接标签(未人工接管的 SDS 链接按名称刷新,人工接管不动)+ 商品镜像;
* 3. 自动建族(auto-group);
* 4. 全量族重算(并集尺码表/包装 + 五维价格矩阵)。
*
* 运行:pnpm --filter @inkreach/api organize
* 后台等价入口:POST /product-families/organize(「整理」按钮)。
*/
import { PrismaService } from '../src/prisma/prisma.service';
import { FamilyRecomputeService } from '../src/product-families/family-recompute.service';
import { ProductFamiliesService } from '../src/product-families/product-families.service';
import { OrganizeService } from '../src/product-families/organize.service';
async function main() {
const prisma = new PrismaService();
await prisma.onModuleInit();
const recompute = new FamilyRecomputeService(prisma);
const families = new ProductFamiliesService(prisma, recompute);
const organize = new OrganizeService(prisma, recompute, families);
const result = await organize.organize();
console.log(
`[organize] labels parsed=${result.labelsParsed} (unparsable=${result.labelsUnparsable}) | ` +
`tags links=${result.linksUpdated} goods=${result.goodsUpdated} | ` +
`families created=${result.familiesCreated} recomputed=${result.familiesRecomputed}`,
);
await prisma.onModuleDestroy();
}
main().catch((error) => {
console.error(error);
process.exit(1);
});