feat: 新增周末契约盲盒功能,首页重构为双模式入口

- 新增 BlindBoxIdea 数据模型及 migration
- 新增盲盒 API (提交想法/查询/抽取)
- 新增周末契约盲盒页面 (动效震动+彩带开奖)
- 原首页功能拆分至 /panic 路由
- 首页重构为极速救场 + 周末契约双卡片入口
This commit is contained in:
2026-02-26 11:27:10 +08:00
parent 30d5ad5ff2
commit 7d51f5200d
7 changed files with 1361 additions and 581 deletions
+39
View File
@@ -0,0 +1,39 @@
import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
export async function POST(req: NextRequest) {
try {
const { roomId } = await req.json();
if (!roomId || typeof roomId !== "string") {
return NextResponse.json({ error: "roomId 不能为空" }, { status: 400 });
}
const pool = await prisma.blindBoxIdea.findMany({
where: { roomId: roomId.trim(), status: "in_pool" },
select: { id: true },
});
if (pool.length === 0) {
return NextResponse.json(
{ error: "盒子是空的,先往里面塞点想法吧!" },
{ status: 404 },
);
}
const picked = pool[Math.floor(Math.random() * pool.length)];
const idea = await prisma.blindBoxIdea.update({
where: { id: picked.id },
data: { status: "drawn" },
});
return NextResponse.json({
id: idea.id,
content: idea.content,
createdAt: idea.createdAt,
});
} catch {
return NextResponse.json({ error: "抽取失败" }, { status: 500 });
}
}
+50
View File
@@ -0,0 +1,50 @@
import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
export async function POST(req: NextRequest) {
try {
const { roomId, content } = await req.json();
if (!roomId || typeof roomId !== "string") {
return NextResponse.json({ error: "roomId 不能为空" }, { status: 400 });
}
if (!content || typeof content !== "string" || content.trim().length === 0) {
return NextResponse.json({ error: "内容不能为空" }, { status: 400 });
}
if (content.trim().length > 200) {
return NextResponse.json({ error: "内容不能超过 200 字" }, { status: 400 });
}
const idea = await prisma.blindBoxIdea.create({
data: {
roomId: roomId.trim(),
content: content.trim(),
},
});
return NextResponse.json({ id: idea.id }, { status: 201 });
} catch {
return NextResponse.json({ error: "提交失败" }, { status: 500 });
}
}
export async function GET(req: NextRequest) {
const roomId = req.nextUrl.searchParams.get("roomId");
if (!roomId) {
return NextResponse.json({ error: "缺少 roomId" }, { status: 400 });
}
const [poolCount, drawn] = await Promise.all([
prisma.blindBoxIdea.count({
where: { roomId, status: "in_pool" },
}),
prisma.blindBoxIdea.findMany({
where: { roomId, status: "drawn" },
orderBy: { createdAt: "desc" },
select: { id: true, content: true, createdAt: true },
}),
]);
return NextResponse.json({ poolCount, drawn });
}