Files
users/app/data-output/packages/page.tsx
v0 1219166526 refactor: overhaul system navigation based on 5 HTML docs
Reorganize modules, add AI Agent smart interaction, include prompt settings, enhance data output with subscriptions, and separate system monitoring.

Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
2026-01-31 04:40:47 +00:00

378 lines
14 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client"
import { useState } from "react"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import { Progress } from "@/components/ui/progress"
import {
Package, Plus, Download, Eye, Trash2, RefreshCw,
Users, Calendar, Tag, Filter, MoreHorizontal, Share2,
CheckCircle2, Clock, AlertCircle
} from "lucide-react"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
const packages = [
{
id: "1",
name: "高价值用户流量包",
description: "CLV评分前20%的活跃用户",
userCount: 15680,
tags: ["高价值", "活跃用户"],
status: "active",
createdAt: "2024-01-10",
lastUpdated: "2024-01-15",
downloadCount: 23,
},
{
id: "2",
name: "潜力用户营销包",
description: "近30天有浏览但未转化的用户",
userCount: 8920,
tags: ["潜力用户", "营销"],
status: "active",
createdAt: "2024-01-08",
lastUpdated: "2024-01-14",
downloadCount: 15,
},
{
id: "3",
name: "流失预警用户包",
description: "预测30天内可能流失的用户",
userCount: 3240,
tags: ["流失预警", "挽回"],
status: "updating",
createdAt: "2024-01-05",
lastUpdated: "2024-01-15",
downloadCount: 8,
},
]
export default function PackagesPage() {
const [showCreateDialog, setShowCreateDialog] = useState(false)
const [showPreviewDialog, setShowPreviewDialog] = useState(false)
const [selectedPackage, setSelectedPackage] = useState<typeof packages[0] | null>(null)
const getStatusBadge = (status: string) => {
switch (status) {
case "active":
return <Badge className="bg-green-100 text-green-700"></Badge>
case "updating":
return <Badge className="bg-blue-100 text-blue-700"></Badge>
case "expired":
return <Badge className="bg-gray-100 text-gray-700"></Badge>
default:
return <Badge variant="secondary"></Badge>
}
}
return (
<div className="space-y-6">
{/* 页面标题 */}
<div className="flex items-center justify-between">
<div>
<h1 className="text-2xl font-bold text-foreground"></h1>
<p className="text-muted-foreground"></p>
</div>
<Button onClick={() => setShowCreateDialog(true)}>
<Plus className="mr-2 h-4 w-4" />
</Button>
</div>
{/* 统计卡片 */}
<div className="grid gap-4 md:grid-cols-4">
<Card>
<CardContent className="pt-6">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-muted-foreground"></p>
<p className="text-2xl font-bold">24</p>
</div>
<Package className="h-8 w-8 text-blue-500" />
</div>
</CardContent>
</Card>
<Card>
<CardContent className="pt-6">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-muted-foreground"></p>
<p className="text-2xl font-bold">156.8K</p>
</div>
<Users className="h-8 w-8 text-green-500" />
</div>
</CardContent>
</Card>
<Card>
<CardContent className="pt-6">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-muted-foreground"></p>
<p className="text-2xl font-bold">89</p>
</div>
<Download className="h-8 w-8 text-purple-500" />
</div>
</CardContent>
</Card>
<Card>
<CardContent className="pt-6">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-muted-foreground"></p>
<p className="text-2xl font-bold">18</p>
</div>
<CheckCircle2 className="h-8 w-8 text-cyan-500" />
</div>
</CardContent>
</Card>
</div>
{/* 流量包列表 */}
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<div>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</div>
<div className="flex items-center gap-2">
<Input placeholder="搜索流量包..." className="w-64" />
<Button variant="outline" size="icon">
<Filter className="h-4 w-4" />
</Button>
</div>
</div>
</CardHeader>
<CardContent>
<Table>
<TableHeader>
<TableRow>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead className="text-right"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{packages.map((pkg) => (
<TableRow key={pkg.id}>
<TableCell>
<div>
<p className="font-medium">{pkg.name}</p>
<p className="text-sm text-muted-foreground">{pkg.description}</p>
</div>
</TableCell>
<TableCell className="font-medium">{pkg.userCount.toLocaleString()}</TableCell>
<TableCell>
<div className="flex gap-1">
{pkg.tags.map((tag) => (
<Badge key={tag} variant="outline" className="text-xs">
{tag}
</Badge>
))}
</div>
</TableCell>
<TableCell>{getStatusBadge(pkg.status)}</TableCell>
<TableCell className="text-muted-foreground">{pkg.lastUpdated}</TableCell>
<TableCell>{pkg.downloadCount}</TableCell>
<TableCell className="text-right">
<div className="flex items-center justify-end gap-1">
<Button
variant="ghost"
size="sm"
onClick={() => {
setSelectedPackage(pkg)
setShowPreviewDialog(true)
}}
>
<Eye className="h-4 w-4" />
</Button>
<Button variant="ghost" size="sm">
<Download className="h-4 w-4" />
</Button>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="sm">
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem>
<RefreshCw className="h-4 w-4 mr-2" />
</DropdownMenuItem>
<DropdownMenuItem>
<Share2 className="h-4 w-4 mr-2" />
</DropdownMenuItem>
<DropdownMenuItem className="text-red-600">
<Trash2 className="h-4 w-4 mr-2" />
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
{/* 创建流量包弹窗 */}
<Dialog open={showCreateDialog} onOpenChange={setShowCreateDialog}>
<DialogContent className="max-w-2xl">
<DialogHeader>
<DialogTitle></DialogTitle>
<DialogDescription></DialogDescription>
</DialogHeader>
<div className="space-y-4">
<div className="space-y-2">
<Label></Label>
<Input placeholder="输入流量包名称" />
</div>
<div className="space-y-2">
<Label></Label>
<Input placeholder="输入流量包描述" />
</div>
<div className="space-y-2">
<Label></Label>
<Card className="p-4">
<div className="space-y-4">
<div className="grid grid-cols-3 gap-4">
<Select>
<SelectTrigger>
<SelectValue placeholder="选择字段" />
</SelectTrigger>
<SelectContent>
<SelectItem value="clv_score">CLV评分</SelectItem>
<SelectItem value="rfm_level">RFM等级</SelectItem>
<SelectItem value="last_active"></SelectItem>
<SelectItem value="purchase_count"></SelectItem>
</SelectContent>
</Select>
<Select>
<SelectTrigger>
<SelectValue placeholder="选择条件" />
</SelectTrigger>
<SelectContent>
<SelectItem value="gt"></SelectItem>
<SelectItem value="lt"></SelectItem>
<SelectItem value="eq"></SelectItem>
<SelectItem value="between"></SelectItem>
</SelectContent>
</Select>
<Input placeholder="输入值" />
</div>
<Button variant="outline" size="sm">
<Plus className="h-4 w-4 mr-1" />
</Button>
</div>
</Card>
</div>
<div className="space-y-2">
<Label></Label>
<Input placeholder="输入标签,用逗号分隔" />
</div>
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setShowCreateDialog(false)}></Button>
<Button>
<Eye className="mr-2 h-4 w-4" />
</Button>
<Button></Button>
</DialogFooter>
</DialogContent>
</Dialog>
{/* 预览弹窗 */}
<Dialog open={showPreviewDialog} onOpenChange={setShowPreviewDialog}>
<DialogContent className="max-w-3xl">
<DialogHeader>
<DialogTitle> - {selectedPackage?.name}</DialogTitle>
<DialogDescription>{selectedPackage?.description}</DialogDescription>
</DialogHeader>
<div className="space-y-4">
<div className="grid grid-cols-3 gap-4">
<Card className="p-4">
<p className="text-sm text-muted-foreground"></p>
<p className="text-2xl font-bold">{selectedPackage?.userCount.toLocaleString()}</p>
</Card>
<Card className="p-4">
<p className="text-sm text-muted-foreground">CLV</p>
<p className="text-2xl font-bold">¥2,580</p>
</Card>
<Card className="p-4">
<p className="text-sm text-muted-foreground"></p>
<p className="text-2xl font-bold">78.5%</p>
</Card>
</div>
<Card>
<CardHeader>
<CardTitle className="text-base"></CardTitle>
</CardHeader>
<CardContent>
<Table>
<TableHeader>
<TableRow>
<TableHead>ID</TableHead>
<TableHead>CLV评分</TableHead>
<TableHead>RFM等级</TableHead>
<TableHead></TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>U****001</TableCell>
<TableCell>92</TableCell>
<TableCell>A</TableCell>
<TableCell>2024-01-15</TableCell>
</TableRow>
<TableRow>
<TableCell>U****002</TableCell>
<TableCell>88</TableCell>
<TableCell>A</TableCell>
<TableCell>2024-01-14</TableCell>
</TableRow>
<TableRow>
<TableCell>U****003</TableCell>
<TableCell>85</TableCell>
<TableCell>B</TableCell>
<TableCell>2024-01-15</TableCell>
</TableRow>
</TableBody>
</Table>
</CardContent>
</Card>
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setShowPreviewDialog(false)}></Button>
<Button>
<Download className="mr-2 h-4 w-4" />
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
)
}