Reorganize navigation and module structure based on new requirements. Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
240 lines
9.0 KiB
TypeScript
240 lines
9.0 KiB
TypeScript
"use client"
|
|
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
|
import { Badge } from "@/components/ui/badge"
|
|
import { Button } from "@/components/ui/button"
|
|
import { Users, Tag, Download, RefreshCw, TrendingUp } from 'lucide-react'
|
|
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, RadarChart, PolarGrid, PolarAngleAxis, PolarRadiusAxis, Radar } from 'recharts'
|
|
|
|
export default function UserProfiling() {
|
|
const ageDistribution = [
|
|
{ range: '18-25', count: 856780, percentage: 20 },
|
|
{ range: '26-35', count: 1500000, percentage: 35 },
|
|
{ range: '36-45', count: 1285670, percentage: 30 },
|
|
{ range: '46-55', count: 428567, percentage: 10 },
|
|
{ range: '55+', count: 214284, percentage: 5 },
|
|
]
|
|
|
|
const behaviorProfile = [
|
|
{ aspect: '消费能力', value: 85 },
|
|
{ aspect: '活跃度', value: 72 },
|
|
{ aspect: '互动频率', value: 68 },
|
|
{ aspect: '忠诚度', value: 78 },
|
|
{ aspect: '推荐意愿', value: 62 },
|
|
{ aspect: '复购率', value: 75 },
|
|
]
|
|
|
|
const segments = [
|
|
{
|
|
name: '高净值群体',
|
|
count: 1284567,
|
|
characteristics: ['消费能力强', '忠诚度高', '品牌认知强'],
|
|
value: 580,
|
|
color: 'purple'
|
|
},
|
|
{
|
|
name: '年轻潮流族',
|
|
count: 2856780,
|
|
characteristics: ['追求时尚', '社交活跃', '冲动消费'],
|
|
value: 280,
|
|
color: 'blue'
|
|
},
|
|
{
|
|
name: '理性消费者',
|
|
count: 4285670,
|
|
characteristics: ['价格敏感', '重视品质', '对比研究'],
|
|
value: 180,
|
|
color: 'green'
|
|
},
|
|
{
|
|
name: '价格敏感型',
|
|
count: 1714283,
|
|
characteristics: ['促销驱动', '低频复购', '优惠敏感'],
|
|
value: 85,
|
|
color: 'yellow'
|
|
},
|
|
]
|
|
|
|
const interestTags = [
|
|
{ tag: '美妆护肤', count: 2856780, heat: 95 },
|
|
{ tag: '时尚穿搭', count: 2145680, heat: 88 },
|
|
{ tag: '健康养生', count: 1856780, heat: 76 },
|
|
{ tag: '数码科技', count: 1428567, heat: 72 },
|
|
{ tag: '母婴育儿', count: 1285670, heat: 68 },
|
|
{ tag: '美食烹饪', count: 985670, heat: 58 },
|
|
{ tag: '运动健身', count: 856780, heat: 52 },
|
|
{ tag: '旅游出行', count: 714283, heat: 45 },
|
|
]
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gray-50 p-6">
|
|
<div className="mb-8 flex items-center justify-between">
|
|
<div>
|
|
<h1 className="text-4xl font-bold text-gray-900 mb-2">用户画像</h1>
|
|
<p className="text-gray-600">智能分析用户群体特征与行为偏好</p>
|
|
</div>
|
|
<div className="flex items-center gap-4">
|
|
<Button variant="outline">
|
|
<RefreshCw className="w-4 h-4 mr-2" />
|
|
重新分析
|
|
</Button>
|
|
<Button>
|
|
<Download className="w-4 h-4 mr-2" />
|
|
导出画像
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 核心指标 */}
|
|
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6 mb-6">
|
|
<Card>
|
|
<CardHeader className="pb-3">
|
|
<CardTitle className="text-sm text-gray-600">用户群体数</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-3xl font-bold text-gray-900 mb-1">128</div>
|
|
<div className="text-sm text-gray-600">覆盖42.8亿用户</div>
|
|
</CardContent>
|
|
</Card>
|
|
<Card>
|
|
<CardHeader className="pb-3">
|
|
<CardTitle className="text-sm text-gray-600">标签覆盖率</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-3xl font-bold text-gray-900 mb-1">87.5%</div>
|
|
<Badge variant="outline" className="border-green-500 text-green-600 bg-green-50">优秀</Badge>
|
|
</CardContent>
|
|
</Card>
|
|
<Card>
|
|
<CardHeader className="pb-3">
|
|
<CardTitle className="text-sm text-gray-600">画像完整度</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-3xl font-bold text-gray-900 mb-1">92.3%</div>
|
|
<Badge variant="outline" className="border-blue-500 text-blue-600 bg-blue-50">优秀</Badge>
|
|
</CardContent>
|
|
</Card>
|
|
<Card>
|
|
<CardHeader className="pb-3">
|
|
<CardTitle className="text-sm text-gray-600">更新频率</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-3xl font-bold text-gray-900 mb-1">实时</div>
|
|
<div className="text-sm text-gray-600">每小时更新</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
{/* 年龄分布与行为画像 */}
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="text-gray-900 flex items-center gap-2">
|
|
<Users className="w-5 h-5" />
|
|
年龄分布
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<ResponsiveContainer width="100%" height={300}>
|
|
<BarChart data={ageDistribution}>
|
|
<CartesianGrid strokeDasharray="3 3" stroke="#e5e7eb" />
|
|
<XAxis dataKey="range" stroke="#6b7280" />
|
|
<YAxis stroke="#6b7280" />
|
|
<Tooltip />
|
|
<Bar dataKey="count" fill="#8b5cf6" name="用户数" />
|
|
</BarChart>
|
|
</ResponsiveContainer>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="text-gray-900 flex items-center gap-2">
|
|
<TrendingUp className="w-5 h-5" />
|
|
行为画像
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<ResponsiveContainer width="100%" height={300}>
|
|
<RadarChart data={behaviorProfile}>
|
|
<PolarGrid stroke="#e5e7eb" />
|
|
<PolarAngleAxis dataKey="aspect" stroke="#6b7280" />
|
|
<PolarRadiusAxis stroke="#6b7280" />
|
|
<Radar name="行为指数" dataKey="value" stroke="#8b5cf6" fill="#8b5cf6" fillOpacity={0.5} />
|
|
<Tooltip />
|
|
</RadarChart>
|
|
</ResponsiveContainer>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
{/* 用户群体细分 */}
|
|
<Card className="mb-6">
|
|
<CardHeader>
|
|
<CardTitle className="text-gray-900 flex items-center gap-2">
|
|
<Users className="w-5 h-5" />
|
|
用户群体细分
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
|
{segments.map((segment, index) => (
|
|
<div key={index} className={`p-6 bg-gradient-to-br from-${segment.color}-50 to-${segment.color}-100 rounded-lg border border-${segment.color}-200`}>
|
|
<div className="flex items-center justify-between mb-4">
|
|
<h3 className="text-xl font-bold text-gray-900">{segment.name}</h3>
|
|
<Badge variant="outline" className={`border-${segment.color}-500 text-${segment.color}-600 bg-${segment.color}-50`}>
|
|
{segment.count.toLocaleString()} 人
|
|
</Badge>
|
|
</div>
|
|
<div className="space-y-2 mb-4">
|
|
{segment.characteristics.map((char, i) => (
|
|
<Badge key={i} variant="outline" className="mr-2 border-gray-300 text-gray-700">
|
|
{char}
|
|
</Badge>
|
|
))}
|
|
</div>
|
|
<div className="text-sm text-gray-600">
|
|
人均价值: <span className="text-lg font-semibold text-gray-900">¥{segment.value}</span>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* 兴趣标签热度 */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="text-gray-900 flex items-center gap-2">
|
|
<Tag className="w-5 h-5" />
|
|
兴趣标签热度
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-3">
|
|
{interestTags.map((item, index) => (
|
|
<div key={index} className="flex items-center gap-4">
|
|
<div className="flex-1">
|
|
<div className="flex items-center justify-between mb-2">
|
|
<span className="text-gray-700 font-medium">{item.tag}</span>
|
|
<div className="flex items-center gap-4">
|
|
<span className="text-sm text-gray-600">{item.count.toLocaleString()} 人</span>
|
|
<span className="text-sm font-semibold text-blue-600">热度 {item.heat}</span>
|
|
</div>
|
|
</div>
|
|
<div className="h-2 bg-gray-200 rounded-full overflow-hidden">
|
|
<div
|
|
className="h-full bg-gradient-to-r from-blue-500 to-purple-500 rounded-full"
|
|
style={{ width: `${item.heat}%` }}
|
|
></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
)
|
|
}
|