skill: 正文改指针 —— 消除第三份副本(结构上根治漂移)
skill/SKILL.md 不再保存技能正文,只留指针指向注册表 admin9webs/atomk-hermes-skills 的 skills/cross-border-ecommerce/dianxiaomi-multiplatform-listing/SKILL.md。 原因:本仓库曾于 2026-09-20(faeb95c)存过一份正文,但没有任何同步步骤, 09-21~09-30 注册表更新到 172 行时它停在 113 行 → 漂移。428255a 先补齐,本次改为指针, 副本从三份(注册表/部署/本仓库)降到两份(注册表实体 + deploy-fleet.sh 下发的部署副本)。 历史正文可 git show 428255a:skill/SKILL.md 取回;README 同步改写。
This commit is contained in:
1 parent
c0fa1ce434
commit
917df5b2d6
2 files changed
+35
-177
No files matched your search
@@ -161,16 +161,16 @@ function wrap(o, n, l) {
|
||||
3449 与 3450)是**两次真实消耗**,两个号都已作废,不能当成修正丢掉前一个
|
||||
- 说明书 §1 的例子 `pc 1000 → 6980309310004` **是错的**,正确是 `6980309310007`
|
||||
|
||||
## 技能实体在哪:本仓库的 `skill/SKILL.md` 只是快照(2026-10-04 查明)
|
||||
## 技能实体在哪:本仓库只留指针(2026-10-04 起)
|
||||
|
||||
本仓库的 `skill/SKILL.md` **不是**技能实体,而是 2026-09-20(提交 `faeb95c`)放进来的一份**一次性快照**。
|
||||
技能的实体在**技能注册表**:`admin9webs/atomk-hermes-skills` →
|
||||
`skill/SKILL.md` 已改成**指针文件**,技能正文不在本仓库。
|
||||
实体在技能注册表:`admin9webs/atomk-hermes-skills` →
|
||||
`skills/cross-border-ecommerce/dianxiaomi-multiplatform-listing/SKILL.md`。
|
||||
|
||||
KVM-2 上的分发链是:
|
||||
分发链(KVM-2 侧):
|
||||
|
||||
```
|
||||
atomk-hermes-skills(注册表,改技能在这里改)
|
||||
atomk-hermes-skills(注册表 = 实体,改技能在这里改)
|
||||
└─ KVM-2 clone: ~/dsh-dingtalk-workspace/skills-repo/
|
||||
└─ deploy-fleet.sh --dsh <技能名>
|
||||
├─→ 各机 ~/.dsh/skills/<技能>/SKILL.md (DSH agent 读这里)
|
||||
@@ -179,17 +179,20 @@ atomk-hermes-skills(注册表,改技能在这里改)
|
||||
|
||||
目标机:`kvm2(.122) / a1(.152) / s01(.231) / s02(.232) / s03(.217)`。
|
||||
|
||||
### 所以改技能的正确姿势
|
||||
### 改技能的正确姿势
|
||||
|
||||
1. 改注册表:`~/dsh-dingtalk-workspace/skills-repo/skills/cross-border-ecommerce/dianxiaomi-multiplatform-listing/SKILL.md`,提交并推送;
|
||||
1. 改注册表 clone:`~/dsh-dingtalk-workspace/skills-repo/skills/cross-border-ecommerce/dianxiaomi-multiplatform-listing/SKILL.md`,提交并推送;
|
||||
2. 分发:`cd ~/dsh-dingtalk-workspace/skills-repo && ./deploy-fleet.sh --dsh dianxiaomi-multiplatform-listing`;
|
||||
3. 若要让本仓库这份快照跟上(**没有自动同步**):
|
||||
`cp <注册表路径> skill/SKILL.md` 然后提交。
|
||||
3. **不需要**再往本仓库同步正文 —— 这里只有指针。
|
||||
|
||||
⚠️ **不要**把 `~/.dsh/skills/` 下的文件改成指向别处的软链 —— `deploy-fleet.sh` 用 `tar xz` 覆盖那个目录,
|
||||
软链会被下次分发直接抹掉,看起来"改了"其实无效。
|
||||
⚠️ 不要把 `~/.dsh/skills/` 下的文件改成软链:`deploy-fleet.sh` 用 `tar xz` 覆盖那个目录,软链会被下次分发抹掉。
|
||||
|
||||
### 漂移历史
|
||||
### 为什么改成指针
|
||||
|
||||
2026-09-21~09-30 期间注册表更新到 172 行(新增 `§2.1 建 listing 前的 0 号自检`、`§8 Ozon 保存被拦的错误链`),
|
||||
而本仓库这份快照停在 113 行、9 天没动。已由提交 `428255a` 以注册表版为准补齐,三者(注册表 / 现场 / 本仓库)md5 现已一致。
|
||||
2026-09-20(提交 `faeb95c`)本仓库曾存过一份技能正文,但**没有任何同步步骤**:
|
||||
09-21~09-30 注册表更新到 172 行(新增 `§2.1 建 listing 前的 0 号自检`、`§8 Ozon 保存被拦的错误链`)时,
|
||||
这份快照仍停在 113 行 —— 这就是当时那次"漂移"。
|
||||
|
||||
处置:`428255a` 先把快照以注册表版为准补齐(三方 md5 一致),随后改为指针,
|
||||
把副本从**三份**(注册表 / 部署 / 本仓库快照)降到**两份**(注册表实体 / 脚本下发的部署副本),
|
||||
从结构上消除这类漂移。历史正文可取回:`git show 428255a:skill/SKILL.md`。
|
||||
+18
-163
@@ -1,172 +1,27 @@
|
||||
---
|
||||
name: dianxiaomi-multiplatform-listing
|
||||
description: "在店小秘(dianxiaomi)把同一批商品批量建到多个跨境平台的「待发布」,并诊断「点保存没反应」。覆盖 Ozon/TikTok/Shopee/Walmart/速卖通/SHEIN/Temu 的店铺选择、类目弹窗、字段 store 落点、价格币种、图片外链写法、SKU 表结构。触发词:店小秘、dianxiaomi、批量建品、待发布、铺货、多平台、保存没反应、静默拦截、SHEIN 建品、Temu 建品、Temu 全托管、Walmart 建品、速卖通建品、TikTok 建品、Shopee 建品。"
|
||||
---
|
||||
# 指针:技能实体不在本仓库
|
||||
|
||||
# 店小秘多平台批量建品
|
||||
`dianxiaomi-multiplatform-listing` 技能的**正文在技能注册表**,这里只有指针(2026-10-04 起)。
|
||||
|
||||
> 完整配方与逐平台踩坑:Gitea `admin9webs/dianxiaomi-crossborder-playbook`(**以 Gitea 为准**;
|
||||
> 本机副本 `~/gitea-push/dianxiaomi-crossborder-playbook/` 可能滞后,读之前先 `git pull`)。
|
||||
> 本技能是可复用的**操作约定 + 通用技术事实**;具体字段表看仓库各平台目录。
|
||||
>
|
||||
> **选品建listing 的两个新配方(2026-09-30)**:
|
||||
> `速卖通建品/RECIPE-2026-09-30.md`(速卖通,实测 4/4 进待发布)、
|
||||
> `shopee建品/README-授权状态-2026-09-30.md`(Shopee 页面事实 + 授权异常证据链与解锁步骤);
|
||||
> 同一份内容也在技能 `dianxiaomi-multiplatform-push/references/`,另有运维脚本仓库
|
||||
> `admin9webs/product-pool-ops` → `listing-spec/`(共用页面库 / 输入生成 / 店铺自检 / 落地回读)。
|
||||
|
||||
## 0. 第一原则:遇到「点保存没反应」先挂钩子,不要猜字段
|
||||
|
||||
**症状**:点「保存」→ 不发 POST、无界面提示、无 `.ant-form-item-has-error`。
|
||||
|
||||
**根因**:校验失败了,但报错被 **`MYJ.message.error` 吞掉**;而且报错**层层递进**
|
||||
(修完 A 才显示 B)——不修完前一层,后一层根本不显示。
|
||||
|
||||
**解法**(在点保存**之前**注入):
|
||||
```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 省份:产地=中国才出现)和**类目相关的文件字段**
|
||||
(速卖通商品说明书:部分类目强制)。
|
||||
|
||||
已用此法定位:
|
||||
| 平台 | 被吞掉的报错 |
|
||||
| | |
|
||||
|---|---|
|
||||
| 速卖通 | `商品说明书 → 请上传文件!`(类目相关) |
|
||||
| SHEIN | `有必选规格未选择,请完善后再提交` |
|
||||
| Temu | `产地选择中国时,省份必填` → `产品变种不能为空!` → `尺寸不能为0或空` → `净重必须小于重量` → `请上传预览图` |
|
||||
| 注册表仓库 | `admin9webs/atomk-hermes-skills`(http://192.168.9.206:3000/admin9webs/atomk-hermes-skills) |
|
||||
| 注册表路径 | `skills/cross-border-ecommerce/dianxiaomi-multiplatform-listing/SKILL.md` |
|
||||
| 本机 clone | `~/dsh-dingtalk-workspace/skills-repo/skills/cross-border-ecommerce/dianxiaomi-multiplatform-listing/SKILL.md` |
|
||||
| 各机部署位置 | `~/.dsh/skills/dianxiaomi-multiplatform-listing/SKILL.md`(DSH 读)、`~/.hermes/skills/...`(Hermes 读) |
|
||||
|
||||
## 1. 通用技术事实
|
||||
**为什么不再放正文**:2026-09-20(提交 `faeb95c`)本仓库曾存过一份正文,但没有任何同步步骤;
|
||||
09-21~09-30 注册表更新到 172 行时,这份快照仍停在 113 行,于是产生"漂移"。
|
||||
现在改为指针,副本从三份降到两份(注册表 = 实体,`~/.dsh/skills` = 由脚本下发)。
|
||||
|
||||
- 站点是 **Vue3 + Pinia SPA**,读 store:
|
||||
```js
|
||||
document.querySelector('#app').__vue_app__.config.globalProperties.$pinia._s.get('<store>').$state
|
||||
```
|
||||
- Chrome CDP 端口 **9223**,profile `/tmp/dxm7`;helper `/tmp/cdp3.mjs`(**ESM,不能用 require**)
|
||||
- VNC:`http://192.168.9.122:6097/vnc.html` / `:6100`(免密)
|
||||
- 列表 API 一律 `POST /api/<平台>Product/pageList.json`,列表在 `data.page.list`
|
||||
- **`idStr ≠ id`**:大整数 JS 精度丢失,服务端操作(删除/详情)一律用 `idStr`
|
||||
|
||||
## 2. 交互约定(血泪换来的)
|
||||
|
||||
| 场景 | 正确做法 |
|
||||
|---|---|
|
||||
| antd select 选项 | **DOM click** `.ant-select-item-option` 通常可行 |
|
||||
| 只吃真实鼠标的组件 | `Input.dispatchMouseEvent` 发 `mousePressed`/`mouseReleased` |
|
||||
| **hover 触发的下拉** | 先 `mouseMoved` 到目标,再 `click`(Walmart「选择图片」) |
|
||||
| 类名含 `!` 的选择器 | `input[class*="!w-200"]`(`input.!w-200` 是非法 CSS) |
|
||||
| 长下拉(几百项) | 先 `scrollTop=0`(会残留上次位置),再滚动找 |
|
||||
| 有 store 直读列表 | **优先读 store**(Temu 类目 1038 个在 `dataState.categories`),比驱动 UI 可靠 |
|
||||
| 文本输入 | **优先 `Input.insertText`**(逐字符 `dispatchKeyEvent` 在 Shopee 产品标题**写入 0 字符**);退化时才用原生 setter `Object.getOwnPropertyDescriptor(proto,'value').set.call(el,v)` + `input`/`change`/`blur` 事件 |
|
||||
| 数字输入 | **原生 setter + `input`/`change`**;部分字段是**整数语义**(速卖通/Shopee 尺寸 `27.5` → `27`),逐字符键入还会把小数点直接吃掉(`27.5` → `275`) |
|
||||
| 改 store 后校验仍失败 | UI **异步同步**,**再点一次保存**可能就过了 |
|
||||
|
||||
## 2.1 建listing 前的 0 号自检:**这个平台有没有可用店铺**(2026-09-30 加)
|
||||
|
||||
没有店铺 → 点「选择分类」**弹窗根本不出现**(类目树随店铺/站点变)、保存必失败;
|
||||
**填完一整屏才发现 = 白跑一轮**。脚本侧同样硬拦(`listShopOptions()` 空数组即跳过该条)。
|
||||
**改技能 / 分发**:
|
||||
|
||||
```bash
|
||||
node listing-spec/platform-shared/preflight-shops.mjs # → /tmp/shop-preflight.json
|
||||
cd ~/dsh-dingtalk-workspace/skills-repo
|
||||
$EDITOR skills/cross-border-ecommerce/dianxiaomi-multiplatform-listing/SKILL.md
|
||||
git commit -am '...' && git push
|
||||
./deploy-fleet.sh --dsh dianxiaomi-multiplatform-listing # 下发到 kvm2/a1/s01/s02/s03
|
||||
|
||||
cat ~/.dsh/skills/dianxiaomi-multiplatform-listing/SKILL.md # 本机看正文
|
||||
```
|
||||
|
||||
**更快的账号级盘点**(一次接口,全平台店铺数):`readAccountShops(c)` 读 `GET /api/userIn.json` 的 `data.shopMap`。
|
||||
实测同一登录 **256 家店 → smt:61 / tiktok:98 / tiktokGlobal:24 / aliChoice:65 / ozon:5 / walmart:3,shopee 0 家**。
|
||||
★ **页面下拉只是子集**(速卖通页只列 10 家,账号里 61 家):
|
||||
判「有没有店」用 `readAccountShops`,判「能不能在这个页面选到」才用 `listShopOptions`。
|
||||
|
||||
实测(2026-09-30,登录子账号 `ejetZhangjiafen`):**TikTok 10 店、速卖通 10 店**;
|
||||
**Shopee 全球「商家账号」=「暂无数据」**;Mercado/Shopify/Amazon 拿不到店铺下拉。
|
||||
⚠️ 注意 **Shopee 此前是能建的**(本 playbook 记录过店铺 `Ljbgkj` 47 条进待发布)——
|
||||
所以「下拉为空」应读作==**当前账号的店铺授权异常/范围不足**==,不是平台从未授权:
|
||||
店小秘首页此时正挂着 `…/authorization/platform?go=shopee` 的「去处理>>」告警。
|
||||
|
||||
## 3. 各平台最独特的一点
|
||||
|
||||
| 平台 | 必须知道 |
|
||||
|---|---|
|
||||
| **Ozon** | 保存按钮是**「保存并移入待发布」**;价格 **CNY**;改价必须**同时抬高原价**,否则 `售价需小于原价`;回读走 API `variantList[].price(原价)/salePrice(售价)` |
|
||||
| **TikTok** | 价格 **MYR**;店铺**锁站点**(一个品牌 × 多站点);图片 store 直接吃**外链数组** |
|
||||
| **Walmart** | 保存体是 **zip 的 multipart**(zip 内 `walmartSave.txt`);Brand 必须**点「无品牌」勾选框**(打字无效);图片必须 **hover → 网络图片** 贴 URL |
|
||||
| **Shopee** | 用**单件模式** `type='single'` 绕开变种(默认 `mutiple`);价格 **CNY**;列表字段是 `itemName` **不是** title;**「上架后自动发布到店铺」是 checkbox,必须不勾**(勾了=保存即发布);尺寸规格是**整数 cm**;图片模块 `.shopee-global-product-image-module`(头是 `header.product-image-header`)。详见 `dianxiaomi-multiplatform-push/references/recipe-shopee-global.md` |
|
||||
| **速卖通** | **`check_box` 属性值必须是数组**(否则 `P.forEach is not a function`);图片列用外链 `{id,url,name,width,height,imgId,checked}`。⚠️ **保存必填**:货值 / **物流属性**(点 `.single-logistics-attr-edit` 铅笔 → 弹窗选「普货」,**不是普通下拉**,报「物流属性必填!」)/ **包装尺寸+包装后尺寸都要整数 cm** / **报价是否含关税** radio value=1;**重量必须精确命中「重量(kg)」**(类目属性里另有「重量(Item Weight)」);描述是 **CKEditor 4**(`ckeditor30`=PC端 / `ckeditor31`=无线端)。详见 `dianxiaomi-multiplatform-push/references/recipe-aliexpress-smt.md` |
|
||||
| **SHEIN** | **店铺锁品类**(箱包店选不了发夹);类目要**两个规格**(点 `.theme-select-box` 加 `尺寸(Size)`);⚠️ **加规格会重建 SKU 行**,顺序必须「规格 → SKU → 尺码表」 |
|
||||
| **Temu** | 规格用 **`.theme-value-add`** 块(值输入 + 添加按钮),**必须手动输值再点添加**,改 store 无效;报错层层递进 |
|
||||
|
||||
## 4. 图片
|
||||
|
||||
全部用**外链**(alicdn 等),且必须**无水印**(平台会删带联系方式的图)。
|
||||
字段形如 `{url, imgUrl, name, width, height}`,多数平台存**数组**,
|
||||
Walmart 例外(必须走「网络图片」UI,落成 `|` 分隔字符串)。
|
||||
|
||||
**尺寸门槛按平台不同**(2026-09-30 实测):Ozon **单边 ≥200px**;**速卖通 / Shopee 单边 ≥400px**
|
||||
——喂 10 张给速卖通会**静默只收 6 张**(300×224 / 300×195 / 367×344 / 300×213 被丢,且不报错)。
|
||||
→ **建输入时就按真实尺寸过滤**:`build-add-input.py --min-side 400`(会下载探尺寸;
|
||||
文件名带中文如 `TIM截图….jpg` 必须**先 percent-encode**,否则 urlopen 报错把好图误杀)。
|
||||
主图上限:速卖通 6 张、Shopee「附图最多 9 张」+ 主图。
|
||||
|
||||
## 5. 定价口径
|
||||
|
||||
Ozon ≤500g 档(用户给定的表,已解出公式):
|
||||
```
|
||||
运费成本 = 4.2 + 重量(g) × 0.045
|
||||
合计成本 = 进货价 + 运费成本
|
||||
售价 = 合计成本 ÷ (1 − 20%佣金 − 利润率)
|
||||
价格带 = 0–1500₽ / 0–113¥(≈13.27₽/¥)
|
||||
```
|
||||
其它档:budget 500-2500g `重量×0.02345+15.96`;small 1-2000g `重量×0.02534+14.07`。
|
||||
跨币种:MYR ≈ CNY×0.60;USD = CNY÷6.68525(店小秘 `siteAndUsCurrencyRate`)。
|
||||
|
||||
## 6. EAN-13 台账(湖北易千亿彩 · 69803093 段)
|
||||
|
||||
- 结构:`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 权重相反**)
|
||||
- 台账唯一来源 **S03 `/root/ean_*.txt`**(KVM-2 够不到)→ 用号后**必须去 S03 落盘**,否则撞号
|
||||
- 说明书 §1 例子 `pc 1000 → 6980309310004` 是**错的**,正确 `6980309310007`
|
||||
|
||||
## 7. 批量作业约定
|
||||
|
||||
- 动辄 1 小时 → `nohup bash run.sh > out.log 2>&1 &` 后台跑,**每条一个日志文件**
|
||||
- 脚本写成「一个 oid 一条命令」+ shell 循环,**单条失败不拖垮整批**
|
||||
- **跑之前先检查是否已存在**,否则重试会产生重复(本会话踩过:某商品被建了 3 份)
|
||||
- 删重复:速卖通 `POST /api/smtProduct/batchDelete.json` body `ids=<idStr>`
|
||||
|
||||
## 8. Ozon「保存并移入待发布」被拦的真实错误链(2026-09-30 实测,逐层挖出来的)
|
||||
|
||||
**症状链**:草稿 `categoryId="0"` → `GET /api/ozonProduct/moveToNoPublish.json?id=<草稿id>&shopId=-1`
|
||||
**返回 code=0 却不动作**(待发布总数不变)→ 改成在编辑页点「保存并移入待发布」→
|
||||
前端校验拦截、**没有任何保存请求发出**、被吞的提示只有 `MYJ.error: 产品信息中有错误,请检查`、
|
||||
且 `.ant-form-item-has-error` 数量为 **0**(光扫 DOM 定位不到)。
|
||||
|
||||
**挖法**:注入 `MYJ.message` / `antd.message` 钩子(见第 0 节)后点保存,再 dump
|
||||
`.ant-form-item-explain-error` / `[class*=explain]` 文本 —— 真正的报错是**分层**出现的:
|
||||
|
||||
| 层 | 报错原文 | 怎么解 |
|
||||
|---|---|---|
|
||||
| 1 | (无提示,纯静默) | 类目未落定:`categoryId=0`/`fullCid` 形如 `304634-` |
|
||||
| 2 | `产品标题只能输入英文或者俄文,请修改!` | 草稿带的是 **1688 中文标题** → 必须换成英/俄文案 |
|
||||
| 3 | `产品描述只能输入英文或者俄文,请修改!` | 同上,描述也要英/俄 |
|
||||
| 4 | `图片高最小尺寸不能小于200像素!` | 有主图高度 < 200px → 挑图/换图 |
|
||||
|
||||
**结论**:Ozon 这条链的正确顺序是 **① 类目落定 → ② 写入英/俄文案(池里 `copy_variants` 的 Ozon 版就是俄文)→
|
||||
③ 图片尺寸达标 → ④ 保存并移入待发布 → ⑤ 回读 `pageList` 的 `waitPublish` 口径验收**。
|
||||
只做类目或只看 `code` 都会得到「假成功/假失败」。
|
||||
|
||||
**类目弹窗的操作要点**(`listing-spec/ozon-daily/ozon-daily-category.mjs`):
|
||||
* 搜索框 `input[name="searchCategory"]`,**必须点「搜索」按钮**才出结果;
|
||||
* 结果行是 `.search-result-item`,文本形如
|
||||
`Галантерея и аксессуары(小百货和配饰)/Аксессуары для волос(发饰)/Повязка для волос(发带)`,
|
||||
**分隔符是 `/` 不是 `>`**;点某一行即落定(弹窗自动关闭,没有「选择」按钮那一步);
|
||||
* 选优打分:末段括号里**精确等于**关键词 +3、末段含关键词 +2、路径含「小百货/Галантерея」+1。
|
||||
|
||||
**只读排查工具**(同目录):`probe-ozon-edit.mjs`(编辑页 Network + 钩子 + 快照)、
|
||||
`diag-move-state.mjs`(按草稿 id / offer id 在待发布·草稿·offline* 三口径定位)。
|
||||
历史正文(172 行,与注册表一致)仍在提交 `428255a`:`git show 428255a:skill/SKILL.md`。
|
||||
Reference in new issue
Block a user