This commit is contained in:
2026-08-14 19:59:32 +08:00
parent f7594ebd39
commit 1540b80c89
29 changed files with 780 additions and 587 deletions
@@ -93,7 +93,7 @@ describe('UnifiedOrdersView contract', () => {
expect(source).toContain('v-model:page-size="pageSize"')
const columnSource = source.slice(source.indexOf('const columns:'), source.indexOf('function emptyFilters'))
const expectedColumnKeys = [
'actions', 'orderNo', 'inboundCode', 'mainStatus', 'customerName', 'receivingWarehouseName',
'actions', 'inboundCode', 'mainStatus', 'customerName', 'receivingWarehouseName',
'destinationWarehouseName', 'totalPackageCount', 'measurementReviewStatus', 'actualGrossWeightKg',
'actualVolumeCbm', 'chargeableWeightKg', 'expectedShipDate', 'loadingStatus', 'containerNo', 'cabinetNo',
'sailingAt', 'portArrivalAt', 'customerRemark', 'latestInternalNote', 'createdAt', 'updatedAt',
@@ -103,8 +103,8 @@ describe('UnifiedOrdersView contract', () => {
'internalOrderStatus', 'expectedArrivalAt', 'feeReviewStatus', 'holdCargo', 'companyName',
'pickupMethod', 'chargeableVolumeCbm', 'recommendedPalletType', 'locationCodes', 'associatedFiles', 'createdBy',
]) expect(columnSource).not.toContain(`key: '${uncontractedKey}'`)
expect(columnSource.indexOf("key: 'actions'")).toBeLessThan(columnSource.indexOf("key: 'orderNo'"))
expect(columnSource.indexOf("key: 'orderNo'")).toBeLessThan(columnSource.indexOf("key: 'inboundCode'"))
expect(columnSource).not.toContain("key: 'orderNo'")
expect(columnSource.indexOf("key: 'actions'")).toBeLessThan(columnSource.indexOf("key: 'inboundCode'"))
expect(columnSource).toContain("{ key: 'mainStatus', prop: 'mainStatus', label: '订单主状态'")
expect(columnSource).toContain("{ key: 'loadingStatus', prop: 'loadingStatus', label: '配载状态', minWidth: 130, slotName: 'field', defaultVisible: false }")
expect(columnSource.match(/defaultVisible: false/g)).toHaveLength(8)
@@ -229,8 +229,8 @@ describe('UnifiedOrdersView contract', () => {
it('distinguishes overflow action buttons by row and keeps a stable missing-field fallback', () => {
expect(source).toContain('function moreUnifiedOrderActionsLabel(row: UnifiedOrderResource)')
expect(source).toContain('[compatibleOrder.inboundCode, compatibleOrder.orderNo, compatibleOrder.orderId, compatibleOrder.id]')
expect(source).toContain("identifier || '当前订单'")
expect(source).toContain("String(row.inboundCode || '').trim() || '当前入仓单'")
expect(source).not.toContain('compatibleOrder.orderNo')
expect(source).not.toContain('aria-label="更多订单操作"')
expect(source).not.toContain('title="更多操作"')
})
@@ -210,7 +210,6 @@ const queryFields = computed(() => showAdvancedFilters.value
const columns: DataTableColumn[] = [
{ key: 'actions', label: '操作', width: 300, fixed: 'left', slotName: 'actions' },
{ key: 'orderNo', prop: 'orderNo', label: '订单号', minWidth: 190, slotName: 'order' },
{ key: 'inboundCode', prop: 'inboundCode', label: '入仓码', minWidth: 190, slotName: 'inboundCode' },
{ key: 'mainStatus', prop: 'mainStatus', label: '订单主状态', minWidth: 130, slotName: 'mainStatus' },
{ key: 'customerName', prop: 'customerName', label: '客户', minWidth: 150, slotName: 'field' },
@@ -676,11 +675,7 @@ function moreUnifiedOrderActions(row: UnifiedOrderResource) {
return unifiedOrderSecondaryActions(row).slice(2)
}
function moreUnifiedOrderActionsLabel(row: UnifiedOrderResource) {
const compatibleOrder = row as UnifiedOrderResource & { id?: string | number | null }
const identifier = [compatibleOrder.inboundCode, compatibleOrder.orderNo, compatibleOrder.orderId, compatibleOrder.id]
.map((value) => String(value ?? '').trim())
.find(Boolean)
return `更多订单操作:${identifier || '当前订单'}`
return `更多订单操作:${String(row.inboundCode || '').trim() || '当前入仓单'}`
}
function unifiedOrderActionLabel(action: UnifiedOrderRowAction) {
if (action === 'note') return '添加备注'
@@ -763,8 +758,7 @@ onMounted(() => {
<el-button link class="back-button" @click="closeDetail"><ArrowLeft :size="16" />返回列表</el-button>
<span class="order-mark" aria-hidden="true"><Box :size="19" /></span>
<div class="order-title">
<h1>{{ detail?.summary.inboundCode || (detail?.summary.inboundId ? `入库单 ${detail.summary.inboundId}` : '暂未生成') }}</h1>
<p>{{ detail?.summary.orderNo || `订单 ${orderId}` }}</p>
<h1>{{ detail?.summary.inboundCode || '入仓码暂缺' }}</h1>
</div>
<StatusBadge v-if="detail" :status="statusLabel(detail.summary.mainStatus)" />
</div>
@@ -792,7 +786,7 @@ onMounted(() => {
<section :id="`order-detail-panel-${activeDetailTab}`" class="detail-panel" role="tabpanel" :aria-labelledby="`order-detail-tab-${activeDetailTab}`" tabindex="0">
<template v-if="activeDetailTab === 'basic'">
<div class="panel-title"><div><h2>订单基本信息</h2><p>{{ detail.summary.orderNo || `订单 ${detail.summary.orderId}` }}</p></div><Box :size="19" /></div>
<div class="panel-title"><div><h2>订单基本信息</h2><p>{{ detail.summary.inboundCode || '入仓码暂缺' }}</p></div><Box :size="19" /></div>
<dl class="order-info-grid">
<div><dt>公司</dt><dd>{{ customerName(detail.summary) }}</dd></div>
<div><dt>运输方式</dt><dd>{{ firstLegTransportModeLabel(detail.order.order?.transportMode) }}</dd></div>
@@ -898,7 +892,7 @@ onMounted(() => {
<template v-else-if="activeDetailTab === 'fulfillment'">
<div class="panel-title"><div><h2>拆分履约</h2><p>根单、已完成分片与当前余量</p></div><ListChecks :size="19" /></div>
<OrderFulfillmentTreePanel :tenant-id="String(detail.summary.tenantId)" :order-id="String(detail.summary.orderId)" />
<OrderFulfillmentTreePanel :tenant-id="String(detail.summary.tenantId)" :order-id="String(detail.summary.orderId)" :inbound-code="detail.summary.inboundCode" />
</template>
<template v-else-if="activeDetailTab === 'workflow'">
@@ -1021,7 +1015,6 @@ onMounted(() => {
<template #orderStatus="{ row }"><StatusBadge :status="orderStatusLabel((row as UnifiedOrderResource).internalOrderStatus || (row as UnifiedOrderResource).mainStatus)" /></template>
<template #measurementReviewStatus="{ row }"><StatusBadge :status="measurementStatusLabel((row as UnifiedOrderResource).measurement?.reviewStatus)" /></template>
<template #field="{ row, column }"><LineClampText v-if="['customerRemark', 'latestInternalNote'].includes(String(column.property))" :content="displayField(row as UnifiedOrderResource, column.property)" :lines="2" /><template v-else>{{ displayField(row as UnifiedOrderResource, column.property) }}</template></template>
<template #order="{ row }"><div class="primary-cell"><strong>{{ (row as UnifiedOrderResource).orderNo || `订单 ${(row as UnifiedOrderResource).orderId}` }}</strong><span v-if="(row as UnifiedOrderResource).inboundCode">入仓码 {{ (row as UnifiedOrderResource).inboundCode }}</span></div></template>
<template #mainStatus="{ row }"><StatusBadge :status="statusLabel((row as UnifiedOrderResource).mainStatus)" /></template>
<template #customer="{ row }"><div class="primary-cell"><strong>{{ customerName(row as UnifiedOrderResource) }}</strong><span>客户 ID {{ (row as UnifiedOrderResource).tenantId }}</span></div></template>
<template #receivingWarehouseName="{ row }">{{ (row as UnifiedOrderResource).receivingWarehouseName || '—' }}</template>
@@ -1043,6 +1036,7 @@ onMounted(() => {
v-if="relationOrder"
:tenant-id="String(relationOrder.tenantId)"
:order-id="String(relationOrder.orderId)"
:inbound-code="relationOrder.inboundCode"
/>
</AppDrawer>
@@ -1056,7 +1050,7 @@ onMounted(() => {
<el-dialog
v-model="measurementDialogOpen"
:title="measurementOrder ? `测量 · ${measurementOrder.inboundCode || measurementOrder.orderNo}` : '测量'"
:title="measurementOrder?.inboundCode ? `测量 · ${measurementOrder.inboundCode}` : '测量'"
width="min(1180px, calc(100vw - 32px))"
top="4vh"
destroy-on-close