feat: connect plan-level preload confirmation
This commit is contained in:
@@ -138,21 +138,18 @@ function adjustmentMax(source: object) {
|
||||
const remaining = candidates.value.find((candidate) => candidate.inboundDetailId === item.inboundDetailId)?.availablePackageCount || 0
|
||||
return Math.max(1, item.packageCount + remaining)
|
||||
}
|
||||
function displayContainerNo(container: ContainerBookingResource | null | undefined) {
|
||||
if (!container) return '柜号待生成'
|
||||
const actual = String(container.containerNo || '').trim()
|
||||
const internalReference = /^(?:MAN|SPLIT)-/i.test(actual)
|
||||
if (actual && !internalReference) return actual
|
||||
function displayCabinetNo(container: ContainerBookingResource | null | undefined) {
|
||||
if (!container) return '待生成'
|
||||
const cabinetReference = String(container.cabinetNo || '').trim()
|
||||
return /^\d{15,}$/.test(cabinetReference) ? '模拟柜次' : cabinetReference || '柜号待生成'
|
||||
return /^\d{15,}$/.test(cabinetReference) ? '待生成' : cabinetReference || '待生成'
|
||||
}
|
||||
function hasRealContainerNo(container: ContainerBookingResource | null | undefined) {
|
||||
if (!container) return false
|
||||
const value = String(container.containerNo || '').trim()
|
||||
return Boolean(value) && !/^(?:MAN|SPLIT)-/i.test(value)
|
||||
}
|
||||
function hasOpaqueCabinetReference(container: ContainerBookingResource | null | undefined) {
|
||||
return Boolean(container && /^\d{15,}$/.test(String(container.cabinetNo || '').trim()))
|
||||
function displayActualContainerNo(container: ContainerBookingResource | null | undefined) {
|
||||
return hasRealContainerNo(container) ? String(container?.containerNo || '').trim() : '待录入'
|
||||
}
|
||||
function syncDrafts(next: SmartLoadingPlan, preserved: Record<string, number> = {}) {
|
||||
for (const key of Object.keys(quantityDrafts)) delete quantityDrafts[key]
|
||||
@@ -346,13 +343,13 @@ async function removeAll() {
|
||||
}
|
||||
async function pushPreload() {
|
||||
if (!plan.value) return
|
||||
const confirmed = await ElMessageBox.confirm('推送后当前方案进入装柜流程,不能继续调整。确认推送预装清单?', '推送预装清单', {
|
||||
const confirmed = await ElMessageBox.confirm('推送后生成预装清单,不会直接开放 PDA。后续还需补集装箱号、关联并放舱真实订舱、确认预装。确认继续?', '推送预装清单', {
|
||||
type: 'warning', confirmButtonText: '确认推送', cancelButtonText: '取消',
|
||||
}).catch(() => false)
|
||||
if (!confirmed || !plan.value) return
|
||||
await mutate(async () => {
|
||||
acceptPlan(await pushSmartLoadingPreload(plan.value!.id, plan.value!.version))
|
||||
ElMessage.success('已推送预装清单')
|
||||
ElMessage.success('预装清单已生成,请继续完成集装箱号、订舱放舱和预装确认')
|
||||
}, '推送预装清单失败')
|
||||
}
|
||||
|
||||
@@ -456,24 +453,23 @@ onMounted(() => { void load(); void loadCustomers() })
|
||||
@click="selectContainer(item.id)"
|
||||
>
|
||||
<span class="container-option__top">
|
||||
<strong>{{ hasRealContainerNo(item) ? displayContainerNo(item) : '模拟柜次' }}</strong>
|
||||
<strong>{{ hasRealContainerNo(item) ? displayActualContainerNo(item) : '模拟柜次' }}</strong>
|
||||
<el-tag size="small" :type="hasRealContainerNo(item) ? 'success' : 'info'">
|
||||
{{ hasRealContainerNo(item) ? '已录入柜号' : '空柜' }}
|
||||
{{ hasRealContainerNo(item) ? '已录入集装箱号' : '空柜' }}
|
||||
</el-tag>
|
||||
</span>
|
||||
<span class="container-option__identity">
|
||||
{{ hasRealContainerNo(item) ? `柜号:${displayContainerNo(item)}` : (hasOpaqueCabinetReference(item) ? '模拟柜次:真实柜号待录入' : `柜次参考:${displayContainerNo(item)}`) }}
|
||||
</span>
|
||||
<span class="container-option__identity">柜次号:{{ displayCabinetNo(item) }}</span>
|
||||
<span>集装箱号:{{ displayActualContainerNo(item) }}</span>
|
||||
<span>渠道:{{ item.channelName || item.channelCode || '渠道待补充' }}</span>
|
||||
<span>仓库:{{ item.warehouseName || item.warehouseId || '仓库待补充' }} · 柜型:{{ item.containerType || '柜型待补充' }}</span>
|
||||
<span v-if="!hasRealContainerNo(item)" class="container-option__hint">真实柜号:待录入</span>
|
||||
<span v-if="!hasRealContainerNo(item)" class="container-option__hint">可先排货,开始装柜前录入集装箱号</span>
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<section class="dispatch-pane plan-pane">
|
||||
<header class="pane-header plan-header">
|
||||
<div><strong>{{ displayContainerNo(selectedContainer) }} 装柜方案</strong><small>{{ plan ? '当前柜号的装柜明细' : '尚未创建方案' }}</small></div>
|
||||
<div><strong>{{ hasRealContainerNo(selectedContainer) ? displayActualContainerNo(selectedContainer) : displayCabinetNo(selectedContainer) }} 装柜方案</strong><small>{{ selectedContainer ? `柜次号:${displayCabinetNo(selectedContainer)} · 集装箱号:${displayActualContainerNo(selectedContainer)}` : '尚未选择柜次' }}</small></div>
|
||||
<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-button v-if="canAssign && editable" type="primary" plain :loading="mutating" @click="recommend"><Sparkles :size="16" />智能推荐</el-button>
|
||||
@@ -496,6 +492,14 @@ onMounted(() => { void load(); void loadCustomers() })
|
||||
<el-button v-if="canCreate" type="primary" :loading="mutating" @click="createPlan"><Plus :size="16" />创建装柜方案</el-button>
|
||||
</el-empty>
|
||||
<template v-else-if="plan">
|
||||
<el-alert
|
||||
class="preload-readiness-alert"
|
||||
type="info"
|
||||
:closable="false"
|
||||
show-icon
|
||||
title="推送预装仅生成预装清单,不会直接开放 PDA"
|
||||
description="后续依次完成:补集装箱号、关联并放舱真实订舱、确认预装;全部满足后才生成 PDA 任务。"
|
||||
/>
|
||||
<div class="capacity-grid">
|
||||
<div><div class="meter-title"><span>体积</span><strong>{{ formatNumber(totalVolume) }} / {{ formatNumber(volumeLimit) }} m³</strong></div><el-progress :percentage="Math.min(displayedVolumePercent, 100)" :status="volumePercent > 100 ? 'exception' : undefined" /></div>
|
||||
<div><div class="meter-title"><span>重量</span><strong>{{ formatNumber(totalWeight, 1) }} / {{ formatNumber(weightLimit, 1) }} kg</strong></div><el-progress :percentage="Math.min(displayedWeightPercent, 100)" :status="weightPercent > 100 ? 'exception' : undefined" /></div>
|
||||
@@ -561,6 +565,7 @@ onMounted(() => { void load(); void loadCustomers() })
|
||||
.plan-actions,.row-actions { flex-wrap: wrap; }
|
||||
.plan-actions :deep(.el-button + .el-button),.row-actions :deep(.el-button + .el-button) { margin-left: 0; }
|
||||
.capacity-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; padding: 12px; border-bottom: 1px solid var(--cc-border); }
|
||||
.preload-readiness-alert { border-radius: 0; border-right: 0; border-left: 0; }
|
||||
.readonly-status-card { display: grid; align-content: start; justify-items: start; gap: 10px; padding: 28px 24px; }
|
||||
.readonly-status-card strong { font-size: 16px; }
|
||||
.readonly-status-card p { max-width: 460px; margin: 0; color: var(--cc-muted); line-height: 1.6; }
|
||||
|
||||
Reference in New Issue
Block a user