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>
320 lines
14 KiB
TypeScript
320 lines
14 KiB
TypeScript
"use client"
|
|
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
|
import { PieChart, BarChart } from "@/components/charts"
|
|
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"
|
|
import { ChevronDown, ChevronRight } from "lucide-react"
|
|
import { useState } from "react"
|
|
|
|
export function UserProfileOverview() {
|
|
const [openSections, setOpenSections] = useState({
|
|
gender: true,
|
|
age: true,
|
|
occupation: false,
|
|
income: false,
|
|
region: false,
|
|
device: false,
|
|
activity: false,
|
|
interest: false,
|
|
})
|
|
|
|
const toggleSection = (section) => {
|
|
setOpenSections((prev) => ({
|
|
...prev,
|
|
[section]: !prev[section],
|
|
}))
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<div className="flex justify-between items-center">
|
|
<h2 className="text-xl font-semibold">用户画像概览</h2>
|
|
<div className="flex space-x-2">
|
|
<Select defaultValue="7days">
|
|
<SelectTrigger className="w-[180px]">
|
|
<SelectValue placeholder="选择时间范围" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="7days">最近7天</SelectItem>
|
|
<SelectItem value="30days">最近30天</SelectItem>
|
|
<SelectItem value="90days">最近90天</SelectItem>
|
|
<SelectItem value="custom">自定义范围</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<Collapsible open={openSections.gender} onOpenChange={() => toggleSection("gender")}>
|
|
<Card className="border shadow-sm">
|
|
<CardHeader className="pb-2">
|
|
<CollapsibleTrigger className="flex justify-between items-center w-full">
|
|
<CardTitle className="text-base font-medium">用户性别分布</CardTitle>
|
|
{openSections.gender ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
|
|
</CollapsibleTrigger>
|
|
</CardHeader>
|
|
<CollapsibleContent>
|
|
<CardContent>
|
|
<PieChart
|
|
data={{
|
|
labels: ["男性", "女性", "未知"],
|
|
datasets: [
|
|
{
|
|
data: [45, 52, 3],
|
|
backgroundColor: [
|
|
"rgba(59, 130, 246, 0.7)",
|
|
"rgba(236, 72, 153, 0.7)",
|
|
"rgba(156, 163, 175, 0.7)",
|
|
],
|
|
},
|
|
],
|
|
}}
|
|
height={250}
|
|
/>
|
|
</CardContent>
|
|
</CollapsibleContent>
|
|
</Card>
|
|
</Collapsible>
|
|
|
|
<Collapsible open={openSections.age} onOpenChange={() => toggleSection("age")}>
|
|
<Card className="border shadow-sm">
|
|
<CardHeader className="pb-2">
|
|
<CollapsibleTrigger className="flex justify-between items-center w-full">
|
|
<CardTitle className="text-base font-medium">用户年龄分布</CardTitle>
|
|
{openSections.age ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
|
|
</CollapsibleTrigger>
|
|
</CardHeader>
|
|
<CollapsibleContent>
|
|
<CardContent>
|
|
<BarChart
|
|
data={{
|
|
labels: ["18岁以下", "18-24岁", "25-34岁", "35-44岁", "45-54岁", "55岁以上"],
|
|
datasets: [
|
|
{
|
|
label: "用户数量",
|
|
data: [1200, 5400, 8900, 5600, 2800, 620],
|
|
backgroundColor: "rgba(59, 130, 246, 0.7)",
|
|
},
|
|
],
|
|
}}
|
|
height={250}
|
|
/>
|
|
</CardContent>
|
|
</CollapsibleContent>
|
|
</Card>
|
|
</Collapsible>
|
|
</div>
|
|
|
|
<Tabs defaultValue="demographic">
|
|
<TabsList>
|
|
<TabsTrigger value="demographic">人口统计</TabsTrigger>
|
|
<TabsTrigger value="geographic">地理分布</TabsTrigger>
|
|
<TabsTrigger value="behavior">行为特征</TabsTrigger>
|
|
<TabsTrigger value="interest">兴趣爱好</TabsTrigger>
|
|
</TabsList>
|
|
<TabsContent value="demographic" className="space-y-4 pt-4">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<Collapsible open={openSections.occupation} onOpenChange={() => toggleSection("occupation")}>
|
|
<Card className="border shadow-sm">
|
|
<CardHeader className="pb-2">
|
|
<CollapsibleTrigger className="flex justify-between items-center w-full">
|
|
<CardTitle className="text-base font-medium">职业分布</CardTitle>
|
|
{openSections.occupation ? (
|
|
<ChevronDown className="h-4 w-4" />
|
|
) : (
|
|
<ChevronRight className="h-4 w-4" />
|
|
)}
|
|
</CollapsibleTrigger>
|
|
</CardHeader>
|
|
<CollapsibleContent>
|
|
<CardContent>
|
|
<PieChart
|
|
data={{
|
|
labels: ["学生", "企业员工", "自由职业", "企业管理者", "公务员", "其他"],
|
|
datasets: [
|
|
{
|
|
data: [15, 35, 20, 18, 7, 5],
|
|
backgroundColor: [
|
|
"rgba(59, 130, 246, 0.7)",
|
|
"rgba(16, 185, 129, 0.7)",
|
|
"rgba(249, 115, 22, 0.7)",
|
|
"rgba(139, 92, 246, 0.7)",
|
|
"rgba(236, 72, 153, 0.7)",
|
|
"rgba(156, 163, 175, 0.7)",
|
|
],
|
|
},
|
|
],
|
|
}}
|
|
height={250}
|
|
/>
|
|
</CardContent>
|
|
</CollapsibleContent>
|
|
</Card>
|
|
</Collapsible>
|
|
|
|
<Collapsible open={openSections.income} onOpenChange={() => toggleSection("income")}>
|
|
<Card className="border shadow-sm">
|
|
<CardHeader className="pb-2">
|
|
<CollapsibleTrigger className="flex justify-between items-center w-full">
|
|
<CardTitle className="text-base font-medium">收入水平</CardTitle>
|
|
{openSections.income ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
|
|
</CollapsibleTrigger>
|
|
</CardHeader>
|
|
<CollapsibleContent>
|
|
<CardContent>
|
|
<PieChart
|
|
data={{
|
|
labels: ["5千以下", "5千-1万", "1万-2万", "2万-3万", "3万以上"],
|
|
datasets: [
|
|
{
|
|
data: [10, 25, 35, 20, 10],
|
|
backgroundColor: [
|
|
"rgba(59, 130, 246, 0.7)",
|
|
"rgba(16, 185, 129, 0.7)",
|
|
"rgba(249, 115, 22, 0.7)",
|
|
"rgba(139, 92, 246, 0.7)",
|
|
"rgba(236, 72, 153, 0.7)",
|
|
],
|
|
},
|
|
],
|
|
}}
|
|
height={250}
|
|
/>
|
|
</CardContent>
|
|
</CollapsibleContent>
|
|
</Card>
|
|
</Collapsible>
|
|
</div>
|
|
</TabsContent>
|
|
|
|
<TabsContent value="geographic" className="space-y-4 pt-4">
|
|
<Collapsible open={openSections.region} onOpenChange={() => toggleSection("region")}>
|
|
<Card className="border shadow-sm">
|
|
<CardHeader className="pb-2">
|
|
<CollapsibleTrigger className="flex justify-between items-center w-full">
|
|
<CardTitle className="text-base font-medium">地区分布</CardTitle>
|
|
{openSections.region ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
|
|
</CollapsibleTrigger>
|
|
</CardHeader>
|
|
<CollapsibleContent>
|
|
<CardContent>
|
|
<BarChart
|
|
data={{
|
|
labels: ["北京", "上海", "广东", "浙江", "江苏", "四川", "湖北", "福建", "山东", "河南"],
|
|
datasets: [
|
|
{
|
|
label: "用户数量",
|
|
data: [3200, 2800, 4500, 2100, 1900, 1600, 1400, 1200, 1100, 900],
|
|
backgroundColor: "rgba(59, 130, 246, 0.7)",
|
|
},
|
|
],
|
|
}}
|
|
height={300}
|
|
/>
|
|
</CardContent>
|
|
</CollapsibleContent>
|
|
</Card>
|
|
</Collapsible>
|
|
</TabsContent>
|
|
|
|
<TabsContent value="behavior" className="space-y-4 pt-4">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<Collapsible open={openSections.activity} onOpenChange={() => toggleSection("activity")}>
|
|
<Card className="border shadow-sm">
|
|
<CardHeader className="pb-2">
|
|
<CollapsibleTrigger className="flex justify-between items-center w-full">
|
|
<CardTitle className="text-base font-medium">活跃时段</CardTitle>
|
|
{openSections.activity ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
|
|
</CollapsibleTrigger>
|
|
</CardHeader>
|
|
<CollapsibleContent>
|
|
<CardContent>
|
|
<BarChart
|
|
data={{
|
|
labels: ["0-3点", "3-6点", "6-9点", "9-12点", "12-15点", "15-18点", "18-21点", "21-24点"],
|
|
datasets: [
|
|
{
|
|
label: "活跃用户数",
|
|
data: [800, 400, 2500, 5800, 4200, 3800, 7500, 6200],
|
|
backgroundColor: "rgba(59, 130, 246, 0.7)",
|
|
},
|
|
],
|
|
}}
|
|
height={250}
|
|
/>
|
|
</CardContent>
|
|
</CollapsibleContent>
|
|
</Card>
|
|
</Collapsible>
|
|
|
|
<Collapsible open={openSections.device} onOpenChange={() => toggleSection("device")}>
|
|
<Card className="border shadow-sm">
|
|
<CardHeader className="pb-2">
|
|
<CollapsibleTrigger className="flex justify-between items-center w-full">
|
|
<CardTitle className="text-base font-medium">使用设备</CardTitle>
|
|
{openSections.device ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
|
|
</CollapsibleTrigger>
|
|
</CardHeader>
|
|
<CollapsibleContent>
|
|
<CardContent>
|
|
<PieChart
|
|
data={{
|
|
labels: ["iOS", "Android", "Windows", "MacOS", "其他"],
|
|
datasets: [
|
|
{
|
|
data: [42, 45, 8, 4, 1],
|
|
backgroundColor: [
|
|
"rgba(59, 130, 246, 0.7)",
|
|
"rgba(16, 185, 129, 0.7)",
|
|
"rgba(249, 115, 22, 0.7)",
|
|
"rgba(139, 92, 246, 0.7)",
|
|
"rgba(156, 163, 175, 0.7)",
|
|
],
|
|
},
|
|
],
|
|
}}
|
|
height={250}
|
|
/>
|
|
</CardContent>
|
|
</CollapsibleContent>
|
|
</Card>
|
|
</Collapsible>
|
|
</div>
|
|
</TabsContent>
|
|
|
|
<TabsContent value="interest" className="space-y-4 pt-4">
|
|
<Collapsible open={openSections.interest} onOpenChange={() => toggleSection("interest")}>
|
|
<Card className="border shadow-sm">
|
|
<CardHeader className="pb-2">
|
|
<CollapsibleTrigger className="flex justify-between items-center w-full">
|
|
<CardTitle className="text-base font-medium">兴趣标签分布</CardTitle>
|
|
{openSections.interest ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
|
|
</CollapsibleTrigger>
|
|
</CardHeader>
|
|
<CollapsibleContent>
|
|
<CardContent>
|
|
<BarChart
|
|
data={{
|
|
labels: ["科技", "金融", "教育", "旅游", "健康", "美食", "时尚", "体育", "娱乐", "汽车"],
|
|
datasets: [
|
|
{
|
|
label: "用户数量",
|
|
data: [6500, 4800, 3900, 5200, 4100, 6800, 3500, 2900, 5500, 3200],
|
|
backgroundColor: "rgba(59, 130, 246, 0.7)",
|
|
},
|
|
],
|
|
}}
|
|
height={300}
|
|
/>
|
|
</CardContent>
|
|
</CollapsibleContent>
|
|
</Card>
|
|
</Collapsible>
|
|
</TabsContent>
|
|
</Tabs>
|
|
</div>
|
|
)
|
|
}
|