refactor: 页面重构

This commit is contained in:
Blizzard
2026-03-30 16:26:42 +08:00
parent a269f8893f
commit 8132edf6c1
20 changed files with 6018 additions and 774 deletions
+26 -21
View File
@@ -19,6 +19,7 @@ import {
Coins
} from 'lucide-react';
import { motion } from 'framer-motion';
import { AnimatedCounter } from '@/components/AnimatedCounter.tsx';
import {
AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend
} from 'recharts';
@@ -40,11 +41,11 @@ import type { RadioChannel } from '@/types/radio.ts';
// ─── Color Palette ───
const COLORS = {
listen: '#D28F4F', // primary (Orange)
sub: '#6A7F6A', // secondary (Green)
renew: '#C86354', // distinct warm red
muted: '#8C7E6C',
chart: ['#D28F4F', '#6A7F6A', '#C86354', '#E8B878', '#8BAE8B'],
listen: '#0f172a', // Slate-900 (primary)
sub: '#3b82f6', // Blue-500
renew: '#10b981', // Emerald-500
muted: '#9ca3af', // Gray-400
chart: ['#0f172a', '#3b82f6', '#10b981', '#f59e0b', '#6366f1'],
};
export default function Dashboard() {
@@ -244,7 +245,7 @@ export default function Dashboard() {
value: vipStats.activeVipUsers,
icon: Crown,
subLabel: '当前生效的尊享会员',
color: '#F59E0B',
color: '#f59e0b',
trend: vipStats.newVipOrders > 0 ? `+${vipStats.newVipOrders} 订单` : undefined,
},
{
@@ -252,7 +253,7 @@ export default function Dashboard() {
value: `¥${(vipStats.vipRevenue / 100).toFixed(2)}`,
icon: Coins,
subLabel: '区间内会员特权变现',
color: '#D28F4F',
color: '#0f172a',
},
];
@@ -265,8 +266,7 @@ export default function Dashboard() {
};
return (
<div className="space-y-8 pb-20 overflow-x-hidden bg-background min-h-screen text-foreground p-6 md:p-10 font-sans relative">
<div className="absolute inset-0 warm-noise" />
<div className="space-y-8 pb-20 overflow-x-hidden min-h-screen text-gray-900 font-sans relative">
{/* ═══ Header ═══ */}
<header className="relative z-10 flex flex-col xl:flex-row xl:items-end justify-between gap-6 pb-6 border-b border-border">
@@ -340,7 +340,7 @@ export default function Dashboard() {
initial={{ opacity: 0, y: 16 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: idx * 0.08 }}
className="bg-card rounded-2xl p-5 border border-border shadow-sm hover:shadow-md transition-all duration-300 flex flex-col gap-3 group"
className="bg-white rounded-[2rem] p-6 border border-gray-100/50 shadow-soft shadow-hover-spring flex flex-col gap-3 group relative overflow-hidden"
>
<div className="flex justify-between items-start">
<p className="text-xs font-semibold text-muted-foreground">{stat.name}</p>
@@ -348,8 +348,13 @@ export default function Dashboard() {
<stat.icon className="w-4 h-4" style={{ color: stat.color }} />
</div>
</div>
<p className="text-2xl md:text-3xl font-bold text-foreground leading-none">
{loading ? '—' : stat.value.toLocaleString()}
<p className="text-2xl md:text-3xl font-bold text-gray-900 leading-none">
{loading ? '—' : (
<AnimatedCounter
value={stat.value}
format={typeof stat.value === 'string' && stat.value.startsWith('¥') ? 'currency' : 'number'}
/>
)}
</p>
<div className="flex justify-between items-center">
<span className="text-[11px] text-muted-foreground">{stat.subLabel}</span>
@@ -372,7 +377,7 @@ export default function Dashboard() {
animate={{ opacity: 1 }}
transition={{ duration: 0.5 }}
>
<div className="bg-card rounded-2xl p-6 border border-border shadow-sm flex flex-col gap-4">
<div className="bg-white rounded-[2rem] p-8 border-glass shadow-soft flex flex-col gap-4">
{/* Chart header */}
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
<div>
@@ -449,7 +454,7 @@ export default function Dashboard() {
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.15 }}
>
<div className="bg-card rounded-2xl p-6 border border-border shadow-sm h-full flex flex-col">
<div className="bg-white rounded-[2rem] p-8 border-glass shadow-soft h-full flex flex-col">
<div className="flex items-center justify-between mb-6 pb-4 border-b border-border">
<h3 className="text-sm font-bold text-foreground"></h3>
<TrendingUp className="w-4 h-4 text-muted-foreground" />
@@ -457,10 +462,10 @@ export default function Dashboard() {
{/* LTV highlight */}
{funnelData && (
<div className="mb-6 rounded-xl bg-primary/10 border border-primary/20 p-4 text-center">
<p className="text-xs text-muted-foreground mb-1"> (LTV)</p>
<p className="text-2xl font-bold" style={{ color: COLORS.listen }}>
¥{(funnelData.ltv / 100).toFixed(2)}
<div className="mb-6 rounded-2xl bg-gray-50/50 border border-gray-100 p-5 text-center shadow-inner group transition-all duration-300 hover:bg-white hover:shadow-soft">
<p className="text-xs text-gray-500 mb-2 transition-colors group-hover:text-gray-900"> (LTV)</p>
<p className="text-3xl font-black" style={{ color: COLORS.listen }}>
<AnimatedCounter value={funnelData.ltv / 100} format="currency" />
</p>
</div>
)}
@@ -481,10 +486,10 @@ export default function Dashboard() {
<span className="text-xs font-bold text-foreground">{step.label}</span>
</div>
<div className="flex items-center gap-2">
<span className="text-sm font-bold text-foreground">{step.value.toLocaleString()}</span>
<span className="text-sm font-bold text-gray-900"><AnimatedCounter value={step.value}/></span>
{convRate && (
<span className="text-[10px] font-semibold text-muted-foreground bg-muted px-1.5 py-0.5 rounded">
{convRate}%
<span className="text-[10px] font-semibold text-gray-500 bg-gray-50 px-2 py-0.5 rounded-full border border-gray-100">
<AnimatedCounter value={convRate} format="percent" />
</span>
)}
</div>