Files
zhuiguang-ai/src/lib/points-reward.ts
T

112 lines
2.7 KiB
TypeScript

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,
};
}