fix(admin): complete container loading workflows
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
|
||||
import { Eye, Pencil } from '@lucide/vue'
|
||||
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
||||
@@ -28,6 +29,7 @@ import {
|
||||
} from '../api/platformLoadingLists'
|
||||
|
||||
const props = defineProps<{ mode: LoadingListMode }>()
|
||||
const route = useRoute()
|
||||
const access = useAccessPreviewStore()
|
||||
const rows = ref<LoadingListSummary[]>([])
|
||||
const loading = ref(false)
|
||||
@@ -47,6 +49,7 @@ const editSaving = ref(false)
|
||||
const editError = ref<ApiErrorDetails | null>(null)
|
||||
const editFormRef = ref<FormInstance>()
|
||||
const editForm = reactive({ containerNo: '', voyageNo: '', operationReason: '' })
|
||||
const handledDeepLink = ref('')
|
||||
|
||||
const isPreload = computed(() => props.mode === 'preload')
|
||||
const title = computed(() => isPreload.value ? '预装清单' : '装柜清单')
|
||||
@@ -107,6 +110,14 @@ function formatNumber(value?: number | null, digits = 3) {
|
||||
return Number(value).toLocaleString('zh-CN', { maximumFractionDigits: digits })
|
||||
}
|
||||
|
||||
function statusLabel(status?: string | null) {
|
||||
return status === 'LOADING' ? '装柜中' : status === 'COMPLETED' ? '装柜完成' : status || '未知状态'
|
||||
}
|
||||
|
||||
function queryId(value: unknown) {
|
||||
return typeof value === 'string' && /^[1-9]\d*$/.test(value) ? value : ''
|
||||
}
|
||||
|
||||
function toQuery(): LoadingListQuery {
|
||||
const range = Array.isArray(query.createdRange) ? query.createdRange.map(String) : []
|
||||
return {
|
||||
@@ -127,6 +138,7 @@ async function load() {
|
||||
const result = isPreload.value ? await listPreloadPlans(request) : await listConfirmedLoadingLists(request)
|
||||
rows.value = result.records
|
||||
total.value = result.total
|
||||
await openDeepLinkedDetail()
|
||||
} catch (cause) {
|
||||
error.value = getApiErrorDetails(cause, `${title.value}加载失败,请稍后重试`)
|
||||
} finally {
|
||||
@@ -134,6 +146,30 @@ async function load() {
|
||||
}
|
||||
}
|
||||
|
||||
async function openDeepLinkedDetail() {
|
||||
const planId = queryId(route.query.planId)
|
||||
const warehouseId = queryId(route.query.warehouseId)
|
||||
if (!planId || !warehouseId || !canView.value) return
|
||||
const key = `${props.mode}:${planId}:${warehouseId}`
|
||||
if (handledDeepLink.value === key) return
|
||||
handledDeepLink.value = key
|
||||
selectedPlanId.value = planId
|
||||
selectedWarehouseId.value = warehouseId
|
||||
detail.value = null
|
||||
detailError.value = null
|
||||
detailOpen.value = true
|
||||
await loadDetail()
|
||||
const expectedStatus = isPreload.value ? 'LOADING' : 'COMPLETED'
|
||||
const loadedDetail = detail.value as LoadingDetail | null
|
||||
if (loadedDetail && loadedDetail.summary.status !== expectedStatus) {
|
||||
detail.value = null
|
||||
detailError.value = {
|
||||
code: 'MODE_STATUS_MISMATCH',
|
||||
message: `该计划不属于当前${title.value}状态,请从对应清单入口查看。`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function search() {
|
||||
if (page.value !== 1) page.value = 1
|
||||
else void load()
|
||||
@@ -141,7 +177,15 @@ function search() {
|
||||
|
||||
|
||||
async function loadDetail() {
|
||||
if (!selectedPlanId.value || !selectedWarehouseId.value || !canView.value) return
|
||||
if (!canView.value) return
|
||||
if (!selectedPlanId.value || !selectedWarehouseId.value) {
|
||||
detail.value = null
|
||||
detailError.value = {
|
||||
message: '该清单缺少所属仓库信息,无法安全查询详情,请联系管理员核对数据。',
|
||||
code: 'MISSING_WAREHOUSE_CONTEXT',
|
||||
}
|
||||
return
|
||||
}
|
||||
detailLoading.value = true
|
||||
detailError.value = null
|
||||
try {
|
||||
@@ -204,13 +248,23 @@ async function saveTransport() {
|
||||
ElMessage.success('运输信息已更新')
|
||||
await load()
|
||||
} catch (cause) {
|
||||
editError.value = getApiErrorDetails(cause, '运输信息保存失败,请刷新详情后重试')
|
||||
const details = getApiErrorDetails(cause, '运输信息保存失败,请刷新详情后重试')
|
||||
if (details.code === 'A0409' || /版本|并发|已被其他人修改/.test(details.message)) {
|
||||
await loadDetail()
|
||||
editError.value = {
|
||||
...details,
|
||||
message: '运输信息已被其他人修改,系统已刷新最新版本;当前输入已保留,请核对后重新保存。',
|
||||
}
|
||||
} else {
|
||||
editError.value = details
|
||||
}
|
||||
} finally {
|
||||
editSaving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
watch([page, pageSize], () => void load())
|
||||
watch(() => [route.query.planId, route.query.warehouseId], () => void openDeepLinkedDetail())
|
||||
onMounted(() => {
|
||||
void load()
|
||||
})
|
||||
@@ -256,7 +310,7 @@ onMounted(() => {
|
||||
</template>
|
||||
<template #customers="{ row }">{{ (row as PreloadSummary).customers.map((item) => item.customerName || item.accountId).join('、') || '—' }}</template>
|
||||
<template #vesselVoyage="{ row }">{{ (row as PreloadSummary).vesselName || '—' }} / {{ (row as PreloadSummary).voyageNo || '—' }}</template>
|
||||
<template #status="{ row }"><StatusBadge :status="row.status" /><span class="status-label">{{ row.status === 'LOADING' ? '装柜中' : row.status === 'COMPLETED' ? '装柜完成' : row.status }}</span></template>
|
||||
<template #status="{ row }"><StatusBadge :status="statusLabel(row.status)" /></template>
|
||||
<template #grossWeight="{ row }">{{ formatNumber(row.totalGrossWeightKg) }}</template>
|
||||
<template #netWeight="{ row }">{{ formatNumber((row as ConfirmedSummary).totalNetWeightKg) }}</template>
|
||||
<template #volume="{ row }">{{ formatNumber(row.totalVolumeCbm) }}</template>
|
||||
@@ -301,8 +355,6 @@ onMounted(() => {
|
||||
<style scoped>
|
||||
.loading-lists-page { display: grid; min-width: 0; gap: 16px; }
|
||||
.table-panel { min-width: 0; overflow: hidden; border: 1px solid var(--cc-border); background: #fff; }
|
||||
.status-label { color: var(--cc-muted); font-size: 12px; }
|
||||
.status-label { margin-left: 6px; }
|
||||
.transport-form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 16px; margin-top: 16px; }
|
||||
.transport-form :deep(.el-form-item:last-child) { grid-column: 1 / -1; }
|
||||
@media (max-width: 640px) { .transport-form { grid-template-columns: 1fr; } .transport-form :deep(.el-form-item:last-child) { grid-column: auto; } }
|
||||
|
||||
Reference in New Issue
Block a user