Files
tms-erp-web/src/views/transportCapacity/components/vehicle-ledger.vue
T
2026-08-26 23:18:14 +08:00

433 lines
13 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.
<template>
<el-dialog
:model-value="modelValue"
title="车辆综合台账"
width="96%"
top="3vh"
append-to-body
destroy-on-close
@update:model-value="$emit('update:modelValue', $event)"
>
<div v-loading="detailLoading" class="vehicle-ledger">
<section-card class="vehicle-ledger__overview">
<div class="vehicle-ledger__title">
<span>{{ vehicleDetail.plateNo || vehicle.plateNo }}</span>
<el-tag :type="plateColorType">{{ vehicleDetail.plateColor || '-' }}</el-tag>
<el-tag type="primary">{{ vehicleDetail.businessRelation || '-' }}</el-tag>
</div>
<el-descriptions :column="4" border>
<el-descriptions-item label="所属组织">{{
vehicleDetail.organizationName || '-'
}}</el-descriptions-item>
<el-descriptions-item label="车辆类型">{{
vehicleDetail.vehicleType || '-'
}}</el-descriptions-item>
<el-descriptions-item label="能源类型">{{
vehicleDetail.energyType || '-'
}}</el-descriptions-item>
<el-descriptions-item label="外廓尺寸(mm">{{ dimensions }}</el-descriptions-item>
<el-descriptions-item label="核定载质量(KG">{{
vehicleDetail.approvedLoadKg ?? '-'
}}</el-descriptions-item>
<el-descriptions-item label="准牵引总质量(KG">{{
vehicleDetail.tractionMassKg ?? '-'
}}</el-descriptions-item>
<el-descriptions-item label="行驶证档案编号">{{
vehicleDetail.drivingLicenseNo || '-'
}}</el-descriptions-item>
<el-descriptions-item label="道路运输证号">{{
vehicleDetail.roadTransportCertNo || '-'
}}</el-descriptions-item>
<el-descriptions-item label="行驶证有效期">{{
vehicleDetail.drivingLicenseEndDate || '-'
}}</el-descriptions-item>
<el-descriptions-item label="道路运输证有效期">{{
vehicleDetail.roadTransportCertEndDate || '-'
}}</el-descriptions-item>
<el-descriptions-item label="道路运输证年审有效期">{{
vehicleDetail.annualReviewEndDate || '-'
}}</el-descriptions-item>
</el-descriptions>
<div class="vehicle-ledger__images">
<div v-for="item in imageFields" :key="item.prop" class="vehicle-ledger__image-item">
<el-image
v-if="vehicleDetail[item.prop]"
:src="vehicleDetail[item.prop]"
:preview-src-list="imageUrls"
:initial-index="item.previewIndex"
preview-teleported
fit="cover"
/>
<el-empty v-else :image-size="36" description="暂无图片" />
<span>{{ item.label }}</span>
</div>
</div>
</section-card>
<el-tabs type="border-card" v-model="activeTab" class="vehicle-ledger__tabs" @tab-change="loadRecords">
<el-tab-pane v-for="tab in tabs" :key="tab.name" :label="tab.label" :name="tab.name">
<el-table v-loading="tableLoading" :data="records" border stripe>
<el-table-column type="index" label="序号" width="70" align="center" />
<el-table-column
v-for="column in activeColumns"
:key="column.prop"
:prop="column.prop"
:label="column.label"
:min-width="column.width || 140"
show-overflow-tooltip
/>
</el-table>
<div class="vehicle-ledger__pagination">
<el-pagination
v-model:current-page="page.current"
v-model:page-size="page.size"
:page-sizes="[10, 20, 50]"
:total="page.total"
layout="total, sizes, prev, pager, next"
@size-change="handlePageChange"
@current-change="loadRecords"
/>
</div>
</el-tab-pane>
</el-tabs>
</div>
</el-dialog>
</template>
<script>
import { getDetail } from '@/api/transportCapacity/transport-vehicle';
import { getList as getInsuranceList } from '@/api/vehicle/insurance-record';
import { getList as getViolationList } from '@/api/vehicle/violation-record';
import { getList as getMaintenanceList } from '@/api/vehicle/maintenance-record';
import { getList as getMaintenancePlanList } from '@/api/vehicle/maintenance-plan';
import { getList as getTireList } from '@/api/vehicle/tire-replacement-record';
import { getList as getAccidentList } from '@/api/vehicle/accident-record';
import { getList as getAnnualInspectionList } from '@/api/vehicle/annual-inspection-record';
import { getList as getMileageList } from '@/api/vehicle/mileage-record';
import { getList as getChangeList } from '@/api/vehicle/transport-change-record';
import { getList as getOilElectricList } from '@/api/vehicle/oil-electric-record';
import { getList as getEtcList } from '@/api/vehicle/etc-record';
import { getList as getOtherExpenseList } from '@/api/vehicle/other-expense-record';
import SectionCard from '@/components/section-card/main.vue';
const cols = (...items) => items.map(([label, prop, width]) => ({ label, prop, width }));
const tabConfigs = [
[
'insurance',
'保险记录',
getInsuranceList,
cols(
['车牌号', 'vehicleNo'],
['保险类型', 'insuranceType'],
['开始日期', 'startDate'],
['结束日期', 'endDate'],
['保费', 'premium'],
['保单号', 'policyNo']
),
],
[
'violation',
'违章记录',
getViolationList,
cols(
['车牌号', 'vehicleNo'],
['驾驶人', 'driverName'],
['类型', 'violationType'],
['事项', 'violationItem'],
['违章时间', 'violationTime'],
['罚款金额', 'fineAmount']
),
],
[
'maintenance',
'维修记录',
getMaintenanceList,
cols(
['车牌号', 'vehicleNo'],
['维修人', 'maintainer'],
['维修时间', 'maintenanceTime'],
['维修位置', 'location'],
['费用', 'cost'],
['维修单位', 'company']
),
],
[
'maintenancePlan',
'保养记录',
getMaintenancePlanList,
cols(
['车牌号', 'vehicleNo'],
['保养人', 'maintainer'],
['保养时间', 'maintenanceTime'],
['保养项目', 'maintenanceItem'],
['费用', 'cost'],
['下次保养时间', 'nextMaintenanceTime']
),
],
[
'tire',
'换胎记录',
getTireList,
cols(
['车牌号', 'vehicleNo'],
['更换时间', 'replacementTime'],
['轮胎品牌', 'tireBrand'],
['轮胎规格', 'tireSpec'],
['费用', 'cost']
),
],
[
'accident',
'事故记录',
getAccidentList,
cols(
['车牌号', 'vehicleNo'],
['事故时间', 'accidentTime'],
['事故地点', 'accidentLocation'],
['事故类型', 'accidentType'],
['损失金额', 'lossAmount']
),
],
[
'annualInspection',
'年检记录',
getAnnualInspectionList,
cols(
['车牌号', 'vehicleNo'],
['年检日期', 'inspectionDate'],
['年检有效期至', 'inspectionEndDate'],
['年检机构', 'inspectionOrganization'],
['费用', 'cost']
),
],
[
'mileage',
'里程记录',
getMileageList,
cols(
['车牌号', 'vehicleNo'],
['记录时间', 'recordTime'],
['里程数', 'mileage'],
['里程单位', 'mileageUnit'],
['备注', 'remark']
),
],
[
'change',
'变更记录',
getChangeList,
cols(
['车牌号', 'vehicleNo'],
['变更类型', 'changeType'],
['变更时间', 'changeTime'],
['变更前内容', 'beforeChange'],
['变更后内容', 'afterChange']
),
],
[
'equipment',
'设备台账',
null,
cols(
['设备编码', 'equipmentCode'],
['设备名称', 'equipmentName'],
['设备类型', 'equipmentType'],
['安装日期', 'installDate'],
['状态', 'status']
),
],
[
'oilElectric',
'油电台账',
getOilElectricList,
cols(
['车牌号', 'vehicleNo'],
['加油/充电日期', 'recordDate'],
['类型', 'energyType'],
['数量', 'quantity'],
['金额', 'amount']
),
],
[
'etc',
'ETC记录',
getEtcList,
cols(
['车牌号', 'vehicleNo'],
['交易日期', 'transactionDate'],
['交易金额', 'amount'],
['交易地点', 'location'],
['ETC卡号', 'etcCardNo']
),
],
[
'otherExpense',
'其他费用记录',
getOtherExpenseList,
cols(
['车牌号', 'vehicleNo'],
['费用日期', 'expenseDate'],
['费用类型', 'expenseType'],
['金额', 'amount'],
['备注', 'remark']
),
],
].map(([name, label, request, columns]) => ({ name, label, request, columns }));
export default {
components: { SectionCard },
props: { modelValue: Boolean, vehicle: { type: Object, default: () => ({}) } },
emits: ['update:modelValue'],
data() {
return {
detailLoading: false,
tableLoading: false,
vehicleDetail: {},
activeTab: 'insurance',
records: [],
page: { current: 1, size: 10, total: 0 },
};
},
computed: {
tabs() {
return tabConfigs;
},
activeConfig() {
return tabConfigs.find(item => item.name === this.activeTab) || tabConfigs[0];
},
activeColumns() {
return this.activeConfig.columns;
},
dimensions() {
const v = this.vehicleDetail;
return (
[v.outerLength, v.outerWidth, v.outerHeight]
.filter(item => item !== null && item !== undefined && item !== '')
.join('×') || '-'
);
},
plateColorType() {
return (
{ 黄牌: 'warning', 蓝牌: 'primary', 绿牌: 'success' }[this.vehicleDetail.plateColor] ||
'info'
);
},
imageFields() {
let previewIndex = 0;
return [
['行驶证主页面', 'drivingLicenseImage'],
['行驶证主页反页', 'drivingLicenseMainBack'],
['行驶证副页正页', 'drivingLicenseViceFront'],
['行驶证副页反页', 'drivingLicenseViceBack'],
['道路运输证', 'roadTransportCertImage'],
].map(([label, prop]) => {
const item = { label, prop, previewIndex };
if (this.vehicleDetail[prop]) previewIndex += 1;
return item;
});
},
imageUrls() {
return this.imageFields.map(item => this.vehicleDetail[item.prop]).filter(Boolean);
},
},
watch: {
modelValue(value) {
if (value) this.initialize();
},
},
methods: {
async initialize() {
this.activeTab = 'insurance';
this.page.current = 1;
this.vehicleDetail = { ...this.vehicle };
if (this.vehicle.id) {
this.detailLoading = true;
try {
const res = await getDetail(this.vehicle.id);
this.vehicleDetail = { ...this.vehicle, ...(res.data.data || {}) };
} finally {
this.detailLoading = false;
}
}
this.loadRecords();
},
async loadRecords() {
const { request } = this.activeConfig;
if (!request) {
this.records = [];
this.page.total = 0;
return;
}
this.tableLoading = true;
try {
const res = await request(this.page.current, this.page.size, {
vehicleNo: this.vehicleDetail.plateNo || this.vehicle.plateNo,
vehicleType: '车辆',
});
const data = res.data.data || {};
this.records = data.records || [];
this.page.total = data.total || 0;
} finally {
this.tableLoading = false;
}
},
handlePageChange() {
this.page.current = 1;
this.loadRecords();
},
},
};
</script>
<style lang="scss" scoped>
.vehicle-ledger__overview {
padding: 16px;
border: 1px solid #eff1f7;
}
.vehicle-ledger__title {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
font-size: 26px;
font-weight: 600;
}
.vehicle-ledger__images {
display: flex;
gap: 16px;
margin-top: 16px;
overflow-x: auto;
}
.vehicle-ledger__image-item {
width: 150px;
flex: 0 0 150px;
color: #606266;
text-align: center;
}
.vehicle-ledger__image-item > span {
display: block;
margin-bottom: 8px;
}
.vehicle-ledger__image-item :deep(.el-image) {
width: 150px;
height: 110px;
border: 1px solid #eff1f7;
}
.vehicle-ledger__image-item :deep(.el-empty) {
height: 110px;
border: 1px solid #eff1f7;
}
.vehicle-ledger__tabs {
margin-top: 16px;
:deep(.el-tabs__content) {
padding: 8px;
}
}
.vehicle-ledger__pagination {
display: flex;
justify-content: flex-end;
margin-top: 16px;
}
</style>