与牧同行-小程序用户端
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

// 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'
});
}
});