You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

890 lines
21 KiB

<template>
<basic-container>
<div class="main" v-loading="details.loadingObj.pageLoading">
<!-- 车辆基本信息 -->
<div class="pageTitle">
<div>车辆基本信息</div>
</div>
<el-form inline class="mt20 pl20" ref="formRef" :model="details.form">
<el-form-item
v-for="item in details.carBasicForm"
:label="item.label"
label-width="160px"
:class="item.type !== 5 ? 'w20' : 'w100'"
:rules="item.rules"
:prop="item.prop"
>
<!-- 普通输入框 -->
<template v-if="item.type === 1">
<el-input
class="w100"
:placeholder="`请输入${item.label}`"
v-model="details.form[item.prop]"
clearable
></el-input>
</template>
<!-- 数字输入框 -->
<template v-else-if="item.type === 2">
<el-input-number
:controls="false"
v-model="details.form[item.prop]"
:placeholder="`请输入${item.label}`"
:min="item.min || 0"
:value-on-clear="0"
:precision="item.precision || 0"
class="w100"
:disabled="item.disabled || false"
></el-input-number>
</template>
<!-- 下拉框 -->
<template v-else-if="item.type === 3">
<el-select
v-model="details.form[item.prop]"
:placeholder="`请选择${item.label}`"
class="w100"
clearable
filterable
@change="value => item.change && item.change(value)"
:multiple="item.multiple || false"
>
<el-option
v-for="val in item.checkarr"
:key="val.value"
:label="val.label"
:value="val.value"
/>
</el-select>
</template>
<!-- 时间选择 -->
<template v-else-if="item.type === 4">
<el-date-picker
v-model="details.form[item.prop]"
type="date"
:placeholder="`请选择${item.label}`"
class="w100"
:default-value="new Date()"
clearable
/>
</template>
<!-- 备注 -->
<template v-else-if="item.type === 5">
<el-input
type="textarea"
v-model="details.form[item.prop]"
clearable
:placeholder="`请选择${item.label}`"
class="w100"
/>
</template>
</el-form-item>
</el-form>
<!-- 相关图片 -->
<div class="pageTitle">
<div>相关图片</div>
</div>
<!-- 图片类型 -->
<div class="mt20 pl20 imgContainer">
<div v-for="item in details.imgArr" :key="item.label" class="imgItem">
<!-- 上传组件 -->
<el-upload
v-model:file-list="item.imgList"
list-type="picture"
:action="doubledCount"
:before-upload="beforeAvatarUpload"
:on-success="res => handleAvatarSuccess(res, item)"
:headers="headers"
multiple
:show-file-list="false"
>
<template #default>
<div class="pageTitle title mb20">
<span class="mr20" @click.stop="() => {}">
{{ item.label }}
</span>
<el-button type="primary" icon="CirclePlus"> 添 加 </el-button>
<el-button icon="Delete" @click.stop="() => handleEmpty(item)"> 清 空 </el-button>
</div>
</template>
</el-upload>
<div class="imgRow">
<div v-for="(value, index) in item.imgList" :key="value.url">
<el-image
class="img"
:src="value.url"
v-loading="!value.imgUrl"
:zoom-rate="1.2"
:max-scale="7"
:min-scale="0.2"
:preview-src-list="item.imgList.map(val => val.imgUrl)"
:initial-index="index"
fit="cover"
/>
</div>
</div>
</div>
</div>
<!-- 底部控件 -->
<div class="footer_container">
<el-button icon="CircleClose"> 关 闭 </el-button>
<el-button type="primary" icon="Position" @click="handleSubmit"> 提 交 </el-button>
</div>
</div>
</basic-container>
</template>
<script setup lang="ts">
import { ref, reactive, computed, nextTick } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { compressImageBlob } from '@/components/IMGcompressor/imgcompressor.js';
import { getToken } from '@/utils/auth';
import { getDictionaryBiz } from '@/api/system/dict';
import { deepClone, debounce, getObjType, isNumber } from '@/utils/util';
import { add, getDictionary, getDetail, update } from '@/api/basicdata/basicdataVehicle';
import { getList } from '@/api/basicdata/basicdataVehicleInfo';
import { getOwn } from '@/api/basicdata/basicdataDriverArtery';
import { useRoute, uesRouter } from 'vue-router';
const details = reactive({
carBasicForm: [
{
label: '车牌号',
prop: 'vehicleNub',
type: 1,
checkarr: [],
rules: [
{
required: true,
message: '请输入车牌号',
trigger: ['blur', 'change'],
},
],
},
{
label: '车辆所属人',
prop: 'vehicleOwners',
type: 3,
multiple: true,
checkarr: [],
},
{
label: '车辆来源',
prop: 'vehicleSource',
type: 1,
checkarr: [],
},
{
label: '是否车头',
prop: 'isHead',
type: 3,
checkarr: [
{
label: '',
value: '1',
},
{
label: '',
value: '0',
},
],
},
{
label: '挂车类型',
prop: 'trailerType',
type: 3,
checkarr: [],
},
{
label: '车辆类型',
prop: 'vehicleModel',
type: 3,
checkarr: [],
change(value) {
console.log('value :>> ', value);
console.log('this :>> ', this);
const { vehicleCommander, vehicleHeight, approvedVolume, vehicleQuality, curbWeight } =
this.checkarr.find(val => val.value === value) || {};
details.form.vehicleCommander = isNumber(vehicleCommander) ? Number(vehicleCommander) : 0;
details.form.vehicleHeight = isNumber(vehicleHeight) ? Number(vehicleHeight) : 0;
details.form.approvedVolume = isNumber(approvedVolume) ? Number(approvedVolume) : 0;
details.form.vehicleQuality = isNumber(vehicleQuality) ? Number(vehicleQuality) : 0;
details.form.curbWeight = isNumber(curbWeight) ? Number(curbWeight) : 0;
},
},
{
label: '车厢类型',
prop: 'carType',
type: 3,
checkarr: [],
},
{
label: '车长(M)',
prop: 'vehicleCommander',
type: 2,
checkarr: [],
precision: 2,
disabled: true,
},
{
label: '外廓高(M)',
prop: 'vehicleHeight',
type: 2,
checkarr: [],
precision: 2,
disabled: true,
},
{
label: '付款方式',
prop: 'paymentMethod',
type: 3,
checkarr: [],
},
{
label: '核定体积',
prop: 'approvedVolume',
type: 2,
checkarr: [],
precision: 2,
disabled: true,
},
{
label: '车牌颜色',
prop: 'licensePlateColor',
type: 3,
checkarr: [],
},
{
label: '车身颜色',
prop: 'vehicleColor',
type: 3,
checkarr: [],
},
{
label: '能源类型',
prop: 'energyType',
type: 3,
checkarr: [],
},
{
label: '车牌类型',
prop: 'licensePlateType',
type: 3,
checkarr: [],
},
{
label: '品牌型号',
prop: 'vehicleBrand',
type: 3,
checkarr: [],
},
{
label: '车辆代号',
prop: 'vehicleCode',
type: 1,
checkarr: [],
},
{
label: '发动机型号',
prop: 'engineCode',
type: 1,
checkarr: [],
},
{
label: '车辆总质量(T)',
prop: 'vehicleQuality',
type: 2,
checkarr: [],
precision: 2,
disabled: true,
},
{
label: '整备质量(T)',
prop: 'curbWeight',
type: 2,
checkarr: [],
precision: 2,
disabled: true,
},
{
label: '载荷质量(T)',
prop: 'loadMass',
type: 2,
checkarr: [],
precision: 2,
},
{
label: '外廓宽(M)',
prop: 'outerWidth',
type: 2,
checkarr: [],
precision: 2,
},
{
label: '到期时间',
prop: 'expirationTime',
type: 4,
checkarr: [],
},
{
label: '道路运输证号',
prop: 'roadTransport',
type: 1,
checkarr: [],
},
{
label: '经营许可证号',
prop: 'businessLicense',
type: 1,
checkarr: [],
},
{
label: '车辆所属单位',
prop: 'vehicleUnit',
type: 1,
checkarr: [],
},
{
label: '车辆所属单位电话',
prop: 'vehicleUnitPhone',
type: 1,
checkarr: [],
},
{
label: '车辆所属人手机号',
prop: 'vehicleOwnerPhone',
type: 1,
checkarr: [],
},
{
label: '车辆所属人身份证号',
prop: 'vehicleOwnerCard',
type: 1,
checkarr: [],
},
{
label: '承运商',
prop: 'carrierId',
type: 3,
checkarr: [],
rules: [
{
required: true,
message: '请选择承运商',
trigger: ['blur', 'change'],
},
],
},
{
label: '车辆年审时间',
prop: 'reviewTime',
type: 4,
checkarr: [],
},
{
label: '车辆年审有效期',
prop: 'reviewValidity',
type: 4,
checkarr: [],
},
{
label: '车辆保险开始时间',
prop: 'insuranceStartTime',
type: 4,
checkarr: [],
},
{
label: '车辆保险结束时间',
prop: 'insuranceEndTime',
type: 4,
checkarr: [],
},
{
label: '有无车身广告',
prop: 'bodyAdvertising',
type: 3,
checkarr: [
{
label: '',
value: '1',
},
{
label: '',
value: '0',
},
],
},
{
label: '车身广告更新时间',
prop: 'advertisementsNewTimes',
type: 4,
checkarr: [],
},
{
label: '是否有GPS',
prop: 'withGps',
type: 3,
checkarr: [
{
label: '',
value: '1',
},
{
label: '',
value: '0',
},
],
},
{
label: 'GPS服务商',
prop: 'gpsServiceProvider',
type: 1,
checkarr: [],
},
{
label: 'GPS型号',
prop: 'gpsModel',
type: 1,
checkarr: [],
},
{
label: '备注',
prop: 'notes',
type: 5,
checkarr: [],
},
],
imgArr: [
{ label: '行驶证正面照片', imgList: [], prop: 'drivingLicensePhoto' },
{ label: '行驶证反面照片', imgList: [], prop: 'drivingLicensePhotoBack' },
{ label: '许可证照片', imgList: [], prop: 'licensePhoto' },
{ label: '车辆照片(最新)', imgList: [], prop: 'vehiclePhoto' },
{ label: '车尾照片', imgList: [], prop: 'vehicleRearPhoto' },
{ label: '道理运输照片', imgList: [], prop: 'roadTransportPhoto' },
{ label: '人车合影照片', imgList: [], prop: 'vehiclePeoplePhoto' },
{ label: '保险卡照片', imgList: [], prop: 'insuranceCardPhoto' },
],
form: {},
// loading
loadingObj: {
/** 页面 */
pageLoading: false,
},
pageInfo: {
type: 'add' as 'add' | 'edit' | 'view',
id: '',
},
});
// 组件实例
const formRef = ref();
// router
const $router = useRouter();
const $route = useRoute();
// 处理数据
const handleData = (key, res) => {
const { code, data } = res.data;
if (code !== 200) return;
for (let i = 0; i < details.carBasicForm.length; i++) {
const value = details.carBasicForm[i];
if (value.label === key)
return (value.checkarr =
getObjType(data) === 'array'
? data.map(val => {
val.label = val.dictValue;
val.value = val.dictKey;
return val;
})
: []);
}
};
// 请求下拉框码值
const initData = async () => {
// 请求车辆类型
const handleCarModel = async () => {
const [res1, res2] = await Promise.all([getList(), getDictionaryBiz('basic_vehicle_model')]);
const { code: code1, data: data1 } = res1.data;
const { code: code2, data: data2 } = res2.data;
if (
code1 !== 200 ||
code2 !== 200 ||
getObjType(data1) !== 'array' ||
getObjType(data2) !== 'array'
)
return;
// 处理数据
for (let i = 0; i < data1.length; i++) {
const value = data1[i];
for (let j = 0; j < data2.length; j++) {
const item = data2[j];
if (value.vehicleModel !== item.dictKey) continue;
value.label = item.dictValue;
value.value = item.dictKey;
break;
}
}
// 赋值
for (let i = 0; i < details.carBasicForm.length; i++) {
const value = details.carBasicForm[i];
if (value.label !== '车辆类型') continue;
value.checkarr = data1;
break;
}
};
// 并发请求
await Promise.all([
// 车辆来源
getDictionaryBiz('basic_vehicle_source').then(res => handleData('车辆来源', res)),
// 是否车头
getDictionaryBiz('yes_no').then(res => handleData('是否车头', res)),
// 挂车类型
getDictionaryBiz('basic_trailer_type').then(res => handleData('挂车类型', res)),
// 车厢类型
getDictionaryBiz('basic_car_type').then(res => handleData('车厢类型', res)),
// 付款方式
getDictionaryBiz('basicdata_vehicle_paymentmethod').then(res => handleData('付款方式', res)),
// 车牌颜色
getDictionaryBiz('basic_plate_color').then(res => handleData('车牌颜色', res)),
// 车身颜色
getDictionaryBiz('basic_vehicle_color').then(res => handleData('车身颜色', res)),
// 能源类型
getDictionaryBiz('basic_energy_type').then(res => handleData('能源类型', res)),
// 车牌类型
getDictionaryBiz('basic_plate_type').then(res => handleData('车牌类型', res)),
// 车辆类型
handleCarModel(),
// 承运商
getDictionary().then(res => {
const { code, data } = res.data;
if (code !== 200) return;
for (let i = 0; i < details.carBasicForm.length; i++) {
const value = details.carBasicForm[i];
if (value.label === '承运商')
return (value.checkarr =
getObjType(data) === 'array'
? data.map(val => {
val.label = val.carrierName;
val.value = val.id;
return val;
})
: []);
}
}),
// 驾驶人
getOwn().then(res => {
const { code, data } = res.data;
if (code !== 200) return;
for (let i = 0; i < details.carBasicForm.length; i++) {
const value = details.carBasicForm[i];
if (value.label === '车辆所属人')
return (value.checkarr =
getObjType(data) === 'array'
? data.map(val => {
val.label = val.name;
val.value = val.id;
return val;
})
: []);
}
}),
]);
details.pageInfo = $route.query;
for (let i = 0; i < details.carBasicForm.length; i++) {
const value = details.carBasicForm[i];
details.form[value.prop] = value.type === 2 ? 0 : '';
}
if (details.pageInfo.type === 'add') return;
const res = await getDetail(details.pageInfo.id);
const { code, data } = res.data;
if (code !== 200) return;
// details.form = data;
for (let i = 0; i < details.carBasicForm.length; i++) {
const value = details.carBasicForm[i];
if (value.type === 3 && value.multiple) {
details.form[value.prop] = details.form[value.prop]
? details.form[value.prop].split(',')
: [];
continue;
}
details.form[value.prop] = data[value.prop] || '';
}
for (let i = 0; i < details.imgArr.length; i++) {
const value = details.imgArr[i];
let _imgList = [];
const _value = data[value.prop];
value.imgList = _value
? _value.split(',').map(val => {
return { url: val, imgUrl: val };
})
: [];
}
};
initData();
// 图片上传接口
const doubledCount = computed(() => {
return '/api/blade-resource/oss/endpoint/put-file';
});
// 上传图片规则
const beforeAvatarUpload = async rawFile => {
console.log(rawFile);
if (rawFile.type !== 'image/png' && rawFile.type !== 'image/jpeg') {
ElMessage.error('图片格式只能为 png/jpg!');
return false;
} else if (rawFile.size / 1024 / 1024 > 10) {
ElMessage.error('图片大小不能大于10MB!');
return false;
}
const res = await compressImageBlob(rawFile);
return res;
};
// 图片上传必须携带TOKEN
const headers = computed(() => {
return { 'Blade-Auth': 'Bearer ' + getToken() };
});
// 图片上传成功
const handleAvatarSuccess = (response, item) => {
for (let i = 0; i < item.imgList.length; i++) {
const value = item.imgList[i];
console.log('value :>> ', value);
value.imgUrl =
value.response && value.response.code === 200 ? value.response.data.link : value.imgUrl || '';
}
ElMessage.success('上传成功');
};
/** 确认清空 */
const handleEmpty = item => {
if (item.imgList.length === 0) return ElMessage.warning('没有图片可以清空');
ElMessageBox.confirm('确定要清空吗', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
item.imgList = [];
})
.catch(() => {});
};
/** 提交 */
const handleSubmit = async () => {
try {
const _flag = await formRef.value.validate();
if (!_flag) return;
details.loadingObj.pageLoading = true;
const submitData = { ...details.form };
for (let i = 0; i < details.carBasicForm.length; i++) {
const value = details.carBasicForm[i];
if (value.type === 3 && value.multiple) {
submitData[value.prop] = details.form[value.prop].join(',');
}
}
for (let i = 0; i < details.imgArr.length; i++) {
const value = details.imgArr[i];
let _imgList = [];
for (let j = 0; j < value.imgList.length; j++) {
const item = value.imgList[j];
if (!item.imgUrl || /'blob'/.test(item.imgUrl))
return ElMessage.warning('存在异常图片请等待上传完毕或移除');
_imgList.push(item.imgUrl);
}
submitData[value.prop] = _imgList.join(',');
}
details.pageInfo.id && (submitData.id = details.pageInfo.id);
const res = details.pageInfo.type === 'add' ? await add(submitData) : await update(submitData);
const { code, data } = res.data;
if (code !== 200) return;
console.log('details.form :>> ', details.form);
console.log('_flag :>> ', _flag);
} catch (error) {
console.log('error :>> ', error);
} finally {
details.loadingObj.pageLoading = false;
}
};
</script>
<style lang="scss" scoped>
.main {
padding: 20px;
}
.pl20 {
padding-left: 20px;
}
.mb20 {
margin-bottom: 20px;
}
.pageTitle {
font-size: 18px;
font-weight: bold;
display: flex;
align-items: center;
&::before {
content: '';
display: inline-block;
height: 100%;
width: 4px;
background: #d3832a;
height: 18px;
margin-right: 10px;
}
}
:deep(.el-form) {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
}
// 相关图片
.imgContainer {
display: flex;
flex-wrap: wrap;
.imgItem {
min-width: 380px;
margin-bottom: 20px;
margin-right: 20px;
.title {
font-weight: bold;
// margin-bottom: 20px;
}
.imgRow {
display: flex;
flex-wrap: wrap;
}
.img {
margin: 10px;
border-radius: 5px;
width: 100px;
height: 100px;
}
}
}
.footer_container {
text-align: center;
}
.w20 {
width: 22%;
}
.w100 {
width: 100% !important;
}
.mr20 {
margin-right: 20px;
}
:deep(.el-input__inner) {
text-align: left;
}
:deep(.el-upload-list) {
display: block;
& > div {
display: flex;
}
& > li {
display: flex;
}
}
:deep(.el-upload--picture-card) {
position: absolute;
top: 0;
left: 0;
}
:deep(.el-upload-list) {
&::before {
content: '';
display: block;
width: var(--el-upload-list-picture-card-size);
height: var(--el-upload-list-picture-card-size);
margin-bottom: 10px;
}
}
// 清空按钮
.errBtn {
background: #ff3e3e;
border-color: #fff;
color: #fff;
&:hover {
background: #ff5c5c;
}
}
.addBtn {
background: #1cd66c;
border-color: #fff;
color: #fff;
&:hover {
background: #ff5c5c;
}
}
</style>