import { NextRequest, NextResponse } from "next/server"; import { db } from "@/lib/db"; import { generatedImage, user } from "@/lib/db/schema"; import { eq, sql, desc, count, and, gte, lt } from "drizzle-orm"; import { auth } from "@/app/(auth)/auth"; export async function GET(request: NextRequest) { try { const session = await auth(); if (!session?.user?.id) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } // 检查是否为管理员 const currentUser = await db.query.user.findFirst({ where: eq(user.id, session.user.id), }); if (currentUser?.role !== "admin") { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } // 获取查询参数 const searchParams = request.nextUrl.searchParams; const month = searchParams.get("month"); // 格式: YYYY-MM const selectedDate = searchParams.get("date"); // 格式: YYYY-MM-DD,用于高峰时段筛选 // 1. 总体统计 const totalStats = await db .select({ totalImages: sql`count(*)::int`, totalUsers: sql`count(distinct ${generatedImage.userId})::int`, }) .from(generatedImage); // 2. 按用户统计(Top 20) const userStats = await db .select({ userId: generatedImage.userId, userName: user.name, userEmail: user.email, imageCount: sql`count(*)::int`, }) .from(generatedImage) .leftJoin(user, eq(generatedImage.userId, user.id)) .groupBy(generatedImage.userId, user.name, user.email) .orderBy(desc(sql`count(*)`)) .limit(20); // 3. 按日期统计(最近30天) const dailyStats = await db .select({ date: sql`date(${generatedImage.createdAt})::text`, count: sql`count(*)::int`, }) .from(generatedImage) .where(sql`${generatedImage.createdAt} >= now() - interval '30 days'`) .groupBy(sql`date(${generatedImage.createdAt})`) .orderBy(sql`date(${generatedImage.createdAt})`); // 4. 按图片尺寸统计 const sizeStats = await db .select({ imageSize: generatedImage.imageSize, count: sql`count(*)::int`, }) .from(generatedImage) .groupBy(generatedImage.imageSize) .orderBy(desc(sql`count(*)`)); // 5. 按模型统计 const modelStats = await db .select({ modelId: generatedImage.modelId, count: sql`count(*)::int`, }) .from(generatedImage) .groupBy(generatedImage.modelId) .orderBy(desc(sql`count(*)`)) .limit(10); // 6. 按月份统计 const monthlyStats = await db .select({ month: sql`to_char(${generatedImage.createdAt}, 'YYYY-MM')`, count: sql`count(*)::int`, }) .from(generatedImage) .groupBy(sql`to_char(${generatedImage.createdAt}, 'YYYY-MM')`) .orderBy(sql`to_char(${generatedImage.createdAt}, 'YYYY-MM')`); // 7. 按小时统计(用于分析高峰时段,支持按日期筛选) let hourlyWhereClause = undefined; if (selectedDate) { const dateStart = new Date(selectedDate); const dateEnd = new Date(selectedDate); dateEnd.setDate(dateEnd.getDate() + 1); hourlyWhereClause = and( gte(generatedImage.createdAt, dateStart), lt(generatedImage.createdAt, dateEnd) ); } const hourlyStats = await db .select({ hour: sql`extract(hour from ${generatedImage.createdAt})::int`, count: sql`count(*)::int`, }) .from(generatedImage) .where(hourlyWhereClause) .groupBy(sql`extract(hour from ${generatedImage.createdAt})`) .orderBy(sql`extract(hour from ${generatedImage.createdAt})`); // 8. 今日统计 const todayStats = await db .select({ count: sql`count(*)::int`, users: sql`count(distinct ${generatedImage.userId})::int`, }) .from(generatedImage) .where(sql`date(${generatedImage.createdAt}) = current_date`); // 9. 本周统计 const weekStats = await db .select({ count: sql`count(*)::int`, users: sql`count(distinct ${generatedImage.userId})::int`, }) .from(generatedImage) .where(sql`${generatedImage.createdAt} >= date_trunc('week', current_date)`); // 10. 指定月份统计(支持选择月份) let monthStart: Date; let monthEnd: Date; if (month) { // 解析指定月份 const [year, mon] = month.split("-").map(Number); monthStart = new Date(year, mon - 1, 1); monthEnd = new Date(year, mon, 1); // 下个月第一天 } else { // 默认当前月 const now = new Date(); monthStart = new Date(now.getFullYear(), now.getMonth(), 1); monthEnd = new Date(now.getFullYear(), now.getMonth() + 1, 1); } const monthStats = await db .select({ count: sql`count(*)::int`, users: sql`count(distinct ${generatedImage.userId})::int`, }) .from(generatedImage) .where(and( gte(generatedImage.createdAt, monthStart), lt(generatedImage.createdAt, monthEnd) )); return NextResponse.json({ overview: { totalImages: totalStats[0]?.totalImages || 0, totalUsers: totalStats[0]?.totalUsers || 0, todayImages: todayStats[0]?.count || 0, todayUsers: todayStats[0]?.users || 0, weekImages: weekStats[0]?.count || 0, weekUsers: weekStats[0]?.users || 0, monthImages: monthStats[0]?.count || 0, monthUsers: monthStats[0]?.users || 0, selectedMonth: month || `${new Date().getFullYear()}-${String(new Date().getMonth() + 1).padStart(2, "0")}`, selectedDate: selectedDate || null, }, userStats, dailyStats, sizeStats, modelStats, monthlyStats, hourlyStats, }); } catch (error) { console.error("[Admin Images Analytics API] Error:", error); return NextResponse.json({ error: "Failed to fetch analytics" }, { status: 500 }); } }