2026-05-25: 等级体系升级(20级)+论坛二级分类+会员空间
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { POINTS_RULES, DAILY_LIMITS, getLevelInfo, getReasonLabel } from "@/lib/level-config";
|
||||
|
||||
export { getLevelInfo, getReasonLabel };
|
||||
|
||||
async function getTodayEarned(userId: number, reason: string): Promise<number> {
|
||||
const startOfDay = new Date();
|
||||
startOfDay.setHours(0, 0, 0, 0);
|
||||
const endOfDay = new Date(startOfDay);
|
||||
endOfDay.setDate(endOfDay.getDate() + 1);
|
||||
|
||||
const result = await prisma.pointsHistory.aggregate({
|
||||
where: {
|
||||
userId,
|
||||
reason,
|
||||
createdAt: {
|
||||
gte: startOfDay,
|
||||
lt: endOfDay,
|
||||
},
|
||||
},
|
||||
_sum: {
|
||||
points: true,
|
||||
},
|
||||
});
|
||||
|
||||
return result._sum.points || 0;
|
||||
}
|
||||
|
||||
export async function rewardPoints(
|
||||
userId: number,
|
||||
reason: keyof typeof POINTS_RULES,
|
||||
detail?: string,
|
||||
refType?: string,
|
||||
refId?: number
|
||||
): Promise<{ success: boolean; points: number; message: string }> {
|
||||
const points = POINTS_RULES[reason];
|
||||
const dailyLimit = DAILY_LIMITS[reason as keyof typeof DAILY_LIMITS];
|
||||
|
||||
if (dailyLimit) {
|
||||
const todayEarned = await getTodayEarned(userId, reason);
|
||||
if (todayEarned >= dailyLimit) {
|
||||
return {
|
||||
success: false,
|
||||
points: 0,
|
||||
message: `今日${reason}积分已达上限(${dailyLimit})`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
await prisma.$transaction(async (tx) => {
|
||||
await tx.user.update({
|
||||
where: { id: userId },
|
||||
data: { points: { increment: points } },
|
||||
});
|
||||
|
||||
await tx.pointsHistory.create({
|
||||
data: {
|
||||
userId,
|
||||
points,
|
||||
reason,
|
||||
detail: detail || null,
|
||||
refType: refType || null,
|
||||
refId: refId || null,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
return { success: true, points, message: `+${points}积分` };
|
||||
}
|
||||
|
||||
export async function getUserPointsHistory(
|
||||
userId: number,
|
||||
page = 1,
|
||||
pageSize = 20
|
||||
) {
|
||||
const [history, total] = await Promise.all([
|
||||
prisma.pointsHistory.findMany({
|
||||
where: { userId },
|
||||
orderBy: { createdAt: "desc" },
|
||||
skip: (page - 1) * pageSize,
|
||||
take: pageSize,
|
||||
}),
|
||||
prisma.pointsHistory.count({ where: { userId } }),
|
||||
]);
|
||||
|
||||
return { history, total, page, pageSize };
|
||||
}
|
||||
|
||||
export async function getUserStats(userId: number) {
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id: userId },
|
||||
select: {
|
||||
points: true,
|
||||
level: true,
|
||||
comments: { select: { id: true } },
|
||||
forumTopics: { select: { id: true } },
|
||||
forumPosts: { select: { id: true } },
|
||||
reviews: { select: { id: true } },
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) return null;
|
||||
|
||||
return {
|
||||
points: user.points,
|
||||
level: getLevelInfo(user.points),
|
||||
commentCount: user.comments.length,
|
||||
topicCount: user.forumTopics.length,
|
||||
postCount: user.forumPosts.length,
|
||||
reviewCount: user.reviews.length,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user