fix: enforce brand matching for references
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-04-27 21:53:02 +08:00
parent 47a0299090
commit 00c4e067bf

View File

@ -42,6 +42,9 @@ type ExternalTaskDetailCandidate = {
brand?: string; brand?: string;
productBrand?: string; productBrand?: string;
brand_name?: string; brand_name?: string;
brand_name_cn?: string;
brandTitle?: string;
brand_title?: string;
categoryName?: string; categoryName?: string;
shopName?: string; shopName?: string;
sceneName?: string; sceneName?: string;
@ -64,6 +67,10 @@ type ExternalTaskDetailResponse = {
brandName?: string | null; brandName?: string | null;
brand?: string | null; brand?: string | null;
productBrand?: string | null; productBrand?: string | null;
brand_name?: string | null;
brand_name_cn?: string | null;
brandTitle?: string | null;
brand_title?: string | null;
categoryName?: string | null; categoryName?: string | null;
shopName?: string | null; shopName?: string | null;
candidateCount?: number; candidateCount?: number;
@ -97,6 +104,29 @@ function normalizeUrlList(value: unknown) {
).slice(0, 64); ).slice(0, 64);
} }
function getExternalBrandName(value: {
brandName?: string | null;
brand?: string | null;
productBrand?: string | null;
brand_name?: string | null;
brand_name_cn?: string | null;
brandTitle?: string | null;
brand_title?: string | null;
}) {
return (
String(
value.brandName ||
value.brand ||
value.productBrand ||
value.brand_name ||
value.brand_name_cn ||
value.brandTitle ||
value.brand_title ||
""
).trim() || null
);
}
function mapUpstreamErrorStatus(code: string) { function mapUpstreamErrorStatus(code: string) {
if ( if (
code === "SKU_NOT_FOUND" || code === "SKU_NOT_FOUND" ||
@ -117,21 +147,15 @@ function mapUpstreamErrorStatus(code: string) {
function normalizeCandidate( function normalizeCandidate(
value: ExternalTaskDetailCandidate, value: ExternalTaskDetailCandidate,
index: number index: number,
fallbackBrandName?: string | null
): AgentModeReferenceCandidate { ): AgentModeReferenceCandidate {
const uploadedAt = String(value.uploadedAt || "").trim() || null; const uploadedAt = String(value.uploadedAt || "").trim() || null;
const taskNo = String(value.taskNo || "").trim() || null; const taskNo = String(value.taskNo || "").trim() || null;
const materialId = String(value.materialId || "").trim() || null; const materialId = String(value.materialId || "").trim() || null;
const sceneName = String(value.sceneName || "").trim() || null; const sceneName = String(value.sceneName || "").trim() || null;
const id = taskNo || materialId || `candidate-${index + 1}`; const id = taskNo || materialId || `candidate-${index + 1}`;
const brandName = const brandName = getExternalBrandName(value) || fallbackBrandName || null;
String(
value.brandName ||
value.brand ||
value.productBrand ||
value.brand_name ||
""
).trim() || null;
return { return {
id, id,
@ -224,13 +248,6 @@ function filterCandidatesByBrand(
const normalizedRequestedBrand = normalizeComparableName(brandName); const normalizedRequestedBrand = normalizeComparableName(brandName);
if (!normalizedRequestedBrand) return candidates; if (!normalizedRequestedBrand) return candidates;
const hasBrandMetadata = candidates.some((candidate) =>
Boolean(normalizeComparableName(candidate.brandName))
);
if (!hasBrandMetadata) {
return candidates;
}
return candidates.filter((candidate) => return candidates.filter((candidate) =>
isCandidateMatchedBrand(candidate, normalizedRequestedBrand) isCandidateMatchedBrand(candidate, normalizedRequestedBrand)
); );
@ -267,11 +284,17 @@ export async function GET(request: NextRequest) {
const normalizedKeyword = parsed.keyword.trim().toUpperCase(); const normalizedKeyword = parsed.keyword.trim().toUpperCase();
const queryType = parsed.queryType as AgentWorkflowMaterialQueryType; const queryType = parsed.queryType as AgentWorkflowMaterialQueryType;
const requestedBrandName = String(parsed.brandName || "").trim();
const upstreamParams = new URLSearchParams({
resourceType: "task-detail",
[queryType]: normalizedKeyword,
});
if (requestedBrandName) {
upstreamParams.set("brandName", requestedBrandName);
}
const upstreamUrl = `${normalizeBaseUrl( const upstreamUrl = `${normalizeBaseUrl(
config.baseUrl config.baseUrl
)}/standard-model-white-background?resourceType=task-detail&${queryType}=${encodeURIComponent( )}/standard-model-white-background?${upstreamParams.toString()}`;
normalizedKeyword
)}`;
const upstreamResponse = await fetch(upstreamUrl, { const upstreamResponse = await fetch(upstreamUrl, {
method: "GET", method: "GET",
@ -299,9 +322,11 @@ export async function GET(request: NextRequest) {
); );
} }
const requestedBrandName = String(parsed.brandName || "").trim(); const upstreamBrandName = getExternalBrandName(upstreamResult.data);
const sortedCandidates = sortCandidatesByUploadedAtDesc( const sortedCandidates = sortCandidatesByUploadedAtDesc(
(upstreamResult.data.candidates || []).map((item, index) => normalizeCandidate(item, index)) (upstreamResult.data.candidates || []).map((item, index) =>
normalizeCandidate(item, index, upstreamBrandName)
)
); );
const normalizedCandidates = filterCandidatesByBrand(sortedCandidates, requestedBrandName) const normalizedCandidates = filterCandidatesByBrand(sortedCandidates, requestedBrandName)
.filter((candidate) => getRenderableCandidateTargetUrls(candidate, parsed.target).length > 0); .filter((candidate) => getRenderableCandidateTargetUrls(candidate, parsed.target).length > 0);
@ -353,12 +378,7 @@ export async function GET(request: NextRequest) {
matchedSku: String(upstreamResult.data.sku || "").trim() || null, matchedSku: String(upstreamResult.data.sku || "").trim() || null,
brandName: brandName:
selectedCandidate.brandName || selectedCandidate.brandName ||
String( upstreamBrandName ||
upstreamResult.data.brandName ||
upstreamResult.data.brand ||
upstreamResult.data.productBrand ||
""
).trim() ||
requestedBrandName || requestedBrandName ||
null, null,
categoryName: selectedCandidate.categoryName || String(upstreamResult.data.categoryName || "").trim() || null, categoryName: selectedCandidate.categoryName || String(upstreamResult.data.categoryName || "").trim() || null,