refactor(claim): 删除自建皮肤领取页,路径式 /claim/<token> 复用现成领取页 + 物品图片

**删掉上一轮自建的领取页**
- `pages/claim-skin/*`、`services/claim-skin.ts`、`types/claim-skin.ts`、`tests/claim-skin.test.ts`
  及其样式(client.css 里 `.claim-skin-*` 整段 254 行)
- 后台我加的展示项:「皮肤自动发货」筛选项、执行器标签、「买家提交信息」卡片

**路径式链接复用现成领取页**
- `utils/claim-path.ts`(中性命名 `isClaimPath` / `resolveClaimToken`)+ 单测
- `App.tsx`:pathname 命中 `/claim/<token>` → 独立 BrowserRouter 渲染**现成的 `ClaimPage`**
  (页面零复制零改动:它只用 `useParams`,不读 hash);`#/claim/:token` 仍走主站 HashRouter,
  两者互不影响,且有用例断言 hash 入口不命中路径判定

**物品图片**
- 后端领取详情的 `product.imageUrl` 接上(内部 SKU 在 `spec_json.code` / `sku_code` /
  `sku_name` 哪个字段都能回退找到图,映射不到返回空串)
- 领取页新增 `ClaimProductImage`:居中大图(宽度 min(220px,62%)、圆角 16px),
  空值或加载失败都降级虚线占位块,不出现破图

`npm run check`:前端 128 / 128 全绿(去掉旧用例 17 个、新增路径与图片用例)
This commit is contained in:
yml2213
2026-10-09 16:13:46 +08:00
parent 4fce07a621
commit 1339c6887e
17 changed files with 171 additions and 1236 deletions
+25 -254
View File
@@ -434,6 +434,31 @@
background: rgba(248, 250, 252, 0.72);
}
/* 待领取物品图:居中大图;imageUrl 为空或加载失败时是同一尺寸的虚线占位块(不会出现破图) */
.claim-product-image-wrap {
display: flex;
justify-content: center;
}
.claim-product-image {
width: min(220px, 62%);
aspect-ratio: 1 / 1;
border-radius: 16px;
object-fit: cover;
background: #f1f5f9;
border: 1px solid rgba(148, 163, 184, 0.24);
}
.claim-product-image-fallback {
display: flex;
align-items: center;
justify-content: center;
font-size: 46px;
color: rgba(100, 116, 139, 0.55);
border-style: dashed;
}
/* ===== 收集页 (Collect Page) ===== */
.collect-page {
@@ -472,260 +497,6 @@
margin-bottom: 0;
}
/* ===== 买家皮肤领取页 (Skin Claim Page) =====
路径式入口 `/claim/<token>`:按竞品的深色玻璃质感卡片做,
但主按钮沿用仓库主题色 `--theme-primary`(橙色渐变),与 /redeem 的主色保持协调。
所有覆盖都挂在 `.claim-skin-page` 下,保证优先级高于 antd 的运行时样式。 */
.claim-skin-page {
min-height: 100vh;
display: flex;
justify-content: center;
padding: 28px 16px 40px;
background: radial-gradient(120% 70% at 50% 0%, #27334f 0%, #141b2d 52%, #0b1020 100%);
color: #e2e8f0;
}
.claim-skin-shell {
width: min(480px, 100%);
display: flex;
flex-direction: column;
gap: 14px;
}
.claim-skin-head {
text-align: center;
}
.claim-skin-page .claim-skin-title {
margin: 0 !important;
color: #f8fafc;
font-size: 22px;
letter-spacing: 0.5px;
}
.claim-skin-subtitle {
margin: 8px 0 0;
color: rgba(226, 232, 240, 0.72);
font-size: 13px;
line-height: 1.6;
}
.claim-skin-page .claim-skin-card {
border: 1px solid rgba(148, 163, 184, 0.22);
border-radius: 16px;
background: rgba(15, 23, 42, 0.66);
box-shadow: 0 18px 40px rgba(2, 6, 23, 0.45);
backdrop-filter: blur(12px);
}
.claim-skin-card .ant-card-body {
display: flex;
flex-direction: column;
gap: 14px;
padding: 20px 18px;
}
/* --- 物品卡片 --- */
.claim-skin-item-image-wrap {
display: flex;
justify-content: center;
}
.claim-skin-item-image {
width: 160px;
height: 160px;
border-radius: 16px;
object-fit: cover;
background: rgba(148, 163, 184, 0.12);
border: 1px solid rgba(148, 163, 184, 0.24);
}
.claim-skin-item-image-fallback {
display: flex;
align-items: center;
justify-content: center;
font-size: 46px;
color: rgba(148, 163, 184, 0.55);
border-style: dashed;
}
.claim-skin-item-name {
display: flex;
align-items: baseline;
justify-content: center;
gap: 8px;
color: #f1f5f9;
font-size: 19px;
font-weight: 700;
line-height: 1.4;
text-align: center;
overflow-wrap: anywhere;
}
.claim-skin-item-qty {
flex: 0 0 auto;
color: #ffb27a;
font-size: 16px;
}
.claim-skin-item-meta {
margin: 0;
color: rgba(148, 163, 184, 0.92);
font-size: 12px;
line-height: 1.6;
text-align: center;
overflow-wrap: anywhere;
}
.claim-skin-item-meta-sub {
color: rgba(148, 163, 184, 0.62);
font-size: 11px;
}
/* --- 表单卡片 --- */
.claim-skin-page .claim-skin-form-title {
margin: 0 !important;
color: #f8fafc;
font-size: 16px;
}
.claim-skin-form-card .ant-form {
display: flex;
flex-direction: column;
gap: 12px;
}
.claim-skin-form-card .ant-form-item {
margin-bottom: 0;
}
.claim-skin-form-card .ant-form-item-label > label {
color: rgba(226, 232, 240, 0.86);
font-size: 14px;
font-weight: 600;
}
.claim-skin-field .ant-input {
background: rgba(8, 13, 26, 0.6);
border-color: rgba(148, 163, 184, 0.3);
color: #f1f5f9;
}
.claim-skin-field .ant-input::placeholder {
color: rgba(148, 163, 184, 0.62);
}
.claim-skin-field .ant-input-affix-wrapper {
background: rgba(8, 13, 26, 0.6);
border-color: rgba(148, 163, 184, 0.3);
}
.claim-skin-field .ant-input-affix-wrapper > input.ant-input {
background: transparent;
}
.claim-skin-field .ant-input-affix-wrapper .anticon {
color: rgba(148, 163, 184, 0.72);
}
.claim-skin-form-hint {
margin: 0;
color: rgba(253, 186, 116, 0.9);
font-size: 12px;
line-height: 1.6;
}
.claim-skin-page .claim-skin-submit.ant-btn {
height: 48px;
border: none;
border-radius: 14px;
font-size: 16px;
font-weight: 700;
background: linear-gradient(135deg, #ff8a3d 0%, var(--theme-primary) 100%);
box-shadow: 0 12px 24px var(--theme-primary-shadow);
}
.claim-skin-page .claim-skin-submit.ant-btn:hover:not(:disabled) {
background: linear-gradient(135deg, #ff9a55 0%, var(--theme-primary-hover) 100%);
}
.claim-skin-page .claim-skin-submit.ant-btn:disabled {
opacity: 0.6;
}
/* --- 提示 / 成功态 --- */
.claim-skin-state .ant-result {
padding: 8px 0 0;
}
.claim-skin-state .ant-result-title {
color: #f8fafc;
font-size: 19px;
}
.claim-skin-state .ant-result-subtitle {
color: rgba(226, 232, 240, 0.72);
font-size: 13px;
line-height: 1.6;
}
.claim-skin-state-desc {
margin: 0;
color: rgba(226, 232, 240, 0.72);
font-size: 13px;
line-height: 1.6;
text-align: center;
}
.claim-skin-contact-tip {
margin: 0;
color: rgba(253, 186, 116, 0.9);
font-size: 12px;
line-height: 1.6;
text-align: center;
}
.claim-skin-account-line {
display: grid;
gap: 4px;
padding: 12px;
border-radius: 12px;
background: rgba(8, 13, 26, 0.55);
border: 1px solid rgba(148, 163, 184, 0.22);
text-align: center;
}
.claim-skin-account-line span {
color: rgba(148, 163, 184, 0.9);
font-size: 12px;
}
.claim-skin-account-line strong {
color: #f8fafc;
font-size: 18px;
overflow-wrap: anywhere;
}
@media (max-width: 480px) {
.claim-skin-page {
padding: 18px 12px 32px;
}
.claim-skin-card .ant-card-body {
gap: 12px;
padding: 16px 14px;
}
.claim-skin-item-image {
width: 140px;
height: 140px;
}
}
/* ===== 买家页面响应式断点 ===== */
@media (max-width: 720px) {