"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 { ChevronLeft, Smartphone, Users, Star, Clock, MessageSquare, Shield, Info, UserPlus, Search, Filter, Tag, ChevronRight, Loader2, } from "lucide-react" import { Badge } from "@/components/ui/badge" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { Progress } from "@/components/ui/progress" import { Input } from "@/components/ui/input" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogFooter, } from "@/components/ui/dialog" import { ScrollArea } from "@/components/ui/scroll-area" import { Tooltip as UITooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip" import { Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, } from "@/components/ui/pagination" import { toast } from "@/components/ui/use-toast" import { fetchWechatAccountDetail, transformWechatAccountDetail, fetchWechatFriends } from "@/api/wechat-accounts" interface RestrictionRecord { id: string date: string reason: string recoveryTime: string type: "friend_limit" | "marketing" | "spam" | "other" } interface FriendTag { id: string name: string color: string } interface WechatFriend { id: string avatar: string nickname: string wechatId: string remark: string addTime: string lastInteraction: string tags: FriendTag[] region: string source: string notes: string } interface WechatAccountDetail { id: string avatar: string nickname: string wechatId: string deviceId: string deviceName: string friendCount: number todayAdded: number status: "normal" | "abnormal" lastActive: string messageCount: number activeRate: number // 新增和修改的字段 accountAge: { years: number months: number } totalChats: number chatFrequency: number // 每日平均聊天次数 restrictionRecords: RestrictionRecord[] isVerified: boolean firstMomentDate: string accountWeight: number weightFactors: { restrictionFactor: number verificationFactor: number ageFactor: number activityFactor: number } weeklyStats: { date: string friends: number messages: number }[] friends: WechatFriend[] } export default function WechatAccountDetailPage({ params }: { params: { id: string } }) { const router = useRouter() const [account, setAccount] = useState(null) const [showRestrictions, setShowRestrictions] = useState(false) const [showTransferConfirm, setShowTransferConfirm] = useState(false) const [showFriendDetail, setShowFriendDetail] = useState(false) const [selectedFriend, setSelectedFriend] = useState(null) const [searchQuery, setSearchQuery] = useState("") const [activeTab, setActiveTab] = useState("overview") const [isLoading, setIsLoading] = useState(false) // 好友列表相关状态 const [friends, setFriends] = useState([]) const [friendsPage, setFriendsPage] = useState(1) const [friendsTotal, setFriendsTotal] = useState(0) const [hasMoreFriends, setHasMoreFriends] = useState(true) const [isFetchingFriends, setIsFetchingFriends] = useState(false) const [hasFriendLoadError, setHasFriendLoadError] = useState(false) const friendsObserver = useRef(null) const friendsLoadingRef = useRef(null) const friendsContainerRef = useRef(null) // 计算好友列表容器高度 const getFriendsContainerHeight = () => { // 最少显示一条记录的高度,最多显示十条记录的高度 const minHeight = 80; // 单条记录高度 const maxHeight = 800; // 十条记录高度 if (friends.length === 0) return minHeight; return Math.min(Math.max(friends.length * 80, minHeight), maxHeight); }; // 生成模拟账号数据(作为备用,服务器请求失败时使用) const generateMockAccountData = (): WechatAccountDetail => { // 生成随机标签 const generateRandomTags = (count: number): FriendTag[] => { const tagPool = [ { name: "潜在客户", color: "bg-blue-100 text-blue-800" }, { name: "高意向", color: "bg-green-100 text-green-800" }, { name: "已成交", color: "bg-purple-100 text-purple-800" }, { name: "需跟进", color: "bg-yellow-100 text-yellow-800" }, { name: "活跃用户", color: "bg-indigo-100 text-indigo-800" }, { name: "沉默用户", color: "bg-gray-100 text-gray-800" }, { name: "企业客户", color: "bg-red-100 text-red-800" }, { name: "个人用户", color: "bg-pink-100 text-pink-800" }, { name: "新增好友", color: "bg-emerald-100 text-emerald-800" }, { name: "老客户", color: "bg-amber-100 text-amber-800" }, ]; return Array.from({ length: Math.floor(Math.random() * count) + 1 }, () => { const randomTag = tagPool[Math.floor(Math.random() * tagPool.length)]; return { id: `tag-${Math.random().toString(36).substring(2, 9)}`, name: randomTag.name, color: randomTag.color, }; }); }; // 生成随机好友 const friendCount = Math.floor(Math.random() * (300 - 150)) + 150; const generateFriends = (count: number): WechatFriend[] => { return Array.from({ length: count }, (_, i) => { const firstName = ["张", "王", "李", "赵", "陈", "刘", "杨", "黄", "周", "吴"][Math.floor(Math.random() * 10)]; const secondName = ["小", "大", "明", "华", "强", "伟", "芳", "娜", "秀", "英"][ Math.floor(Math.random() * 10) ]; const lastName = ["明", "华", "强", "伟", "芳", "娜", "秀", "英", "军", "杰"][Math.floor(Math.random() * 10)]; const nickname = firstName + secondName + lastName; // 生成随机的添加时间(过去1年内) const addDate = new Date(); addDate.setDate(addDate.getDate() - Math.floor(Math.random() * 365)); // 生成随机的最后互动时间(过去30天内) const lastDate = new Date(); lastDate.setDate(lastDate.getDate() - Math.floor(Math.random() * 30)); return { id: `friend-${i}`, avatar: `/placeholder.svg?height=40&width=40&text=${nickname[0]}`, nickname, wechatId: `wxid_${Math.random().toString(36).substring(2, 9)}`, remark: Math.random() > 0.5 ? `${nickname}(${["同事", "客户", "朋友", "同学"][Math.floor(Math.random() * 4)]})` : "", addTime: addDate.toISOString().split("T")[0], lastInteraction: lastDate.toISOString().split("T")[0], tags: generateRandomTags(3), region: ["广东", "北京", "上海", "浙江", "江苏", "四川", "湖北", "福建", "山东", "河南"][ Math.floor(Math.random() * 10) ], source: ["抖音", "小红书", "朋友介绍", "搜索添加", "群聊", "附近的人", "名片分享"][ Math.floor(Math.random() * 7) ], notes: Math.random() > 0.7 ? ["对产品很感兴趣", "需要进一步跟进", "已购买过产品", "价格敏感", "需要更多信息"][ Math.floor(Math.random() * 5) ] : "", }; }); }; const friends = generateFriends(friendCount); const mockAccount: WechatAccountDetail = { id: params.id, avatar: "https://hebbkx1anhila5yf.public.blob.vercel-storage.com/img_v3_02jn_e7fcc2a4-3560-478d-911a-4ccd69c6392g.jpg-a8zVtwxMuSrPWN9dfWH93EBY0yM3Dh.jpeg", nickname: "卡若-25vig", wechatId: `wxid_${Math.random().toString(36).substr(2, 8)}`, deviceId: "device-1", deviceName: "设备1", friendCount: friends.length, todayAdded: 12, status: "normal", lastActive: new Date().toLocaleString(), messageCount: 1234, activeRate: 87, accountAge: { years: 2, months: 8, }, totalChats: 15234, chatFrequency: 42, restrictionRecords: [ { id: "1", date: "2024-02-25", reason: "添加好友过于频繁", recoveryTime: "2024-02-26", type: "friend_limit", }, { id: "2", date: "2024-01-15", reason: "营销内容违规", recoveryTime: "2024-01-16", type: "marketing", }, ], isVerified: true, firstMomentDate: "2021-06-15", accountWeight: 85, weightFactors: { restrictionFactor: 0.8, verificationFactor: 1.0, ageFactor: 0.9, activityFactor: 0.85, }, weeklyStats: Array.from({ length: 7 }, (_, i) => ({ date: `Day ${i + 1}`, friends: Math.floor(Math.random() * 50) + 50, messages: Math.floor(Math.random() * 100) + 100, })), friends: friends, }; return mockAccount; }; // 随机生成标签颜色 const getRandomTagColor = (): string => { const colors = [ "bg-blue-100 text-blue-800", "bg-green-100 text-green-800", "bg-red-100 text-red-800", "bg-pink-100 text-pink-800", "bg-emerald-100 text-emerald-800", "bg-amber-100 text-amber-800", ]; return colors[Math.floor(Math.random() * colors.length)]; }; // 获取好友列表数据 const fetchFriends = useCallback(async (page: number = 1, isNewSearch: boolean = false) => { if (!account || isFetchingFriends) return; try { setIsFetchingFriends(true); setHasFriendLoadError(false); // 调用API获取好友列表 const response = await fetchWechatFriends(account.wechatId, page, 20, searchQuery); if (response && response.code === 200) { // 更新总数计数,确保在第一次加载时设置 if (isNewSearch || friendsTotal === 0) { setFriendsTotal(response.data.total || 0); } const newFriends = response.data.list.map((friend: any) => ({ id: friend.wechatId, avatar: friend.avatar, nickname: friend.nickname || '未设置昵称', wechatId: friend.wechatId, remark: friend.remark || '', addTime: '2024-01-01', // 接口未返回,使用默认值 lastInteraction: '2024-01-01', // 接口未返回,使用默认值 tags: (friend.labels || []).map((label: string, index: number) => ({ id: `tag-${index}`, name: label, color: getRandomTagColor(), })), region: friend.region || '未知地区', source: '微信好友', // 接口未返回,使用默认值 notes: '', })); // 更新状态 if (isNewSearch) { setFriends(newFriends); } else { setFriends(prev => [...prev, ...newFriends]); } setFriendsPage(page); // 判断是否还有更多数据 setHasMoreFriends(page * 20 < response.data.total); console.log("好友列表加载成功,总数:", response.data.total); } else { setHasFriendLoadError(true); toast({ title: "获取好友列表失败", description: response?.msg || "请稍后再试", variant: "destructive" }); } } catch (error) { setHasFriendLoadError(true); console.error("获取好友列表失败:", error); toast({ title: "获取好友列表失败", description: "请检查网络连接或稍后再试", variant: "destructive" }); } finally { setIsFetchingFriends(false); } }, [account, searchQuery, friendsTotal]); // 处理搜索 const handleSearch = useCallback(() => { setFriends([]); setFriendsPage(1); setHasMoreFriends(true); fetchFriends(1, true); }, [fetchFriends]); // 处理标签切换 useEffect(() => { if (account && friends.length === 0) { fetchFriends(1, true); } }, [account, friends.length, fetchFriends]); // 设置IntersectionObserver用于懒加载 useEffect(() => { friendsObserver.current = new IntersectionObserver((entries) => { if (entries[0].isIntersecting && hasMoreFriends && !isFetchingFriends) { fetchFriends(friendsPage + 1); } }, { threshold: 0.5 }); return () => { if (friendsObserver.current) { friendsObserver.current.disconnect(); } }; }, [fetchFriends, friendsPage, hasMoreFriends, isFetchingFriends]); // 观察加载指示器 useEffect(() => { if (friendsLoadingRef.current && friendsObserver.current) { friendsObserver.current.observe(friendsLoadingRef.current); } return () => { if (friendsLoadingRef.current && friendsObserver.current) { friendsObserver.current.unobserve(friendsLoadingRef.current); } }; }, [friendsLoadingRef.current, friendsObserver.current]); useEffect(() => { // 模拟API调用获取账号详情 const fetchAccount = async () => { try { setIsLoading(true) // 调用API获取微信账号详情 const response = await fetchWechatAccountDetail(params.id) if (response && response.code === 200) { // 转换数据格式 const transformedAccount = transformWechatAccountDetail(response) setAccount(transformedAccount) // 如果有好友总数,更新friendsTotal状态 if (transformedAccount && transformedAccount.friendCount > 0) { setFriendsTotal(transformedAccount.friendCount); } } else { toast({ title: "获取微信账号详情失败", description: response?.msg || "请稍后再试", variant: "destructive" }) // 获取失败时使用模拟数据 const mockData = generateMockAccountData(); setAccount(mockData); // 更新好友总数 setFriendsTotal(mockData.friendCount); } } catch (error) { console.error("获取微信账号详情失败:", error) toast({ title: "获取微信账号详情失败", description: "请检查网络连接或稍后再试", variant: "destructive" }) // 请求出错时使用模拟数据 const mockData = generateMockAccountData(); setAccount(mockData); // 更新好友总数 setFriendsTotal(mockData.friendCount); } finally { setIsLoading(false) } } fetchAccount() }, [params.id]) if (!account) { return
加载中...
} const getWeightColor = (weight: number) => { if (weight >= 80) return "text-green-600" if (weight >= 60) return "text-yellow-600" return "text-red-600" } const getWeightDescription = (weight: number) => { if (weight >= 80) return "账号状态良好" if (weight >= 60) return "账号状态一般" return "账号状态较差" } const calculateMaxDailyAdds = (weight: number) => { const baseLimit = 20 return Math.floor(baseLimit * (weight / 100)) } const getRestrictionTypeColor = (type: string) => { switch (type) { case "friend_limit": return "text-yellow-600" case "marketing": return "text-red-600" case "spam": return "text-orange-600" default: return "text-gray-600" } } const formatAccountAge = (age: { years: number; months: number }) => { if (age.years > 0) { return `${age.years}年${age.months}个月`; } return `${age.months}个月`; }; const handleTransferFriends = () => { setShowTransferConfirm(true) } const confirmTransferFriends = () => { // 模拟API调用 toast({ title: "好友转移成功", description: `已成功转移 ${account?.friends.length} 个好友`, }); setShowTransferConfirm(false) } const handleFriendClick = (friend: WechatFriend) => { setSelectedFriend(friend) setShowFriendDetail(true) } return ( {isLoading ? (
) : account ? (

账号详情

{account.nickname[0]} {account.isVerified && ( 已认证 )}

{account.nickname}

{account.status === "normal" ? "正常" : "异常"}

微信号:{account.wechatId}

账号概览 好友列表 ({friendsTotal > 0 ? friendsTotal : account.friendCount}) {/* 账号基础信息 */}
账号年龄
{formatAccountAge(account.accountAge)}
注册时间:{account.firstMomentDate}
活跃程度
{account.chatFrequency}次/天
总聊天数:{account.totalChats.toLocaleString()}
{/* 账号权重评估 */}
账号权重评估
{account.accountWeight}

{getWeightDescription(account.accountWeight)}

账号年龄 {(account.weightFactors.ageFactor * 100).toFixed(0)}%
活跃度 {(account.weightFactors.activityFactor * 100).toFixed(0)}%
限制影响 {(account.weightFactors.restrictionFactor * 100).toFixed(0)}%
实名认证 {(account.weightFactors.verificationFactor * 100).toFixed(0)}%
{/* 添加好友统计 */}
添加好友统计

根据账号权重计算每日可添加好友数量

今日已添加 {account.todayAdded}
添加进度 {account.todayAdded}/{calculateMaxDailyAdds(account.accountWeight)}
根据当前账号权重({account.accountWeight}分),每日最多可添加{" "} {calculateMaxDailyAdds(account.accountWeight)}{" "} 个好友
{/* 限制记录 */}
限制记录
setShowRestrictions(true)}> 共 {account.restrictionRecords.length} 次
{account.restrictionRecords.slice(0, 2).map((record) => (
{record.reason} {record.date}
))}
{/* 搜索栏 */}
setSearchQuery(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && handleSearch()} className="pl-9" />
{/* 好友列表 */}
{isFetchingFriends && friends.length === 0 ? (
) : friends.length === 0 && hasFriendLoadError ? (

加载好友失败,请重试

) : friends.length === 0 ? (
未找到匹配的好友
) : ( <> {friends.map((friend) => (
handleFriendClick(friend)} > {friend.nickname?.[0] || 'U'}
{friend.nickname} {friend.remark && ({friend.remark})}
{friend.wechatId}
{friend.tags.slice(0, 3).map((tag: FriendTag) => ( {tag.name} ))} {friend.tags.length > 3 && ( +{friend.tags.length - 3} )}
))} {/* 懒加载指示器 */} {hasMoreFriends && (
{isFetchingFriends && }
)} )}
{/* 显示加载状态和总数 */}
{friendsTotal > 0 ? ( 已加载 {Math.min(friends.length, friendsTotal)} / {friendsTotal} 条记录 ) : !isFetchingFriends && !hasFriendLoadError && account ? ( 共 {account.friendCount} 条记录 ) : null}
{/* 限制记录详情弹窗 */} 限制记录详情 每次限制恢复时间为24小时
{account.restrictionRecords.map((record) => (
{record.reason}
{record.date}
恢复时间:{record.recoveryTime}
))}
{/* 好友转移确认弹窗 */} 好友转移确认 即将导出该微信号的好友列表,用于创建新的获客计划
{account.nickname[0]}
{account.nickname}
{account.wechatId}

• 将导出该账号下的所有好友信息

• 好友信息将用于创建新的订单获客计划

• 导出过程中请勿关闭页面

{/* 好友详情弹窗 */} 好友详情 {selectedFriend && (
{selectedFriend.nickname[0]}
{selectedFriend.nickname}
{selectedFriend.wechatId}
{selectedFriend.remark && (
备注: {selectedFriend.remark}
)}
添加时间
{selectedFriend.addTime}
最近互动
{selectedFriend.lastInteraction}
地区
{selectedFriend.region}
来源
{selectedFriend.source}
标签
{selectedFriend.tags.map((tag: FriendTag) => ( {tag.name} ))} {selectedFriend.tags.length === 0 && 暂无标签}
{selectedFriend.notes && (
备注信息
{selectedFriend.notes}
)}
)}
) : (

未找到账号信息

)}
) }