175 lines
4.8 KiB
JavaScript
175 lines
4.8 KiB
JavaScript
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 = `
|
|
<div class="__captcha-parent">
|
|
<div class="captcha-box">
|
|
<div class="captcha-loading loading"></div>
|
|
</div>
|
|
<!-- 底部 -->
|
|
<div class="slider-bottom">
|
|
<div class="refresh-btn"></div>
|
|
<div class="close-btn"></div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
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 };
|