This commit is contained in:
2026-09-30 14:01:58 +08:00
parent f14e1a2ea3
commit 8c51e9c1cf
109 changed files with 1525 additions and 651 deletions
@@ -53,7 +53,7 @@ function mountView() {
AdminPage: { template: '<main><slot /></main>' },
ListPageLayout: { template: '<section><slot name="toolbar" /><slot name="state" /><slot /></section>' },
QueryToolbar: { name: 'QueryToolbar', props: ['modelValue'], emits: ['update:modelValue', 'search', 'reset'], template: '<div data-testid="query-toolbar" />' },
DataTable: { name: 'DataTable', props: ['page', 'pageSize', 'data'], emits: ['update:page', 'update:pageSize', 'selection-change'], template: '<div data-testid="data-table"><slot name="toolbar-actions" /><div v-for="row in data" :key="row.orderId" class="test-row"><slot name="estimatedVolume" :row="row" /><slot name="expectedArrival" :row="row" /></div></div>' },
DataTable: { name: 'DataTable', props: ['page', 'pageSize', 'data'], emits: ['update:page', 'update:pageSize', 'selection-change'], template: '<div data-testid="data-table"><slot name="toolbar-start" /><slot name="toolbar-actions" /><slot name="filters" /><slot name="notices" /><div v-for="row in data" :key="row.orderId" class="test-row"><slot name="estimatedVolume" :row="row" /><slot name="expectedArrival" :row="row" /></div></div>' },
'el-button': { template: '<button><slot /></button>' },
'el-input-number': { name: 'ElInputNumber', props: ['modelValue', 'disabled'], emits: ['update:modelValue', 'change'], template: '<input class="number-input" :value="modelValue" :disabled="disabled" @change="$emit(\'change\')" />' },
'el-date-picker': { name: 'ElDatePicker', props: ['modelValue', 'disabled'], emits: ['update:modelValue', 'change'], template: '<input class="date-input" :value="modelValue" :disabled="disabled" @change="$emit(\'change\')" />' },
@@ -236,12 +236,14 @@ describe('UnifiedOrdersView contract', () => {
expect(source).toContain("detail.summary.internalRemark || detail.summary.latestInternalNote || '—'")
})
it('uses ListPageLayout regions for one 16px query-to-table gap', () => {
it('keeps the title, search, errors and results in the integrated list', () => {
expect(source).toContain('<ListPageLayout ariaLabel="统一订单列表">')
expect(source).toContain('<template #toolbar>')
expect(source).toContain('<template v-if="loadError" #state>')
expect(source).toContain('<template #filters>')
expect(source).toContain('<template #notices>')
expect(source).toContain('<template #default>')
expect(source).toContain('v-if="!loadError" id="unified-orders-results" class="surface-panel table-panel table-card"')
expect(source).toContain(':results-visible="!loadError"')
expect(source).toContain('<template #toolbar-start><h1>订单列表</h1></template>')
expect(source).toContain('appearance="integrated"')
expect(source).not.toContain('class="orders-load-error"')
expect(source).not.toContain('.orders-load-error { margin-top: 0; }')
})
@@ -249,7 +251,7 @@ describe('UnifiedOrdersView contract', () => {
it('counts detail in the three directly visible row actions', () => {
expect(source).toContain("{ key: 'detail', label: '详情', priority: 500 }")
expect(source).toContain('...unifiedOrderSecondaryActions(row).map')
expect(source).toContain('<RowActions class="density-action" :actions="unifiedOrderRowActions(row as UnifiedOrderResource)"')
expect(source).toContain('<RowActions text-actions class="density-action" :actions="unifiedOrderRowActions(row as UnifiedOrderResource)"')
expect(source).toContain("if (action === 'approve') return '审核'")
expect(source).not.toContain("if (action === 'approve') return '通过'")
})
@@ -2692,8 +2692,15 @@ onBeforeUnmount(() => {
<template v-else>
<ListPageLayout ariaLabel="统一订单列表">
<template #toolbar>
<div class="orders-query-panel">
<template #default>
<div id="unified-orders-results" role="tabpanel"><DataTable appearance="integrated" :stripe="false" column-settings-mode="show" :results-visible="!loadError" v-model:page="page" v-model:page-size="pageSize" :data="records" :columns="columns" preference-key="unified-orders-table-v2" :loading="loading" :total="total" :page-sizes="[20, 50, 100]" :row-class-name="unifiedOrderRowClassName" row-key="orderId" border empty-text="暂无符合条件的订单" aria-label="统一订单列表" @selection-change="handleOrderSelectionChange">
<template #toolbar-start><h1>订单列表</h1></template>
<template #filters>
<div class="orders-query-panel integrated-query-group">
<div class="status-tabs" role="tablist" aria-label="订单主状态">
<button
v-for="(tab, index) in statusTabs"
@@ -2719,17 +2726,13 @@ onBeforeUnmount(() => {
</QueryToolbar>
</div>
</template>
<template v-if="loadError" #state>
<template #notices><template v-if="loadError">
<LoadErrorState title="订单列表暂时无法加载" :message="loadError.message" :loading="loading" @retry="loadOrders">
<template #details><ApiErrorMeta :details="loadError" /></template>
</LoadErrorState>
</template>
</template></template>
<template #before-results><div v-if="coLoadError" class="coload-error" role="alert"><span>{{ coLoadError.message }}</span><ApiErrorMeta :details="coLoadError" /></div></template>
<template #default>
<div v-if="!loadError" id="unified-orders-results" class="surface-panel table-panel table-card" role="tabpanel">
<div v-if="coLoadError" class="coload-error" role="alert"><span>{{ coLoadError.message }}</span><ApiErrorMeta :details="coLoadError" /></div>
<DataTable v-model:page="page" v-model:page-size="pageSize" :data="records" :columns="columns" preference-key="unified-orders-table-v2" :loading="loading" :total="total" :page-sizes="[20, 50, 100]" :row-class-name="unifiedOrderRowClassName" row-key="orderId" border stripe empty-text="暂无符合条件的订单" aria-label="统一订单列表" @selection-change="handleOrderSelectionChange">
<template #toolbar-actions>
<el-button v-if="can('platform:order:import')" :disabled="loading" @click="openLegacyImport"><FileUp :size="16" />导入旧系统订单</el-button>
<el-button v-if="can('platform:order:export') && can('platform:download:list')" :loading="exportSubmitting" :disabled="loading || exportSubmitting" @click="exportOrders"><Download :size="16" />导出<span v-if="selectedOrders.length">(已选 {{ selectedOrders.length }})</span></el-button>
@@ -2740,7 +2743,7 @@ onBeforeUnmount(() => {
<el-button v-if="can('platform:firstleg:inbound:view')" :loading="printingCartonLabels" :disabled="loading || printingCartonLabels || !selectedCartonLabelOrders.length" @click="printSelectedCartonLabels"><Printer :size="16" />打印箱唛<span v-if="selectedCartonLabelOrders.length">({{ selectedCartonLabelOrders.length }})</span></el-button>
<el-button v-if="can('platform:firstleg:smart-loading:list')" type="primary" @click="smartLoadingOpen = true"><PackageOpen :size="16" />智能装柜</el-button>
</template>
<template #actions="{ row }"><RowActions class="density-action" :actions="unifiedOrderRowActions(row as UnifiedOrderResource)" :more-label="moreUnifiedOrderActionsLabel(row as UnifiedOrderResource)" @action="handleUnifiedOrderRowAction($event, row as UnifiedOrderResource)" /></template>
<template #actions="{ row }"><RowActions text-actions class="density-action" :actions="unifiedOrderRowActions(row as UnifiedOrderResource)" :more-label="moreUnifiedOrderActionsLabel(row as UnifiedOrderResource)" @action="handleUnifiedOrderRowAction($event, row as UnifiedOrderResource)" /></template>
<template #inboundCode="{ row }">
<div class="inbound-relation-cell order-code-cell">
<strong class="inbound-code-value" :title="(row as UnifiedOrderResource).inboundCode || '待生成入仓码'">{{ (row as UnifiedOrderResource).inboundCode || '待生成入仓码' }}</strong>
@@ -2807,8 +2810,7 @@ onBeforeUnmount(() => {
<template #expectedShipDate="{ row }">{{ formatDate((row as UnifiedOrderResource).expectedShipDate) }}</template>
<template #updatedAt="{ row }">{{ formatDate((row as UnifiedOrderResource).updatedAt) }}</template>
<template #pagination-left="{ total: tableTotal }"><span>共 {{ tableTotal }} 条</span></template>
</DataTable>
</div>
</DataTable></div>
</template>
</ListPageLayout>
@@ -2974,7 +2976,7 @@ onBeforeUnmount(() => {
.page-intro h1 { margin: 0; color: var(--cc-text); font-size: 22px; line-height: 1.35; }
.page-intro p { margin: 5px 0 0; color: var(--cc-muted); font-size: var(--admin-font-body, 13px); line-height: 1.6; }
.page-intro :deep(.el-button) { flex: 0 0 auto; }
.orders-query-panel { overflow: hidden; border: 1px solid var(--cc-border); border-radius: var(--admin-radius, 4px); background: var(--admin-surface, #fff); }
.orders-query-panel { min-width: 0; }
.status-tabs { display: flex; max-width: 100%; overflow-x: auto; margin-bottom: 0; border-bottom: 1px solid var(--admin-table-border, #e5e7eb); background: #f9fafb; scrollbar-width: thin; }
.status-tab { position: relative; flex: 0 0 auto; min-height: var(--admin-tab-height, 38px); padding: 0 var(--admin-space-6, 16px); border: 0; background: transparent; color: var(--cc-muted); font: inherit; font-size: var(--admin-font-body, 13px); cursor: pointer; }
.status-tab::after { position: absolute; right: 12px; bottom: 0; left: 12px; height: 3px; background: transparent; content: ''; }
+1 -1
View File
@@ -5,7 +5,7 @@ export const unifiedOrderRoutes = [
path: 'orders',
name: 'unified-orders',
component: () => import('./pages/UnifiedOrdersView.vue'),
meta: {
meta: { showPageHeading: false,
title: '订单列表',
description: '围绕同一订单主线跟进审核、测量、分柜、装柜和派送',
permission: 'platform:order:list',