feat(fleet): integrate trip management and fee coverage workflows

This commit is contained in:
2026-10-03 04:35:55 +08:00
parent bca08f8749
commit dc35288a1b
87 changed files with 3774 additions and 233 deletions
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { physicalWeightLb, totalPhysicalWeightLb } from '../dispatchPhysicalWeight'
import '@/styles/adminDensity.css'
import { computed, reactive, ref, watch } from 'vue'
import { GripVertical, Plus } from '@lucide/vue'
@@ -87,15 +88,14 @@ const assigned = computed(() => assignedIds.value.map((id) => palletSnapshot(id)
const assignedPackages = computed(() => assigned.value.reduce((sum, item) => sum + Number(item.packageCount || 0), 0))
const assignedVolume = computed(() => assigned.value.reduce((sum, item) => sum + Number(item.volumeCbm || 0), 0))
const selectedVehicleSpec = computed(() => dispatchVehicleSpecs.find((item) => item.value === selectedVehicle.value))
function weightKg(item?: DispatchPalletCandidateDto) {
const grossWeightKg = Number(item?.grossWeightKg)
if (Number.isFinite(grossWeightKg) && grossWeightKg > 0) return grossWeightKg
const volumeWeightKg = Number(item?.volumeWeightKg)
return Number.isFinite(volumeWeightKg) && volumeWeightKg > 0 ? volumeWeightKg : 0
const weightLb = (item?: DispatchPalletCandidateDto) => physicalWeightLb(item?.grossWeightKg)
const orderWeightLb = (pallets: DispatchPalletCandidateDto[]) => totalPhysicalWeightLb(pallets)
const containerWeightLb = (container: LoadingContainer) => totalPhysicalWeightLb(container.palletIds.map(id => palletSnapshot(id)))
const formatWeightLb = (weight: number | null) => weight === null ? '待确认' : `${number(weight, 0)}LB`
const containerOverweight = (container: LoadingContainer) => {
const weight = containerWeightLb(container)
return weight !== null && weight > container.maxWeightLb * 1.1
}
const weightLb = (item?: DispatchPalletCandidateDto) => weightKg(item) * 2.2046226218
const orderWeightLb = (pallets: DispatchPalletCandidateDto[]) => pallets.reduce((sum, item) => sum + weightLb(item), 0)
const containerWeightLb = (container: LoadingContainer) => container.palletIds.reduce((sum, id) => sum + weightLb(palletSnapshot(id)), 0)
function palletId(item: DispatchPalletCandidateDto) {
return String(item.planPalletId || item.warehousePalletId || '')
@@ -234,9 +234,13 @@ async function movePallet(item: DispatchPalletCandidateDto, containerId: string)
ElMessage.warning('该装车托盘已达到设置的托数')
return
}
const nextWeight = containerWeightLb(target) + weightLb(item)
if (nextWeight > target.maxWeightLb * 1.1) ElMessage.error(`${target.vehicleLabel}重量将达到 ${nextWeight.toFixed(0)}LB,已超过限重10%,请注意调整`)
else if (nextWeight > target.maxWeightLb) ElMessage.warning(`${target.vehicleLabel}当前重量 ${nextWeight.toFixed(0)}LB,已超过额定限重 ${target.maxWeightLb}LB`)
const currentWeight = containerWeightLb(target), incomingWeight = weightLb(item)
if (currentWeight === null || incomingWeight === null) ElMessage.warning('存在未确认的实际毛重,请在正式配载前补齐;材积重不能用于载重校验')
else {
const nextWeight = currentWeight + incomingWeight
if (nextWeight > target.maxWeightLb * 1.1) ElMessage.error(`${target.vehicleLabel}重量将达到 ${nextWeight.toFixed(0)}LB,已超过限重10%,请注意调整`)
else if (nextWeight > target.maxWeightLb) ElMessage.warning(`${target.vehicleLabel}当前重量 ${nextWeight.toFixed(0)}LB,已超过额定限重 ${target.maxWeightLb}LB`)
}
const anchor = assigned.value[0]
if (anchor?.customerId && anchor.customerId !== item.customerId) {
ElMessage.warning('一次排车只能装同一客户的托盘')
@@ -434,7 +438,7 @@ watch([warehouseTab, () => query.orderType], () => {
><template #default="{ row }">{{ orderType(row.first.orderType) }}</template></el-table-column
>
<el-table-column label="重量(lb)" width="100" align="right"
><template #default="{ row }">{{ number(orderWeightLb(row.pallets), 0) }}LB</template></el-table-column
><template #default="{ row }">{{ formatWeightLb(orderWeightLb(row.pallets)) }}</template></el-table-column
>
<el-table-column label="托盘数量" width="90" align="right"
><template #default="{ row }">{{ row.pallets.length }}</template></el-table-column
@@ -479,7 +483,7 @@ watch([warehouseTab, () => query.orderType], () => {
<GripVertical :size="16" class="drag-handle" />
<div class="pallet-copy">
<strong>{{ text(item.palletNo) }}</strong
><span>{{ Number(item.packageCount || 0) }}箱 · {{ number(weightLb(item), 0) }}LB</span>
><span>{{ Number(item.packageCount || 0) }}箱 · {{ formatWeightLb(weightLb(item)) }}</span>
<div v-if="relabelCartonMarks(item).length" class="carton-marks">
<div v-for="mark in relabelCartonMarks(item)" :key="`relabel-${mark}`" class="carton-mark-line">
<span>{{ mark }}</span
@@ -518,7 +522,7 @@ watch([warehouseTab, () => query.orderType], () => {
:key="container.id"
class="loading-container"
:class="{
'loading-container--overweight': containerWeightLb(container) > container.maxWeightLb * 1.1,
'loading-container--overweight': containerOverweight(container),
}"
@dragover.prevent
@drop.prevent="dropInto($event, container.id)"
@@ -527,7 +531,7 @@ watch([warehouseTab, () => query.orderType], () => {
<strong>{{ container.vehicleLabel }}</strong
><span
>托数 <b>{{ container.palletIds.length }}</b
>/{{ container.capacity }} · 重量 <b>{{ number(containerWeightLb(container), 0) }}LB</b>/{{ container.maxWeightLb }}LB <em v-if="containerWeightLb(container) > container.maxWeightLb * 1.1">超限10%</em></span
>/{{ container.capacity }} · 重量 <b>{{ formatWeightLb(containerWeightLb(container)) }}</b>/{{ container.maxWeightLb }}LB <em v-if="containerOverweight(container)">超限10%</em></span
><el-button class="density-action" data-tone="danger" :aria-label="`删除装车车型${index + 1}`" @click="deleteContainer(container)">删除</el-button>
</div>
<div class="container-body">