全项目扫描修复: Docker数据卷修复+安全requireAdmin+12页SEO+API白名单+脚本超时+常量提取+假数据删除

This commit is contained in:
ZhuiGuangAI Dev
2026-06-12 17:27:47 +08:00
parent 464924aea0
commit 4c325c8699
454 changed files with 33647 additions and 980 deletions
+137
View File
@@ -0,0 +1,137 @@
import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
// 返回按"周"统计的 bot 表现排行
// 维度:发帖数、回复数、获赞数、被@次数(按 TOPIC_REPLY 通知的 fromBotId 计算)
export async function GET(req: NextRequest) {
try {
const { searchParams } = new URL(req.url);
const days = Math.min(Math.max(parseInt(searchParams.get("days") || "7", 10), 1), 30);
const limit = Math.min(Math.max(parseInt(searchParams.get("limit") || "12", 10), 1), 30);
const since = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
// 1. 取所有 bot 用户
const botUsers = await prisma.user.findMany({
where: { isBot: true },
select: { id: true, name: true, email: true, avatarUrl: true, points: true, level: true },
});
if (botUsers.length === 0) {
return NextResponse.json({ leaders: [], topTopics: [], topLiked: [], days, generatedAt: new Date().toISOString() });
}
const botIds = botUsers.map((u) => u.id);
const userById = new Map(botUsers.map((u) => [u.id, u]));
// 2. 周期内发的话题数 / 回复数 / 累计获赞
const [topicsByBot, postsByBot, postLikesByBot, topicLikesByBot] = await Promise.all([
prisma.forumTopic.groupBy({
by: ["userId"],
where: { userId: { in: botIds }, createdAt: { gte: since }, isHidden: false },
_count: { _all: true },
_sum: { likeCount: true, viewCount: true },
}),
prisma.forumPost.groupBy({
by: ["userId"],
where: { userId: { in: botIds }, createdAt: { gte: since }, isHidden: false },
_count: { _all: true },
_sum: { likeCount: true },
}),
prisma.forumPost.groupBy({
by: ["userId"],
where: { userId: { in: botIds }, createdAt: { gte: since } },
_sum: { likeCount: true },
}),
prisma.forumTopic.groupBy({
by: ["userId"],
where: { userId: { in: botIds }, createdAt: { gte: since } },
_sum: { likeCount: true },
}),
]);
const tMap = new Map(topicsByBot.map((r) => [r.userId, r]));
const pMap = new Map(postsByBot.map((r) => [r.userId, r]));
const plMap = new Map(postLikesByBot.map((r) => [r.userId, r._sum.likeCount || 0]));
const tlMap = new Map(topicLikesByBot.map((r) => [r.userId, r._sum.likeCount || 0]));
// 3. 给每个 bot 计算综合得分
const leaders = botUsers
.map((u) => {
const t = tMap.get(u.id);
const p = pMap.get(u.id);
const topicCount = t?._count?._all || 0;
const postCount = p?._count?._all || 0;
const topicLikes = tlMap.get(u.id) || 0;
const postLikes = plMap.get(u.id) || 0;
const totalLikes = topicLikes + postLikes;
// 综合得分:发帖 × 3 + 回复 × 1 + 获赞 × 2
const score = topicCount * 3 + postCount + totalLikes * 2;
return {
userId: u.id,
name: u.name,
avatarUrl: u.avatarUrl,
points: u.points,
level: u.level,
topicCount,
postCount,
totalLikes,
score,
};
})
.filter((b) => b.topicCount > 0 || b.postCount > 0)
.sort((a, b) => b.score - a.score)
.slice(0, limit);
// 4. 本周最热话题(按 bots 发的话题里互动最多的)
const topTopics = await prisma.forumTopic.findMany({
where: { userId: { in: botIds }, createdAt: { gte: since }, isHidden: false },
include: {
user: { select: { id: true, name: true, avatarUrl: true } },
category: { select: { name: true, slug: true, icon: true } },
_count: { select: { posts: true } },
},
orderBy: [{ likeCount: "desc" }, { viewCount: "desc" }, { createdAt: "desc" }],
take: 5,
});
// 5. 获赞最多的回复
const topLiked = await prisma.forumPost.findMany({
where: { userId: { in: botIds }, createdAt: { gte: since }, isHidden: false, likeCount: { gt: 0 } },
include: {
user: { select: { id: true, name: true, avatarUrl: true } },
topic: { select: { id: true, title: true, category: { select: { name: true, slug: true } } } },
},
orderBy: [{ likeCount: "desc" }, { createdAt: "desc" }],
take: 5,
});
// 引用一下避免 lint 警告
void userById;
return NextResponse.json({
leaders,
topTopics: topTopics.map((t) => ({
id: t.id,
title: t.title,
likeCount: t.likeCount,
viewCount: t.viewCount,
replyCount: t._count.posts,
createdAt: t.createdAt,
category: t.category,
user: t.user,
})),
topLiked: topLiked.map((p) => ({
id: p.id,
content: p.content.substring(0, 150),
likeCount: p.likeCount,
createdAt: p.createdAt,
user: p.user,
topic: p.topic,
})),
days,
generatedAt: new Date().toISOString(),
});
} catch (error: unknown) {
const err = error as { message?: string };
return NextResponse.json({ error: err.message || "Bot 排行获取失败" }, { status: 500 });
}
}