"use client" import { useState } from "react" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { Badge } from "@/components/ui/badge" import { Input } from "@/components/ui/input" import { Checkbox } from "@/components/ui/checkbox" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { Label } from "@/components/ui/label" import { Textarea } from "@/components/ui/textarea" import { Package, Plus, Download, Send, Mail, MessageSquare, Users, Calendar, RefreshCw, CheckCircle2, Clock, Target, Loader2, Settings, Trash2, Copy, } from "lucide-react" // 流量包接口 interface TrafficPackage { id: string name: string description: string pool: string userCount: number criteria: string[] createdAt: string status: 'active' | 'expired' | 'processing' downloadCount: number lastSentAt?: string sentTo?: string[] } // 发送目标 interface SendTarget { type: 'email' | 'wechat' | 'feishu' value: string name: string } // 预定义流量包 const DEFAULT_PACKAGES: TrafficPackage[] = [ { id: 'pkg_1', name: '钻石用户包-2024Q1', description: 'RFM≥90的高价值用户,适合高端产品推广', pool: 'diamond', userCount: 12500000, criteria: ['RFM≥90', '月活跃≥20天', '消费≥10次'], createdAt: '2024-01-15', status: 'active', downloadCount: 15, lastSentAt: '2024-01-28', sentTo: ['marketing@company.com', '飞书-营销群'], }, { id: 'pkg_2', name: '厦门本地高价值用户', description: '厦门地区A级以上用户', pool: 'gold', userCount: 850000, criteria: ['地区=厦门', 'RFM≥80'], createdAt: '2024-01-20', status: 'active', downloadCount: 8, }, { id: 'pkg_3', name: '电商活跃用户包', description: '京东、淘宝高频购买用户', pool: 'silver', userCount: 45000000, criteria: ['电商消费≥5次/月', '客单价≥200'], createdAt: '2024-01-22', status: 'active', downloadCount: 22, lastSentAt: '2024-01-29', sentTo: ['sales@company.com'], }, { id: 'pkg_4', name: '沉默用户唤醒包', description: '30天未活跃但曾有高价值行为的用户', pool: 'potential', userCount: 28000000, criteria: ['30天未活跃', '历史RFM≥60'], createdAt: '2024-01-25', status: 'active', downloadCount: 5, }, ] // 预定义发送目标 const SAVED_TARGETS: SendTarget[] = [ { type: 'email', value: 'marketing@company.com', name: '营销部邮箱' }, { type: 'email', value: 'sales@company.com', name: '销售部邮箱' }, { type: 'feishu', value: 'oc_xxx', name: '飞书-营销群' }, { type: 'feishu', value: 'oc_yyy', name: '飞书-运营群' }, { type: 'wechat', value: 'wxid_xxx', name: '企微-客户群' }, ] export default function PackagesPage() { const [packages, setPackages] = useState(DEFAULT_PACKAGES) const [showCreateDialog, setShowCreateDialog] = useState(false) const [showSendDialog, setShowSendDialog] = useState(false) const [selectedPackage, setSelectedPackage] = useState(null) const [sending, setSending] = useState(false) const [selectedTargets, setSelectedTargets] = useState([]) const [customEmail, setCustomEmail] = useState('') const formatNumber = (num: number): string => { if (num >= 1000000000) return `${(num / 1000000000).toFixed(2)}B` if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M` if (num >= 1000) return `${(num / 1000).toFixed(0)}K` return num.toLocaleString() } const getPoolConfig = (pool: string) => { switch (pool) { case 'diamond': return { name: '钻石池', icon: '💎', color: 'from-blue-500 to-purple-600' } case 'gold': return { name: '黄金池', icon: '🏆', color: 'from-yellow-400 to-orange-500' } case 'silver': return { name: '白银池', icon: '🥈', color: 'from-gray-300 to-gray-500' } case 'bronze': return { name: '青铜池', icon: '🥉', color: 'from-orange-300 to-orange-500' } default: return { name: '潜力池', icon: '🌱', color: 'from-green-300 to-green-500' } } } const getTargetIcon = (type: string) => { switch (type) { case 'email': return case 'feishu': return 🪶 case 'wechat': return default: return } } const toggleTarget = (value: string) => { setSelectedTargets(prev => prev.includes(value) ? prev.filter(t => t !== value) : [...prev, value] ) } const openSendDialog = (pkg: TrafficPackage) => { setSelectedPackage(pkg) setSelectedTargets([]) setCustomEmail('') setShowSendDialog(true) } // 下载流量包为CSV const downloadPackage = async (pkg: TrafficPackage) => { try { // 从API获取用户数据 const res = await fetch(`/api/traffic-packages?action=export&packageId=${pkg.id}`) const data = await res.json() if (data.success && data.users) { // 生成CSV内容 const headers = ['手机号', '姓名', '等级', '估值分', '标签'] const rows = data.users.map((u: any) => [ u.phone || '', u.name || '', u.level || '', u.score || '', (u.tags || []).join(';') ]) const csvContent = [ headers.join(','), ...rows.map((r: string[]) => r.join(',')) ].join('\n') // 创建下载链接 const blob = new Blob(['\ufeff' + csvContent], { type: 'text/csv;charset=utf-8' }) const url = URL.createObjectURL(blob) const link = document.createElement('a') link.href = url link.download = `${pkg.name}_${new Date().toISOString().split('T')[0]}.csv` document.body.appendChild(link) link.click() document.body.removeChild(link) URL.revokeObjectURL(url) // 更新下载次数 setPackages(prev => prev.map(p => p.id === pkg.id ? { ...p, downloadCount: p.downloadCount + 1 } : p )) } else { alert('导出失败:' + (data.error || '未知错误')) } } catch (error) { console.error('下载失败:', error) alert('下载失败,请重试') } } const sendPackage = async () => { if (!selectedPackage) return setSending(true) try { // 调用API发送流量包 const targets = [...selectedTargets] if (customEmail) targets.push(customEmail) await fetch('/api/traffic-packages', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'send', packageId: selectedPackage.id, targets, }) }) // 更新包状态 setPackages(packages.map(p => p.id === selectedPackage.id ? { ...p, lastSentAt: new Date().toLocaleString(), sentTo: targets, } : p)) } catch (error) { console.error('发送失败:', error) } finally { setSending(false) setShowSendDialog(false) } } return (
{/* 顶部标题 */}

流量包

管理和分发用户流量包

{/* 统计卡片 */}

流量包总数

{packages.length}

覆盖用户

{formatNumber(packages.reduce((sum, p) => sum + p.userCount, 0))}

总下载次数

{packages.reduce((sum, p) => sum + p.downloadCount, 0)}

本周发送

12

{/* 流量包列表 */}
{packages.map(pkg => { const poolConfig = getPoolConfig(pkg.pool) return (
{poolConfig.icon}

{pkg.name}

可用

{pkg.description}

{pkg.criteria.map((c, i) => ( {c} ))}
{formatNumber(pkg.userCount)} 用户 创建于 {pkg.createdAt} 下载 {pkg.downloadCount} 次 {pkg.lastSentAt && ( 上次发送: {pkg.lastSentAt} )}
) })}
{/* 发送流量包弹窗 */} 发送流量包 选择发送目标,支持邮箱、微信群、飞书群 {selectedPackage && (
{/* 流量包信息 */}
{selectedPackage.name}
{formatNumber(selectedPackage.userCount)} 用户
{/* 已保存的目标 */}
{SAVED_TARGETS.map(target => (
toggleTarget(target.value)} >
{getTargetIcon(target.type)}
{target.name}
{target.value}
))}
{/* 自定义邮箱 */}
setCustomEmail(e.target.value)} />
{/* 发送说明 */}

📌 发送说明:

  • 邮箱发送:将生成CSV附件发送到指定邮箱
  • 飞书群:通过飞书机器人发送流量包链接
  • 微信群:通过企微机器人发送流量包链接
)}
{/* 创建流量包弹窗 */} 创建流量包 从人群圈选创建流量包