From 4c12831ee070e3ad5fe6c7e304134a2b268baacb Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Wed, 12 Aug 2026 18:16:44 +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 --- .../pages/ContainersView.test.ts | 1 + .../container-loading/pages/ContainersView.vue | 2 +- .../pages/GlobalSmartLoadingView.test.ts | 1 + .../pages/GlobalSmartLoadingView.vue | 3 ++- .../pages/SmartLoadingWorkbenchView.test.ts | 1 + .../pages/SmartLoadingWorkbenchView.vue | 4 ++-- .../customs/pages/CustomsCasesView.test.ts | 1 + src/modules/customs/pages/CustomsCasesView.vue | 2 +- .../PlatformFirstLegOrdersPanel.test.ts | 7 +++++++ .../components/PlatformFirstLegOrdersPanel.vue | 12 ++++++++---- .../components/LoadingListDetailDrawer.vue | 1 + .../components/LoadingListsView.test.ts | 2 ++ .../components/LoadingListsView.vue | 1 + .../pages/OceanBookingsView.test.ts | 13 +++++++++++++ .../ocean-bookings/pages/OceanBookingsView.vue | 6 +++--- .../pages/OutboundDispatchesView.test.ts | 1 + .../pages/OutboundDispatchesView.vue | 2 +- .../pages/PortSchedulesView.test.ts | 1 + .../port-schedules/pages/PortSchedulesView.vue | 2 +- .../components/TruckAttachmentDialog.test.ts | 2 ++ .../components/TruckAttachmentDialog.vue | 2 +- .../pages/TruckAppointmentsView.test.ts | 1 + .../trucking/pages/TruckAppointmentsView.vue | 2 +- .../components/SmartLoadingWorkbench.test.ts | 17 +++++++++++++++++ .../components/SmartLoadingWorkbench.vue | 7 ++++--- 25 files changed, 75 insertions(+), 19 deletions(-) create mode 100644 src/modules/unified-orders/workflows/components/SmartLoadingWorkbench.test.ts diff --git a/src/modules/container-loading/pages/ContainersView.test.ts b/src/modules/container-loading/pages/ContainersView.test.ts index 26c149ea..0ecca07d 100644 --- a/src/modules/container-loading/pages/ContainersView.test.ts +++ b/src/modules/container-loading/pages/ContainersView.test.ts @@ -188,5 +188,6 @@ describe('ContainersView', () => { expect(source).toContain("row.planStatus === 'EDITING' && canSmartLoading") expect(source).not.toContain('canSmartLoading && row.containerNo') expect(source).not.toContain('link type="primary" :aria-label="containerViewLabel') + expect(source).toContain(':loading="loading" stripe preference-key="container-loading-table"') }) }) diff --git a/src/modules/container-loading/pages/ContainersView.vue b/src/modules/container-loading/pages/ContainersView.vue index 64c7edf3..32ce800e 100644 --- a/src/modules/container-loading/pages/ContainersView.vue +++ b/src/modules/container-loading/pages/ContainersView.vue @@ -323,7 +323,7 @@ onMounted(() => { void Promise.all([loadWarehouses(), loadBusinessOptions(), loa - + 新增货柜 查看{{ row.planStatus === 'LOADING' ? '录入集装箱号' : '编辑' }}排柜查看预装清单查看装柜清单 {{ row.cabinetNo }}{{ row.bookingNo }} diff --git a/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts b/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts index 060fad9d..cbc5b455 100644 --- a/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts +++ b/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts @@ -222,5 +222,6 @@ describe('GlobalSmartLoadingView', () => { expect(source).toContain('type="danger" plain') expect(source).not.toContain('link type="danger"') expect(source).toContain('@media (max-width: 720px)') + expect(source.match(/体积{{ formatNumber(totalVolume) }} / {{ formatNumber(volumeLimit) }} m³ 重量{{ formatNumber(totalWeight, 1) }} / {{ formatNumber(weightLimit, 1) }} kg - + 保存移除 {{ row.orderNo || '—' }}{{ row.inboundCode || '—' }} {{ row.productNameZh || '未命名货物' }}{{ row.skuCode || '无 SKU' }} diff --git a/src/modules/container-loading/pages/SmartLoadingWorkbenchView.test.ts b/src/modules/container-loading/pages/SmartLoadingWorkbenchView.test.ts index a7b21d18..7365b72e 100644 --- a/src/modules/container-loading/pages/SmartLoadingWorkbenchView.test.ts +++ b/src/modules/container-loading/pages/SmartLoadingWorkbenchView.test.ts @@ -92,5 +92,6 @@ describe('SmartLoadingWorkbenchView', () => { expect(source).toContain("canPush && plan?.status === 'EDITING'") expect(source).not.toContain("canPush && plan?.status === 'EDITING' && container?.containerNo") expect(source).not.toContain('link type="primary" :disabled="!routeMatches(row)') + expect(source.match(/]*\bstripe\b/g)).toHaveLength(2) }) }) diff --git a/src/modules/container-loading/pages/SmartLoadingWorkbenchView.vue b/src/modules/container-loading/pages/SmartLoadingWorkbenchView.vue index ab2af338..3338130d 100644 --- a/src/modules/container-loading/pages/SmartLoadingWorkbenchView.vue +++ b/src/modules/container-loading/pages/SmartLoadingWorkbenchView.vue @@ -227,7 +227,7 @@ onMounted(load) 体积占用(含 110% 上限){{ formatNumber(totalVolume) }} / {{ formatNumber(volumeLimit) }} m³重量占用(含 110% 上限){{ formatNumber(totalWeight,1) }} / {{ formatNumber(weightLimit,1) }} kg 创建排柜计划 - + 装柜方案计划 {{ plan.planNo }} · 版本 {{ plan.version }};智能建议必须经人工核对。 保存箱数移除 {{ row.orderNo || '—' }}{{ row.inboundCode || '—' }} @@ -236,7 +236,7 @@ onMounted(load) {{ formatNumber(Number(row.volumeCbm || 0)) }} m³{{ formatNumber(Number(row.grossWeightKg || 0),1) }} kg {{ row.destinationWarehouseName || row.destinationWarehouseCode || '—' }} - + 候选货物系统基于仓库、目的仓、可用箱数及 110% 容量上限校验。 分配 {{ row.orderNo || '—' }}{{ row.inboundCode || '—' }} diff --git a/src/modules/customs/pages/CustomsCasesView.test.ts b/src/modules/customs/pages/CustomsCasesView.test.ts index d75d5e28..50e7b0ef 100644 --- a/src/modules/customs/pages/CustomsCasesView.test.ts +++ b/src/modules/customs/pages/CustomsCasesView.test.ts @@ -36,5 +36,6 @@ describe('CustomsCasesView', () => { it('uses a bordered view action instead of a text link', () => { expect(source).toContain('size="small" type="primary" plain') expect(source).not.toContain("customs:view')\" link") + expect(source).toContain(':total="total" stripe row-key="id"') }) }) diff --git a/src/modules/customs/pages/CustomsCasesView.vue b/src/modules/customs/pages/CustomsCasesView.vue index 225d618c..533d411d 100644 --- a/src/modules/customs/pages/CustomsCasesView.vue +++ b/src/modules/customs/pages/CustomsCasesView.vue @@ -27,6 +27,6 @@ async function openDetail(id: string) { detailOpen.value = true; detailLoading.v async function submit() { if (!detail.value || !submitForm.customsAgentName.trim()) return; actionError.value = null; try { await submitCustomsCase(detail.value.customsCase.id, { ...submitForm, expectedVersion: detail.value.customsCase.version }); ElMessage.success('已登记线下提交批次'); detail.value = await getCustomsCase(detail.value.customsCase.id) } catch (cause) { actionError.value = getApiErrorDetails(cause); if (actionError.value.code === 'A0409') detail.value = await getCustomsCase(detail.value.customsCase.id) } } watch([page, pageSize], () => void load()); onMounted(load) -查看 +查看 {{ detail.customsCase.customsNo }}{{ detail.customsCase.checklistCode }} / {{ detail.customsCase.checklistVersionNo }}{{ detail.documents.length }} / {{ detail.receipts.length }}登记线下提交状态历史{{ customsHistoryActionLabel(entry.action) }}:{{ customsStatusLabel(entry.fromStatus) }} → {{ customsStatusLabel(entry.toStatus) }}{{ entry.note || '' }} diff --git a/src/modules/first-leg-orders/components/PlatformFirstLegOrdersPanel.test.ts b/src/modules/first-leg-orders/components/PlatformFirstLegOrdersPanel.test.ts index c974ee0a..0de1cf35 100644 --- a/src/modules/first-leg-orders/components/PlatformFirstLegOrdersPanel.test.ts +++ b/src/modules/first-leg-orders/components/PlatformFirstLegOrdersPanel.test.ts @@ -39,6 +39,13 @@ describe('PlatformFirstLegOrdersPanel review queue', () => { expect(source).toContain('内部备注') expect(source).toContain('取消订单') expect(source).toContain("minWidth: 288, fixed: 'left'") + expect(source).toContain('size="small" plain type="success"') + expect(source).toContain('size="small" plain type="primary"') + expect(source).toContain('size="small" plain type="danger"') + expect(source).toContain('详情') + expect(source).not.toContain('v-if="actionLabel(row as PlatformFirstLegOrderResource)" link') + expect(source).toContain('@media (max-width: 360px)') + expect(source).toContain('.order-row-actions :deep(.el-button) { width: 100%; min-height: 40px; }') }) it('distinguishes overflow action buttons by order and keeps a stable missing-field fallback', () => { diff --git a/src/modules/first-leg-orders/components/PlatformFirstLegOrdersPanel.vue b/src/modules/first-leg-orders/components/PlatformFirstLegOrdersPanel.vue index b07c2c8c..d25d3305 100644 --- a/src/modules/first-leg-orders/components/PlatformFirstLegOrdersPanel.vue +++ b/src/modules/first-leg-orders/components/PlatformFirstLegOrdersPanel.vue @@ -602,10 +602,10 @@ onMounted(() => void loadTenants()) 详情 - {{ actionLabel(row as PlatformFirstLegOrderResource) }} - 维护快递 - 内部备注 - 取消订单 + {{ actionLabel(row as PlatformFirstLegOrderResource) }} + 维护快递 + 内部备注 + 取消订单 @@ -661,4 +661,8 @@ onMounted(() => void loadTenants()) .detail-page-header .el-button { width: 100%; min-height: 40px; } .detail-table-scroll :deep(.el-table) { min-width: 560px; } } +@media (max-width: 360px) { + .order-row-actions { align-items: stretch; flex-direction: column; } + .order-row-actions :deep(.el-button) { width: 100%; min-height: 40px; } +} diff --git a/src/modules/loading-lists/components/LoadingListDetailDrawer.vue b/src/modules/loading-lists/components/LoadingListDetailDrawer.vue index 6ff90ef9..0e471535 100644 --- a/src/modules/loading-lists/components/LoadingListDetailDrawer.vue +++ b/src/modules/loading-lists/components/LoadingListDetailDrawer.vue @@ -106,6 +106,7 @@ function formatNumber(value?: number | null, digits = 3) { { expect(source).toContain('flex-wrap: wrap') expect(source).toContain('@media (max-width: 720px)') expect(source).toContain('.row-actions { gap: 4px; }') + expect(source).toContain(':loading="loading"\n stripe') + expect(detailSource).toContain(':columns="itemColumns"\n stripe') }) it('does not expose unknown history action codes', () => { diff --git a/src/modules/loading-lists/components/LoadingListsView.vue b/src/modules/loading-lists/components/LoadingListsView.vue index aece5c9f..57e9ff96 100644 --- a/src/modules/loading-lists/components/LoadingListsView.vue +++ b/src/modules/loading-lists/components/LoadingListsView.vue @@ -300,6 +300,7 @@ onMounted(() => { :data="rows" :columns="columns" :loading="loading" + stripe :total="total" :preference-key="`loading-lists-${mode}`" row-key="planId" diff --git a/src/modules/ocean-bookings/pages/OceanBookingsView.test.ts b/src/modules/ocean-bookings/pages/OceanBookingsView.test.ts index 7890b7ba..5c57e88d 100644 --- a/src/modules/ocean-bookings/pages/OceanBookingsView.test.ts +++ b/src/modules/ocean-bookings/pages/OceanBookingsView.test.ts @@ -22,3 +22,16 @@ describe('OceanBookingsView prototype field matrix', () => { expect(source).not.toContain('打印') }) }) + +describe('OceanBookingsView visual action contract', () => { + const source = readFileSync(resolve(process.cwd(), 'src/modules/ocean-bookings/pages/OceanBookingsView.vue'), 'utf8') + + it('uses bordered business buttons and stacks them on narrow screens', () => { + expect(source).toContain('size="small" type="primary" plain') + expect(source).toContain('size="small" @click="open(row.id)"') + expect(source).not.toContain('link type="primary" @click="open(row.id)') + expect(source).toContain('@media(max-width:420px)') + expect(source).toContain('.table-actions') + expect(source).toContain(':total="total" stripe preference-key="ocean-bookings"') + }) +}) diff --git a/src/modules/ocean-bookings/pages/OceanBookingsView.vue b/src/modules/ocean-bookings/pages/OceanBookingsView.vue index 58448653..b9d375d6 100644 --- a/src/modules/ocean-bookings/pages/OceanBookingsView.vue +++ b/src/modules/ocean-bookings/pages/OceanBookingsView.vue @@ -54,9 +54,9 @@ watch([page, pageSize], () => void load()); onMounted(load) - + 新增订舱 - 查看编辑 + 查看编辑 {{ row.vesselName || '—' }} / {{ row.voyageNo }} {{ formatDateTime(row.etd) }} {{ formatDateTime(row.eta) }} @@ -67,4 +67,4 @@ watch([page, pageSize], () => void load()); onMounted(load) - + diff --git a/src/modules/outbound-dispatch/pages/OutboundDispatchesView.test.ts b/src/modules/outbound-dispatch/pages/OutboundDispatchesView.test.ts index 5676ce71..04f80954 100644 --- a/src/modules/outbound-dispatch/pages/OutboundDispatchesView.test.ts +++ b/src/modules/outbound-dispatch/pages/OutboundDispatchesView.test.ts @@ -158,5 +158,6 @@ describe('OutboundDispatchesView', () => { expect(source).toContain('size="small" type="primary" @click="action') expect(source).toContain('size="small" type="danger" plain') expect(source).not.toContain("outbound-dispatch:view')\" link") + expect(source).toContain(':loading="loading" stripe row-key="inboundId"') }) }) diff --git a/src/modules/outbound-dispatch/pages/OutboundDispatchesView.vue b/src/modules/outbound-dispatch/pages/OutboundDispatchesView.vue index 09b4d360..a10a4030 100644 --- a/src/modules/outbound-dispatch/pages/OutboundDispatchesView.vue +++ b/src/modules/outbound-dispatch/pages/OutboundDispatchesView.vue @@ -188,7 +188,7 @@ onBeforeUnmount(() => { disposed = true; listRequestId += 1; optionRequestId += - + 查看确认撤销 {{ row.gate?.passed ? '通过' : '未通过' }} diff --git a/src/modules/port-schedules/pages/PortSchedulesView.test.ts b/src/modules/port-schedules/pages/PortSchedulesView.test.ts index 5b6e5f18..eb5d53f4 100644 --- a/src/modules/port-schedules/pages/PortSchedulesView.test.ts +++ b/src/modules/port-schedules/pages/PortSchedulesView.test.ts @@ -78,5 +78,6 @@ describe('PortSchedulesView', () => { expect(source).toContain('size="small" @click="openSchedule') expect(source).not.toContain("port-schedule:view')\" link") expect(source).toContain(' void load()); onMounted(load) - + 新增船期 查看编辑 {{ row.schedule.vesselName }} / {{ row.schedule.voyageNo }}{{ formatDateTime(row.schedule.observedAt) }}{{ formatDateTime(row.schedule.updatedAt) }}{{ row.expired ? '已过期' : '有效' }} diff --git a/src/modules/trucking/components/TruckAttachmentDialog.test.ts b/src/modules/trucking/components/TruckAttachmentDialog.test.ts index a21b158c..29f54582 100644 --- a/src/modules/trucking/components/TruckAttachmentDialog.test.ts +++ b/src/modules/trucking/components/TruckAttachmentDialog.test.ts @@ -17,5 +17,7 @@ describe('TruckAttachmentDialog interaction governance', () => { expect(source).not.toContain('输入文件服务 ID') expect(source).toContain('deleteTruckAppointmentAttachment') expect(source).toContain('删除') + expect(source).toContain('size="small" type="danger" plain') + expect(source).not.toContain(' text type="danger"') }) }) diff --git a/src/modules/trucking/components/TruckAttachmentDialog.vue b/src/modules/trucking/components/TruckAttachmentDialog.vue index 3bcafb9a..d068b3cf 100644 --- a/src/modules/trucking/components/TruckAttachmentDialog.vue +++ b/src/modules/trucking/components/TruckAttachmentDialog.vue @@ -16,7 +16,7 @@ async function remove(item: TruckAttachmentReference) { if (!props.appointmentId {{ item.fileName || '未命名文件' }}{{ attachmentTypeLabel(item.attachmentType) }}{{ item.uploadedAt ? ` · ${item.uploadedAt}` : '' }} - 删除 + 删除 关闭 diff --git a/src/modules/trucking/pages/TruckAppointmentsView.test.ts b/src/modules/trucking/pages/TruckAppointmentsView.test.ts index 5b675496..9a12a2fe 100644 --- a/src/modules/trucking/pages/TruckAppointmentsView.test.ts +++ b/src/modules/trucking/pages/TruckAppointmentsView.test.ts @@ -123,5 +123,6 @@ describe('TruckAppointmentsView', () => { expect(source).toContain('size="small" type="primary" plain') expect(source).toContain('size="small" :aria-label="appointmentActionLabel(\'编辑\'') expect(source).not.toContain("truck-appointment:view')\" link") + expect(source).toContain(':total="total" stripe preference-key="trucking-appointments"') }) }) diff --git a/src/modules/trucking/pages/TruckAppointmentsView.vue b/src/modules/trucking/pages/TruckAppointmentsView.vue index 827b383a..454858ca 100644 --- a/src/modules/trucking/pages/TruckAppointmentsView.vue +++ b/src/modules/trucking/pages/TruckAppointmentsView.vue @@ -59,7 +59,7 @@ function openDetail(row: TruckAppointmentResource, edit = false) { router.push({ - + 新增拖车 {{ row.carrierName || (row.carrierId ? '已关联承运商' : '—') }} {{ row.driverName || '—' }}{{ row.driverPhone || '—' }} diff --git a/src/modules/unified-orders/workflows/components/SmartLoadingWorkbench.test.ts b/src/modules/unified-orders/workflows/components/SmartLoadingWorkbench.test.ts new file mode 100644 index 00000000..49b44383 --- /dev/null +++ b/src/modules/unified-orders/workflows/components/SmartLoadingWorkbench.test.ts @@ -0,0 +1,17 @@ +import { readFileSync } from 'node:fs' +import { resolve } from 'node:path' +import { describe, expect, it } from 'vitest' + +const source = readFileSync(resolve(process.cwd(), 'src/modules/unified-orders/workflows/components/SmartLoadingWorkbench.vue'), 'utf8') + +describe('SmartLoadingWorkbench business actions', () => { + it('uses semantic outlined buttons and keeps narrow action cells usable', () => { + expect(source).toContain('size="small" plain type="primary"') + expect(source).toContain('size="small" plain type="danger"') + expect(source).toContain('调整') + expect(source).toContain('移除') + expect(source).toContain('加入') + expect(source).not.toContain('当前装柜方案版本 {{ plan.version }} · {{ plan.planNo || '—' }} - 调整 - 移除 + 调整 + 移除 {{ (row as SmartLoadingPlanItem).orderNo || '—' }}{{ (row as SmartLoadingPlanItem).inboundCode || '—' }} {{ formatNumber((row as SmartLoadingPlanItem).grossWeightKg) }} @@ -322,7 +322,7 @@ onMounted(() => { void load() }) - 加入 + 加入 {{ Number($index) + 1 }} {{ (row as SmartLoadingCandidate).orderNo || '—' }}{{ (row as SmartLoadingCandidate).inboundCode || '—' }} {{ (row as SmartLoadingCandidate).destinationWarehouseName || (row as SmartLoadingCandidate).destinationWarehouseCode || '—' }} @@ -384,4 +384,5 @@ onMounted(() => { void load() }) .smart-loading__actions :deep(.el-button:not(.is-circle)) { flex: 1 1 150px; margin-left: 0; } } @media (max-width: 420px) { .smart-loading__summary { grid-template-columns: 1fr; } } +@media (max-width: 360px) { .smart-loading :deep(.el-table__cell .el-button) { width: 100%; min-height: 40px; } }
计划 {{ plan.planNo }} · 版本 {{ plan.version }};智能建议必须经人工核对。
系统基于仓库、目的仓、可用箱数及 110% 容量上限校验。