import { countDown } from 'timer'; import { BaseLifeCycle } from 'lifeCycle'; import { BaseLog } from 'base-log' const log = new BaseLog('PhoneVerify'); /** * 生命周期 * created(button, view) -> beforeSend(button) -> sended(button, view, data) -> * [updated(button)](如果发送成功) -> destroyed(button)(如果发送成功) * 注:bindButton方法会贯穿所有声明周期 */ // 远程发送返回结果格式 export interface RemoteSendData { passed: boolean // 是否通过 message?: string // 提示 res? // 远端返回结果 } export interface ButtonData { text: string // 按钮文案 locked?: boolean // 是否禁止点击发送 } // 前端获取到的数据格式 export interface ViewData { message?: string // 相关信息提示 passed?: boolean } // 配置格式 export interface PhoneVerifyOption{ remoteSend? // 发送接口 unit initText // 初始化按钮文案,默认为发送验证码 sendingText successText failText // 失败时按钮文案,默认为重新发送 successMessage failMessage? // 远程发送失败文案 interval // 发送间隔 } export interface CreateConfig extends BaseLifeCycle{ bindButton? // 按钮绑定,所有生命周期均会调用 beforeSend? sended? // 已发送生命周期 } // 默认配置 let defaultOption:PhoneVerifyOption = { interval: 60, unit: '秒', initText: '发送验证码', sendingText: '发送中', successText: '发送成功', failText: '重新发送', successMessage: '发送成功', failMessage: '发送失败' } let modeOptions = {}; let countDownTimers = []; export class PhoneVerify { locked option // == 初始化,默认添加default mode static init = (option:PhoneVerifyOption) => { PhoneVerify.addMode('default', option); } // == 添加验证模式 static addMode = (modeName, option:PhoneVerifyOption) => { const modeOption = Object.assign({}, defaultOption, option); if(modeOptions[modeName]) { log.warn(`已存在mode名为${modeName}手机验证模式,请勿重复添加!`); return; } modeOptions[modeName] = modeOption; } // == 移除验证模式 static removeMode = (modeName) => { delete modeOptions[modeName]; } // == 每次实例化创建默认配置 constructor(option:PhoneVerifyOption) { if(option) defaultOption = Object.assign({}, defaultOption, option); } // == 根据模式创建短信发送方法 createByMode = (modeName, config:CreateConfig) => { const modeDefaultOption = modeOptions[modeName] || {}; // 模式默认配置低于实例化时创建的默认配置 const option = Object.assign({}, modeDefaultOption, defaultOption); return this.create(config, option); } // == 创建短信发送方法 create = (config:CreateConfig, option?:PhoneVerifyOption) => { option = option || modeOptions['default'] || defaultOption; this.option = Object.assign({}, option, config); const {initText, created, bindButton} = this.option; // 调用构建生命周期方法 if(created) created({text:initText},{}); if(bindButton) bindButton({text:initText}, 'created'); this.clearTimers(); return this.send; } // 定时器 clearTimers = () => { if(countDownTimers){ for (let countDownTimer of countDownTimers) { if(countDownTimer.finish) countDownTimer.finish(); } } } // == 发送验证码 send = (params) => { if(this.locked) return false; this.locked = true; const { bindButton, remoteSend, successMessage, failMessage, beforeSend, sendingText } = this.option; if(beforeSend) beforeSend({text:sendingText,locked:this.locked}); if(bindButton) bindButton({text:sendingText,locked:this.locked},'beforeSend'); if(remoteSend){ return remoteSend(params).then((data:RemoteSendData) => { return this.afterSend(data); },() => { return this.afterSend({passed:false, message:failMessage}); }); }else{ return this.afterSend({passed:true, message:successMessage}); } } // == 发送后处理 afterSend = (data:RemoteSendData) => { const {successText, failText, sended, bindButton} = this.option; const {passed, message} = data; if(passed){ if(sended) sended( {text:successText, locked:this.locked}, {message, passed}, data ); if(bindButton) bindButton({text:successText, locked:this.locked},'sended'); const countDownTimer = this.setCountDown(); countDownTimers.push(countDownTimer); }else{ this.locked = false; if(sended) sended( {text:failText, locked:this.locked}, {message, passed}, data ); if(bindButton) bindButton({text:failText, locked:this.locked},'sended'); } } // == 设置倒计时 setCountDown = () => { const {interval, updated, destroyed, initText, bindButton, unit} = this.option; return countDown(interval, { pure: true, created: (second) => { if(updated) updated({text:`${second}${unit}`, locked:this.locked}); if(bindButton) bindButton({text:`${second}${unit}`,locked:this.locked},'updated'); }, updated:(second) => { if(updated) updated({text:`${second}${unit}`, locked:this.locked}); if(bindButton) bindButton({text:`${second}${unit}`,locked:this.locked},'updated'); }, destroyed: () => { this.locked = false; if(destroyed) destroyed({text: initText, locked:this.locked}); if(bindButton) bindButton({text:initText,locked:this.locked},'destroyed'); } }); } }