diff --git a/furniture-3d-system/src/app/api/supply-chain/limit-management/breach-orders/[id]/route.ts b/furniture-3d-system/src/app/api/supply-chain/limit-management/breach-orders/[id]/route.ts index 30f7d695..99a91d48 100644 --- a/furniture-3d-system/src/app/api/supply-chain/limit-management/breach-orders/[id]/route.ts +++ b/furniture-3d-system/src/app/api/supply-chain/limit-management/breach-orders/[id]/route.ts @@ -1,4 +1,4 @@ -import { NextRequest } from 'next/server' +import { NextRequest, NextResponse } from 'next/server' import { z } from 'zod' import { ErrorCode } from '@/server/core/errors' import { handleRequest, jsonError, jsonSuccess } from '@/server/core/response' @@ -46,7 +46,8 @@ export async function GET(request: NextRequest, context: { params: Promise<{ id: } export async function POST(request: NextRequest, context: { params: Promise<{ id: string }> }) { - return handleRequest(request, async (ctx) => { + // 申诉与审核返回不同结果形状,统一按 unknown 返回(与既有路由一致)。 + return handleRequest(request, async (ctx): Promise> => { const { id } = await context.params const parsed = actionSchema.safeParse(await request.json().catch(() => null)) if (!parsed.success) { diff --git a/furniture-3d-system/src/app/api/supply-chain/limit-management/breach-orders/route.ts b/furniture-3d-system/src/app/api/supply-chain/limit-management/breach-orders/route.ts index 797e436e..253d07ae 100644 --- a/furniture-3d-system/src/app/api/supply-chain/limit-management/breach-orders/route.ts +++ b/furniture-3d-system/src/app/api/supply-chain/limit-management/breach-orders/route.ts @@ -1,4 +1,4 @@ -import { NextRequest } from 'next/server' +import { NextRequest, NextResponse } from 'next/server' import { z } from 'zod' import { ErrorCode } from '@/server/core/errors' import { handleRequest, jsonError, jsonSuccess } from '@/server/core/response' @@ -13,8 +13,8 @@ const listQuerySchema = z.object({ const filtersSchema = z.object({ status: z.array(z.string()).optional(), - platform: z.array(z.string()).optional(), - shopName: z.array(z.string()).optional(), + platform: z.array(z.string().max(40)).max(50).optional(), + shopName: z.array(z.string().max(120)).max(50).optional(), ownerName: z.array(z.string()).optional(), keyword: z.string().optional(), itemCode: z.array(z.string().max(120)).max(50).optional(), @@ -23,8 +23,6 @@ const filtersSchema = z.object({ orderNo: z.array(z.string().max(80)).max(50).optional(), ownerKeyword: z.array(z.string().max(60)).max(50).optional(), appealType: z.array(z.string().max(60)).max(50).optional(), - platform: z.array(z.string().max(40)).max(50).optional(), - shopName: z.array(z.string().max(120)).max(50).optional(), listedFrom: z.string().max(10).optional(), listedTo: z.string().max(10).optional(), flowFrom: z.string().max(10).optional(), @@ -90,7 +88,9 @@ export async function GET(request: NextRequest) { } export async function POST(request: NextRequest) { - return handleRequest(request, async (ctx) => { + // 一个接口分支返回多种结果形状(生成 / 导入 / 标记离职…),统一按 unknown 返回, + // 与 reference-image-estimate 等既有路由保持一致。 + return handleRequest(request, async (ctx): Promise> => { const parsed = actionSchema.safeParse(await request.json().catch(() => null)) if (!parsed.success) return jsonError(ErrorCode.VALIDATION_INVALID_FORMAT, '请求内容不正确', 400, ctx.requestId) const viewer = await supplyChainBreachOrderService.resolveViewer(ctx.user) diff --git a/furniture-3d-system/src/app/supply-chain/management/custom-table/BreachOrderTab.tsx b/furniture-3d-system/src/app/supply-chain/management/custom-table/BreachOrderTab.tsx index a790188a..ba23f4e7 100644 --- a/furniture-3d-system/src/app/supply-chain/management/custom-table/BreachOrderTab.tsx +++ b/furniture-3d-system/src/app/supply-chain/management/custom-table/BreachOrderTab.tsx @@ -86,7 +86,8 @@ function MultiFilterChip({ }: { label: string placeholder: string - field: 'owner' | 'itemCode' | 'orderNo' + /** 与 `/api/supply-chain/limit-management/breach-orders/filter-options` 支持的字段保持一致 */ + field: 'owner' | 'itemCode' | 'orderNo' | 'shopStyleCode' | 'shopItemCode' | 'appealType' | 'platform' | 'shopName' values: string[] onChange: (values: string[]) => void width?: number diff --git a/furniture-3d-system/src/lib/supply-chain-product-archive.ts b/furniture-3d-system/src/lib/supply-chain-product-archive.ts index a8e10e8b..71d31a4c 100644 --- a/furniture-3d-system/src/lib/supply-chain-product-archive.ts +++ b/furniture-3d-system/src/lib/supply-chain-product-archive.ts @@ -210,6 +210,10 @@ export type ProductArchiveFilters = { productStatus?: ProductArchiveStatusFilter[] productionType?: string[] material?: string[] + /** 材质等级(从「材质」文本识别 E0 / E1 / ENF) */ + materialLevel?: string[] + /** 是否有检测报告(外部检测报告接口按 SPU 匹配,「有 / 无」) */ + inspectionReport?: string[] color?: string[] brand?: string[] supplier?: string[] diff --git a/furniture-3d-system/src/server/core/errors.ts b/furniture-3d-system/src/server/core/errors.ts index e4a4c25c..f412e408 100644 --- a/furniture-3d-system/src/server/core/errors.ts +++ b/furniture-3d-system/src/server/core/errors.ts @@ -44,6 +44,9 @@ export enum ErrorCode { SUPPLY_CHAIN_CATEGORY_GROUP_TIER_NOT_FOUND = 'SUPPLY_CHAIN_CATEGORY_GROUP_TIER_001', SUPPLY_CHAIN_CATEGORY_GROUP_TIER_EXISTS = 'SUPPLY_CHAIN_CATEGORY_GROUP_TIER_002', + // 通用资源错误 RESOURCE_xxx(跨模块的「资源不存在」,如破价订单查询) + RESOURCE_NOT_FOUND = 'RESOURCE_001', + // 停产需求管理错误 PRODUCTION_STOP_xxx PRODUCTION_STOP_DEMAND_NOT_FOUND = 'PRODUCTION_STOP_001', PRODUCTION_STOP_ITEM_NOT_FOUND = 'PRODUCTION_STOP_002', @@ -148,6 +151,7 @@ export const ERROR_MESSAGES: Record = { [ErrorCode.PRODUCTION_STOP_REASON_CATEGORY_IN_USE]: '该停产原因分类已被需求使用,不能删除', [ErrorCode.SUPPLY_CHAIN_CATEGORY_GROUP_TIER_NOT_FOUND]: '分类档位不存在', [ErrorCode.SUPPLY_CHAIN_CATEGORY_GROUP_TIER_EXISTS]: '该分类下已存在同名规模标签', + [ErrorCode.RESOURCE_NOT_FOUND]: '资源不存在', // 认证错误 [ErrorCode.AUTH_INVALID_CREDENTIALS]: '用户名或密码错误', [ErrorCode.AUTH_INVALID_TOKEN]: '无效的认证令牌', @@ -262,6 +266,7 @@ export const ERROR_HTTP_STATUS: Record = { [ErrorCode.SUPPLY_CHAIN_OWNER_CONFIG_NOT_FOUND]: HTTP_STATUS.NOT_FOUND, [ErrorCode.SUPPLY_CHAIN_CATEGORY_GROUP_TIER_NOT_FOUND]: HTTP_STATUS.NOT_FOUND, [ErrorCode.SUPPLY_CHAIN_CATEGORY_GROUP_TIER_EXISTS]: HTTP_STATUS.CONFLICT, + [ErrorCode.RESOURCE_NOT_FOUND]: HTTP_STATUS.NOT_FOUND, [ErrorCode.PRODUCTION_STOP_DEMAND_NOT_FOUND]: HTTP_STATUS.NOT_FOUND, [ErrorCode.PRODUCTION_STOP_ITEM_NOT_FOUND]: HTTP_STATUS.NOT_FOUND, [ErrorCode.PRODUCTION_STOP_REASON_CATEGORY_NOT_FOUND]: HTTP_STATUS.NOT_FOUND, diff --git a/furniture-3d-system/src/server/repositories/supply-chain-product-archive-select.ts b/furniture-3d-system/src/server/repositories/supply-chain-product-archive-select.ts index b374e7e1..1159f05a 100644 --- a/furniture-3d-system/src/server/repositories/supply-chain-product-archive-select.ts +++ b/furniture-3d-system/src/server/repositories/supply-chain-product-archive-select.ts @@ -28,7 +28,6 @@ export const productArchiveSelect = { opsHead: true, productStatus: true, productionType: true, - sabcRating: true, material: true, color: true, weight: true, diff --git a/furniture-3d-system/src/server/repositories/supply-chain-product-archive.repository.ts b/furniture-3d-system/src/server/repositories/supply-chain-product-archive.repository.ts index 667d60fd..3889f2d3 100644 --- a/furniture-3d-system/src/server/repositories/supply-chain-product-archive.repository.ts +++ b/furniture-3d-system/src/server/repositories/supply-chain-product-archive.repository.ts @@ -137,7 +137,9 @@ class SupplyChainProductArchiveRepositoryClass implements SupplyChainProductArch const query = await preparePeriodArchiveQuery(params.filters, params.field) // 无其他筛选时走 SQL 侧 DISTINCT + 搜索下推,不再把全表取值拉进内存去重。 if (query.ids === null && Object.keys(query.where).length === 0) { - return listColumnOptionsFromSql(field, params, params.field === 'storageType') + // 「入库/代发 / 材质等级 / 是否有检测报告」都在上面的专用分支里算过候选值, + // 走到这里的一定是原始档案列,按原值出候选值即可。 + return listColumnOptionsFromSql(field, params, false) } const records = await readSelectedArchives(query, { [field]: true } as Prisma.SupplyChainProductArchiveSelect) const values = records.map((record) => { diff --git a/furniture-3d-system/src/server/services/bom-costing/bom-costing-multimodal-gateway.ts b/furniture-3d-system/src/server/services/bom-costing/bom-costing-multimodal-gateway.ts index b183ef42..4092e9f7 100644 --- a/furniture-3d-system/src/server/services/bom-costing/bom-costing-multimodal-gateway.ts +++ b/furniture-3d-system/src/server/services/bom-costing/bom-costing-multimodal-gateway.ts @@ -40,7 +40,13 @@ interface BomCostingChatCompletionResponse { completedFromJsonPayload: boolean } -export type BomCostingMultimodalOperation = 'IMAGE_FACTS' | 'SYNTHESIS' +/** + * 多模态调用用途: + * - IMAGE_FACTS:图片事实抽取(BOM 识图 / 后台截图识别) + * - IMAGE_EXTRACTION:纯图片信息提取(破价申诉凭证识别:优惠明细、链接时间) + * - SYNTHESIS:结合图片与文本的复核/汇总 + */ +export type BomCostingMultimodalOperation = 'IMAGE_FACTS' | 'IMAGE_EXTRACTION' | 'SYNTHESIS' const BOM_COSTING_REASONING_EFFORTS = new Set([ 'none', diff --git a/furniture-3d-system/src/server/services/supply-chain-breach-evidence.service.ts b/furniture-3d-system/src/server/services/supply-chain-breach-evidence.service.ts index 81d3f888..52eef20b 100644 --- a/furniture-3d-system/src/server/services/supply-chain-breach-evidence.service.ts +++ b/furniture-3d-system/src/server/services/supply-chain-breach-evidence.service.ts @@ -38,6 +38,7 @@ export async function recognizeBreachEvidence(image: string): Promise