From 532d8ff7ad98b8b9c4bbb73b9210503c49fbdf32 Mon Sep 17 00:00:00 2001 From: kurihada Date: Tue, 3 Mar 2026 13:11:33 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E7=9B=B2=E7=9B=92=E8=AF=B7?= =?UTF-8?q?=E6=B1=82=E5=A5=91=E7=BA=A6=E5=B9=B6=E7=A7=BB=E9=99=A4=E5=86=97?= =?UTF-8?q?=E4=BD=99=20userId=20=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PROJECT_AUDIT_2026-03-03.md | 12 +++++++----- src/app/blindbox/page.tsx | 7 +++---- src/hooks/useBlindboxDraw.ts | 2 +- src/hooks/useBlindboxIdeas.ts | 10 +++++----- src/hooks/useBlindboxPlan.ts | 24 ++++++++++-------------- src/hooks/useBlindboxRoom.ts | 5 ++--- src/hooks/useBlindboxRooms.ts | 4 ++-- 7 files changed, 30 insertions(+), 34 deletions(-) diff --git a/PROJECT_AUDIT_2026-03-03.md b/PROJECT_AUDIT_2026-03-03.md index b6b2b85..64b8ef6 100644 --- a/PROJECT_AUDIT_2026-03-03.md +++ b/PROJECT_AUDIT_2026-03-03.md @@ -220,12 +220,14 @@ - 证据: - `src/lib/roomRepository.ts` 已移除 likes 全删全建逻辑,改为差量同步。 -### R3 请求参数契约不统一(前端仍大量发送已废弃 `userId`) +### R3 请求参数契约不统一(前端仍大量发送已废弃 `userId`)【已完成】 +- 修复状态:✅ 已完成(2026-03-03) +- 修复内容: + - 盲盒主链路前端请求已去除冗余 `userId`(`useBlindboxIdeas`、`useBlindboxDraw`、`useBlindboxPlan`、`useBlindboxRoom`、`blindbox/page`); + - `useBlindboxRooms` 改为基于登录态启用请求,接口统一使用鉴权 cookie,不再拼接 `userId` query; + - 保留房间实时 SSE 的 `userId` 参数(用于已修复的成员校验链路),其余盲盒链路契约已统一。 - 证据: - - 例如 `src/hooks/useBlindboxIdeas.ts:57/71/104/...`、`src/hooks/useBlindboxPlan.ts:50/68/...` -- 建议: - - 明确“鉴权由 cookie/token 提供”,清理冗余 `userId` 参数; - - 用 Zod schema 统一约束(`src/lib/schemas/requests.ts` 目前未形成全链路使用)。 + - `rg` 检索显示盲盒前端链路已无 `?userId=` 或 `userId: profile.id` 传参。 ### R4 统一 API 调用层(减少重复 fetch + 错误处理分散) - 现状: diff --git a/src/app/blindbox/page.tsx b/src/app/blindbox/page.tsx index b92cf13..6918eaa 100644 --- a/src/app/blindbox/page.tsx +++ b/src/app/blindbox/page.tsx @@ -172,7 +172,7 @@ export default function BlindboxLobbyPage() { const [showAuth, setShowAuth] = useState(false); const toast = useToast(); const { rooms: swrRooms, isLoading: swrLoading, isUnauthorized, error: swrError, mutate: mutateRooms } = useBlindboxRooms( - loggedIn && profile ? profile.id : undefined, + loggedIn, ); const rooms = swrRooms; const loading = !loggedIn ? false : swrLoading; @@ -233,7 +233,7 @@ export default function BlindboxLobbyPage() { const res = await fetch("/api/blindbox/room", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ userId: profile.id, name: name || undefined }), + body: JSON.stringify({ name: name || undefined }), }); const data = await res.json(); if (!res.ok) throw new Error(data.error); @@ -254,7 +254,7 @@ export default function BlindboxLobbyPage() { const res = await fetch("/api/blindbox/room/join", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ userId: profile.id, code }), + body: JSON.stringify({ code }), }); const data = await res.json(); if (!res.ok) throw new Error(data.error); @@ -273,7 +273,6 @@ export default function BlindboxLobbyPage() { const res = await fetch(`/api/blindbox/room/${room.code}`, { method: "DELETE", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ userId: profile.id }), }); if (!res.ok) { const data = await res.json(); diff --git a/src/hooks/useBlindboxDraw.ts b/src/hooks/useBlindboxDraw.ts index 7fc8175..a45c29e 100644 --- a/src/hooks/useBlindboxDraw.ts +++ b/src/hooks/useBlindboxDraw.ts @@ -81,7 +81,7 @@ export function useBlindboxDraw( const res = await fetch("/api/blindbox/draw", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ roomId: room.id, userId: profile.id }), + body: JSON.stringify({ roomId: room.id }), }); if (!res.ok) { diff --git a/src/hooks/useBlindboxIdeas.ts b/src/hooks/useBlindboxIdeas.ts index ef7e017..7c521df 100644 --- a/src/hooks/useBlindboxIdeas.ts +++ b/src/hooks/useBlindboxIdeas.ts @@ -62,7 +62,7 @@ export function useBlindboxIdeas(room: RoomInfo | null, profile: UserProfile | n const fetchIdeas = useCallback(async () => { if (!room || !profile) return; try { - const res = await fetch(`/api/blindbox?roomId=${room.id}&userId=${profile.id}`); + const res = await fetch(`/api/blindbox?roomId=${room.id}`); if (res.ok) { const data = await res.json(); setPoolCount(data.poolCount ?? 0); @@ -76,7 +76,7 @@ export function useBlindboxIdeas(room: RoomInfo | null, profile: UserProfile | n if (!room || !profile) return; setSuggestionsLoading(true); try { - const res = await fetch(`/api/blindbox/suggest?roomId=${room.id}&userId=${profile.id}`); + const res = await fetch(`/api/blindbox/suggest?roomId=${room.id}`); if (res.ok) { const data = await res.json(); if (data.suggestions?.length > 0) { @@ -109,7 +109,7 @@ export function useBlindboxIdeas(room: RoomInfo | null, profile: UserProfile | n const res = await fetch("/api/blindbox", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ roomId: room.id, userId: profile.id, content: text }), + body: JSON.stringify({ roomId: room.id, content: text }), }); if (!res.ok) { const data = await res.json(); @@ -156,7 +156,7 @@ export function useBlindboxIdeas(room: RoomInfo | null, profile: UserProfile | n const res = await fetch("/api/blindbox", { method: "PUT", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ ideaId, userId: profile.id, content: trimmed }), + body: JSON.stringify({ ideaId, content: trimmed }), }); if (!res.ok) { const data = await res.json(); @@ -188,7 +188,7 @@ export function useBlindboxIdeas(room: RoomInfo | null, profile: UserProfile | n const res = await fetch("/api/blindbox", { method: "DELETE", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ ideaId, userId: profile.id }), + body: JSON.stringify({ ideaId }), }); if (!res.ok) { const data = await res.json(); diff --git a/src/hooks/useBlindboxPlan.ts b/src/hooks/useBlindboxPlan.ts index b3a79bb..5c4545d 100644 --- a/src/hooks/useBlindboxPlan.ts +++ b/src/hooks/useBlindboxPlan.ts @@ -1,7 +1,6 @@ "use client"; import { useState, useCallback, useRef, useEffect } from "react"; -import { getCachedProfile } from "@/lib/userId"; import { useToast } from "@/hooks/useToast"; import type { RoomInfo } from "@/hooks/useBlindboxRoom"; import type { WeekendPlanData, UserProfile } from "@/types"; @@ -47,7 +46,7 @@ export function useBlindboxPlan( const fetchAcceptedPlan = useCallback(async () => { if (!room || !profile) return; try { - const res = await fetch(`/api/blindbox/plan?mode=latest&roomId=${room.id}&userId=${profile.id}`); + const res = await fetch(`/api/blindbox/plan?mode=latest&roomId=${room.id}`); if (!res.ok) return; const data = await res.json(); if (data.plan) { @@ -65,7 +64,7 @@ export function useBlindboxPlan( if (!profile) return; (async () => { try { - const res = await fetch(`/api/blindbox/plan?mode=pending&userId=${profile.id}`); + const res = await fetch("/api/blindbox/plan?mode=pending"); if (!res.ok) return; const data = await res.json(); if (data.pending?.length) setPendingContracts(data.pending); @@ -93,13 +92,10 @@ export function useBlindboxPlan( }); n.onclick = () => { window.focus(); n.close(); }; } - const p = getCachedProfile(); - if (p) { - fetch(`/api/blindbox/plan?mode=pending&userId=${p.id}`) - .then((r) => r.json()) - .then((d) => { if (d.pending?.length) setPendingContracts(d.pending); }) - .catch((e) => { console.error("refreshPendingContracts failed:", e); }); - } + fetch("/api/blindbox/plan?mode=pending") + .then((r) => r.json()) + .then((d) => { if (d.pending?.length) setPendingContracts(d.pending); }) + .catch((e) => { console.error("refreshPendingContracts failed:", e); }); }, ms); return () => clearTimeout(timer); @@ -110,7 +106,7 @@ export function useBlindboxPlan( setGenerating(true); setPhase("planning"); setPlanStatusMessages([PLAN_STATUS_STEPS[0]]); - const payload = { roomId: room.id, userId: profile.id, availableTime: timeConfig }; + const payload = { roomId: room.id, availableTime: timeConfig }; const stepRef = { current: 0 }; const fallbackTimer = setInterval(() => { stepRef.current = (stepRef.current + 1) % PLAN_STATUS_STEPS.length; @@ -195,7 +191,7 @@ export function useBlindboxPlan( const res = await fetch("/api/blindbox/plan", { method: "PATCH", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ planId, userId: profile.id, action: "update_plan", days: newDays }), + body: JSON.stringify({ planId, action: "update_plan", days: newDays }), }); if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error || "保存失败"); } catch (e) { @@ -212,7 +208,7 @@ export function useBlindboxPlan( const res = await fetch("/api/blindbox/plan/refine", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ userId: profile.id, instruction, days: planDays }), + body: JSON.stringify({ instruction, days: planDays }), }); if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error || "AI 调整失败"); const data = await res.json(); @@ -233,7 +229,7 @@ export function useBlindboxPlan( const res = await fetch("/api/blindbox/plan", { method: "PATCH", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ planId, userId: profile.id, action: "accept" }), + body: JSON.stringify({ planId, action: "accept" }), }); const data = await res.json().catch(() => ({})); if (!res.ok) { diff --git a/src/hooks/useBlindboxRoom.ts b/src/hooks/useBlindboxRoom.ts index 11f3766..36c7b86 100644 --- a/src/hooks/useBlindboxRoom.ts +++ b/src/hooks/useBlindboxRoom.ts @@ -77,7 +77,7 @@ export function useBlindboxRoom(code: string) { const res = await fetch("/api/blindbox/room/join", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ userId: profile.id, code }), + body: JSON.stringify({ code }), }); if (res.ok) { setIsMember(true); fetchRoom(); } } catch (e) { console.error("handleJoinRoom failed:", e); } @@ -99,7 +99,7 @@ export function useBlindboxRoom(code: string) { const patchRes = await fetch(`/api/blindbox/room/${room.code}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ userId: profile.id, city: cityName, address: addressLabel, lat, lng }), + body: JSON.stringify({ city: cityName, address: addressLabel, lat, lng }), }); if (!patchRes.ok) throw new Error("保存位置失败"); setRoom((prev) => prev ? { ...prev, city: cityName, address: addressLabel, lat, lng } : prev); @@ -123,7 +123,6 @@ export function useBlindboxRoom(code: string) { const res = await fetch(`/api/blindbox/room/${room.code}`, { method: "DELETE", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ userId: profile.id }), }); if (!res.ok) { const data = await res.json(); diff --git a/src/hooks/useBlindboxRooms.ts b/src/hooks/useBlindboxRooms.ts index d6d37e4..05b2ab4 100644 --- a/src/hooks/useBlindboxRooms.ts +++ b/src/hooks/useBlindboxRooms.ts @@ -18,9 +18,9 @@ interface RoomsResponse { rooms: RoomSummary[]; } -export function useBlindboxRooms(userId: string | undefined) { +export function useBlindboxRooms(enabled: boolean) { const { data, error, isLoading, mutate } = useSWR( - userId ? `/api/blindbox/rooms?userId=${userId}` : null, + enabled ? "/api/blindbox/rooms" : null, fetcher, { revalidateOnFocus: true,