diff --git a/src/app/api/stats/route.ts b/src/app/api/stats/route.ts index 4953426..7db30ab 100644 --- a/src/app/api/stats/route.ts +++ b/src/app/api/stats/route.ts @@ -23,7 +23,7 @@ export async function GET(request: NextRequest) { case 'city_node_count': return await getCityNodeCount() case 'allocation_status': - return await getAllocationStatus() + return await getAllocationStatus(request) case 'edge_nodes': return await getEdgeNodes(request) default: @@ -105,42 +105,47 @@ async function getCityNodeCount() { } // 城市分配状态 -async function getAllocationStatus() { +async function getAllocationStatus(request: NextRequest) { try { + const { searchParams } = new URL(request.url) + const hours = searchParams.get('hours') || '24' + const hoursNum = parseInt(hours) || 24 + // 使用参数化查询防止SQL注入 const result = await prisma.$queryRaw` - SELECT + SELECT city, c1.count AS count, c2.assigned AS assigned FROM cityhash LEFT JOIN ( - SELECT - city_id, - COUNT(*) AS count - FROM - edge - WHERE - active = 1 - GROUP BY - city_id + SELECT + city_id, + COUNT(*) AS count + FROM + edge + WHERE + active = 1 + GROUP BY + city_id ) c1 ON c1.city_id = cityhash.id LEFT JOIN ( - SELECT - city AS city_id, - COUNT(*) AS assigned - FROM - \`change\` - WHERE - time > NOW() - INTERVAL 1 DAY - GROUP BY - city + SELECT + city AS city_id, + COUNT(*) AS assigned + FROM + \`change\` + WHERE + time > NOW() - INTERVAL ${hoursNum} HOUR + GROUP BY + city ) c2 ON c2.city_id = cityhash.id WHERE cityhash.macaddr IS NOT NULL; - ` + ` return NextResponse.json(safeSerialize(result)) + } catch (error) { console.error('Allocation status query error:', error) const errorMessage = error instanceof Error ? error.message : 'Unknown error' diff --git a/src/app/dashboard/components/allocationStatus.tsx b/src/app/dashboard/components/allocationStatus.tsx index cd463ea..accdcca 100644 --- a/src/app/dashboard/components/allocationStatus.tsx +++ b/src/app/dashboard/components/allocationStatus.tsx @@ -23,49 +23,19 @@ export default function AllocationStatus({ detailed = false }: { detailed?: bool const [data, setData] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) - const [timeFilter, setTimeFilter] = useState('24h') // 默认24小时 - const [customTime, setCustomTime] = useState('') + const [timeFilter, setTimeFilter] = useState('24') // 默认24小时 + const [customHours, setCustomHours] = useState('') - // 生成时间筛选条件 - const getTimeCondition = useCallback(() => { - if (timeFilter === 'custom' && customTime) { - // 将datetime-local格式转换为SQL datetime格式 - return customTime.replace('T', ' ') + ':00' - } - const now = new Date() - let filterDate + // 获取时间参数(小时数) + const getTimeHours = useCallback(() => { - switch(timeFilter) { - case '1h': - filterDate = new Date(now.getTime() - 60 * 60 * 1000) - break - case '6h': - filterDate = new Date(now.getTime() - 6 * 60 * 60 * 1000) - break - case '12h': - filterDate = new Date(now.getTime() - 12 * 60 * 60 * 1000) - break - case '24h': - filterDate = new Date(now.getTime() - 24 * 60 * 60 * 1000) - break - case '7d': - filterDate = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000) - break - case 'fixed': - return '2025-08-24 11:27:00' - case 'custom': - if (customTime) { - return customTime - } - // 如果自定义时间为空,默认使用24小时 - filterDate = new Date(now.getTime() - 24 * 60 * 60 * 1000) - break - default: - filterDate = new Date(now.getTime() - 24 * 60 * 60 * 1000) + if (timeFilter === 'custom' && customHours) { + const hours = parseInt(customHours) + return isNaN(hours) ? 24 : Math.max(1, hours) // 默认24小时,最少1小时 } - return filterDate.toISOString().slice(0, 19).replace('T', ' ') - }, [timeFilter, customTime]) + return parseInt(timeFilter) || 24 // 默认24小时 + }, [timeFilter, customHours]) // 计算超额量 const calculateOverage = (assigned: number, count: number) => { @@ -78,8 +48,9 @@ export default function AllocationStatus({ detailed = false }: { detailed?: bool setError(null) setLoading(true) - const timeCondition = getTimeCondition() - const response = await fetch(`/api/stats?type=allocation_status&time=${encodeURIComponent(timeCondition)}`) + const hours = getTimeHours() + + const response = await fetch(`/api/stats?type=allocation_status&hours=${hours}`) if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`) @@ -101,7 +72,7 @@ export default function AllocationStatus({ detailed = false }: { detailed?: bool } finally { setLoading(false) } - }, [getTimeCondition]) + }, [getTimeHours]) useEffect(() => { fetchData() @@ -124,23 +95,26 @@ export default function AllocationStatus({ detailed = false }: { detailed?: bool onChange={(e) => setTimeFilter(e.target.value)} className="border rounded p-2" > - - - - - - + + + + + + {timeFilter === 'custom' && (
setCustomTime(e.target.value)} - className="border rounded p-2" + type="number" + min="1" + max="720" + value={customHours} + onChange={(e) => setCustomHours(e.target.value)} + placeholder="输入小时数" + className="border rounded p-2 w-24" /> - 格式: YYYY-MM-DDTHH:MM + 小时 (1-720)
)} @@ -151,6 +125,7 @@ export default function AllocationStatus({ detailed = false }: { detailed?: bool 查询 +
diff --git a/src/app/dashboard/components/gatewayConfig.tsx b/src/app/dashboard/components/gatewayConfig.tsx index 889d675..7b7235e 100644 --- a/src/app/dashboard/components/gatewayConfig.tsx +++ b/src/app/dashboard/components/gatewayConfig.tsx @@ -127,9 +127,6 @@ function GatewayConfigContent() {

网关配置状态

查询和管理网关设备的配置信息

-
- 更新时间: {new Date().toLocaleTimeString()} -
{/* 查询表单 */}