From f32e76f843633ae3151c4146d7464577475c54f4 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Fri, 9 Oct 2026 15:07:03 +0800 Subject: [PATCH] =?UTF-8?q?docs(douyin-mashida):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=9A=AE=E8=82=A4=E9=A2=86=E5=8F=96=E6=B5=81=E7=A8=8B=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E6=96=87=E6=A1=A3=20+=20=E8=81=94=E8=B0=83=E6=B8=85?= =?UTF-8?q?=E5=8D=95=E8=A1=A5=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `09-皮肤领取流程.md`:为什么改(固定链接/输订单号的问题)、新流程图、 为什么链接必须是路径式(# 是打手页)、商品图怎么来(内部 SKU → 英文 sku → 图片, 复用权威映射表 + 漏图守卫测试)、配置项表、兼容性(旧链接保留)、下一步(真正发货) - `08-公网联调.md`:联调 checklist 补「皮肤领取页两项配置」(含 `#` 告警)、 把「手机打开链接」改为买家领取链接并补任务/token 与四表对账 --- docs/抖音-码速达/08-公网联调.md | 17 ++++-- docs/抖音-码速达/09-皮肤领取流程.md | 94 +++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 docs/抖音-码速达/09-皮肤领取流程.md diff --git a/docs/抖音-码速达/08-公网联调.md b/docs/抖音-码速达/08-公网联调.md index 87313ee1..7712951d 100644 --- a/docs/抖音-码速达/08-公网联调.md +++ b/docs/抖音-码速达/08-公网联调.md @@ -162,15 +162,22 @@ npm run douyin-mashida:preflight -- --public-url https://xxxx.ngrok-free.app --s 2. 切公网地址 npm run douyin-mashida:set-public-url -- --public-url https://<域名> 3. 填真实凭据 面板:uid = 抖店商户号,secret = 真实用户秘钥 (baseUrl 保持 https://dy-openplatform-api.wanmahui.com) -4. 前置自检 npm run douyin-mashida:preflight -- --public-url https://<域名> --secret <真密钥> +4. 皮肤领取页两项配置 面板: + claimLinkBase = https://<域名>/claim 皮肤订单领取页基址 + messageTemplate = 您的订单已发货,请点击领取:{link} + ⚠️ claimLinkBase 必须是**路径式**(不要带 #): + #/claim 是打手领取页,配错会把买家带到打手流程 +5. 前置自检 npm run douyin-mashida:preflight -- --public-url https://<域名> --secret <真密钥> 全 ✅ 才能开始 -5. 订阅推送 ★ npm run douyin-mashida:subscribe -- --public-url https://<域名> +6. 订阅推送 ★ npm run douyin-mashida:subscribe -- --public-url https://<域名> (不做这步平台一条消息都不会推,见 §2) -6. 平台侧下一笔小额真单 → 日志看: +7. 平台侧下一笔小额真单 → 日志看: POST /api/v1/open/douyin-mashida/message 收到推送 [douyin-mashida/certificate] 券码已同步 syncV2 成功 -7. 手机打开 cert_link 走一遍兑换(首次要过 ngrok 警示页)→ 本地看到 verifyV3 + order.message -8. 对账 orders / order_items / redeem_certificates 三张表 + fulfillment_tasks / claim_tokens 已建任务与领取 token +8. 手机打开买家领取链接 https://<域名>/claim/(首次要过 ngrok 警示页) + → 看到物品图片 → 填游戏账号 → 领取 → 本地看到 verifyV3 +9. 对账 orders / order_items / redeem_certificates / fulfillment_tasks 四张表 ``` ### 必须实测的 7 个点 diff --git a/docs/抖音-码速达/09-皮肤领取流程.md b/docs/抖音-码速达/09-皮肤领取流程.md new file mode 100644 index 00000000..8390db32 --- /dev/null +++ b/docs/抖音-码速达/09-皮肤领取流程.md @@ -0,0 +1,94 @@ +# 09 - 皮肤自动发货:买家领取流程 + +> 本文档描述抖音码速达**皮肤类商品**的交付改造:从「固定兑换链接 + 用户输订单号」 +> 改为「每单一条领取链接 + 买家填游戏账号领取」。 +> 代码位置:`apps/backend/src/services/{fulfillment,claim}/`、`apps/backend/src/services/platforms/douyin-mashida/`、 +> `apps/frontend/src/pages/claim-skin/`。 + +## 1. 为什么要改 + +旧流程(`https://<域名>/redeem`,见文档 07)有三个毛病: + +| 问题 | 说明 | +| --- | --- | +| 不认人 | 链接是**同一个**,谁拿到都能打开;靠买家手输订单号来"认领" | +| 多一步 | 买家要先去抖店订单里复制 19 位订单号,再回到页面粘贴 | +| 不合规风险 | 任何人输入别人的订单号都能看到脱敏摘要(虽无手机号,但没必要暴露) | + +新流程:**一个订单一条链接**,链接自带 token,打开就知道是谁的单,直接领。 + +## 2. 新流程 + +```text +买家付款 + └─ 平台推送 trade_TradePaid → 建单 + order_items + └─ 按【内部 SKU】分流 + ├─ 命中 AFFILIATE_DASH_SKU_MAPPING(皮肤/礼包类)→ 自动发货 + │ ├─ 建履约任务(皮肤执行器,requires_claim) + │ ├─ 生成 claim token → 领取链接 = claimLinkBase + '/' + token + │ ├─ coupons.syncV2:cert_link = 该订单的领取链接(买家在抖店卡券里点开直达) + │ └─ order.message:按 messageTemplate 把链接推给买家 + └─ 未命中 → manual_dispatch(接单平台/人工) +``` + +买家侧: + +```text +打开 https://<域名>/claim/ ← 路径式,没有 #(与打手领取页 #/claim 分开) + ├─ 展示:物品图片 + 内部 SKU + 数量 + 订单号 + 商品标题 + ├─ token 失效 → 友好提示,不展示表单 + ├─ 待领取 → 填「游戏账号 / 角色ID」→ 二次确认 → 领取 + └─ 领取成功 → 保存账号到任务 + 调 coupons.verifyV3 核销平台券 → 成功态 +``` + +## 3. 为什么链接必须是**路径式** + +仓库里已经有一个 `#/claim/{token}` 页面,那是**打手**用的(要走游戏 UID 绑定、领取身份校验那一套)。 +皮肤买家链接如果用 hash 形式,买家会被带进打手流程。 + +因此: + +- 买家页走**独立 BrowserRouter 分支**(照 `/redeem` 的做法,见 `apps/frontend/src/App.tsx`) +- 后端拼链接**只**用抖音配置的 `claimLinkBase`,**不要**经过 `buildClaimUrl()` + (后者读全局 `orders.claimBaseUrl`,默认值是 hash 形式 `…/#/claim`) +- 后台面板对 `claimLinkBase` 里出现 `#` 的情况会直接报错提示 + +## 4. 商品图怎么来 + +图片按 affiliate_dash 的**英文 sku** 命名,放在前端 `apps/frontend/public/images/products/`(Vite publicDir,原样对外): + +```text +内部 SKU(平台 sku_order_list[].code) 英文 sku(= 图片文件名) +幸运币2个 → lucky_coin_x2.webp +套装-浪漫天命 → suit_romantic_destiny.webp +``` + +映射复用**已有**的权威表 `services/platforms/affiliate-dash/sku-mapping.ts`(`AFFILIATE_DASH_SKU_MAPPING`), +由 `product-image.ts` 的 `resolveProductImageUrl()` 输出 `/images/products/<英文sku>.webp`。 +映射不到返回空串,前端显示占位图(不猜、不拼不存在的文件)。 + +单测里有一条**守卫**:映射表每个 sku 都必须有对应图片文件,新增商品漏图会直接测试失败。 + +## 5. 配置项(后台「抖音码速达接入配置」面板) + +| 字段 | 作用 | 留空/关闭时 | +| --- | --- | --- | +| `claimLinkBase` | 皮肤订单领取页基址,如 `https://<域名>/claim` | 回退到通用 `certLink` | +| `messageTemplate` | 付款后发给买家的领取消息,支持 `{link}` `{sku}` `{orderNo}` `{productTitle}` | 用默认文案 | +| `claimMessageEnabled` | 是否在付款后发领取消息 | 关闭则只把链接写进卡券 | +| `certLink` | **通用兜底**兑换链接(非皮肤订单、或解析不出领取链接时用) | — | + +## 6. 兼容性 + +- 旧订单的卡券里已经写死了旧链接,**永远指向 `/redeem`**(收不回来)→ 旧页面**保留可用**,不删。 +- 新订单才会走领取链接;`certLink` 继续作为兜底,非皮肤订单行为完全不变。 +- 买家游戏账号存在 `fulfillment_tasks.claim_submission_json`: + **不写** `work_orders.material_json`(那是发给打手的工单素材,写进去等于泄露买家隐私)。 + +## 7. 下一步(尚未实现) + +领取成功后任务停在「已领取」,真正把物品发到买家账号仍需要履约: + +- 皮肤类是否全自动发放(对接发货平台/卡密),还是先出一张人工工单; +- 失败/退款场景要能 `coupons.cancelVerify` 冲正并把链接置回可用; +- 接单平台类订单的领取链接沿用同一套 token + 页面,还是另有形态。