refactor: overhaul UI for streamlined user experience

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>
This commit is contained in:
v0
2025-07-18 13:47:12 +00:00
parent 440b310c6f
commit 2408d50cb0
316 changed files with 55785 additions and 0 deletions

364
app/traffic-pool/page.tsx Normal file
View File

@@ -0,0 +1,364 @@
"use client"
import { useState } from "react"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Badge } from "@/components/ui/badge"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import { Search, Filter, Plus, Users, ArrowRight, BarChart } from "lucide-react"
export default function TrafficPoolPage() {
const [selectedCategory, setSelectedCategory] = useState("all")
const [searchQuery, setSearchQuery] = useState("")
// 模拟场景分类数据
const categories = [
{ id: "all", name: "所有场景" },
{ id: "user-assets", name: "用户资产" },
{ id: "street-vendor", name: "地摊相关" },
{ id: "fandeng", name: "樊登读书" },
{ id: "wow", name: "魔兽世界" },
{ id: "other", name: "其他场景" },
]
// 模拟流量池数据
const pools = [
{
id: "1",
name: "私域池",
description: "已转化为私域用户的高价值流量池",
userCount: 12500,
categories: ["用户资产", "樊登读书"],
conversionRate: 32,
status: "active",
growth: "+15%",
},
{
id: "2",
name: "公域池",
description: "尚未转化的公域流量用户池",
userCount: 45600,
categories: ["地摊相关"],
conversionRate: 8,
status: "active",
growth: "+23%",
},
{
id: "3",
name: "游戏池",
description: "游戏相关用户的流量池",
userCount: 28900,
categories: ["魔兽世界"],
conversionRate: 15,
status: "active",
growth: "+8%",
},
{
id: "4",
name: "休眠池",
description: "长期未活跃的休眠用户池",
userCount: 9800,
categories: ["用户资产", "地摊相关", "樊登读书", "魔兽世界"],
conversionRate: 3,
status: "inactive",
growth: "-5%",
},
]
// 过滤流量池
const filteredPools = pools.filter((pool) => {
const matchesSearch =
pool.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
pool.description.toLowerCase().includes(searchQuery.toLowerCase())
const matchesCategory =
selectedCategory === "all" ||
pool.categories.some((cat) => {
const categoryObj = categories.find((c) => c.name === cat)
return categoryObj && categoryObj.id === selectedCategory
})
return matchesSearch && matchesCategory
})
// 模拟用户数据
const poolUsers = [
{ id: "1", name: "张三", source: "微信", joinDate: "2023-05-15", category: "用户资产", value: "高" },
{ id: "2", name: "李四", source: "抖音", joinDate: "2023-04-10", category: "地摊相关", value: "中" },
{ id: "3", name: "王五", source: "小红书", joinDate: "2023-03-05", category: "樊登读书", value: "低" },
{ id: "4", name: "赵六", source: "官网", joinDate: "2023-02-20", category: "魔兽世界", value: "高" },
{ id: "5", name: "钱七", source: "微信", joinDate: "2023-01-15", category: "用户资产", value: "中" },
]
return (
<div className="container mx-auto py-6 space-y-8">
<div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
<div>
<h1 className="text-3xl font-bold tracking-tight"></h1>
<p className="text-muted-foreground"></p>
</div>
<div className="flex gap-2">
<Button>
<Plus className="mr-2 h-4 w-4" />
</Button>
</div>
</div>
<div className="flex flex-col md:flex-row gap-4 items-center">
<div className="relative w-full md:max-w-sm">
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
<Input
type="search"
placeholder="搜索流量池..."
className="pl-8"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
</div>
<Select value={selectedCategory} onValueChange={setSelectedCategory}>
<SelectTrigger className="w-full md:w-[180px]">
<SelectValue placeholder="选择场景分类" />
</SelectTrigger>
<SelectContent>
{categories.map((category) => (
<SelectItem key={category.id} value={category.id}>
{category.name}
</SelectItem>
))}
</SelectContent>
</Select>
<Button variant="outline" size="icon" className="ml-auto">
<Filter className="h-4 w-4" />
</Button>
</div>
<Tabs defaultValue="grid" className="w-full">
<TabsList className="grid w-full max-w-md grid-cols-3">
<TabsTrigger value="grid"></TabsTrigger>
<TabsTrigger value="list"></TabsTrigger>
<TabsTrigger value="analytics"></TabsTrigger>
</TabsList>
<TabsContent value="grid" className="space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{filteredPools.map((pool) => (
<Card key={pool.id} className={`${pool.status === "inactive" ? "border-dashed opacity-70" : ""}`}>
<CardHeader className="pb-2">
<div className="flex justify-between items-start">
<div>
<CardTitle>{pool.name}</CardTitle>
<CardDescription>{pool.description}</CardDescription>
</div>
<Badge
className={pool.status === "active" ? "bg-green-100 text-green-800" : "bg-gray-100 text-gray-800"}
>
{pool.status === "active" ? "活跃" : "休眠"}
</Badge>
</div>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div className="flex justify-between items-center">
<div className="flex items-center">
<Users className="h-4 w-4 mr-2 text-muted-foreground" />
<span className="text-sm font-medium"></span>
</div>
<div className="flex items-center">
<span className="font-bold">{pool.userCount.toLocaleString()}</span>
<span
className={`text-xs ml-2 ${pool.growth.startsWith("+") ? "text-green-600" : "text-red-600"}`}
>
{pool.growth}
</span>
</div>
</div>
<div className="flex justify-between items-center">
<div className="flex items-center">
<ArrowRight className="h-4 w-4 mr-2 text-muted-foreground" />
<span className="text-sm font-medium"></span>
</div>
<span className="font-bold">{pool.conversionRate}%</span>
</div>
<div>
<span className="text-sm font-medium"></span>
<div className="flex flex-wrap gap-2 mt-2">
{pool.categories.map((category, index) => (
<Badge key={index} variant="outline" className="bg-blue-50">
{category}
</Badge>
))}
</div>
</div>
<div className="pt-4 flex justify-end gap-2">
<Button variant="outline" size="sm">
</Button>
<Button size="sm"></Button>
</div>
</div>
</CardContent>
</Card>
))}
</div>
</TabsContent>
<TabsContent value="list" className="space-y-6">
<Card>
<CardContent className="p-0">
<Table>
<TableHeader>
<TableRow>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead className="text-right"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{filteredPools.map((pool) => (
<TableRow key={pool.id}>
<TableCell>
<div>
<p className="font-medium">{pool.name}</p>
<p className="text-sm text-muted-foreground">{pool.description}</p>
</div>
</TableCell>
<TableCell>
<div className="flex items-center">
<span>{pool.userCount.toLocaleString()}</span>
<span
className={`text-xs ml-2 ${pool.growth.startsWith("+") ? "text-green-600" : "text-red-600"}`}
>
{pool.growth}
</span>
</div>
</TableCell>
<TableCell>{pool.conversionRate}%</TableCell>
<TableCell>
<div className="flex flex-wrap gap-1">
{pool.categories.map((category, index) => (
<Badge key={index} variant="outline" className="bg-blue-50">
{category}
</Badge>
))}
</div>
</TableCell>
<TableCell>
<Badge
className={
pool.status === "active" ? "bg-green-100 text-green-800" : "bg-gray-100 text-gray-800"
}
>
{pool.status === "active" ? "活跃" : "休眠"}
</Badge>
</TableCell>
<TableCell className="text-right">
<div className="flex justify-end gap-2">
<Button variant="outline" size="sm">
</Button>
<Button size="sm"></Button>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
</TabsContent>
<TabsContent value="analytics" className="space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent className="h-80 flex items-center justify-center">
<div className="text-center text-muted-foreground flex flex-col items-center">
<BarChart className="h-10 w-10 mb-2" />
<p></p>
</div>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent className="h-80 flex items-center justify-center">
<div className="text-center text-muted-foreground flex flex-col items-center">
<BarChart className="h-10 w-10 mb-2" />
<p></p>
</div>
</CardContent>
</Card>
</div>
</TabsContent>
</Tabs>
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent>
<Table>
<TableHeader>
<TableRow>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead className="text-right"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{poolUsers.map((user) => (
<TableRow key={user.id}>
<TableCell className="font-medium">{user.name}</TableCell>
<TableCell>{user.source}</TableCell>
<TableCell>{user.joinDate}</TableCell>
<TableCell>
<Badge variant="outline" className="bg-blue-50">
{user.category}
</Badge>
</TableCell>
<TableCell>
<Badge
className={
user.value === "高"
? "bg-green-100 text-green-800"
: user.value === "中"
? "bg-yellow-100 text-yellow-800"
: "bg-red-100 text-red-800"
}
>
{user.value}
</Badge>
</TableCell>
<TableCell className="text-right">
<Button variant="outline" size="sm">
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
</div>
)
}