2026-04-10 01:49:07 +08:00

313 lines
8.9 KiB
JavaScript
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.

const auth = require('../../../utils/auth');
const PHONE_RE = /^1[3456789]\d{9}$/;
Page({
data: {
activeTab: 1, // 1=身份证 2=护照
// 上传图片 URL(远程)
idCardImageUrl: '',
idCardBackImageUrl: '',
passportImageUrl: '',
// 识别字段(只读,OCR 自动填充)
name: '',
idCardNumber: '',
birthDate: '',
genderOptions: [
{ value: 0, label: '男' },
{ value: 1, label: '女' }
],
genderIndex: 0,
// 护照识别额外字段(只读)
passportNumber: '',
nationality: '',
issueDate: '',
expiryDate: '',
// 联系方式
mobile: '',
verificationCode: '',
// UI 状态
recognizing: false,
submitting: false,
codeSending: false,
countdown: 0,
ocrDone: false
},
_timer: null,
onLoad() {
this.loadAuth();
},
onShow() {
const accessToken = wx.getStorageSync('accessToken') || '';
if (!accessToken) {
wx.redirectTo({ url: '/subpackages/mine/login/login' });
}
},
onUnload() {
this._clearTimer();
},
onPullDownRefresh() {
this.loadAuth().finally(() => wx.stopPullDownRefresh());
},
onBack() {
if (getCurrentPages().length > 1) {
wx.navigateBack({ delta: 1 });
} else {
wx.switchTab({ url: '/pages/mine/mine' });
}
},
onSwitchTab(e) {
const tab = Number(e.currentTarget.dataset.tab);
if (tab === this.data.activeTab) return;
this.setData({
activeTab: tab,
verificationCode: '',
ocrDone: false,
name: '', idCardNumber: '', birthDate: '', genderIndex: 0,
passportNumber: '', nationality: '', issueDate: '', expiryDate: '',
idCardImageUrl: '', idCardBackImageUrl: '', passportImageUrl: ''
});
this.loadAuth();
},
loadAuth() {
return auth
.fetchMyAuth()
.then((res) => {
const d = res && typeof res === 'object' ? res : {};
const name = d.name || d.realName || '';
const mobile = d.mobile || d.phone || '';
const idCardNumber = d.idCardNumber || d.idNumber || '';
const idCardImageUrl = d.idCardImageUrl || d.idCardFrontImageUrl || '';
const idCardBackImageUrl = d.idCardBackImageUrl || '';
const passportImageUrl = d.passportPhotoUrl || d.passportImageUrl || '';
const birthDate = d.birthDate || d.birthday || '';
const rawGender = d.gender != null ? String(d.gender) : '';
const genderIndex = (rawGender === '1' || rawGender === 'F' || rawGender === '女') ? 1 : 0;
const ocrDone = Boolean(name || idCardNumber || passportImageUrl);
this.setData({
name, mobile, idCardNumber,
idCardImageUrl, idCardBackImageUrl, passportImageUrl,
birthDate, genderIndex, ocrDone
});
})
.catch(() => {});
},
onChooseImage(e) {
const kind = e.currentTarget.dataset.kind;
wx.chooseMedia({
count: 1,
mediaType: ['image'],
sourceType: ['album', 'camera'],
success: (res) => {
const tempFilePath = res.tempFiles && res.tempFiles[0] ? res.tempFiles[0].tempFilePath : '';
if (!tempFilePath) return;
this._uploadAndOcr(tempFilePath, kind);
}
});
},
async _uploadAndOcr(tempFilePath, kind) {
wx.showLoading({ title: '上传识别中...', mask: true });
this.setData({ recognizing: true });
try {
const imageUrl = await auth.uploadFile(tempFilePath);
if (kind === 'idFront') this.setData({ idCardImageUrl: imageUrl });
else if (kind === 'idBack') this.setData({ idCardBackImageUrl: imageUrl });
else if (kind === 'passport') this.setData({ passportImageUrl: imageUrl });
if (kind === 'idFront') {
const ocr = await auth.ocrIdCard(imageUrl);
if (ocr && ocr.success === false) {
wx.showToast({ title: ocr.message || '身份证识别失败', icon: 'none' });
return;
}
const genderIndex = (ocr && (ocr.gender === '女' || ocr.gender === 'F' || ocr.gender === '1')) ? 1 : 0;
this.setData({
name: (ocr && ocr.name) || '',
idCardNumber: (ocr && ocr.idCardNumber) || '',
birthDate: (ocr && ocr.birthDate) || '',
genderIndex,
ocrDone: true
});
wx.showToast({ title: '识别成功', icon: 'success' });
} else if (kind === 'passport') {
const ocr = await auth.ocrPassport(imageUrl);
if (ocr && ocr.success === false) {
wx.showToast({ title: ocr.message || '护照识别失败', icon: 'none' });
return;
}
const genderIndex = (ocr && (ocr.gender === '女' || ocr.gender === 'F' || ocr.gender === '1')) ? 1 : 0;
this.setData({
name: (ocr && ocr.name) || '',
passportNumber: (ocr && ocr.passportNumber) || '',
nationality: (ocr && ocr.nationality) || '',
birthDate: (ocr && (ocr.birthDate || ocr.birthDateYmd)) || '',
issueDate: (ocr && (ocr.issueDate || ocr.issueDateYmd)) || '',
expiryDate: (ocr && (ocr.expiryDate || ocr.validToDate)) || '',
genderIndex,
ocrDone: true
});
wx.showToast({ title: '识别成功', icon: 'success' });
} else {
wx.showToast({ title: '上传成功', icon: 'success' });
}
} catch (err) {
wx.showToast({ title: (err && err.message) || '识别失败', icon: 'none' });
} finally {
this.setData({ recognizing: false });
wx.hideLoading();
}
},
onMobileInput(e) {
this.setData({ mobile: (e.detail.value || '').trim() });
},
onCodeInput(e) {
this.setData({ verificationCode: (e.detail.value || '').trim() });
},
onSendCodeTap() {
const { mobile, countdown, codeSending } = this.data;
if (codeSending || countdown > 0) return;
if (!PHONE_RE.test(mobile)) {
wx.showToast({ title: '请输入正确手机号', icon: 'none' });
return;
}
this.setData({ codeSending: true });
wx.showLoading({ title: '发送中...' });
auth
.sendVerificationCode(mobile)
.then(() => {
wx.showToast({ title: '验证码已发送', icon: 'success' });
this._startCountdown(60);
})
.catch(() => {
wx.showToast({ title: '发送失败', icon: 'none' });
})
.finally(() => {
this.setData({ codeSending: false });
wx.hideLoading();
});
},
_startCountdown(sec) {
this._clearTimer();
this.setData({ countdown: sec });
this._timer = setInterval(() => {
const next = this.data.countdown - 1;
if (next <= 0) {
this._clearTimer();
this.setData({ countdown: 0 });
} else {
this.setData({ countdown: next });
}
}, 1000);
},
_clearTimer() {
if (this._timer) {
clearInterval(this._timer);
this._timer = null;
}
},
onSubmitTap() {
if (this.data.submitting) return;
const {
activeTab, idCardImageUrl, passportImageUrl,
name, idCardNumber, birthDate,
genderOptions, genderIndex, mobile, verificationCode
} = this.data;
if (!name) {
wx.showToast({ title: '请先上传证件图片完成识别', icon: 'none' });
return;
}
if (!PHONE_RE.test(mobile)) {
wx.showToast({ title: '请输入正确手机号', icon: 'none' });
return;
}
if (!verificationCode) {
wx.showToast({ title: '请输入验证码', icon: 'none' });
return;
}
const genderValue = genderOptions[genderIndex] ? genderOptions[genderIndex].value : 0;
let payload;
if (activeTab === 1) {
if (!idCardImageUrl) {
wx.showToast({ title: '请上传身份证人像面', icon: 'none' });
return;
}
if (!idCardNumber) {
wx.showToast({ title: '请先完成身份证识别', icon: 'none' });
return;
}
payload = {
authType: 0,
name,
mobile,
smsCode: verificationCode,
gender: genderValue,
birthDate: birthDate || undefined,
idCardNumber,
idCardImageUrl
};
} else {
if (!passportImageUrl) {
wx.showToast({ title: '请上传护照', icon: 'none' });
return;
}
if (!birthDate) {
wx.showToast({ title: '请先完成护照识别', icon: 'none' });
return;
}
payload = {
authType: 1,
name,
mobile,
smsCode: verificationCode,
gender: genderValue,
birthDate,
passportPhotoUrl: passportImageUrl
};
}
this.setData({ submitting: true });
wx.showLoading({ title: '提交中...' });
auth
.submitMyAuth(payload)
.then(() => {
wx.showToast({ title: '提交成功', icon: 'success' });
setTimeout(() => wx.navigateBack({ delta: 1 }), 600);
})
.catch((err) => {
wx.showToast({ title: (err && err.message) || '提交失败', icon: 'none' });
})
.finally(() => {
this.setData({ submitting: false });
wx.hideLoading();
});
}
});