114 lines
7.2 KiB
Markdown
114 lines
7.2 KiB
Markdown
---
|
||
name: dianxiaomi-multiplatform-listing
|
||
description: "在店小秘(dianxiaomi)把同一批商品批量建到多个跨境平台的「待发布」,并诊断「点保存没反应」。覆盖 Ozon/TikTok/Shopee/Walmart/速卖通/SHEIN/Temu 的店铺选择、类目弹窗、字段 store 落点、价格币种、图片外链写法、SKU 表结构。触发词:店小秘、dianxiaomi、批量建品、待发布、铺货、多平台、保存没反应、静默拦截、SHEIN 建品、Temu 建品、Temu 全托管、Walmart 建品、速卖通建品、TikTok 建品、Shopee 建品。"
|
||
---
|
||
|
||
# 店小秘多平台批量建品
|
||
|
||
> 完整配方与逐平台踩坑:Gitea `admin9webs/dianxiaomi-crossborder-playbook`(本机 `~/gitea-push/dianxiaomi-crossborder-playbook/`)
|
||
> 本技能是可复用的**操作约定 + 通用技术事实**;具体字段表看仓库各平台目录。
|
||
|
||
## 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或空` → `净重必须小于重量` → `请上传预览图` |
|
||
|
||
## 1. 通用技术事实
|
||
|
||
- 站点是 **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 可靠 |
|
||
| 文本输入 | `Object.getOwnPropertyDescriptor(proto,'value').set.call(el,v)` + `input`/`change`/`blur` 事件 |
|
||
| 改 store 后校验仍失败 | UI **异步同步**,**再点一次保存**可能就过了 |
|
||
|
||
## 3. 各平台最独特的一点
|
||
|
||
| 平台 | 必须知道 |
|
||
|---|---|
|
||
| **Ozon** | 保存按钮是**「保存并移入待发布」**;价格 **CNY**;改价必须**同时抬高原价**,否则 `售价需小于原价`;回读走 API `variantList[].price(原价)/salePrice(售价)` |
|
||
| **TikTok** | 价格 **MYR**;店铺**锁站点**(一个品牌 × 多站点);图片 store 直接吃**外链数组** |
|
||
| **Shopee** | 用**单件模式** `type='single'` 绕开变种;价格 **CNY**;列表字段是 `itemName` **不是** title |
|
||
| **Walmart** | 保存体是 **zip 的 multipart**(zip 内 `walmartSave.txt`);Brand 必须**点「无品牌」勾选框**(打字无效);图片必须 **hover → 网络图片** 贴 URL |
|
||
| **速卖通** | **`check_box` 属性值必须是数组**(否则 `P.forEach is not a function`);图片列用外链 `{id,url,name,width,height,imgId,checked}` |
|
||
| **SHEIN** | **店铺锁品类**(箱包店选不了发夹);类目要**两个规格**(点 `.theme-select-box` 加 `尺寸(Size)`);⚠️ **加规格会重建 SKU 行**,顺序必须「规格 → SKU → 尺码表」 |
|
||
| **Temu** | 规格用 **`.theme-value-add`** 块(值输入 + 添加按钮),**必须手动输值再点添加**,改 store 无效;报错层层递进 |
|
||
|
||
## 4. 图片
|
||
|
||
全部用**外链**(alicdn 等),且必须**无水印**(平台会删带联系方式的图)。
|
||
字段形如 `{url, imgUrl, name, width, height}`,多数平台存**数组**,
|
||
Walmart 例外(必须走「网络图片」UI,落成 `|` 分隔字符串)。
|
||
|
||
## 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 权重相反**)
|
||
- 台账唯一来源 **SG3 `43.134.190.229` 的 `/root/ean_*.txt`**(KVM-2 够不到,经 A3 落账)→
|
||
用号后**必须同步过去**,否则撞号。⚠️ **「S03」是客户/团队代号,不是主机名**(舰队里没有这台机器);
|
||
登录 `ssh -i ~/9webs_sites.pem root@43.134.190.229`(key 在 A3 .102),**别名 `ssh SG3` 解析不了**。
|
||
格式惯例:一个文件 = 一个完整连续区间 `ean_69803093_<lo>-<hi>.txt`,**空洞也要写进去**。
|
||
同步用 `~/ean-sync/sync_to_sg3.sh`(幂等,哈希一致即跳过,重叠则中止)
|
||
- 2026-09-21:pc **3400~3551** 已落 SG3(`/root/ean_69803093_3400-3551.txt`,152 行),
|
||
下一号 pc **3552**。发号只看台账,**不看 `tm_done.json`**(断点文件、换号后不更新)
|
||
- 说明书 §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>`
|