超管后台 - 关联设备列表增加设备状态和微信状态筛选、还有数量排序

This commit is contained in:
柳清爽
2025-04-29 11:30:44 +08:00
parent 12e5b93a38
commit cd864763ee

View File

@@ -8,12 +8,14 @@ import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import { ArrowLeft, Edit } from "lucide-react" import { ArrowLeft, Edit, ArrowUp, ArrowDown, ArrowUpDown } from "lucide-react"
import { toast } from "sonner" import { toast } from "sonner"
import { use } from "react" import { use } from "react"
import Image from "next/image" import Image from "next/image"
import { Badge } from "@/components/ui/badge" import { Badge } from "@/components/ui/badge"
import { apiRequest } from '@/lib/api-utils' import { apiRequest } from '@/lib/api-utils'
import { Loader2 } from "lucide-react"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
interface ProjectProfile { interface ProjectProfile {
id: number id: number
@@ -69,6 +71,9 @@ export default function ProjectDetailPage({ params }: ProjectDetailPageProps) {
const [devices, setDevices] = useState<Device[]>([]) const [devices, setDevices] = useState<Device[]>([])
const [subUsers, setSubUsers] = useState<SubUser[]>([]) const [subUsers, setSubUsers] = useState<SubUser[]>([])
const [activeTab, setActiveTab] = useState("overview") const [activeTab, setActiveTab] = useState("overview")
const [sortOrder, setSortOrder] = useState<'asc' | 'desc' | null>(null)
const [deviceStatusFilter, setDeviceStatusFilter] = useState<'all' | 'online' | 'offline'>('all')
const [wechatStatusFilter, setWechatStatusFilter] = useState<'all' | 'loggedIn' | 'loggedOut' | 'notLogged'>('all')
const fetchProject = async () => { const fetchProject = async () => {
try { try {
@@ -92,17 +97,48 @@ export default function ProjectDetailPage({ params }: ProjectDetailPageProps) {
}, [id]) }, [id])
const fetchDevices = async () => { const fetchDevices = async () => {
if (activeTab !== "devices") return
setIsDevicesLoading(true)
try { try {
setIsDevicesLoading(true)
const result = await apiRequest(`/company/devices?companyId=${id}`) const result = await apiRequest(`/company/devices?companyId=${id}`)
if (result.code === 200 && result.data) {
setDevices(result.data) if (result.code === 200) {
let filteredDevices = result.data
// 应用设备状态筛选
if (deviceStatusFilter !== 'all') {
filteredDevices = filteredDevices.filter(device =>
deviceStatusFilter === 'online' ? device.alive === 1 : device.alive !== 1
)
}
// 应用微信状态筛选
if (wechatStatusFilter !== 'all') {
filteredDevices = filteredDevices.filter(device => {
if (wechatStatusFilter === 'loggedIn') return device.wAlive === 1
if (wechatStatusFilter === 'loggedOut') return device.wAlive === 0
return device.wAlive === -1
})
}
// 应用排序
if (sortOrder) {
filteredDevices = [...filteredDevices].sort((a, b) => {
const aCount = a.friendCount || 0
const bCount = b.friendCount || 0
return sortOrder === 'asc' ? aCount - bCount : bCount - aCount
})
}
setDevices(filteredDevices)
} else { } else {
toast.error(result.msg || "获取设备列表失败") toast.error(result.msg || "获取设备列表失败")
setDevices([])
} }
} catch (error) { } catch (error) {
console.error("获取设备列表失败:", error) toast.error("网络错误,请稍后重试")
toast.error("网络错误,请稍后再试") setDevices([])
} finally { } finally {
setIsDevicesLoading(false) setIsDevicesLoading(false)
} }
@@ -110,7 +146,7 @@ export default function ProjectDetailPage({ params }: ProjectDetailPageProps) {
useEffect(() => { useEffect(() => {
fetchDevices() fetchDevices()
}, [activeTab, id]) }, [activeTab, id, sortOrder, deviceStatusFilter, wechatStatusFilter])
useEffect(() => { useEffect(() => {
const fetchSubUsers = async () => { const fetchSubUsers = async () => {
@@ -133,6 +169,14 @@ export default function ProjectDetailPage({ params }: ProjectDetailPageProps) {
fetchSubUsers() fetchSubUsers()
}, [id]) }, [id])
const handleSort = () => {
setSortOrder(prev => {
if (prev === null) return 'desc'
if (prev === 'desc') return 'asc'
return null
})
}
if (isLoading) { if (isLoading) {
return <div className="flex items-center justify-center min-h-screen">...</div> return <div className="flex items-center justify-center min-h-screen">...</div>
} }
@@ -226,67 +270,111 @@ export default function ProjectDetailPage({ params }: ProjectDetailPageProps) {
</TabsContent> </TabsContent>
<TabsContent value="devices"> <TabsContent value="devices">
<Card> <div className="space-y-4">
<CardHeader> <div className="flex justify-between items-center">
<CardTitle></CardTitle> <h2 className="text-lg font-semibold"></h2>
<CardDescription></CardDescription> <div className="flex items-center gap-4">
</CardHeader> <div className="flex items-center gap-2">
<CardContent> <span className="text-sm text-muted-foreground"></span>
{isDevicesLoading ? ( <Select
<div className="flex items-center justify-center py-8">...</div> value={deviceStatusFilter}
) : devices.length === 0 ? ( onValueChange={(value: 'all' | 'online' | 'offline') => setDeviceStatusFilter(value)}
<div className="flex items-center justify-center py-8 text-muted-foreground"></div> >
) : ( <SelectTrigger className="w-[120px]">
<> <SelectValue placeholder="选择状态" />
<Table> </SelectTrigger>
<TableHeader> <SelectContent>
<TableRow> <SelectItem value="all"></SelectItem>
<TableHead></TableHead> <SelectItem value="online">线</SelectItem>
<TableHead></TableHead> <SelectItem value="offline">线</SelectItem>
<TableHead></TableHead> </SelectContent>
<TableHead>IMEI</TableHead> </Select>
<TableHead></TableHead> </div>
<TableHead></TableHead> <div className="flex items-center gap-2">
<TableHead className="text-right"></TableHead> <span className="text-sm text-muted-foreground"></span>
<Select
value={wechatStatusFilter}
onValueChange={(value: 'all' | 'loggedIn' | 'loggedOut' | 'notLogged') => setWechatStatusFilter(value)}
>
<SelectTrigger className="w-[120px]">
<SelectValue placeholder="选择状态" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all"></SelectItem>
<SelectItem value="loggedIn"></SelectItem>
<SelectItem value="loggedOut"></SelectItem>
<SelectItem value="notLogged"></SelectItem>
</SelectContent>
</Select>
</div>
<Button
variant="outline"
size="sm"
onClick={handleSort}
className="flex items-center gap-2"
>
<span></span>
{sortOrder === 'asc' && <ArrowUp className="h-4 w-4" />}
{sortOrder === 'desc' && <ArrowDown className="h-4 w-4" />}
{sortOrder === null && <ArrowUpDown className="h-4 w-4" />}
</Button>
</div>
</div>
{isDevicesLoading ? (
<div className="flex justify-center items-center h-32">
<Loader2 className="h-8 w-8 animate-spin" />
</div>
) : devices.length > 0 ? (
<div className="border rounded-lg">
<Table>
<TableHeader>
<TableRow>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead>IMEI</TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{devices.map((device) => (
<TableRow key={device.id}>
<TableCell>{device.memo}</TableCell>
<TableCell>{device.model}</TableCell>
<TableCell>{device.brand}</TableCell>
<TableCell>{device.imei}</TableCell>
<TableCell>
<Badge variant={device.alive === 1 ? "success" : "destructive"}>
{device.alive === 1 ? "在线" : "离线"}
</Badge>
</TableCell>
<TableCell>
<Badge
variant={
device.wAlive === 1
? "success"
: device.wAlive === 0
? "destructive"
: "secondary"
}
>
{device.wAlive === 1 ? "已登录" : device.wAlive === 0 ? "已登出" : "未登录微信"}
</Badge>
</TableCell>
<TableCell>{device.friendCount || 0}</TableCell>
</TableRow> </TableRow>
</TableHeader> ))}
<TableBody> </TableBody>
{devices.map((device) => ( </Table>
<TableRow key={device.id}> </div>
<TableCell className="font-medium">{device.memo}</TableCell> ) : (
<TableCell>{device.model}</TableCell> <div className="text-center py-8 text-muted-foreground">
<TableCell>{device.brand}</TableCell>
<TableCell>{device.imei}</TableCell> </div>
<TableCell> )}
<Badge variant={device.alive === 1 ? "success" : "destructive"}> </div>
{device.alive === 1 ? "在线" : "离线"}
</Badge>
</TableCell>
<TableCell>
<Badge
variant={
device.wAlive === 1
? "success"
: device.wAlive === 0
? "destructive"
: "secondary"
}
>
{device.wAlive === 1 ? "已登录" : device.wAlive === 0 ? "已登出" : "未登录微信"}
</Badge>
</TableCell>
<TableCell className="text-right">{device.friendCount || 0}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
<div className="mt-4 text-sm text-muted-foreground">
{devices.length}
</div>
</>
)}
</CardContent>
</Card>
</TabsContent> </TabsContent>
<TabsContent value="accounts"> <TabsContent value="accounts">