From 0288855002007c6847ca4e03a1e599243f2a7ceb Mon Sep 17 00:00:00 2001 From: wmp <17516219072@163.com> Date: Mon, 22 Sep 2025 18:40:41 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BD=91=E5=85=B3=E9=85=8D=E7=BD=AE=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=88=86=E9=A1=B5=E5=8A=9F=E8=83=BD&=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E5=88=86=E9=85=8D=E8=A3=85=E5=A1=AB=E5=B8=83=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/api/stats/route.ts | 79 +++++- .../dashboard/components/allocationStatus.tsx | 13 +- .../dashboard/components/gatewayConfig.tsx | 231 +++++++++--------- src/app/dashboard/components/gatewayinfo.tsx | 6 - 4 files changed, 192 insertions(+), 137 deletions(-) diff --git a/src/app/api/stats/route.ts b/src/app/api/stats/route.ts index 1218774..93aaf18 100644 --- a/src/app/api/stats/route.ts +++ b/src/app/api/stats/route.ts @@ -54,17 +54,76 @@ async function getGatewayInfo() { async function getGatewayConfig(request: NextRequest) { try { const { searchParams } = new URL(request.url) - const macAddress = searchParams.get('mac') || '000C29DF1647' + const macAddress = searchParams.get('mac') || '' + const offset = parseInt(searchParams.get('offset') || '0') + const limit = parseInt(searchParams.get('limit') || '100') - // 使用参数化查询防止SQL注入 - const result = await prisma.$queryRaw` - SELECT edge, city, user, public, inner_ip, ischange, isonline - FROM gateway - LEFT JOIN cityhash ON cityhash.hash = gateway.cityhash - LEFT JOIN edge ON edge.macaddr = gateway.edge - WHERE gateway.macaddr = ${macAddress}; - ` - return NextResponse.json(safeSerialize(result)) + // 定义类型接口 + interface GatewayRecord { + edge: string | null; + city: string | null; + user: string | null; + public: string | null; + inner_ip: string | null; + ischange: boolean | number | null; + isonline: boolean | number | null; + } + + // 获取总数 + let totalCountQuery = '' + let totalCountParams: (string | number)[] = [] + + if (macAddress) { + totalCountQuery = ` + SELECT COUNT(*) as total + FROM gateway + LEFT JOIN cityhash ON cityhash.hash = gateway.cityhash + LEFT JOIN edge ON edge.macaddr = gateway.edge + WHERE gateway.macaddr = ? + ` + totalCountParams = [macAddress] + } else { + totalCountQuery = ` + SELECT COUNT(*) as total + FROM gateway + ` + } + + const totalCountResult = await prisma.$queryRawUnsafe<[{ total: bigint }]>( + totalCountQuery, + ...totalCountParams + ) + const totalCount = Number(totalCountResult[0]?.total || 0) + + // 获取分页数据 + let query = ` + select edge, city, user, public, inner_ip, ischange, isonline + from + gateway + left join cityhash + on cityhash.hash = gateway.cityhash + left join edge + on edge.macaddr = gateway.edge + ` + let params: (string | number)[] = [] + + if (macAddress) { + query += ' WHERE gateway.macaddr = ?' + params = [macAddress] + } else { + query += ' LIMIT ? OFFSET ?' + params.push(limit, offset) + } + + // 指定返回类型 + const result = await prisma.$queryRawUnsafe(query, ...params) + + return NextResponse.json({ + data: safeSerialize(result), + totalCount: totalCount, + currentPage: Math.floor(offset / limit) + 1, + totalPages: Math.ceil(totalCount / limit) + }) } catch (error) { console.error('Gateway config query error:', error) return NextResponse.json({ error: '查询网关配置失败' }, { status: 500 }) diff --git a/src/app/dashboard/components/allocationStatus.tsx b/src/app/dashboard/components/allocationStatus.tsx index accdcca..a68ef06 100644 --- a/src/app/dashboard/components/allocationStatus.tsx +++ b/src/app/dashboard/components/allocationStatus.tsx @@ -127,7 +127,7 @@ export default function AllocationStatus({ detailed = false }: { detailed?: bool
-
+
@@ -159,17 +159,6 @@ export default function AllocationStatus({ detailed = false }: { detailed?: bool
- -
-
-
{formatNumber(data.length)}
-
监控城市数量
-
-
-
{formatNumber(problematicCities.length)}
-
需关注城市
-
-
) diff --git a/src/app/dashboard/components/gatewayConfig.tsx b/src/app/dashboard/components/gatewayConfig.tsx index c2115b5..bbe9bdc 100644 --- a/src/app/dashboard/components/gatewayConfig.tsx +++ b/src/app/dashboard/components/gatewayConfig.tsx @@ -2,9 +2,9 @@ import { useEffect, useState, Suspense } from 'react' import { useSearchParams } from 'next/navigation' import { Table, TableHeader, TableBody, TableHead, TableRow, TableCell } from '@/components/ui/table' +import { Pagination } from '@/components/ui/pagination' interface GatewayConfig { - id: number city: string edge: string user: string @@ -14,79 +14,83 @@ interface GatewayConfig { isonline: number } +interface ApiResponse { + data: GatewayConfig[] + totalCount: number + currentPage: number + totalPages: number +} + function GatewayConfigContent() { const [data, setData] = useState([]) const [loading, setLoading] = useState(false) const [macAddress, setMacAddress] = useState('') const [error, setError] = useState('') - const [success, setSuccess] = useState('') const searchParams = useSearchParams() + + // 分页状态 + const [currentPage, setCurrentPage] = useState(1) + const [itemsPerPage, setItemsPerPage] = useState(100) + const [totalItems, setTotalItems] = useState(0) - // 监听URL的mac参数变化:同步到输入框并触发查询 + // 判断是否为MAC地址查询(用于控制分页显示) + const isMacQuery = !!macAddress + + // 监听URL的mac参数变化 useEffect(() => { const urlMac = searchParams.get('mac') if (urlMac) { - setMacAddress(urlMac) - fetchData(urlMac) + setMacAddress(urlMac) + setCurrentPage(1) // 重置到第一页 + fetchData(urlMac, 1, itemsPerPage) } else { - // 如果没有mac参数,显示所有网关配置 setMacAddress('') - fetchData('') + setCurrentPage(1) // 重置到第一页 + fetchData('', 1, itemsPerPage) } }, [searchParams]) - const fetchData = async (mac: string) => { + const fetchData = async (mac: string, page: number = 1, limit: number = itemsPerPage) => { setLoading(true) setError('') - setSuccess('') try { - // 构建API URL - 如果有MAC地址则添加参数,否则获取全部 - const apiUrl = mac.trim() - ? `/api/stats?type=gateway_config&mac=${encodeURIComponent(mac)}` - : `/api/stats?type=gateway_config` + // 计算偏移量 + const offset = (page - 1) * limit - const response = await fetch(apiUrl) - const result = await response.json() - - if (!response.ok) { - throw new Error(result.error || '查询失败') + // 构建API URL + let apiUrl = `/api/stats?type=gateway_config&offset=${offset}&limit=${limit}` + if (mac.trim()) { + apiUrl += `&mac=${encodeURIComponent(mac)}` } + const response = await fetch(apiUrl) + if (!response.ok) { + throw new Error(`HTTP错误! 状态: ${response.status}`) + } + + const result: ApiResponse = await response.json() + // 检查返回的数据是否有效 - if (!result || result.length === 0) { + if (!result.data || result.data.length === 0) { if (mac.trim()) { setError(`未找到MAC地址为 ${mac} 的网关配置信息`) } else { setError('未找到任何网关配置信息') } setData([]) + setTotalItems(0) return } - const validatedData = result.map((item: { - city: string - edge: string - user: string - public: string - inner_ip: string - ischange: number - isonline: number - }) => ({ - city: item.city, - edge: item.edge, - user: item.user, - public: item.public, - inner_ip: item.inner_ip, - ischange: item.ischange, - isonline: item.isonline, - })) + setData(result.data) - setData(validatedData) + setTotalItems(result.totalCount || 0) } catch (error) { - console.error('Failed to fetch gateway config:', error) + console.error('获取网关配置失败:', error) setError(error instanceof Error ? error.message : '获取网关配置失败') setData([]) + setTotalItems(0) } finally { setLoading(false) } @@ -94,7 +98,21 @@ function GatewayConfigContent() { const handleSubmit = (e: React.FormEvent) => { e.preventDefault() - fetchData(macAddress) + setCurrentPage(1) // 重置到第一页 + fetchData(macAddress, 1, itemsPerPage) + } + + // 处理页码变化 + const handlePageChange = (page: number) => { + setCurrentPage(page) + fetchData(macAddress, page, itemsPerPage) + } + + // 处理每页显示数量变化 + const handleSizeChange = (size: number) => { + setItemsPerPage(size) + setCurrentPage(1) + fetchData(macAddress, 1, size) } const getStatusBadge = (value: number, trueText: string = '是', falseText: string = '否') => { @@ -128,7 +146,7 @@ function GatewayConfigContent() { {/* 查询表单 */}
-
+
)} - - {success && !error && ( -
-
- - - - {success} -
-
- )} {loading ? ( @@ -174,80 +181,86 @@ function GatewayConfigContent() {
) : data.length > 0 ? ( <> - {/* 详细表格 */} -
-
- - - - MAC地址 - 城市 - 内部账号 - IP地址 - 内网入口 - 配置更新 - 在用状态 - - - - {data.map((item, index) => ( - - -
{item.edge}
-
- +
+
+
+ + + 城市 + MAC地址 + IP地址 + 线路 + 端口 + 配置更新 + 在用状态 + + + + {data.map((item, index) => ( + + {item.city} - - {item.user} - -
{item.public}
-
- -
{item.inner_ip}
-
- -
{getStatusBadge(item.ischange, '正常', '更新')}
-
- -
{getOnlineStatus(item.isonline)}
-
-
- ))} -
-
-
-
-
-
{data.length}
-
网关数量
+ + + +
{item.edge}
+
+ +
{item.public}
+
+ {item.user} + +
{item.inner_ip}
+
+ + {getStatusBadge(item.ischange, '正常', '更新')} + + + {getOnlineStatus(item.isonline)} + + + ))} + + +
+
+
+
{totalItems}
+
配置条数
{data.filter(item => item.isonline === 1).length}
-
在线网关
+
在用节点
{data.filter(item => item.ischange === 1).length}
-
已更新配置
-
-
-
- {new Set(data.map(item => item.city)).size} -
-
覆盖城市
+
需要更新
+
-
+ + {/* 分页组件 - 仅在非MAC查询时显示 */} + {!isMacQuery && ( + + )} ) : ( - <> +
+
📋
+

暂无网关配置数据

+
)} ) diff --git a/src/app/dashboard/components/gatewayinfo.tsx b/src/app/dashboard/components/gatewayinfo.tsx index 0059229..281e242 100644 --- a/src/app/dashboard/components/gatewayinfo.tsx +++ b/src/app/dashboard/components/gatewayinfo.tsx @@ -213,12 +213,6 @@ useEffect(() => {
禁用网关
-
-
- {new Set(data.map(item => item.setid)).size} -
-
配置版本数
-