修复分配状态里的时间筛选查询问题
This commit is contained in:
@@ -23,7 +23,7 @@ export async function GET(request: NextRequest) {
|
|||||||
case 'city_node_count':
|
case 'city_node_count':
|
||||||
return await getCityNodeCount()
|
return await getCityNodeCount()
|
||||||
case 'allocation_status':
|
case 'allocation_status':
|
||||||
return await getAllocationStatus()
|
return await getAllocationStatus(request)
|
||||||
case 'edge_nodes':
|
case 'edge_nodes':
|
||||||
return await getEdgeNodes(request)
|
return await getEdgeNodes(request)
|
||||||
default:
|
default:
|
||||||
@@ -105,42 +105,47 @@ async function getCityNodeCount() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 城市分配状态
|
// 城市分配状态
|
||||||
async function getAllocationStatus() {
|
async function getAllocationStatus(request: NextRequest) {
|
||||||
try {
|
try {
|
||||||
|
const { searchParams } = new URL(request.url)
|
||||||
|
const hours = searchParams.get('hours') || '24'
|
||||||
|
const hoursNum = parseInt(hours) || 24
|
||||||
|
|
||||||
// 使用参数化查询防止SQL注入
|
// 使用参数化查询防止SQL注入
|
||||||
const result = await prisma.$queryRaw`
|
const result = await prisma.$queryRaw`
|
||||||
SELECT
|
SELECT
|
||||||
city,
|
city,
|
||||||
c1.count AS count,
|
c1.count AS count,
|
||||||
c2.assigned AS assigned
|
c2.assigned AS assigned
|
||||||
FROM
|
FROM
|
||||||
cityhash
|
cityhash
|
||||||
LEFT JOIN (
|
LEFT JOIN (
|
||||||
SELECT
|
SELECT
|
||||||
city_id,
|
city_id,
|
||||||
COUNT(*) AS count
|
COUNT(*) AS count
|
||||||
FROM
|
FROM
|
||||||
edge
|
edge
|
||||||
WHERE
|
WHERE
|
||||||
active = 1
|
active = 1
|
||||||
GROUP BY
|
GROUP BY
|
||||||
city_id
|
city_id
|
||||||
) c1 ON c1.city_id = cityhash.id
|
) c1 ON c1.city_id = cityhash.id
|
||||||
LEFT JOIN (
|
LEFT JOIN (
|
||||||
SELECT
|
SELECT
|
||||||
city AS city_id,
|
city AS city_id,
|
||||||
COUNT(*) AS assigned
|
COUNT(*) AS assigned
|
||||||
FROM
|
FROM
|
||||||
\`change\`
|
\`change\`
|
||||||
WHERE
|
WHERE
|
||||||
time > NOW() - INTERVAL 1 DAY
|
time > NOW() - INTERVAL ${hoursNum} HOUR
|
||||||
GROUP BY
|
GROUP BY
|
||||||
city
|
city
|
||||||
) c2 ON c2.city_id = cityhash.id
|
) c2 ON c2.city_id = cityhash.id
|
||||||
WHERE
|
WHERE
|
||||||
cityhash.macaddr IS NOT NULL;
|
cityhash.macaddr IS NOT NULL;
|
||||||
`
|
`
|
||||||
return NextResponse.json(safeSerialize(result))
|
return NextResponse.json(safeSerialize(result))
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Allocation status query error:', error)
|
console.error('Allocation status query error:', error)
|
||||||
const errorMessage = error instanceof Error ? error.message : 'Unknown error'
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error'
|
||||||
|
|||||||
@@ -23,49 +23,19 @@ export default function AllocationStatus({ detailed = false }: { detailed?: bool
|
|||||||
const [data, setData] = useState<AllocationStatus[]>([])
|
const [data, setData] = useState<AllocationStatus[]>([])
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
const [error, setError] = useState<string | null>(null)
|
const [error, setError] = useState<string | null>(null)
|
||||||
const [timeFilter, setTimeFilter] = useState('24h') // 默认24小时
|
const [timeFilter, setTimeFilter] = useState('24') // 默认24小时
|
||||||
const [customTime, setCustomTime] = useState('')
|
const [customHours, setCustomHours] = useState('')
|
||||||
|
|
||||||
// 生成时间筛选条件
|
// 获取时间参数(小时数)
|
||||||
const getTimeCondition = useCallback(() => {
|
const getTimeHours = useCallback(() => {
|
||||||
if (timeFilter === 'custom' && customTime) {
|
|
||||||
// 将datetime-local格式转换为SQL datetime格式
|
|
||||||
return customTime.replace('T', ' ') + ':00'
|
|
||||||
}
|
|
||||||
const now = new Date()
|
|
||||||
let filterDate
|
|
||||||
|
|
||||||
switch(timeFilter) {
|
if (timeFilter === 'custom' && customHours) {
|
||||||
case '1h':
|
const hours = parseInt(customHours)
|
||||||
filterDate = new Date(now.getTime() - 60 * 60 * 1000)
|
return isNaN(hours) ? 24 : Math.max(1, hours) // 默认24小时,最少1小时
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return filterDate.toISOString().slice(0, 19).replace('T', ' ')
|
return parseInt(timeFilter) || 24 // 默认24小时
|
||||||
}, [timeFilter, customTime])
|
}, [timeFilter, customHours])
|
||||||
|
|
||||||
// 计算超额量
|
// 计算超额量
|
||||||
const calculateOverage = (assigned: number, count: number) => {
|
const calculateOverage = (assigned: number, count: number) => {
|
||||||
@@ -78,8 +48,9 @@ export default function AllocationStatus({ detailed = false }: { detailed?: bool
|
|||||||
setError(null)
|
setError(null)
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
|
|
||||||
const timeCondition = getTimeCondition()
|
const hours = getTimeHours()
|
||||||
const response = await fetch(`/api/stats?type=allocation_status&time=${encodeURIComponent(timeCondition)}`)
|
|
||||||
|
const response = await fetch(`/api/stats?type=allocation_status&hours=${hours}`)
|
||||||
|
|
||||||
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`)
|
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`)
|
||||||
|
|
||||||
@@ -101,7 +72,7 @@ export default function AllocationStatus({ detailed = false }: { detailed?: bool
|
|||||||
} finally {
|
} finally {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
}, [getTimeCondition])
|
}, [getTimeHours])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchData()
|
fetchData()
|
||||||
@@ -124,23 +95,26 @@ export default function AllocationStatus({ detailed = false }: { detailed?: bool
|
|||||||
onChange={(e) => setTimeFilter(e.target.value)}
|
onChange={(e) => setTimeFilter(e.target.value)}
|
||||||
className="border rounded p-2"
|
className="border rounded p-2"
|
||||||
>
|
>
|
||||||
<option value="1h">最近1小时</option>
|
<option value="1">最近1小时</option>
|
||||||
<option value="6h">最近6小时</option>
|
<option value="6">最近6小时</option>
|
||||||
<option value="12h">最近12小时</option>
|
<option value="12">最近12小时</option>
|
||||||
<option value="24h">最近24小时</option>
|
<option value="24">最近24小时</option>
|
||||||
<option value="7d">最近7天</option>
|
<option value="168">最近7天</option>
|
||||||
<option value="custom">自定义时间</option>
|
<option value="custom">自定义小时</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
{timeFilter === 'custom' && (
|
{timeFilter === 'custom' && (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<input
|
<input
|
||||||
type="datetime-local"
|
type="number"
|
||||||
value={customTime}
|
min="1"
|
||||||
onChange={(e) => setCustomTime(e.target.value)}
|
max="720"
|
||||||
className="border rounded p-2"
|
value={customHours}
|
||||||
|
onChange={(e) => setCustomHours(e.target.value)}
|
||||||
|
placeholder="输入小时数"
|
||||||
|
className="border rounded p-2 w-24"
|
||||||
/>
|
/>
|
||||||
<small>格式: YYYY-MM-DDTHH:MM</small>
|
<small>小时 (1-720)</small>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -151,6 +125,7 @@ export default function AllocationStatus({ detailed = false }: { detailed?: bool
|
|||||||
查询
|
查询
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='flex gap-6 overflow-hidden'>
|
<div className='flex gap-6 overflow-hidden'>
|
||||||
<div className="flex flex-3 w-full">
|
<div className="flex flex-3 w-full">
|
||||||
<Table>
|
<Table>
|
||||||
|
|||||||
@@ -127,9 +127,6 @@ function GatewayConfigContent() {
|
|||||||
<h2 className="text-xl font-semibold text-gray-800">网关配置状态</h2>
|
<h2 className="text-xl font-semibold text-gray-800">网关配置状态</h2>
|
||||||
<p className="text-sm text-gray-600 mt-1">查询和管理网关设备的配置信息</p>
|
<p className="text-sm text-gray-600 mt-1">查询和管理网关设备的配置信息</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-gray-500">
|
|
||||||
更新时间: {new Date().toLocaleTimeString()}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 查询表单 */}
|
{/* 查询表单 */}
|
||||||
|
|||||||
Reference in New Issue
Block a user