import "./captcha.less"; import Slider from "./slider/slider"; import Rotate from "./rotate/rotate"; import Concat from "./concat/concat"; import Disable from "./disable/disable"; import ImageClick from "./image_click/image_click"; import WordImageClick from "./word_image_click/word_image_click"; import { CaptchaConfig, wrapConfig, wrapStyle } from "./config/config"; import { clearAllPreventDefault } from "./common/common"; const template = `
`; function createCaptchaByType(type, tac) { const box = tac.config.domBindEl.find(".captcha-box"); const styleConfig = tac.style; switch (type) { case "SLIDER": return new Slider(box, styleConfig); case "ROTATE": return new Rotate(box, styleConfig); case "CONCAT": return new Concat(box, styleConfig); case "IMAGE_CLICK": return new ImageClick(box, styleConfig); case "WORD_IMAGE_CLICK": return new WordImageClick(box, styleConfig); case "DISABLED": return new Disable(box, styleConfig); default: return null; } } class TianAiCaptcha { constructor(config, style) { this.config = wrapConfig(config); if (this.config.btnRefreshFun) { this.btnRefreshFun = this.config.btnRefreshFun; } if (this.config.btnCloseFun) { this.btnCloseFun = this.config.btnCloseFun; } this.style = wrapStyle(style); } init() { this.destroyWindow(); this.config.domBindEl.append(template); this.domTemplate = this.config.domBindEl.find(".__captcha-parent"); clearAllPreventDefault(this.domTemplate); // 绑定按钮事件 this.config.domBindEl .find(".refresh-btn") .click((el) => { this.btnRefreshFun(el, this); }); this.config.domBindEl .find(".close-btn") .click((el) => { this.btnCloseFun(el, this); }); // 加载验证码 this.reloadCaptcha(); return this; } btnRefreshFun(el, tac) { tac.reloadCaptcha(); } btnCloseFun(el, tac) { tac.destroyWindow(); } reloadCaptcha() { this.showLoading(); this.destroyCaptcha(() => { this.createCaptcha(); }); } showLoading() { this.config.domBindEl .find(".captcha-loading") .css("display", "block"); } closeLoading() { this.config.domBindEl .find(".captcha-loading") .css("display", "none"); } destroyWindow() { if (this.C) { this.C.destroy(); this.C = undefined; } if (this.domTemplate) { this.domTemplate.remove(); } } openCaptcha() { setTimeout(() => { this.C.el.css("transform", "translateX(0)"); }, 10); } createCaptcha() { this.config.requestCaptchaData().then((data) => { this.closeLoading(); if (!data.code) { throw new Error("[TAC] 后台验证码接口数据错误!!!"); } let captchaType = data.code === 200 ? data.data?.type : "DISABLED"; const captcha = createCaptchaByType(captchaType, this); if (captcha == null) { throw new Error("[TAC] 未知的验证码类型[" + captchaType + "]"); } captcha.init(data, (d, c) => { // 验证 const currentCaptchaData = c.currentCaptchaData; const data = { bgImageWidth: currentCaptchaData.bgImageWidth, bgImageHeight: currentCaptchaData.bgImageHeight, templateImageWidth: currentCaptchaData.templateImageWidth, templateImageHeight: currentCaptchaData.templateImageHeight, startTime: currentCaptchaData.startTime.getTime(), stopTime: currentCaptchaData.stopTime.getTime(), trackList: currentCaptchaData.trackList, }; if (c.type === "ROTATE_DEGREE" || c.type === "ROTATE") { data.bgImageWidth = c.currentCaptchaData.end; } if (currentCaptchaData.data) { data.data = currentCaptchaData.data; } // 清空 const id = c.currentCaptchaData.currentCaptchaId; c.currentCaptchaData = undefined; if (this.config.onDataReady) { Promise.resolve(this.config.onDataReady({ id, data }, c, this)).catch((error) => { console.error("[TAC] onDataReady callback failed", error); }); return; } // 调用验证接口 this.config.validCaptcha(id, data, c, this); }); this.C = captcha; this.openCaptcha(); }); } destroyCaptcha(callback) { if (this.C) { this.C.el.css("transform", "translateX(300px)"); setTimeout(() => { this.C.destroy(); callback && callback(); }, 500); } else { callback(); } } } export { TianAiCaptcha, CaptchaConfig };