feat(claim-skin): 买家皮肤领取页(路径式 /claim/<token>)

买家从卡券/订单消息里的链接打开,看到物品图片与信息,填游戏账号即可领取。

- **路径式无 `#`**:新增独立 BrowserRouter 分支(照 `/redeem` 的做法),
  `isClaimSkinPath` 只认 `/claim/<token>` 两段精确匹配;
  打手领取页仍是主站 HashRouter 的 `#/claim/:token`(其 pathname 为 `/`),两者互不影响
- **物品卡片**:商品图(映射不到或加载失败都降级为占位块,不出现破图)、
  内部 SKU、数量 ×N、订单号、引流标题(灰色副信息)
- **领取表单**:按接口下发的 `claimFields` 动态渲染(游戏账号/角色ID),
  提交前二次确认让买家核对账号
- **状态**:待领取展示表单;已领取展示成功态(优先于 tokenStatus);
  token 失效/过期/关闭/已用分别给中文提示与联系客服引导
- 纯函数抽到 `utils/claim-skin.ts` 并补 20 个单测(路由判定、状态映射、字段校验、格式化)
This commit is contained in:
yml2213
2026-10-09 15:06:56 +08:00
parent b70741daec
commit eacca11768
9 changed files with 1214 additions and 0 deletions
+17
View File
@@ -0,0 +1,17 @@
import { apiGet, apiPost } from '@/lib/http'
import type { ClaimSkinDetail, ClaimSkinSubmitResult } from '@/types/claim-skin'
/**
* 买家侧「皮肤领取页」接口封装(路径式公开链接,无需登录态)。
*
* token 来自路径 `/claim/<token>`,这里统一 `encodeURIComponent`,
* 避免 token 里出现 `/`、`?`、`#` 等字符时拼出错误路径。
*/
export function fetchClaimSkinDetail(token: string) {
return apiGet<ClaimSkinDetail>(`/api/v1/claim-skin/${encodeURIComponent(token)}`)
}
/** 提交游戏账号领取。后端返回统一错误结构时由 http 拦截器抛错。 */
export function submitClaimSkin(token: string, payload: { gameAccount: string }) {
return apiPost<ClaimSkinSubmitResult>(`/api/v1/claim-skin/${encodeURIComponent(token)}`, payload)
}