"use client" import { useState, useEffect } from "react" import { Button } from "@/components/ui/button" import { Card } from "@/components/ui/card" import { Badge } from "@/components/ui/badge" import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog" import { Checkbox } from "@/components/ui/checkbox" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import { Smartphone, CheckCircle2, Loader2, Plus, Battery, Users, MapPin, Activity } from "lucide-react" import { cn } from "@/lib/utils" import { DeviceFilter } from "./DeviceFilter" import { AddDeviceDialog } from "./AddDeviceDialog" import type { Device, DeviceFilterParams } from "@/types/device" export interface DeviceSelectorProps { /** 是否使用对话框模式 */ dialogMode?: boolean /** 对话框是否打开 */ open?: boolean /** 对话框打开状态变更回调 */ onOpenChange?: (open: boolean) => void /** 是否支持多选 */ multiple?: boolean /** 已选择的设备ID */ selectedDevices?: string[] /** 设备选择变更回调 */ onDevicesChange: (deviceIds: string[]) => void /** 是���排除已用于其他计划的设备 */ devices?: Device[] /** 是否显示下一步按钮 */ showNextButton?: boolean /** 下一步按钮点击回调 */ onNext?: () => void /** 上一步按钮点击回调 */ onPrevious?: () => void /** 自定义类名 */ className?: string /** 页面标题 */ title?: string /** 最大选择数量 */ maxSelection?: number } /** * 统一的设备选择器组件 * 支持对话框模式和内嵌模式,支持单选和多选,样式与设备管理页面一致 */ export function DeviceSelector({ dialogMode = false, open = false, onOpenChange, multiple = true, selectedDevices = [], onDevicesChange, devices: propDevices, showNextButton = false, onNext, onPrevious, className, title = "选择设备", maxSelection = 10, }: DeviceSelectorProps) { const [devices, setDevices] = useState([]) const [loading, setLoading] = useState(true) const [selected, setSelected] = useState(selectedDevices) const [filters, setFilters] = useState({}) const [showAddDialog, setShowAddDialog] = useState(false) const [currentPage, setCurrentPage] = useState(1) const devicesPerPage = 10 // 如果外部selectedDevices变化,同步更新内部状态 useEffect(() => { setSelected(selectedDevices) }, [selectedDevices]) // 加载设备数据 useEffect(() => { const fetchDevices = async () => { setLoading(true) try { if (propDevices) { setDevices(propDevices) } else { // 模拟设备数据 await new Promise((resolve) => setTimeout(resolve, 800)) const mockDevices: Device[] = Array.from({ length: 25 }, (_, i) => ({ id: `device-${i + 1}`, name: `设备 ${i + 1}`, imei: `IMEI-${Math.random().toString(36).substr(2, 8)}`, type: i % 2 === 0 ? "android" : "ios", status: i < 20 ? "online" : i < 23 ? "offline" : "busy", wechatId: `wxid_${Math.random().toString(36).substr(2, 8)}`, friendCount: Math.floor(Math.random() * 1000) + 100, battery: Math.floor(Math.random() * 100) + 1, lastActive: i < 5 ? "刚刚" : i < 10 ? "5分钟前" : i < 15 ? "1小时前" : "2小时前", addFriendStatus: Math.random() > 0.2 ? "normal" : "abnormal", remark: `${title}设备 ${i + 1}`, model: i % 3 === 0 ? "iPhone 14" : i % 3 === 1 ? "Samsung S23" : "Xiaomi 13", category: i % 4 === 0 ? "acquisition" : i % 4 === 1 ? "maintenance" : i % 4 === 2 ? "testing" : "backup", todayAdded: Math.floor(Math.random() * 50), totalTasks: Math.floor(Math.random() * 100) + 10, completedTasks: Math.floor(Math.random() * 80) + 5, activePlans: i < 15 ? [`plan-${i + 1}`, `plan-${i + 2}`] : [], planNames: i < 15 ? [`计划 ${i + 1}`, `计划 ${i + 2}`] : [], tags: i % 2 === 0 ? ["高效", "稳定"] : ["测试", "备用"], location: i % 3 === 0 ? "北京" : i % 3 === 1 ? "上海" : "深圳", operator: `操作员${(i % 5) + 1}`, })) setDevices(mockDevices) } } catch (error) { console.error("获取设备失败:", error) } finally { setLoading(false) } } if (!dialogMode || open) { fetchDevices() } }, [dialogMode, open, propDevices, title]) // 处理设备选择 const handleDeviceToggle = (deviceId: string) => { let newSelected: string[] if (multiple) { if (selected.includes(deviceId)) { newSelected = selected.filter((id) => id !== deviceId) } else { if (selected.length >= maxSelection) { return // 达到最大选择数量 } newSelected = [...selected, deviceId] } } else { newSelected = [deviceId] } setSelected(newSelected) onDevicesChange(newSelected) } // 处理全选/取消全选 const handleSelectAll = () => { if (selected.length === Math.min(filteredDevices.length, maxSelection)) { setSelected([]) onDevicesChange([]) } else { const newSelected = filteredDevices.slice(0, maxSelection).map((device) => device.id) setSelected(newSelected) onDevicesChange(newSelected) } } // 处理对话框确认 const handleConfirm = () => { onDevicesChange(selected) if (onOpenChange) { onOpenChange(false) } } // 处理设备添加 const handleDeviceAdded = (newDevice: Device) => { setDevices([newDevice, ...devices]) } // 过滤设备 const filteredDevices = devices.filter((device) => { // 关键词搜索 if (filters.keyword) { const keyword = filters.keyword.toLowerCase() const matchesKeyword = device.name.toLowerCase().includes(keyword) || device.imei.toLowerCase().includes(keyword) || device.wechatId.toLowerCase().includes(keyword) || (device.remark && device.remark.toLowerCase().includes(keyword)) || (device.model && device.model.toLowerCase().includes(keyword)) if (!matchesKeyword) return false } // 状态过滤 if (filters.status?.length && !filters.status.includes(device.status)) { return false } // 类型过滤 if (filters.type?.length && !filters.type.includes(device.type)) { return false } // 分类过滤 if (filters.category?.length && device.category && !filters.category.includes(device.category)) { return false } // 型号过滤 if (filters.models?.length && device.model && !filters.models.includes(device.model)) { return false } // 电量范围过滤 if (filters.batteryRange) { const [min, max] = filters.batteryRange if (device.battery < min || device.battery > max) { return false } } // 好友数量范围过滤 if (filters.friendCountRange) { const [min, max] = filters.friendCountRange if (device.friendCount < min || device.friendCount > max) { return false } } // 标签过滤 if (filters.tags?.length && device.tags) { const hasMatchingTag = filters.tags.some((tag) => device.tags?.includes(tag)) if (!hasMatchingTag) return false } // 活跃计划过滤 if (filters.hasActivePlans !== undefined) { const hasActivePlans = device.activePlans && device.activePlans.length > 0 if (filters.hasActivePlans !== hasActivePlans) { return false } } return true }) // 分页数据 const paginatedDevices = filteredDevices.slice((currentPage - 1) * devicesPerPage, currentPage * devicesPerPage) // 获取可用的型号和标签 const availableModels = [...new Set(devices.map((d) => d.model).filter(Boolean))] const availableTags = [...new Set(devices.flatMap((d) => d.tags || []))] // 设备卡片组件 const DeviceCard = ({ device }: { device: Device }) => { const isSelected = selected.includes(device.id) const canSelect = !isSelected && (selected.length < maxSelection || !multiple) return ( (canSelect || isSelected ? handleDeviceToggle(device.id) : undefined)} >
{multiple ? ( e.stopPropagation()} /> ) : isSelected ? ( ) : (
)}

{device.name}

{device.status === "online" ? "在线" : device.status === "busy" ? "忙碌" : "离线"}
{device.type === "android" ? "Android" : "iOS"}
IMEI: {device.imei}
微信号: {device.wechatId}
{device.model &&
型号: {device.model}
} {device.remark &&
备注: {device.remark}
}
50 ? "text-green-500" : device.battery > 20 ? "text-yellow-500" : "text-red-500", )} /> {device.battery}%
{device.friendCount}
{device.todayAdded !== undefined &&
+{device.todayAdded}
}
{device.lastActive}
{/* 计划和任务信息 */} {device.activePlans && device.activePlans.length > 0 && (
活跃计划: {device.activePlans.length}
{device.planNames && (
{device.planNames.join(", ")}
)}
)} {/* 任务完成情况 */} {device.totalTasks !== undefined && device.completedTasks !== undefined && (
任务完成: {device.completedTasks}/{device.totalTasks}( {Math.round((device.completedTasks / device.totalTasks) * 100)}%)
)} {/* 标签 */} {device.tags && device.tags.length > 0 && (
{device.tags.map((tag) => ( {tag} ))}
)} {/* 位置和操作员 */} {(device.location || device.operator) && (
{device.location && (
{device.location}
)} {device.operator && 操作员: {device.operator}}
)}
) } // 设备列表内容 const DeviceListContent = () => (
列表视图 过滤器
已选择 {selected.length} / {Math.min(filteredDevices.length, maxSelection)} 个设备 {multiple && maxSelection < filteredDevices.length && ( (最多可选 {maxSelection} 个) )}
{multiple && ( )}
{loading ? (
正在加载设备列表...
) : filteredDevices.length === 0 ? (

未找到匹配的设备

) : ( <>
{paginatedDevices.map((device) => ( ))}
{/* 分页 */} {filteredDevices.length > devicesPerPage && (
第 {currentPage} / {Math.ceil(filteredDevices.length / devicesPerPage)} 页
)} )}
) // 对话框模式 if (dialogMode) { return ( <> {title}
) } // 内嵌模式 return ( <>

{title}

{filteredDevices.length} 个设备可用
{showNextButton && (
{onPrevious && ( )}
{onNext && ( )}
)}
) }