✨ 司机身份证OCR支持正反面识别并回填有效期
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -303,6 +303,42 @@
|
||||
/>
|
||||
</el-col>
|
||||
</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 title="驾驶证信息">
|
||||
@@ -701,6 +737,9 @@ const emptyForm = () => ({
|
||||
posts: '',
|
||||
idCardFront: '',
|
||||
idCardBack: '',
|
||||
idCardValidStart: '',
|
||||
idCardValidEnd: '',
|
||||
idCardLongTerm: 0,
|
||||
headPhoto: '',
|
||||
drivingType: '',
|
||||
drivingLicenseNo: '',
|
||||
@@ -1260,12 +1299,13 @@ export default {
|
||||
},
|
||||
handleIdCardUploadSuccess(prop, url) {
|
||||
this.setImage(prop, url);
|
||||
if (prop !== 'idCardFront') {
|
||||
return;
|
||||
this.recognizeIdCard(url, prop);
|
||||
},
|
||||
handleIdCardLongTermChange() {
|
||||
if (this.driverForm.idCardLongTerm === 1) {
|
||||
this.driverForm.idCardValidEnd = '';
|
||||
}
|
||||
this.recognizeBaiduOcr(url, 'id_card', 'front', '身份证', data => {
|
||||
this.applyIdCardRecognition(data);
|
||||
});
|
||||
this.validateFormField('idCardValidEnd');
|
||||
},
|
||||
handleDrivingLicenseUploadSuccess(prop, url) {
|
||||
this.setImage(prop, url);
|
||||
@@ -1308,7 +1348,7 @@ export default {
|
||||
loading.close();
|
||||
});
|
||||
},
|
||||
recognizeIdCard(url = '') {
|
||||
recognizeIdCard(url = '', prop = 'idCardFront') {
|
||||
if (!url) {
|
||||
this.$message.warning('身份证图片上传成功,未获取到图片地址,无法自动识别');
|
||||
return;
|
||||
@@ -1321,7 +1361,7 @@ export default {
|
||||
recognitionIDCard(url)
|
||||
.then(res => {
|
||||
const data = res.data.data || {};
|
||||
this.applyIdCardRecognition(data);
|
||||
this.applyIdCardRecognition(data, prop);
|
||||
this.$message.success('身份证识别完成');
|
||||
})
|
||||
.catch(() => {
|
||||
@@ -1444,45 +1484,62 @@ export default {
|
||||
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 idCardNo = String(
|
||||
data.idNo ||
|
||||
data.idCardNo ||
|
||||
data.idCard ||
|
||||
this.getOcrValue(data, ['idNo', 'idCardNo', 'number', '公民身份号码', '身份证号'])
|
||||
).toUpperCase();
|
||||
this.getOcrValue(data, ['idNo', 'idCardNo', 'number', '公民身份号码', '身份证号']) ||
|
||||
''
|
||||
)
|
||||
.trim()
|
||||
.toUpperCase();
|
||||
const ocrGender = data.gender || this.getOcrValue(data, ['gender', '性别']);
|
||||
const ocrNation =
|
||||
data.nation ||
|
||||
data.ethnicGroup ||
|
||||
this.getOcrValue(data, ['ethnic_group', 'nation', '民族']);
|
||||
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;
|
||||
}
|
||||
if (ocrGender) {
|
||||
if (canWrite(this.driverForm.gender, ocrGender)) {
|
||||
this.driverForm.gender = ocrGender;
|
||||
}
|
||||
if (ocrNation) {
|
||||
if (canWrite(this.driverForm.nation, ocrNation)) {
|
||||
this.driverForm.nation = this.normalizeNation(ocrNation);
|
||||
}
|
||||
if (ocrAddress) {
|
||||
if (canWrite(this.driverForm.address, ocrAddress)) {
|
||||
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;
|
||||
if (!this.driverForm.qualificationNo) {
|
||||
this.driverForm.qualificationNo = idCardNo;
|
||||
}
|
||||
const idCardInfo = this.parseIdCardInfo(idCardNo);
|
||||
if (idCardInfo.birthday) {
|
||||
if (!this.driverForm.birthday && idCardInfo.birthday) {
|
||||
this.driverForm.birthday = idCardInfo.birthday;
|
||||
}
|
||||
if (!this.driverForm.gender && idCardInfo.gender) {
|
||||
this.driverForm.gender = idCardInfo.gender;
|
||||
}
|
||||
}
|
||||
// 有效期:正反面都可回填;反面通常才有,识别到就覆盖
|
||||
this.applyIdCardValidity(data);
|
||||
this.$nextTick(() => {
|
||||
[
|
||||
'driverName',
|
||||
@@ -1492,11 +1549,46 @@ export default {
|
||||
'nation',
|
||||
'qualificationNo',
|
||||
'address',
|
||||
].forEach(prop => {
|
||||
this.$refs.driverForm?.validateField(prop);
|
||||
'idCardValidEnd',
|
||||
].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 = []) {
|
||||
const keyInfos = data.keyInfos || data.keyInfo || data.ocrKeyInfos || [];
|
||||
const list = Array.isArray(keyInfos) ? keyInfos : [];
|
||||
@@ -1675,6 +1767,8 @@ export default {
|
||||
const row = {
|
||||
...this.driverForm,
|
||||
birthday: this.normalizeBirthday(this.driverForm.birthday),
|
||||
idCardValidStart: this.normalizeBirthday(this.driverForm.idCardValidStart),
|
||||
idCardValidEnd: this.normalizeBirthday(this.driverForm.idCardValidEnd),
|
||||
drivingLicenseStartDate: this.normalizeBirthday(this.driverForm.drivingLicenseStartDate),
|
||||
drivingLicenseEndDate: this.normalizeBirthday(this.driverForm.drivingLicenseEndDate),
|
||||
qualificationStartDate: this.normalizeBirthday(this.driverForm.qualificationStartDate),
|
||||
|
||||
Reference in New Issue
Block a user