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

390 lines
10 KiB

  1. import http from '../../../utils/api'
  2. const baseUrl = require('../../../utils/baseUrl')
  3. Page({
  4. data: {
  5. // 表单数据
  6. name: '',
  7. idNumber: '',
  8. // 焦点状态
  9. nameFocus: false,
  10. idNumberFocus: false,
  11. // 错误提示
  12. nameError: '',
  13. idNumberError: '',
  14. // 提示显示控制 - 修复:初始为false
  15. showNameHint: false,
  16. showIdNumberHint: false,
  17. // 验证状态
  18. isNameValid: false,
  19. isIdNumberValid: false,
  20. // 协议状态
  21. agreed: false,
  22. // 提交状态
  23. canSubmit: false,
  24. isSubmitting: false,
  25. // 进度条
  26. currentStep: 1,
  27. lineProgress1: 0,
  28. lineProgress2: 0,
  29. // 弹窗数据
  30. showModal: false,
  31. modalTitle: '',
  32. modalContent: '',
  33. // 成功弹窗数据
  34. showSuccessModal: false,
  35. maskedIdNumber: ''
  36. },
  37. onLoad() {
  38. // 页面加载时启动进度条动画
  39. setTimeout(() => {
  40. this.setData({ lineProgress1: 50 });
  41. }, 600);
  42. },
  43. // 姓名输入处理 - 修复:简化逻辑
  44. onNameInput(e) {
  45. const value = e.detail.value.trim();
  46. let error = '';
  47. let showHint = true;
  48. let isValid = false;
  49. if (value) {
  50. if (!/^[\u4e00-\u9fa5]{2,10}$/.test(value)) {
  51. error = '姓名应为2-10个汉字';
  52. } else {
  53. isValid = true;
  54. // 验证通过时保持提示显示,但无错误
  55. }
  56. } else {
  57. // 内容为空时显示正常提示
  58. error = '';
  59. }
  60. this.setData({
  61. name: value,
  62. nameError: error,
  63. showNameHint: showHint,
  64. isNameValid: isValid
  65. }, () => {
  66. this.checkForm();
  67. });
  68. },
  69. onNameFocus() {
  70. this.setData({
  71. nameFocus: true,
  72. showNameHint: true // 获得焦点时显示提示
  73. });
  74. },
  75. onNameBlur() {
  76. const { name } = this.data;
  77. this.setData({
  78. nameFocus: false,
  79. // 失去焦点时,如果内容为空或验证失败,保持提示显示
  80. showNameHint: !!(name && !this.data.isNameValid)
  81. });
  82. },
  83. // 清除姓名
  84. clearName() {
  85. this.setData({
  86. name: '',
  87. nameError: '',
  88. showNameHint: false,
  89. isNameValid: false
  90. }, () => {
  91. this.checkForm();
  92. });
  93. },
  94. // 身份证号输入处理 - 修复:简化逻辑
  95. onIdNumberInput(e) {
  96. const value = e.detail.value.trim().toUpperCase();
  97. let error = '';
  98. let showHint = true;
  99. let isValid = false;
  100. if (value) {
  101. if (value.length < 18) {
  102. error = '还需输入' + (18 - value.length) + '位';
  103. } else if (value.length === 18) {
  104. if (this.validateIdNumber(value)) {
  105. isValid = true;
  106. // 验证通过时保持提示显示,但无错误
  107. } else {
  108. error = '身份证号格式不正确';
  109. }
  110. }
  111. } else {
  112. // 内容为空时显示正常提示
  113. error = '';
  114. }
  115. this.setData({
  116. idNumber: value,
  117. idNumberError: error,
  118. showIdNumberHint: showHint,
  119. isIdNumberValid: isValid
  120. }, () => {
  121. this.checkForm();
  122. });
  123. },
  124. onIdNumberFocus() {
  125. this.setData({
  126. idNumberFocus: true,
  127. showIdNumberHint: true // 获得焦点时显示提示
  128. });
  129. },
  130. onIdNumberBlur() {
  131. const { idNumber } = this.data;
  132. let error = '';
  133. let isValid = false;
  134. // 最终验证
  135. if (idNumber) {
  136. if (idNumber.length < 18) {
  137. error = '还需输入' + (18 - idNumber.length) + '位';
  138. } else if (idNumber.length === 18) {
  139. if (this.validateIdNumber(idNumber)) {
  140. isValid = true;
  141. } else {
  142. error = '身份证号格式不正确';
  143. }
  144. }
  145. }
  146. this.setData({
  147. idNumberFocus: false,
  148. idNumberError: error,
  149. isIdNumberValid: isValid,
  150. // 失去焦点时,如果内容为空或验证失败,保持提示显示
  151. showIdNumberHint: !!(idNumber && !isValid)
  152. });
  153. },
  154. // 清除身份证号
  155. clearIdNumber() {
  156. this.setData({
  157. idNumber: '',
  158. idNumberError: '',
  159. showIdNumberHint: false,
  160. isIdNumberValid: false
  161. }, () => {
  162. this.checkForm();
  163. });
  164. },
  165. // 身份证验证函数
  166. validateIdNumber(idNumber) {
  167. // 基础格式验证
  168. if (!/^\d{17}[\dXx]$/.test(idNumber)) {
  169. return false;
  170. }
  171. // 地区码验证(简化的验证,实际应该更严谨)
  172. const areaCode = idNumber.substring(0, 2);
  173. const validAreaCodes = ['11', '12', '13', '14', '15', '21', '22', '23',
  174. '31', '32', '33', '34', '35', '36', '37', '41',
  175. '42', '43', '44', '45', '46', '50', '51', '52',
  176. '53', '54', '61', '62', '63', '64', '65'];
  177. if (!validAreaCodes.includes(areaCode)) {
  178. return false;
  179. }
  180. // 出生日期验证
  181. const year = parseInt(idNumber.substring(6, 10));
  182. const month = parseInt(idNumber.substring(10, 12));
  183. const day = parseInt(idNumber.substring(12, 14));
  184. const currentYear = new Date().getFullYear();
  185. if (year < 1900 || year > currentYear) return false;
  186. if (month < 1 || month > 12) return false;
  187. if (day < 1 || day > 31) return false;
  188. // 校验码验证
  189. const checkCode = idNumber.charAt(17).toUpperCase();
  190. const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
  191. const checkCodes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
  192. let sum = 0;
  193. for (let i = 0; i < 17; i++) {
  194. sum += parseInt(idNumber.charAt(i)) * weights[i];
  195. }
  196. const mod = sum % 11;
  197. return checkCode === checkCodes[mod];
  198. },
  199. // 协议处理
  200. toggleAgreement() {
  201. const newAgreed = !this.data.agreed;
  202. this.setData({
  203. agreed: newAgreed
  204. }, () => {
  205. this.checkForm();
  206. });
  207. },
  208. // 显示协议弹窗
  209. showAgreementModal() {
  210. const title = '用户服务协议';
  211. const content = `欢迎您使用"与牧同行"服务!\n\n在使用我们的服务前,请您仔细阅读并同意以下协议:\n\n1. 服务条款\n您在使用与牧同行提供的各项服务时,应当遵守相关法律法规,不得从事任何非法行为。\n\n2. 用户责任\n您需要保证所提供信息的真实性、准确性和完整性。\n\n3. 服务变更\n我们保留随时修改、暂停或终止服务的权利。\n\n4. 免责声明\n在法律法规允许的最大范围内,我们对因使用服务而产生的任何间接损失不承担责任。\n\n5. 法律适用\n本协议的订立、执行和解释及争议的解决均适用中华人民共和国法律。\n\n请您确保已阅读并理解以上条款。`;
  212. this.showModal(title, content);
  213. },
  214. // 显示隐私弹窗
  215. showPrivacyModal() {
  216. const title = '隐私保护协议';
  217. const content = `我们非常重视您的隐私保护,请您仔细阅读以下隐私政策:\n\n1. 信息收集\n我们仅收集为您提供服务所必需的信息,包括姓名、身份证号等实名信息。\n\n2. 信息使用\n您的信息仅用于身份验证和服务提供,不会用于其他商业用途。\n\n3. 信息保护\n我们采用先进的安全技术保护您的信息,防止未经授权的访问、使用或泄露。\n\n4. 信息共享\n除非获得您的明确同意,我们不会向第三方共享您的个人信息。\n\n5. 您的权利\n您可以随时查看、更正或删除您的个人信息。\n\n6. 政策更新\n我们可能会不时更新本隐私政策,更新后的政策将在本页面公布。\n\n我们承诺严格遵守相关法律法规,保护您的个人信息安全。`;
  218. this.showModal(title, content);
  219. },
  220. // 显示弹窗
  221. showModal(title, content) {
  222. this.setData({
  223. modalTitle: title,
  224. modalContent: content,
  225. showModal: true
  226. });
  227. },
  228. // 关闭弹窗
  229. closeModal() {
  230. this.setData({ showModal: false });
  231. },
  232. // 阻止事件冒泡
  233. stopPropagation(e) {
  234. // 阻止冒泡
  235. },
  236. // 检查表单
  237. checkForm() {
  238. const {
  239. isNameValid,
  240. isIdNumberValid,
  241. agreed
  242. } = this.data;
  243. const isValid = isNameValid &&
  244. isIdNumberValid &&
  245. agreed;
  246. this.setData({
  247. canSubmit: isValid
  248. });
  249. },
  250. // 提交认证
  251. async submitAuth() {
  252. if (!this.data.canSubmit || this.data.isSubmitting) return;
  253. // 最终验证
  254. const { name, idNumber } = this.data;
  255. if (!/^[\u4e00-\u9fa5]{2,10}$/.test(name)) {
  256. this.setData({
  257. nameError: '姓名应为2-10个汉字',
  258. showNameHint: true,
  259. canSubmit: false
  260. });
  261. return;
  262. }
  263. if (!this.validateIdNumber(idNumber)) {
  264. this.setData({
  265. idNumberError: '身份证号格式不正确',
  266. showIdNumberHint: true,
  267. canSubmit: false
  268. });
  269. return;
  270. }
  271. this.setData({
  272. isSubmitting: true,
  273. currentStep: 2,
  274. lineProgress1: 100,
  275. lineProgress2: 50
  276. });
  277. // 显示加载动画
  278. wx.showLoading({
  279. title: '正在验证...',
  280. mask: true
  281. });
  282. try {
  283. // 模拟API请求
  284. await new Promise(resolve => setTimeout(resolve, 1500));
  285. wx.hideLoading();
  286. // 处理身份证号脱敏显示
  287. const maskedId = idNumber.substring(0, 4) + '**********' + idNumber.substring(14);
  288. // 显示成功弹窗
  289. this.showSuccessModal(maskedId);
  290. // 保存认证信息
  291. wx.setStorageSync('realNameAuth', {
  292. name: name,
  293. idNumber: idNumber,
  294. certified: true,
  295. certifiedTime: new Date().getTime()
  296. });
  297. this.setData({
  298. isSubmitting: false,
  299. currentStep: 3,
  300. lineProgress2: 100
  301. });
  302. } catch (error) {
  303. wx.hideLoading();
  304. this.setData({ isSubmitting: false });
  305. wx.showToast({
  306. title: '认证失败,请重试',
  307. icon: 'error',
  308. duration: 2000
  309. });
  310. }
  311. },
  312. // 显示成功弹窗
  313. showSuccessModal(maskedId) {
  314. this.setData({
  315. maskedIdNumber: maskedId,
  316. showSuccessModal: true
  317. });
  318. },
  319. // 关闭成功弹窗
  320. closeSuccessModal() {
  321. this.setData({ showSuccessModal: false });
  322. },
  323. // 前往首页
  324. goToHome() {
  325. this.closeSuccessModal();
  326. wx.switchTab({
  327. url: '/pages/personal/personal'
  328. });
  329. }
  330. });