Redesign navigation, home overview, user portrait, and valuation pages with improved functionality and responsive design. Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
180 lines
7.5 KiB
TypeScript
180 lines
7.5 KiB
TypeScript
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
|
import { formatNumber, getGrowthClass } from "@/lib/utils"
|
|
import { ArrowDown, ArrowUp } from "lucide-react"
|
|
|
|
export function DashboardOverview() {
|
|
// 这里应该从API获取实际数据
|
|
const overviewData = {
|
|
userAcquisition: {
|
|
total: 12458,
|
|
growth: 12.5,
|
|
sources: [
|
|
{ name: "微信", value: 4523, growth: 15.2 },
|
|
{ name: "抖音", value: 3254, growth: 24.3 },
|
|
{ name: "小红书", value: 2145, growth: 8.7 },
|
|
{ name: "公众号", value: 1536, growth: -3.2 },
|
|
{ name: "官网", value: 1000, growth: 5.6 },
|
|
],
|
|
},
|
|
userRetention: {
|
|
rate: 68.5,
|
|
growth: 2.3,
|
|
periods: [
|
|
{ name: "7天", value: 85.2, growth: 1.2 },
|
|
{ name: "30天", value: 68.5, growth: 2.3 },
|
|
{ name: "90天", value: 42.3, growth: 3.5 },
|
|
{ name: "180天", value: 28.7, growth: -1.2 },
|
|
{ name: "365天", value: 15.4, growth: -2.5 },
|
|
],
|
|
},
|
|
userConversion: {
|
|
rate: 12.5,
|
|
growth: 3.2,
|
|
stages: [
|
|
{ name: "浏览", value: 100, growth: 0 },
|
|
{ name: "注册", value: 35.2, growth: 2.1 },
|
|
{ name: "首次购买", value: 12.5, growth: 3.2 },
|
|
{ name: "复购", value: 8.3, growth: 5.4 },
|
|
{ name: "会员", value: 4.2, growth: 1.8 },
|
|
],
|
|
},
|
|
}
|
|
|
|
return (
|
|
<Tabs defaultValue="acquisition" className="w-full">
|
|
<TabsList className="grid w-full grid-cols-3">
|
|
<TabsTrigger value="acquisition">用户获取</TabsTrigger>
|
|
<TabsTrigger value="retention">用户留存</TabsTrigger>
|
|
<TabsTrigger value="conversion">用户转化</TabsTrigger>
|
|
</TabsList>
|
|
<TabsContent value="acquisition">
|
|
<Card className="border shadow-sm">
|
|
<CardHeader>
|
|
<CardTitle>用户获取分析</CardTitle>
|
|
<CardDescription>各渠道用户获取情况及增长趋势</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-4">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<p className="text-sm font-medium">总获取用户</p>
|
|
<p className="text-2xl font-bold">{formatNumber(overviewData.userAcquisition.total)}</p>
|
|
</div>
|
|
<div className={`flex items-center ${getGrowthClass(overviewData.userAcquisition.growth)}`}>
|
|
{overviewData.userAcquisition.growth > 0 ? (
|
|
<ArrowUp className="h-4 w-4 mr-1" />
|
|
) : (
|
|
<ArrowDown className="h-4 w-4 mr-1" />
|
|
)}
|
|
<span>{Math.abs(overviewData.userAcquisition.growth)}%</span>
|
|
</div>
|
|
</div>
|
|
<div className="space-y-2">
|
|
{overviewData.userAcquisition.sources.map((source) => (
|
|
<div key={source.name} className="flex items-center justify-between">
|
|
<div className="flex items-center">
|
|
<span className="text-sm">{source.name}</span>
|
|
</div>
|
|
<div className="flex items-center space-x-2">
|
|
<span className="text-sm">{formatNumber(source.value)}</span>
|
|
<span className={`text-xs ${getGrowthClass(source.growth)}`}>
|
|
{source.growth > 0 ? "+" : ""}
|
|
{source.growth}%
|
|
</span>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</TabsContent>
|
|
<TabsContent value="retention">
|
|
<Card className="border shadow-sm">
|
|
<CardHeader>
|
|
<CardTitle>用户留存分析</CardTitle>
|
|
<CardDescription>不同时间段的用户留存率及变化趋势</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-4">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<p className="text-sm font-medium">30天留存率</p>
|
|
<p className="text-2xl font-bold">{overviewData.userRetention.rate}%</p>
|
|
</div>
|
|
<div className={`flex items-center ${getGrowthClass(overviewData.userRetention.growth)}`}>
|
|
{overviewData.userRetention.growth > 0 ? (
|
|
<ArrowUp className="h-4 w-4 mr-1" />
|
|
) : (
|
|
<ArrowDown className="h-4 w-4 mr-1" />
|
|
)}
|
|
<span>{Math.abs(overviewData.userRetention.growth)}%</span>
|
|
</div>
|
|
</div>
|
|
<div className="space-y-2">
|
|
{overviewData.userRetention.periods.map((period) => (
|
|
<div key={period.name} className="flex items-center justify-between">
|
|
<div className="flex items-center">
|
|
<span className="text-sm">{period.name}</span>
|
|
</div>
|
|
<div className="flex items-center space-x-2">
|
|
<span className="text-sm">{period.value}%</span>
|
|
<span className={`text-xs ${getGrowthClass(period.growth)}`}>
|
|
{period.growth > 0 ? "+" : ""}
|
|
{period.growth}%
|
|
</span>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</TabsContent>
|
|
<TabsContent value="conversion">
|
|
<Card className="border shadow-sm">
|
|
<CardHeader>
|
|
<CardTitle>用户转化分析</CardTitle>
|
|
<CardDescription>用户转化漏斗各阶段转化率及变化趋势</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-4">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<p className="text-sm font-medium">首次购买转化率</p>
|
|
<p className="text-2xl font-bold">{overviewData.userConversion.rate}%</p>
|
|
</div>
|
|
<div className={`flex items-center ${getGrowthClass(overviewData.userConversion.growth)}`}>
|
|
{overviewData.userConversion.growth > 0 ? (
|
|
<ArrowUp className="h-4 w-4 mr-1" />
|
|
) : (
|
|
<ArrowDown className="h-4 w-4 mr-1" />
|
|
)}
|
|
<span>{Math.abs(overviewData.userConversion.growth)}%</span>
|
|
</div>
|
|
</div>
|
|
<div className="space-y-2">
|
|
{overviewData.userConversion.stages.map((stage) => (
|
|
<div key={stage.name} className="flex items-center justify-between">
|
|
<div className="flex items-center">
|
|
<span className="text-sm">{stage.name}</span>
|
|
</div>
|
|
<div className="flex items-center space-x-2">
|
|
<span className="text-sm">{stage.value}%</span>
|
|
<span className={`text-xs ${getGrowthClass(stage.growth)}`}>
|
|
{stage.growth > 0 ? "+" : ""}
|
|
{stage.growth}%
|
|
</span>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</TabsContent>
|
|
</Tabs>
|
|
)
|
|
}
|