feat(phase3): complete loading workbenches
This commit is contained in:
@@ -25,13 +25,36 @@ describe('PlatformFirstLegOrdersPanel review queue', () => {
|
||||
expect(source).toContain('await nextTick()')
|
||||
})
|
||||
|
||||
it('keeps the fixed action column compact by grouping secondary actions', () => {
|
||||
it('shows up to three row actions directly and overflows only the fourth action onward', () => {
|
||||
expect(source).toContain('class="table-actions order-row-actions"')
|
||||
expect(source).toContain('更多订单操作')
|
||||
expect(source).toContain('directSecondaryActionCount')
|
||||
expect(source).toContain('Math.max(0, 3 - primaryActionCount)')
|
||||
expect(source).toContain("isDirectSecondaryAction(row as PlatformFirstLegOrderResource, 'express')")
|
||||
expect(source).toContain("isDirectSecondaryAction(row as PlatformFirstLegOrderResource, 'note')")
|
||||
expect(source).toContain("isDirectSecondaryAction(row as PlatformFirstLegOrderResource, 'cancel')")
|
||||
expect(source).toContain('v-if="hasOverflowActions(row as PlatformFirstLegOrderResource)"')
|
||||
expect(source).toContain(':aria-label="moreOrderActionsLabel(row as PlatformFirstLegOrderResource)"')
|
||||
expect(source).toContain(':title="moreOrderActionsLabel(row as PlatformFirstLegOrderResource)"')
|
||||
expect(source).toContain('维护快递')
|
||||
expect(source).toContain('内部备注')
|
||||
expect(source).toContain('取消订单')
|
||||
expect(source).toContain("minWidth: 224, fixed: 'left'")
|
||||
expect(source).toContain("minWidth: 288, fixed: 'left'")
|
||||
})
|
||||
|
||||
it('distinguishes overflow action buttons by order and keeps a stable missing-field fallback', () => {
|
||||
expect(source).toContain('function moreOrderActionsLabel(order: PlatformFirstLegOrderResource)')
|
||||
expect(source).toContain('[compatibleOrder.orderNo, compatibleOrder.id, compatibleOrder.orderId]')
|
||||
expect(source).toContain("identifier || '当前订单'")
|
||||
expect(source).not.toContain('aria-label="更多订单操作"')
|
||||
})
|
||||
|
||||
it('uses structured list regions so toolbar and table keep one layout gap', () => {
|
||||
expect(source).toContain('<ListPageLayout class="first-leg-order-list"')
|
||||
expect(source).toContain('<template #toolbar>')
|
||||
expect(source).toContain('<template v-if="tenantLoadError || loadError" #state>')
|
||||
expect(source).toContain('<template #default>')
|
||||
expect(source).toContain('<section v-if="!loadError" class="surface-panel table-panel">')
|
||||
expect(source).toContain('.first-leg-order-list { gap: 16px; }')
|
||||
})
|
||||
|
||||
it('prioritizes order status and removes noisy customer and time metadata', () => {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { ArrowLeft, CircleX, Eye, FilePenLine, MoreHorizontal, PackageCheck } from '@lucide/vue'
|
||||
import { ArrowLeft, CircleCheckBig, CircleX, Eye, FilePenLine, MoreHorizontal, PackageCheck } from '@lucide/vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import {
|
||||
acceptPlatformFirstLegOrder,
|
||||
@@ -97,7 +97,7 @@ const queryFields = computed<QueryField[]>(() => [
|
||||
])
|
||||
|
||||
const orderColumns: DataTableColumn[] = [
|
||||
{ key: 'actions', label: '操作', minWidth: 224, fixed: 'left', slotName: 'actions' },
|
||||
{ key: 'actions', label: '操作', minWidth: 288, fixed: 'left', slotName: 'actions' },
|
||||
{ key: 'status', label: '状态', width: 108, slotName: 'status' },
|
||||
{ key: 'orderInfo', label: '订单信息', minWidth: 210, slotName: 'orderInfo' },
|
||||
{ key: 'customer', label: '客户', minWidth: 190, showOverflowTooltip: true, slotName: 'customer' },
|
||||
@@ -202,8 +202,41 @@ function canMaintainExpress(order: PlatformFirstLegOrderResource) {
|
||||
return can('platform:order:fulfillment') && !['DRAFT', 'REJECTED', 'CANCELLED'].includes(order.status)
|
||||
}
|
||||
|
||||
function hasSecondaryActions(order: PlatformFirstLegOrderResource) {
|
||||
return canCancel(order) || canMaintainExpress(order) || can('platform:order:note')
|
||||
type SecondaryAction = 'express' | 'note' | 'cancel'
|
||||
|
||||
function secondaryActions(order: PlatformFirstLegOrderResource): SecondaryAction[] {
|
||||
const actions: SecondaryAction[] = []
|
||||
if (canMaintainExpress(order)) actions.push('express')
|
||||
if (can('platform:order:note')) actions.push('note')
|
||||
if (canCancel(order)) actions.push('cancel')
|
||||
return actions
|
||||
}
|
||||
|
||||
function directSecondaryActionCount(order: PlatformFirstLegOrderResource) {
|
||||
const primaryActionCount = actionLabel(order) ? 2 : 1
|
||||
return Math.max(0, 3 - primaryActionCount)
|
||||
}
|
||||
|
||||
function isDirectSecondaryAction(order: PlatformFirstLegOrderResource, action: SecondaryAction) {
|
||||
const index = secondaryActions(order).indexOf(action)
|
||||
return index >= 0 && index < directSecondaryActionCount(order)
|
||||
}
|
||||
|
||||
function isOverflowSecondaryAction(order: PlatformFirstLegOrderResource, action: SecondaryAction) {
|
||||
const index = secondaryActions(order).indexOf(action)
|
||||
return index >= directSecondaryActionCount(order)
|
||||
}
|
||||
|
||||
function hasOverflowActions(order: PlatformFirstLegOrderResource) {
|
||||
return secondaryActions(order).length > directSecondaryActionCount(order)
|
||||
}
|
||||
|
||||
function moreOrderActionsLabel(order: PlatformFirstLegOrderResource) {
|
||||
const compatibleOrder = order as PlatformFirstLegOrderResource & { orderId?: string | number | null }
|
||||
const identifier = [compatibleOrder.orderNo, compatibleOrder.id, compatibleOrder.orderId]
|
||||
.map((value) => String(value ?? '').trim())
|
||||
.find(Boolean)
|
||||
return `更多订单操作:${identifier || '当前订单'}`
|
||||
}
|
||||
|
||||
function runSecondaryAction(command: string | number | object, order: PlatformFirstLegOrderResource) {
|
||||
@@ -511,7 +544,7 @@ onMounted(() => void loadTenants())
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<ListPageLayout ariaLabel="头程订单列表">
|
||||
<ListPageLayout class="first-leg-order-list" ariaLabel="头程订单列表">
|
||||
<template #toolbar>
|
||||
<QueryToolbar
|
||||
v-model="filters"
|
||||
@@ -525,18 +558,18 @@ onMounted(() => void loadTenants())
|
||||
/>
|
||||
</template>
|
||||
|
||||
<el-alert v-if="tenantLoadError" type="warning" :closable="false" show-icon role="alert">
|
||||
<template #title><div class="api-error-alert-title"><span>{{ tenantLoadError.message }}</span><ApiErrorMeta :details="tenantLoadError" /></div></template>
|
||||
<el-button link type="warning" @click="loadTenants">重新加载企业列表</el-button>
|
||||
</el-alert>
|
||||
|
||||
<template v-if="loadError" #state>
|
||||
<el-alert type="error" :closable="false" show-icon role="alert">
|
||||
<template v-if="tenantLoadError || loadError" #state>
|
||||
<el-alert v-if="tenantLoadError" type="warning" :closable="false" show-icon role="alert">
|
||||
<template #title><div class="api-error-alert-title"><span>{{ tenantLoadError.message }}</span><ApiErrorMeta :details="tenantLoadError" /></div></template>
|
||||
<el-button link type="warning" @click="loadTenants">重新加载企业列表</el-button>
|
||||
</el-alert>
|
||||
<el-alert v-if="loadError" type="error" :closable="false" show-icon role="alert">
|
||||
<template #title><div class="api-error-alert-title"><span>{{ loadError.message }}</span><ApiErrorMeta :details="loadError" /></div></template>
|
||||
<el-button link type="danger" @click="loadOrders">重新加载</el-button>
|
||||
</el-alert>
|
||||
</template>
|
||||
|
||||
<template #default>
|
||||
<section v-if="!loadError" class="surface-panel table-panel">
|
||||
<DataTable
|
||||
v-model:page="page"
|
||||
@@ -554,14 +587,17 @@ onMounted(() => void loadTenants())
|
||||
<template #actions="{ row }">
|
||||
<div class="table-actions order-row-actions">
|
||||
<el-button link type="primary" :disabled="actionLoadingId === String((row as PlatformFirstLegOrderResource).id)" @click="openDetail(row as PlatformFirstLegOrderResource)"><Eye :size="15" />详情</el-button>
|
||||
<el-button v-if="actionLabel(row as PlatformFirstLegOrderResource)" link type="success" :loading="actionLoadingId === String((row as PlatformFirstLegOrderResource).id)" @click="runLifecycleAction(row as PlatformFirstLegOrderResource)">{{ actionLabel(row as PlatformFirstLegOrderResource) }}</el-button>
|
||||
<el-dropdown v-if="hasSecondaryActions(row as PlatformFirstLegOrderResource)" trigger="click" popper-class="first-leg-action-menu" :disabled="actionLoadingId === String((row as PlatformFirstLegOrderResource).id)" @command="runSecondaryAction($event, row as PlatformFirstLegOrderResource)">
|
||||
<el-button link type="primary" aria-label="更多订单操作" title="更多订单操作"><MoreHorizontal :size="17" /></el-button>
|
||||
<el-button v-if="actionLabel(row as PlatformFirstLegOrderResource)" link type="success" :loading="actionLoadingId === String((row as PlatformFirstLegOrderResource).id)" @click="runLifecycleAction(row as PlatformFirstLegOrderResource)"><CircleCheckBig :size="15" />{{ actionLabel(row as PlatformFirstLegOrderResource) }}</el-button>
|
||||
<el-button v-if="isDirectSecondaryAction(row as PlatformFirstLegOrderResource, 'express')" link type="primary" :disabled="actionLoadingId === String((row as PlatformFirstLegOrderResource).id)" @click="openExpress(row as PlatformFirstLegOrderResource)"><PackageCheck :size="15" />维护快递</el-button>
|
||||
<el-button v-if="isDirectSecondaryAction(row as PlatformFirstLegOrderResource, 'note')" link type="primary" :disabled="actionLoadingId === String((row as PlatformFirstLegOrderResource).id)" @click="openNote(row as PlatformFirstLegOrderResource)"><FilePenLine :size="15" />内部备注</el-button>
|
||||
<el-button v-if="isDirectSecondaryAction(row as PlatformFirstLegOrderResource, 'cancel')" link type="danger" :disabled="actionLoadingId === String((row as PlatformFirstLegOrderResource).id)" @click="cancelOrder(row as PlatformFirstLegOrderResource)"><CircleX :size="15" />取消订单</el-button>
|
||||
<el-dropdown v-if="hasOverflowActions(row as PlatformFirstLegOrderResource)" trigger="click" popper-class="first-leg-action-menu" :disabled="actionLoadingId === String((row as PlatformFirstLegOrderResource).id)" @command="runSecondaryAction($event, row as PlatformFirstLegOrderResource)">
|
||||
<el-button link type="primary" :aria-label="moreOrderActionsLabel(row as PlatformFirstLegOrderResource)" :title="moreOrderActionsLabel(row as PlatformFirstLegOrderResource)"><MoreHorizontal :size="17" /></el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="canMaintainExpress(row as PlatformFirstLegOrderResource)" command="express"><PackageCheck :size="15" />维护快递</el-dropdown-item>
|
||||
<el-dropdown-item v-if="can('platform:order:note')" command="note"><FilePenLine :size="15" />内部备注</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canCancel(row as PlatformFirstLegOrderResource)" command="cancel" divided><CircleX :size="15" />取消订单</el-dropdown-item>
|
||||
<el-dropdown-item v-if="isOverflowSecondaryAction(row as PlatformFirstLegOrderResource, 'express')" command="express"><PackageCheck :size="15" />维护快递</el-dropdown-item>
|
||||
<el-dropdown-item v-if="isOverflowSecondaryAction(row as PlatformFirstLegOrderResource, 'note')" command="note"><FilePenLine :size="15" />内部备注</el-dropdown-item>
|
||||
<el-dropdown-item v-if="isOverflowSecondaryAction(row as PlatformFirstLegOrderResource, 'cancel')" command="cancel" divided><CircleX :size="15" />取消订单</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
@@ -576,6 +612,7 @@ onMounted(() => void loadTenants())
|
||||
<template #express="{ row }"><div class="primary-cell"><strong>{{ (row as PlatformFirstLegOrderResource).expressCompany || '未维护' }}</strong><span>{{ (row as PlatformFirstLegOrderResource).expressTrackingNo || '—' }}</span></div></template>
|
||||
</DataTable>
|
||||
</section>
|
||||
</template>
|
||||
</ListPageLayout>
|
||||
</template>
|
||||
|
||||
@@ -595,6 +632,7 @@ onMounted(() => void loadTenants())
|
||||
|
||||
<style scoped>
|
||||
.detail-page { overflow: hidden; }
|
||||
.first-leg-order-list { gap: 16px; }
|
||||
.detail-page-header { display: flex; min-height: 88px; align-items: center; justify-content: space-between; gap: 18px; padding: 20px 24px; border-bottom: 1px solid var(--cc-border); }
|
||||
.detail-page-header h1 { margin: 0; font-size: 20px; line-height: 1.35; }
|
||||
.detail-page-header p { margin: 5px 0 0; color: var(--cc-muted); font-size: 12px; line-height: 1.5; }
|
||||
|
||||
Reference in New Issue
Block a user