"use client" import { useState, useEffect, useRef, useCallback } from "react" import { useRouter } from "next/navigation" import { Card } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { ChevronLeft, Search, RefreshCw, Users, Star, Filter, Smartphone, MessageCircle, User, Layers, X, Clock, Tag, DollarSign, Eye, ChevronDown, ChevronUp, BarChart3, } from "lucide-react" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs" import { useToast } from "@/components/ui/use-toast" import { useDebounce } from "@/hooks/use-debounce" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { Badge } from "@/components/ui/badge" import { Checkbox } from "@/components/ui/checkbox" import { Sheet, SheetContent, SheetHeader, SheetTitle } from "@/components/ui/sheet" import { ScrollArea } from "@/components/ui/scroll-area" import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog" import { Progress } from "@/components/ui/progress" // 保持原有的接口定义... interface Device { id: string name: string status: "online" | "offline" | "busy" battery: number location: string wechatAccounts: number dailyAddLimit: number todayAdded: number } interface WechatAccount { id: string nickname: string wechatId: string avatar: string deviceId: string status: "normal" | "limited" | "blocked" friendCount: number dailyAddLimit: number } interface CustomerService { id: string name: string avatar: string status: "online" | "offline" | "busy" assignedUsers: number } interface TrafficPool { id: string name: string description: string userCount: number tags: string[] createdAt: string } interface RFMScore { recency: number frequency: number monetary: number total: number segment: string priority: "high" | "medium" | "low" } interface UserTag { id: string name: string color: string source: string } interface UserInteraction { id: string type: "message" | "purchase" | "view" | "click" content: string timestamp: string value?: number } interface TrafficUser { id: string avatar: string nickname: string wechatId: string phone: string region: string note: string status: "pending" | "added" | "failed" | "duplicate" addTime: string source: string scenario: string deviceId: string wechatAccountId: string customerServiceId: string poolIds: string[] tags: UserTag[] rfmScore: RFMScore lastInteraction: string totalSpent: number interactionCount: number conversionRate: number isDuplicate: boolean mergedAccounts: string[] addStatus: "not_added" | "adding" | "added" | "failed" interactions: UserInteraction[] } // 保持原有的模拟数据生成函数... const SCENARIOS = [ { id: "poster", name: "海报获客", icon: "🎨" }, { id: "phone", name: "电话获客", icon: "📞" }, { id: "douyin", name: "抖音获客", icon: "🎵" }, { id: "xiaohongshu", name: "小红书获客", icon: "📖" }, { id: "weixinqun", name: "微信群获客", icon: "👥" }, { id: "api", name: "API获客", icon: "🔗" }, { id: "order", name: "订单获客", icon: "📦" }, { id: "payment", name: "付款码获客", icon: "💳" }, ] const RFM_SEGMENTS = { "555": { name: "重要价值客户", color: "bg-gradient-to-r from-red-500 to-pink-500 text-white border-0", icon: "👑", priority: "high", }, "554": { name: "重要保持客户", color: "bg-gradient-to-r from-purple-500 to-indigo-500 text-white border-0", icon: "💎", priority: "high", }, "544": { name: "重要发展客户", color: "bg-gradient-to-r from-blue-500 to-cyan-500 text-white border-0", icon: "🚀", priority: "high", }, "455": { name: "重要挽留客户", color: "bg-gradient-to-r from-orange-500 to-red-500 text-white border-0", icon: "⚠️", priority: "medium", }, "444": { name: "一般价值客户", color: "bg-gradient-to-r from-green-500 to-emerald-500 text-white border-0", icon: "👤", priority: "medium", }, "333": { name: "一般保持客户", color: "bg-gradient-to-r from-yellow-500 to-orange-500 text-white border-0", icon: "📈", priority: "medium", }, "222": { name: "新用户", color: "bg-gradient-to-r from-cyan-500 to-blue-500 text-white border-0", icon: "🌟", priority: "low", }, "111": { name: "流失预警客户", color: "bg-gradient-to-r from-gray-500 to-slate-500 text-white border-0", icon: "😴", priority: "low", }, } // 生成模拟数据的函数保持不变... const generateMockDevices = (): Device[] => { return Array.from({ length: 8 }, (_, i) => ({ id: `device-${i + 1}`, name: `设备${i + 1}`, status: ["online", "offline", "busy"][Math.floor(Math.random() * 3)] as "online" | "offline" | "busy", battery: Math.floor(Math.random() * 100), location: ["北京", "上海", "广州", "深圳"][Math.floor(Math.random() * 4)], wechatAccounts: Math.floor(Math.random() * 5) + 1, dailyAddLimit: Math.random() > 0.5 ? 20 : 10, todayAdded: Math.floor(Math.random() * 15), })) } const generateMockWechatAccounts = (devices: Device[]): WechatAccount[] => { const accounts: WechatAccount[] = [] devices.forEach((device) => { for (let i = 0; i < device.wechatAccounts; i++) { accounts.push({ id: `wx-${device.id}-${i + 1}`, nickname: `微信${device.id.split("-")[1]}-${i + 1}`, wechatId: `wxid_${Math.random().toString(36).substr(2, 8)}`, avatar: `/placeholder.svg?height=40&width=40&query=wx${Math.floor(Math.random() * 10)}`, deviceId: device.id, status: ["normal", "limited", "blocked"][Math.floor(Math.random() * 3)] as "normal" | "limited" | "blocked", friendCount: Math.floor(Math.random() * 4000) + 1000, dailyAddLimit: Math.random() > 0.5 ? 20 : 10, }) } }) return accounts } const generateMockCustomerServices = (): CustomerService[] => { return Array.from({ length: 5 }, (_, i) => ({ id: `cs-${i + 1}`, name: `客服${i + 1}`, avatar: `/placeholder.svg?height=40&width=40&query=cs${i}`, status: ["online", "offline", "busy"][Math.floor(Math.random() * 3)] as "online" | "offline" | "busy", assignedUsers: Math.floor(Math.random() * 100) + 50, })) } const generateMockTrafficPools = (): TrafficPool[] => { return [ { id: "pool-1", name: "高价值客户池", description: "包含所有高价值客户,优先添加", userCount: 156, tags: ["高价值", "优先添加", "重要客户"], createdAt: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString(), }, { id: "pool-2", name: "潜在客户池", description: "潜在客户,需要培育", userCount: 287, tags: ["潜在客户", "待培育", "中等价值"], createdAt: new Date(Date.now() - 20 * 24 * 60 * 60 * 1000).toISOString(), }, { id: "pool-3", name: "活跃用户池", description: "近期活跃度高的用户", userCount: 124, tags: ["活跃用户", "高互动", "高频次"], createdAt: new Date(Date.now() - 15 * 24 * 60 * 60 * 1000).toISOString(), }, { id: "pool-4", name: "流失预警池", description: "有流失风险的用户", userCount: 68, tags: ["流失预警", "挽回", "低活跃度"], createdAt: new Date(Date.now() - 10 * 24 * 60 * 60 * 1000).toISOString(), }, { id: "pool-5", name: "新用户池", description: "最近30天新增用户", userCount: 93, tags: ["新用户", "引导", "培育"], createdAt: new Date(Date.now() - 5 * 24 * 60 * 60 * 1000).toISOString(), }, ] } // 其他生成函数保持不变... const generateRFMScore = (): RFMScore => { const r = Math.floor(Math.random() * 5) + 1 const f = Math.floor(Math.random() * 5) + 1 const m = Math.floor(Math.random() * 5) + 1 const segmentKey = `${r}${f}${m}` as keyof typeof RFM_SEGMENTS const segment = RFM_SEGMENTS[segmentKey] || RFM_SEGMENTS["333"] return { recency: r, frequency: f, monetary: m, total: r + f + m, segment: segment.name, priority: segment.priority, } } const generateMockInteractions = (): UserInteraction[] => { const interactions: UserInteraction[] = [] const interactionCount = Math.floor(Math.random() * 10) + 5 for (let i = 0; i < interactionCount; i++) { const type = ["message", "purchase", "view", "click"][Math.floor(Math.random() * 4)] as | "message" | "purchase" | "view" | "click" const date = new Date() date.setDate(date.getDate() - Math.floor(Math.random() * 30)) date.setHours(Math.floor(Math.random() * 24), Math.floor(Math.random() * 60)) let content = "" let value: number | undefined = undefined switch (type) { case "message": content = ["您好,请问有什么可以帮到您?", "产品有什么优惠活动吗?", "��谢,我考虑一下"][ Math.floor(Math.random() * 3) ] break case "purchase": content = ["购买了产品A", "购买了服务B", "订阅了会员计划"][Math.floor(Math.random() * 3)] value = Math.floor(Math.random() * 1000) + 100 break case "view": content = ["浏览了产品页面", "查看了促销活动", "访问了会员中心"][Math.floor(Math.random() * 3)] break case "click": content = ["点击了广告链接", "点击了推荐产品", "点击了优惠券"][Math.floor(Math.random() * 3)] break } interactions.push({ id: `interaction-${i}`, type, content, timestamp: date.toISOString(), value, }) } return interactions.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()) } const generateUserTags = (rfmScore: RFMScore): UserTag[] => { const tags: UserTag[] = [] if (rfmScore.recency >= 4) { tags.push({ id: `tag-recency-${rfmScore.recency}`, name: "近期活跃", color: "bg-gradient-to-r from-emerald-400 to-emerald-500 text-white border-0", source: "system", }) } else if (rfmScore.recency <= 2) { tags.push({ id: `tag-recency-${rfmScore.recency}`, name: "长期未活跃", color: "bg-gradient-to-r from-slate-400 to-slate-500 text-white border-0", source: "system", }) } if (rfmScore.frequency >= 4) { tags.push({ id: `tag-frequency-${rfmScore.frequency}`, name: "高频互动", color: "bg-gradient-to-r from-blue-400 to-blue-500 text-white border-0", source: "system", }) } if (rfmScore.monetary >= 4) { tags.push({ id: `tag-monetary-${rfmScore.monetary}`, name: "高消费", color: "bg-gradient-to-r from-purple-400 to-purple-500 text-white border-0", source: "system", }) } const otherTags = [ { name: "潜在客户", color: "bg-gradient-to-r from-amber-400 to-yellow-500 text-white border-0" }, { name: "已成交", color: "bg-gradient-to-r from-green-400 to-green-500 text-white border-0" }, { name: "需跟进", color: "bg-gradient-to-r from-orange-400 to-red-400 text-white border-0" }, { name: "VIP客户", color: "bg-gradient-to-r from-rose-400 to-pink-500 text-white border-0" }, { name: "企业客户", color: "bg-gradient-to-r from-indigo-400 to-blue-500 text-white border-0" }, { name: "个人客户", color: "bg-gradient-to-r from-gray-400 to-gray-500 text-white border-0" }, { name: "新客户", color: "bg-gradient-to-r from-cyan-400 to-teal-500 text-white border-0" }, { name: "老客户", color: "bg-gradient-to-r from-violet-400 to-purple-500 text-white border-0" }, ] const tagCount = Math.floor(Math.random() * 3) + 1 const selectedIndices = new Set() while (selectedIndices.size < tagCount) { selectedIndices.add(Math.floor(Math.random() * otherTags.length)) } selectedIndices.forEach((index) => { const tag = otherTags[index] tags.push({ id: `tag-other-${index}`, name: tag.name, color: tag.color, source: Math.random() > 0.5 ? "manual" : "auto", }) }) return tags } const generateMockUsers = ( devices: Device[], wechatAccounts: WechatAccount[], customerServices: CustomerService[], trafficPools: TrafficPool[], ): TrafficUser[] => { return Array.from({ length: 500 }, (_, i) => { const device = devices[Math.floor(Math.random() * devices.length)] const wechatAccount = wechatAccounts.filter((acc) => acc.deviceId === device.id)[0] || wechatAccounts[0] const customerService = customerServices[Math.floor(Math.random() * customerServices.length)] const scenario = SCENARIOS[Math.floor(Math.random() * SCENARIOS.length)] const rfmScore = generateRFMScore() const isDuplicate = Math.random() < 0.15 const poolCount = Math.floor(Math.random() * 3) const poolIds = poolCount === 0 ? [] : Array.from({ length: poolCount }, () => trafficPools[Math.floor(Math.random() * trafficPools.length)].id) if (rfmScore.priority === "high" && !poolIds.includes("pool-1")) { if (Math.random() > 0.5) { poolIds.push("pool-1") } } const addTime = new Date() addTime.setDate(addTime.getDate() - Math.floor(Math.random() * 30)) const lastInteraction = new Date() lastInteraction.setDate(lastInteraction.getDate() - Math.floor(Math.random() * 7)) const tags = generateUserTags(rfmScore) const interactions = generateMockInteractions() return { id: `user-${i + 1}`, avatar: `/placeholder.svg?height=40&width=40&query=avatar${i % 10}`, nickname: `用户${i + 1}`, wechatId: `wxid_${Math.random().toString(36).substr(2, 8)}`, phone: `1${Math.floor(Math.random() * 9 + 1)}${Math.random().toString().slice(2, 11)}`, region: device.location, note: Math.random() > 0.7 ? `这是用户${i + 1}的备注信息` : "", status: isDuplicate ? "duplicate" : (["pending", "added", "failed"][Math.floor(Math.random() * 3)] as "pending" | "added" | "failed"), addTime: addTime.toISOString(), source: scenario.name, scenario: scenario.id, deviceId: device.id, wechatAccountId: wechatAccount.id, customerServiceId: customerService.id, poolIds, tags, rfmScore, lastInteraction: lastInteraction.toISOString(), totalSpent: Math.floor(Math.random() * 10000), interactionCount: interactions.length, conversionRate: Math.floor(Math.random() * 100), isDuplicate, mergedAccounts: isDuplicate ? [`wx-${Math.random().toString(36).substr(2, 6)}`] : [], addStatus: ["not_added", "adding", "added", "failed"][Math.floor(Math.random() * 4)] as | "not_added" | "adding" | "added" | "failed", interactions, } }) } const mockDevices = generateMockDevices() const mockWechatAccounts = generateMockWechatAccounts(mockDevices) const mockCustomerServices = generateMockCustomerServices() const mockTrafficPools = generateMockTrafficPools() const mockUsers = generateMockUsers(mockDevices, mockWechatAccounts, mockCustomerServices, mockTrafficPools) export default function TrafficPoolPage() { const router = useRouter() const { toast } = useToast() // 基础数据状态 const [users, setUsers] = useState(mockUsers) const [devices] = useState(mockDevices) const [wechatAccounts] = useState(mockWechatAccounts) const [customerServices] = useState(mockCustomerServices) const [trafficPools] = useState(mockTrafficPools) // UI状态 const [loading, setLoading] = useState(false) const [selectedUsers, setSelectedUsers] = useState([]) const [showFilters, setShowFilters] = useState(false) const [showUserDetail, setShowUserDetail] = useState(false) const [showAddToPool, setShowAddToPool] = useState(false) const [selectedUser, setSelectedUser] = useState(null) const [selectedPool, setSelectedPool] = useState(null) const [activeDetailTab, setActiveDetailTab] = useState("info") // 筛选状态 const [deviceFilter, setDeviceFilter] = useState("all") const [poolFilter, setPoolFilter] = useState("all") const [valuationFilter, setValuationFilter] = useState("all") const [statusFilter, setStatusFilter] = useState("all") const [searchQuery, setSearchQuery] = useState("") // 分页状态 const [currentPage, setCurrentPage] = useState(1) const usersPerPage = 10 // 数据分析展开状态 const [showAnalytics, setShowAnalytics] = useState(false) const debouncedSearchQuery = useDebounce(searchQuery, 300) const searchInputRef = useRef(null) // 计算统计数据 const stats = { total: users.length, highValue: users.filter((u) => u.rfmScore.priority === "high").length, mediumValue: users.filter((u) => u.rfmScore.priority === "medium").length, lowValue: users.filter((u) => u.rfmScore.priority === "low").length, duplicates: users.filter((u) => u.isDuplicate).length, pending: users.filter((u) => u.status === "pending").length, added: users.filter((u) => u.status === "added").length, failed: users.filter((u) => u.status === "failed").length, avgSpent: Math.round(users.reduce((sum, u) => sum + u.totalSpent, 0) / users.length), addSuccessRate: Math.round((users.filter((u) => u.status === "added").length / users.length) * 100), duplicateRate: Math.round((users.filter((u) => u.isDuplicate).length / users.length) * 100), } // 过滤用户 const filteredUsers = useCallback(() => { return users.filter((user) => { const matchesSearch = !debouncedSearchQuery || user.nickname.toLowerCase().includes(debouncedSearchQuery.toLowerCase()) || user.wechatId.toLowerCase().includes(debouncedSearchQuery.toLowerCase()) || user.phone.includes(debouncedSearchQuery) const matchesDevice = deviceFilter === "all" || user.deviceId === deviceFilter const matchesValuation = valuationFilter === "all" || user.rfmScore.priority === valuationFilter const matchesStatus = statusFilter === "all" || user.status === statusFilter const matchesPool = poolFilter === "all" || (poolFilter === "none" ? user.poolIds.length === 0 : user.poolIds.includes(poolFilter)) return matchesSearch && matchesDevice && matchesValuation && matchesStatus && matchesPool }) }, [users, debouncedSearchQuery, deviceFilter, valuationFilter, statusFilter, poolFilter])() // 按优先级排序 const sortedUsers = filteredUsers.sort((a, b) => { const priorityOrder = { high: 3, medium: 2, low: 1 } return priorityOrder[b.rfmScore.priority] - priorityOrder[a.rfmScore.priority] }) // 计算分页 const totalPages = Math.ceil(sortedUsers.length / usersPerPage) const paginatedUsers = sortedUsers.slice((currentPage - 1) * usersPerPage, currentPage * usersPerPage) // 重置到第一页当筛选条件改变时 useEffect(() => { setCurrentPage(1) }, [debouncedSearchQuery, deviceFilter, valuationFilter, statusFilter, poolFilter]) // 处理用户选择 const handleUserSelect = useCallback((userId: string, checked: boolean) => { setSelectedUsers((prev) => (checked ? [...prev, userId] : prev.filter((id) => id !== userId))) }, []) // 处理全选 const handleSelectAll = useCallback( (checked: boolean) => { if (checked) { setSelectedUsers(paginatedUsers.map((user) => user.id)) } else { setSelectedUsers([]) } }, [paginatedUsers], ) // 重置筛选器 const resetFilters = useCallback(() => { setDeviceFilter("all") setPoolFilter("all") setValuationFilter("all") setStatusFilter("all") setSearchQuery("") if (searchInputRef.current) { searchInputRef.current.value = "" } setShowFilters(false) }, []) // 刷新数据 const handleRefresh = useCallback(() => { setLoading(true) setTimeout(() => { const refreshedUsers = generateMockUsers(devices, wechatAccounts, customerServices, trafficPools) setUsers(refreshedUsers) setLoading(false) toast({ title: "刷新成功", description: "流量池数据已更新", }) }, 800) }, [devices, wechatAccounts, customerServices, trafficPools, toast]) // 添加到流量池 const handleAddToPool = useCallback(() => { if (selectedUsers.length === 0) { toast({ title: "请选择用户", description: "请先选择要添加到流量池的用户", variant: "destructive", }) return } setShowAddToPool(true) }, [selectedUsers.length, toast]) // 确认添加到流量池 const confirmAddToPool = useCallback(() => { if (!selectedPool) { toast({ title: "请选择流量池", description: "请选择要添加到的流量池", variant: "destructive", }) return } const updatedUsers = users.map((user) => { if (selectedUsers.includes(user.id)) { if (!user.poolIds.includes(selectedPool)) { return { ...user, poolIds: [...user.poolIds, selectedPool], addStatus: "added" as const, } } } return user }) setUsers(updatedUsers) setShowAddToPool(false) setSelectedPool(null) setSelectedUsers([]) const poolName = trafficPools.find((pool) => pool.id === selectedPool)?.name || "未知流量池" toast({ title: "添加成功", description: `已将 ${selectedUsers.length} 个用户添加到 ${poolName}`, }) }, [selectedPool, selectedUsers, users, trafficPools, toast]) // 获取辅助函数 const getRFMSegmentInfo = (segment: string) => { const segmentEntry = Object.entries(RFM_SEGMENTS).find(([_, info]) => info.name === segment) return segmentEntry ? segmentEntry[1] : { name: segment, color: "bg-gray-100 text-gray-800", icon: "👤" } } const getWechatAccount = (accountId: string) => { return wechatAccounts.find((acc) => acc.id === accountId) } const getCustomerService = (csId: string) => { return customerServices.find((cs) => cs.id === csId) } const getDevice = (deviceId: string) => { return devices.find((device) => device.id === deviceId) } const getPoolNames = (poolIds: string[]) => { return poolIds.map((id) => trafficPools.find((pool) => pool.id === id)?.name || "未知流量池") } const formatDateTime = (dateString: string) => { const date = new Date(dateString) return new Intl.DateTimeFormat("zh-CN", { year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", }).format(date) } const formatDate = (dateString: string) => { const date = new Date(dateString) return new Intl.DateTimeFormat("zh-CN", { year: "numeric", month: "2-digit", day: "2-digit", }).format(date) } const getInteractionIcon = (type: string) => { switch (type) { case "message": return case "purchase": return case "view": return case "click": return default: return } } // 用户卡片组件 const UserCard = ({ user }: { user: TrafficUser }) => { const wechatAccount = getWechatAccount(user.wechatAccountId) const customerService = getCustomerService(user.customerServiceId) const segmentInfo = getRFMSegmentInfo(user.rfmScore.segment) return ( { setSelectedUser(user) setShowUserDetail(true) setActiveDetailTab("info") }} >
handleUserSelect(user.id, checked as boolean)} onClick={(e) => e.stopPropagation()} className="mb-2" /> {user.nickname[0]}
{user.nickname} {user.rfmScore.priority === "high" && ( )}
{user.addStatus === "not_added" ? "未添加" : user.addStatus === "adding" ? "添加中" : user.addStatus === "added" ? "已添加" : "添加失败"}
{wechatAccount?.wechatId || "未知微信号"}
{getDevice(user.deviceId)?.name || "未知设备"}
{customerService?.name || "未分配"}
{user.tags.slice(0, 2).map((tag) => ( {tag.name} ))} {user.tags.length > 2 && ( +{user.tags.length - 2} )}
{user.poolIds.length > 0 && (
{getPoolNames(user.poolIds).join(", ")}
)}
) } // 用户详情组件 const UserDetail = ({ user }: { user: TrafficUser }) => { const wechatAccount = getWechatAccount(user.wechatAccountId) const customerService = getCustomerService(user.customerServiceId) const device = getDevice(user.deviceId) const segmentInfo = getRFMSegmentInfo(user.rfmScore.segment) return (
{user.nickname[0]}
{user.nickname}
{wechatAccount?.wechatId || "未知微信号"}
{segmentInfo.icon} {user.rfmScore.segment} {user.rfmScore.priority === "high" && 优先添加}
基本信息 用户旅程 用户标签
关联信息
设备: {device?.name || "未知设备"}
微信号: {wechatAccount?.nickname || "未知微信"}
客服: {customerService?.name || "未分配"}
添加时间: {formatDate(user.addTime)}
最近互动: {formatDate(user.lastInteraction)}
RFM评分
最近性(R)
{user.rfmScore.recency}
频率(F)
{user.rfmScore.frequency}
金额(M)
{user.rfmScore.monetary}
总分
{user.rfmScore.total}/15
流量池
{user.poolIds.length > 0 ? (
{getPoolNames(user.poolIds).map((name, index) => ( {name} ))}
) : (
未分配到任何流量池
)}
统计数据
总消费
¥{user.totalSpent}
互动次数
{user.interactionCount}
转化率
{user.conversionRate}%
添加状态
{user.addStatus === "added" ? "已添加" : user.addStatus === "not_added" ? "未添加" : user.addStatus === "adding" ? "添加中" : "添加失败"}
互动记录
{user.interactions.map((interaction) => (
{getInteractionIcon(interaction.type)}
{interaction.type === "message" ? "消息互动" : interaction.type === "purchase" ? "购买行为" : interaction.type === "view" ? "页面浏览" : "点击行为"}
{formatDateTime(interaction.timestamp)}
{interaction.content}
{interaction.value !== undefined && (
¥{interaction.value}
)}
))}
用户标签
{user.tags.map((tag) => ( {tag.name} ))} {user.tags.length === 0 &&
暂无标签
}
价值标签
{segmentInfo.icon} {user.rfmScore.segment}
RFM总分: {user.rfmScore.total}/15
价值等级:
{user.rfmScore.priority === "high" ? "高价值" : user.rfmScore.priority === "medium" ? "中价值" : "低价值"}
) } return (
{/* 顶部导航栏 */}

流量池管理

{/* 数据分析按钮 */}
{/* 搜索栏 */}
setSearchQuery(e.target.value)} className="pl-9" ref={searchInputRef} />
{/* 数据分析面板 - 可折叠 */} {showAnalytics && (
{/* 核心指标 */}
{filteredUsers.length}
总用户数
{stats.highValue}
高价值用户
{/* 用户价值分布 */}
用户价值分布
高价值
{stats.highValue}
中价值
{stats.mediumValue}
低价值
{stats.lowValue}
{/* 添加效率 */}
添加效率
{stats.addSuccessRate}%
成功率
¥{stats.avgSpent}
平均消费
{stats.added}
已添加
{stats.pending}
待添加
{stats.failed}
添加失败
)} {/* 筛选器抽屉 */} 筛选选项
设备
流量池
用户价值
添加状态
{/* 主内容区域 */}
{/* 筛选器标签 */} {(deviceFilter !== "all" || poolFilter !== "all" || valuationFilter !== "all" || statusFilter !== "all" || searchQuery) && (
{deviceFilter !== "all" && ( setDeviceFilter("all")} > 设备: {devices.find((d) => d.id === deviceFilter)?.name} )} {poolFilter !== "all" && ( setPoolFilter("all")} > 流量池: {poolFilter === "none" ? "未分配" : trafficPools.find((p) => p.id === poolFilter)?.name} )} {valuationFilter !== "all" && ( setValuationFilter("all")} > 价值: {valuationFilter === "high" ? "高价值" : valuationFilter === "medium" ? "中价值" : "低价值"} )} {statusFilter !== "all" && ( setStatusFilter("all")} > 状态:{" "} {statusFilter === "pending" ? "待添加" : statusFilter === "added" ? "已添加" : statusFilter === "failed" ? "添加失败" : "重复用户"} )} {searchQuery && ( setSearchQuery("")} > 搜索: {searchQuery} )}
)} {/* 全选和批量操作 */}
0} onCheckedChange={handleSelectAll} id="select-all" />
{/* 批量操作栏 */} {selectedUsers.length > 0 && (
已选择 {selectedUsers.length} 个用户
)} {/* 用户列表 */} {loading ? (
加载中...
) : paginatedUsers.length === 0 ? (
暂无数据
) : ( <> {paginatedUsers.map((user) => ( ))} {/* 分页 */} {totalPages > 1 && (
第 {currentPage} / {totalPages} 页
)} )}
{/* 用户详情抽屉 */} 用户详情
{selectedUser && }
{/* 添加到流量池对话框 */} 添加到流量池
已选择 {selectedUsers.length} 个用户,请选择要添加到的流量池
{selectedPool && (
{trafficPools.find((p) => p.id === selectedPool)?.name}
{trafficPools.find((p) => p.id === selectedPool)?.description}
{trafficPools .find((p) => p.id === selectedPool) ?.tags.map((tag, index) => ( {tag} ))}
)}
) }