init: init prok
This commit is contained in:
79
packages/server/src/routes/redemption.ts
Normal file
79
packages/server/src/routes/redemption.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { Router } from "express";
|
||||
import { z } from "zod";
|
||||
import { prisma } from "@stamp/shared";
|
||||
import { requireAuth } from "../middleware/auth.js";
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get("/rules", async (_req, res) => {
|
||||
const rules = await prisma.redemptionRule.findMany({
|
||||
where: { enabled: true },
|
||||
orderBy: { sortOrder: "asc" },
|
||||
select: { id: true, name: true, description: true, threshold: true },
|
||||
});
|
||||
res.json({ success: true, data: rules });
|
||||
});
|
||||
|
||||
const redeemSchema = z.object({
|
||||
ruleId: z.string().uuid("规则 ID 格式不正确"),
|
||||
});
|
||||
|
||||
router.post("/redeem", requireAuth, async (req, res) => {
|
||||
const parsed = redeemSchema.safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
res.status(400).json({ success: false, error: { code: "VALIDATION", message: parsed.error.issues[0].message } });
|
||||
return;
|
||||
}
|
||||
|
||||
const rule = await prisma.redemptionRule.findUnique({ where: { id: parsed.data.ruleId, enabled: true } });
|
||||
if (!rule) {
|
||||
res.status(404).json({ success: false, error: { code: "NOT_FOUND", message: "兑换规则不存在" } });
|
||||
return;
|
||||
}
|
||||
|
||||
const collectionCount = await prisma.collection.count({ where: { userId: req.userId! } });
|
||||
if (collectionCount < rule.threshold) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
error: { code: "INSUFFICIENT", message: `需要收集 ${rule.threshold} 枚图章,当前只有 ${collectionCount} 枚` },
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const redemption = await prisma.$transaction(async (tx) => {
|
||||
const record = await tx.redemption.create({
|
||||
data: { userId: req.userId!, ruleId: rule.id, stampCount: collectionCount },
|
||||
});
|
||||
await tx.collection.deleteMany({ where: { userId: req.userId! } });
|
||||
return record;
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
id: redemption.id,
|
||||
ruleName: rule.name,
|
||||
stampCount: redemption.stampCount,
|
||||
redeemedAt: redemption.redeemedAt.toISOString(),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
router.get("/history", requireAuth, async (req, res) => {
|
||||
const records = await prisma.redemption.findMany({
|
||||
where: { userId: req.userId! },
|
||||
include: { rule: { select: { name: true } } },
|
||||
orderBy: { redeemedAt: "desc" },
|
||||
});
|
||||
|
||||
const data = records.map((r) => ({
|
||||
id: r.id,
|
||||
ruleName: r.rule.name,
|
||||
stampCount: r.stampCount,
|
||||
redeemedAt: r.redeemedAt.toISOString(),
|
||||
}));
|
||||
|
||||
res.json({ success: true, data });
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user