51 lines
1.7 KiB
TypeScript
51 lines
1.7 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server'
|
||
import { prisma } from '@/lib/prisma'
|
||
import { withCors } from '@/lib/middleware'
|
||
import { Prisma } from '@prisma/client' // 为了 Prisma.sql / Prisma.join
|
||
|
||
async function handleTimeDistribution(req: NextRequest) {
|
||
try {
|
||
const pathSegments = req.nextUrl.pathname.split('/')
|
||
const hostnameIndex = pathSegments.indexOf('hosts') + 1
|
||
const hostname = pathSegments[hostnameIndex]
|
||
|
||
if (!hostname) {
|
||
return NextResponse.json({ error: '缺少主机名' }, { status: 400 })
|
||
}
|
||
|
||
const sp = req.nextUrl.searchParams
|
||
const fromParam = sp.get('from') // ISO,如 2025-09-01T00:00:00Z
|
||
const toParam = sp.get('to') // ISO
|
||
|
||
const whereParts: any[] = [Prisma.sql`"hostname" = ${hostname}`]
|
||
if (fromParam) whereParts.push(Prisma.sql`"timestamp" >= ${new Date(fromParam)}`)
|
||
if (toParam) whereParts.push(Prisma.sql`"timestamp" < ${new Date(toParam)}`)
|
||
|
||
const rows = await prisma.$queryRaw<
|
||
{ ts: bigint | number; count: number }[]
|
||
>(Prisma.sql`
|
||
SELECT
|
||
EXTRACT(EPOCH FROM date_trunc('hour', "timestamp"))::bigint AS ts,
|
||
COUNT(*)::int AS count
|
||
FROM "records"
|
||
WHERE ${Prisma.join(whereParts, ' AND ')}
|
||
GROUP BY 1
|
||
ORDER BY 1
|
||
`)
|
||
|
||
// JSON 不支持 BigInt,转成 number(秒级时间戳安全)
|
||
const distribution = rows.map(r => ({
|
||
timestamp: Number(r.ts),
|
||
count: r.count
|
||
}))
|
||
|
||
return NextResponse.json(
|
||
{ hostname, distribution },
|
||
)
|
||
} catch (error) {
|
||
console.error('获取时间分布统计失败:', error)
|
||
return NextResponse.json({ error: '获取时间分布统计失败' }, { status: 500 })
|
||
}
|
||
}
|
||
|
||
export const GET = withCors(handleTimeDistribution) |