refactor: restructure project into 5 core modules
Organize project by 5 core modules based on requirement docs. Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
This commit is contained in:
222
app/ai-assistant/trend-prediction/page.tsx
Normal file
222
app/ai-assistant/trend-prediction/page.tsx
Normal file
@@ -0,0 +1,222 @@
|
||||
"use client"
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { TrendingUp, TrendingDown, AlertCircle, Download, RefreshCw } from 'lucide-react'
|
||||
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, AreaChart, Area } from 'recharts'
|
||||
|
||||
export default function TrendPrediction() {
|
||||
const userGrowthPrediction = [
|
||||
{ date: '2024-06', actual: 428, predicted: null },
|
||||
{ date: '2024-07', actual: null, predicted: 445 },
|
||||
{ date: '2024-08', actual: null, predicted: 468 },
|
||||
{ date: '2024-09', actual: null, predicted: 495 },
|
||||
{ date: '2024-10', actual: null, predicted: 528 },
|
||||
{ date: '2024-11', actual: null, predicted: 565 },
|
||||
{ date: '2024-12', actual: null, predicted: 608 },
|
||||
]
|
||||
|
||||
const valuePrediction = [
|
||||
{ date: '2024-06', actual: 125.8, predicted: null },
|
||||
{ date: '2024-07', actual: null, predicted: 132.5 },
|
||||
{ date: '2024-08', actual: null, predicted: 141.2 },
|
||||
{ date: '2024-09', actual: null, predicted: 151.8 },
|
||||
{ date: '2024-10', actual: null, predicted: 164.5 },
|
||||
{ date: '2024-11', actual: null, predicted: 179.2 },
|
||||
{ date: '2024-12', actual: null, predicted: 196.5 },
|
||||
]
|
||||
|
||||
const churnRiskData = [
|
||||
{ segment: '高价值用户', risk: 8.5, count: 1285, trend: 'down' },
|
||||
{ segment: 'VIP用户', risk: 12.3, count: 856, trend: 'stable' },
|
||||
{ segment: '活跃用户', risk: 18.6, count: 12856, trend: 'up' },
|
||||
{ segment: '沉默用户', risk: 45.8, count: 28560, trend: 'up' },
|
||||
]
|
||||
|
||||
const opportunityData = [
|
||||
{ name: '新品推广机会', potential: '¥85.6M', probability: 78, timeframe: '未来30天' },
|
||||
{ name: '复购唤醒', potential: '¥56.2M', probability: 65, timeframe: '未来15天' },
|
||||
{ name: '会员升级', potential: '¥38.5M', probability: 82, timeframe: '未来7天' },
|
||||
{ name: '交叉销售', potential: '¥92.8M', probability: 58, timeframe: '未来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 className="bg-gradient-to-br from-blue-50 to-blue-100 border-blue-200">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm text-gray-600">下月预测用户数</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-3xl font-bold text-blue-600 mb-1">445M</div>
|
||||
<div className="text-sm text-gray-600">+3.9% 增长</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="bg-gradient-to-br from-green-50 to-green-100 border-green-200">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm text-gray-600">下月预测价值</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-3xl font-bold text-green-600 mb-1">¥132.5亿</div>
|
||||
<div className="text-sm text-gray-600">+5.3% 增长</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="bg-gradient-to-br from-orange-50 to-orange-100 border-orange-200">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm text-gray-600">流失风险用户</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-3xl font-bold text-orange-600 mb-1">42.5K</div>
|
||||
<div className="text-sm text-gray-600">需重点关注</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="bg-gradient-to-br from-purple-50 to-purple-100 border-purple-200">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm text-gray-600">预测准确率</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-3xl font-bold text-purple-600 mb-1">94.2%</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">
|
||||
<TrendingUp className="w-5 h-5 text-blue-600" />
|
||||
用户增长预测
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ResponsiveContainer width="100%" height={300}>
|
||||
<LineChart data={userGrowthPrediction}>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#e5e7eb" />
|
||||
<XAxis dataKey="date" stroke="#6b7280" />
|
||||
<YAxis stroke="#6b7280" />
|
||||
<Tooltip />
|
||||
<Line type="monotone" dataKey="actual" stroke="#3b82f6" strokeWidth={2} name="实际值" />
|
||||
<Line type="monotone" dataKey="predicted" stroke="#8b5cf6" strokeWidth={2} strokeDasharray="5 5" name="预测值" />
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-gray-900 flex items-center gap-2">
|
||||
<TrendingUp className="w-5 h-5 text-green-600" />
|
||||
资产价值预测
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ResponsiveContainer width="100%" height={300}>
|
||||
<AreaChart data={valuePrediction}>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#e5e7eb" />
|
||||
<XAxis dataKey="date" stroke="#6b7280" />
|
||||
<YAxis stroke="#6b7280" />
|
||||
<Tooltip />
|
||||
<Area type="monotone" dataKey="actual" stroke="#10b981" fill="#10b981" fillOpacity={0.3} name="实际值" />
|
||||
<Area type="monotone" dataKey="predicted" stroke="#8b5cf6" fill="#8b5cf6" fillOpacity={0.2} strokeDasharray="5 5" name="预测值" />
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* 流失风险预警 */}
|
||||
<Card className="mb-6">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-gray-900 flex items-center gap-2">
|
||||
<AlertCircle className="w-5 h-5 text-orange-600" />
|
||||
流失风险预警
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
{churnRiskData.map((item, index) => (
|
||||
<div key={index} className="flex items-center justify-between p-4 bg-gray-50 rounded-lg">
|
||||
<div className="flex items-center gap-4">
|
||||
<div>
|
||||
<div className="text-lg font-semibold text-gray-900">{item.segment}</div>
|
||||
<div className="text-sm text-gray-600">{item.count.toLocaleString()} 用户</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-6">
|
||||
<div className="text-right">
|
||||
<div className="text-2xl font-bold text-orange-600">{item.risk}%</div>
|
||||
<div className="text-xs text-gray-600">流失风险</div>
|
||||
</div>
|
||||
{item.trend === 'down' ? (
|
||||
<TrendingDown className="w-6 h-6 text-green-600" />
|
||||
) : item.trend === 'up' ? (
|
||||
<TrendingUp className="w-6 h-6 text-red-600" />
|
||||
) : (
|
||||
<div className="w-6 h-6 flex items-center justify-center">
|
||||
<div className="w-4 h-0.5 bg-gray-400"></div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 商机预测 */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-gray-900 flex items-center gap-2">
|
||||
<TrendingUp className="w-5 h-5 text-purple-600" />
|
||||
商机预测
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
{opportunityData.map((item, index) => (
|
||||
<div key={index} className="p-4 bg-gradient-to-br from-purple-50 to-pink-50 rounded-lg border border-purple-200">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<h3 className="text-lg font-semibold text-gray-900">{item.name}</h3>
|
||||
<Badge variant="outline" className="border-purple-500 text-purple-600 bg-purple-50">
|
||||
{item.timeframe}
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="flex items-end justify-between">
|
||||
<div>
|
||||
<div className="text-sm text-gray-600 mb-1">预测收益</div>
|
||||
<div className="text-2xl font-bold text-purple-600">{item.potential}</div>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<div className="text-sm text-gray-600 mb-1">成功概率</div>
|
||||
<div className="text-2xl font-bold text-green-600">{item.probability}%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user