1、完善项目
2、完善合同 3、完善费用项 4、司机管理对接OCR 5、完善运输计划 6、完善临时额度
This commit is contained in:
@@ -100,12 +100,7 @@
|
||||
>
|
||||
查看
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
text
|
||||
v-if="hasPermission('driver_edit')"
|
||||
@click="openDriver(row)"
|
||||
>
|
||||
<el-button type="primary" text v-if="hasPermission('driver_edit')" @click="openDriver(row)">
|
||||
修改
|
||||
</el-button>
|
||||
<el-button
|
||||
@@ -222,7 +217,7 @@
|
||||
:readonly="readonly"
|
||||
:headers="uploadHeaders"
|
||||
large
|
||||
@success="url => setImage('idCardFront', url)"
|
||||
@success="url => handleIdCardUploadSuccess('idCardFront', url)"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
@@ -233,7 +228,7 @@
|
||||
:readonly="readonly"
|
||||
:headers="uploadHeaders"
|
||||
large
|
||||
@success="url => setImage('idCardBack', url)"
|
||||
@success="url => handleIdCardUploadSuccess('idCardBack', url)"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
@@ -317,7 +312,10 @@
|
||||
:readonly="readonly"
|
||||
:headers="uploadHeaders"
|
||||
large
|
||||
@success="url => setImage('drivingLicenseFront', url)"
|
||||
@success="
|
||||
(url, file) =>
|
||||
handleDrivingLicenseUploadSuccess('drivingLicenseFront', url, file)
|
||||
"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
@@ -328,7 +326,9 @@
|
||||
:readonly="readonly"
|
||||
:headers="uploadHeaders"
|
||||
large
|
||||
@success="url => setImage('drivingLicenseBack', url)"
|
||||
@success="
|
||||
(url, file) => handleDrivingLicenseUploadSuccess('drivingLicenseBack', url, file)
|
||||
"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -483,6 +483,7 @@
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import NProgress from 'nprogress';
|
||||
import { ElLoading } from 'element-plus';
|
||||
import { option } from '@/option/transportCapacity/driver';
|
||||
import {
|
||||
getList,
|
||||
@@ -491,10 +492,13 @@ import {
|
||||
remove,
|
||||
changeStatus,
|
||||
getExpiryStat,
|
||||
recognitionIDCard,
|
||||
recognitionTransportCertificates,
|
||||
} from '@/api/transportCapacity/driver';
|
||||
import { getDeptTree } from '@/api/system/dept';
|
||||
import { exportBlob } from '@/api/common';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { getUploadHeaders } from '@/utils/upload';
|
||||
import { downloadXls } from '@/utils/util';
|
||||
import ImageUploadField from '@/components/image-upload-field/main.vue';
|
||||
|
||||
@@ -565,10 +569,8 @@ export default {
|
||||
driverBox: false,
|
||||
readonly: false,
|
||||
driverForm: emptyForm(),
|
||||
uploadHeaders: {
|
||||
'Blade-Auth': `bearer ${getToken()}`,
|
||||
'Blade-Requested-With': 'BladeHttpRequest',
|
||||
},
|
||||
drivingLicenseUploads: {},
|
||||
uploadHeaders: getUploadHeaders(),
|
||||
nationOptions: [
|
||||
'汉族',
|
||||
'蒙古族',
|
||||
@@ -773,6 +775,7 @@ export default {
|
||||
},
|
||||
resetDriver() {
|
||||
this.driverForm = emptyForm();
|
||||
this.drivingLicenseUploads = {};
|
||||
this.readonly = false;
|
||||
this.submitLoading = false;
|
||||
this.$refs.driverForm?.clearValidate();
|
||||
@@ -781,6 +784,230 @@ export default {
|
||||
this.driverForm[prop] = url;
|
||||
this.$refs.driverForm?.validateField(prop);
|
||||
},
|
||||
handleIdCardUploadSuccess(prop, url) {
|
||||
this.setImage(prop, url);
|
||||
this.recognizeIdCard(url);
|
||||
},
|
||||
handleDrivingLicenseUploadSuccess(prop, url, file = {}) {
|
||||
this.setImage(prop, url);
|
||||
this.drivingLicenseUploads[prop] = this.getUploadRecognitionKey(file, url);
|
||||
this.recognizeDrivingLicense();
|
||||
},
|
||||
recognizeIdCard(url = '') {
|
||||
if (!url) {
|
||||
this.$message.warning('身份证图片上传成功,未获取到图片地址,无法自动识别');
|
||||
return;
|
||||
}
|
||||
const loading = ElLoading.service({
|
||||
lock: true,
|
||||
text: '身份证识别中',
|
||||
background: 'rgba(255, 255, 255, 0.7)',
|
||||
});
|
||||
recognitionIDCard(url)
|
||||
.then(res => {
|
||||
const data = res.data.data || {};
|
||||
this.applyIdCardRecognition(data);
|
||||
this.$message.success('身份证识别完成');
|
||||
})
|
||||
.catch(() => {
|
||||
this.$message.warning('身份证图片上传成功,自动识别失败,请手动填写身份信息');
|
||||
})
|
||||
.finally(() => {
|
||||
loading.close();
|
||||
});
|
||||
},
|
||||
recognizeDrivingLicense() {
|
||||
const objectKeys = [
|
||||
this.drivingLicenseUploads.drivingLicenseFront || this.driverForm.drivingLicenseFront,
|
||||
this.drivingLicenseUploads.drivingLicenseBack || this.driverForm.drivingLicenseBack,
|
||||
].filter(Boolean);
|
||||
if (!objectKeys.length) {
|
||||
this.$message.warning('驾驶证图片上传成功,未获取到图片地址,无法自动识别');
|
||||
return;
|
||||
}
|
||||
const loading = ElLoading.service({
|
||||
lock: true,
|
||||
text: '驾驶证识别中',
|
||||
background: 'rgba(255, 255, 255, 0.7)',
|
||||
});
|
||||
recognitionTransportCertificates(objectKeys)
|
||||
.then(res => {
|
||||
const data = res.data.data || {};
|
||||
this.applyDrivingLicenseRecognition(data);
|
||||
this.$message.success('驾驶证识别完成');
|
||||
})
|
||||
.catch(() => {
|
||||
this.$message.warning('驾驶证图片上传成功,自动识别失败,请手动填写驾驶证信息');
|
||||
})
|
||||
.finally(() => {
|
||||
loading.close();
|
||||
});
|
||||
},
|
||||
applyDrivingLicenseRecognition(data = {}) {
|
||||
const driverName = data.driverLicenseName || data.name || this.getOcrValue(data, ['name', '姓名']);
|
||||
const idCardNo = String(
|
||||
data.driverLicenseIdNo ||
|
||||
data.idNo ||
|
||||
data.idCardNo ||
|
||||
this.getOcrValue(data, ['ID_no', 'idNo', 'idCardNo', '证号'])
|
||||
).toUpperCase();
|
||||
const drivingType =
|
||||
data.driverLicenseType ||
|
||||
data.drivingType ||
|
||||
data.driverClass ||
|
||||
this.getOcrValue(data, ['class', '准驾车型']);
|
||||
const drivingLicenseNo =
|
||||
data.driverLicenseFileNo ||
|
||||
data.drivingLicenseNo ||
|
||||
data.fileNo ||
|
||||
this.getOcrValue(data, ['file_no', '档案编号']);
|
||||
const validDateStart =
|
||||
data.driverLicenseValidDateStart ||
|
||||
data.drivingLicenseStartDate ||
|
||||
this.getOcrValue(data, ['date_vaild_start', '有效期限(起始时间)']);
|
||||
const validDateEnd =
|
||||
data.driverLicenseValidDateEnd ||
|
||||
data.drivingLicenseEndDate ||
|
||||
this.getOcrValue(data, ['date_vaild_end', '有效期限(终止时间)', '有效期限(终⽌时间)']);
|
||||
if (driverName && !this.driverForm.driverName) {
|
||||
this.driverForm.driverName = driverName;
|
||||
}
|
||||
if (idCardNo && !this.driverForm.idCardNo) {
|
||||
this.driverForm.idCardNo = idCardNo;
|
||||
}
|
||||
if (idCardNo && !this.driverForm.qualificationNo) {
|
||||
this.driverForm.qualificationNo = idCardNo;
|
||||
}
|
||||
if (drivingType) {
|
||||
this.driverForm.drivingType = drivingType;
|
||||
}
|
||||
if (drivingLicenseNo) {
|
||||
this.driverForm.drivingLicenseNo = drivingLicenseNo;
|
||||
}
|
||||
if (validDateStart) {
|
||||
this.driverForm.drivingLicenseStartDate = this.normalizeBirthday(validDateStart);
|
||||
}
|
||||
if (validDateEnd) {
|
||||
this.driverForm.drivingLicenseEndDate = this.normalizeBirthday(validDateEnd);
|
||||
this.driverForm.drivingLicenseLongTerm = 0;
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
[
|
||||
'driverName',
|
||||
'idCardNo',
|
||||
'drivingType',
|
||||
'drivingLicenseNo',
|
||||
'drivingLicenseEndDate',
|
||||
'qualificationNo',
|
||||
].forEach(prop => {
|
||||
this.$refs.driverForm?.validateField(prop);
|
||||
});
|
||||
});
|
||||
},
|
||||
getUploadRecognitionKey(file = {}, url = '') {
|
||||
return (
|
||||
file.objectKey ||
|
||||
file.key ||
|
||||
file.fileName ||
|
||||
file.name ||
|
||||
file.link ||
|
||||
file.url ||
|
||||
file.domain ||
|
||||
url ||
|
||||
''
|
||||
);
|
||||
},
|
||||
applyIdCardRecognition(data = {}) {
|
||||
const driverName = data.name || data.driverName || this.getOcrValue(data, ['name', '姓名']);
|
||||
const idCardNo = String(
|
||||
data.idNo ||
|
||||
data.idCardNo ||
|
||||
data.idCard ||
|
||||
this.getOcrValue(data, ['idNo', 'idCardNo', 'number', '公民身份号码', '身份证号'])
|
||||
).toUpperCase();
|
||||
const ocrGender = data.gender || this.getOcrValue(data, ['gender', '性别']);
|
||||
const ocrNation =
|
||||
data.nation ||
|
||||
data.ethnicGroup ||
|
||||
this.getOcrValue(data, ['ethnic_group', 'nation', '民族']);
|
||||
const ocrBirthday =
|
||||
data.birthday || data.birthDate || this.getOcrValue(data, ['date', '出生']);
|
||||
if (driverName) {
|
||||
this.driverForm.driverName = driverName;
|
||||
}
|
||||
if (ocrGender) {
|
||||
this.driverForm.gender = ocrGender;
|
||||
}
|
||||
if (ocrNation) {
|
||||
this.driverForm.nation = this.normalizeNation(ocrNation);
|
||||
}
|
||||
if (ocrBirthday) {
|
||||
this.driverForm.birthday = this.normalizeBirthday(ocrBirthday);
|
||||
}
|
||||
if (idCardNo) {
|
||||
this.driverForm.idCardNo = idCardNo;
|
||||
if (!this.driverForm.qualificationNo) {
|
||||
this.driverForm.qualificationNo = idCardNo;
|
||||
}
|
||||
const idCardInfo = this.parseIdCardInfo(idCardNo);
|
||||
if (!this.driverForm.birthday && idCardInfo.birthday) {
|
||||
this.driverForm.birthday = idCardInfo.birthday;
|
||||
}
|
||||
if (!this.driverForm.gender && idCardInfo.gender) {
|
||||
this.driverForm.gender = idCardInfo.gender;
|
||||
}
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
['driverName', 'idCardNo', 'birthday', 'gender', 'nation', 'qualificationNo'].forEach(
|
||||
prop => {
|
||||
this.$refs.driverForm?.validateField(prop);
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
getOcrValue(data = {}, keys = []) {
|
||||
const keyInfos = data.keyInfos || data.keyInfo || data.ocrKeyInfos || [];
|
||||
const list = Array.isArray(keyInfos) ? keyInfos : [];
|
||||
const item = list.find(info => {
|
||||
const key = String(info.key || '').toLowerCase();
|
||||
const description = String(info.description || '');
|
||||
return keys.some(value => key === String(value).toLowerCase() || description === value);
|
||||
});
|
||||
return item ? item.value || '' : '';
|
||||
},
|
||||
normalizeNation(value = '') {
|
||||
const nation = String(value || '').trim();
|
||||
if (!nation) return '';
|
||||
if (this.nationOptions.includes(nation)) return nation;
|
||||
const fullNation = `${nation}族`;
|
||||
return this.nationOptions.includes(fullNation) ? fullNation : nation;
|
||||
},
|
||||
normalizeBirthday(value = '') {
|
||||
const birthday = String(value || '').trim();
|
||||
const match = birthday.match(/^(\d{4})[-/.年](\d{1,2})[-/.月](\d{1,2})日?$/);
|
||||
if (!match) return birthday;
|
||||
const [, year, month, day] = match;
|
||||
return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`;
|
||||
},
|
||||
parseIdCardInfo(idCardNo = '') {
|
||||
if (!/^\d{17}[\dX]$/.test(idCardNo)) {
|
||||
return {};
|
||||
}
|
||||
const birthday = `${idCardNo.slice(6, 10)}-${idCardNo.slice(10, 12)}-${idCardNo.slice(
|
||||
12,
|
||||
14
|
||||
)}`;
|
||||
const date = new Date(`${birthday}T00:00:00`);
|
||||
const validDate =
|
||||
!Number.isNaN(date.getTime()) &&
|
||||
date.getFullYear() === Number(idCardNo.slice(6, 10)) &&
|
||||
date.getMonth() + 1 === Number(idCardNo.slice(10, 12)) &&
|
||||
date.getDate() === Number(idCardNo.slice(12, 14));
|
||||
return {
|
||||
birthday: validDate ? birthday : '',
|
||||
gender: Number(idCardNo.slice(16, 17)) % 2 === 1 ? '男' : '女',
|
||||
};
|
||||
},
|
||||
validateFormField(prop) {
|
||||
this.$refs.driverForm?.validateField(prop);
|
||||
},
|
||||
@@ -914,7 +1141,9 @@ export default {
|
||||
type: 'warning',
|
||||
}).then(() => {
|
||||
NProgress.start();
|
||||
exportBlob('/blade-transport/driver/export-driver', this.buildExportParams(), { feedback: true })
|
||||
exportBlob('/blade-transport/driver/export-driver', this.buildExportParams(), {
|
||||
feedback: true,
|
||||
})
|
||||
.then(res => {
|
||||
downloadXls(res.data, `司机管理${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`);
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user