const AuthPageUtil = { smsTimers: {}, slideUuid: '', slideX: 0, slideToken: '', isPhone(phone) { return /^1[3-9]\d{9}$/.test(String(phone || '').trim()); }, isPassword(password) { const value = String(password || ''); return value.length >= 6 && value.length <= 20; }, loadVerifyType() { return ApiClient.get(ApiClient.API.authVerifyConfig, {}, { publicRequest: true }) .then((res) => { const data = (res && res.data) || res || {}; const yes = (value) => value === true || value === 1 || value === '1' || String(value).toLowerCase() === 'true'; if ( yes(data.lottery_slide_captcha) || yes(data.lotterySlideCaptcha) || yes(data.slideCaptchaEnabled) || yes(data.slideEnabled) || data.verifyType === 'slide' ) { return 'slide'; } return 'captcha'; }) .catch(() => 'captcha'); }, buildSmsParams(options = {}) { const params = { phoneNumber: options.phoneNumber, }; if (options.verifyType === 'slide') { params.verifyType = 'slide'; params.slideToken = options.slideToken || this.slideToken; params.slideUuid = options.slideUuid || this.slideUuid; params.slideX = options.slideX || this.slideX; } if (options.verifyType === 'captcha') { params.verifyType = 'captcha'; params.code = options.code || ''; params.uuid = options.uuid || ''; } return params; }, sendSmsCode(options) { return ApiClient.get(ApiClient.API.authSmsCode, this.buildSmsParams(options), { publicRequest: true, }); }, sendForgotPasswordSmsCode(options) { return ApiClient.get(ApiClient.API.authForgotPasswordSmsCode, this.buildSmsParams(options), { publicRequest: true, }); }, getImageCaptcha() { return ApiClient.get(ApiClient.API.authCode, {}, { publicRequest: true }); }, installSlideCaptchaTenantHeader() { if (typeof window === 'undefined' || window.__cxzSlideCaptchaTenantPatched) return; window.__cxzSlideCaptchaTenantPatched = true; const isSlideCaptchaUrl = (url) => String(url || '').indexOf('/api/web/auth/slide-captcha') >= 0; const tenantId = () => typeof ApiClient !== 'undefined' && ApiClient.tenantId ? ApiClient.tenantId : '000000'; if (typeof window.fetch === 'function') { const nativeFetch = window.fetch.bind(window); window.fetch = function (input, init = {}) { const requestUrl = typeof input === 'string' ? input : input && input.url; if (!isSlideCaptchaUrl(requestUrl)) return nativeFetch(input, init); const isRequestInput = typeof Request !== 'undefined' && input instanceof Request; const headers = new Headers(init.headers || (isRequestInput ? input.headers : undefined)); headers.set('tenantId', tenantId()); if (isRequestInput) { return nativeFetch(new Request(input, { ...init, headers })); } return nativeFetch(input, { ...init, headers }); }; } if (window.XMLHttpRequest && window.XMLHttpRequest.prototype) { const xhrProto = window.XMLHttpRequest.prototype; const nativeOpen = xhrProto.open; const nativeSetRequestHeader = xhrProto.setRequestHeader; const nativeSend = xhrProto.send; xhrProto.open = function (method, url, ...args) { this.__cxzSlideCaptchaRequest = isSlideCaptchaUrl(url); this.__cxzSlideTenantHeaderSet = false; return nativeOpen.call(this, method, url, ...args); }; xhrProto.setRequestHeader = function (name, value) { if (this.__cxzSlideCaptchaRequest && String(name || '').toLowerCase() === 'tenantid') { this.__cxzSlideTenantHeaderSet = true; } return nativeSetRequestHeader.call(this, name, value); }; xhrProto.send = function (...args) { if (this.__cxzSlideCaptchaRequest && !this.__cxzSlideTenantHeaderSet) { nativeSetRequestHeader.call(this, 'tenantId', tenantId()); this.__cxzSlideTenantHeaderSet = true; } return nativeSend.apply(this, args); }; } }, startSmsCountdown(buttonSelector, seconds = 60) { const $button = layui.$(buttonSelector); let left = seconds; clearInterval(this.smsTimers[buttonSelector]); $button.prop('disabled', true).text(`${left}s后重发`); this.smsTimers[buttonSelector] = setInterval(() => { left -= 1; if (left <= 0) { clearInterval(this.smsTimers[buttonSelector]); $button.prop('disabled', false).text('获取验证码'); return; } $button.text(`${left}s后重发`); }, 1000); }, loadSlideCaptchaScript() { this.installSlideCaptchaTenantHeader(); if (window.SlideCaptcha) return Promise.resolve(window.SlideCaptcha); if (window.__slideCaptchaLoading) return window.__slideCaptchaLoading; window.__slideCaptchaLoading = new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = `${ApiClient.baseUrl}/static/slide-captcha/slide-captcha.js`; script.dataset.apiBase = ApiClient.baseUrl || ''; script.dataset.tenantId = ApiClient.tenantId || '000000'; script.onload = () => { if (window.SlideCaptcha) resolve(window.SlideCaptcha); else reject(new Error('滑动验证组件加载失败')); }; script.onerror = () => reject(new Error('滑动验证组件加载失败')); document.body.appendChild(script); }); return window.__slideCaptchaLoading; }, openSlideCaptcha(options = {}) { this.installSlideCaptchaTenantHeader(); this.loadSlideCaptchaScript() .then((SlideCaptcha) => { SlideCaptcha.open({ title: options.title || '安全验证', subtitle: options.subtitle || '拖动滑块完成验证', apiBase: ApiClient.baseUrl || '', tenantId: ApiClient.tenantId || '000000', headers: ApiClient.publicHeaders(), onSuccess: (result) => { const data = result || {}; const nested = data.data || {}; this.slideToken = data.slideToken || data.token || data.verifyToken || nested.slideToken || nested.token || nested.verifyToken || ''; this.slideUuid = data.slideUuid || data.uuid || nested.slideUuid || nested.uuid || ''; this.slideX = Number(data.slideX || data.x || nested.slideX || nested.x || 0) || 0; if (!this.slideToken && !this.slideUuid) { if (typeof options.onError === 'function') { options.onError(new Error('滑动验证未返回凭证,请重试')); } return; } if (typeof options.onSuccess === 'function') { options.onSuccess({ slideToken: this.slideToken, slideUuid: this.slideUuid, slideX: this.slideX, }); } }, onCancel: options.onCancel, onError: options.onError, }); }) .catch((error) => { if (typeof options.onError === 'function') options.onError(error); }); }, }; if (typeof window !== 'undefined') { window.AuthPageUtil = AuthPageUtil; }