f01d3ba那版是用 SSH 双引号包着的 heredoc 写的,节内的反引号在**本地**就被当成命令替换执行了, 落库内容里所有代码片段(skill/SKILL.md、部署路径等)全部变成空白。本次用 stdin 追加重写, 内容完整(含 §2.1 / §8 /428255a等引用)。
176 lines
13 KiB
Markdown
176 lines
13 KiB
Markdown
# 店小秘多平台铺货配方(dianxiaomi crossborder playbook)
|
||
|
||
同一批 **48 个 1688 商品**铺到店小秘各平台的「待发布」。本仓库是**可复用的配方 + 踩坑记录**,
|
||
不是一次性脚本堆积——每个平台一个目录,含配方脚本、输入数据、逐条结果。
|
||
|
||
## 战果
|
||
|
||
| 平台 | 店铺 | 待发布 | 状态 |
|
||
|---|---|---|---|
|
||
| TikTok | AutoMavenShop_MY | **47** | 完成 |
|
||
| Shopee | Ljbgkj | **47** | 完成 |
|
||
| 速卖通 | 4024039 | **47** | 完成(含清理 4 份重复) |
|
||
| Walmart | Snowmountain | **46** | 完成 |
|
||
| Ozon | Yejet | **47** | 已建;改价 40/47 |
|
||
| SHEIN | 4 家分品类 | **40** | 完成(`shbatch.mjs` 自动批量;1 条因 ①箱包店发品额度用尽改挂 ②店) |
|
||
| Temu 全托管 | ①Alimingpro | **47** | 完成(`tmbatch.mjs` 批量 46 + 手工首条;预览图已解) |
|
||
| Joom | Dummer-Pets(84 家里的第一家) | **47** | 完成(`jmbatch.mjs` 批量 46 + 手工首条;与 aliChoice 共用 `smtChoice*` store) |
|
||
|
||
> `601964534137`(遥控器保护套)18 张图全带水印、无干净图,所有平台统一跳过。
|
||
|
||
## 🔁 可复用配方(2026-09-30 更新,选品建listing)
|
||
|
||
本轮把「选品建listing」从一次性脚本升级成**可复用配方 + 共用页面库**,落点是
|
||
Gitea `admin9webs/atomk-hermes-skills` 的技能 `cross-border-ecommerce/dianxiaomi-multiplatform-push`:
|
||
|
||
| 内容 | 位置 |
|
||
|---|---|
|
||
| 速卖通配方(**实测 4/4 进待发布、采集箱 0 新增草稿**) | 本仓库 `速卖通建品/RECIPE-2026-09-30.md`,技能 `references/recipe-aliexpress-smt.md` |
|
||
| Shopee 现状(脚本就绪,**卡店铺授权异常**) | 本仓库 `shopee建品/README-授权状态-2026-09-30.md`,技能 `references/recipe-shopee-global.md` |
|
||
| 共用页面库(CDP 点击/滚动、insertText 写文本、原生 setter 写数字、类目弹窗、网络图片、CKEditor、物流属性、店铺自检) | `listing-spec/platform-shared/dxm-add-lib.mjs` |
|
||
| 建listing 输入生成(**按真实图片尺寸过滤**:Ozon≥200 / 速卖通·Shopee≥400;英文类目→中文搜索词) | `listing-spec/platform-shared/build-add-input.py` |
|
||
| **建listing 前置自检:这个平台有没有可用店铺** | `listing-spec/platform-shared/preflight-shops.mjs` |
|
||
| 落地回读(待发布命中 + 本轮是否残留草稿) | `listing-spec/platform-smt/verify-landing.mjs` |
|
||
| 运维脚本归档仓库 | Gitea `admin9webs/product-pool-ops` → `listing-spec/` |
|
||
|
||
**每轮批量前先跑店铺自检**(没有店铺 → 「选择分类」弹窗根本不出现、保存必失败;填完一屏才发现 = 白跑一轮)。
|
||
2026-09-30 实测:TikTok 10 店、速卖通 10 店;**Shopee 无(授权异常)**;Mercado/Shopify/Amazon 拿不到店铺下拉。
|
||
|
||
## ⭐ 最重要的一节:保存静默拦截诊断法
|
||
|
||
**症状**:点「保存」→ 不发 POST、无界面提示、无 `.ant-form-item-has-error`。
|
||
|
||
**根因**:校验确实失败了,但报错被 **`MYJ.message.error` 吞掉**;而且报错是**层层递进**的
|
||
(修完 A 才显示 B),所以肉眼和 DOM 扫描都抓不到。
|
||
|
||
**解法**——在点保存**之前**挂钩子:
|
||
|
||
```js
|
||
window.__cap = [];
|
||
function wrap(o, n, l) {
|
||
const f = o[n];
|
||
o[n] = function () {
|
||
window.__cap.push(l + ': ' + [...arguments].map(a => typeof a === 'string' ? a : JSON.stringify(a)).join(' '));
|
||
return f.apply(o, arguments);
|
||
};
|
||
}
|
||
['error','warning','info','success'].forEach(k => wrap(MYJ.message, k, 'MYJ.' + k));
|
||
['error','warning','info','success'].forEach(k => wrap(antd.message, k, 'antd.' + k));
|
||
```
|
||
|
||
点保存 → 读 `window.__cap`。
|
||
|
||
**为什么之前的「必填扫描」不够**:扫 `.ant-form-item-required` 且为空,漏掉两类——
|
||
**条件必填**(Temu 的省份,只有「产地=中国」才出现)和**类目相关的文件字段**
|
||
(速卖通的商品说明书,有些类目强制、有些不强制)。
|
||
|
||
详见 `静默拦截诊断/HOOK.md`。
|
||
|
||
## 各平台要点速查
|
||
|
||
| 平台 | 目录 | 最独特的一点 |
|
||
|---|---|---|
|
||
| Ozon | `ozon改价/` | 保存按钮是**「保存并移入待发布」**;价格是 **CNY**;改价必须同时抬高原价,否则报「售价需小于原价」 |
|
||
| TikTok | `tiktok建品/` | 价格 **MYR**;图片 store 直接吃**外链数组** |
|
||
| Shopee | `shopee建品/` | 用**单件模式**绕开变种;价格 **CNY**;列表字段是 `itemName` 不是 title |
|
||
| Walmart | `walmart建品/` | 保存体是 **zip 的 multipart**;Brand 必须点「无品牌」;图片必须 **hover** 开下拉走「网络图片」 |
|
||
| 速卖通 | `速卖通建品/` | `check_box` 属性值**必须是数组**;`idStr ≠ id` |
|
||
| SHEIN | `shein建品/` | 店铺**锁品类**;**一个产品最多 3 个规格**(加满就停);**加规格会重建 SKU 行**;类目动态必填属性(`.attr-label.required`)不填只报「产品信息中有错误」 |
|
||
| Temu | `temu建品/` | 类目 1038 个从 store 直读;规格是 `.theme-value-add`(**必须手动输值再点「添加」**,与 SHEIN 不同构);主图**必须满 5 张**;**预览图逐行点单元格** → 引用产品轮播图 → 全部 → 选择 |
|
||
| Joom | `joom建品/` | 店铺是**复选框组**(85 个 = 全部+84 店,别碰「全部」);类目是**可搜索下拉平铺列表**;商品数据落在 **`smtChoiceAddBasicStore`**(与 aliChoice 同构,不在 `joom*` 里) |
|
||
|
||
## 通用技术事实
|
||
|
||
- Chrome CDP 端口 **9223**,profile `/tmp/dxm7`
|
||
- **列表路由:`/draft` = 采集箱,`/offline` = 待发布**(找不到刚存的货,先确认进的是 `offline`)
|
||
- Temu 全托管 `/web/temu/choiceTemuList/*`;Temu 半托管 POP `/web/popTemu/pageList/*`
|
||
- Temu 全托管保存接口 `/api/pddkjProduct/add*.json`(拼多多跨境 = Temu 全托管)
|
||
- 站点是 Vue3 + Pinia:
|
||
`document.querySelector('#app').__vue_app__.config.globalProperties.$pinia._s.get('<store>').$state`
|
||
- CDP helper:`cdp3.mjs`(`newTarget`/`attach`/`closeAllTabs`/`CDP`/`SAN`),ESM,**不能用 require**
|
||
- 平时跑在 `/tmp/cdp3.mjs`,**是 /tmp 下的临时文件,重启机器会丢** → 仓库根目录有备份,
|
||
丢了 `cp cdp3.mjs /tmp/cdp3.mjs` 即可
|
||
- ⚠️ 同一个 URL 开了多个标签时,`attach(url)` 会抢到**最后一个**匹配的标签。
|
||
批量脚本请用 `shein建品/sh_lib.mjs` 的 `newPage(url)`:按 target 直连,不会抢错
|
||
- VNC:`http://192.168.9.122:6097/vnc.html` 或 `:6100`(免密)
|
||
|
||
## 二十条会重复踩的坑
|
||
|
||
1. **保存静默拦截** → 挂钩子,别猜
|
||
2. **`idStr ≠ id`** → 大整数精度丢失,服务端操作一律用 `idStr`
|
||
3. **`!w-200` 不是合法 CSS 类选择器** → 用 `input[class*="!w-200"]`
|
||
4. **antd select 吃 DOM click**,但有些组件只吃真实鼠标事件
|
||
5. **hover 触发的下拉**点不开 → 先 `mouseMoved` 再 `click`
|
||
6. **加规格会重建 SKU 行** → 顺序「规格 → SKU → 尺码表」
|
||
7. **store 赋值后 UI 异步同步** → 当次校验可能仍失败,再点一次保存
|
||
8. **类目决定是否强制资质文件**(速卖通某些类目要上传说明书)
|
||
9. **SHEIN 店铺锁品类** → 不能用「首字母第一家店」
|
||
10. `pkill -f <pat>` 会自杀 → 用 `[.]` 技巧(`pgrep -f 'foo[.]sh'`)
|
||
11. **SKU 表里「一格一图」的弹窗是单格的** → 勾「全部」只作用当前行,N 行要走 N 遍
|
||
(Temu 预览图就是这样:点 `.sku-image` 单元格 → 引用产品轮播图 → 全部 → 选择)
|
||
12. **选了类目别忘了确认弹窗关了** → 弹窗还开着时后面的点击全被挡,最后只会看到
|
||
「请上传预览图」这种牛头不对马嘴的报错(Temu 有 13 条就是这么挂的)
|
||
13. **SHEIN 规格上限 3 个** → 主题列表里看着能全点,点第 4 个就报「规格最多选择3个」
|
||
14. **类目动态必填属性**(`.attr-label.required`,如下拉、勾选组)不填不给具体提示,
|
||
只报「产品信息中有错误,请检查」→ 兜底:空的下拉选第一项、勾选组勾第一个
|
||
15. **EAN 游标必须落盘** → 计数器只存内存,换进程重跑就会从起点重发,必撞号
|
||
|
||
16. **没标 `*` 的字段也可能是必填** → Joom 的「运费」和「详情图语言」都没星号,
|
||
不填只给 `MYJ.error: 运费不能为空` / `请选择详情图语言且至少添加一张详情图`
|
||
17. **虚拟滚动的下拉,前几项里可能没有你要的值** → 先 `Input.insertText('英')` 过滤再点,
|
||
否则只能拿到列表第一项(Joom 详情图语言会落到「阿拉伯语」)
|
||
18. **找不到字段落点?打一个哨兵串** → 在页面手输 `PROBE-TITLE-XYZ`,再遍历所有 pinia store
|
||
的 `$state` 找这个串,立刻知道数据落在哪个 store(Joom 就是这么发现数据在 `smtChoice*` 的)
|
||
|
||
19. **搜不到 ≠ 结构不同:先怀疑输入,再怀疑结构** → Lazada 的类目树是**英文**的,
|
||
拿中文「发圈」去搜,搜索确实执行了但结果 0 条;换成 `Hair Accessories` 立刻出 6 条、
|
||
结构还与 SHEIN 完全一致。我们为此多花了 2 轮去怀疑「弹窗结构不同」
|
||
|
||
20. **平台的 store 不一定以平台名命名** → Lazada 选完类目后 pinia 里**没有任何 `lazada*` store**
|
||
(我们一度误判为「懒加载」)。找不到落点时**不要按平台名过滤**,dump 全部 store 或打哨兵串
|
||
(Temu 第一轮就撞了一次,靠编辑页改号救回来)
|
||
|
||
## EAN-13 台账(湖北易千亿彩 · 69803093 段)
|
||
|
||
- 结构:8 位前缀 `69803093` + 4 位产品码 + 1 位校验
|
||
- 校验位:`(10 - sum(d*(1 if i%2==0 else 3) for i,d in enumerate(d12)) % 10) % 10`
|
||
(左起权重 1,3,1,3…;UPC-A 权重相反,别混用)
|
||
- 台账唯一来源:**SG3 `43.134.190.229` 的 `/root/ean_*.txt`**(KVM-2 够不到,经 A3 落账)
|
||
- ⚠️ **「S03」是客户/团队代号(湖北易千亿彩),不是主机名** —— 舰队里没有叫 S03 的机器,
|
||
KVM-2 与 A3 的 hosts/DNS/known_hosts/记忆全查不到。别再找"S03 是哪台"了。
|
||
- 登录:`ssh -i ~/9webs_sites.pem root@43.134.190.229`(key 在 **A3 192.168.9.102**,
|
||
`~/9webs_sites.pem`)。⚠️ 别名 `ssh SG3` **解析不了**,一律用 IP。
|
||
- 格式惯例:**一个文件 = 一个完整连续区间** `ean_69803093_<lo>-<hi>.txt`,一行一个 EAN、
|
||
无表头无注释;区间的标签与内容都按"整段已发放"算 —— **空洞也要写进去**
|
||
(失败重跑烧掉的号,不写进去下次就会重发)。另有 `698030931_*`(9 位前缀)与 `upc_*` 系列,别混。
|
||
- 已用情况(2026-09-21 核对):
|
||
- Walmart pc **3400~3446**(`walmart建品/ean_69803093_3400-3446.txt`)
|
||
- Temu 全托管 pc **3447~3551**(逐条见 `temu建品/ean_temu_used.txt`;
|
||
游标 `temu建品/ean_cursor.json` → 下一号 pc **3552**)
|
||
- ✅ **已落 SG3**:`/root/ean_69803093_3400-3551.txt`(152 行 = pc 3400~3551 连续,含 58 个
|
||
重跑烧掉的空洞),两端 sha256 一致。SG3 全台账 = 11 个文件 / 2442 个号 / **跨文件重复 0**。
|
||
- 工具(别再手搓,`~/ean-sync/`):
|
||
- `verify_ledger.py` —— 校验位复算、`-FIX` 取代规则、与 `tm_done.json` 对账、游标分叉检查,
|
||
产出 `out/merge-<date>.txt` 与 `out/pid-map-<date>.json`
|
||
- `sync_to_sg3.sh` —— **幂等**同步:算区间 → 生成连续区间文件 → 查 SG3(哈希一致即跳过)
|
||
→ 重叠安全检查(除目标文件外该区间有号就中止)→ 经 A3 推送 → 哈希复核(`--dry` 只看不动)
|
||
- ⚠️ 发号**只看台账**,不看 `tm_done.json` —— 它是断点文件、换号后不更新(实测它对
|
||
`548459586741` 记 3449、对 `764423265986` 记 3449,均与台账不符)
|
||
- `<pid>-FIX` 行**取代**同一 pid 的早先行(pc 3449 曾被同时发给两个 pid,其中一个已由
|
||
`tm_fixean2.mjs` 换到 pc 3551);但同一 pid 在不同轮次拿到**不同**号(如 548459586741 的
|
||
3449 与 3450)是**两次真实消耗**,两个号都已作废,不能当成修正丢掉前一个
|
||
- 说明书 §1 的例子 `pc 1000 → 6980309310004` **是错的**,正确是 `6980309310007`
|
||
|
||
## 维护约定:`skill/SKILL.md` 是 KVM-2 上那份技能的唯一实体(2026-10-04 起)
|
||
|
||
KVM-2 的 `~/.dsh/skills/dianxiaomi-multiplatform-listing/SKILL.md` 现在是指向本仓库
|
||
`skill/SKILL.md` 的**软链**(原来是一份会各自漂移的拷贝)。
|
||
|
||
* 改技能 = 改这里的 `skill/SKILL.md`,改完**必须 commit + push**。
|
||
否则现场改动只是"未提交状态":DSH 下一次会话立刻就读得到,看起来已经生效,而仓库里没有 —— 这正是漂移的成因。
|
||
* **不要**再把部署文件当独立副本去改。
|
||
* 软链目标依赖本机 clone 路径 `~/gitea-push/dianxiaomi-crossborder-playbook/`;若要把 clone 挪走或重建,
|
||
记得同步更新软链,否则技能会从 DSH 目录里消失(已实测:提供器**会**跟随软链)。
|
||
* 历史漂移:2026-09-21~09-30 期间现场 172 行、仓库 113 行,差了两节
|
||
(`§2.1 建 listing 前的 0 号自检`、`§8 Ozon 保存被拦的错误链`),已由提交 `428255a` 以现场版为准回填。
|