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:
@@ -472,6 +472,260 @@
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user