优化
This commit is contained in:
@@ -4,6 +4,7 @@ import test from 'node:test'
|
||||
|
||||
const storeSource = readFileSync(new URL('./firstLegOrders.ts', import.meta.url), 'utf8')
|
||||
const apiSource = readFileSync(new URL('../api/firstLeg.ts', import.meta.url), 'utf8')
|
||||
const unifiedApiSource = readFileSync(new URL('../api/unifiedOrders.ts', import.meta.url), 'utf8')
|
||||
|
||||
test('declares the documented merchant warehouse and first-leg endpoints', () => {
|
||||
assert.match(apiSource, /url: '\/merchant\/v1\/warehouses'/)
|
||||
@@ -18,16 +19,57 @@ test('maps transport and status fields instead of treating container mode as tra
|
||||
assert.match(storeSource, /draft\.transportMode === 'ROAD'\) return 'TRUCK'/)
|
||||
assert.match(storeSource, /status === 'SUBMITTED'\) return 'PENDING_REVIEW'/)
|
||||
assert.match(storeSource, /status === 'REJECTED'\) return 'PENDING_REVIEW'/)
|
||||
assert.match(storeSource, /status === 'PROCESSING'\) return 'IN_TRANSIT'/)
|
||||
assert.match(storeSource, /status === 'APPROVED' \|\| status === 'ACCEPTED' \|\| status === 'PROCESSING'\) return 'WAIT_MEASURE'/)
|
||||
assert.match(storeSource, /status === 'COMPLETED'\) return 'DELIVERED'/)
|
||||
})
|
||||
|
||||
test('uses real API data without falling back to demo warehouses or orders', () => {
|
||||
test('prefers unified reads and only falls back to the real legacy API when C02 is unavailable', () => {
|
||||
assert.match(storeSource, /orders\.value = \[\]/)
|
||||
assert.match(storeSource, /warehouses\.value = \[\]/)
|
||||
assert.match(storeSource, /Promise\.allSettled\(\[getMerchantFirstLegOrders\(\), getMerchantWarehouses\(\)\]\)/)
|
||||
assert.match(storeSource, /Promise\.allSettled\(\[getOrdersForClient\(query\), getMerchantWarehouses\(\)\]\)/)
|
||||
assert.match(storeSource, /getMerchantUnifiedOrders\(unifiedQuery\)/)
|
||||
assert.match(storeSource, /isUnifiedOrderQueryUnavailable\(error\)/)
|
||||
assert.match(storeSource, /getMerchantFirstLegOrders\(legacyQuery\(query\)\)/)
|
||||
assert.doesNotMatch(storeSource, /DEMO_PLATFORM_RECEIVING_WAREHOUSES|initialOrders/)
|
||||
})
|
||||
|
||||
test('declares the final C02 row and detail contract in the API adapter', () => {
|
||||
assert.match(unifiedApiSource, /const unifiedOrderBaseUrl = '\/merchant\/v1\/orders'/)
|
||||
assert.doesNotMatch(unifiedApiSource, /orders\/unified/)
|
||||
assert.match(unifiedApiSource, /orderId: number \| string/)
|
||||
assert.match(unifiedApiSource, /mainStatus: ApiUnifiedOrderMainStatus/)
|
||||
assert.match(unifiedApiSource, /nextAction: string \| null/)
|
||||
assert.match(unifiedApiSource, /loadingVersion: number/)
|
||||
assert.match(unifiedApiSource, /pickingVersion: number/)
|
||||
assert.match(unifiedApiSource, /summary: MerchantUnifiedOrderRow/)
|
||||
assert.match(unifiedApiSource, /order: MerchantFirstLegOrderDetail/)
|
||||
assert.match(unifiedApiSource, /timeline: MerchantUnifiedTimelineEvent\[\]/)
|
||||
assert.match(unifiedApiSource, /customNodes\?: MerchantUnifiedCustomNode\[\]/)
|
||||
assert.match(unifiedApiSource, /error\.status === 404 \|\| error\.code === 'A0404'/)
|
||||
})
|
||||
|
||||
test('keeps drafts on the legacy read path without assigning a unified main status', () => {
|
||||
assert.match(storeSource, /getMerchantFirstLegOrders\(legacyQuery\(query, 'DRAFT'\)\)/)
|
||||
assert.match(storeSource, /getById\(id\)\?\.status === 'DRAFT' \? loadLegacyDetail\(id\) : loadUnifiedDetail\(id\)/)
|
||||
assert.match(storeSource, /return loadLegacyDetail\(String\(createdId\)\)/)
|
||||
assert.match(storeSource, /draftLoadError/)
|
||||
})
|
||||
|
||||
test('routes supported filters to C02 without sending DRAFT as a main status', () => {
|
||||
assert.match(storeSource, /interface ClientOrderReadQuery extends MerchantUnifiedOrderQuery/)
|
||||
assert.match(storeSource, /if \(query\.draftOnly\)/)
|
||||
assert.match(storeSource, /const unifiedQuery: MerchantUnifiedOrderQuery/)
|
||||
assert.match(storeSource, /getMerchantUnifiedOrders\(unifiedQuery\)/)
|
||||
})
|
||||
|
||||
test('maps C02 rows by orderId and leaves absent transport details unknown', () => {
|
||||
assert.match(storeSource, /id: String\(summary\.orderId\)/)
|
||||
assert.match(storeSource, /transportMode: null/)
|
||||
assert.match(storeSource, /summary\?\.loading\?\.loadingVersion/)
|
||||
assert.match(storeSource, /summary\?\.loading\?\.pickingVersion/)
|
||||
assert.match(storeSource, /summary\?\.inboundId == null \? '' : String\(summary\.inboundId\)/)
|
||||
})
|
||||
|
||||
test('sends backend-required channel, customs, destination and cargo fields', () => {
|
||||
for (const field of ['pickupMethod', 'channelCode', 'channelName', 'taxMode', 'customsInspection', 'destinationType', 'packageType']) {
|
||||
assert.match(storeSource, new RegExp(field))
|
||||
@@ -63,7 +105,17 @@ test('sends an idempotency key for create and submit writes', () => {
|
||||
|
||||
test('does not expose the contradictory backend rejected state in the client model', () => {
|
||||
assert.match(storeSource, /status === 'REJECTED'\) return 'PENDING_REVIEW'/)
|
||||
assert.match(storeSource, /item\.toStatus === 'SUBMITTED' \|\| item\.toStatus === 'REJECTED' \? 'SUBMITTED'/)
|
||||
assert.match(storeSource, /item\.toStatus === 'REJECTED' \? '订单信息已补充'/)
|
||||
})
|
||||
|
||||
test('maps the final backend timeline and keeps missing custom nodes empty', () => {
|
||||
assert.match(storeSource, /detail\.timeline\.flatMap/)
|
||||
assert.match(storeSource, /item\.mainStatus/)
|
||||
assert.match(storeSource, /\(detail\.customNodes \?\? \[\]\)/)
|
||||
assert.match(storeSource, /\.filter\(\(item\) => item\.customerVisible\)/)
|
||||
assert.match(storeSource, /kind: 'CUSTOM_NODE'/)
|
||||
assert.match(storeSource, /status: null/)
|
||||
assert.match(storeSource, /\.sort\(\(left, right\)/)
|
||||
})
|
||||
|
||||
test('maps backend warehouse snapshots and fulfillment courier fields', () => {
|
||||
@@ -78,5 +130,5 @@ test('keeps failed order loads distinct from empty results', () => {
|
||||
assert.match(storeSource, /const loadError = ref\(''\)/)
|
||||
assert.match(storeSource, /orderResult\.reason instanceof Error/)
|
||||
assert.match(storeSource, /warehouseLoadError/)
|
||||
assert.match(storeSource, /return \{ orders, warehouses, loading, loadedFromApi, loadError, warehouseLoadError/)
|
||||
assert.match(storeSource, /return \{ orders, warehouses, loading, loadedFromApi, loadError, warehouseLoadError, draftLoadError/)
|
||||
})
|
||||
|
||||
@@ -15,11 +15,19 @@ import {
|
||||
type MerchantFirstLegOrderDetail,
|
||||
type MerchantWarehouse,
|
||||
} from '@/modules/first-leg/api/firstLeg'
|
||||
import {
|
||||
getMerchantUnifiedOrder,
|
||||
getMerchantUnifiedOrders,
|
||||
isUnifiedOrderQueryUnavailable,
|
||||
type MerchantUnifiedOrderDetail,
|
||||
type MerchantUnifiedOrderQuery,
|
||||
type MerchantUnifiedOrderRow,
|
||||
} from '@/modules/first-leg/api/unifiedOrders'
|
||||
import type { MerchantTenantStatus } from '@/modules/tenant-management/public'
|
||||
import type { PlatformReceivingWarehouse, PlatformReceivingWarehouseSnapshot } from '@chongchong/shared'
|
||||
import type { FirstLegPartySnapshot } from '@/modules/first-leg/data/firstLegParties'
|
||||
import type { FirstLegOrder, FirstLegOrderDraft, FirstLegOrderTimelineItem } from '@/modules/first-leg/types/firstLegOrder'
|
||||
import { canClientEditFirstLegOrder } from '@/modules/first-leg/utils/firstLegOrder'
|
||||
import { canClientEditFirstLegOrder, getFirstLegStatusLabel } from '@/modules/first-leg/utils/firstLegOrder'
|
||||
|
||||
export type ClientWarehouseType = 'DOMESTIC' | 'FBA' | 'OVERSEAS'
|
||||
export type ClientWarehouse = PlatformReceivingWarehouse & {
|
||||
@@ -32,12 +40,14 @@ const countryCodes: Readonly<Record<string, string>> = {
|
||||
}
|
||||
|
||||
function clientStatus(status: ApiFirstLegStatus): FirstLegOrder['status'] {
|
||||
if (status === 'DRAFT') return 'DRAFT'
|
||||
if (status === 'SUBMITTED') return 'PENDING_REVIEW'
|
||||
// 后端联调任务曾出现 REJECTED,但一期已确认订单不设驳回状态;兼容旧数据时仍按待审核展示。
|
||||
if (status === 'REJECTED') return 'PENDING_REVIEW'
|
||||
if (status === 'APPROVED' || status === 'ACCEPTED') return 'ACCEPTED'
|
||||
if (status === 'PROCESSING') return 'IN_TRANSIT'
|
||||
return status
|
||||
if (status === 'APPROVED' || status === 'ACCEPTED' || status === 'PROCESSING') return 'WAIT_MEASURE'
|
||||
if (status === 'COMPLETED') return 'DELIVERED'
|
||||
if (status === 'CANCELLED') return 'PENDING_REVIEW'
|
||||
return 'PENDING_REVIEW'
|
||||
}
|
||||
|
||||
function clientTransport(order: MerchantFirstLegOrder): FirstLegOrder['transportMode'] {
|
||||
@@ -152,14 +162,97 @@ function partySnapshot(detail: MerchantFirstLegOrderDetail, type: 'SENDER' | 'RE
|
||||
}
|
||||
|
||||
function timeline(detail: MerchantFirstLegOrderDetail): FirstLegOrderTimelineItem[] {
|
||||
return detail.statusHistory.map((item) => ({
|
||||
id: String(item.id),
|
||||
event: item.toStatus === 'SUBMITTED' || item.toStatus === 'REJECTED' ? 'SUBMITTED' : item.toStatus === 'CANCELLED' ? 'CANCELLED' : item.toStatus === 'COMPLETED' ? 'COMPLETED' : item.toStatus === 'ACCEPTED' || item.toStatus === 'APPROVED' ? 'ACCEPTED' : 'IN_TRANSIT',
|
||||
title: item.toStatus === 'REJECTED' ? '平台要求补充订单信息' : item.action || `状态更新为 ${item.toStatus}`,
|
||||
description: item.reason ?? '',
|
||||
return detail.statusHistory.map((item) => {
|
||||
const status = clientStatus(item.toStatus)
|
||||
return {
|
||||
id: String(item.id),
|
||||
kind: 'MAIN_STATUS',
|
||||
status: status === 'DRAFT' ? null : status,
|
||||
nodeType: '',
|
||||
title: item.toStatus === 'REJECTED' ? '订单信息已补充' : item.action || '订单进度已更新',
|
||||
description: item.reason ?? '',
|
||||
operatorName: item.operatorName ?? '',
|
||||
occurredAt: item.occurredAt,
|
||||
plannedAt: '',
|
||||
completed: true,
|
||||
attachmentCount: 0,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function businessSummary(summary?: MerchantUnifiedOrderRow): FirstLegOrder['businessSummary'] {
|
||||
return {
|
||||
totalPackageCount: summary?.totalPackageCount ?? null,
|
||||
actualGrossWeightKg: summary?.actualGrossWeightKg ?? null,
|
||||
actualVolumeCbm: summary?.actualVolumeCbm ?? null,
|
||||
chargeableWeightKg: summary?.measurement?.chargeableWeightKg ?? null,
|
||||
measurementCompletedAt: summary?.measurement?.completedAt ?? '',
|
||||
preloadStatus: summary?.preload?.status ?? '',
|
||||
preloadItemCount: summary?.preload?.itemCount ?? null,
|
||||
loadingStatus: summary?.loading?.status ?? '',
|
||||
loadingVersion: summary?.loading?.loadingVersion ?? null,
|
||||
pickingVersion: summary?.loading?.pickingVersion ?? null,
|
||||
expectedPickCount: summary?.loading?.expectedCount ?? null,
|
||||
pickedCount: summary?.loading?.pickedCount ?? null,
|
||||
evidenceCount: summary?.loading?.evidenceCount ?? null,
|
||||
sealNo: summary?.loading?.sealNo ?? '',
|
||||
deliveryStatus: summary?.delivery?.status ?? '',
|
||||
deliveryCompletedAt: summary?.delivery?.completedAt ?? '',
|
||||
deliveryTrackingNo: summary?.delivery?.trackingNo ?? '',
|
||||
containerNo: summary?.transport?.containerNo ?? '',
|
||||
cabinetNo: summary?.transport?.cabinetNo ?? '',
|
||||
vesselName: summary?.transport?.vesselName ?? '',
|
||||
voyageNo: summary?.transport?.voyageNo ?? '',
|
||||
inboundId: summary?.inboundId == null ? '' : String(summary.inboundId),
|
||||
inboundVersion: summary?.inboundVersion ?? null,
|
||||
inboundCode: summary?.inboundCode ?? '',
|
||||
nextAction: summary?.nextAction ?? '',
|
||||
}
|
||||
}
|
||||
|
||||
const unifiedActionLabels: Readonly<Record<string, string>> = {
|
||||
SUBMIT_ORDER: '订单已提交',
|
||||
APPROVE_ORDER: '订单审核通过',
|
||||
CONFIRM_MEASUREMENT: '测量数据已确认',
|
||||
SMART_SPLIT: '分柜方案已更新',
|
||||
CONFIRM_PRELOAD: '预装清单已确认',
|
||||
COMPLETE_LOADING: '装柜已完成',
|
||||
COMPLETE_DELIVERY: '派送已完成',
|
||||
}
|
||||
|
||||
function unifiedTimeline(detail: MerchantUnifiedOrderDetail): FirstLegOrderTimelineItem[] {
|
||||
const statusItems: FirstLegOrderTimelineItem[] = detail.timeline.flatMap((item, index) => item.mainStatus ? [{
|
||||
id: `status-${item.source}-${item.eventType}-${index}`,
|
||||
kind: 'MAIN_STATUS' as const,
|
||||
status: item.mainStatus,
|
||||
nodeType: '',
|
||||
title: (item.action && unifiedActionLabels[item.action]) || (item.mainStatus ? `进入${getFirstLegStatusLabel(item.mainStatus)}` : '订单进度已更新'),
|
||||
description: item.remark ?? '',
|
||||
operatorName: item.operatorName ?? '',
|
||||
occurredAt: item.occurredAt,
|
||||
}))
|
||||
occurredAt: item.occurredAt ?? '',
|
||||
plannedAt: '',
|
||||
completed: true,
|
||||
attachmentCount: 0,
|
||||
}] : [])
|
||||
const customItems: FirstLegOrderTimelineItem[] = (detail.customNodes ?? [])
|
||||
.filter((item) => item.customerVisible)
|
||||
.map((item) => ({
|
||||
id: `node-${item.id}`,
|
||||
kind: 'CUSTOM_NODE',
|
||||
status: null,
|
||||
nodeType: item.nodeType,
|
||||
title: item.name,
|
||||
description: item.remark ?? '',
|
||||
operatorName: item.operatorName ?? '',
|
||||
occurredAt: item.completedAt ?? item.plannedAt ?? '',
|
||||
plannedAt: item.plannedAt ?? '',
|
||||
completed: Boolean(item.completedAt),
|
||||
attachmentCount: item.attachmentIds.length,
|
||||
}))
|
||||
return [...statusItems, ...customItems].sort((left, right) => {
|
||||
const timeDifference = Date.parse(left.occurredAt) - Date.parse(right.occurredAt)
|
||||
return Number.isNaN(timeDifference) ? 0 : timeDifference
|
||||
})
|
||||
}
|
||||
|
||||
function mapOrder(order: MerchantFirstLegOrder, warehouses: PlatformReceivingWarehouse[], detail?: MerchantFirstLegOrderDetail): FirstLegOrder {
|
||||
@@ -182,7 +275,7 @@ function mapOrder(order: MerchantFirstLegOrder, warehouses: PlatformReceivingWar
|
||||
packageType: item.packageType, hsCode: item.hsCode ?? '', declaredValue: item.declaredValue ?? 0,
|
||||
currency: item.currency ?? 'USD', dangerousGoods: item.dangerousGoods ?? false,
|
||||
})),
|
||||
timeline: detail ? timeline(detail) : [], createdAt: order.createdAt, updatedAt: order.updatedAt,
|
||||
timeline: detail ? timeline(detail) : [], businessSummary: businessSummary(), createdAt: order.createdAt, updatedAt: order.updatedAt,
|
||||
tradeTerm: order.tradeTerm ?? '', destinationCountryCode: order.destinationCountryCode,
|
||||
destinationWarehouseId: order.destinationWarehouseId ? String(order.destinationWarehouseId) : '',
|
||||
destinationWarehouseName: order.destinationWarehouseName, pickupMethod: order.pickupMethod, channelCode: order.channelCode,
|
||||
@@ -191,6 +284,91 @@ function mapOrder(order: MerchantFirstLegOrder, warehouses: PlatformReceivingWar
|
||||
}
|
||||
}
|
||||
|
||||
function mapUnifiedOrderRow(summary: MerchantUnifiedOrderRow, warehouses: PlatformReceivingWarehouse[]): FirstLegOrder {
|
||||
const warehouse = warehouses.find((item) => item.id === String(summary.receivingWarehouseId))
|
||||
return {
|
||||
id: String(summary.orderId), orderNo: summary.orderNo, referenceNo: '', transportMode: null,
|
||||
businessType: 'EXPORT', origin: '', destination: summary.destinationWarehouseName ?? '',
|
||||
receivingWarehouseId: summary.receivingWarehouseId == null ? '' : String(summary.receivingWarehouseId),
|
||||
receivingWarehouseName: summary.receivingWarehouseName ?? '', receivingWarehouseSnapshot: warehouseSnapshot(warehouse),
|
||||
expectedDepartureDate: summary.expectedShipDate ?? '', etd: '', eta: '', shipperPartyId: '', shipperPartySnapshot: null,
|
||||
shipper: '', consigneePartyId: '', consigneePartySnapshot: null, consignee: '', expressCompanyName: '',
|
||||
trackingNumber: summary.delivery?.trackingNo ?? '', priority: 'NORMAL', customerRemark: '', operatorName: '',
|
||||
status: summary.mainStatus, version: 0, items: [], timeline: [], businessSummary: businessSummary(summary),
|
||||
createdAt: summary.createdAt, updatedAt: summary.updatedAt, tradeTerm: '', destinationCountryCode: '',
|
||||
destinationWarehouseId: summary.destinationWarehouseId == null ? '' : String(summary.destinationWarehouseId),
|
||||
destinationWarehouseName: summary.destinationWarehouseName ?? '', pickupMethod: 'SELF_EXPRESS', channelCode: '',
|
||||
channelName: summary.channelName ?? '', taxMode: 'BUY_DECLARATION', customsInspection: false,
|
||||
destinationType: 'PRIVATE', amazonWarehouseCode: '', shipmentId: '',
|
||||
}
|
||||
}
|
||||
|
||||
function mapUnifiedOrderDetail(detail: MerchantUnifiedOrderDetail, warehouses: PlatformReceivingWarehouse[]): FirstLegOrder {
|
||||
const mapped = mapOrder(detail.order.order, warehouses, detail.order)
|
||||
mapped.id = String(detail.summary.orderId)
|
||||
mapped.status = detail.summary.mainStatus
|
||||
mapped.businessSummary = businessSummary(detail.summary)
|
||||
mapped.timeline = unifiedTimeline(detail)
|
||||
mapped.trackingNumber = detail.summary.delivery?.trackingNo ?? mapped.trackingNumber
|
||||
return mapped
|
||||
}
|
||||
|
||||
type OrderListReadResult =
|
||||
| { source: 'unified'; records: MerchantUnifiedOrderRow[]; drafts: MerchantFirstLegOrder[]; draftError: string }
|
||||
| { source: 'legacy'; records: MerchantFirstLegOrder[] }
|
||||
|
||||
interface ClientOrderReadQuery extends MerchantUnifiedOrderQuery {
|
||||
draftOnly?: boolean
|
||||
includeDrafts?: boolean
|
||||
}
|
||||
|
||||
function legacyQuery(query: ClientOrderReadQuery, status?: ApiFirstLegStatus) {
|
||||
return {
|
||||
keyword: query.keyword,
|
||||
status,
|
||||
createdFrom: query.createdFrom,
|
||||
createdTo: query.createdTo,
|
||||
}
|
||||
}
|
||||
|
||||
async function getOrdersForClient(query: ClientOrderReadQuery = {}): Promise<OrderListReadResult> {
|
||||
if (query.draftOnly) {
|
||||
const drafts = await getMerchantFirstLegOrders(legacyQuery(query, 'DRAFT'))
|
||||
return { source: 'legacy', records: drafts.records }
|
||||
}
|
||||
const includeDrafts = query.includeDrafts ?? true
|
||||
const unifiedQuery: MerchantUnifiedOrderQuery = {
|
||||
keyword: query.keyword,
|
||||
orderNo: query.orderNo,
|
||||
mainStatus: query.mainStatus,
|
||||
receivingWarehouseId: query.receivingWarehouseId,
|
||||
destinationWarehouseId: query.destinationWarehouseId,
|
||||
createdFrom: query.createdFrom,
|
||||
createdTo: query.createdTo,
|
||||
page: query.page,
|
||||
size: query.size,
|
||||
}
|
||||
try {
|
||||
const response = await getMerchantUnifiedOrders(unifiedQuery)
|
||||
if (!includeDrafts) return { source: 'unified', records: response.records, drafts: [], draftError: '' }
|
||||
try {
|
||||
const drafts = await getMerchantFirstLegOrders(legacyQuery(query, 'DRAFT'))
|
||||
return { source: 'unified', records: response.records, drafts: drafts.records, draftError: '' }
|
||||
} catch (error) {
|
||||
return {
|
||||
source: 'unified',
|
||||
records: response.records,
|
||||
drafts: [],
|
||||
draftError: error instanceof Error ? error.message : '订单草稿加载失败',
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (!isUnifiedOrderQueryUnavailable(error)) throw error
|
||||
const response = await getMerchantFirstLegOrders(legacyQuery(query))
|
||||
return { source: 'legacy', records: response.records }
|
||||
}
|
||||
}
|
||||
|
||||
function mapWarehouse(item: MerchantWarehouse): ClientWarehouse {
|
||||
return {
|
||||
id: String(item.id), code: item.warehouseCode, name: item.warehouseName, province: '',
|
||||
@@ -207,19 +385,21 @@ export const useFirstLegOrdersStore = defineStore('client-first-leg-orders', ()
|
||||
const loadedFromApi = ref(false)
|
||||
const loadError = ref('')
|
||||
const warehouseLoadError = ref('')
|
||||
const activeCount = computed(() => orders.value.filter((item) => ['PENDING_REVIEW', 'ACCEPTED', 'BOOKED', 'IN_TRANSIT'].includes(item.status)).length)
|
||||
const draftLoadError = ref('')
|
||||
const activeCount = computed(() => orders.value.filter((item) => item.status !== 'DRAFT' && item.status !== 'DELIVERED').length)
|
||||
const pendingCount = computed(() => orders.value.filter((item) => item.status === 'PENDING_REVIEW').length)
|
||||
|
||||
function getById(id: string) { return orders.value.find((item) => item.id === id) }
|
||||
|
||||
async function load() {
|
||||
async function load(query: ClientOrderReadQuery = {}) {
|
||||
loading.value = true
|
||||
loadedFromApi.value = true
|
||||
loadError.value = ''
|
||||
warehouseLoadError.value = ''
|
||||
draftLoadError.value = ''
|
||||
orders.value = []
|
||||
warehouses.value = []
|
||||
const [orderResult, warehouseResult] = await Promise.allSettled([getMerchantFirstLegOrders(), getMerchantWarehouses()])
|
||||
const [orderResult, warehouseResult] = await Promise.allSettled([getOrdersForClient(query), getMerchantWarehouses()])
|
||||
if (warehouseResult.status === 'fulfilled') {
|
||||
warehouses.value = warehouseResult.value.records
|
||||
.filter((item) => item.status === 'ACTIVE' && ['DOMESTIC', 'FBA', 'OVERSEAS'].includes(item.warehouseType))
|
||||
@@ -228,22 +408,47 @@ export const useFirstLegOrdersStore = defineStore('client-first-leg-orders', ()
|
||||
warehouseLoadError.value = warehouseResult.reason instanceof Error ? warehouseResult.reason.message : '公共仓库数据加载失败'
|
||||
}
|
||||
if (orderResult.status === 'fulfilled') {
|
||||
orders.value = orderResult.value.records.map((item) => mapOrder(item, warehouses.value))
|
||||
if (orderResult.value.source === 'unified') {
|
||||
draftLoadError.value = orderResult.value.draftError
|
||||
orders.value = [
|
||||
...orderResult.value.drafts.map((item) => mapOrder(item, warehouses.value)),
|
||||
...orderResult.value.records.map((item) => mapUnifiedOrderRow(item, warehouses.value)),
|
||||
].sort((left, right) => Date.parse(right.createdAt) - Date.parse(left.createdAt))
|
||||
} else {
|
||||
orders.value = orderResult.value.records.map((item) => mapOrder(item, warehouses.value))
|
||||
}
|
||||
} else {
|
||||
loadError.value = orderResult.reason instanceof Error ? orderResult.reason.message : '订单数据加载失败'
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
async function loadDetail(id: string) {
|
||||
const detail = await getMerchantFirstLegOrder(id)
|
||||
const mapped = mapOrder(detail.order, warehouses.value, detail)
|
||||
const index = orders.value.findIndex((item) => item.id === id)
|
||||
function upsertOrder(mapped: FirstLegOrder) {
|
||||
const index = orders.value.findIndex((item) => item.id === mapped.id)
|
||||
if (index >= 0) orders.value[index] = mapped
|
||||
else orders.value.unshift(mapped)
|
||||
return mapped
|
||||
}
|
||||
|
||||
async function loadLegacyDetail(id: string) {
|
||||
const detail = await getMerchantFirstLegOrder(id)
|
||||
return upsertOrder(mapOrder(detail.order, warehouses.value, detail))
|
||||
}
|
||||
|
||||
async function loadUnifiedDetail(id: string) {
|
||||
try {
|
||||
const detail = await getMerchantUnifiedOrder(id)
|
||||
return upsertOrder(mapUnifiedOrderDetail(detail, warehouses.value))
|
||||
} catch (error) {
|
||||
if (!isUnifiedOrderQueryUnavailable(error)) throw error
|
||||
return loadLegacyDetail(id)
|
||||
}
|
||||
}
|
||||
|
||||
async function loadDetail(id: string) {
|
||||
return getById(id)?.status === 'DRAFT' ? loadLegacyDetail(id) : loadUnifiedDetail(id)
|
||||
}
|
||||
|
||||
async function loadWarehouseDetail(id: string) {
|
||||
const detail = await getMerchantWarehouseDetail(id)
|
||||
const mapped = mapWarehouse(detail.warehouse)
|
||||
@@ -276,18 +481,18 @@ export const useFirstLegOrdersStore = defineStore('client-first-leg-orders', ()
|
||||
const order = getById(id)
|
||||
if (!order || !canClientEditFirstLegOrder(order.status)) throw new Error('当前订单状态不允许编辑')
|
||||
await updateMerchantFirstLegOrder(id, savePayload(draft, warehouse, customerName))
|
||||
return loadDetail(id)
|
||||
return loadLegacyDetail(id)
|
||||
}
|
||||
const createdId = await createMerchantFirstLegOrder(savePayload(draft, warehouse, customerName))
|
||||
return loadDetail(String(createdId))
|
||||
return loadLegacyDetail(String(createdId))
|
||||
}
|
||||
|
||||
async function submit(draft: FirstLegOrderDraft, customerName: string, id?: string, companyAuditStatus?: MerchantTenantStatus) {
|
||||
if (companyAuditStatus && companyAuditStatus !== 'ACTIVE') throw new Error('企业资料尚未审核通过,请先完善企业资料并等待平台审核')
|
||||
const order = await saveDraft(draft, customerName, id)
|
||||
await submitMerchantFirstLegOrder(order.id)
|
||||
return loadDetail(order.id)
|
||||
return loadUnifiedDetail(order.id)
|
||||
}
|
||||
|
||||
return { orders, warehouses, loading, loadedFromApi, loadError, warehouseLoadError, activeCount, pendingCount, getById, load, loadDetail, loadWarehouseDetail, saveDraft, submit }
|
||||
return { orders, warehouses, loading, loadedFromApi, loadError, warehouseLoadError, draftLoadError, activeCount, pendingCount, getById, load, loadDetail, loadWarehouseDetail, saveDraft, submit }
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user