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:
@@ -11,6 +11,7 @@ import {
|
||||
} from 'react-router'
|
||||
|
||||
import { getAdminRole, hasAdminSession } from '@/utils/admin-auth'
|
||||
import { isClaimSkinPath } from '@/utils/claim-skin'
|
||||
import { isRedeemPath } from '@/utils/redeem'
|
||||
import { isWorkerSite, WORKER_SITE_ORIGIN } from '@/utils/site'
|
||||
import { hasWorkerSession } from '@/utils/worker-auth'
|
||||
@@ -35,6 +36,7 @@ const AdminUsersPage = lazy(() => import('@/pages/admin/AdminUsersPage'))
|
||||
const AdminDevMockPage = lazy(() => import('@/pages/admin/AdminDevMockPage'))
|
||||
const AdminWorkerPlatformPage = lazy(() => import('@/pages/admin/AdminWorkerPlatformPage'))
|
||||
const ClaimPage = lazy(() => import('@/pages/claim/ClaimPage'))
|
||||
const ClaimSkinPage = lazy(() => import('@/pages/claim-skin/ClaimSkinPage'))
|
||||
const CollectPage = lazy(() => import('@/pages/collect/CollectPage'))
|
||||
const NotFoundPage = lazy(() => import('@/pages/NotFoundPage'))
|
||||
const RedeemPage = lazy(() => import('@/pages/redeem/RedeemPage'))
|
||||
@@ -90,6 +92,14 @@ export default function App() {
|
||||
return <WorkerSiteRedirect path={legacyWorkerPath} />
|
||||
}
|
||||
|
||||
// 买家皮肤领取页是路径式(`https://<域名>/claim/<token>`,不带 `#`),必须早于站点判断,
|
||||
// 用独立的 BrowserRouter 分支承载,主站 HashRouter 不受影响。
|
||||
// 注意:打手领取页仍是主站 HashRouter 里的 `#/claim/:token`,它的 pathname 是 `/`,
|
||||
// 不会命中这里(判定见 utils/claim-skin.isClaimSkinPath),两者互不影响。
|
||||
if (isClaimSkinPath(window.location.pathname)) {
|
||||
return <ClaimSkinApplication />
|
||||
}
|
||||
|
||||
// 固定兑换链接是路径式(`https://<域名>/redeem`,不带 `#`),必须早于站点判断,
|
||||
// 用独立的 BrowserRouter 分支承载,主站 HashRouter 不受影响。
|
||||
if (isRedeemPath(window.location.pathname)) {
|
||||
@@ -158,6 +168,25 @@ function RedeemApplication() {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 路径式皮肤领取页(`/claim/<token>`)的独立路由树。
|
||||
*
|
||||
* 只在 `isClaimSkinPath` 命中时才会挂载,所以这里的兜底路由正常走不到;
|
||||
* 真走到也复用同一个页面(token 为空时页面自己展示「链接无效」),不会出现路由空屏。
|
||||
*/
|
||||
function ClaimSkinApplication() {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<Suspense fallback={<RouteLoading />}>
|
||||
<Routes>
|
||||
<Route path="/claim/:token" element={<ClaimSkinPage />} />
|
||||
<Route path="*" element={<ClaimSkinPage />} />
|
||||
</Routes>
|
||||
</Suspense>
|
||||
</BrowserRouter>
|
||||
)
|
||||
}
|
||||
|
||||
function WorkerApplication() {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
|
||||
Reference in New Issue
Block a user