From f51e51d50f74b2a75e2921d4ebc4d614f97f414a Mon Sep 17 00:00:00 2001 From: liuyihe <2513762445@qq.com> Date: Thu, 29 Oct 2026 13:37:28 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/cross-border/PROTOTYPE_MATRIX.md | 3 ++ .../cross-border/api/businessOrders.ts | 2 +- src/modules/cross-border/api/orderBudgets.ts | 13 ++++++ src/modules/cross-border/api/procurement.ts | 5 +++ .../cross-border/businessOrders.test.mjs | 23 ++++++++-- .../components/BusinessOrdersView.vue | 11 ++++- .../components/ProcurementDetailPanel.vue | 43 ++++++++++--------- .../components/TransportDemandForm.vue | 2 +- src/modules/cross-border/procurement.test.mjs | 27 +++++++++++- .../cross-border/transportDemandForm.test.mjs | 8 ++-- .../cross-border/transportDemandForm.ts | 10 +++-- .../cross-border/views/ProcurementView.vue | 26 +++++++++-- 12 files changed, 133 insertions(+), 40 deletions(-) create mode 100644 src/modules/cross-border/api/orderBudgets.ts diff --git a/src/modules/cross-border/PROTOTYPE_MATRIX.md b/src/modules/cross-border/PROTOTYPE_MATRIX.md index 0742710..e91ab40 100644 --- a/src/modules/cross-border/PROTOTYPE_MATRIX.md +++ b/src/modules/cross-border/PROTOTYPE_MATRIX.md @@ -32,3 +32,6 @@ | 两类业务 | 列表、详情、承运安排 | 既有独立路由及只读承运摘要 | 本轮不改变承载;Client 不新增编辑路由 | 既有行为回归 | 统一表单组件和转换逻辑各自位于应用内部,运行时不跨应用引用。两端业务组件源码一致性另作定向检查;下单数据不允许混入客户标识,Admin 在 API 参数显式选择客户,Client 由认证会话确定客户。 + + +2026-10-29 用户截图调整:采购待确认支持确认或必填原因驳回;四张实收/库存数量卡片置顶,商品及收件信息置底。本土卡车数量改托数,托数及预算须为正数。采购及卡车先等待Finance余额/授信冻结成功,再以同一幂等键建单;不足保留表单并提示原因。自动检查与人工视觉验收分别记录;待人工1920×1080、100%截图确认。 diff --git a/src/modules/cross-border/api/businessOrders.ts b/src/modules/cross-border/api/businessOrders.ts index b54b2de..a4e37e3 100644 --- a/src/modules/cross-border/api/businessOrders.ts +++ b/src/modules/cross-border/api/businessOrders.ts @@ -95,7 +95,7 @@ export interface TruckCreate { destinationContactPhone: string pickupAt: string deliveryAt: string - packageCount: number + palletCount: number totalWeightKg: number totalVolumeCbm: number budgetAmount?: number diff --git a/src/modules/cross-border/api/orderBudgets.ts b/src/modules/cross-border/api/orderBudgets.ts new file mode 100644 index 0000000..afbe31d --- /dev/null +++ b/src/modules/cross-border/api/orderBudgets.ts @@ -0,0 +1,13 @@ +import { apiRequest } from '@/api/http' +interface BudgetResult { status: string; usable: boolean; amountCny: number | string; message: string; orderNo: string | null } +const base = '/merchant/v1/last-leg/order-budgets' +// 资金回执成功才继续下单;超时保留当前幂等键,允许用户再次核对。 +export async function requireOrderBudget(kind: 'procurement' | 'trucking', key: string, amount: number, currency: string) { + const url = `${base}/${kind}/${encodeURIComponent(key)}` + let result = await apiRequest({ method: 'POST', url, data: { amount, currency } }) + for (let attempt = 0; result.status === 'FREEZE_PENDING' && attempt < 12; attempt++) { + await new Promise(resolve => setTimeout(resolve, 1000)) + result = await apiRequest({ method: 'GET', url }) + } + if (!result.usable) throw new Error(result.message || '余额及授信校验未完成,请稍后重试') +} diff --git a/src/modules/cross-border/api/procurement.ts b/src/modules/cross-border/api/procurement.ts index 38883d9..32fd12f 100644 --- a/src/modules/cross-border/api/procurement.ts +++ b/src/modules/cross-border/api/procurement.ts @@ -118,6 +118,8 @@ export interface ProcurementWorkflow { orderNo: string version: number status: string + rejectionReason: string | null + photosNeedUpdate: boolean receivedQuantity: number stockQuantity: number reservedQuantity: number @@ -144,6 +146,9 @@ export function confirmProcurement(orderNo: string, data: { version: number; ide return apiRequest({ method: 'POST', url: `${endpoint}/${encodeURIComponent(orderNo)}/confirm`, data }) } +export function rejectProcurement(orderNo: string, data: { version: number; idempotencyKey: string; reason: string }) { + return apiRequest({ method: 'POST', url: `${endpoint}/${encodeURIComponent(orderNo)}/reject`, data }) +} export function getProcurementFile(orderNo: string, fileId: string) { return apiBlobRequest({ method: 'GET', url: `${endpoint}/${encodeURIComponent(orderNo)}/files/${encodeURIComponent(fileId)}/content` }) } diff --git a/src/modules/cross-border/businessOrders.test.mjs b/src/modules/cross-border/businessOrders.test.mjs index 954bfab..ce6d659 100644 --- a/src/modules/cross-border/businessOrders.test.mjs +++ b/src/modules/cross-border/businessOrders.test.mjs @@ -119,7 +119,7 @@ test('uses the shared dense order-list and detail visual language', () => { assert.match(view, /\.detail-grid div \{[^}]*min-height: 34px;[^}]*grid-template-columns: 76px minmax\(0, 1fr\)/) }) -function transportHarness(kind = 'trucking', failFirst = false) { +function transportHarness(kind = 'trucking', failFirst = false, budgetCheck = async () => {}) { const calls = [] const script = view.match(/