优化
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
getPlatformUnifiedOrder,
|
||||
downloadPlatformProductImage,
|
||||
listPlatformUnifiedOrders,
|
||||
getPlatformUnifiedOrderStatusCounts,
|
||||
listPlatformUnifiedOrderFeeDetails,
|
||||
updatePlatformUnifiedOrderDeclaration,
|
||||
updatePlatformUnifiedOrderPlanning,
|
||||
@@ -26,6 +27,14 @@ describe('unified orders API contract', () => {
|
||||
vi.mocked(http.put).mockReset()
|
||||
})
|
||||
|
||||
it('requests unpaged counts without main status and preserves unknown counts as absent', async () => {
|
||||
vi.mocked(http.get).mockResolvedValue({ data: { counts: { PENDING_REVIEW: 8, WAIT_MEASURE: 0, LOADED: -1, LOADING: null, DELIVERED: '2' } } })
|
||||
await expect(getPlatformUnifiedOrderStatusCounts({ inboundCode: 'IN-8', loaded: false, fullContainer: false, channelName: '', ...{ page: 2, size: 20, mainStatus: 'LOADING' } })).resolves.toEqual({ counts: { PENDING_REVIEW: 8, WAIT_MEASURE: 0 } })
|
||||
expect(http.get).toHaveBeenCalledWith('/platform/v1/orders/status-counts', {
|
||||
params: { inboundCode: 'IN-8', loaded: false, fullContainer: false },
|
||||
})
|
||||
})
|
||||
|
||||
it('uploads the old-system workbook with a retry-safe key', async () => {
|
||||
vi.mocked(http.post).mockResolvedValue({ data: { total: 1, succeeded: 1, failed: 0, items: [] } })
|
||||
const file = new File(['xlsx'], 'legacy.xlsx', { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
|
||||
|
||||
@@ -11,16 +11,26 @@ export type UnifiedOrderMainStatus =
|
||||
| 'LOADED'
|
||||
| 'DELIVERED'
|
||||
| 'COMPLETED'
|
||||
| 'WAIT_WEIGHT_CONFIRM' | 'WEIGHT_CONFIRMED' | 'WAIT_CUSTOMS_DOCS' | 'EXPORT_CUSTOMS'
|
||||
| 'SAILING_CLEARANCE' | 'WAIT_UNLOAD' | 'WAIT_DISPATCH' | 'OUTBOUND_DOCUMENT' | 'DELIVERING' | 'SIGNED'
|
||||
|
||||
export const unifiedOrderStatusOptions: Array<{ value: UnifiedOrderMainStatus; label: string }> = [
|
||||
{ value: 'PENDING_REVIEW', label: '待审核' },
|
||||
{ value: 'WAIT_MEASURE', label: '待测量数据' },
|
||||
{ value: 'WAIT_WEIGHT_CONFIRM', label: '待客户确认' },
|
||||
{ value: 'WEIGHT_CONFIRMED', label: '已确认数据' },
|
||||
{ value: 'WAIT_CUSTOMS_DOCS', label: '待上传资料' },
|
||||
{ value: 'WAIT_PALLETIZE', label: '一件代发打托' },
|
||||
{ value: 'WAIT_SPLIT', label: '待分柜' },
|
||||
{ value: 'LOADING', label: '装柜中' },
|
||||
{ value: 'LOADED', label: '装柜完成' },
|
||||
{ value: 'DELIVERED', label: '派送完成' },
|
||||
{ value: 'COMPLETED', label: '已完成' },
|
||||
{ value: 'EXPORT_CUSTOMS', label: '出口报关' },
|
||||
{ value: 'SAILING_CLEARANCE', label: '已开船/待清关' },
|
||||
{ value: 'WAIT_UNLOAD', label: '待拆柜' },
|
||||
{ value: 'WAIT_DISPATCH', label: '待排车' },
|
||||
{ value: 'OUTBOUND_DOCUMENT', label: '出库单' },
|
||||
{ value: 'DELIVERING', label: '派送中' },
|
||||
{ value: 'SIGNED', label: '签收完成' },
|
||||
]
|
||||
|
||||
export interface UnifiedOrderMeasurementSummary {
|
||||
@@ -314,6 +324,23 @@ export interface UnifiedOrderQuery {
|
||||
size: number
|
||||
}
|
||||
|
||||
export type UnifiedOrderStatusCountQuery = Omit<UnifiedOrderQuery, 'page' | 'size' | 'mainStatus'>
|
||||
export interface UnifiedOrderStatusCounts {
|
||||
counts: Partial<Record<UnifiedOrderMainStatus | 'MEASUREMENT_REVIEW', number>>
|
||||
}
|
||||
|
||||
export async function getPlatformUnifiedOrderStatusCounts(query: UnifiedOrderStatusCountQuery): Promise<UnifiedOrderStatusCounts> {
|
||||
// Strip these fields at runtime too, so callers cannot accidentally scope the other tabs.
|
||||
const params = Object.fromEntries(Object.entries(query).filter(([key, value]) =>
|
||||
!['page', 'size', 'mainStatus'].includes(key) && value !== undefined && value !== ''))
|
||||
const response = await http.get<ApiEnvelope<UnifiedOrderStatusCounts>, ApiEnvelope<UnifiedOrderStatusCounts>>(
|
||||
`${unifiedOrdersApiPath}/status-counts`, { params },
|
||||
)
|
||||
const result = unwrapApiResponse(response)
|
||||
return { counts: Object.fromEntries(Object.entries(result.counts || {}).filter(([, count]) =>
|
||||
typeof count === 'number' && Number.isSafeInteger(count) && count >= 0)) }
|
||||
}
|
||||
|
||||
type PagePayload = Omit<UnifiedOrderPageResource, 'page' | 'size' | 'total' | 'pages'> & {
|
||||
page: number | string
|
||||
size: number | string
|
||||
@@ -667,5 +694,7 @@ export async function listPlatformUnifiedOrderFeeDetails(accountId: string, inbo
|
||||
}
|
||||
|
||||
export function unifiedOrderStatusLabel(status: UnifiedOrderMainStatus) {
|
||||
if (status === 'DELIVERED') return '签收完成'
|
||||
if (status === 'COMPLETED') return '已完成'
|
||||
return unifiedOrderStatusOptions.find((item) => item.value === status)?.label || '未知状态'
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ vi.mock('@/modules/inbounds', () => ({ downloadWeightImage: vi.fn(), getInboundM
|
||||
vi.mock('@/modules/unified-orders/workflows', () => ({ UnifiedOrderWorkflowPanel: { template: '<div />' } }))
|
||||
vi.mock('@/modules/unified-orders/api/unifiedOrders', () => ({
|
||||
updatePlatformUnifiedOrderRemarks: vi.fn(), approvePlatformUnifiedOrder: vi.fn(), batchApprovePlatformUnifiedOrders: vi.fn(),
|
||||
getPlatformUnifiedOrder: vi.fn(), listPlatformUnifiedOrderFeeDetails: vi.fn(), listPlatformUnifiedOrders: vi.fn(),
|
||||
getPlatformUnifiedOrder: vi.fn(), listPlatformUnifiedOrderFeeDetails: vi.fn(), getPlatformUnifiedOrderStatusCounts: vi.fn().mockResolvedValue({ counts: {} }), listPlatformUnifiedOrders: vi.fn(),
|
||||
unifiedOrderStatusOptions: [{ value: 'WAIT_SPLIT', label: '待分柜' }],
|
||||
}))
|
||||
vi.mock('@/modules/unified-orders/api/coLoadGroups', () => ({
|
||||
|
||||
@@ -28,7 +28,7 @@ vi.mock('@/shared/api/inboundCodeRelations', () => ({
|
||||
vi.mock('@/modules/unified-orders/api/unifiedOrders', () => ({
|
||||
updatePlatformUnifiedOrderRemarks: vi.fn(), approvePlatformUnifiedOrder: vi.fn(), batchApprovePlatformUnifiedOrders: vi.fn(),
|
||||
downloadPlatformProductImage: vi.fn(),
|
||||
getPlatformUnifiedOrder: vi.fn(), listPlatformUnifiedOrderFeeDetails: vi.fn(), listPlatformUnifiedOrders: vi.fn(),
|
||||
getPlatformUnifiedOrder: vi.fn(), listPlatformUnifiedOrderFeeDetails: vi.fn(), getPlatformUnifiedOrderStatusCounts: vi.fn().mockResolvedValue({ counts: {} }), listPlatformUnifiedOrders: vi.fn(),
|
||||
unifiedOrderStatusOptions: [],
|
||||
}))
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { flushPromises, shallowMount } from '@vue/test-utils'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { listPlatformUnifiedOrders, updatePlatformUnifiedOrderPlanning } from '@/modules/unified-orders/api/unifiedOrders'
|
||||
import { getPlatformUnifiedOrderStatusCounts, listPlatformUnifiedOrders, updatePlatformUnifiedOrderPlanning } from '@/modules/unified-orders/api/unifiedOrders'
|
||||
import { createPlatformExportTask } from '@/modules/downloads'
|
||||
import { showExportTaskCreatedDialog } from '@/shared/components/exportTaskCreatedDialog'
|
||||
import { ApiResponseError } from '@/shared/api/http'
|
||||
@@ -31,7 +31,7 @@ vi.mock('@/modules/unified-orders/api/unifiedOrders', () => ({
|
||||
approvePlatformUnifiedOrder: vi.fn(),
|
||||
getPlatformUnifiedOrder: vi.fn(),
|
||||
listPlatformUnifiedOrderFeeDetails: vi.fn(),
|
||||
listPlatformUnifiedOrders: vi.fn(),
|
||||
getPlatformUnifiedOrderStatusCounts: vi.fn().mockResolvedValue({ counts: {} }), listPlatformUnifiedOrders: vi.fn(),
|
||||
updatePlatformUnifiedOrderPlanning: vi.fn(),
|
||||
unifiedOrderStatusOptions: [
|
||||
{ value: 'PENDING_REVIEW', label: '待审核' },
|
||||
@@ -39,8 +39,8 @@ vi.mock('@/modules/unified-orders/api/unifiedOrders', () => ({
|
||||
{ value: 'WAIT_SPLIT', label: '待分柜' },
|
||||
{ value: 'LOADING', label: '装柜中' },
|
||||
{ value: 'LOADED', label: '装柜完成' },
|
||||
{ value: 'DELIVERED', label: '派送完成' },
|
||||
{ value: 'COMPLETED', label: '已完成' },
|
||||
{ value: 'DELIVERING', label: '派送中' },
|
||||
{ value: 'SIGNED', label: '签收完成' },
|
||||
],
|
||||
}))
|
||||
|
||||
@@ -69,12 +69,70 @@ function mountView() {
|
||||
|
||||
describe('UnifiedOrdersView list request coordination', () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(getPlatformUnifiedOrderStatusCounts).mockReset().mockResolvedValue({ counts: {} })
|
||||
vi.mocked(listPlatformUnifiedOrders).mockReset().mockResolvedValue(emptyPage())
|
||||
vi.mocked(updatePlatformUnifiedOrderPlanning).mockReset()
|
||||
vi.mocked(createPlatformExportTask).mockReset().mockResolvedValue({ taskName: '国内仓订单', taskNo: 'EXP-1' } as never)
|
||||
vi.mocked(showExportTaskCreatedDialog).mockReset().mockResolvedValue(false)
|
||||
})
|
||||
|
||||
it('shows only supported counts, keeps all text-only and never scopes counts by status or pagination', async () => {
|
||||
vi.mocked(getPlatformUnifiedOrderStatusCounts).mockResolvedValue({ counts: { PENDING_REVIEW: 12, WAIT_MEASURE: 0, SIGNED: 3 } })
|
||||
const wrapper = mountView()
|
||||
await flushPromises()
|
||||
const tabs = wrapper.findAll('[role="tab"]')
|
||||
expect(tabs[0]!.text()).toBe('全部')
|
||||
expect(tabs[1]!.text()).toBe('待审核(12)')
|
||||
expect(tabs[2]!.text()).toBe('待测量数据(0)')
|
||||
expect(tabs[3]!.text()).toBe('测量数据审核')
|
||||
expect(tabs.at(-1)!.text()).toBe('签收完成(3)')
|
||||
expect(tabs.map((tab) => tab.text())).not.toContain('派送完成')
|
||||
expect(tabs.map((tab) => tab.text())).not.toContain('已完成')
|
||||
await tabs[1]!.trigger('click')
|
||||
wrapper.getComponent({ name: 'DataTable' }).vm.$emit('update:page', 2)
|
||||
await flushPromises()
|
||||
expect(getPlatformUnifiedOrderStatusCounts).toHaveBeenCalledTimes(1)
|
||||
const toolbar = wrapper.getComponent({ name: 'QueryToolbar' })
|
||||
toolbar.vm.$emit('update:modelValue', { ...toolbar.props('modelValue'), inboundCode: ' IN-9 ', loaded: 'false' })
|
||||
toolbar.vm.$emit('search')
|
||||
await flushPromises()
|
||||
expect(getPlatformUnifiedOrderStatusCounts).toHaveBeenCalledTimes(2)
|
||||
const params = vi.mocked(getPlatformUnifiedOrderStatusCounts).mock.lastCall![0]
|
||||
expect(params).toMatchObject({ inboundCode: 'IN-9', loaded: false })
|
||||
expect(params).not.toHaveProperty('mainStatus')
|
||||
expect(params).not.toHaveProperty('page')
|
||||
expect(params).not.toHaveProperty('size')
|
||||
toolbar.vm.$emit('reset')
|
||||
await flushPromises()
|
||||
expect(getPlatformUnifiedOrderStatusCounts).toHaveBeenCalledTimes(3)
|
||||
})
|
||||
|
||||
it('ignores older count responses and hides stale counts during loading and failures with retry', async () => {
|
||||
let resolveOld!: (value: { counts: { PENDING_REVIEW: number } }) => void
|
||||
vi.mocked(getPlatformUnifiedOrderStatusCounts).mockImplementationOnce(() => new Promise((resolve) => { resolveOld = resolve }))
|
||||
const wrapper = mountView()
|
||||
await flushPromises()
|
||||
expect(wrapper.get('[role="tablist"]').attributes('aria-busy')).toBe('true')
|
||||
expect(wrapper.find('.order-status-count').exists()).toBe(false)
|
||||
vi.mocked(getPlatformUnifiedOrderStatusCounts).mockResolvedValueOnce({ counts: { PENDING_REVIEW: 7 } })
|
||||
wrapper.getComponent({ name: 'QueryToolbar' }).vm.$emit('search')
|
||||
await flushPromises()
|
||||
resolveOld({ counts: { PENDING_REVIEW: 99 } })
|
||||
await flushPromises()
|
||||
expect(wrapper.findAll('[role="tab"]')[1]!.text()).toBe('待审核(7)')
|
||||
vi.mocked(getPlatformUnifiedOrderStatusCounts).mockRejectedValueOnce(new Error('统计不可用'))
|
||||
wrapper.getComponent({ name: 'QueryToolbar' }).vm.$emit('search')
|
||||
await flushPromises()
|
||||
expect(wrapper.find('.order-status-count').exists()).toBe(false)
|
||||
expect(wrapper.findComponent({ name: 'DataTable' }).exists()).toBe(true)
|
||||
expect(wrapper.find('.order-status-feedback').text()).toContain('重试数量')
|
||||
vi.mocked(getPlatformUnifiedOrderStatusCounts).mockResolvedValueOnce({ counts: { PENDING_REVIEW: 8, MEASUREMENT_REVIEW: 3 } })
|
||||
await wrapper.findAll('button').find((button) => button.text() === '重试数量')!.trigger('click')
|
||||
await flushPromises()
|
||||
expect(wrapper.findAll('[role="tab"]')[1]!.text()).toBe('待审核(8)')
|
||||
expect(wrapper.findAll('[role="tab"]')[3]!.text()).toBe('测量数据审核(3)')
|
||||
})
|
||||
|
||||
it('loads once initially and once for query, reset, status tab and pagination', async () => {
|
||||
const wrapper = mountView()
|
||||
await flushPromises()
|
||||
|
||||
@@ -62,9 +62,9 @@ describe('UnifiedOrdersView contract', () => {
|
||||
|
||||
it('exposes the product main statuses including dropship palletizing', () => {
|
||||
expect(unifiedOrderStatusOptions.map((item) => item.label)).toEqual([
|
||||
'待审核', '待测量数据', '一件代发打托', '待分柜', '装柜中', '装柜完成', '派送完成', '已完成',
|
||||
'待审核', '待测量数据', '待客户确认', '已确认数据', '待上传资料', '一件代发打托', '待分柜', '装柜中', '装柜完成', '出口报关', '已开船/待清关', '待拆柜', '待排车', '出库单', '派送中', '签收完成',
|
||||
])
|
||||
for (const legacyLabel of ['待客户确认', '差异处理中', '派送中', '进入分柜']) {
|
||||
for (const legacyLabel of ['差异处理中', '进入分柜']) {
|
||||
expect(source).not.toContain(legacyLabel)
|
||||
}
|
||||
})
|
||||
@@ -629,7 +629,7 @@ describe('UnifiedOrdersView contract', () => {
|
||||
expect(source).toContain('feePanelRevision.value += 1')
|
||||
expect(source).not.toContain('<h3 class="fee-section-title">头程自动初算</h3>')
|
||||
expect(source).toContain('其他费用明细')
|
||||
expect(source).toContain('@changed="loadDetail(true)"')
|
||||
expect(source).toContain('@changed="loadDetail(true); loadStatusCounts()"')
|
||||
expect(source).toContain('firstLegTransportModeLabel(detail.order.order?.transportMode)')
|
||||
expect(source).toContain('firstLegPickupMethodLabel(detail.order.order?.pickupMethod)')
|
||||
expect(source).toContain('firstLegDestinationTypeLabel(detail.order.order?.destinationType)')
|
||||
|
||||
@@ -11,6 +11,9 @@ import {
|
||||
getPlatformUnifiedOrderBatchApprovalPreview,
|
||||
updatePlatformUnifiedOrderRemarks,
|
||||
listPlatformUnifiedOrders,
|
||||
getPlatformUnifiedOrderStatusCounts,
|
||||
type UnifiedOrderStatusCountQuery,
|
||||
type UnifiedOrderStatusCounts,
|
||||
updatePlatformUnifiedOrderPlanning,
|
||||
unifiedOrderStatusOptions,
|
||||
type UnifiedOrderDetailResource,
|
||||
@@ -121,6 +124,10 @@ const page = ref(1)
|
||||
const pageSize = ref(20)
|
||||
const total = ref(0)
|
||||
const loading = ref(false)
|
||||
const statusCounts = ref<UnifiedOrderStatusCounts['counts']>({})
|
||||
const statusCountsLoading = ref(false)
|
||||
const statusCountsError = ref<ApiErrorDetails | null>(null)
|
||||
let statusCountsRequestSerial = 0
|
||||
const loadError = ref<ApiErrorDetails | null>(null)
|
||||
const legacyImportOpen = ref(false)
|
||||
const legacyImportFile = ref<File | null>(null)
|
||||
@@ -714,11 +721,16 @@ function optionalBoolean(value: string | null | undefined) {
|
||||
|
||||
function selectStatus(status: UnifiedOrderMainStatus | '' | 'MEASUREMENT_REVIEW') {
|
||||
if (selectedTab.value === status) return
|
||||
const leavingMeasurementReview = measurementReviewSelected.value
|
||||
measurementReviewSelected.value = status === 'MEASUREMENT_REVIEW'
|
||||
if (measurementReviewSelected.value) selectedOrders.value = []
|
||||
if (status === 'MEASUREMENT_REVIEW') return
|
||||
if (status === 'MEASUREMENT_REVIEW') {
|
||||
void loadStatusCounts()
|
||||
return
|
||||
}
|
||||
selectedStatus.value = status
|
||||
if (page.value === 1) void loadOrders()
|
||||
if (leavingMeasurementReview) void loadStatusCounts()
|
||||
if (page.value === 1) void loadOrders(false)
|
||||
else page.value = 1
|
||||
}
|
||||
|
||||
@@ -786,6 +798,7 @@ async function savePlanning(row: UnifiedOrderResource) {
|
||||
row.estimatedVolumeCbm = estimatedVolumeCbm
|
||||
draft.savedExpectedArrivalAt = draft.expectedArrivalAt
|
||||
draft.savedEstimatedVolumeCbm = estimatedVolumeCbm
|
||||
void loadStatusCounts()
|
||||
ElMessage.success('订单运营预估已更新')
|
||||
} catch (error) {
|
||||
const details = getApiErrorDetails(error, '订单运营预估保存失败')
|
||||
@@ -821,6 +834,7 @@ const canEditDeclaration = computed(() => Boolean(
|
||||
))
|
||||
|
||||
async function handleDeclarationUpdated() {
|
||||
void loadStatusCounts()
|
||||
activeDetailTab.value = 'basic'
|
||||
await loadDetail(true)
|
||||
}
|
||||
@@ -1089,6 +1103,7 @@ async function updateMeasurementCalculationMode(row: Record<string, unknown> | n
|
||||
measurementSectionModes.outer = mode
|
||||
measurementLoadedKey.value = ''
|
||||
ElMessage.success(`${row ? '当前数据' : '全部测量数据'}已保存并绑定计算规则,体积已重新计算`)
|
||||
void loadStatusCounts()
|
||||
return true
|
||||
} catch (error) {
|
||||
measurementLoadedKey.value = ''
|
||||
@@ -1141,6 +1156,7 @@ async function saveWarehouseOuterDimensions(row: Record<string, unknown>) {
|
||||
if (refreshed) measurementDetail.value = refreshed
|
||||
measurementLoadedKey.value = ''
|
||||
ElMessage.success(`序号 ${row.itemNo || '—'} 的外箱规已更新,相关数值已重新计算`)
|
||||
void loadStatusCounts()
|
||||
} catch (error) {
|
||||
measurementLoadedKey.value = ''
|
||||
await loadMeasurementDetails()
|
||||
@@ -1583,7 +1599,50 @@ async function loadWarehouses() {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadOrders() {
|
||||
function orderCountFilters(): UnifiedOrderStatusCountQuery {
|
||||
const activeFilters = appliedFilters.value
|
||||
const range = activeFilters.createdRange
|
||||
return {
|
||||
tenantId: activeFilters.tenantId || undefined,
|
||||
receivingWarehouseId: activeFilters.receivingWarehouseId || undefined,
|
||||
destinationWarehouseId: activeFilters.destinationWarehouseId || undefined,
|
||||
inboundCode: trimmed(activeFilters.inboundCode),
|
||||
expectedArrivalDate: activeFilters.expectedArrivalDate || undefined,
|
||||
feeReviewStatus: activeFilters.feeReviewStatus || undefined,
|
||||
channelName: trimmed(activeFilters.channelName),
|
||||
containerNo: trimmed(activeFilters.containerNo),
|
||||
cabinetNo: trimmed(activeFilters.cabinetNo),
|
||||
sailingDate: activeFilters.sailingDate || undefined,
|
||||
loaded: optionalBoolean(activeFilters.loaded),
|
||||
fullContainer: optionalBoolean(activeFilters.fullContainer),
|
||||
measurementReviewStatus: activeFilters.measurementReviewStatus || undefined,
|
||||
fbaCode: trimmed(activeFilters.fbaCode),
|
||||
createdFrom: range.length === 2 ? `${range[0]}T00:00:00` : undefined,
|
||||
createdTo: range.length === 2 ? `${range[1]}T23:59:59` : undefined,
|
||||
}
|
||||
}
|
||||
|
||||
async function loadStatusCounts() {
|
||||
const serial = ++statusCountsRequestSerial
|
||||
statusCounts.value = {}
|
||||
statusCountsLoading.value = true
|
||||
statusCountsError.value = null
|
||||
try {
|
||||
const result = await getPlatformUnifiedOrderStatusCounts(orderCountFilters())
|
||||
if (serial === statusCountsRequestSerial) statusCounts.value = result.counts
|
||||
} catch (error) {
|
||||
if (serial === statusCountsRequestSerial) statusCountsError.value = getApiErrorDetails(error, '订单页签数量加载失败')
|
||||
} finally {
|
||||
if (serial === statusCountsRequestSerial) statusCountsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function tabCount(value: UnifiedOrderMainStatus | '' | 'MEASUREMENT_REVIEW') {
|
||||
return value ? statusCounts.value[value] : undefined
|
||||
}
|
||||
|
||||
async function loadOrders(refreshCounts = true) {
|
||||
if (refreshCounts) void loadStatusCounts()
|
||||
if (measurementReviewSelected.value) return
|
||||
selectedApprovalOrders.value = []
|
||||
selectedOrders.value = []
|
||||
@@ -1592,26 +1651,9 @@ async function loadOrders() {
|
||||
coLoadError.value = null
|
||||
Object.keys(planningDrafts).forEach((key) => delete planningDrafts[key])
|
||||
try {
|
||||
const activeFilters = appliedFilters.value
|
||||
const range = activeFilters.createdRange
|
||||
const result = await listPlatformUnifiedOrders({
|
||||
tenantId: activeFilters.tenantId || undefined,
|
||||
...orderCountFilters(),
|
||||
mainStatus: selectedStatus.value || undefined,
|
||||
receivingWarehouseId: activeFilters.receivingWarehouseId || undefined,
|
||||
destinationWarehouseId: activeFilters.destinationWarehouseId || undefined,
|
||||
inboundCode: trimmed(activeFilters.inboundCode),
|
||||
expectedArrivalDate: activeFilters.expectedArrivalDate || undefined,
|
||||
feeReviewStatus: activeFilters.feeReviewStatus || undefined,
|
||||
channelName: trimmed(activeFilters.channelName),
|
||||
containerNo: trimmed(activeFilters.containerNo),
|
||||
cabinetNo: trimmed(activeFilters.cabinetNo),
|
||||
sailingDate: activeFilters.sailingDate || undefined,
|
||||
loaded: optionalBoolean(activeFilters.loaded),
|
||||
fullContainer: optionalBoolean(activeFilters.fullContainer),
|
||||
measurementReviewStatus: activeFilters.measurementReviewStatus || undefined,
|
||||
fbaCode: trimmed(activeFilters.fbaCode),
|
||||
createdFrom: range.length === 2 ? `${range[0]}T00:00:00` : undefined,
|
||||
createdTo: range.length === 2 ? `${range[1]}T23:59:59` : undefined,
|
||||
page: page.value,
|
||||
size: pageSize.value,
|
||||
})
|
||||
@@ -1628,17 +1670,19 @@ async function loadOrders() {
|
||||
|
||||
function search() {
|
||||
appliedFilters.value = cloneFilters(filters.value)
|
||||
void loadStatusCounts()
|
||||
if (page.value !== 1) {
|
||||
page.value = 1
|
||||
return
|
||||
}
|
||||
void loadOrders()
|
||||
void loadOrders(false)
|
||||
}
|
||||
|
||||
function reset() {
|
||||
filters.value = emptyFilters()
|
||||
appliedFilters.value = emptyFilters()
|
||||
if (page.value === 1) void loadOrders()
|
||||
void loadStatusCounts()
|
||||
if (page.value === 1) void loadOrders(false)
|
||||
else page.value = 1
|
||||
}
|
||||
|
||||
@@ -1806,6 +1850,7 @@ async function executeConfirmAndSendFee() {
|
||||
automaticFee.value = { feeStatus: snapshot.feeStatus, totalAmount: Number(snapshot.totalAmount || 0) }
|
||||
feePanelRevision.value += 1
|
||||
ElMessage.success('计费量和单价已确认并发送给客户')
|
||||
void loadStatusCounts()
|
||||
feeConfirmOpen.value = false
|
||||
feeConfirmAttempt = null
|
||||
await loadDetail(true)
|
||||
@@ -2298,7 +2343,7 @@ async function loadDetail(force = false) {
|
||||
}
|
||||
}
|
||||
|
||||
watch([page, pageSize], () => { void loadOrders() })
|
||||
watch([page, pageSize], () => { void loadOrders(false) })
|
||||
watch(businessInboundCode, (value) => {
|
||||
detailAssociationRequestSerial += 1
|
||||
resolvedDetailTarget.value = null
|
||||
@@ -2321,12 +2366,16 @@ watch(detailRouteKey, (value) => {
|
||||
watch(measurementPreviewOpen, (open) => {
|
||||
if (!open) releaseMeasurementPreview()
|
||||
})
|
||||
watch(smartLoadingOpen, (open, wasOpen) => {
|
||||
if (wasOpen && !open) void loadOrders()
|
||||
})
|
||||
onMounted(() => {
|
||||
void loadCustomers()
|
||||
void loadWarehouses()
|
||||
if (!isDetailRoute.value) void loadOrders()
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
statusCountsRequestSerial += 1
|
||||
detailAssociationRequestSerial += 1
|
||||
measurementRequestSerial += 1
|
||||
holdRequestSerial += 1
|
||||
@@ -2506,7 +2555,7 @@ onBeforeUnmount(() => {
|
||||
:inbound-id="normalizedInboundId"
|
||||
:destination-type="detail.summary.destinationType"
|
||||
@summary="otherFeeSummary = $event"
|
||||
@changed="loadDetail(true)"
|
||||
@changed="loadDetail(true); loadStatusCounts()"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
@@ -2703,9 +2752,9 @@ onBeforeUnmount(() => {
|
||||
|
||||
<template v-else>
|
||||
<div v-if="measurementReviewSelected" id="unified-orders-results" role="tabpanel">
|
||||
<InboundTaskList mode="review" title="订单列表">
|
||||
<InboundTaskList mode="review" title="订单列表" @changed="loadStatusCounts">
|
||||
<template #status-tabs>
|
||||
<div ref="statusTabList" class="status-tabs density-status-tabs" role="tablist" aria-label="订单主状态">
|
||||
<div ref="statusTabList" class="status-tabs density-status-tabs" role="tablist" aria-label="订单主状态" :aria-busy="statusCountsLoading">
|
||||
<button
|
||||
v-for="(tab, index) in statusTabs"
|
||||
:key="tab.value || 'ALL'"
|
||||
@@ -2717,7 +2766,13 @@ onBeforeUnmount(() => {
|
||||
:class="['status-tab', { 'is-active': selectedTab === tab.value }]"
|
||||
@click="selectStatus(tab.value)"
|
||||
@keydown="handleTabKeydown($event, index)"
|
||||
>{{ tab.label }}</button>
|
||||
><span>{{ tab.label }}</span><span v-if="tabCount(tab.value) !== undefined" class="order-status-count">({{ tabCount(tab.value) }})</span></button>
|
||||
</div>
|
||||
<div v-if="statusCountsLoading" class="order-status-feedback" role="status">页签数量加载中…</div>
|
||||
<div v-else-if="statusCountsError" class="order-status-feedback" role="status">
|
||||
<span>{{ statusCountsError.message }}</span>
|
||||
<el-button link type="primary" @click="loadStatusCounts">重试数量</el-button>
|
||||
<ApiErrorMeta :details="statusCountsError" />
|
||||
</div>
|
||||
</template>
|
||||
</InboundTaskList>
|
||||
@@ -2732,7 +2787,7 @@ onBeforeUnmount(() => {
|
||||
<template #toolbar-start><h1>订单列表</h1></template>
|
||||
<template #filters>
|
||||
<div class="orders-query-panel integrated-query-group">
|
||||
<div ref="statusTabList" class="status-tabs density-status-tabs" role="tablist" aria-label="订单主状态">
|
||||
<div ref="statusTabList" class="status-tabs density-status-tabs" role="tablist" aria-label="订单主状态" :aria-busy="statusCountsLoading">
|
||||
<button
|
||||
v-for="(tab, index) in statusTabs"
|
||||
:key="tab.value || 'ALL'"
|
||||
@@ -2744,9 +2799,15 @@ onBeforeUnmount(() => {
|
||||
:class="['status-tab', { 'is-active': selectedTab === tab.value }]"
|
||||
@click="selectStatus(tab.value)"
|
||||
@keydown="handleTabKeydown($event, index)"
|
||||
>{{ tab.label }}</button>
|
||||
><span>{{ tab.label }}</span><span v-if="tabCount(tab.value) !== undefined" class="order-status-count">({{ tabCount(tab.value) }})</span></button>
|
||||
</div>
|
||||
|
||||
<div v-if="statusCountsLoading" class="order-status-feedback" role="status">页签数量加载中…</div>
|
||||
<div v-else-if="statusCountsError" class="order-status-feedback" role="status">
|
||||
<span>{{ statusCountsError.message }}</span>
|
||||
<el-button link type="primary" @click="loadStatusCounts">重试数量</el-button>
|
||||
<ApiErrorMeta :details="statusCountsError" />
|
||||
</div>
|
||||
<QueryToolbar id="unified-orders-advanced-filters" v-model="filters" class="orders-query-toolbar" ariaLabel="订单列表筛选" :fields="queryFields" :available-fields="allQueryFields" preference-key="unified-orders-query-v2" :search-on-reset="false" @search="search" @reset="reset">
|
||||
<template #actions>
|
||||
<el-button :aria-expanded="showAdvancedFilters" aria-controls="unified-orders-advanced-filters" @click="showAdvancedFilters = !showAdvancedFilters">
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* Order-specific sections. Shared density lives in styles/adminDensity.css. */
|
||||
.unified-orders-page .order-status-count { font-variant-numeric: tabular-nums; }
|
||||
.unified-orders-page .order-status-feedback { display: flex; align-items: center; flex-wrap: wrap; gap: var(--admin-space-3, 8px); padding: var(--admin-space-2, 6px) var(--admin-space-4, 10px); color: var(--cc-muted); font-size: var(--admin-font-caption, 12px); }
|
||||
.unified-orders-page .inbound-fee-panel .fee-summary {
|
||||
grid-template-columns: minmax(230px, 1.3fr) repeat(4, minmax(150px, 1fr));
|
||||
border-top: 0;
|
||||
|
||||
Reference in New Issue
Block a user