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.
472 lines
12 KiB
472 lines
12 KiB
// pages/auth/real-name-auth.js
|
|
import http from '../../../utils/api'
|
|
|
|
Page({
|
|
data: {
|
|
// 表单数据
|
|
name: '',
|
|
idNumber: '',
|
|
|
|
// 焦点状态
|
|
nameFocus: false,
|
|
idNumberFocus: false,
|
|
|
|
// 错误提示
|
|
nameError: '',
|
|
idNumberError: '',
|
|
|
|
// 提示显示控制
|
|
showNameHint: false,
|
|
showIdNumberHint: false,
|
|
|
|
// 验证状态
|
|
isNameValid: false,
|
|
isIdNumberValid: false,
|
|
|
|
// 协议状态
|
|
agreed: false,
|
|
|
|
// 提交状态
|
|
canSubmit: false,
|
|
isSubmitting: false,
|
|
|
|
// 进度条
|
|
currentStep: 1,
|
|
lineProgress1: 0,
|
|
lineProgress2: 0,
|
|
|
|
// 弹窗数据
|
|
showModal: false,
|
|
modalTitle: '',
|
|
modalContent: '',
|
|
|
|
// 成功弹窗数据
|
|
showSuccessModal: false,
|
|
maskedIdNumber: '',
|
|
|
|
// 错误弹窗数据
|
|
showErrorModal: false,
|
|
errorTitle: '',
|
|
errorMessage: ''
|
|
},
|
|
|
|
onLoad() {
|
|
// 页面加载时启动进度条动画
|
|
setTimeout(() => {
|
|
this.setData({ lineProgress1: 50 });
|
|
}, 600);
|
|
},
|
|
|
|
// 姓名输入处理
|
|
onNameInput(e) {
|
|
const value = e.detail.value.trim();
|
|
let error = '';
|
|
let showHint = true;
|
|
let isValid = false;
|
|
|
|
if (value) {
|
|
if (!/^[\u4e00-\u9fa5]{2,10}$/.test(value)) {
|
|
error = '姓名应为2-10个汉字';
|
|
} else {
|
|
isValid = true;
|
|
// 验证通过时保持提示显示,但无错误
|
|
}
|
|
} else {
|
|
// 内容为空时显示正常提示
|
|
error = '';
|
|
}
|
|
|
|
this.setData({
|
|
name: value,
|
|
nameError: error,
|
|
showNameHint: showHint,
|
|
isNameValid: isValid
|
|
}, () => {
|
|
this.checkForm();
|
|
});
|
|
},
|
|
|
|
onNameFocus() {
|
|
this.setData({
|
|
nameFocus: true,
|
|
showNameHint: true // 获得焦点时显示提示
|
|
});
|
|
},
|
|
|
|
onNameBlur() {
|
|
const { name } = this.data;
|
|
|
|
this.setData({
|
|
nameFocus: false,
|
|
// 失去焦点时,如果内容为空或验证失败,保持提示显示
|
|
showNameHint: !!(name && !this.data.isNameValid)
|
|
});
|
|
},
|
|
|
|
// 清除姓名
|
|
clearName() {
|
|
this.setData({
|
|
name: '',
|
|
nameError: '',
|
|
showNameHint: false,
|
|
isNameValid: false
|
|
}, () => {
|
|
this.checkForm();
|
|
});
|
|
},
|
|
|
|
// 身份证号输入处理
|
|
onIdNumberInput(e) {
|
|
const value = e.detail.value.trim().toUpperCase();
|
|
let error = '';
|
|
let showHint = true;
|
|
let isValid = false;
|
|
|
|
if (value) {
|
|
if (value.length < 18) {
|
|
error = '还需输入' + (18 - value.length) + '位';
|
|
} else if (value.length === 18) {
|
|
if (this.validateIdNumber(value)) {
|
|
isValid = true;
|
|
// 验证通过时保持提示显示,但无错误
|
|
} else {
|
|
error = '身份证号格式不正确';
|
|
}
|
|
}
|
|
} else {
|
|
// 内容为空时显示正常提示
|
|
error = '';
|
|
}
|
|
|
|
this.setData({
|
|
idNumber: value,
|
|
idNumberError: error,
|
|
showIdNumberHint: showHint,
|
|
isIdNumberValid: isValid
|
|
}, () => {
|
|
this.checkForm();
|
|
});
|
|
},
|
|
|
|
onIdNumberFocus() {
|
|
this.setData({
|
|
idNumberFocus: true,
|
|
showIdNumberHint: true // 获得焦点时显示提示
|
|
});
|
|
},
|
|
|
|
onIdNumberBlur() {
|
|
const { idNumber } = this.data;
|
|
let error = '';
|
|
let isValid = false;
|
|
|
|
// 最终验证
|
|
if (idNumber) {
|
|
if (idNumber.length < 18) {
|
|
error = '还需输入' + (18 - idNumber.length) + '位';
|
|
} else if (idNumber.length === 18) {
|
|
if (this.validateIdNumber(idNumber)) {
|
|
isValid = true;
|
|
} else {
|
|
error = '身份证号格式不正确';
|
|
}
|
|
}
|
|
}
|
|
|
|
this.setData({
|
|
idNumberFocus: false,
|
|
idNumberError: error,
|
|
isIdNumberValid: isValid,
|
|
// 失去焦点时,如果内容为空或验证失败,保持提示显示
|
|
showIdNumberHint: !!(idNumber && !isValid)
|
|
});
|
|
},
|
|
|
|
// 清除身份证号
|
|
clearIdNumber() {
|
|
this.setData({
|
|
idNumber: '',
|
|
idNumberError: '',
|
|
showIdNumberHint: false,
|
|
isIdNumberValid: false
|
|
}, () => {
|
|
this.checkForm();
|
|
});
|
|
},
|
|
|
|
// 身份证验证函数
|
|
validateIdNumber(idNumber) {
|
|
// 基础格式验证
|
|
if (!/^\d{17}[\dXx]$/.test(idNumber)) {
|
|
return false;
|
|
}
|
|
|
|
// 地区码验证(简化的验证,实际应该更严谨)
|
|
const areaCode = idNumber.substring(0, 2);
|
|
const validAreaCodes = ['11', '12', '13', '14', '15', '21', '22', '23',
|
|
'31', '32', '33', '34', '35', '36', '37', '41',
|
|
'42', '43', '44', '45', '46', '50', '51', '52',
|
|
'53', '54', '61', '62', '63', '64', '65'];
|
|
|
|
if (!validAreaCodes.includes(areaCode)) {
|
|
return false;
|
|
}
|
|
|
|
// 出生日期验证
|
|
const year = parseInt(idNumber.substring(6, 10));
|
|
const month = parseInt(idNumber.substring(10, 12));
|
|
const day = parseInt(idNumber.substring(12, 14));
|
|
|
|
const currentYear = new Date().getFullYear();
|
|
if (year < 1900 || year > currentYear) return false;
|
|
if (month < 1 || month > 12) return false;
|
|
if (day < 1 || day > 31) return false;
|
|
|
|
// 校验码验证
|
|
const checkCode = idNumber.charAt(17).toUpperCase();
|
|
const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
|
|
const checkCodes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
|
|
|
|
let sum = 0;
|
|
for (let i = 0; i < 17; i++) {
|
|
sum += parseInt(idNumber.charAt(i)) * weights[i];
|
|
}
|
|
|
|
const mod = sum % 11;
|
|
return checkCode === checkCodes[mod];
|
|
},
|
|
|
|
// 协议处理
|
|
toggleAgreement() {
|
|
const newAgreed = !this.data.agreed;
|
|
this.setData({
|
|
agreed: newAgreed
|
|
}, () => {
|
|
this.checkForm();
|
|
});
|
|
},
|
|
|
|
// 显示协议弹窗
|
|
showAgreementModal() {
|
|
const title = '用户服务协议';
|
|
const content = `欢迎您使用"与牧同行"服务!\n\n在使用我们的服务前,请您仔细阅读并同意以下协议:\n\n1. 服务条款\n您在使用与牧同行提供的各项服务时,应当遵守相关法律法规,不得从事任何非法行为。\n\n2. 用户责任\n您需要保证所提供信息的真实性、准确性和完整性。\n\n3. 服务变更\n我们保留随时修改、暂停或终止服务的权利。\n\n4. 免责声明\n在法律法规允许的最大范围内,我们对因使用服务而产生的任何间接损失不承担责任。\n\n5. 法律适用\n本协议的订立、执行和解释及争议的解决均适用中华人民共和国法律。\n\n请您确保已阅读并理解以上条款。`;
|
|
|
|
this.showModal(title, content);
|
|
},
|
|
|
|
// 显示隐私弹窗
|
|
showPrivacyModal() {
|
|
const title = '隐私保护协议';
|
|
const content = `我们非常重视您的隐私保护,请您仔细阅读以下隐私政策:\n\n1. 信息收集\n我们仅收集为您提供服务所必需的信息,包括姓名、身份证号等实名信息。\n\n2. 信息使用\n您的信息仅用于身份验证和服务提供,不会用于其他商业用途。\n\n3. 信息保护\n我们采用先进的安全技术保护您的信息,防止未经授权的访问、使用或泄露。\n\n4. 信息共享\n除非获得您的明确同意,我们不会向第三方共享您的个人信息。\n\n5. 您的权利\n您可以随时查看、更正或删除您的个人信息。\n\n6. 政策更新\n我们可能会不时更新本隐私政策,更新后的政策将在本页面公布。\n\n我们承诺严格遵守相关法律法规,保护您的个人信息安全。`;
|
|
|
|
this.showModal(title, content);
|
|
},
|
|
|
|
// 显示弹窗
|
|
showModal(title, content) {
|
|
this.setData({
|
|
modalTitle: title,
|
|
modalContent: content,
|
|
showModal: true
|
|
});
|
|
},
|
|
|
|
// 关闭弹窗
|
|
closeModal() {
|
|
this.setData({ showModal: false });
|
|
},
|
|
|
|
// 显示错误弹窗
|
|
showErrorModal(title, message) {
|
|
this.setData({
|
|
errorTitle: title || '认证失败',
|
|
errorMessage: message || '请检查信息后重试',
|
|
showErrorModal: true
|
|
});
|
|
},
|
|
|
|
// 关闭错误弹窗
|
|
closeErrorModal() {
|
|
this.setData({
|
|
showErrorModal: false,
|
|
isSubmitting: false // 关闭错误弹窗时重置提交状态
|
|
});
|
|
},
|
|
|
|
// 阻止事件冒泡
|
|
stopPropagation(e) {
|
|
// 阻止冒泡
|
|
},
|
|
|
|
// 检查表单
|
|
checkForm() {
|
|
const {
|
|
isNameValid,
|
|
isIdNumberValid,
|
|
agreed
|
|
} = this.data;
|
|
|
|
const isValid = isNameValid &&
|
|
isIdNumberValid &&
|
|
agreed;
|
|
|
|
this.setData({
|
|
canSubmit: isValid
|
|
});
|
|
},
|
|
|
|
// 提交认证
|
|
async submitAuth() {
|
|
if (!this.data.canSubmit || this.data.isSubmitting) return;
|
|
|
|
// 最终验证
|
|
const { name, idNumber } = this.data;
|
|
|
|
if (!/^[\u4e00-\u9fa5]{2,10}$/.test(name)) {
|
|
this.setData({
|
|
nameError: '姓名应为2-10个汉字',
|
|
showNameHint: true,
|
|
canSubmit: false
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (!this.validateIdNumber(idNumber)) {
|
|
this.setData({
|
|
idNumberError: '身份证号格式不正确',
|
|
showIdNumberHint: true,
|
|
canSubmit: false
|
|
});
|
|
return;
|
|
}
|
|
|
|
this.setData({
|
|
isSubmitting: true,
|
|
currentStep: 2,
|
|
lineProgress1: 100,
|
|
lineProgress2: 50
|
|
});
|
|
|
|
// 显示加载动画
|
|
wx.showLoading({
|
|
title: '正在验证...',
|
|
mask: true
|
|
});
|
|
|
|
try {
|
|
// 调用实名认证接口
|
|
const result = await this.callRealNameApi(name, idNumber);
|
|
|
|
wx.hideLoading();
|
|
|
|
if (result.success) {
|
|
// 处理身份证号脱敏显示
|
|
const maskedId = idNumber.substring(0, 4) + '**********' + idNumber.substring(14);
|
|
|
|
// 显示成功弹窗
|
|
this.showSuccessModal(maskedId);
|
|
|
|
this.setData({
|
|
isSubmitting: false,
|
|
currentStep: 3,
|
|
lineProgress2: 100
|
|
});
|
|
} else {
|
|
// 接口返回失败
|
|
this.handleApiError(result);
|
|
}
|
|
|
|
} catch (error) {
|
|
wx.hideLoading();
|
|
this.setData({
|
|
isSubmitting: false,
|
|
currentStep: 1,
|
|
lineProgress2: 0
|
|
});
|
|
|
|
this.showErrorModal('网络错误', '认证请求失败,请检查网络连接后重试');
|
|
console.error('实名认证错误:', error);
|
|
}
|
|
},
|
|
|
|
// 调用实名认证API
|
|
async callRealNameApi(realName, idCard) {
|
|
return new Promise((resolve, reject) => {
|
|
http.realName({
|
|
data: {
|
|
realName: realName, // 姓名字段
|
|
idCard: idCard // 身份证号字段
|
|
},
|
|
success: (res) => {
|
|
console.log('API响应:', res);
|
|
|
|
// 根据实际API响应结构调整
|
|
if (res.code === 200 || res.code === 0) {
|
|
resolve({
|
|
success: true,
|
|
data: res.data || {}
|
|
});
|
|
} else {
|
|
resolve({
|
|
success: false,
|
|
code: res.code,
|
|
message: res.msg || '认证失败'
|
|
});
|
|
}
|
|
},
|
|
fail: (err) => {
|
|
reject(err);
|
|
}
|
|
});
|
|
});
|
|
},
|
|
|
|
// 处理API错误
|
|
handleApiError(result) {
|
|
console.log('API错误:', result);
|
|
|
|
this.setData({
|
|
isSubmitting: false,
|
|
currentStep: 1,
|
|
lineProgress2: 0
|
|
});
|
|
|
|
// 根据错误码显示不同提示
|
|
let title = '认证失败';
|
|
let message = result.message || '请检查信息后重试';
|
|
|
|
// 根据不同的错误码定制提示信息
|
|
if (result.code === 500) {
|
|
message = result.message || '服务器内部错误,请稍后重试';
|
|
} else if (result.code === 400) {
|
|
message = result.message || '请求参数错误,请检查填写的信息';
|
|
} else if (result.code === 401) {
|
|
message = result.message || '身份验证失败,请重新登录';
|
|
} else if (result.code === 403) {
|
|
message = result.message || '认证信息不正确,请核对姓名和身份证号';
|
|
}
|
|
|
|
this.showErrorModal(title, message);
|
|
},
|
|
|
|
// 显示成功弹窗
|
|
showSuccessModal(maskedId) {
|
|
this.setData({
|
|
maskedIdNumber: maskedId,
|
|
showSuccessModal: true
|
|
});
|
|
},
|
|
|
|
// 关闭成功弹窗
|
|
closeSuccessModal() {
|
|
this.setData({ showSuccessModal: false });
|
|
},
|
|
|
|
// 返回
|
|
goToHome() {
|
|
this.closeSuccessModal();
|
|
wx.switchTab({
|
|
url: '/pages/personal/personal'
|
|
});
|
|
}
|
|
});
|