chore: 以本地为准,上传全部并替换 GitHub
This commit is contained in:
326
app/data-market/page.tsx
Normal file
326
app/data-market/page.tsx
Normal file
@@ -0,0 +1,326 @@
|
||||
"use client"
|
||||
|
||||
import { useState, useEffect } from "react"
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Progress } from "@/components/ui/progress"
|
||||
import Link from "next/link"
|
||||
import {
|
||||
Package,
|
||||
Server,
|
||||
Webhook,
|
||||
ArrowUpRight,
|
||||
TrendingUp,
|
||||
Users,
|
||||
Zap,
|
||||
DollarSign,
|
||||
Loader2,
|
||||
Diamond,
|
||||
Award,
|
||||
Medal,
|
||||
Shield,
|
||||
Target,
|
||||
BarChart3,
|
||||
Globe,
|
||||
ArrowDownToLine,
|
||||
ArrowUpFromLine,
|
||||
} from "lucide-react"
|
||||
|
||||
export default function DataMarketPage() {
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [pools, setPools] = useState<any[]>([])
|
||||
const [stats, setStats] = useState({
|
||||
totalPackages: 0,
|
||||
totalApis: 8,
|
||||
totalSubscriptions: 45,
|
||||
monthlyRevenue: 125000,
|
||||
apiCalls: 8956234
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
loadData()
|
||||
}, [])
|
||||
|
||||
const loadData = async () => {
|
||||
setLoading(true)
|
||||
try {
|
||||
const res = await fetch('/api/traffic-packages?action=pools')
|
||||
const data = await res.json()
|
||||
if (data.success) {
|
||||
setPools(data.pools)
|
||||
setStats(prev => ({
|
||||
...prev,
|
||||
totalPackages: data.pools.length
|
||||
}))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载失败:', error)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const formatNumber = (num: number): string => {
|
||||
if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`
|
||||
if (num >= 1000) return `${(num / 1000).toFixed(0)}K`
|
||||
return num.toLocaleString()
|
||||
}
|
||||
|
||||
// 流量池图标映射
|
||||
const poolIcons: Record<string, any> = {
|
||||
diamond: Diamond,
|
||||
gold: Award,
|
||||
silver: Medal,
|
||||
bronze: Shield,
|
||||
potential: Target
|
||||
}
|
||||
|
||||
// 流量池颜色映射
|
||||
const poolColors: Record<string, string> = {
|
||||
diamond: 'from-purple-500 to-pink-500',
|
||||
gold: 'from-yellow-500 to-orange-500',
|
||||
silver: 'from-gray-400 to-gray-500',
|
||||
bronze: 'from-orange-400 to-orange-600',
|
||||
potential: 'from-blue-400 to-cyan-500'
|
||||
}
|
||||
|
||||
const modules = [
|
||||
{
|
||||
title: "流量包",
|
||||
icon: Package,
|
||||
color: "text-purple-600",
|
||||
bg: "bg-purple-100",
|
||||
href: "/data-market/packages",
|
||||
desc: "用户人群包创建与导出,按流量池分层管理",
|
||||
stats: `${pools.length}个流量池`,
|
||||
},
|
||||
{
|
||||
title: "API市场",
|
||||
icon: Server,
|
||||
color: "text-blue-600",
|
||||
bg: "bg-blue-100",
|
||||
href: "/data-market/api",
|
||||
desc: "开放API接口服务,支持用户查询、画像等",
|
||||
stats: `${stats.totalApis}个API`,
|
||||
},
|
||||
{
|
||||
title: "开放接口",
|
||||
icon: Globe,
|
||||
color: "text-orange-600",
|
||||
bg: "bg-orange-100",
|
||||
href: "/data-market/open-api",
|
||||
desc: "第三方系统对接,存客宝/点了码数据流入流出",
|
||||
stats: "3个接入方",
|
||||
},
|
||||
{
|
||||
title: "数据订阅",
|
||||
icon: Webhook,
|
||||
color: "text-green-600",
|
||||
bg: "bg-green-100",
|
||||
href: "/data-market/subscription",
|
||||
desc: "实时数据推送服务,支持Webhook订阅",
|
||||
stats: `${stats.totalSubscriptions}个订阅`,
|
||||
},
|
||||
]
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50/30 to-purple-50/20 flex items-center justify-center">
|
||||
<Loader2 className="h-8 w-8 animate-spin text-blue-500" />
|
||||
<span className="ml-3 text-gray-500">加载数据市场...</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50/30 to-purple-50/20">
|
||||
<div className="p-6 space-y-6">
|
||||
{/* 顶部标题 */}
|
||||
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-gray-900">数据市场</h1>
|
||||
<p className="text-sm text-gray-500 mt-1">
|
||||
用户数据资产变现与开放服务平台
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 统计概览 */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||
<Card className="bg-white/80 backdrop-blur border-0 shadow-sm">
|
||||
<CardContent className="p-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm text-gray-500">流量池</p>
|
||||
<p className="text-2xl font-bold text-gray-900">{pools.length}</p>
|
||||
</div>
|
||||
<div className="w-12 h-12 rounded-xl bg-purple-100 flex items-center justify-center">
|
||||
<Package className="h-6 w-6 text-purple-600" />
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="bg-white/80 backdrop-blur border-0 shadow-sm">
|
||||
<CardContent className="p-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm text-gray-500">API接口</p>
|
||||
<p className="text-2xl font-bold text-gray-900">{stats.totalApis}</p>
|
||||
</div>
|
||||
<div className="w-12 h-12 rounded-xl bg-blue-100 flex items-center justify-center">
|
||||
<Server className="h-6 w-6 text-blue-600" />
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="bg-white/80 backdrop-blur border-0 shadow-sm">
|
||||
<CardContent className="p-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm text-gray-500">API调用</p>
|
||||
<p className="text-2xl font-bold text-gray-900">{formatNumber(stats.apiCalls)}</p>
|
||||
</div>
|
||||
<div className="w-12 h-12 rounded-xl bg-green-100 flex items-center justify-center">
|
||||
<Zap className="h-6 w-6 text-green-600" />
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="bg-white/80 backdrop-blur border-0 shadow-sm">
|
||||
<CardContent className="p-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm text-gray-500">月收入</p>
|
||||
<p className="text-2xl font-bold text-gray-900">¥{formatNumber(stats.monthlyRevenue)}</p>
|
||||
</div>
|
||||
<div className="w-12 h-12 rounded-xl bg-orange-100 flex items-center justify-center">
|
||||
<DollarSign className="h-6 w-6 text-orange-600" />
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* 功能模块 */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{modules.map((module, index) => (
|
||||
<Link key={index} href={module.href}>
|
||||
<Card className="h-full cursor-pointer hover:shadow-lg transition-all duration-300 border-none shadow-sm bg-white/70 backdrop-blur group hover:-translate-y-1">
|
||||
<CardContent className="p-6">
|
||||
<div className={`w-14 h-14 rounded-2xl ${module.bg} flex items-center justify-center mb-4 group-hover:scale-110 transition-transform`}>
|
||||
<module.icon className={`w-7 h-7 ${module.color}`} />
|
||||
</div>
|
||||
<h3 className="text-lg font-bold text-gray-900 mb-2">{module.title}</h3>
|
||||
<p className="text-sm text-gray-500 mb-4">{module.desc}</p>
|
||||
<div className="flex items-center justify-between">
|
||||
<Badge variant="secondary">{module.stats}</Badge>
|
||||
<ArrowUpRight className="w-5 h-5 text-gray-400 group-hover:text-blue-500 transition-colors" />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* 流量池资产 */}
|
||||
<Card className="border-none shadow-lg bg-white/80 backdrop-blur">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Target className="h-5 w-5 text-purple-500" />
|
||||
可变现数据资产
|
||||
<Badge variant="outline" className="ml-2">按价值分层</Badge>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-1 md:grid-cols-5 gap-4">
|
||||
{pools.map((pool) => {
|
||||
const PoolIcon = poolIcons[pool.id] || Package
|
||||
const color = poolColors[pool.id] || 'from-gray-400 to-gray-500'
|
||||
|
||||
return (
|
||||
<Link key={pool.id} href={`/data-market/packages?pool=${pool.id}`}>
|
||||
<Card className="cursor-pointer hover:shadow-lg transition-all duration-300 border-0 overflow-hidden group">
|
||||
<div className={`h-2 bg-gradient-to-r ${color}`} />
|
||||
<CardContent className="p-4">
|
||||
<div className={`w-12 h-12 rounded-xl bg-gradient-to-r ${color} flex items-center justify-center mb-3 group-hover:scale-110 transition-transform`}>
|
||||
<PoolIcon className="h-6 w-6 text-white" />
|
||||
</div>
|
||||
<h3 className="font-bold text-gray-900 mb-1">{pool.name}</h3>
|
||||
<div className="flex items-center justify-between mt-3">
|
||||
<span className="text-xl font-bold text-gray-900">
|
||||
{formatNumber(pool.count || 0)}
|
||||
</span>
|
||||
<span className="text-xs text-gray-500">用户</span>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 数据变现趋势 */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<Card className="border-none shadow-md bg-white/80">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-sm font-medium flex items-center gap-2">
|
||||
<TrendingUp className="h-4 w-4 text-green-500" />
|
||||
API调用趋势
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-3">
|
||||
{[
|
||||
{ name: '用户画像API', calls: 3500000, growth: 12.5 },
|
||||
{ name: '智能搜索API', calls: 2800000, growth: 8.3 },
|
||||
{ name: '人群圈选API', calls: 1500000, growth: 25.6 },
|
||||
{ name: 'RFM评分API', calls: 1156234, growth: 15.2 },
|
||||
].map((api, i) => (
|
||||
<div key={i} className="flex items-center justify-between p-3 rounded-lg bg-gray-50">
|
||||
<div>
|
||||
<div className="font-medium text-gray-900">{api.name}</div>
|
||||
<div className="text-sm text-gray-500">{formatNumber(api.calls)} 次调用</div>
|
||||
</div>
|
||||
<Badge className="bg-green-100 text-green-700">
|
||||
+{api.growth}%
|
||||
</Badge>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-none shadow-md bg-white/80">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-sm font-medium flex items-center gap-2">
|
||||
<BarChart3 className="h-4 w-4 text-blue-500" />
|
||||
数据订阅分布
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
{[
|
||||
{ name: '用户行为数据', percentage: 35 },
|
||||
{ name: '交易数据', percentage: 28 },
|
||||
{ name: '标签更新', percentage: 22 },
|
||||
{ name: '用户画像变更', percentage: 15 },
|
||||
].map((sub, i) => (
|
||||
<div key={i}>
|
||||
<div className="flex items-center justify-between mb-1">
|
||||
<span className="text-sm text-gray-700">{sub.name}</span>
|
||||
<span className="text-sm font-medium">{sub.percentage}%</span>
|
||||
</div>
|
||||
<Progress value={sub.percentage} className="h-2" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user