/** * OMS 订单接口(Swagger:OMS-Order,与 admin 同源) */ import { axiosInstance } from '@/api/rbac' import { resolveAdminApiPath } from '@/utils/adminApi' function orderUrl(path: string): string { return resolveAdminApiPath(path) } export interface OrderListRequest { page: number pageSize: number /** all 或各状态英文 key,与文档一致 */ status?: string keyword?: string createTimeStart?: string createTimeEnd?: string } export interface OrderListResult { items: any[] total: number } export interface OrderStatusCountsResult { total: number counts: Record } function assertBusinessOk(body: any) { if (body == null) throw new Error('空响应') const code = body.code ?? body.Code const ok = code === undefined || code === null || code === 0 || code === 200 || code === '0' || code === '200' || body.success === true || body.Success === true if (!ok) { throw new Error(body.msg ?? body.Msg ?? body.message ?? body.Message ?? '请求失败') } } /** 取出分页载荷(兼容 data 包裹或顶层直出、items/list/records、camel/Pascal) */ function parseOrderListPayload(resBody: any): OrderListResult { assertBusinessOk(resBody) const inner = resBody.data ?? resBody.Data ?? resBody if (Array.isArray(inner)) { return { items: inner, total: inner.length } } const payload = inner && typeof inner === 'object' && !Array.isArray(inner) ? inner : resBody const items = payload.items ?? payload.Items ?? payload.list ?? payload.List ?? payload.records ?? payload.Records ?? payload.rows ?? payload.Rows ?? (Array.isArray(payload) ? payload : []) const totalRaw = payload.total ?? payload.Total ?? payload.totalCount ?? payload.TotalCount ?? payload.count ?? payload.Count const list = Array.isArray(items) ? items : [] const total = typeof totalRaw === 'number' ? totalRaw : totalRaw != null && totalRaw !== '' ? Number(totalRaw) : list.length return { items: list, total: Number.isFinite(total) ? total : 0, } } /** 分页查询订单列表 POST /order/list */ export async function postOrderList(params: OrderListRequest): Promise { const body: OrderListRequest = { page: params.page, pageSize: params.pageSize, status: params.status ?? 'all', keyword: params.keyword ?? '', } if (params.createTimeStart?.trim()) { body.createTimeStart = params.createTimeStart.trim() } if (params.createTimeEnd?.trim()) { body.createTimeEnd = params.createTimeEnd.trim() } const res = await axiosInstance.post(orderUrl('/order/list'), body) return parseOrderListPayload(res.data) } /** 各状态订单数量聚合 GET /order/status-counts(单次查询,非逐状态分页) */ export async function getOrderStatusCounts(): Promise { const res = await axiosInstance.get(orderUrl('/order/status-counts')) assertBusinessOk(res.data) const inner = res.data?.data ?? res.data?.Data ?? res.data ?? {} const totalRaw = inner.total ?? inner.Total ?? 0 const counts = inner.counts ?? inner.Counts ?? {} return { total: Number(totalRaw) || 0, counts: typeof counts === 'object' && counts !== null ? counts : {}, } } /** 订单详情 GET /order/detail?id= */ export async function getOrderDetail(id: number | string): Promise { const res = await axiosInstance.get(orderUrl('/order/detail'), { params: { id }, }) assertBusinessOk(res.data) return res.data?.data ?? res.data?.Data ?? res.data } export interface OrderIdRequest { id: number | string } export interface OrderExportRequest { status?: string keyword?: string createTimeStart?: string createTimeEnd?: string } export interface OrderPrintResult { printUrl?: string } export interface OrderExportResult { downloadUrl?: string expireAt?: string } async function postOrderById(path: string, body: OrderIdRequest): Promise { const res = await axiosInstance.post(orderUrl(path), { id: body.id }) assertBusinessOk(res.data) } /** POST /order/pay */ export function postOrderPay(body: OrderIdRequest) { return postOrderById('/order/pay', body) } /** POST /order/pre-declare */ export function postOrderPreDeclare(body: OrderIdRequest) { return postOrderById('/order/pre-declare', body) } /** POST /order/intercept */ export function postOrderIntercept(body: OrderIdRequest) { return postOrderById('/order/intercept', body) } /** POST /order/cancel-intercept */ export function postOrderCancelIntercept(body: OrderIdRequest) { return postOrderById('/order/cancel-intercept', body) } /** POST /order/delete */ export function postOrderDelete(body: OrderIdRequest) { return postOrderById('/order/delete', body) } export interface OrderTrackUpsertResult { skipped?: boolean skipReason?: string success?: boolean url?: string requestJson?: string curlCommand?: string statusCode?: number responseBody?: string } /** POST /order/track-upsert-small-bag → 同步调用轨迹 UpsertSmallBag(联调/手动触发) */ export async function postOrderTrackUpsertSmallBag(body: OrderIdRequest): Promise { const res = await axiosInstance.post(orderUrl('/order/track-upsert-small-bag'), { id: body.id }) assertBusinessOk(res.data) const d = res.data?.data ?? res.data?.Data ?? res.data ?? {} return { skipped: d.skipped ?? d.Skipped, skipReason: d.skipReason ?? d.SkipReason, success: d.success ?? d.Success, url: d.url ?? d.Url, requestJson: d.requestJson ?? d.RequestJson, curlCommand: d.curlCommand ?? d.CurlCommand, statusCode: d.statusCode ?? d.StatusCode, responseBody: d.responseBody ?? d.ResponseBody, } } export interface OrderDownstreamForwardResult { success?: boolean supplierCode?: string url?: string requestJson?: string statusCode?: number responseBody?: string } /** POST /order/downstream-forward-create-one → 后端查订单表组装并转发 createOrderOne */ export async function postOrderDownstreamForwardCreateOne( body: OrderIdRequest ): Promise { const res = await axiosInstance.post(orderUrl('/order/downstream-forward-create-one'), { id: body.id }) assertBusinessOk(res.data) const d = res.data?.data ?? res.data?.Data ?? res.data ?? {} return { success: d.success ?? d.Success, supplierCode: d.supplierCode ?? d.SupplierCode, url: d.url ?? d.Url, requestJson: d.requestJson ?? d.RequestJson, statusCode: d.statusCode ?? d.StatusCode, responseBody: d.responseBody ?? d.ResponseBody, } } /** POST /order/print → data.printUrl */ export async function postOrderPrint(body: OrderIdRequest): Promise { const res = await axiosInstance.post(orderUrl('/order/print'), { id: body.id }) assertBusinessOk(res.data) const d = res.data?.data ?? res.data?.Data ?? {} return { printUrl: d.printUrl ?? d.PrintUrl ?? '', } } /** POST /order/export → data.downloadUrl、expireAt */ export async function postOrderExport(params: OrderExportRequest): Promise { const res = await axiosInstance.post(orderUrl('/order/export'), { status: params.status ?? 'all', keyword: params.keyword ?? '', createTimeStart: params.createTimeStart ?? '', createTimeEnd: params.createTimeEnd ?? '', }) assertBusinessOk(res.data) const d = res.data?.data ?? res.data?.Data ?? {} return { downloadUrl: d.downloadUrl ?? d.DownloadUrl ?? '', expireAt: d.expireAt ?? d.ExpireAt ?? '', } } /** POST /order/price-check → data.items + data.failures */ export interface PriceCheckRequest { destinationCountry: string shippingMethod: string cargoWeight: string length: string width: string height: string /** @deprecated 请使用 cargoTypes */ cargoType?: string /** 货物类型(多选,字典 cargo_attribute 编码) */ cargoTypes?: string[] /** 仓库主键(多选;为空则遍历全部仓库) */ warehouseIds?: number[] destinationProvince: string postalCode: string } export interface PriceCheckFailure { productId?: number productCode?: string productName?: string step?: string reason?: string cargoTypeName?: string warehouseName?: string } function normalizePriceCheckFailure(raw: unknown): PriceCheckFailure | null { if (raw == null) return null if (typeof raw === 'string') { const text = raw.trim() return text ? { reason: text } : null } if (typeof raw !== 'object') return null const row = raw as Record const reason = String( row.reason ?? row.Reason ?? row.message ?? row.Message ?? row.msg ?? row.Msg ?? '', ).trim() if (!reason && row.step == null && row.Step == null) return null return { productId: (row.productId ?? row.ProductId) as number | undefined, productCode: (row.productCode ?? row.ProductCode) as string | undefined, productName: (row.productName ?? row.ProductName) as string | undefined, step: (row.step ?? row.Step) as string | undefined, reason: reason || undefined, cargoTypeName: (row.cargoTypeName ?? row.CargoTypeName) as string | undefined, warehouseName: (row.warehouseName ?? row.WarehouseName) as string | undefined, } } /** 解析查价响应(兼容 data 包裹 / 直出、camel/Pascal、failures 在根或 data 内) */ export function parsePriceCheckResponse(resBody: any): { items: any[] failures: PriceCheckFailure[] } { assertBusinessOk(resBody) const root = resBody ?? {} const inner = root.data ?? root.Data ?? root if (Array.isArray(inner)) { return { items: inner, failures: [] } } const payload = inner && typeof inner === 'object' && !Array.isArray(inner) ? inner : root const items = (payload as any).items ?? (payload as any).Items ?? (payload as any).list ?? (payload as any).List ?? [] const rawFailures = (payload as any).failures ?? (payload as any).Failures ?? root.failures ?? root.Failures ?? [] const failureRows = Array.isArray(rawFailures) ? rawFailures : rawFailures && typeof rawFailures === 'object' ? [rawFailures] : [] const failures = failureRows .map(normalizePriceCheckFailure) .filter((f): f is PriceCheckFailure => f != null && Boolean(f.reason?.trim())) const itemList = Array.isArray(items) ? items : [] if (!itemList.length && !failures.length) { const msg = String( root.msg ?? root.Msg ?? root.message ?? root.Message ?? (payload as any).msg ?? (payload as any).Msg ?? (payload as any).message ?? (payload as any).Message ?? '', ).trim() if (msg) { failures.push({ reason: msg }) } } return { items: itemList, failures } } export async function postOrderPriceCheck(params: PriceCheckRequest): Promise<{ items: any[] failures: PriceCheckFailure[] }> { const res = await axiosInstance.post(orderUrl('/order/price-check'), params) return parsePriceCheckResponse(res.data) } /** GET /order/template/list */ export async function getOrderTemplateList(params: { page?: number pageSize?: number type?: 'standard' | 'custom' | string keyword?: string }): Promise { const res = await axiosInstance.get(orderUrl('/order/template/list'), { params: { page: params.page ?? 1, pageSize: params.pageSize ?? 50, type: params.type ?? '', keyword: params.keyword ?? '', }, }) return parseOrderListPayload(res.data) } /** GET /order/template/download?templateId= → Excel 文件流 */ export async function downloadOrderTemplate(templateId: number, fileName: string) { const res = await axiosInstance.get(orderUrl('/order/template/download'), { params: { templateId }, responseType: 'blob', }) const blob = res.data as Blob const ct = (res.headers['content-type'] || '').toString() if (ct.includes('application/json')) { const text = await blob.text() const json = JSON.parse(text) throw new Error(json.msg ?? json.message ?? json.Message ?? '下载失败') } const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = fileName.endsWith('.xlsx') ? fileName : `${fileName}.xlsx` a.style.display = 'none' document.body.appendChild(a) a.click() document.body.removeChild(a) URL.revokeObjectURL(url) } /** POST /order/upload multipart: file + templateId */ export async function postOrderUpload(file: File, templateId: number): Promise<{ taskId?: number }> { const form = new FormData() form.append('file', file) form.append('templateId', String(templateId)) const res = await axiosInstance.post(orderUrl('/order/upload'), form) assertBusinessOk(res.data) const d = res.data?.data ?? res.data?.Data ?? {} const taskId = d.taskId ?? d.TaskId return { taskId: taskId != null ? Number(taskId) : undefined } } /** GET /order/task/list */ export async function getOrderTaskList(params: { page?: number pageSize?: number status?: string keyword?: string }): Promise { const res = await axiosInstance.get(orderUrl('/order/task/list'), { params: { page: params.page ?? 1, pageSize: params.pageSize ?? 20, status: params.status ?? '', keyword: params.keyword ?? '', }, }) return parseOrderListPayload(res.data) } /** GET /order/task/detail?taskId= */ export async function getOrderTaskDetail(taskId: number | string): Promise { const res = await axiosInstance.get(orderUrl('/order/task/detail'), { params: { taskId }, }) assertBusinessOk(res.data) return res.data?.data ?? res.data?.Data ?? {} } /** POST /order/parcel/create */ export async function postOrderParcelCreate(body: Record): Promise { const res = await axiosInstance.post(orderUrl('/order/parcel/create'), body) assertBusinessOk(res.data) return res.data?.data ?? res.data?.Data ?? {} } /** POST /order/update */ export async function postOrderUpdate(body: Record): Promise { const res = await axiosInstance.post(orderUrl('/order/update'), body) assertBusinessOk(res.data) return res.data?.data ?? res.data?.Data ?? res.data } /** POST /order/weight/update */ export async function postOrderWeightUpdate(body: { id: number | string weights: Array<{ type: string length?: number width?: number height?: number actualWeight?: number }> }): Promise { const res = await axiosInstance.post(orderUrl('/order/weight/update'), body) assertBusinessOk(res.data) return res.data?.data ?? res.data?.Data ?? res.data } /** POST /order/fee/recalculate-receivable */ export async function postOrderRecalculateReceivable(body: OrderIdRequest): Promise { const res = await axiosInstance.post(orderUrl('/order/fee/recalculate-receivable'), { id: body.id }) assertBusinessOk(res.data) return res.data?.data ?? res.data?.Data ?? res.data } /** POST /order/fee/recalculate-payable */ export async function postOrderRecalculatePayable(body: OrderIdRequest): Promise { const res = await axiosInstance.post(orderUrl('/order/fee/recalculate-payable'), { id: body.id }) assertBusinessOk(res.data) return res.data?.data ?? res.data?.Data ?? res.data }