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.

351 lines
7.2 KiB

4 hours ago
/**
* 2.0
*
*/
// 验证码插件实例
let AliyunCaptchaPluginInterface: any = null;
// 计时器
let timer: number | null = null;
// 页面实例引用
let pageInstance: any = null;
// 是否在发送中(防止重复请求)
let isSending: boolean = false;
// 倒计时剩余秒数
let remainingSeconds: number = 0;
// 发送验证码的接口配置
interface SendCodeConfig {
url: string;
mobileField?: string;
extraData?: Record<string, any>;
}
// 验证码配置选项
interface CaptchaOptions {
sceneId: string;
sendCodeConfig: SendCodeConfig;
onSendSuccess?: () => void;
onSendFail?: (err: any) => void;
countdown?: number;
}
// 当前配置
let currentOptions: CaptchaOptions | null = null;
/**
*
*/
function initPlugin() {
if (!AliyunCaptchaPluginInterface) {
AliyunCaptchaPluginInterface = requirePlugin('AliyunCaptcha');
}
}
/**
*
* @param captchaVerifyParam
*/
async function successCallback(captchaVerifyParam: string) {
if (!pageInstance || !currentOptions) return;
if (isSending) {
wx.showToast({
title: '发送中,请稍候',
icon: 'none',
});
return;
}
const { sendCodeConfig, onSendSuccess, onSendFail, countdown = 60 } = currentOptions;
const mobileField = sendCodeConfig.mobileField || 'mobile';
const mobile = pageInstance.data[mobileField];
if (!mobile) {
wx.showToast({
title: '请输入手机号',
icon: 'none',
});
return;
}
isSending = true;
updateCountdownText('发送中...');
try {
const res = await wx.ajax({
method: 'POST',
url: sendCodeConfig.url,
data: {
[mobileField]: mobile,
captchaVerifyParam,
...sendCodeConfig.extraData,
},
});
wx.showToast({
icon: 'none',
title: '验证码已发送~',
});
// 开始倒计时
startCountdown(countdown);
// 执行成功回调
onSendSuccess?.();
return res;
} catch (err: any) {
// 发送失败,重置状态(包括阿里云插件,以便下次重新验证)
resetCaptchaState(true);
const errorMsg = err.data?.msg || err.message || '发送失败,请重试';
wx.showToast({
title: errorMsg,
icon: 'none',
duration: 2000,
});
onSendFail?.(err);
throw err;
} finally {
isSending = false;
}
}
/**
*
* @param error
*/
function failCallback(error: any) {
console.error('阿里云验证码验证失败:', error);
wx.showToast({
title: '验证失败,请重试',
icon: 'none',
});
}
/**
*
* @param seconds
*/
function startCountdown(seconds: number) {
// 清除之前的计时器
if (timer) {
clearInterval(timer);
timer = null;
}
remainingSeconds = seconds;
updateCountdownText(`${remainingSeconds}s后重新发送`);
timer = setInterval(() => {
remainingSeconds--;
if (remainingSeconds <= 0) {
// 倒计时结束,重置状态(包括阿里云插件,以便下次重新验证)
resetCaptchaState(true);
} else {
updateCountdownText(`${remainingSeconds}s后重新发送`);
}
}, 1000) as unknown as number;
}
/**
*
* 使
*/
function resetCaptchaState(resetPluginToo: boolean = false) {
if (timer) {
clearInterval(timer);
timer = null;
}
remainingSeconds = 0;
isSending = false;
updateCountdownText('发送验证码');
// 如果需要,同时重置阿里云插件状态(接口失败时使用)
if (resetPluginToo) {
refreshCaptchaComponent();
}
}
/**
*
*
*/
function resetAliyunPlugin(): void {
// 销毁插件实例,下次会自动重新初始化
AliyunCaptchaPluginInterface = null;
}
/**
*
*
*/
export function refreshCaptchaComponent(callback?: () => void): void {
if (!pageInstance) return;
// 卸载组件
pageInstance.setData({
loadCaptcha: false,
});
// 重置插件实例
resetAliyunPlugin();
// 延迟重新加载组件,确保卸载完成
setTimeout(() => {
if (!pageInstance || !currentOptions) return;
// 重新初始化配置
const pluginProps = {
SceneId: currentOptions.sceneId,
mode: 'popup',
success: successCallback.bind(pageInstance),
fail: failCallback.bind(pageInstance),
slideStyle: {
width: 540,
height: 60,
},
language: 'cn',
region: 'cn',
};
// 重新加载组件
pageInstance.setData({
loadCaptcha: true,
pluginProps,
});
if (callback) callback();
}, 100);
}
/**
*
* @param text
*/
function updateCountdownText(text: string) {
if (pageInstance) {
pageInstance.setData({ codeText: text });
}
}
/**
*
* @param page
* @param options
* @returns
*/
export function initCaptcha(page: any, options: CaptchaOptions) {
initPlugin();
pageInstance = page;
currentOptions = options;
const pluginProps = {
SceneId: options.sceneId,
mode: 'popup',
success: successCallback.bind(page),
fail: failCallback.bind(page),
slideStyle: {
width: 540,
height: 60,
},
language: 'cn',
region: 'cn',
};
return {
loadCaptcha: true,
pluginProps,
};
}
/**
*
* @returns
*/
export function showCaptcha(): boolean {
if (!AliyunCaptchaPluginInterface) {
initPlugin();
}
if (isCountingDown()) {
return false;
}
wx.getNetworkType({
success: (res) => {
if (res.networkType === 'none') {
wx.showToast({
title: '网络连接不可用,请检查网络设置',
icon: 'none',
});
return;
}
AliyunCaptchaPluginInterface.show();
},
fail: () => {
AliyunCaptchaPluginInterface.show();
},
});
return true;
}
/**
*
* 使
* @returns
*/
export function showCaptchaWithReset(): boolean {
// 重置插件状态,清除已验证的状态
resetAliyunPlugin();
if (isCountingDown()) {
return false;
}
// 重新初始化后显示
initPlugin();
AliyunCaptchaPluginInterface.show();
return true;
}
/**
*
* @returns
*/
export function isCountingDown(): boolean {
return timer !== null;
}
/**
*
*
*/
export function clearCountdown() {
resetCaptchaState();
}
/**
*
* @returns
*/
export function getCaptchaPlugin() {
if (!AliyunCaptchaPluginInterface) {
initPlugin();
}
return AliyunCaptchaPluginInterface;
}
/**
*
*/
export function destroyCaptcha() {
clearCountdown();
pageInstance = null;
currentOptions = null;
}