chore(points): fix lint - apps/web/src/pages/points/Center.tsx
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Has been cancelled
CI/CD Pipeline / Check if frontend-only change (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Style (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 4h38m57s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 4h38m4s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Failing after 4h38m3s
CI/CD Pipeline / Check push changed paths (pull_request) Failing after 4h38m5s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 4h38m4s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Has been cancelled
CI/CD Pipeline / Check if frontend-only change (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Style (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 4h38m57s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 4h38m4s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Failing after 4h38m3s
CI/CD Pipeline / Check push changed paths (pull_request) Failing after 4h38m5s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 4h38m4s
This commit is contained in:
@@ -1,154 +1,351 @@
|
||||
/**
|
||||
* 积分中心首页
|
||||
* 展示:
|
||||
* - 当前积分余额 + 会员状态(来自 balance + membership)
|
||||
* - 每日免费额度(来自 dailyUsage)
|
||||
* - 快捷入口(充值 / 消费记录 / 订阅)
|
||||
* 积分中心主页(/points 或 /app/points)
|
||||
* 展示余额、会员信息、免费额度、快捷入口、最近流水
|
||||
*
|
||||
* 字段对齐新契约(2026-09-16):
|
||||
* - balance 不含 free_clips_*,从 dailyUsage 取
|
||||
* - subscription.member_type → plan_id(free/monthly/quarterly/yearly)
|
||||
* - subscription.member_type_name → 前端 PLAN_LABEL 映射
|
||||
*/
|
||||
import React, { useEffect } from "react"
|
||||
import { Card, Button, Space, Statistic, Tag, Progress, Alert } from "antd"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
import {
|
||||
Card,
|
||||
Col,
|
||||
Row,
|
||||
Statistic,
|
||||
Button,
|
||||
Space,
|
||||
Tag,
|
||||
Typography,
|
||||
Progress,
|
||||
List,
|
||||
Avatar,
|
||||
Empty,
|
||||
} from "antd"
|
||||
import {
|
||||
ThunderboltOutlined,
|
||||
CrownOutlined,
|
||||
CrownFilled,
|
||||
ArrowUpOutlined,
|
||||
ArrowDownOutlined,
|
||||
HistoryOutlined,
|
||||
PlusCircleOutlined,
|
||||
GiftOutlined,
|
||||
WalletOutlined,
|
||||
FileTextOutlined,
|
||||
InfoCircleOutlined,
|
||||
} from "@ant-design/icons"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
import PageHead from "@/components/layout/PageHead"
|
||||
import { usePointsStore } from "@/store/pointsStore"
|
||||
import styles from "./Points.css"
|
||||
import { PLAN_LABEL } from "@/api/subscription/types"
|
||||
import "./Points.css"
|
||||
|
||||
const MEMBER_LABEL: Record<string, string> = {
|
||||
monthly: "月卡会员",
|
||||
quarterly: "季卡会员",
|
||||
yearly: "年卡会员",
|
||||
const { Text } = Typography
|
||||
|
||||
const SOURCE_NAME: Record<string, string> = {
|
||||
recharge: "充值",
|
||||
task_reward: "任务奖励",
|
||||
ai_voice: "AI 配音",
|
||||
ai_digital_human: "AI 数字人",
|
||||
ai_video: "智能混剪",
|
||||
voice_clone_train: "声音克隆训练",
|
||||
voice_clone_synth: "声音克隆合成",
|
||||
douyin_extract: "抖音提取",
|
||||
ai_rewrite: "AI 改写",
|
||||
ai_title: "AI 标题",
|
||||
ai_cover: "AI 封面",
|
||||
sign_up: "注册赠送",
|
||||
bind_phone: "绑定手机",
|
||||
gift: "活动赠送",
|
||||
admin: "管理员调整",
|
||||
}
|
||||
|
||||
const PointsCenterPage: React.FC = () => {
|
||||
const sourceLabel = (src: string): string => {
|
||||
if (src.startsWith("refund:")) return `${SOURCE_NAME[src.slice(7)] || src.slice(7)}退款`
|
||||
return SOURCE_NAME[src] || src
|
||||
}
|
||||
|
||||
/** 会员标签:优先取 membership.member_type,降级 subscription.plan_id */
|
||||
const memberKey = (
|
||||
membership: { member_type: string | null } | null,
|
||||
subscription: { plan_id: string } | null,
|
||||
): string | null =>
|
||||
membership?.member_type ??
|
||||
(subscription?.plan_id && subscription.plan_id !== "free" ? subscription.plan_id : null)
|
||||
|
||||
const memberLabel = (
|
||||
membership: { member_type: string | null } | null,
|
||||
subscription: { plan_id: string; plan_name?: string } | null,
|
||||
): string => {
|
||||
const key = memberKey(membership, subscription)
|
||||
if (!key) return "免费会员"
|
||||
return PLAN_LABEL[key as keyof typeof PLAN_LABEL] || subscription?.plan_name || "付费会员"
|
||||
}
|
||||
|
||||
const PointsCenter: React.FC = () => {
|
||||
const navigate = useNavigate()
|
||||
const { balance, dailyUsage, membership, subscription, rules, init } = usePointsStore()
|
||||
const { balance, dailyUsage, membership, subscription, rules, init, loading } = usePointsStore()
|
||||
|
||||
useEffect(() => {
|
||||
init()
|
||||
}, [init])
|
||||
|
||||
const bal = membership?.points_balance ?? balance?.balance ?? 0
|
||||
const earned = balance?.total_earned ?? 0
|
||||
const spent = balance?.total_spent ?? 0
|
||||
const isMember = membership?.is_member ?? balance?.is_member ?? false
|
||||
const memberKey =
|
||||
membership?.member_type ??
|
||||
(subscription?.plan_id && subscription.plan_id !== "free" ? subscription.plan_id : null)
|
||||
const memberLabel = memberKey ? MEMBER_LABEL[memberKey] || "" : ""
|
||||
const freeLimit = dailyUsage?.free_clips_limit ?? 0
|
||||
|
||||
// 免费额度从 dailyUsage 取
|
||||
const freeUsed = dailyUsage?.free_clips_used ?? 0
|
||||
const freeLimit = dailyUsage?.free_clips_limit ?? (isMember ? 0 : 3)
|
||||
const freeRemain = dailyUsage?.free_clips_remaining ?? 0
|
||||
const freePercent = freeLimit > 0 ? Math.round((freeUsed / freeLimit) * 100) : 0
|
||||
const freeMultiplier = rules?.free_user_multiplier ?? 1.15
|
||||
|
||||
// 最近流水 mock(后续可改为调用 getPointsTransactions(1,5))
|
||||
const recentTx = [
|
||||
{ type: "deduct" as const, source: "ai_voice", amount: 1, time: "今天 10:30" },
|
||||
{ type: "deduct" as const, source: "ai_video", amount: 3, time: "今天 09:15" },
|
||||
{ type: "add" as const, source: "recharge", amount: 100, time: "昨天" },
|
||||
]
|
||||
|
||||
return (
|
||||
<div className={styles.pointsPage}>
|
||||
<h2 className={styles.pageTitle}>积分中心</h2>
|
||||
|
||||
{/* 余额卡片 */}
|
||||
<Card className={styles.balanceCard}>
|
||||
<div className={styles.balanceMain}>
|
||||
<Statistic
|
||||
title="当前积分"
|
||||
value={membership?.points_balance ?? balance?.balance ?? 0}
|
||||
prefix={<ThunderboltOutlined style={{ color: "#faad14" }} />}
|
||||
valueStyle={{ color: "#faad14", fontSize: 36, fontWeight: 700 }}
|
||||
/>
|
||||
{isMember && memberLabel && (
|
||||
<Tag color="gold" icon={<CrownOutlined />} className={styles.memberTag}>
|
||||
{memberLabel}
|
||||
{membership?.max_resolution ? ` · ${membership.max_resolution}` : ""}
|
||||
</Tag>
|
||||
)}
|
||||
</div>
|
||||
<Space>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<PlusCircleOutlined />}
|
||||
onClick={() => navigate("/points/recharge")}
|
||||
>
|
||||
立即充值
|
||||
</Button>
|
||||
<Button icon={<HistoryOutlined />} onClick={() => navigate("/points/transactions")}>
|
||||
消费记录
|
||||
</Button>
|
||||
<Button icon={<CrownOutlined />} onClick={() => navigate("/subscription")}>
|
||||
{isMember ? "管理订阅" : "开通会员"}
|
||||
</Button>
|
||||
</Space>
|
||||
{balance?.member_expires_at && isMember && (
|
||||
<div className={styles.expireTip}>
|
||||
会员到期时间:{new Date(balance.member_expires_at).toLocaleDateString("zh-CN")}
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
|
||||
{/* 每日免费额度卡片 */}
|
||||
<Card title="🎁 每日免费额度" className={styles.freeCard}>
|
||||
{!isMember && freeLimit > 0 ? (
|
||||
<>
|
||||
<Progress
|
||||
percent={freePercent}
|
||||
strokeColor={{ "0%": "#52c41a", "100%": "#faad14" }}
|
||||
format={() => `${freeUsed}/${freeLimit}`}
|
||||
/>
|
||||
<div className={styles.freeTip}>
|
||||
<GiftOutlined /> 今日还剩 <b>{freeRemain}</b> 次免费生成额度
|
||||
{dailyUsage?.reset_at && (
|
||||
<span className={styles.resetTime}>
|
||||
(
|
||||
{new Date(dailyUsage.reset_at).toLocaleTimeString("zh-CN", {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
})}{" "}
|
||||
重置)
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
) : isMember ? (
|
||||
<Alert
|
||||
type="info"
|
||||
showIcon
|
||||
message="会员享有更高免费额度"
|
||||
description={`每日免费 ${subscription ? "(见会员权益)" : ""}生成次数,积分消耗享折扣`}
|
||||
/>
|
||||
) : (
|
||||
<Alert
|
||||
type="info"
|
||||
showIcon
|
||||
message="暂无可用免费额度"
|
||||
description="充值或开通会员解锁更多权益"
|
||||
/>
|
||||
)}
|
||||
</Card>
|
||||
|
||||
{/* 快捷提示 */}
|
||||
{!isMember && rules && (
|
||||
<Alert
|
||||
type="warning"
|
||||
showIcon
|
||||
message={`非会员积分消耗倍率 ×${freeMultiplier},开通会员可享折扣`}
|
||||
action={
|
||||
<Button size="small" type="primary" onClick={() => navigate("/subscription")}>
|
||||
开通会员
|
||||
<div className="xx-points-page">
|
||||
<PageHead
|
||||
title="积分中心"
|
||||
description="管理积分余额、查看流水、充值使用"
|
||||
actions={
|
||||
<Space>
|
||||
<Button icon={<FileTextOutlined />} onClick={() => navigate("/points/rules")}>
|
||||
积分规则
|
||||
</Button>
|
||||
}
|
||||
style={{ marginTop: 16 }}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<WalletOutlined />}
|
||||
onClick={() => navigate("/points/recharge")}
|
||||
>
|
||||
充值积分
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
/>
|
||||
|
||||
{/* 累计统计 */}
|
||||
<Card title="📊 累计统计" className={styles.statsCard}>
|
||||
<div className={styles.statsGrid}>
|
||||
<Statistic title="累计获得" value={balance?.total_earned ?? 0} suffix="积分" />
|
||||
<Statistic title="累计消耗" value={balance?.total_spent ?? 0} suffix="积分" />
|
||||
</div>
|
||||
{/* 顶部大卡 */}
|
||||
<Card className="xx-points-hero" bordered={false}>
|
||||
<Row gutter={24} align="middle">
|
||||
<Col xs={24} md={14}>
|
||||
<Space direction="vertical" size={8} style={{ width: "100%" }}>
|
||||
<Text type="secondary" style={{ color: "rgba(255,255,255,0.8)" }}>
|
||||
当前可用积分
|
||||
</Text>
|
||||
<div className="xx-points-hero-balance">
|
||||
<ThunderboltOutlined />
|
||||
<span>{loading ? "…" : bal.toLocaleString()}</span>
|
||||
</div>
|
||||
<Space size={8} wrap>
|
||||
{isMember ? (
|
||||
<Tag color="gold" icon={<CrownFilled />} style={{ padding: "4px 10px" }}>
|
||||
{memberLabel(membership, subscription)}
|
||||
</Tag>
|
||||
) : (
|
||||
<Tag
|
||||
style={{
|
||||
padding: "4px 10px",
|
||||
background: "rgba(255,255,255,0.2)",
|
||||
color: "#fff",
|
||||
border: "none",
|
||||
}}
|
||||
>
|
||||
免费会员
|
||||
</Tag>
|
||||
)}
|
||||
{balance?.member_expires_at && isMember && (
|
||||
<Text style={{ color: "rgba(255,255,255,0.85)", fontSize: 12 }}>
|
||||
到期 {new Date(balance.member_expires_at).toLocaleDateString("zh-CN")}
|
||||
</Text>
|
||||
)}
|
||||
{membership?.max_resolution && isMember && (
|
||||
<Text style={{ color: "rgba(255,255,255,0.85)", fontSize: 12 }}>
|
||||
· {membership.max_resolution}
|
||||
</Text>
|
||||
)}
|
||||
{!isMember && (
|
||||
<Button
|
||||
size="small"
|
||||
type="primary"
|
||||
onClick={() => navigate("/subscription")}
|
||||
style={{ background: "#fff", color: "#7c3aed", borderColor: "#fff" }}
|
||||
>
|
||||
<CrownFilled /> 升级会员享折扣
|
||||
</Button>
|
||||
)}
|
||||
</Space>
|
||||
</Space>
|
||||
</Col>
|
||||
<Col xs={24} md={10}>
|
||||
{/* 今日免费额度 */}
|
||||
{!isMember && freeLimit > 0 && (
|
||||
<div className="xx-points-free-quota">
|
||||
<div className="xx-points-free-title">
|
||||
<InfoCircleOutlined /> 今日免费混剪
|
||||
</div>
|
||||
<Progress
|
||||
percent={freeLimit > 0 ? Math.round((freeUsed / freeLimit) * 100) : 0}
|
||||
strokeColor={{ "0%": "#f59e0b", "100%": "#ef4444" }}
|
||||
format={() => `${freeUsed}/${freeLimit} 条`}
|
||||
/>
|
||||
<Text style={{ color: "rgba(255,255,255,0.8)", fontSize: 12 }}>
|
||||
剩余 {freeRemain} 条免费混剪,超出部分消耗积分
|
||||
{rules?.free_user_multiplier ? `(×${rules.free_user_multiplier} 倍率)` : ""}
|
||||
{dailyUsage?.reset_at && (
|
||||
<span>
|
||||
{" "}
|
||||
·{" "}
|
||||
{new Date(dailyUsage.reset_at).toLocaleTimeString("zh-CN", {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
})}
|
||||
重置
|
||||
</span>
|
||||
)}
|
||||
</Text>
|
||||
</div>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
{/* 统计 */}
|
||||
<Row gutter={[16, 16]} style={{ marginTop: 16 }}>
|
||||
<Col xs={12} md={6}>
|
||||
<Card>
|
||||
<Statistic
|
||||
title="累计获得"
|
||||
value={earned}
|
||||
prefix={<ArrowUpOutlined style={{ color: "#10b981" }} />}
|
||||
valueStyle={{ color: "#10b981" }}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={12} md={6}>
|
||||
<Card>
|
||||
<Statistic
|
||||
title="累计消耗"
|
||||
value={spent}
|
||||
prefix={<ArrowDownOutlined style={{ color: "#ef4444" }} />}
|
||||
valueStyle={{ color: "#ef4444" }}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={12} md={6}>
|
||||
<Card>
|
||||
<Statistic
|
||||
title="可用积分"
|
||||
value={bal}
|
||||
prefix={<ThunderboltOutlined style={{ color: "#8b5cf6" }} />}
|
||||
valueStyle={{ color: "#8b5cf6" }}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={12} md={6}>
|
||||
<Card>
|
||||
<Statistic
|
||||
title={isMember ? "会员等级" : "今日免费剩余"}
|
||||
value={isMember ? memberLabel(membership, subscription) : `${freeRemain} 条`}
|
||||
prefix={<CrownFilled style={{ color: "#f59e0b" }} />}
|
||||
valueStyle={{ color: "#f59e0b" }}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{/* 快捷入口 & 最近流水 */}
|
||||
<Row gutter={[16, 16]} style={{ marginTop: 8 }}>
|
||||
<Col xs={24} md={14}>
|
||||
<Card
|
||||
title={
|
||||
<Space>
|
||||
<HistoryOutlined />
|
||||
最近流水
|
||||
</Space>
|
||||
}
|
||||
extra={<a onClick={() => navigate("/points/transactions")}>查看全部 →</a>}
|
||||
>
|
||||
{recentTx.length === 0 ? (
|
||||
<Empty description="暂无积分流水" />
|
||||
) : (
|
||||
<List
|
||||
dataSource={recentTx}
|
||||
renderItem={(item) => (
|
||||
<List.Item>
|
||||
<List.Item.Meta
|
||||
avatar={
|
||||
<Avatar
|
||||
size="small"
|
||||
style={{
|
||||
background: item.type === "add" ? "#d1fae5" : "#fee2e2",
|
||||
color: item.type === "add" ? "#059669" : "#dc2626",
|
||||
}}
|
||||
icon={item.type === "add" ? <ArrowUpOutlined /> : <ArrowDownOutlined />}
|
||||
/>
|
||||
}
|
||||
title={sourceLabel(item.source)}
|
||||
description={item.time}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
color: item.type === "add" ? "#10b981" : "#ef4444",
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
{item.type === "add" ? "+" : "-"}
|
||||
{item.amount}
|
||||
</div>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} md={10}>
|
||||
<Card title="快捷操作">
|
||||
<Space direction="vertical" style={{ width: "100%" }} size={10}>
|
||||
<Button
|
||||
block
|
||||
size="large"
|
||||
type="primary"
|
||||
icon={<WalletOutlined />}
|
||||
onClick={() => navigate("/points/recharge")}
|
||||
>
|
||||
充值积分
|
||||
</Button>
|
||||
<Button
|
||||
block
|
||||
size="large"
|
||||
icon={<HistoryOutlined />}
|
||||
onClick={() => navigate("/points/transactions")}
|
||||
>
|
||||
积分明细
|
||||
</Button>
|
||||
<Button
|
||||
block
|
||||
size="large"
|
||||
icon={<CrownFilled />}
|
||||
onClick={() => navigate("/subscription")}
|
||||
>
|
||||
{isMember ? "续费/升级会员" : "升级付费会员"}
|
||||
</Button>
|
||||
<Button
|
||||
block
|
||||
size="large"
|
||||
icon={<FileTextOutlined />}
|
||||
onClick={() => navigate("/points/rules")}
|
||||
>
|
||||
积分消耗规则
|
||||
</Button>
|
||||
</Space>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PointsCenterPage
|
||||
export default PointsCenter
|
||||
export const Component = PointsCenter
|
||||
|
||||
Reference in New Issue
Block a user