feat(fleet): show vehicle delivery and reassignment records

This commit is contained in:
2026-10-03 10:12:55 +08:00
parent 94b8b8b31c
commit f7b84ea887
9 changed files with 209 additions and 6 deletions
@@ -37,5 +37,15 @@ describe('overseas master data real page mounts', () => {
expect(wrapper.findComponent({ name: 'LoadErrorState' }).exists()).toBe(true)
})
it('mounts API-backed vehicle detail without fabricating fulfillment history', async () => { const wrapper = mountView(VehicleDetailView); await flushPromises(); expect(wrapper.get('.density-detail-title').text()).toBe('CA-TEST'); expect(wrapper.get('.density-fields').findAll('dt')).toHaveLength(14); expect(wrapper.get('.density-fields').text()).toContain('在役'); expect(wrapper.text()).not.toContain('IN_SERVICE'); expect(wrapper.text()).toContain('派送记录请在海外仓的排车管理或派送管理中查看') })
it('mounts vehicle detail and scopes both real fulfillment projections to the loaded vehicle', async () => {
const wrapper = mountView(VehicleDetailView); await flushPromises()
expect(wrapper.get('.density-detail-title').text()).toBe('CA-TEST')
expect(wrapper.get('.density-fields').findAll('dt')).toHaveLength(14)
expect(wrapper.get('.density-fields').text()).toContain('在役')
expect(wrapper.text()).not.toContain('IN_SERVICE')
const tables = wrapper.findAllComponents({ name: 'VehicleFulfillmentTable' })
expect(tables.map(table => table.props())).toEqual([
{ vehicleId: 'VH-TEST-001', kind: 'deliveries' }, { vehicleId: 'VH-TEST-001', kind: 'changes' },
])
})
})
@@ -76,8 +76,9 @@ describe('overseas master data real contract pages', () => {
expect(detail).toContain('派送订单明细')
expect(detail).toContain('派送更换记录')
expect(detail).toContain('getVehicle(')
expect(detail).toContain('派送记录请在海外仓的排车管理或派送管理中查看')
expect(detail).toContain('车辆更换记录尚未接入')
expect(detail).toContain(':vehicle-id="detail.id" kind="deliveries"')
expect(detail).toContain(':vehicle-id="detail.id" kind="changes"')
expect(detail).not.toContain('车辆更换记录尚未接入')
expect(detail).not.toContain('AppDrawer')
expect(detail).not.toContain('const vehicle =')
})
@@ -2,6 +2,7 @@
import '@/styles/adminDensity.css'
import { onBeforeUnmount, ref, watch } from 'vue'
import VehicleCareTable from '../components/VehicleCareTable.vue'
import VehicleFulfillmentTable from '../components/VehicleFulfillmentTable.vue'
import type { VehicleCareType } from '../vehicleCareTypes'
import StatusBadge from '@/shared/components/StatusBadge.vue'
import { vehicleStatusLabels } from '../presentation'
@@ -17,5 +18,5 @@ function back(){void router.push({name:'overseas-master-data-vehicles'})}
watch(() => route.params.vehicleId, () => { activeTab.value='overview';void load() }, { immediate:true })
onBeforeUnmount(() => { request++ })
</script>
<template><AdminPage class="admin-density" ><DetailPageLayout class="density-detail-layout surface-panel" aria-label="车辆详情"><template #header><div class="density-detail-header"><div class="density-detail-heading"><el-button link class="density-back" @click="back"><ArrowLeft :size="16" />返回列表</el-button><h1 class="density-detail-title">{{ detail?.plateNumber || '—' }}</h1><StatusBadge v-if="detail" :status="vehicleStatusLabels[detail.status]" /></div></div></template><LoadErrorState v-if="error" title="车辆详情加载失败" :message="error.message" @retry="load"/><section v-loading="loading" class="detail-surface"><el-tabs v-if="detail" v-model="activeTab"><el-tab-pane label="车辆概览" name="overview" /><el-tab-pane label="保养及加油" name="care" /><el-tab-pane label="维修记录" name="REPAIR" /><el-tab-pane label="紧急故障" name="BREAKDOWN" /><el-tab-pane label="应急救援" name="RESCUE" /><el-tab-pane label="异常管理" name="EXCEPTION" /></el-tabs><template v-if="activeTab === 'overview'"><FormSection class="density-form-section" title="车辆信息"><dl v-if="detail" class="detail-grid density-fields"><div v-for="item in [['车牌号',detail.plateNumber],['车型',detail.model],['最大标准托位',detail.maxPalletSpaces??'待确认'],['最大载重(kg)',detail.maxLoadKg??'待确认'],['可用容积(m³)',detail.maxVolumeCbm??'待确认'],['油耗(L/100km)',detail.fuelConsumptionPer100Km],['当前公里码(km)',detail.mileageKm],['司机 / 外派单位',detail.driverOrDispatchCompany||'—'],['联系电话',detail.phone||'—'],['区域',detail.region==='OVERSEAS'?'海外':'国内'],['车辆归属',detail.ownership==='OWNED'?'自有车辆':'外派车辆'],['状态',vehicleStatusLabels[detail.status]],['更新时间',detail.updatedAt],['备注',detail.remark||'—']]" :key="item[0]" :class="{ 'wide-field': ['司机 / 外派单位', '备注'].includes(String(item[0])) }"><dt>{{item[0]}}</dt><dd>{{item[1]}}</dd></div></dl></FormSection><FormSection class="density-form-section" title="派送订单明细"><p class="contract-note">派送记录请在海外仓的排车管理或派送管理中查看。</p></FormSection><FormSection class="density-form-section" title="派送更换记录" :bordered="false"><p class="contract-note">车辆更换记录尚未接入。</p></FormSection></template><div v-if="detail && activeTab === 'care'" :key="detail.id" class="care-grid"><VehicleCareTable :vehicle-id="detail.id" :plate="detail.plateNumber" record-type="MAINTENANCE" /><VehicleCareTable :vehicle-id="detail.id" :plate="detail.plateNumber" record-type="FUEL" /></div><VehicleCareTable v-if="detail && ['REPAIR','BREAKDOWN','RESCUE','EXCEPTION'].includes(activeTab)" :key="`${detail.id}:${activeTab}`" :vehicle-id="detail.id" :plate="detail.plateNumber" :record-type="activeTab as VehicleCareType" /></section></DetailPageLayout></AdminPage></template>
<style scoped>.care-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--admin-space-6)}.detail-grid .wide-field { grid-column: span 2; }.contract-note{margin:0;padding:var(--admin-space-6);color:var(--cc-muted);text-align:center}</style>
<template><AdminPage class="admin-density" ><DetailPageLayout class="density-detail-layout surface-panel" aria-label="车辆详情"><template #header><div class="density-detail-header"><div class="density-detail-heading"><el-button link class="density-back" @click="back"><ArrowLeft :size="16" />返回列表</el-button><h1 class="density-detail-title">{{ detail?.plateNumber || '—' }}</h1><StatusBadge v-if="detail" :status="vehicleStatusLabels[detail.status]" /></div></div></template><LoadErrorState v-if="error" title="车辆详情加载失败" :message="error.message" @retry="load"/><section v-loading="loading" class="detail-surface"><el-tabs v-if="detail" v-model="activeTab"><el-tab-pane label="车辆概览" name="overview" /><el-tab-pane label="保养及加油" name="care" /><el-tab-pane label="维修记录" name="REPAIR" /><el-tab-pane label="紧急故障" name="BREAKDOWN" /><el-tab-pane label="应急救援" name="RESCUE" /><el-tab-pane label="异常管理" name="EXCEPTION" /></el-tabs><template v-if="activeTab === 'overview'"><FormSection class="density-form-section" title="车辆信息"><dl v-if="detail" class="detail-grid density-fields"><div v-for="item in [['车牌号',detail.plateNumber],['车型',detail.model],['最大标准托位',detail.maxPalletSpaces??'待确认'],['最大载重(kg)',detail.maxLoadKg??'待确认'],['可用容积(m³)',detail.maxVolumeCbm??'待确认'],['油耗(L/100km)',detail.fuelConsumptionPer100Km],['当前公里码(km)',detail.mileageKm],['司机 / 外派单位',detail.driverOrDispatchCompany||'—'],['联系电话',detail.phone||'—'],['区域',detail.region==='OVERSEAS'?'海外':'国内'],['车辆归属',detail.ownership==='OWNED'?'自有车辆':'外派车辆'],['状态',vehicleStatusLabels[detail.status]],['更新时间',detail.updatedAt],['备注',detail.remark||'—']]" :key="item[0]" :class="{ 'wide-field': ['司机 / 外派单位', '备注'].includes(String(item[0])) }"><dt>{{item[0]}}</dt><dd>{{item[1]}}</dd></div></dl></FormSection><FormSection class="density-form-section" title="派送订单明细"><VehicleFulfillmentTable v-if="detail" :vehicle-id="detail.id" kind="deliveries" /></FormSection><FormSection class="density-form-section" title="派送更换记录" :bordered="false"><VehicleFulfillmentTable v-if="detail" :vehicle-id="detail.id" kind="changes" /></FormSection></template><div v-if="detail && activeTab === 'care'" :key="detail.id" class="care-grid"><VehicleCareTable :vehicle-id="detail.id" :plate="detail.plateNumber" record-type="MAINTENANCE" /><VehicleCareTable :vehicle-id="detail.id" :plate="detail.plateNumber" record-type="FUEL" /></div><VehicleCareTable v-if="detail && ['REPAIR','BREAKDOWN','RESCUE','EXCEPTION'].includes(activeTab)" :key="`${detail.id}:${activeTab}`" :vehicle-id="detail.id" :plate="detail.plateNumber" :record-type="activeTab as VehicleCareType" /></section></DetailPageLayout></AdminPage></template>
<style scoped>.care-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--admin-space-6)}.detail-grid .wide-field { grid-column: span 2; }</style>