103 lines
3.5 KiB
TypeScript
103 lines
3.5 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
||
import { getResolvedProductPlanningApiConfig } from "@/lib/product-planning/server-config";
|
||
import {
|
||
isProductPlanningEnabled,
|
||
PRODUCT_PLANNING_DISABLED_MESSAGE,
|
||
} from "@/lib/product-planning/server-feature";
|
||
import { getProductPlanningToken } from "@/lib/product-planning/server-auth";
|
||
import { normalizeTaobaoItem } from "@/lib/product-planning/taobao";
|
||
import type { ProductPlanningTaobaoItemResponse } from "@/lib/product-planning/types";
|
||
|
||
export const runtime = "nodejs";
|
||
|
||
function jsonError(status: number, error: string) {
|
||
const payload: ProductPlanningTaobaoItemResponse = {
|
||
success: false,
|
||
error,
|
||
};
|
||
return NextResponse.json(payload, { status });
|
||
}
|
||
|
||
export async function GET(request: NextRequest) {
|
||
const token = await getProductPlanningToken(request);
|
||
if (!token?.sub) {
|
||
return jsonError(401, "未登录");
|
||
}
|
||
if (!(await isProductPlanningEnabled())) {
|
||
return jsonError(403, PRODUCT_PLANNING_DISABLED_MESSAGE);
|
||
}
|
||
|
||
const itemId = String(request.nextUrl.searchParams.get("id") || "").trim();
|
||
if (!itemId) {
|
||
return jsonError(400, "缺少商品ID参数");
|
||
}
|
||
|
||
const config = await getResolvedProductPlanningApiConfig();
|
||
const apiKey = config.taobaoApiKey;
|
||
const apiSecret = config.taobaoApiSecret;
|
||
if (!apiKey || !apiSecret) {
|
||
return jsonError(500, "缺少商品策划工具淘宝 API Key / Secret,请前往系统设置配置");
|
||
}
|
||
|
||
const apiUrl =
|
||
`${config.oneboundBaseUrl}/taobao/item_get_pro/?key=${encodeURIComponent(apiKey)}` +
|
||
`&secret=${encodeURIComponent(apiSecret)}&num_iid=${encodeURIComponent(itemId)}`;
|
||
|
||
try {
|
||
const response = await fetch(apiUrl, {
|
||
signal: AbortSignal.timeout(15000),
|
||
headers: { Accept: "application/json" },
|
||
cache: "no-store",
|
||
});
|
||
|
||
if (!response.ok) {
|
||
return jsonError(502, `淘宝商品详情接口请求失败:${response.status}`);
|
||
}
|
||
|
||
const data = await response.json();
|
||
if (data?.error_code && data.error_code !== "0000") {
|
||
return jsonError(502, data.error || data.reason || "淘宝商品详情接口返回错误");
|
||
}
|
||
|
||
if (!data?.item) {
|
||
const fallbackUrl =
|
||
`${config.oneboundBaseUrl}/taobao/item_get/?key=${encodeURIComponent(apiKey)}` +
|
||
`&secret=${encodeURIComponent(apiSecret)}&num_iid=${encodeURIComponent(itemId)}`;
|
||
const fallbackResponse = await fetch(fallbackUrl, {
|
||
signal: AbortSignal.timeout(15000),
|
||
headers: { Accept: "application/json" },
|
||
cache: "no-store",
|
||
});
|
||
|
||
if (!fallbackResponse.ok) {
|
||
return jsonError(502, `淘宝商品详情接口请求失败:${fallbackResponse.status}`);
|
||
}
|
||
|
||
const fallbackData = await fallbackResponse.json();
|
||
if (fallbackData?.error_code && fallbackData.error_code !== "0000") {
|
||
return jsonError(
|
||
502,
|
||
fallbackData.error || fallbackData.reason || "淘宝商品详情接口返回错误"
|
||
);
|
||
}
|
||
|
||
if (!fallbackData?.item) {
|
||
return jsonError(404, "未找到商品信息");
|
||
}
|
||
|
||
return NextResponse.json({
|
||
success: true,
|
||
item: normalizeTaobaoItem(fallbackData.item, itemId),
|
||
} satisfies ProductPlanningTaobaoItemResponse);
|
||
}
|
||
|
||
return NextResponse.json({
|
||
success: true,
|
||
item: normalizeTaobaoItem(data.item, itemId),
|
||
} satisfies ProductPlanningTaobaoItemResponse);
|
||
} catch (error) {
|
||
console.error("[ProductPlanning][TaobaoItem] request failed:", error);
|
||
return jsonError(502, "淘宝商品详情接口调用失败");
|
||
}
|
||
}
|