优化
This commit is contained in:
@@ -21,7 +21,6 @@ import {
|
||||
performOceanBookingAction,
|
||||
releaseOceanBooking,
|
||||
requestOceanBookingChange,
|
||||
updateOceanBooking,
|
||||
listWarehouseLogisticsChannels,
|
||||
type OceanLogisticsChannel,
|
||||
type OceanBookingAction,
|
||||
@@ -47,28 +46,24 @@ const containerKindOptions = [
|
||||
{ value: 'LCL', label: '拼箱 LCL' },
|
||||
]
|
||||
const actionLabels: Record<OceanBookingAction, string> = {
|
||||
submit: '提交', confirm: '确认订舱', release: '确认放舱', fail: '标记失败', cancel: '取消订舱',
|
||||
release: '确认放舱', cancel: '取消订舱',
|
||||
'change-request': '申请改船', 'change-confirm': '确认改船', 'change-fail': '改船失败',
|
||||
}
|
||||
const actionPermissions: Record<OceanBookingAction, string> = {
|
||||
submit: 'platform:firstleg:ocean-booking:submit', confirm: 'platform:firstleg:ocean-booking:confirm',
|
||||
release: 'platform:firstleg:ocean-booking:release', fail: 'platform:firstleg:ocean-booking:confirm',
|
||||
release: 'platform:firstleg:ocean-booking:release',
|
||||
cancel: 'platform:firstleg:ocean-booking:cancel', 'change-request': 'platform:firstleg:ocean-booking:change',
|
||||
'change-confirm': 'platform:firstleg:ocean-booking:change', 'change-fail': 'platform:firstleg:ocean-booking:change',
|
||||
}
|
||||
const actionsByStatus: Partial<Record<OceanBookingStatus, OceanBookingAction[]>> = {
|
||||
DRAFT: ['submit', 'cancel'],
|
||||
SUBMITTED: ['confirm', 'fail', 'cancel'],
|
||||
CONFIRMED: ['release', 'change-request', 'cancel'],
|
||||
CHANGE_PENDING: ['change-confirm', 'change-fail', 'cancel'],
|
||||
FAILED: ['cancel'],
|
||||
}
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const access = useAccessPreviewStore()
|
||||
const id = computed(() => String(route.params.bookingId || ''))
|
||||
const isNew = computed(() => id.value === 'new')
|
||||
const isNew = computed(() => route.name === 'ocean-booking-create' || id.value === 'new')
|
||||
const detail = ref<OceanBookingDetail | null>(null)
|
||||
const loading = ref(false)
|
||||
const saving = ref(false)
|
||||
@@ -99,6 +94,7 @@ function blankParties(): OceanBookingParty[] {
|
||||
function blankData(): OceanBookingDraftData {
|
||||
return {
|
||||
customerId: null, customerName: null, channelCode: '', warehouseId: '', warehouseName: '', serviceTerm: null, freightTerm: null, parties: blankParties(),
|
||||
billOfLadingNo: '', vesselName: '', voyageNo: '', estimatedSailingAt: null, estimatedArrivalAt: null,
|
||||
containerRequirements: [createBlankContainerRequirement()],
|
||||
}
|
||||
}
|
||||
@@ -106,20 +102,25 @@ const form = reactive<OceanBookingSaveRequest>({ expectedVersion: 0, data: blank
|
||||
const rules: FormRules = {
|
||||
warehouseId: [{ required: true, message: '请选择装柜仓库', trigger: 'change' }],
|
||||
channelCode: [{ required: true, message: '请选择物流渠道', trigger: 'change' }],
|
||||
billOfLadingNo: [{ required: true, message: '请输入提单号', trigger: 'blur' }],
|
||||
vesselName: [{ required: true, message: '请输入船名', trigger: 'blur' }],
|
||||
voyageNo: [{ required: true, message: '请输入航次', trigger: 'blur' }],
|
||||
estimatedSailingAt: [{ required: true, message: '请选择预计开船时间', trigger: 'change' }],
|
||||
estimatedArrivalAt: [{ required: true, message: '请选择预计到港时间', trigger: 'change' }],
|
||||
serviceTerm: [{ required: true, message: '请输入主要运输条款 Service Term', trigger: 'blur' }],
|
||||
freightTerm: [{ required: true, message: '请输入运费条款 Freight Term', trigger: 'blur' }],
|
||||
}
|
||||
const editable = computed(() => isNew.value || detail.value?.status === 'DRAFT')
|
||||
const editable = computed(() => isNew.value)
|
||||
const canSave = computed(() => isNew.value
|
||||
? access.can('platform:firstleg:ocean-booking:create')
|
||||
: editable.value && access.can('platform:firstleg:ocean-booking:edit'))
|
||||
const availableActions = computed(() => (actionsByStatus[detail.value?.status || 'DRAFT'] || [])
|
||||
const availableActions = computed(() => (actionsByStatus[detail.value?.status || 'CONFIRMED'] || [])
|
||||
.filter((action) => access.can(actionPermissions[action])))
|
||||
|
||||
const changeDialogOpen = ref(false)
|
||||
const changeForm = reactive({ vesselName: '', voyageNo: '', estimatedSailingAt: null as string | null, estimatedArrivalAt: null as string | null, reason: '' })
|
||||
const releaseDialogOpen = ref(false)
|
||||
const releaseForm = reactive({ billOfLadingNo: '', vesselName: '', voyageNo: '', estimatedSailingAt: null as string | null, estimatedArrivalAt: null as string | null, reason: '' })
|
||||
const releaseReason = ref('')
|
||||
|
||||
function statusLabel(status: OceanBookingStatus | string | null | undefined) {
|
||||
return oceanBookingStatusLabel(status)
|
||||
@@ -153,6 +154,9 @@ function normalizeDraftData() {
|
||||
form.data.customerName = form.data.customerId ? form.data.customerName : null
|
||||
form.data.serviceTerm = form.data.serviceTerm?.trim() || null
|
||||
form.data.freightTerm = form.data.freightTerm?.trim() || null
|
||||
form.data.billOfLadingNo = form.data.billOfLadingNo.trim()
|
||||
form.data.vesselName = form.data.vesselName.trim()
|
||||
form.data.voyageNo = form.data.voyageNo.trim()
|
||||
}
|
||||
function selectWarehouse(value: unknown) {
|
||||
const warehouseId = String(value || '')
|
||||
@@ -197,6 +201,8 @@ function applyDetail(value: OceanBookingDetail) {
|
||||
form.expectedVersion = value.version
|
||||
form.data = {
|
||||
customerId: value.customerId ?? null, customerName: value.customerName ?? null, channelCode: value.channelCode || '', warehouseId: value.warehouseId || '', warehouseName: value.warehouseName || '',
|
||||
billOfLadingNo: value.billOfLadingNo || '', vesselName: value.vesselName || '', voyageNo: value.voyageNo || '',
|
||||
estimatedSailingAt: value.estimatedSailingAt || null, estimatedArrivalAt: value.estimatedArrivalAt || null,
|
||||
shippingCompanyId: value.shippingCompanyId, shippingCompanyName: value.shippingCompanyName,
|
||||
bookingAgentId: value.bookingAgentId, bookingAgentName: value.bookingAgentName,
|
||||
departurePortCode: value.departurePortCode, departurePortName: value.departurePortName,
|
||||
@@ -223,7 +229,11 @@ async function save() {
|
||||
actionError.value = null
|
||||
normalizeDraftData()
|
||||
if (!await formRef.value?.validate().catch(() => false)) {
|
||||
actionError.value = { message: '请完善装柜仓库、物流渠道和运输条款等必填信息' }
|
||||
actionError.value = { message: '请完善装柜仓库、物流渠道、真实运输资料和运输条款等必填信息' }
|
||||
return
|
||||
}
|
||||
if (form.data.estimatedArrivalAt! < form.data.estimatedSailingAt!) {
|
||||
actionError.value = { message: '预计到港时间不能早于预计开船时间' }
|
||||
return
|
||||
}
|
||||
if (form.data.parties.some((party) => !party.partyName.trim())) {
|
||||
@@ -237,18 +247,15 @@ async function save() {
|
||||
const payload = { ...form.data }
|
||||
if (isNew.value) {
|
||||
const created = await createOceanBooking({ expectedVersion: 0, data: payload })
|
||||
ElMessage.success('订舱已创建')
|
||||
ElMessage.success('线下订舱资料已登记并确认')
|
||||
await router.replace(`/ocean-bookings/${created.id}`)
|
||||
applyDetail(created)
|
||||
} else {
|
||||
applyDetail(await updateOceanBooking(id.value, { expectedVersion: form.expectedVersion, data: payload }))
|
||||
ElMessage.success('订舱草稿已保存')
|
||||
}
|
||||
} catch (cause) { actionError.value = getApiErrorDetails(cause) }
|
||||
finally { saving.value = false }
|
||||
}
|
||||
async function requiredReason(action: OceanBookingAction) {
|
||||
if (!['fail', 'cancel', 'change-fail'].includes(action)) return null
|
||||
if (!['cancel', 'change-fail'].includes(action)) return null
|
||||
const result = await ElMessageBox.prompt(`请填写“${actionLabels[action]}”原因,服务端将写入状态历史。`, actionLabels[action], {
|
||||
inputValidator: (value) => Boolean(value?.trim()) || '原因不能为空',
|
||||
confirmButtonText: '确认', cancelButtonText: '取消', type: 'warning',
|
||||
@@ -264,31 +271,28 @@ function openChangeDialog() {
|
||||
changeDialogOpen.value = true
|
||||
}
|
||||
function openReleaseDialog() {
|
||||
releaseForm.billOfLadingNo = detail.value?.billOfLadingNo || ''
|
||||
releaseForm.vesselName = detail.value?.vesselName || ''
|
||||
releaseForm.voyageNo = detail.value?.voyageNo || ''
|
||||
releaseForm.estimatedSailingAt = detail.value?.estimatedSailingAt || null
|
||||
releaseForm.estimatedArrivalAt = detail.value?.estimatedArrivalAt || null
|
||||
releaseForm.reason = ''
|
||||
releaseReason.value = ''
|
||||
releaseDialogOpen.value = true
|
||||
}
|
||||
async function submitRelease() {
|
||||
if (!detail.value) return
|
||||
const billOfLadingNo = releaseForm.billOfLadingNo.trim()
|
||||
const vesselName = releaseForm.vesselName.trim()
|
||||
const voyageNo = releaseForm.voyageNo.trim()
|
||||
if (!billOfLadingNo || !vesselName || !voyageNo || !releaseForm.estimatedSailingAt || !releaseForm.estimatedArrivalAt) {
|
||||
actionError.value = getApiErrorDetails(new Error('请完整填写提单号、船名、航次、预计开船和预计到港时间'))
|
||||
const billOfLadingNo = detail.value.billOfLadingNo?.trim()
|
||||
const vesselName = detail.value.vesselName?.trim()
|
||||
const voyageNo = detail.value.voyageNo?.trim()
|
||||
const estimatedSailingAt = detail.value.estimatedSailingAt
|
||||
const estimatedArrivalAt = detail.value.estimatedArrivalAt
|
||||
if (!billOfLadingNo || !vesselName || !voyageNo || !estimatedSailingAt || !estimatedArrivalAt) {
|
||||
actionError.value = getApiErrorDetails(new Error('当前订舱缺少已确认运输资料,无法放舱'))
|
||||
return
|
||||
}
|
||||
if (releaseForm.estimatedArrivalAt < releaseForm.estimatedSailingAt) {
|
||||
if (estimatedArrivalAt < estimatedSailingAt) {
|
||||
actionError.value = getApiErrorDetails(new Error('预计到港时间不能早于预计开船时间'))
|
||||
return
|
||||
}
|
||||
actionSaving.value = true
|
||||
actionError.value = null
|
||||
try {
|
||||
applyDetail(await releaseOceanBooking(id.value, { expectedVersion: detail.value.version, billOfLadingNo, vesselName, voyageNo, estimatedSailingAt: releaseForm.estimatedSailingAt, estimatedArrivalAt: releaseForm.estimatedArrivalAt, reason: releaseForm.reason.trim() || null }))
|
||||
applyDetail(await releaseOceanBooking(id.value, { expectedVersion: detail.value.version, billOfLadingNo, vesselName, voyageNo, estimatedSailingAt, estimatedArrivalAt, reason: releaseReason.value.trim() || null }))
|
||||
releaseDialogOpen.value = false
|
||||
ElMessage.success('确认放舱成功')
|
||||
} catch (cause) { actionError.value = getApiErrorDetails(cause) }
|
||||
@@ -344,7 +348,7 @@ onMounted(() => { void load(); void loadOptions() })
|
||||
<template #header>
|
||||
<div class="detail-heading">
|
||||
<el-button @click="router.push('/ocean-bookings')"><ArrowLeft :size="16" />返回列表</el-button>
|
||||
<PageToolbar class="booking-page-toolbar" as="section" :title="detail?.bookingNo || '订舱资料'" :description="detail ? `${detail.customerName || '未关联客户'} · ${detail.pol || '—'} → ${detail.pod || '—'}` : '填写并保存订舱资料'">
|
||||
<PageToolbar class="booking-page-toolbar" as="section" :title="detail?.bookingNo || '订舱资料'" :description="detail ? `${detail.customerName || '未关联客户'} · ${detail.pol || '—'} → ${detail.pod || '—'}` : '登记线下已确认的真实订舱资料'">
|
||||
<template v-if="detail" #actions><div class="heading-status"><StatusBadge :status="statusLabel(detail.status)" /></div></template>
|
||||
</PageToolbar>
|
||||
</div>
|
||||
@@ -355,10 +359,10 @@ onMounted(() => { void load(); void loadOptions() })
|
||||
<el-alert v-if="actionError" type="error" :closable="false" show-icon :title="actionError.message"><ApiErrorMeta :details="actionError" /></el-alert>
|
||||
<section class="surface-panel">
|
||||
<div class="section-title">
|
||||
<div><h2>订舱信息</h2><p v-if="detail && !editable">当前状态仅可查看,草稿状态才允许编辑。</p></div>
|
||||
<div><h2>订舱信息</h2><p v-if="detail && !editable">已确认订舱资料仅可查看,船期变更请使用“申请改船”。</p></div>
|
||||
<div class="actions">
|
||||
<el-button v-for="item in availableActions" :key="item" :loading="actionSaving" @click="runAction(item)">{{ actionLabels[item] }}</el-button>
|
||||
<el-button v-if="canSave" type="primary" :loading="saving" @click="save"><Save :size="16" />保存</el-button>
|
||||
<el-button v-if="canSave" type="primary" :loading="saving" @click="save"><Save :size="16" />{{ isNew ? '登记订舱' : '保存' }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-alert v-if="optionsError" type="warning" :closable="false" show-icon :title="optionsError"><el-button link type="warning" :loading="optionsLoading" @click="loadOptions">重新加载选项</el-button></el-alert>
|
||||
@@ -367,25 +371,25 @@ onMounted(() => { void load(); void loadOptions() })
|
||||
<h3>基本信息</h3><div class="booking-group__body booking-group__body--fields">
|
||||
<el-form-item label="订舱号"><el-input :model-value="detail?.bookingNo || '保存后生成'" disabled /></el-form-item>
|
||||
<el-form-item label="客户(可选)"><el-select :model-value="form.data.customerId" filterable clearable placeholder="请选择客户(可选)" no-data-text="暂无可选客户" :loading="optionsLoading" style="width:100%" @update:model-value="selectCustomer"><el-option v-if="form.data.customerId && !selectableCustomers.some((customer) => String(customer.id) === String(form.data.customerId))" :label="form.data.customerName || '客户名称缺失'" :value="String(form.data.customerId)" /><el-option v-for="customer in selectableCustomers" :key="String(customer.id)" :label="customer.tenantName" :value="String(customer.id)" /></el-select></el-form-item>
|
||||
<el-form-item label="状态"><el-input :model-value="detail ? statusLabel(detail.status) : '待创建'" disabled /></el-form-item>
|
||||
<el-form-item label="状态"><el-input :model-value="detail ? statusLabel(detail.status) : '登记后直接确认'" disabled /></el-form-item>
|
||||
<el-form-item label="装柜仓库" prop="warehouseId"><el-select :model-value="form.data.warehouseId" filterable placeholder="请选择装柜仓库" :loading="optionsLoading" style="width:100%" @update:model-value="selectWarehouse"><el-option v-for="warehouse in warehouses" :key="String(warehouse.id)" :label="warehouse.warehouseName" :value="String(warehouse.id)" /></el-select></el-form-item>
|
||||
<el-form-item label="物流渠道" prop="channelCode"><el-select :model-value="form.data.channelCode" filterable :disabled="!form.data.warehouseId || channelsLoading || !!channelsError || channelUnavailable" :loading="channelsLoading" :placeholder="form.data.warehouseId ? '请选择物流渠道' : '请先选择装柜仓库'" no-data-text="该仓库暂无有效物流渠道" style="width:100%" @update:model-value="selectChannel(String($event || ''))"><el-option v-if="form.data.channelCode && !channels.some((channel) => channel.channelCode === form.data.channelCode)" :label="selectedChannelName || form.data.channelCode" :value="form.data.channelCode" /><el-option v-for="channel in channels" :key="channel.channelCode" :label="channel.channelName" :value="channel.channelCode"><span>{{ channel.channelName }}</span><small class="channel-code">{{ channel.channelCode }}</small></el-option></el-select><div v-if="channelsError" class="field-error"><span>{{ channelsError }}</span><el-button link type="primary" :loading="channelsLoading" @click="loadChannels(form.data.warehouseId)">重新加载</el-button></div><div v-else-if="channelUnavailable" class="field-hint">该仓库暂无有效物流渠道,请更换仓库或联系管理员。</div></el-form-item>
|
||||
<el-form-item label="提单号"><el-input :model-value="detail?.billOfLadingNo || ''" disabled placeholder="确认放舱时录入" /></el-form-item>
|
||||
<el-form-item label="提单号" prop="billOfLadingNo"><el-input v-model="form.data.billOfLadingNo" maxlength="128" placeholder="请输入提单号" /></el-form-item>
|
||||
<el-form-item label="船公司"><el-select :model-value="form.data.shippingCompanyId" filterable clearable placeholder="请选择船公司" :loading="optionsLoading" style="width:100%" @update:model-value="selectPartner('shippingCompany', String($event || ''))"><el-option v-if="form.data.shippingCompanyId && !shippingCompanies.some((partner) => String(partner.id) === String(form.data.shippingCompanyId))" :label="form.data.shippingCompanyName || '船公司名称缺失'" :value="String(form.data.shippingCompanyId)" /><el-option v-for="partner in shippingCompanies" :key="String(partner.id)" :label="partner.partnerName" :value="String(partner.id)" /></el-select></el-form-item>
|
||||
<el-form-item label="订舱代理"><el-select :model-value="form.data.bookingAgentId" filterable clearable placeholder="请选择订舱代理" :loading="optionsLoading" style="width:100%" @update:model-value="selectPartner('bookingAgent', String($event || ''))"><el-option v-if="form.data.bookingAgentId && !bookingAgents.some((partner) => String(partner.id) === String(form.data.bookingAgentId))" :label="form.data.bookingAgentName || '订舱代理名称缺失'" :value="String(form.data.bookingAgentId)" /><el-option v-for="partner in bookingAgents" :key="String(partner.id)" :label="partner.partnerName" :value="String(partner.id)" /></el-select></el-form-item>
|
||||
</div>
|
||||
</section>
|
||||
<section class="booking-group" aria-label="航线船期">
|
||||
<h3>航线船期</h3><div class="booking-group__body booking-group__body--fields">
|
||||
<el-form-item label="船名"><el-input :model-value="detail?.vesselName || ''" disabled placeholder="确认放舱时录入" /></el-form-item>
|
||||
<el-form-item label="航次"><el-input :model-value="detail?.voyageNo || ''" disabled placeholder="确认放舱时录入" /></el-form-item>
|
||||
<el-form-item label="船名" prop="vesselName"><el-input v-model="form.data.vesselName" maxlength="128" placeholder="请输入船名" /></el-form-item>
|
||||
<el-form-item label="航次" prop="voyageNo"><el-input v-model="form.data.voyageNo" maxlength="64" placeholder="请输入航次" /></el-form-item>
|
||||
<el-form-item label="起运港代码"><el-input v-model="form.data.departurePortCode" placeholder="例如:CNNGB" /></el-form-item>
|
||||
<el-form-item label="起运港"><el-input v-model="form.data.departurePortName" placeholder="例如:宁波港" /></el-form-item>
|
||||
<el-form-item label="目的港代码"><el-input v-model="form.data.destinationPortCode" placeholder="例如:USLAX" /></el-form-item>
|
||||
<el-form-item label="目的港"><el-input v-model="form.data.destinationPortName" placeholder="例如:洛杉矶港" /></el-form-item>
|
||||
<el-form-item class="booking-field--wide" label="交货地点"><el-input v-model="form.data.placeOfDelivery" placeholder="请输入最终交货地点" /></el-form-item>
|
||||
<el-form-item label="预计开船"><el-date-picker :model-value="detail?.estimatedSailingAt || null" type="datetime" value-format="YYYY-MM-DDTHH:mm:ss" disabled placeholder="确认放舱时录入" style="width:100%" /></el-form-item>
|
||||
<el-form-item label="预计到港"><el-date-picker :model-value="detail?.estimatedArrivalAt || null" type="datetime" value-format="YYYY-MM-DDTHH:mm:ss" disabled placeholder="确认放舱时录入" style="width:100%" /></el-form-item>
|
||||
<el-form-item label="预计开船" prop="estimatedSailingAt"><el-date-picker v-model="form.data.estimatedSailingAt" type="datetime" value-format="YYYY-MM-DDTHH:mm:ss" placeholder="请选择预计开船时间" style="width:100%" /></el-form-item>
|
||||
<el-form-item label="预计到港" prop="estimatedArrivalAt"><el-date-picker v-model="form.data.estimatedArrivalAt" type="datetime" value-format="YYYY-MM-DDTHH:mm:ss" placeholder="请选择预计到港时间" style="width:100%" /></el-form-item>
|
||||
</div>
|
||||
</section>
|
||||
<section class="booking-group" aria-label="条款与柜量">
|
||||
@@ -459,14 +463,17 @@ onMounted(() => { void load(); void loadOptions() })
|
||||
</el-form>
|
||||
<LoadErrorState v-if="actionError" compact title="提交失败" :message="actionError.message" :show-retry="false"><template #details><ApiErrorMeta :details="actionError" /></template></LoadErrorState>
|
||||
</AppDialog>
|
||||
<AppDialog v-model="releaseDialogOpen" title="确认放舱" width="min(560px, 94vw)" :confirm-loading="actionSaving" :confirm-disabled="!releaseForm.billOfLadingNo.trim() || !releaseForm.vesselName.trim() || !releaseForm.voyageNo.trim() || !releaseForm.estimatedSailingAt || !releaseForm.estimatedArrivalAt" confirm-text="确认放舱" cancel-text="取消" @confirm="submitRelease">
|
||||
<AppDialog v-model="releaseDialogOpen" title="确认放舱" width="min(560px, 94vw)" :confirm-loading="actionSaving" confirm-text="确认放舱" cancel-text="取消" @confirm="submitRelease">
|
||||
<el-form label-position="top">
|
||||
<el-form-item label="提单号" required><el-input v-model="releaseForm.billOfLadingNo" maxlength="128" placeholder="请输入提单号" /></el-form-item>
|
||||
<el-form-item label="船名" required><el-input v-model="releaseForm.vesselName" maxlength="128" placeholder="请输入船名" /></el-form-item>
|
||||
<el-form-item label="航次" required><el-input v-model="releaseForm.voyageNo" maxlength="64" placeholder="请输入航次" /></el-form-item>
|
||||
<el-form-item label="预计开船" required><el-date-picker v-model="releaseForm.estimatedSailingAt" type="datetime" value-format="YYYY-MM-DDTHH:mm:ss" placeholder="请选择预计开船时间" style="width:100%" /></el-form-item>
|
||||
<el-form-item label="预计到港" required><el-date-picker v-model="releaseForm.estimatedArrivalAt" type="datetime" value-format="YYYY-MM-DDTHH:mm:ss" placeholder="请选择预计到港时间" style="width:100%" /></el-form-item>
|
||||
<el-form-item label="备注"><el-input v-model="releaseForm.reason" type="textarea" maxlength="1000" placeholder="请输入放舱备注(可选)" /></el-form-item>
|
||||
<el-alert title="请复核已登记的真实订舱资料。放舱不会重新采集或修改这些信息。" type="info" :closable="false" show-icon />
|
||||
<el-descriptions class="release-summary" :column="2" border>
|
||||
<el-descriptions-item label="提单号">{{ detail?.billOfLadingNo || '—' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="船名">{{ detail?.vesselName || '—' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="航次">{{ detail?.voyageNo || '—' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="预计开船">{{ detail?.estimatedSailingAt || '—' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="预计到港">{{ detail?.estimatedArrivalAt || '—' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-form-item label="备注"><el-input v-model="releaseReason" type="textarea" maxlength="1000" placeholder="请输入放舱备注(可选)" /></el-form-item>
|
||||
</el-form>
|
||||
<LoadErrorState v-if="actionError" compact title="放舱失败" :message="actionError.message" :show-retry="false"><template #details><ApiErrorMeta :details="actionError" /></template></LoadErrorState>
|
||||
</AppDialog>
|
||||
|
||||
Reference in New Issue
Block a user