62 lines
8.6 KiB
Vue
62 lines
8.6 KiB
Vue
<script setup lang="ts">
|
||
import '@/styles/adminDensity.css'
|
||
import { computed } from 'vue'
|
||
import type { PlatformProcurement, ProcurementFile } from '../procurementTypes'
|
||
import type { ProcurementCommand } from '../api/procurementCommands'
|
||
import { transportForm, transportCargo, type TransportForm } from '../procurementTransportForm'
|
||
import { dateTime, measurement, money } from '../procurementPresentation'
|
||
const props = defineProps<{ command: ProcurementCommand; detail: PlatformProcurement; files: ProcurementFile[] }>()
|
||
const form = defineModel<TransportForm>({ required: true })
|
||
const cargo = computed(() => transportCargo(props.detail, form.value.leg))
|
||
const labelSet = computed(() => form.value.leg === 'OVERSEAS' ? props.detail.transport.overseasLabels : props.detail.transport.domesticLabels)
|
||
const sender = computed(() => form.value.leg === 'DOMESTIC' ? props.detail.transport.overseasLabels?.receiver : labelSet.value?.sender)
|
||
const estimate = computed(() => props.detail.customerView.fees.find(row => row.active && row.purpose === 'INTERNATIONAL_ESTIMATE'))
|
||
const changedReceiver = computed(() => form.value.leg === 'DOMESTIC' && (form.value.receiver.name.trim() !== props.detail.customerView.order.contactName || form.value.receiver.phone.trim() !== props.detail.customerView.order.contactPhone || form.value.receiver.address.trim() !== props.detail.customerView.order.receivingAddress))
|
||
function changeLeg() { form.value = transportForm(props.detail, form.value.leg) }
|
||
function selectCarton(id: string) { const box = props.detail.transport.domesticCargo.find(row => row.cartonId === id); if (box) Object.assign(form.value, { lengthCm: String(box.lengthCm), widthCm: String(box.widthCm), heightCm: String(box.heightCm), grossWeightKg: String(box.grossWeightKg) }) }
|
||
</script>
|
||
<template>
|
||
<div class="admin-density">
|
||
<template v-if="command === 'labels'">
|
||
<el-form-item label="面单运输段" required><el-radio-group v-model="form.leg" @change="changeLeg"><el-radio value="OVERSEAS" :disabled="!!detail.purchaseFacts.overseas_shipped_at">国际段</el-radio><el-radio value="DOMESTIC" :disabled="!detail.purchaseFacts.domestic_received_at">寄客户段</el-radio></el-radio-group></el-form-item>
|
||
<p>寄件资料:{{ sender ? `${sender.name} · ${sender.phone} · ${sender.address}` : '由实际海外收货仓主档提供,保存时核对。' }}</p>
|
||
<div class="transport-grid"><el-form-item :label="form.leg === 'OVERSEAS' ? '国内接收人' : '最终收件人'" required><el-input v-model="form.receiver.name" maxlength="128" /></el-form-item><el-form-item label="联系电话" required><el-input v-model="form.receiver.phone" maxlength="64" /></el-form-item></div>
|
||
<el-form-item label="完整收件地址" required><el-input v-model="form.receiver.address" maxlength="1000" /></el-form-item>
|
||
<el-form-item v-if="changedReceiver" label="客户确认收件信息变更凭证" required><el-select v-model="form.addressVoucherFileId" placeholder="选择本单已上传的客户确认凭证"><el-option v-for="file in files.filter(item => item.category === 'EXCEPTION')" :key="file.fileId" :label="file.fileName" :value="file.fileId" /></el-select></el-form-item>
|
||
<section v-for="row in form.labels" :key="row.cartonId" class="label-row">
|
||
<strong>{{ cargo.find(box => box.cartonId === row.cartonId)?.cartonNo || '未关联箱' }}</strong>
|
||
<div class="label-grid"><el-form-item label="本单面单文件" required><el-select v-model="row.fileId" placeholder="选择 PDF、JPG 或 PNG"><el-option v-for="file in files.filter(item => item.category === 'LABEL')" :key="file.fileId" :value="file.fileId" :label="file.fileName" /></el-select></el-form-item><el-form-item label="对应页码" required><el-input-number v-model="row.page" :min="1" :precision="0" controls-position="right" placeholder="图片填 1" /></el-form-item><el-form-item label="承运商" required><el-input v-model="row.carrier" maxlength="128" placeholder="填写实际承运商" /></el-form-item><el-form-item label="本箱运单号" required><el-input v-model="row.trackingNo" maxlength="128" placeholder="填写本箱主/子运单号" /></el-form-item></div>
|
||
</section>
|
||
</template>
|
||
<template v-if="command === 'international-estimate'">
|
||
<el-alert title="本次只冻结预估国际运费,不直接扣款。变价时先释放原冻结,释放完成后再次核对并提交新预估;同价也需核对当前面单版本。" type="info" :closable="false" />
|
||
<p>当前面单:第 {{ labelSet?.version || '—' }} 版;有效原预估:{{ estimate ? money(estimate.amount, estimate.currency) : '尚未核定' }}</p>
|
||
<div class="transport-grid"><el-form-item label="预估国际运费(CNY)" required><el-input v-model="form.amount" placeholder="明确填写金额,包括零元" /></el-form-item><el-form-item label="业务日期" required><el-date-picker v-model="form.businessDate" type="date" value-format="YYYY-MM-DD" /></el-form-item></div>
|
||
</template>
|
||
<template v-if="command === 'labels/apply'">
|
||
<p>国际面单第 {{ labelSet?.version || '—' }} 版,逐箱记录实际贴单。</p>
|
||
<el-form-item label="本次已贴面单的箱" required><el-checkbox-group v-model="form.cartonIds"><el-checkbox v-for="row in labelSet?.labels || []" :key="row.cartonId" :value="row.cartonId" :disabled="!!row.appliedAt">{{ cargo.find(box => box.cartonId === row.cartonId)?.cartonNo || '未关联箱' }} · {{ row.appliedAt ? `已贴单 ${dateTime(row.appliedAt)}` : '待贴单' }}</el-checkbox></el-checkbox-group></el-form-item>
|
||
<el-form-item label="实际贴单时间" required><el-date-picker v-model="form.occurredAt" type="datetime" value-format="YYYY-MM-DDTHH:mm:ss" /></el-form-item>
|
||
</template>
|
||
<template v-if="command === 'domestic-repack'">
|
||
<el-alert title="只允许原箱一对一换包装,不改变货物来源和件数。保存后旧国内面单失效,须重新制单并核对国内费用。" type="warning" :closable="false" />
|
||
<el-form-item label="换包装原箱" required><el-select v-model="form.cartonId" placeholder="选择国内可寄原箱" @change="selectCarton"><el-option v-for="box in cargo" :key="box.cartonId" :value="box.cartonId" :label="`${box.cartonNo} · ${box.quantity} 件`" /></el-select></el-form-item>
|
||
<div class="measure-grid"><el-form-item label="新长度(cm)" required><el-input v-model="form.lengthCm" placeholder="最多两位小数" /></el-form-item><el-form-item label="新宽度(cm)" required><el-input v-model="form.widthCm" placeholder="最多两位小数" /></el-form-item><el-form-item label="新高度(cm)" required><el-input v-model="form.heightCm" placeholder="最多两位小数" /></el-form-item><el-form-item label="新毛重(kg)" required><el-input v-model="form.grossWeightKg" placeholder="最多三位小数" /></el-form-item></div>
|
||
</template>
|
||
<template v-if="['overseas-shipment', 'customer-shipment'].includes(command)">
|
||
<el-alert title="仅在货物实际交给承运方后确认。本次将整批交寄全部可寄原箱,不能拆批或重复交寄。" type="warning" :closable="false" />
|
||
<p>面单第 {{ labelSet?.version || '—' }} 版;收件信息:{{ labelSet ? `${labelSet.receiver.name} · ${labelSet.receiver.phone} · ${labelSet.receiver.address}` : '未建立' }}</p>
|
||
<el-form-item label="实际交承运方时间" required><el-date-picker v-model="form.occurredAt" type="datetime" value-format="YYYY-MM-DDTHH:mm:ss" /></el-form-item>
|
||
</template>
|
||
<table class="density-table"><thead><tr><th>原箱</th><th>当前可寄件数</th><th>长 × 宽 × 高(cm)</th><th>毛重(kg)</th></tr></thead><tbody><tr v-for="box in cargo" :key="box.cartonId"><td>{{ box.cartonNo }}</td><td>{{ box.quantity }}</td><td>{{ [box.lengthCm, box.widthCm, box.heightCm].map(value => measurement(value, 2)).join(' × ') }}</td><td>{{ measurement(box.grossWeightKg, 3) }}</td></tr><tr v-if="!cargo.length"><td colspan="4">当前没有可寄货物</td></tr></tbody></table>
|
||
</div>
|
||
</template>
|
||
<style scoped>
|
||
.transport-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--admin-space-3); }
|
||
.label-grid { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1.2fr) minmax(0, 1.8fr); gap: var(--admin-space-3); }
|
||
.measure-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--admin-space-3); }
|
||
.label-row { padding-top: var(--admin-space-3); border-top: 1px solid var(--cc-border); }
|
||
:deep(.el-select), :deep(.el-input-number), :deep(.el-date-editor) { width: 100%; }
|
||
@media (max-width: 760px) { .transport-grid, .label-grid, .measure-grid { grid-template-columns: 1fr; } }
|
||
</style>
|