Files
zhuiguang-ai/src/app/api/user/[id]/activity/route.ts
T

93 lines
3.0 KiB
TypeScript

import { prisma } from "@/lib/prisma";
import { NextResponse } from "next/server";
const DAYS = 90;
export async function GET(_req: Request, { params }: { params: { id: string } }) {
try {
const userId = parseInt(params.id);
if (isNaN(userId)) {
return NextResponse.json({ error: "无效的用户ID" }, { status: 400 });
}
const since = new Date();
since.setDate(since.getDate() - DAYS);
since.setHours(0, 0, 0, 0);
const [topics, posts, comments, checkIns] = await Promise.all([
prisma.forumTopic.findMany({
where: { userId, createdAt: { gte: since } },
select: { createdAt: true },
}),
prisma.forumPost.findMany({
where: { userId, createdAt: { gte: since } },
select: { createdAt: true },
}),
prisma.comment.findMany({
where: { userId, createdAt: { gte: since } },
select: { createdAt: true },
}),
prisma.forumCheckIn.findMany({
where: { userId, checkInDate: { gte: since } },
select: { checkInDate: true, streak: true, pointsEarned: true },
}),
]);
const all = new Map<string, { count: number; topics: number; posts: number; comments: number }>();
const bump = (d: Date, type: "topics" | "posts" | "comments") => {
const k = d.toISOString().slice(0, 10);
const cur = all.get(k) || { count: 0, topics: 0, posts: 0, comments: 0 };
cur.count += 1;
cur[type] += 1;
all.set(k, cur);
};
topics.forEach(t => bump(t.createdAt, "topics"));
posts.forEach(p => bump(p.createdAt, "posts"));
comments.forEach(c => bump(c.createdAt, "comments"));
const heatmap: Array<{ date: string; count: number; topics: number; posts: number; comments: number }> = [];
for (let i = DAYS - 1; i >= 0; i--) {
const d = new Date();
d.setDate(d.getDate() - i);
const k = d.toISOString().slice(0, 10);
const v = all.get(k);
heatmap.push({
date: k,
count: v?.count || 0,
topics: v?.topics || 0,
posts: v?.posts || 0,
comments: v?.comments || 0,
});
}
const checkInList = checkIns
.map(c => ({
date: c.checkInDate.toISOString().slice(0, 10),
streak: c.streak,
points: c.pointsEarned,
}))
.sort((a, b) => a.date.localeCompare(b.date));
const totalActiveDays = heatmap.filter(d => d.count > 0).length;
const totalActions = topics.length + posts.length + comments.length;
return NextResponse.json({
heatmap,
checkIns: checkInList,
summary: {
totalDays: DAYS,
activeDays: totalActiveDays,
activeRate: Math.round((totalActiveDays / DAYS) * 100),
totalActions,
topicsCount: topics.length,
postsCount: posts.length,
commentsCount: comments.length,
},
});
} catch (error: unknown) {
const err = error as { message?: string };
return NextResponse.json({ error: err.message || "获取活跃度数据失败" }, { status: 500 });
}
}