Files
jh-monitor/src/app/(root)/gatewayMonitor/page.tsx

160 lines
5.9 KiB
TypeScript

'use client'
import { useEffect, useState, Suspense } from 'react'
import { Table, TableHeader, TableBody, TableHead, TableRow, TableCell } from '@/components/ui/table'
import { getGatewayInfo, getGatewayConfig, type GatewayConfig, type GatewayInfo } from '@/actions/stats'
import { toast } from 'sonner'
import { Page } from '@/components/page'
export default function GatewayConfigs() {
const [gateways, setGateways] = useState<Map<string, GatewayInfo>>(new Map())
const [data, setData] = useState<Map<string, Map<string, GatewayConfig | undefined>>>(new Map())
// 初始化数据
const initData = async () => {
const now = Date.now()
try {
// 固定端口信息
const slots = new Set<string>()
for (let i = 2; i <= 251; i++) {
slots.add(`172.30.168.${i}`)
}
// 获取网关信息
const resp = await getGatewayInfo()
if (!resp.success) {
throw new Error(`查询网关信息失败:${resp.error}`)
}
const gateways = resp.data
const findGateways = gateways.reduce((map, gateway) => {
map.set(gateway.macaddr, gateway)
return map
}, new Map<string, GatewayInfo>())
setGateways(findGateways)
// 获取网关配置
const data = new Map<string, Map<string, GatewayConfig | undefined>>()
for (const slot of slots) {
data.set(slot, new Map<string, GatewayConfig>())
}
await Promise.all(gateways.map((gateway, index) => {
return new Promise<void>(async (resolve) => {
const resp = await getGatewayConfig(1, { mac: gateway.macaddr })
if (!resp.success) {
throw new Error(`查询网关 ${gateway.inner_ip} 配置失败:${resp.error}`)
}
const configs = resp.data.items
const findConfig = configs.reduce((map, config) => {
map.set(config.inner_ip, config)
return map
}, new Map<string, GatewayConfig>())
for (const slot of slots) {
data.get(slot)!.set(gateway.macaddr, findConfig.get(slot))
}
resolve()
})
}))
setData(data)
}
catch (error) {
toast.error(`初始化页面数据失败:${(error as Error).message}`)
}
console.log('初始化数据耗时', Date.now() - now, 'ms')
}
useEffect(() => {
initData()
}, [])
return (
<Page className="gap-3">
<div className="flex gap-2">
<div className="flex items-center">
<div className="w-3 h-3 bg-green-500 rounded-full mr-2"></div>
<span className="text-sm font-medium">线 {Array.from(gateways.values()).filter(item => item.enable).length}</span>
</div>
<div className="flex items-center">
<div className="w-3 h-3 bg-red-500 rounded-full mr-2"></div>
<span className="text-sm font-medium">线 {Array.from(gateways.values()).filter(item => !item.enable).length}</span>
</div>
</div>
<Table>
<TableHeader>
<TableRow>
<TableHead className="border-r sticky left-0 bg-gray-50"></TableHead>
{gateways.values().map((pair, index) => (
<TableHead key={index} className="border-r h-auto">
<div className="flex flex-col items-center">
<div className="font-medium">{pair.inner_ip}</div>
<div className="text-xs text-gray-500 mt-1">{pair.macaddr}</div>
</div>
</TableHead>
)).toArray()}
</TableRow>
</TableHeader>
<TableBody>
{data.entries().map(([slot, configs], rowIndex) => (
<TableRow key={rowIndex}>
<TableCell className="border-r sticky left-0 bg-background">{slot}</TableCell>
{configs.entries().map(([_, config], colIndex) => {
if (!config) {
return (
<TableCell key={colIndex} className="not-last:border-r">
-
</TableCell>
)
}
const statusConfig = {
ischange: config.ischange === 0
? { bg: 'bg-green-100', text: 'text-green-800', label: '正常' }
: { bg: 'bg-yellow-100', text: 'text-yellow-800', label: '更新' },
isonline: config.isonline === 0
? { bg: 'bg-green-100', text: 'text-green-800', label: '空闲' }
: { bg: 'bg-blue-100', text: 'text-blue-800', label: '在用' },
}
return (
<TableCell key={`${colIndex}`} className="not-last:border-r">
<div key={colIndex} className="flex flex-col gap-1">
<div className="text-sm font-medium">{config.public}</div>
<div className="text-xs font-medium flex justify-between">
<span>{config.user}</span>
<span>{shrinkCity(config.city || '?')}</span>
</div>
<div className="flex justify-between items-center">
<span className={`px-2 py-0.5 rounded text-xs font-medium ${statusConfig.ischange.bg} ${statusConfig.ischange.text}`}>
{statusConfig.ischange.label}
</span>
<span className={`px-2 py-0.5 rounded text-xs font-medium ${statusConfig.isonline.bg} ${statusConfig.isonline.text}`}>
{statusConfig.isonline.label}
</span>
</div>
</div>
</TableCell>
)
}).toArray()}
</TableRow>
)).toArray()}
</TableBody>
</Table>
</Page>
)
}
function shrinkCity(city: string) {
switch (city) {
case '黔东南苗族侗族自治州':
return '黔东南'
case '延边朝鲜族自治州':
return '延边'
default:
return city
}
}