Your Name 478562c312
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
feat: migrate product planning workspace
2026-03-26 16:38:48 +08:00

101 lines
3.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 { normalizeJdItem } 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}/jd/item_get_app/?key=${encodeURIComponent(apiKey)}` +
`&secret=${encodeURIComponent(apiSecret)}&num_iid=${encodeURIComponent(itemId)}&domain_type=jd`;
const descApiUrl =
`${config.oneboundBaseUrl}/jd/item_get_desc/?key=${encodeURIComponent(apiKey)}` +
`&secret=${encodeURIComponent(apiSecret)}&num_iid=${encodeURIComponent(itemId)}&domain_type=jd`;
try {
const [response, descResponse] = await Promise.all([
fetch(apiUrl, {
signal: AbortSignal.timeout(15000),
headers: { Accept: "application/json" },
cache: "no-store",
}),
fetch(descApiUrl, {
signal: AbortSignal.timeout(15000),
headers: { Accept: "application/json" },
cache: "no-store",
}).catch(() => null),
]);
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) {
return jsonError(404, "未找到商品信息");
}
let descHtml = "";
if (descResponse?.ok) {
try {
const descData = await descResponse.json();
descHtml = String(descData?.item?.desc || "").trim();
} catch (error) {
console.warn("[ProductPlanning][JdItem] parse desc failed:", error);
}
}
return NextResponse.json({
success: true,
item: normalizeJdItem(
{
...data.item,
desc: descHtml || data.item.desc,
},
itemId
),
} satisfies ProductPlanningTaobaoItemResponse);
} catch (error) {
console.error("[ProductPlanning][JdItem] request failed:", error);
return jsonError(502, "京东商品详情接口调用失败");
}
}