修复分配状态里的时间筛选查询问题

This commit is contained in:
wmp
2025-09-22 10:31:49 +08:00
parent 4f3671c8a6
commit 826d8fc4c3
3 changed files with 55 additions and 78 deletions

View File

@@ -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'

View File

@@ -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>

View File

@@ -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>
{/* 查询表单 */} {/* 查询表单 */}