9641acbcbd
- 将 MatchResult.tsx 和 profile/page.tsx 中重复的导航 URL 构建逻辑提取到 src/lib/navigation.ts
- 7 个 room API 路由从 return NextResponse.json({ error }, { status }) 统一改为 throw ApiError,由 apiHandler 统一捕获
68 lines
1.8 KiB
TypeScript
68 lines
1.8 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { atomicUpdateRoom } from "@/lib/store";
|
|
import { notify } from "@/lib/roomEvents";
|
|
import { apiHandler, ApiError, requireUserId } from "@/lib/api";
|
|
|
|
export const POST = apiHandler(async (req, { params }) => {
|
|
const { id } = await params;
|
|
const { userId, action, targetUserId } = await req.json();
|
|
|
|
requireUserId(userId);
|
|
if (!action) throw new ApiError("action required");
|
|
|
|
const updated = await atomicUpdateRoom(id, (data) => {
|
|
if (data.creatorId !== userId) {
|
|
throw new ApiError("只有房主可以执行此操作", 403);
|
|
}
|
|
|
|
switch (action) {
|
|
case "lock":
|
|
data.locked = true;
|
|
break;
|
|
|
|
case "unlock":
|
|
data.locked = false;
|
|
break;
|
|
|
|
case "kick":
|
|
if (!targetUserId || targetUserId === userId) {
|
|
throw new ApiError("无效的操作对象");
|
|
}
|
|
data.users = data.users.filter((u) => u !== targetUserId);
|
|
if (!data.kickedUsers.includes(targetUserId)) {
|
|
data.kickedUsers.push(targetUserId);
|
|
}
|
|
delete data.swipeCounts[targetUserId];
|
|
for (const rid of Object.keys(data.likes)) {
|
|
data.likes[rid] = data.likes[rid].filter(
|
|
(u) => u !== targetUserId,
|
|
);
|
|
}
|
|
if (
|
|
data.match &&
|
|
data.likes[data.match]?.length !== data.users.length
|
|
) {
|
|
data.match = null;
|
|
}
|
|
break;
|
|
|
|
case "end_voting":
|
|
for (const u of data.users) {
|
|
data.swipeCounts[u] = data.restaurants.length;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
throw new ApiError("未知操作");
|
|
}
|
|
|
|
return data;
|
|
});
|
|
|
|
if (!updated) throw new ApiError("房间不存在或已过期", 404);
|
|
|
|
notify(id);
|
|
|
|
return NextResponse.json({ ok: true });
|
|
});
|