diff --git a/.gitignore b/.gitignore index 2dada1e..f983731 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ dist/ deploy/certbot/ deploy/data-dump.json uploads/ + +# Data cleaning runtime artifacts (production snapshots, exports, reports) +data-cleaning/runs/ diff --git a/data-cleaning/README.md b/data-cleaning/README.md index cc67767..98bed58 100644 --- a/data-cleaning/README.md +++ b/data-cleaning/README.md @@ -3,6 +3,88 @@ 本目录存放商品数据清洗相关的全部脚本与规则文件。清洗目标:把右侧 SDS 原产品库 (`origin_goods`)按规则批量配置为左侧官网商品(`goods`),替代后台手动逐个点击。 +## 转换规则调查(2026-08-27,基于生产环境只读数据) + +> 数据来源:`https://official.inkreach.cc/api` 生产接口(JWT 只读拉取): +> `/origin-goods?page=1..3&pageSize=200`(共 552 条)、`/goods?page=1..2&pageSize=200`(共 240 条)、 +> `/tags`、`/categories`、`/countries`。未做任何写操作。 +> 原始 JSON 快照存于 `runs/survey-2026-08-27/`(已加入 .gitignore,不入库)。 + +### 1. 右侧原产品(origin_goods)命名结构 + +右侧只有**一个字符串** `goodName`,整体模式: + +``` +国家(物流备注)品名-SKU-工艺位置[-仓库名] + ↑ ↑ ↑ ↑ ↑ + | | | | └─ 可选第4段:美西洛杉矶一仓 / 美中亚特兰大仓 等 + | | | └─ 单面印花 / 双面印花 / 直喷双面 / 直喷单面 / 不打印 ... + | | └─ SKU 编码(字母+数字,如 DG001 / C1717 / KRHM003) + | └─ 包邮 / 不包邮 / DHL包邮*运费结算订单时支付 / 不包邮光板 等变体 + └─ 美国/德国/韩国...(全角括号为主,少量半角混用) +``` + +统计(552 条): +- **541 条**匹配 `国家(备注)其余` 模式;**11 条异常**: + - 4 条自定义商品(`Goods Origin ...`,source=CUSTOM) + - 2 条缺国家前缀:`(不包邮)230g水洗炒雪花T恤-双面印花` / `(不包邮)180g纯棉T恤成人款-...` + - 1 条用空格代替括号:`法国 180g纯棉T恤-FRTM001-双面印花` + - 2 条半角左括号混用:`美国(不包邮)女士高弹中长款瑜伽运动裤-JSD004-...` + - 2 条同上变体 +- 「备注)之后」按 `-` 分段:**387 条 = 3 段**(品名-SKU-工艺)、**154 条 = 4 段**(品名-SKU-工艺-仓库) +- 物流备注出现的变体形态(示例):`包邮`、`不包邮`、`DHL包邮`、`DHL包邮*运费结算订单时支付`、`包邮*运费订单结算时支付`、`不包邮光板` +- 国家前缀出现过的值:美国、德国、英国、意大利、西班牙、西班牙直发、韩国、日本、加拿大、墨西哥、巴西、波兰、澳大利亚 + +### 2. 左侧已配置商品(goods)现状 —— 人工配置的实际结果 + +240 条 goods 记录,覆盖 **209 个**不同 origin_good_id(**343 个 origin 尚未配置**)。 + +**没有系统级拆分逻辑**:前端 [GoodsView.vue](../apps/admin/src/views/goods/GoodsView.vue) 提交的是完整原名, +后端 [goods.service.ts](../apps/api/src/goods/goods.service.ts) create/batchCreate 也原样入库。 +因此左侧名称与右端的差异(113/240 条被改过)全部是**人工在编辑弹窗里改的**,且存在多种风格并存。 + +改名风格分布(113 条改名的归类): + +| 风格 | 数量 | 示例 | +|------|------|------| +| A. 全拆:去前缀去括号,品名+空格+SKU,丢弃工艺段 | 27 | `韩国(包邮)200g纯棉T恤-KRTM001-单面印花` → `200g纯棉T恤 KRTM001` | +| B. 半改:仅把长备注缩成「X包邮」,其余原样保留 | 86 | `德国(DHL包邮*运费结算订单时支付)230g水洗T恤-DETM002-单面印花` → `德国(DHL包邮)230g水洗T恤-DETM002-单面印花` | +| R0. 保持原名不动 | 127 | 多为后期配置(2026-06 后期 ~ 07),未加工 | + +标签体系(生产库现有 3 组 7 个标签)与左侧使用情况: + +| 分组 | 标签(id) | 左侧使用次数 | +|------|----------|--------------| +| 物流渠道 | 包邮(30) / 不包邮(31) | 87 / 153 ← 基本每个商品都挂了物流标签 | +| 印刷位置 | 双面印(35) / 单面印(34) | 14 / 14 ← 只有少数挂了 | +| 印刷工艺 | 烫画(32) / 直喷(33) / 不打印(42) | 11 / 3 / 1 | + +其他字段:goodPriority 几乎全部为 5;positionId 全部为空; +国家字段与名称里的国家前缀一致率 238/240(仅 `西班牙直发(...)` 两条归入了「西班牙」)。 + +### 3. 从字符串解析出的隐含规则(草稿,待确认) + +一条原产品字符串可以机械解析出以下信息(541/552 可完全机器解析): + +| 解析项 | 来源 | 对应目标字段 | +|--------|------|--------------| +| 国家 | 第一个 `(` 之前文本(需处理:空格分隔、半角括号、「西班牙直发→西班牙」映射) | `countryId` | +| 物流渠道 | 括号内含「包邮」与否 → 包邮 / 不包邮 | tag: 物流渠道 | +| 工艺/印刷位置 | 最后一段的 关键词:单面印花→单面印、双面印花→双面印、直喷→直喷、烫画→烫画、光板/不打印→不打印 | tags: 印刷位置 + 印刷工艺 | +| 展示名 | 目标形态(用户口径):`品名 SKU`(最后一个 `-` 连接改为空格连接,丢弃工艺/仓库段) | `goodName` | + +### 4. 待确认问题(规则定稿前必须回答) + +1. 展示名采用哪种?A 全拆(`200g纯棉T恤 KRTM001`,推荐—— majority 且官网展示干净)还是 B 保留国家括号? +2. 同一基础商品的「单面印花」「双面印花」是拆成两个 goods(现状),还是合并为一个 good 并用标签区分? + (注意 A 全拆后两者 goodName 完全相同,如 ITTM001 已出现重名两条) +3. 历史 R0 的 127 条保持原名的记录是否要统一重命名? +4. 未配置的 343 个 origin 是本次要全部自动配置的目标吗?(其中可能有不应上架的商品) +5. 仓库名后缀(第 4 段)只做清洗忽略即可,还是需要保留到某个字段? +6. 国家中文名 → countries 表的映射以 `countryName` 精确匹配为准?缺失国家(如法国 FRTM001 对应的国家若不存在)如何处理? + +--- + ## 执行流水线 ``` @@ -28,6 +110,6 @@ |------|------|------| | `sync-rules.config.mjs` | 待创建 | 同步规则文件(品类映射 / 国家分配 / 标签分配 / 优先级策略),规则未定,先占位 | | `sync-transform.mjs` | 待创建 | 数据转换脚本 | -| `runs/` | 待创建 | 每次执行的导出、转换产物与变更摘要报告(按日期归档) | +| `runs/` | 待创建 | 每次执行的导出、转换产物与变更摘要报告(按日期归档);已含 `survey-2026-08-27/` 调查快照(gitignore) | 详细实施计划见 [plans/feature/goods-data-cleaning-feature.md](../plans/feature/goods-data-cleaning-feature.md)。