refactor: 提取 buildNavUrl 工具函数,统一 room API 错误处理

- 将 MatchResult.tsx 和 profile/page.tsx 中重复的导航 URL 构建逻辑提取到 src/lib/navigation.ts
- 7 个 room API 路由从 return NextResponse.json({ error }, { status }) 统一改为 throw ApiError,由 apiHandler 统一捕获
This commit is contained in:
2026-02-26 19:31:00 +08:00
parent c9e20d4c95
commit 9641acbcbd
10 changed files with 21 additions and 58 deletions
+1 -6
View File
@@ -22,12 +22,7 @@ export const POST = apiHandler(async (req, { params }) => {
return data;
});
if (!updated) {
return NextResponse.json(
{ error: "房间不存在或已过期" },
{ status: 404 },
);
}
if (!updated) throw new ApiError("房间不存在或已过期", 404);
notify(id);
+1 -6
View File
@@ -59,12 +59,7 @@ export const POST = apiHandler(async (req, { params }) => {
return data;
});
if (!updated) {
return NextResponse.json(
{ error: "房间不存在或已过期" },
{ status: 404 },
);
}
if (!updated) throw new ApiError("房间不存在或已过期", 404);
notify(id);
+2 -7
View File
@@ -1,7 +1,7 @@
import { NextResponse } from "next/server";
import { atomicUpdateRoom } from "@/lib/store";
import { notify } from "@/lib/roomEvents";
import { apiHandler } from "@/lib/api";
import { apiHandler, ApiError } from "@/lib/api";
export const POST = apiHandler(async (req, { params }) => {
const { id } = await params;
@@ -27,12 +27,7 @@ export const POST = apiHandler(async (req, { params }) => {
return data;
});
if (!updated) {
return NextResponse.json(
{ error: "房间不存在或已过期" },
{ status: 404 },
);
}
if (!updated) throw new ApiError("房间不存在或已过期", 404);
notify(id);
+2 -8
View File
@@ -1,18 +1,12 @@
import { NextResponse } from "next/server";
import { buildRoomStatus } from "@/lib/buildRoomStatus";
import { apiHandler } from "@/lib/api";
import { apiHandler, ApiError } from "@/lib/api";
export const GET = apiHandler(async (_req, { params }) => {
const { id } = await params;
const status = await buildRoomStatus(id);
if (!status) {
return NextResponse.json(
{ error: "房间不存在或已过期" },
{ status: 404 },
);
}
if (!status) throw new ApiError("房间不存在或已过期", 404);
return NextResponse.json(status);
});
+1 -6
View File
@@ -40,12 +40,7 @@ export const POST = apiHandler(async (req, { params }) => {
return data;
});
if (!updated) {
return NextResponse.json(
{ error: "房间不存在或已过期" },
{ status: 404 },
);
}
if (!updated) throw new ApiError("房间不存在或已过期", 404);
notify(id);
+1 -6
View File
@@ -32,12 +32,7 @@ export const POST = apiHandler(async (req, { params }) => {
return data;
});
if (!updated) {
return NextResponse.json(
{ error: "房间不存在或已过期" },
{ status: 404 },
);
}
if (!updated) throw new ApiError("房间不存在或已过期", 404);
notify(id);
+1 -6
View File
@@ -150,12 +150,7 @@ export const POST = apiHandler(async (req) => {
restaurants = results.slice(0, 15);
}
if (restaurants.length === 0) {
return NextResponse.json(
{ error: sceneConfig.emptyError },
{ status: 404 },
);
}
if (restaurants.length === 0) throw new ApiError(sceneConfig.emptyError, 404);
const roomId = await createRoom(restaurants, userId, sceneConfig.key);
return NextResponse.json({ roomId, restaurants });
+2 -5
View File
@@ -29,6 +29,7 @@ import RestaurantImage from "@/components/RestaurantImage";
import { ProfileCardSkeleton, RecordItemSkeleton } from "@/components/Skeleton";
import { getUserId, getCachedProfile, setCachedProfile, setCachedPreferences, logout } from "@/lib/userId";
import { getAvatarBg, AVATARS } from "@/lib/avatars";
import { buildNavUrl } from "@/lib/navigation";
import type { UserProfile, UserPreferences, DecisionRecord, FavoriteRecord, Restaurant } from "@/types";
function firstImage(r: Restaurant): string {
@@ -279,10 +280,6 @@ export default function ProfilePage() {
if (!profile) return null;
const amapNavUrl = (r: Restaurant) =>
r.location
? `https://uri.amap.com/marker?position=${r.location}&name=${encodeURIComponent(r.name)}&callnative=1`
: `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(r.name)}`;
return (
<div className="h-dvh bg-background pb-16 overflow-y-auto scrollbar-none">
@@ -567,7 +564,7 @@ export default function ProfilePage() {
{history.map((d) => (
<a
key={d.id}
href={amapNavUrl(d.restaurantData)}
href={buildNavUrl(d.restaurantData)}
target="_blank"
rel="noopener noreferrer"
className="flex gap-3 rounded-xl bg-elevated p-2.5 transition-colors active:bg-subtle"
+1 -8
View File
@@ -35,6 +35,7 @@ import ShareCardModal from "@/components/ShareCardModal";
import RestaurantImage from "@/components/RestaurantImage";
import AuthModal from "@/components/AuthModal";
import Button from "@/components/Button";
import { buildNavUrl } from "@/lib/navigation";
import { useToast } from "@/hooks/useToast";
interface MatchResultProps {
@@ -52,14 +53,6 @@ interface MatchResultProps {
scene?: SceneType;
}
function buildNavUrl(restaurant: Restaurant): string {
if (restaurant.location) {
const [lng, lat] = restaurant.location.split(",");
return `https://uri.amap.com/marker?position=${lng},${lat}&name=${encodeURIComponent(restaurant.name)}&callnative=1`;
}
return `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(restaurant.name)}`;
}
function NoMatchResult({
onReset,
resetting,
+9
View File
@@ -0,0 +1,9 @@
import type { Restaurant } from "@/types";
export function buildNavUrl(restaurant: Restaurant): string {
if (restaurant.location) {
const [lng, lat] = restaurant.location.split(",");
return `https://uri.amap.com/marker?position=${lng},${lat}&name=${encodeURIComponent(restaurant.name)}&callnative=1`;
}
return `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(restaurant.name)}`;
}