优化
This commit is contained in:
@@ -196,7 +196,7 @@ onMounted(() => { void Promise.all([loadWarehouses(), loadRows()]) })
|
|||||||
<section v-if="!warehouseError && !loadError" class="surface-panel table-panel">
|
<section v-if="!warehouseError && !loadError" class="surface-panel table-panel">
|
||||||
<DataTable v-model:page="page" v-model:page-size="pageSize" :data="rows" :columns="columns" :total="total" :loading="loading" preference-key="container-loading-table" empty-text="暂无货柜">
|
<DataTable v-model:page="page" v-model:page-size="pageSize" :data="rows" :columns="columns" :total="total" :loading="loading" preference-key="container-loading-table" empty-text="暂无货柜">
|
||||||
<template #toolbar-actions><el-button v-if="canCreate" type="primary" @click="openCreate"><Plus :size="16" />新增货柜</el-button></template>
|
<template #toolbar-actions><el-button v-if="canCreate" type="primary" @click="openCreate"><Plus :size="16" />新增货柜</el-button></template>
|
||||||
<template #actions="{ row }"><div class="row-actions"><el-button link type="primary" :aria-label="containerViewLabel(row as ContainerBookingResource)" @click="openDetail(row)"><Eye :size="15" />查看</el-button><el-button v-if="canEdit && row.planStatus !== 'COMPLETED'" link type="primary" @click="openEdit(row)"><Pencil :size="15" />编辑</el-button><el-button v-if="canSmartLoading && row.planStatus === 'EDITING'" link type="primary" @click="goWorkbench(row)"><Sparkles :size="15" />排柜</el-button></div></template>
|
<template #actions="{ row }"><div class="row-actions"><el-button link type="primary" :aria-label="containerViewLabel(row as ContainerBookingResource)" @click="openDetail(row)"><Eye :size="15" />查看</el-button><el-button v-if="canEdit && row.planStatus !== 'COMPLETED'" link type="primary" @click="openEdit(row)"><Pencil :size="15" />编辑</el-button><el-button v-if="canSmartLoading && row.planStatus !== 'COMPLETED'" link type="primary" @click="goWorkbench(row)"><Sparkles :size="15" />排柜</el-button></div></template>
|
||||||
<template #cabinet="{ row }"><strong>{{ row.cabinetNo }}</strong><small>{{ row.bookingNo }}</small></template>
|
<template #cabinet="{ row }"><strong>{{ row.cabinetNo }}</strong><small>{{ row.bookingNo }}</small></template>
|
||||||
<template #containerNo="{ row }">{{ row.containerNo || '待录入' }}</template>
|
<template #containerNo="{ row }">{{ row.containerNo || '待录入' }}</template>
|
||||||
<template #status="{ row }"><el-tag :type="row.planStatus === 'COMPLETED' ? 'success' : row.planStatus === 'LOADING' ? 'warning' : 'info'">{{ statusText(row.planStatus) }}</el-tag></template>
|
<template #status="{ row }"><el-tag :type="row.planStatus === 'COMPLETED' ? 'success' : row.planStatus === 'LOADING' ? 'warning' : 'info'">{{ statusText(row.planStatus) }}</el-tag></template>
|
||||||
|
|||||||
@@ -82,6 +82,24 @@ describe('GlobalSmartLoadingView', () => {
|
|||||||
expect(wrapper.text()).toContain('CB-1 装柜方案')
|
expect(wrapper.text()).toContain('CB-1 装柜方案')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('keeps loading containers editable and hides completed containers', async () => {
|
||||||
|
const loadingContainer = { ...container, id: '9007199254740995', cabinetNo: 'CB-LOADING', planStatus: 'LOADING' as const }
|
||||||
|
const completedContainer = { ...container, id: '9007199254740996', cabinetNo: 'CB-COMPLETED', planStatus: 'COMPLETED' as const }
|
||||||
|
vi.mocked(listContainers).mockResolvedValue({ records: [completedContainer, loadingContainer], page: 1, size: 100, total: 2, pages: 1 })
|
||||||
|
vi.mocked(getSmartLoadingPlanByBooking).mockResolvedValue({ ...plan, bookingId: loadingContainer.id, status: 'LOADING' })
|
||||||
|
|
||||||
|
const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
expect(getSmartLoadingPlanByBooking).toHaveBeenCalledWith(loadingContainer.id)
|
||||||
|
expect(wrapper.text()).toContain('CB-LOADING')
|
||||||
|
expect(wrapper.text()).toContain('装柜中')
|
||||||
|
expect(wrapper.text()).not.toContain('CB-COMPLETED')
|
||||||
|
expect(wrapper.text()).toContain('智能推荐')
|
||||||
|
expect(wrapper.text()).toContain('加入')
|
||||||
|
expect(wrapper.text()).not.toContain('推送预装')
|
||||||
|
})
|
||||||
|
|
||||||
it('refreshes the latest plan after A0409 without losing the selected container', async () => {
|
it('refreshes the latest plan after A0409 without losing the selected container', async () => {
|
||||||
const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
|
const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ const canAssign = computed(() => access.can('platform:firstleg:smart-loading:ass
|
|||||||
const canDelete = computed(() => access.can('platform:firstleg:smart-loading:delete'))
|
const canDelete = computed(() => access.can('platform:firstleg:smart-loading:delete'))
|
||||||
const canPush = computed(() => access.can('platform:firstleg:smart-loading:push'))
|
const canPush = computed(() => access.can('platform:firstleg:smart-loading:push'))
|
||||||
const selectedContainer = computed(() => containers.value.find((item) => item.id === selectedContainerId.value) || null)
|
const selectedContainer = computed(() => containers.value.find((item) => item.id === selectedContainerId.value) || null)
|
||||||
const editable = computed(() => plan.value?.status === 'EDITING')
|
const editable = computed(() => plan.value?.status === 'EDITING' || plan.value?.status === 'LOADING')
|
||||||
const assignedDetailIds = computed(() => new Set((plan.value?.items || []).map((item) => item.inboundDetailId)))
|
const assignedDetailIds = computed(() => new Set((plan.value?.items || []).map((item) => item.inboundDetailId)))
|
||||||
const totalPackages = computed(() => (plan.value?.items || []).reduce((sum, item) => sum + Number(item.packageCount || 0), 0))
|
const totalPackages = computed(() => (plan.value?.items || []).reduce((sum, item) => sum + Number(item.packageCount || 0), 0))
|
||||||
const totalVolume = computed(() => (plan.value?.items || []).reduce((sum, item) => sum + Number(item.volumeCbm || 0), 0))
|
const totalVolume = computed(() => (plan.value?.items || []).reduce((sum, item) => sum + Number(item.volumeCbm || 0), 0))
|
||||||
@@ -75,8 +75,7 @@ const queryFields = computed<QueryField[]>(() => [
|
|||||||
{ key: 'warehouseId', type: 'select', label: '装柜仓库', options: warehouseOptions.value, width: 190 },
|
{ key: 'warehouseId', type: 'select', label: '装柜仓库', options: warehouseOptions.value, width: 190 },
|
||||||
{ key: 'status', type: 'select', label: '柜次状态', width: 160, options: [
|
{ key: 'status', type: 'select', label: '柜次状态', width: 160, options: [
|
||||||
{ label: '可编辑', value: 'EDITING' },
|
{ label: '可编辑', value: 'EDITING' },
|
||||||
{ label: '已推送预装', value: 'LOADING' },
|
{ label: '装柜中', value: 'LOADING' },
|
||||||
{ label: '已完成', value: 'COMPLETED' },
|
|
||||||
] },
|
] },
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -85,6 +84,7 @@ const filteredContainers = computed(() => {
|
|||||||
const warehouseId = String(appliedQuery.value.warehouseId || '')
|
const warehouseId = String(appliedQuery.value.warehouseId || '')
|
||||||
const status = String(appliedQuery.value.status || '')
|
const status = String(appliedQuery.value.status || '')
|
||||||
return containers.value.filter((item) => {
|
return containers.value.filter((item) => {
|
||||||
|
if (item.planStatus === 'COMPLETED') return false
|
||||||
if (warehouseId && item.warehouseId !== warehouseId) return false
|
if (warehouseId && item.warehouseId !== warehouseId) return false
|
||||||
if (status && item.planStatus !== status) return false
|
if (status && item.planStatus !== status) return false
|
||||||
if (!keyword) return true
|
if (!keyword) return true
|
||||||
@@ -131,7 +131,7 @@ function formatNumber(value: number, digits = 3) {
|
|||||||
function candidateRow(source: object) { return source as SmartLoadingCandidate }
|
function candidateRow(source: object) { return source as SmartLoadingCandidate }
|
||||||
function itemRow(source: object) { return source as SmartLoadingItem }
|
function itemRow(source: object) { return source as SmartLoadingItem }
|
||||||
function statusLabel(status: ContainerPlanStatus) {
|
function statusLabel(status: ContainerPlanStatus) {
|
||||||
return ({ EDITING: '可编辑', LOADING: '已推送预装', COMPLETED: '已完成' } as const)[status]
|
return ({ EDITING: '可编辑', LOADING: '装柜中', COMPLETED: '已完成' } as const)[status]
|
||||||
}
|
}
|
||||||
function statusType(status: ContainerPlanStatus) {
|
function statusType(status: ContainerPlanStatus) {
|
||||||
return status === 'EDITING' ? 'primary' : status === 'LOADING' ? 'warning' : 'success'
|
return status === 'EDITING' ? 'primary' : status === 'LOADING' ? 'warning' : 'success'
|
||||||
@@ -197,7 +197,9 @@ async function load() {
|
|||||||
const remainingPages = firstPage.pages > 1
|
const remainingPages = firstPage.pages > 1
|
||||||
? await Promise.all(Array.from({ length: firstPage.pages - 1 }, (_, index) => listContainers({ page: index + 2, size: 100 })))
|
? await Promise.all(Array.from({ length: firstPage.pages - 1 }, (_, index) => listContainers({ page: index + 2, size: 100 })))
|
||||||
: []
|
: []
|
||||||
containers.value = [firstPage, ...remainingPages].flatMap((page) => page.records)
|
containers.value = [firstPage, ...remainingPages]
|
||||||
|
.flatMap((page) => page.records)
|
||||||
|
.filter((item) => item.planStatus !== 'COMPLETED')
|
||||||
if (!filteredContainers.value.some((item) => item.id === selectedContainerId.value)) selectedContainerId.value = preferredContainerId()
|
if (!filteredContainers.value.some((item) => item.id === selectedContainerId.value)) selectedContainerId.value = preferredContainerId()
|
||||||
await loadSelectedData()
|
await loadSelectedData()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -371,7 +373,7 @@ onMounted(load)
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<aside class="dispatch-pane container-pane" aria-label="货柜列表">
|
<aside class="dispatch-pane container-pane" aria-label="货柜列表">
|
||||||
<header class="pane-header"><div><strong>货柜</strong><small>可用、装柜中与已完成</small></div></header>
|
<header class="pane-header"><div><strong>货柜</strong><small>可用与装柜中</small></div></header>
|
||||||
<div v-loading="loading" class="container-list">
|
<div v-loading="loading" class="container-list">
|
||||||
<el-empty v-if="!filteredContainers.length" description="暂无符合条件的货柜" :image-size="72" />
|
<el-empty v-if="!filteredContainers.length" description="暂无符合条件的货柜" :image-size="72" />
|
||||||
<button
|
<button
|
||||||
@@ -398,7 +400,7 @@ onMounted(load)
|
|||||||
<div class="plan-actions">
|
<div class="plan-actions">
|
||||||
<el-tooltip content="刷新当前柜次" placement="top"><el-button aria-label="刷新当前柜次" :loading="selectionLoading" @click="loadSelectedData()"><RefreshCw :size="16" /></el-button></el-tooltip>
|
<el-tooltip content="刷新当前柜次" placement="top"><el-button aria-label="刷新当前柜次" :loading="selectionLoading" @click="loadSelectedData()"><RefreshCw :size="16" /></el-button></el-tooltip>
|
||||||
<el-button v-if="canAssign && editable" type="primary" plain :loading="mutating" @click="recommend"><Sparkles :size="16" />智能推荐</el-button>
|
<el-button v-if="canAssign && editable" type="primary" plain :loading="mutating" @click="recommend"><Sparkles :size="16" />智能推荐</el-button>
|
||||||
<el-button v-if="canPush && editable" type="primary" :disabled="!plan?.items.length" :loading="mutating" @click="pushPreload"><Upload :size="16" />推送预装</el-button>
|
<el-button v-if="canPush && plan?.status === 'EDITING'" type="primary" :disabled="!plan.items.length" :loading="mutating" @click="pushPreload"><Upload :size="16" />推送预装</el-button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user