Files
admin-web/src/modules/overseas-business/components/ProcurementTransportFields.vue
T
2026-10-20 14:52:06 +08:00

62 lines
8.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>