diff --git a/src/app/dashboard/components/gatewayConfig.tsx b/src/app/dashboard/components/gatewayConfig.tsx index 9f19e26..0351894 100644 --- a/src/app/dashboard/components/gatewayConfig.tsx +++ b/src/app/dashboard/components/gatewayConfig.tsx @@ -1,9 +1,9 @@ 'use client' -import { useEffect, useState, Suspense } from 'react' +import { useEffect, useState, Suspense, useCallback } from 'react' import { useSearchParams } from 'next/navigation' import { Table, TableHeader, TableBody, TableHead, TableRow, TableCell } from '@/components/ui/table' import { Pagination } from '@/components/ui/pagination' -import { getGatewayConfig, type GatewayConfig } from '@/actions/stats' +import { getGatewayInfo, getGatewayConfig, type GatewayConfig, type GatewayInfo } from '@/actions/stats' import { toast } from 'sonner' import { zodResolver } from '@hookform/resolvers/zod' import { useForm } from 'react-hook-form' @@ -11,15 +11,15 @@ import { z } from 'zod' import { Button } from '@/components/ui/button' import { Form, FormField, FormItem, FormLabel } from '@/components/ui/form' import { Input } from '@/components/ui/input' +import { cn } from '@/lib/utils' +import { Search } from 'lucide-react' function GatewayConfigContent() { const [data, setData] = useState([]) const [loading, setLoading] = useState(false) const searchParams = useSearchParams() - - // 分页状态 - const [page, setPage] = useState(1) - const [total, setTotal] = useState(0) + const [infoData, setInfoData] = useState([]) + const [totalCount, setTotalCount] = useState(0) // 定义表单验证规则 const filterSchema = z.object({ @@ -44,21 +44,80 @@ function GatewayConfigContent() { }) const { watch, handleSubmit: formHandleSubmit, setValue } = form const macaddrValue = watch('macaddr') - // 监听URL的mac参数变化 - useEffect(() => { - const urlMac = searchParams.get('mac') - if (urlMac) { - setValue('macaddr', urlMac) - setPage(1) - fetchData({ mac: urlMac }, 1) - } - else { - setValue('macaddr', '') - setPage(1) - fetchData({}, 1) - } - }, [searchParams, setValue]) + // 将线性数据转换为二维矩阵数据 + const transformToMatrix = (data: GatewayConfig[]) => { + // 按城市分组 + const cityGroups: { [city: string]: GatewayConfig[] } = {} + + data.forEach((item) => { + if (!item.city) return + if (!cityGroups[item.city]) { + cityGroups[item.city] = [] + } + cityGroups[item.city].push(item) + }) + + // 获取所有唯一的MAC地址(作为列) + const allMacAddresses = Array.from(new Set(data.map(item => item.edge).filter(Boolean))).sort() as string[] + + // 使用安全的类型定义 + interface MatrixRow { + city: string + devices: { [mac: string]: GatewayConfig | null } + } + + // 构建矩阵数据 + const matrixData: MatrixRow[] = Object.entries(cityGroups).map(([city, items]) => { + const devices: { [mac: string]: GatewayConfig | null } = {} + + // 初始化所有MAC地址为null + allMacAddresses.forEach((mac) => { + devices[mac] = null + }) + + // 填充有数据的MAC地址 + items.forEach((item) => { + if (item.edge) { + devices[item.edge] = item + } + }) + + return { + city, + devices, + } + }) + + return { + matrixData, + macAddresses: allMacAddresses, + } + } + + // 初始化调用 + useEffect(() => { + fetchData({}, 1) + gatewayData() + }, []) + + // 获取网关基本信息 + const gatewayData = async () => { + try { + const result = await getGatewayInfo() + if (!result.success) { + throw new Error(result.error || '查询网关信息失败') + } + setInfoData(result.data) + } + catch (error) { + console.error('Failed to fetch gateway info:', error) + } + finally { + setLoading(false) + } + } + // 网关配置数据 const fetchData = async (filters: { mac?: string public?: string @@ -84,7 +143,7 @@ function GatewayConfigContent() { }) setData(result.data.items) - setTotal(result.data.total) + setTotalCount(result.data.total) } catch (error) { toast.error((error as Error).message || '获取网关配置失败') @@ -95,7 +154,6 @@ function GatewayConfigContent() { } const onSubmit = (data: FilterFormValues) => { - setPage(1) const filters = { mac: data.macaddr || '', public: data.public || '', @@ -106,112 +164,102 @@ function GatewayConfigContent() { fetchData(filters, 1) } - // 处理页码变化 - const handlePageChange = (page: number) => { - setPage(page) - const formValues = form.getValues() - const filters = { - mac: formValues.macaddr || undefined, - public: formValues.public || undefined, - city: formValues.city || undefined, - user: formValues.user || undefined, - inner_ip: formValues.inner_ip || undefined, - } - fetchData(filters, page) - } - - // 处理每页显示数量变化 - const handleSizeChange = (size: number) => { - setPage(1) - const formValues = form.getValues() - const filters = { - mac: formValues.macaddr || undefined, - public: formValues.public || undefined, - city: formValues.city || undefined, - user: formValues.user || undefined, - inner_ip: formValues.inner_ip || undefined, - } - fetchData(filters, 1) - } - - const getStatusBadge = (value: number, trueText: string = '是', falseText: string = '否') => { - // 0是正常1是更新,正常(绿)+ 更新(红) - return ( - - {value === 0 ? trueText : falseText} - - ) - } - - const getOnlineStatus = (isonline: number) => { - // 0是空闲1是在用,在用(红)+ 空闲(绿) - return ( -
-
- {getStatusBadge(isonline, '空闲', '在用')} -
- ) - } + // 获取转换后的矩阵数据 + const { matrixData, macAddresses } = transformToMatrix(data) return (
{/* 查询表单 */} -
-
- -
- ( - - MAC地址 - - - )} - /> - ( - - IP地址 - - - )} - /> - ( - - 线路 - - - )} - /> - ( - - 端口号 - - - )} - /> - ( - - 城市 - - - )} - /> - +
+
+
+ + +
+ ( + +
+ + { + e.preventDefault() + onSubmit(form.getValues()) + }} + /> +
+
+ )} + /> +
+ + +
+
+
+ 在线 {infoData.filter(item => item.enable === 1).length} +
+
+
+ 离线 {infoData.filter(item => item.enable === 0).length} +
- - +
+
+
+
+ +
+ ( + + IP地址 + + + )} + /> + ( + + 线路 + + + )} + /> + ( + + 端口号 + + + )} + /> + ( + + 城市 + + + )} + /> + +
+
+ +
{loading ? ( @@ -221,75 +269,154 @@ function GatewayConfigContent() {
) : data.length > 0 ? ( <> + {/* 网关基本信息 */}
-
- - - - 端口 - 线路 - 城市 - 节点MAC - 节点IP - 配置更新 - 在用状态 - - - - {data.map((item, index) => ( - - {item.inner_ip} - {item.user} - {item.city} - {item.edge} - {item.public} - - {getStatusBadge(item.ischange, '正常', '更新')} - - - {getOnlineStatus(item.isonline)} - - - ))} - -
-
-
-
-
{total}
-
配置条数
-
-
-
- {data.filter(item => item.isonline === 1).length} +
+ {infoData.map((item, index) => ( +
+
+
+
{item.macaddr}
+
+
+ + {item.enable === 1 ? '在线' : '离线'} + +
+
+
+
+ {item.inner_ip || '未配置IP'} +
+
+
配置版本: {item.setid || 'N/A'}
+ {/*
+ 在用节点: {data.filter(d => d.isonline === 1).length} +
*/} +
-
在用节点
-
-
-
- {data.filter(item => item.ischange === 1).length} -
-
需要更新
-
+ ))}
-
- {/* 分页组件 */} -
-
- {!macaddrValue && ( - - )} + {/* 二维矩阵表格 */} +
+
+
+
+
+ 蓝色:在用 +
+
+
+ 绿色:空闲 +
+
+
+ 黄色:更新 +
+
+
+
+ 共 {totalCount} 条记录 +
+
+
+ +
+ + + + + 城市 + + {macAddresses.map((mac, index) => ( + + {mac} + + ))} + + + + {matrixData.map((row, rowIndex) => ( + + + {row.city} + + {macAddresses.map((mac, colIndex) => { + const item = row.devices[mac] + if (!item) { + return ( + +
-
+
+ ) + } + + // 状态颜色配置 + const statusConfig = { + ischange: item.ischange === 0 + ? { bg: 'bg-green-100', border: 'border-green-200', text: 'text-green-800', label: '正常' } + : { bg: 'bg-yellow-100', border: 'border-yellow-200', text: 'text-yellow-800', label: '更新' }, + isonline: item.isonline === 0 + ? { bg: 'bg-green-100', border: 'border-green-200', text: 'text-green-800', label: '空闲' } + : { bg: 'bg-blue-100', border: 'border-blue-200', text: 'text-blue-800', label: '在用' }, + } + + return ( + +
+
+ IP地址: + {item.public || 'N/A'} +
+
+ 线路: + {item.user || 'N/A'} +
+
+ 端口: + {item.inner_ip || 'N/A'} +
+
+ + {statusConfig.ischange.label} + + + {statusConfig.isonline.label} + +
+
+
+ ) + })} +
+ ))} +
+
+
-
) : ( diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index b801fe2..39761b5 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -10,7 +10,6 @@ import Settings from './components/settings' import Edge from './components/edge' import { LogOut } from 'lucide-react' import { logout } from '@/actions/auth' -import { toast } from 'sonner' const tabs = [ { id: 'gatewayInfo', label: '网关信息' },