Files
tms-erp-web/src/views/transportCapacity/components/vehicle-ledger.vue
T
gxwebsoft 21b7877ff1 feat(business-crud-page): 统一独立表单页顶部页面标题样式及展示
- 独立表单页 shipping-template、transport-plan、waybill-manage 加入统一的 archive-page-form__title 页面标题支持
- 全局样式抽离 archive-page-form__title 至 element-ui.scss,实现统一样式和竖条修饰
- loading-manage/form 页面新增页标题展示,保持风格一致
- master-order 编辑模式下新增页面标题支持,动态显示编辑或新增总单
- business-crud-page 组件新增 formPageTitle 属性,支持父级传递页面标题数据
- 优化多个业务页面表格和弹窗样式,调整列宽及边框圆角阴影,提高视觉一致性
- 删除 customer-archive.vue 中重复本地标题样式定义,使用全局统一样式
- 全站弹窗分组组件 section-card 相关设计规范文档更新,强化统一卡片风格
- 移除 cargo-type.vue 添加 "新建" 按钮逻辑,调整按钮显示权限
- 统一所有新增弹窗的底部操作区浮动效果及内容区最大高度限制,提升交互体验
2026-08-21 11:07:32 +08:00

422 lines
12 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">
<span>{{ item.label }}</span>
<el-image
v-if="vehicleDetail[item.prop]"
:src="vehicleDetail[item.prop]"
:preview-src-list="imageUrls"
preview-teleported
fit="cover"
/>
<el-empty v-else :image-size="36" description="暂无图片" />
</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-tabs>
<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>
</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() {
return [
['行驶证主页面', 'drivingLicenseImage'],
['行驶证主页反页', 'drivingLicenseMainBack'],
['行驶证副页正页', 'drivingLicenseViceFront'],
['行驶证副页反页', 'drivingLicenseViceBack'],
['道路运输证', 'roadTransportCertImage'],
].map(([label, prop]) => ({ label, prop }));
},
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;
}
.vehicle-ledger__pagination {
display: flex;
justify-content: flex-end;
margin-top: 16px;
}
</style>