✨ 司机身份证OCR支持正反面识别并回填有效期
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -303,6 +303,42 @@
|
|||||||
/>
|
/>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
<el-row :gutter="18">
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="身份证有效期" prop="idCardValidEnd">
|
||||||
|
<div class="date-range">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="driverForm.idCardValidStart"
|
||||||
|
type="date"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
placeholder="起"
|
||||||
|
:disabled="driverForm.idCardLongTerm === 1"
|
||||||
|
@change="validateFormField('idCardValidEnd')"
|
||||||
|
/>
|
||||||
|
<el-date-picker
|
||||||
|
v-model="driverForm.idCardValidEnd"
|
||||||
|
type="date"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
placeholder="止"
|
||||||
|
:disabled="driverForm.idCardLongTerm === 1"
|
||||||
|
@change="validateFormField('idCardValidEnd')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="长期有效" prop="idCardLongTerm">
|
||||||
|
<el-checkbox
|
||||||
|
v-model="driverForm.idCardLongTerm"
|
||||||
|
:true-label="1"
|
||||||
|
:false-label="0"
|
||||||
|
@change="handleIdCardLongTermChange"
|
||||||
|
>
|
||||||
|
是
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
</section-card>
|
</section-card>
|
||||||
|
|
||||||
<section-card title="驾驶证信息">
|
<section-card title="驾驶证信息">
|
||||||
@@ -701,6 +737,9 @@ const emptyForm = () => ({
|
|||||||
posts: '',
|
posts: '',
|
||||||
idCardFront: '',
|
idCardFront: '',
|
||||||
idCardBack: '',
|
idCardBack: '',
|
||||||
|
idCardValidStart: '',
|
||||||
|
idCardValidEnd: '',
|
||||||
|
idCardLongTerm: 0,
|
||||||
headPhoto: '',
|
headPhoto: '',
|
||||||
drivingType: '',
|
drivingType: '',
|
||||||
drivingLicenseNo: '',
|
drivingLicenseNo: '',
|
||||||
@@ -1260,12 +1299,13 @@ export default {
|
|||||||
},
|
},
|
||||||
handleIdCardUploadSuccess(prop, url) {
|
handleIdCardUploadSuccess(prop, url) {
|
||||||
this.setImage(prop, url);
|
this.setImage(prop, url);
|
||||||
if (prop !== 'idCardFront') {
|
this.recognizeIdCard(url, prop);
|
||||||
return;
|
},
|
||||||
|
handleIdCardLongTermChange() {
|
||||||
|
if (this.driverForm.idCardLongTerm === 1) {
|
||||||
|
this.driverForm.idCardValidEnd = '';
|
||||||
}
|
}
|
||||||
this.recognizeBaiduOcr(url, 'id_card', 'front', '身份证', data => {
|
this.validateFormField('idCardValidEnd');
|
||||||
this.applyIdCardRecognition(data);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
handleDrivingLicenseUploadSuccess(prop, url) {
|
handleDrivingLicenseUploadSuccess(prop, url) {
|
||||||
this.setImage(prop, url);
|
this.setImage(prop, url);
|
||||||
@@ -1308,7 +1348,7 @@ export default {
|
|||||||
loading.close();
|
loading.close();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
recognizeIdCard(url = '') {
|
recognizeIdCard(url = '', prop = 'idCardFront') {
|
||||||
if (!url) {
|
if (!url) {
|
||||||
this.$message.warning('身份证图片上传成功,未获取到图片地址,无法自动识别');
|
this.$message.warning('身份证图片上传成功,未获取到图片地址,无法自动识别');
|
||||||
return;
|
return;
|
||||||
@@ -1321,7 +1361,7 @@ export default {
|
|||||||
recognitionIDCard(url)
|
recognitionIDCard(url)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
const data = res.data.data || {};
|
const data = res.data.data || {};
|
||||||
this.applyIdCardRecognition(data);
|
this.applyIdCardRecognition(data, prop);
|
||||||
this.$message.success('身份证识别完成');
|
this.$message.success('身份证识别完成');
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
@@ -1444,45 +1484,62 @@ export default {
|
|||||||
this.driverForm.drivingLicenseLongTerm = 0;
|
this.driverForm.drivingLicenseLongTerm = 0;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
applyIdCardRecognition(data = {}) {
|
applyIdCardRecognition(data = {}, prop = 'idCardFront') {
|
||||||
|
// 正反面都走同一 ShenFenZheng 接口;反面结果可能也带姓名/民族等字段,
|
||||||
|
// 反面只补空、不覆盖正面已填值,避免国徽页误识别冲掉正面信息。
|
||||||
|
const fromBack = prop === 'idCardBack';
|
||||||
|
const canWrite = (current, next) => !!next && (!fromBack || !current);
|
||||||
const driverName = data.name || data.driverName || this.getOcrValue(data, ['name', '姓名']);
|
const driverName = data.name || data.driverName || this.getOcrValue(data, ['name', '姓名']);
|
||||||
const idCardNo = String(
|
const idCardNo = String(
|
||||||
data.idNo ||
|
data.idNo ||
|
||||||
data.idCardNo ||
|
data.idCardNo ||
|
||||||
data.idCard ||
|
data.idCard ||
|
||||||
this.getOcrValue(data, ['idNo', 'idCardNo', 'number', '公民身份号码', '身份证号'])
|
this.getOcrValue(data, ['idNo', 'idCardNo', 'number', '公民身份号码', '身份证号']) ||
|
||||||
).toUpperCase();
|
''
|
||||||
|
)
|
||||||
|
.trim()
|
||||||
|
.toUpperCase();
|
||||||
const ocrGender = data.gender || this.getOcrValue(data, ['gender', '性别']);
|
const ocrGender = data.gender || this.getOcrValue(data, ['gender', '性别']);
|
||||||
const ocrNation =
|
const ocrNation =
|
||||||
data.nation ||
|
data.nation ||
|
||||||
data.ethnicGroup ||
|
data.ethnicGroup ||
|
||||||
this.getOcrValue(data, ['ethnic_group', 'nation', '民族']);
|
this.getOcrValue(data, ['ethnic_group', 'nation', '民族']);
|
||||||
const ocrAddress = data.address || this.getOcrValue(data, ['address', '住址', '地址']);
|
const ocrAddress = data.address || this.getOcrValue(data, ['address', '住址', '地址']);
|
||||||
if (driverName) {
|
const ocrBirthday =
|
||||||
|
data.birthday || this.getOcrValue(data, ['birthday', '出生', '出生年月', '出生日期']);
|
||||||
|
if (canWrite(this.driverForm.driverName, driverName)) {
|
||||||
this.driverForm.driverName = driverName;
|
this.driverForm.driverName = driverName;
|
||||||
}
|
}
|
||||||
if (ocrGender) {
|
if (canWrite(this.driverForm.gender, ocrGender)) {
|
||||||
this.driverForm.gender = ocrGender;
|
this.driverForm.gender = ocrGender;
|
||||||
}
|
}
|
||||||
if (ocrNation) {
|
if (canWrite(this.driverForm.nation, ocrNation)) {
|
||||||
this.driverForm.nation = this.normalizeNation(ocrNation);
|
this.driverForm.nation = this.normalizeNation(ocrNation);
|
||||||
}
|
}
|
||||||
if (ocrAddress) {
|
if (canWrite(this.driverForm.address, ocrAddress)) {
|
||||||
this.driverForm.address = String(ocrAddress).trim();
|
this.driverForm.address = String(ocrAddress).trim();
|
||||||
}
|
}
|
||||||
if (idCardNo) {
|
if (ocrBirthday) {
|
||||||
|
const birthday = this.normalizeBirthday(ocrBirthday);
|
||||||
|
if (canWrite(this.driverForm.birthday, birthday)) {
|
||||||
|
this.driverForm.birthday = birthday;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (idCardNo && canWrite(this.driverForm.idCardNo, idCardNo)) {
|
||||||
this.driverForm.idCardNo = idCardNo;
|
this.driverForm.idCardNo = idCardNo;
|
||||||
if (!this.driverForm.qualificationNo) {
|
if (!this.driverForm.qualificationNo) {
|
||||||
this.driverForm.qualificationNo = idCardNo;
|
this.driverForm.qualificationNo = idCardNo;
|
||||||
}
|
}
|
||||||
const idCardInfo = this.parseIdCardInfo(idCardNo);
|
const idCardInfo = this.parseIdCardInfo(idCardNo);
|
||||||
if (idCardInfo.birthday) {
|
if (!this.driverForm.birthday && idCardInfo.birthday) {
|
||||||
this.driverForm.birthday = idCardInfo.birthday;
|
this.driverForm.birthday = idCardInfo.birthday;
|
||||||
}
|
}
|
||||||
if (!this.driverForm.gender && idCardInfo.gender) {
|
if (!this.driverForm.gender && idCardInfo.gender) {
|
||||||
this.driverForm.gender = idCardInfo.gender;
|
this.driverForm.gender = idCardInfo.gender;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 有效期:正反面都可回填;反面通常才有,识别到就覆盖
|
||||||
|
this.applyIdCardValidity(data);
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
[
|
[
|
||||||
'driverName',
|
'driverName',
|
||||||
@@ -1492,11 +1549,46 @@ export default {
|
|||||||
'nation',
|
'nation',
|
||||||
'qualificationNo',
|
'qualificationNo',
|
||||||
'address',
|
'address',
|
||||||
].forEach(prop => {
|
'idCardValidEnd',
|
||||||
this.$refs.driverForm?.validateField(prop);
|
].forEach(field => {
|
||||||
|
this.$refs.driverForm?.validateField(field);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
applyIdCardValidity(data = {}) {
|
||||||
|
const validStart =
|
||||||
|
data.validDateStart ||
|
||||||
|
data.idCardValidStart ||
|
||||||
|
this.getOcrValue(data, ['签发日期', '有效起始日期', '有效期限起', '身份证_签发日期']);
|
||||||
|
const validEndRaw =
|
||||||
|
data.validDateEnd ||
|
||||||
|
data.idCardValidEnd ||
|
||||||
|
this.getOcrValue(data, [
|
||||||
|
'失效日期',
|
||||||
|
'有效期限',
|
||||||
|
'有效期限止',
|
||||||
|
'身份证_有效期限',
|
||||||
|
'身份证_失效日期',
|
||||||
|
]);
|
||||||
|
const longTerm = data.longTerm ?? data.idCardLongTerm;
|
||||||
|
const validEndText = String(validEndRaw || '').trim();
|
||||||
|
if (longTerm === 1 || longTerm === '1' || /长期|永久/.test(validEndText)) {
|
||||||
|
this.driverForm.idCardLongTerm = 1;
|
||||||
|
this.driverForm.idCardValidEnd = '';
|
||||||
|
} else if (validEndText) {
|
||||||
|
const endDate = this.normalizeBirthday(validEndText);
|
||||||
|
if (endDate) {
|
||||||
|
this.driverForm.idCardValidEnd = endDate;
|
||||||
|
this.driverForm.idCardLongTerm = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (validStart) {
|
||||||
|
const startDate = this.normalizeBirthday(validStart);
|
||||||
|
if (startDate) {
|
||||||
|
this.driverForm.idCardValidStart = startDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
getOcrValue(data = {}, keys = []) {
|
getOcrValue(data = {}, keys = []) {
|
||||||
const keyInfos = data.keyInfos || data.keyInfo || data.ocrKeyInfos || [];
|
const keyInfos = data.keyInfos || data.keyInfo || data.ocrKeyInfos || [];
|
||||||
const list = Array.isArray(keyInfos) ? keyInfos : [];
|
const list = Array.isArray(keyInfos) ? keyInfos : [];
|
||||||
@@ -1675,6 +1767,8 @@ export default {
|
|||||||
const row = {
|
const row = {
|
||||||
...this.driverForm,
|
...this.driverForm,
|
||||||
birthday: this.normalizeBirthday(this.driverForm.birthday),
|
birthday: this.normalizeBirthday(this.driverForm.birthday),
|
||||||
|
idCardValidStart: this.normalizeBirthday(this.driverForm.idCardValidStart),
|
||||||
|
idCardValidEnd: this.normalizeBirthday(this.driverForm.idCardValidEnd),
|
||||||
drivingLicenseStartDate: this.normalizeBirthday(this.driverForm.drivingLicenseStartDate),
|
drivingLicenseStartDate: this.normalizeBirthday(this.driverForm.drivingLicenseStartDate),
|
||||||
drivingLicenseEndDate: this.normalizeBirthday(this.driverForm.drivingLicenseEndDate),
|
drivingLicenseEndDate: this.normalizeBirthday(this.driverForm.drivingLicenseEndDate),
|
||||||
qualificationStartDate: this.normalizeBirthday(this.driverForm.qualificationStartDate),
|
qualificationStartDate: this.normalizeBirthday(this.driverForm.qualificationStartDate),
|
||||||
|
|||||||
Reference in New Issue
Block a user