From 3e331f58ce09d338e499cb71be2ba6185103cf9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=8C=E7=B3=96=E5=8C=85=E5=AD=90?= Date: Fri, 15 May 2026 15:43:59 +0800 Subject: [PATCH] =?UTF-8?q?=E9=AA=8C=E8=AF=81=E7=A0=81=E8=B0=83=E8=AF=95?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components.d.ts | 3 + src/config/menu.ts | 8 + src/router.ts | 2 + src/vendor/tianai-captcha/captcha/captcha.js | 193 ++++++++ .../tianai-captcha/captcha/captcha.less | 104 ++++ .../tianai-captcha/captcha/common/common.js | 462 ++++++++++++++++++ .../tianai-captcha/captcha/common/common.less | 86 ++++ .../tianai-captcha/captcha/concat/concat.js | 142 ++++++ .../tianai-captcha/captcha/concat/concat.less | 17 + .../tianai-captcha/captcha/config/config.js | 217 ++++++++ .../captcha/config/styleConfig.js | 23 + .../tianai-captcha/captcha/disable/disable.js | 58 +++ .../captcha/disable/disable.less | 25 + .../captcha/image_click/image_click.js | 132 +++++ .../captcha/image_click/image_click.less | 66 +++ .../tianai-captcha/captcha/rotate/rotate.js | 136 ++++++ .../tianai-captcha/captcha/rotate/rotate.less | 12 + .../tianai-captcha/captcha/slider/slider.js | 144 ++++++ .../tianai-captcha/captcha/slider/slider.less | 89 ++++ .../word_image_click/word_image_click.js | 13 + src/vendor/tianai-captcha/images/dun.jpeg | Bin 0 -> 8340 bytes src/vendor/tianai-captcha/images/icon.png | Bin 0 -> 3100 bytes src/vendor/tianai-captcha/images/loading.gif | Bin 0 -> 6773 bytes src/vendor/tianai-captcha/index.ts | 39 ++ src/views/debug/CaptchaSandbox.vue | 209 ++++++++ 25 files changed, 2180 insertions(+) create mode 100644 src/vendor/tianai-captcha/captcha/captcha.js create mode 100644 src/vendor/tianai-captcha/captcha/captcha.less create mode 100644 src/vendor/tianai-captcha/captcha/common/common.js create mode 100644 src/vendor/tianai-captcha/captcha/common/common.less create mode 100644 src/vendor/tianai-captcha/captcha/concat/concat.js create mode 100644 src/vendor/tianai-captcha/captcha/concat/concat.less create mode 100644 src/vendor/tianai-captcha/captcha/config/config.js create mode 100644 src/vendor/tianai-captcha/captcha/config/styleConfig.js create mode 100644 src/vendor/tianai-captcha/captcha/disable/disable.js create mode 100644 src/vendor/tianai-captcha/captcha/disable/disable.less create mode 100644 src/vendor/tianai-captcha/captcha/image_click/image_click.js create mode 100644 src/vendor/tianai-captcha/captcha/image_click/image_click.less create mode 100644 src/vendor/tianai-captcha/captcha/rotate/rotate.js create mode 100644 src/vendor/tianai-captcha/captcha/rotate/rotate.less create mode 100644 src/vendor/tianai-captcha/captcha/slider/slider.js create mode 100644 src/vendor/tianai-captcha/captcha/slider/slider.less create mode 100644 src/vendor/tianai-captcha/captcha/word_image_click/word_image_click.js create mode 100644 src/vendor/tianai-captcha/images/dun.jpeg create mode 100644 src/vendor/tianai-captcha/images/icon.png create mode 100644 src/vendor/tianai-captcha/images/loading.gif create mode 100644 src/vendor/tianai-captcha/index.ts create mode 100644 src/views/debug/CaptchaSandbox.vue diff --git a/components.d.ts b/components.d.ts index eab8558..bbfb868 100644 --- a/components.d.ts +++ b/components.d.ts @@ -9,6 +9,7 @@ declare module '@vue/runtime-core' { export interface GlobalComponents { ElAside: typeof import('element-plus/es')['ElAside'] ElButton: typeof import('element-plus/es')['ElButton'] + ElCard: typeof import('element-plus/es')['ElCard'] ElCol: typeof import('element-plus/es')['ElCol'] ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider'] ElContainer: typeof import('element-plus/es')['ElContainer'] @@ -32,6 +33,8 @@ declare module '@vue/runtime-core' { ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] ElOption: typeof import('element-plus/es')['ElOption'] ElPagination: typeof import('element-plus/es')['ElPagination'] + ElRadioButton: typeof import('element-plus/es')['ElRadioButton'] + ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] ElRow: typeof import('element-plus/es')['ElRow'] ElSelect: typeof import('element-plus/es')['ElSelect'] ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] diff --git a/src/config/menu.ts b/src/config/menu.ts index 01ed255..aabe1c4 100644 --- a/src/config/menu.ts +++ b/src/config/menu.ts @@ -33,6 +33,14 @@ const menus: MenuGroup[] = [ { title: '图片资源库', path: '/api/sourceImage', permission: 'sourceImage:list' }, { title: '歌曲库', path: '/api/music', permission: 'music:list' } ] + }, + { + name: 'debug', + title: '调试工具', + icon: 'Tools', + child: [ + { title: '图形验证码', path: '/debug/captcha', permission: 'captcha:list' } + ] } ] diff --git a/src/router.ts b/src/router.ts index 335cd67..ba2f271 100644 --- a/src/router.ts +++ b/src/router.ts @@ -18,6 +18,8 @@ const routes: Array = [ { path: '/api/hitokoto', name: 'Hitokoto', component: () => import('@/views/api/Hitokoto.vue'), meta: { title: '一言' } }, { path: '/api/photoWall', name: 'PhotoWall', component: () => import('@/views/api/PhotoWall.vue'), meta: { title: '照片墙' } }, { path: '/api/sourceImage', name: 'SourceImage', component: () => import('@/views/api/SourceImage.vue'), meta: { title: '图片资源库' } }, + + { path: '/debug/captcha', name: 'CaptchaSandbox', component: () => import('@/views/debug/CaptchaSandbox.vue'), meta: { title: '图形验证码' } }, ]} ] diff --git a/src/vendor/tianai-captcha/captcha/captcha.js b/src/vendor/tianai-captcha/captcha/captcha.js new file mode 100644 index 0000000..e90c1ed --- /dev/null +++ b/src/vendor/tianai-captcha/captcha/captcha.js @@ -0,0 +1,193 @@ +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("#tianai-captcha-box"); + const styleConfig = tac.style; + switch (type) { + case "SLIDER": + return new Slider(box, styleConfig); + case "ROTATE": + case "ROTATE_DEGREE": + 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("#tianai-captcha-parent"); + clearAllPreventDefault(this.domTemplate); + this.loadStyle(); + // 绑定按钮事件 + this.config.domBindEl + .find("#tianai-captcha-slider-refresh-btn") + .click((el) => { + this.btnRefreshFun(el, this); + }); + this.config.domBindEl + .find("#tianai-captcha-slider-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("#tianai-captcha-loading") + .css("display", "block"); + } + + closeLoading() { + this.config.domBindEl + .find("#tianai-captcha-loading") + .css("display", "none"); + } + + loadStyle() { + // 设置样式 + const bgUrl = this.style.bgUrl; + const logoUrl = this.style.logoUrl; + if (bgUrl) { + // 背景图片 + this.config.domBindEl + .find("#tianai-captcha-bg-img") + .css("background-image", "url(" + bgUrl + ")"); + } + if (logoUrl && logoUrl !== "") { + // logo + this.config.domBindEl.find("#tianai-captcha-logo").attr("src", logoUrl); + } else if (logoUrl === null) { + // 删除logo + this.config.domBindEl.find("#tianai-captcha-logo").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; + // 调用验证接口 + 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(); + if (callback) { + callback(); + } + }, 500); + } else { + callback(); + } + } +} + +export { TianAiCaptcha, CaptchaConfig }; diff --git a/src/vendor/tianai-captcha/captcha/captcha.less b/src/vendor/tianai-captcha/captcha/captcha.less new file mode 100644 index 0000000..29f7b8a --- /dev/null +++ b/src/vendor/tianai-captcha/captcha/captcha.less @@ -0,0 +1,104 @@ +#tianai-captcha-parent { + box-shadow: 0 0 11px 0 #999999; + width: 318px; + height: 318px; + overflow: hidden; + position: relative; + z-index: 997; + box-sizing: border-box; + border-radius: 5px; + padding: 8px; + #tianai-captcha-box { + height: 260px; + width: 100%; + position: relative; + overflow: hidden; + .loading { + width: 120px; + height: 20px; + mask: linear-gradient(90deg, #000 70%, #0000 0) 0/20%; + background: linear-gradient(#f7b645 0 0) 0 / 0% no-repeat #dddddd6b; + animation: cartoon 1s infinite steps(6); + margin: 120px auto; + @keyframes cartoon { + 100% { + background-size: 120%; + } + } + } + #tianai-captcha { + transform-style: preserve-3d; + will-change: transform; + transition-duration: 0.45s; + transform: translateX(-300px); + } + } + #tianai-captcha-bg-img { + background-color: #fff; + background-position: top; + background-size: cover; + z-index: -1; + width: 100%; + height: 100%; + top: 0; + left: 0; + position: absolute; + border-radius: 6px; + //background-image: url(""); + } + + .slider-bottom { + .close-btn { + width: 20px; + height: 20px; + background-image: url("../images/icon.png"); + background-repeat: no-repeat; + background-position: 0 -14px; + float: right; + margin-right: 2px; + cursor: pointer; + } + .refresh-btn { + width: 20px; + height: 20px; + background-image: url("../images/icon.png"); + background-position: 0 -167px; + background-repeat: no-repeat; + float: right; + margin-right: 10px; + cursor: pointer; + } + .logo { + height: 30px; + float: left; + } + height: 19px; + width: 100%; + } + .slider-move-shadow { + animation: myanimation 2s infinite; + height: 100%; + width: 5px; + background-color: #fff; + position: absolute; + top: 0; + left: 0; + filter: opacity(0.5); + box-shadow: 1px 1px 1px #fff; + border-radius: 50%; + } + #tianai-captcha-slider-move-track-mask { + border-width: 1px; + border-style: solid; + border-color: #00f4ab; + + width: 0; + height: 32px; + background-color: #a9ffe5; + opacity: 0.5; + position: absolute; + top: -1px; + left: -1px; + border-radius: 5px; + } +} diff --git a/src/vendor/tianai-captcha/captcha/common/common.js b/src/vendor/tianai-captcha/captcha/common/common.js new file mode 100644 index 0000000..ee90b17 --- /dev/null +++ b/src/vendor/tianai-captcha/captcha/common/common.js @@ -0,0 +1,462 @@ +/** 是否打印日志 */ +var isPrintLog = false; + +function printLog(params) { + if (isPrintLog) { + console.log(JSON.stringify(params)); + } +} + +/** + * 清除默认事件 + * @param event event + */ +function clearPreventDefault(event) { + if (event.preventDefault) { + event.preventDefault(); + } +} + +/** + * 阻止某div默认事件 + * @param dom + */ +function clearAllPreventDefault(dom) { + Dom(dom).each((el) => { + // 手机端 + el.addEventListener("touchmove", clearPreventDefault, { passive: false }); + // pc端 + el.addEventListener("mousemove", clearPreventDefault, { passive: false }); + }); +} + +/** + * 获取当前坐标 + * @param event 事件 + * @returns {{x: number, y: number}} + */ +function getCurrentCoordinate(event) { + if (event.pageX !== null && event.pageX !== undefined) { + return { + x: Math.round(event.pageX), + y: Math.round(event.pageY), + }; + } + let targetTouches; + if (event.changedTouches) { + // 抬起事件 + targetTouches = event.changedTouches; + } else if (event.targetTouches) { + // pc 按下事件 + targetTouches = event.targetTouches; + } else if (event.originalEvent && event.originalEvent.targetTouches) { + // 鼠标触摸事件 + targetTouches = event.originalEvent.targetTouches; + } + if (targetTouches[0].pageX !== null && targetTouches[0].pageX !== undefined) { + return { + x: Math.round(targetTouches[0].pageX), + y: Math.round(targetTouches[0].pageY), + }; + } + return { + x: Math.round(targetTouches[0].clientX), + y: Math.round(targetTouches[0].clientY), + }; +} + +function down(currentCaptcha, event) { + // debugger + const coordinate = getCurrentCoordinate(event); + let startX = coordinate.x; + let startY = coordinate.y; + currentCaptcha.currentCaptchaData.startX = startX; + currentCaptcha.currentCaptchaData.startY = startY; + const trackList = currentCaptcha.currentCaptchaData.trackList; + currentCaptcha.currentCaptchaData.startTime = new Date(); + const startTime = currentCaptcha.currentCaptchaData.startTime; + + trackList.push({ + x: coordinate.x, + y: coordinate.y, + type: "down", + t: new Date().getTime() - startTime.getTime(), + }); + printLog(["start", startX, startY]); + currentCaptcha.__m__ = move.bind(null, currentCaptcha); + currentCaptcha.__u__ = up.bind(null, currentCaptcha); + // pc + window.addEventListener("mousemove", currentCaptcha.__m__); + window.addEventListener("mouseup", currentCaptcha.__u__); + // 手机端 + window.addEventListener("touchmove", currentCaptcha.__m__, false); + window.addEventListener("touchend", currentCaptcha.__u__, false); + if (currentCaptcha && currentCaptcha.doDown) { + currentCaptcha.doDown(event, currentCaptcha); + } +} + +function move(currentCaptcha, event) { + if (event.touches && event.touches.length > 0) { + event = event.touches[0]; + } + // debugger + const coordinate = getCurrentCoordinate(event); + let pageX = coordinate.x; + let pageY = coordinate.y; + const startX = currentCaptcha.currentCaptchaData.startX; + const startY = currentCaptcha.currentCaptchaData.startY; + const startTime = currentCaptcha.currentCaptchaData.startTime; + const end = currentCaptcha.currentCaptchaData.end; + const bgImageWidth = currentCaptcha.currentCaptchaData.bgImageWidth; + const trackList = currentCaptcha.currentCaptchaData.trackList; + let moveX = pageX - startX; + let moveY = pageY - startY; + const track = { + x: coordinate.x, + y: coordinate.y, + type: "move", + t: new Date().getTime() - startTime.getTime(), + }; + trackList.push(track); + if (moveX < 0) { + moveX = 0; + } else if (moveX > end) { + moveX = end; + } + currentCaptcha.currentCaptchaData.moveX = moveX; + currentCaptcha.currentCaptchaData.moveY = moveY; + if (currentCaptcha.doMove) { + currentCaptcha.doMove(event, currentCaptcha); + } + printLog(["move", track]); +} +function destroyEvent(currentCaptcha) { + if (currentCaptcha) { + if (currentCaptcha.__m__) { + window.removeEventListener("mousemove", currentCaptcha.__m__); + window.removeEventListener("touchmove", currentCaptcha.__m__); + } + if (currentCaptcha.__u__) { + window.removeEventListener("mouseup", currentCaptcha.__u__); + window.removeEventListener("touchend", currentCaptcha.__u__); + } + } +} + +function up(currentCaptcha, event) { + destroyEvent(currentCaptcha); + const coordinate = getCurrentCoordinate(event); + currentCaptcha.currentCaptchaData.stopTime = new Date(); + const startTime = currentCaptcha.currentCaptchaData.startTime; + const trackList = currentCaptcha.currentCaptchaData.trackList; + + const track = { + x: coordinate.x, + y: coordinate.y, + type: "up", + t: new Date().getTime() - startTime.getTime(), + }; + + trackList.push(track); + printLog(["up", track]); + printLog(["tracks", trackList]); + if (currentCaptcha.doUp) { + currentCaptcha.doUp(event, currentCaptcha); + } + currentCaptcha.endCallback(currentCaptcha.currentCaptchaData, currentCaptcha); +} + +function initConfig( + bgImageWidth, + bgImageHeight, + templateImageWidth, + templateImageHeight, + end, +) { + // bugfix 图片宽高可能会有小数情况,强转一下整数 + const currentCaptchaConfig = { + startTime: new Date(), + trackList: [], + movePercent: 0, + clickCount: 0, + bgImageWidth: Math.round(bgImageWidth), + bgImageHeight: Math.round(bgImageHeight), + templateImageWidth: Math.round(templateImageWidth), + templateImageHeight: Math.round(templateImageHeight), + end: end, + }; + printLog(["init", currentCaptchaConfig]); + return currentCaptchaConfig; +} + +function closeTips(el, callback) { + const tipEl = Dom(el).find("#tianai-captcha-tips"); + tipEl.removeClass("tianai-captcha-tips-on"); + // tipEl.removeClass("tianai-captcha-tips-success") + // tipEl.removeClass("tianai-captcha-tips-error") + // 延时 + if (callback) { + setTimeout(callback, 0.35); + } +} + +function showTips(el, msg, type, callback) { + const tipEl = Dom(el).find("#tianai-captcha-tips"); + tipEl.text(msg); + if (type === 1) { + // 成功 + tipEl.removeClass("tianai-captcha-tips-error"); + tipEl.addClass("tianai-captcha-tips-success"); + } else { + // 失败 + tipEl.removeClass("tianai-captcha-tips-success"); + tipEl.addClass("tianai-captcha-tips-error"); + } + tipEl.addClass("tianai-captcha-tips-on"); + // 延时 + setTimeout(callback, 1000); +} + +class CommonCaptcha { + showTips(msg, type, callback) { + showTips(this.el, msg, type, callback); + } + + closeTips(msg, callback) { + closeTips(this.el, msg, callback); + } +} + +function Dom(domStr, dom) { + return new DomEl(domStr, dom); +} + +class DomEl { + constructor(domStr, dom) { + if (dom instanceof HTMLElement) { + this.dom = dom; + this.domStr = domStr; + return; + } + if (domStr instanceof DomEl) { + this.dom = domStr.dom; + this.domStr = domStr.domStr; + } else if (typeof domStr === "string") { + this.dom = document.querySelector(domStr); + this.domStr = domStr; + } else if (domStr instanceof HTMLElement) { + this.dom = domStr; + this.domStr = domStr.nodeName; + } else { + throw new Error("不支持的类型"); + } + } + + each(callback) { + this.getTarget().querySelectorAll("*").forEach(callback); + } + + removeClass(className) { + let element = this.getTarget(); + if (element.classList) { + // 使用 classList API 移除类 + element.classList.remove(className); + } else { + // 兼容旧版本浏览器 + const currentClass = element.className; + const regex = new RegExp("(?:^|\\s)" + className + "(?!\\S)", "g"); + element.className = currentClass.replace(regex, ""); + } + return this; + } + + addClass(className) { + const element = this.getTarget(); + if (element.classList) { + // 使用 classList API 添加类 + element.classList.add(className); + } else { + // 兼容旧版本浏览器 + let currentClass = element.className; + if (currentClass.indexOf(className) === -1) { + element.className = currentClass + " " + className; + } + } + return this; + } + + find(str) { + const el = this.getTarget().querySelector(str); + if (el) { + return new DomEl(str, el); + } + return null; + } + + children(selector) { + const childNodes = this.getTarget().childNodes; + for (let i = 0; i < childNodes.length; i++) { + if (childNodes[i].nodeType === 1 && childNodes[i].matches(selector)) { + return new DomEl(selector, childNodes[i]); + } + } + return null; + } + + remove() { + this.getTarget().remove(); + return null; + } + + css(property, value) { + if (typeof property === "string" && typeof value === "string") { + // 设置单个属性 + this.getTarget().style[property] = value; + } else if (typeof property === "object") { + // 设置多个属性 + for (var prop in property) { + if (property.hasOwnProperty(prop)) { + this.getTarget().style[prop] = property[prop]; + } + } + } else if (typeof property === "string" && typeof value === "undefined") { + // 获取单个属性 + return window.getComputedStyle(element)[property]; + } + } + + attr(attributeName, value) { + if (value === undefined) { + // 如果未提供值,则返回属性的当前值 + return this.getTarget().getAttribute(attributeName); + } else { + // 如果提供了值,则设置属性的值 + this.getTarget().setAttribute(attributeName, value); + } + return this; + } + + text(str) { + this.getTarget().innerText = str; + return this; + } + + html(str) { + this.getTarget().innerHtml = str; + return this; + } + + is(dom) { + if (dom && typeof dom === "object" && typeof dom.nodeType !== "undefined") { + return this.dom === dom; + } + if (dom instanceof DomEl) { + return this.dom === dom.dom; + } + } + + append(content) { + if (typeof content === "string") { + this.getTarget().insertAdjacentHTML("beforeend", content); + } else if (content instanceof HTMLElement) { + this.getTarget().appendChild(content); + } else { + throw new Error("Invalid content type"); + } + return this; + } + + click(fun) { + this.on("click", fun); + return this; + } + + mousedown(fun) { + this.on("mousedown", fun); + return this; + } + + touchstart(fun) { + this.on("touchstart", fun); + return this; + } + + on(eventType, fun) { + this.getTarget().addEventListener(eventType, fun, { passive: true }); + return this; + } + + width() { + return this.getTarget().offsetWidth; + } + + height() { + return this.getTarget().offsetHeight; + } + + getTarget() { + if (this.dom) { + return this.dom; + } + throw new Error("dom不存在: [" + this.domStr + "]"); + } +} + +function http(options) { + return new Promise(function (resolve, reject) { + var xhr = new XMLHttpRequest(); + xhr.open(options.method || "GET", options.url); + // 设置请求头 + if (options.headers) { + for (const header in options.headers) { + if (options.headers.hasOwnProperty(header)) { + xhr.setRequestHeader(header, options.headers[header]); + } + } + } + xhr.onreadystatechange = function () { + if (xhr.readyState === XMLHttpRequest.DONE) { + if (xhr.status >= 200 && xhr.status <= 500) { + const contentType = xhr.getResponseHeader("Content-Type"); + if (contentType && contentType.indexOf("application/json") !== -1) { + resolve(JSON.parse(xhr.responseText)); + } else { + resolve(xhr.responseText); + } + } else { + reject(new Error("Request failed with status: " + xhr.status)); + } + } + }; + xhr.onerror = function () { + reject(new Error("Network Error")); + }; + xhr.send(options.data); + }); +} + +function isEmptyObject(obj) { + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + return false; // 对象不为空 + } + } + return true; // 对象为空 +} + +export { + isEmptyObject, + http, + Dom, + DomEl, + CommonCaptcha, + clearAllPreventDefault, + down, + move, + up, + initConfig, + showTips, + closeTips, + destroyEvent, +}; diff --git a/src/vendor/tianai-captcha/captcha/common/common.less b/src/vendor/tianai-captcha/captcha/common/common.less new file mode 100644 index 0000000..5d9ed4c --- /dev/null +++ b/src/vendor/tianai-captcha/captcha/common/common.less @@ -0,0 +1,86 @@ +#tianai-captcha { + text-align: left; + box-sizing: content-box; + width: 300px; + height: 260px; + z-index: 999; + .slider-bottom .logo { + height: 30px; + } + .slider-bottom { + height: 19px; + width: 100%; + } + .content { + .tianai-captcha-tips { + height: 25px; + width: 100%; + position: absolute; + bottom: -25px; + left: 0; + z-index: 999; + font-size: 15px; + line-height: 25px; + /*background-color: #FF5D39;*/ + color: #fff; + text-align: center; + /* transform: translateY(0px); */ + /* display: none; */ + /* transition: max-height 0.5s; */ + transition: bottom 0.3s ease-in-out; + } + .tianai-captcha-tips.tianai-captcha-tips-error { + background-color: #ff5d39; + } + .tianai-captcha-tips.tianai-captcha-tips-success { + background-color: #39c522; + } + .tianai-captcha-tips.tianai-captcha-tips-on { + bottom: 0; + } + + #tianai-captcha-loading { + z-index: 9999; + background-color: #f5f5f5; + text-align: center; + height: 100%; + overflow: hidden; + position: relative; + display: flex; + justify-content: center; + align-items: center; + img { + display: block; + width: 45px; + height: 45px; + } + } + } + #tianai-captcha-slider-bg-canvas { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + border-radius: 5px; + } + #tianai-captcha-slider-bg-div { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + border-radius: 5px; + .tianai-captcha-slider-bg-div-slice { + position: absolute; + } + } +} +@keyframes myanimation { + from { + left: 0; + } + to { + left: 289px; + } +} diff --git a/src/vendor/tianai-captcha/captcha/concat/concat.js b/src/vendor/tianai-captcha/captcha/concat/concat.js new file mode 100644 index 0000000..9e2ec1a --- /dev/null +++ b/src/vendor/tianai-captcha/captcha/concat/concat.js @@ -0,0 +1,142 @@ +import "../common/common.less"; +import "../slider/slider.less"; +import "./concat.less"; +import { + Dom, + CommonCaptcha, + clearAllPreventDefault, + down, + initConfig, + destroyEvent, +} from "../common/common.js"; + +const TYPE = "CONCAT"; + +function getTemplate(styleConfig) { + return ` +
+
+ 拖动滑块完成拼图 +
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ `; +} + +class Concat extends CommonCaptcha { + constructor(divId, styleConfig) { + super(); + this.boxEl = Dom(divId); + this.styleConfig = styleConfig; + this.type = TYPE; + this.currentCaptchaData = {}; + } + + init(captchaData, endCallback, loadSuccessCallback) { + // 重载样式 + this.destroy(); + this.boxEl.append(getTemplate(this.styleConfig)); + this.el = this.boxEl.find("#tianai-captcha"); + this.loadStyle(); + // 按钮绑定事件 + this.el + .find("#tianai-captcha-slider-move-btn") + .mousedown(down.bind(null, this)); + this.el + .find("#tianai-captcha-slider-move-btn") + .touchstart(down.bind(null, this)); + clearAllPreventDefault(this.el); + // 绑定全局 + window.currentCaptcha = this; + // 载入验证码 + this.loadCaptchaForData(this, captchaData); + this.endCallback = endCallback; + if (loadSuccessCallback) { + // 加载成功 + loadSuccessCallback(this); + } + return this; + } + + destroy() { + destroyEvent(); + const existsCaptchaEl = this.boxEl.children("#tianai-captcha"); + if (existsCaptchaEl) { + existsCaptchaEl.remove(); + } + } + + doMove() { + const moveX = this.currentCaptchaData.moveX; + this.el + .find("#tianai-captcha-slider-move-btn") + .css("transform", "translate(" + moveX + "px, 0px)"); + this.el + .find("#tianai-captcha-slider-concat-img-div") + .css("background-position-x", moveX + "px"); + this.el + .find("#tianai-captcha-slider-move-track-mask") + .css("width", moveX + "px"); + } + + loadStyle() { + let sliderImg = ""; + let moveTrackMaskBorderColor = "#00f4ab"; + let moveTrackMaskBgColor = "#a9ffe5"; + const styleConfig = this.styleConfig; + if (styleConfig) { + sliderImg = styleConfig.btnUrl; + moveTrackMaskBgColor = styleConfig.moveTrackMaskBgColor; + moveTrackMaskBorderColor = styleConfig.moveTrackMaskBorderColor; + } + this.el + .find(".slider-move .slider-move-btn") + .css("background-image", "url(" + sliderImg + ")"); + // this.el.find("#tianai-captcha-slider-move-track-font").text(title); + this.el + .find("#tianai-captcha-slider-move-track-mask") + .css("border-color", moveTrackMaskBorderColor); + this.el + .find("#tianai-captcha-slider-move-track-mask") + .css("background-color", moveTrackMaskBgColor); + } + + loadCaptchaForData(that, data) { + const bgImg = that.el.find(".tianai-captcha-slider-concat-bg-img"); + const sliderImg = that.el.find("#tianai-captcha-slider-concat-img-div"); + bgImg.css("background-image", "url(" + data.data.backgroundImage + ")"); + sliderImg.css("background-image", "url(" + data.data.backgroundImage + ")"); + sliderImg.css("background-position", "0px 0px"); + var backgroundImageHeight = data.data.backgroundImageHeight; + var height = + ((backgroundImageHeight - data.data.data.randomY) / + backgroundImageHeight) * + 180; + sliderImg.css("height", height + "px"); + + that.currentCaptchaData = initConfig( + bgImg.width(), + bgImg.height(), + sliderImg.width(), + sliderImg.height(), + 300 - 63 + 5, + ); + that.currentCaptchaData.currentCaptchaId = data.data.id; + } +} + +export default Concat; diff --git a/src/vendor/tianai-captcha/captcha/concat/concat.less b/src/vendor/tianai-captcha/captcha/concat/concat.less new file mode 100644 index 0000000..ef645bc --- /dev/null +++ b/src/vendor/tianai-captcha/captcha/concat/concat.less @@ -0,0 +1,17 @@ +#tianai-captcha.tianai-captcha-concat { + .tianai-captcha-slider-concat-img-div { + background-size: 100% 180px; + position: absolute; + transform: translate(0px, 0px); + /* border-bottom: 1px solid blue; */ + z-index: 1; + width: 100%; + } + .tianai-captcha-slider-concat-bg-img { + width: 100%; + height: 100%; + position: absolute; + transform: translate(0px, 0px); + background-size: 100% 180px; + } +} diff --git a/src/vendor/tianai-captcha/captcha/config/config.js b/src/vendor/tianai-captcha/captcha/config/config.js new file mode 100644 index 0000000..8c354b2 --- /dev/null +++ b/src/vendor/tianai-captcha/captcha/config/config.js @@ -0,0 +1,217 @@ +import StyleConfig from "./styleConfig"; +import { Dom, http } from "../common/common"; +class CaptchaConfig { + constructor(args) { + if (!args.bindEl) { + throw new Error("[TAC] 必须配置 [bindEl]用于将验证码绑定到该元素上"); + } + if (!args.requestCaptchaDataUrl) { + throw new Error("[TAC] 必须配置 [requestCaptchaDataUrl]请求验证码接口"); + } + if (!args.validCaptchaUrl) { + throw new Error("[TAC] 必须配置 [validCaptchaUrl]验证验证码接口"); + } + this.bindEl = args.bindEl; + this.domBindEl = Dom(args.bindEl); + this.requestCaptchaDataUrl = args.requestCaptchaDataUrl; + this.validCaptchaUrl = args.validCaptchaUrl; + if (args.validSuccess) { + this.validSuccess = args.validSuccess; + } + if (args.validFail) { + this.validFail = args.validFail; + } + if (args.requestHeaders) { + this.requestHeaders = args.requestHeaders; + } else { + this.requestHeaders = {}; + } + if (args.btnCloseFun) { + this.btnCloseFun = args.btnCloseFun; + } + if (args.btnRefreshFun) { + this.btnRefreshFun = args.btnRefreshFun; + } + this.requestChain = []; + // 时间戳转换 + this.timeToTimestamp = args.timeToTimestamp || true; + this.insertRequestChain(0, { + preRequest(type, param, c, tac) { + if (this.timeToTimestamp && param.data) { + for (let key in param.data) { + // 将date全部转换为时间戳 + if (param.data[key] instanceof Date) { + param.data[key] = param.data[key].getTime(); + } + } + } + return true; + }, + }); + } + addRequestChain(fun) { + this.requestChain.push(fun); + } + insertRequestChain(index, chain) { + this.requestChain.splice(index, 0, chain); + } + removeRequestChain(index) { + this.requestChain.splice(index, 1); + } + requestCaptchaData() { + const requestParam = {}; + requestParam.headers = this.requestHeaders || {}; + requestParam.data = {}; + // 设置默认值 + requestParam.headers["Content-Type"] = "application/json;charset=UTF-8"; + requestParam.method = "POST"; + requestParam.url = this.requestCaptchaDataUrl; + // 请求前装载参数 + this._preRequest("requestCaptchaData", requestParam); + // 发送请求 + const request = this.doSendRequest(requestParam); + // 返回结果 + return request.then((res) => { + // 装返回结果 + this._postRequest("requestCaptchaData", requestParam, res); + // 返回结果 + return res; + }); + } + + doSendRequest(requestParam) { + // 如果content-type是json,那么data就是json字符串, 这里直接匹配所有header是否包含application/json + if (requestParam.headers) { + for (const key in requestParam.headers) { + if (requestParam.headers[key].indexOf("application/json") > -1) { + if (typeof requestParam.data !== "string") { + requestParam.data = JSON.stringify(requestParam.data); + } + break; + } + } + } + return http(requestParam).then((res) => { + try { + return JSON.parse(res); + } catch (e) { + return res; + } + }); + } + + _preRequest(type, requestParam, c, tac) { + for (let i = 0; i < this.requestChain.length; i++) { + const r = this.requestChain[i]; + if (r.preRequest) { + if (!r.preRequest(type, requestParam, this, c, tac)) { + break; + } + } + } + } + + _postRequest(type, requestParam, res, c, tac) { + for (let i = 0; i < this.requestChain.length; i++) { + const r = this.requestChain[i]; + // 判断r是否存圩postRequest方法 + if (r.postRequest) { + if (!r.postRequest(type, requestParam, res, this, c, tac)) { + break; + } + } + } + } + + validCaptcha(currentCaptchaId, data, c, tac) { + const sendParam = { + id: currentCaptchaId, + data: data, + }; + let requestParam = {}; + requestParam.headers = this.requestHeaders || {}; + requestParam.data = sendParam; + requestParam.headers["Content-Type"] = "application/json;charset=UTF-8"; + requestParam.method = "POST"; + requestParam.url = this.validCaptchaUrl; + + this._preRequest("validCaptcha", requestParam, c, tac); + const request = this.doSendRequest(requestParam); + return request + .then((res) => { + this._postRequest("validCaptcha", requestParam, res, c, tac); + return res; + }) + .then((res) => { + if (res.code == 200) { + const useTimes = (data.stopTime - data.startTime) / 1000; + c.showTips(`验证成功,耗时${useTimes}秒`, 1, () => + this.validSuccess(res, c, tac), + ); + } else { + let tipMsg = "验证失败,请重新尝试!"; + if (res.code) { + if (res.code != 4001) { + tipMsg = "验证码被黑洞吸走了!"; + } + } + c.showTips(tipMsg, 0, () => this.validFail(res, c, tac)); + } + }) + .catch((e) => { + let tipMsg = c.styleConfig.i18n.tips_error; + if (e.code && e.code != 200) { + if (e.code != 4001) { + tipMsg = c.styleConfig.i18n.tips_4001; + } + c.showTips(tipMsg, 0, () => this.validFail(e, c, tac)); + return; + } + c.showTips(tipMsg, 0, () => this.validFail(e, c, tac)); + }); + } + + validSuccess(res, c, tac) { + console.log( + "验证码校验成功, 请重写 [config.validSuccess] 方法, 用于自定义逻辑处理", + ); + window.currentCaptchaRes = res; + tac.destroyWindow(); + } + + validFail(res, c, tac) { + tac.reloadCaptcha(); + } +} + +function wrapConfig(config) { + if (config instanceof CaptchaConfig) { + return config; + } + return new CaptchaConfig(config); +} + +function wrapStyle(style) { + // if (!style) { + // style = {} + // } + // + // if (!style.btnUrl) { + // // 设置默认图片 + // style.btnUrl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABkCAYAAABU19jRAAAJcUlEQVR4nO2d63MT1xmHf9rV6mr5fgNMuSW+ENsY8N0EE2BMhinJNB8y/dD2Qz/0v+gMf0w/JHTKNJAhICwbsA02TpNAHEMgQIwNBSEb8F2rvXTeY1kjYyA+TmVJmfeZ8YiRWa9299E57/mdI63Dtm3E+RjAKTDMaj4F8AU9uyzMCQBn+EQxb+EjAF+RMH8AcJrPFLMGvCSMzWeKWSN/I2GiAFx8xpi1oPBZYiTQWRhGChaGkYKFYaRgYRgpWBhGChaGkYKFYaRgYRgpWBhGChaGkYKFYaRgYRgpWBhGChaGkYKFYaRgYRgpWBhGChaGkYKFYaRgYRgpWBhGChaGkYKFYaRgYRgpWBhGCiefrtShGwZiup74+4qqwu12Z/W7lIVJEfN6FDfv3sPXfYOIRRfpm1UQKC7EkQ+PYFtRcdZKw8KkiLsPJ/CfgSFcH7yOxWhU7MSluYQoR44fxdaCoqyUhoVJEfZ8FN99c1N0Sx6PR+zEMAz0XAgBNtB14hi25OXDkWXHxUVvinA4ln6ScTqdsGwbvRd7EPwyiEcvXyDbvpyHhUkRaq4fe/c3wEWSWFZiJySNYZroCYYQPHsBY1OTWSWNevLkyb/TYwa8lt8UAb8ftluDW9UwPj4hDs0Rb3JUVRXd09j9nwELKKgoR4HXlw2Hb3INkyK8mob9NdUwLROq4sCVKwMrdqRpGkzTFN0TaWR2HcKu0rKMr2lYmBTi1jS01dUt7UBx4PKlfvHP5JaGuqseIY0DjmOHsKukNKOPiYVJMU5VRXt9PSwboO+fvHJ5QEiiKEvlIz3S86HuHiiqAhw9iJ0lpRnb0rAwG4CqKHh/Tz0UhwOWaWGg/5oofEkmJLU4wfPdQia765CQJhNHJCzMBkEtSVtdLRw2YNo2hgaGEDMMMWpahrwJBUMUCkM9djgjE2EWZgOhFqW5rlbMKdm2heHBYUT1mCiAEW9pKKfpPh8Sj5mYCLMwG4zLqWJfTZWQgL5S++uhYURjBrR4S0MtUSYnwixMGvBoGvZUV4quh0S4Pjgsaho1XtOIcM8wxJCb+qmu33dljDS/CWEeTb/E/Pw89EUdebkBVBQWrnnbWVjQoMAtsT9asGDQhf8VUbnX5UJ9VaVoZahVuXZ1cMXoiaSJxWIiEab/dPj4UXFczjRrk/VJ70/hp/jhuxF89o9TGP1+FH6fD9OxGHw5Pnicb34/PJ2dweitu7hwLojvb47A9rhQmJeXGLm8iQeP/4uRH27h88/+iZhhYs40UFZQsK7XrqkqigvyYbk18VrHH74+EX74YAzRqI66mupE15UmzKwW5kEkgtFvRxA8ex7hJ2HMzczgzu0f8fjxExRt2YzcgB9udfUJjuo6Tv/7HE6f+pe4GHd//AkwLRhuDeXFRW+U5v7EI4yMjKI3GMLt0Tt4cO8BAoEcWJoTZYXrl6asqBC6U0GOy42HY+MrZi1JmoWFRZQW5sNyuVBeUpxOabJ7aiASjiB4/iKmnj+H5loaacwvLOL2jRF4AjnY8dc/I/DKbTdoSHvr8SO8DD/DzPSMWHrg1JwYvHZdpK2NVZWU26/aF3VDTyLP0N/bh4mJR3C7XZiZnRVdht/nx7u7tsOzzg5qORFWHAocigO9vX2Jronwej24cXMEbq8XrfW169rH/4usnq02o1FEo9FEE47luN22sTAzC0OPrd7ItnHn9h0MDg3D6/WKbZdHJqYRg26ar92XDgvD39zA2Ng4VKdTbEf7mpmeRX/fAPRfeRch+luNNTXICeSu+h3ti7okUzdgp3luO6uFUTUN9lLmnniOCkdKVnML8uB0r76rD72Di4qL4NI0IUnydpZlw/WmGsY00bRvDzZvKhfFKLAU9VOG8v7BdijW+i8kLX649yyMz0+fwVQksur3NILyejzw5efCoaT3kmW1MN68AMq2bBIXXtd18WMZBt6r242DBzvgda3uWhQ4xNzOkeNdohZYXFjA4vwCfD4/Sio2i9bjdeSoGirKylFYXirykehiFHpUR2FJCbZu+x1yXlMrrQWSZWwygv6Ll3DxXBCX+66u6I7o2DRFRWtbM1o62xNdb7rI7lGSqqBs+zZMTj4XLYY/x49t7+zABx8eReWO7ciLL41ctZmqoqRiE/x+P6amp5FbkI9jx7tw+GgncqmbesPuPAEfduzcgenZOTg0FaWby/GXP/0RdZXvrOvlkyzjzyfR81UIoQs9IpRJniqglszt0tDc1oS9bc2o37lTLMhKI2bW35HtRXQRs3MLmH/xUrzzVb8HJQUFyHX/crJCQ+JwOALFqaKspGjNRWtkbg5zc7PQXC5szl/f6Ig6MFqiSavuqHCmumuFLIYBt+ZEY0sTGtua0VBTJQK/NKPzLfzSQEKWL4NiiG5a1gpZzPhMdnNrE/a3N2NPVaUI+jIAnacGNhiShdbx9pzrFgunSA4tqeUQRbuqoLW9BQ0tjSINzhBZBCzMBvPzVAS950KiG6KWJVkWGnXRELrjQBtqG/eioTqzZAELs3FQy3Iv/BR9wUtiUtGOr+tNhoptGt1V7atD4+4aEehlGizMBnH/WRj9wcuiG7LjI7Vllm8d3nnoAKoaakXq+0tzWumChUkxdlyWge4rYt0uzRMpSck01SzUDR3s7MC7e2pFRqSmOZx7GyxMCrESLcsldAd7oCgrEx6xrldRRM1SvbceHfV1K0K7TISFSREx28L41KRIcGmdruOVz82KBFd1oqWjBe/tb0ArLd3McFnAwqSOiclJ9JwP4fLFXtEtJXdDywluU2uTGDpTgZupNcur8GerU8R0eBJDV6+LRVbJLYdIcF2aSHD3tzaL9b20zjdbYGFShB0z4HY6V9QtFNLRXFATxf2U4FZXZkLcLwULkyJoaUXMNMV6HbyS4O6jicQMS3DXCguTInJKC9HU0YoPOg8k1uy0t7eivnmfSHB9WSgLwZOPKcKwLcT0GL69cxe3b46KoK6+ZS92V2zNyAR3jfBsdaox6LPSpiVyf/rEo/rq11JlFzxbnWoomEMW5CtrhWsYRgoWhpGChWGkYGEYKVgYRgoWhpGChWGkYGEYKVgYRgoWhpGChWGkYGEYKVgYRgoWhpGChWGkYGEYKVgYRgoWhpGChWGkYGEYKVgYRgoWhpGChWGkYGEYKVgYRgr6qGx6b4/BZBXUwnzCl4xZI5844g3MCQBn+Kwxb+EjAGcdST3SxwBO8RljXsOnAL4AgP8BXnVIgIvemwsAAAAASUVORK5CYII="; + // } + // if (!style.moveTrackMaskBgColor && !style.moveTrackMaskBorderColor) { + // style.moveTrackMaskBgColor = "#89d2ff"; + // style.moveTrackMaskBorderColor = "#0298f8"; + // + // } + // return style; + + let margeStyle = { ...StyleConfig, ...style }; + margeStyle.i18n = { ...StyleConfig.i18n, ...style?.i18n }; + return margeStyle; +} + +const captchaRequestChains = {}; + +export { CaptchaConfig, wrapConfig, wrapStyle }; diff --git a/src/vendor/tianai-captcha/captcha/config/styleConfig.js b/src/vendor/tianai-captcha/captcha/config/styleConfig.js new file mode 100644 index 0000000..b01f855 --- /dev/null +++ b/src/vendor/tianai-captcha/captcha/config/styleConfig.js @@ -0,0 +1,23 @@ +export default { + // 按钮图片 + btnUrl: + "data:image/png;base64,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", + // 移动边框背景颜色 + moveTrackMaskBgColor: "#89d2ff", + // 移动边框颜色 + moveTrackMaskBorderColor: "#0298f8", + // 文字提示 + i18n: { + tips_success: "验证成功,耗时%s秒", + tips_error: "验证失败,请重新尝试!", + slider_title: "拖动滑块完成拼图", + concat_title: "拖动滑块完成拼图", + image_click_title: "请依次点击:", + rotate_title: "拖动滑块完成拼图", + // TITLE 大小 + slider_title_size: "15px", + concat_title_size: "15px", + image_click_title_size: "20px", + rotate_title_size: "15px", + }, +}; diff --git a/src/vendor/tianai-captcha/captcha/disable/disable.js b/src/vendor/tianai-captcha/captcha/disable/disable.js new file mode 100644 index 0000000..0ee18ef --- /dev/null +++ b/src/vendor/tianai-captcha/captcha/disable/disable.js @@ -0,0 +1,58 @@ +const TYPE = "DISABLE"; +import "./disable.less"; + +function getTemplate(styleConfig) { + return ` +
+
+ ${styleConfig.i18n.disable_title} +
+
+
+ + + + + +
+
+
+ `; +} +class Disable { + constructor(boxEl, styleConfig) { + this.boxEl = boxEl; + this.styleConfig = styleConfig; + this.type = TYPE; + this.currentCaptchaData = {}; + } + init(captchaData, endCallback, loadSuccessCallback) { + // 重载样式 + this.destroy(); + this.boxEl.append(getTemplate(this.styleConfig)); + this.el = this.boxEl.find("#tianai-captcha"); + // 绑定全局 + // window.currentCaptcha = this; + // 载入验证码 + this.loadCaptchaForData(this, captchaData); + this.endCallback = endCallback; + if (loadSuccessCallback) { + // 加载成功 + loadSuccessCallback(this); + } + return this; + } + + destroy() { + const existsCaptchaEl = this.boxEl.find("#tianai-captcha"); + if (existsCaptchaEl) { + existsCaptchaEl.remove(); + } + } + loadCaptchaForData(that, data) { + const msg = data.msg || data.message || "接口异常"; + that.el.find("#content-span").text(msg); + } +} + +export default Disable; diff --git a/src/vendor/tianai-captcha/captcha/disable/disable.less b/src/vendor/tianai-captcha/captcha/disable/disable.less new file mode 100644 index 0000000..a8e932f --- /dev/null +++ b/src/vendor/tianai-captcha/captcha/disable/disable.less @@ -0,0 +1,25 @@ +#tianai-captcha.tianai-captcha-disable { + z-index: 999; + position: absolute; + left: 0; + top: 0; + .content { + width: 100%; + height: 180px; + position: relative; + overflow: hidden; + .bg-img-div { + background-image: url("../../images/dun.jpeg"); + width: 100%; + height: 100%; + overflow: hidden; + #content-span { + color: #fff; + overflow: hidden; + margin-top: 132px; + display: block; + text-align: center; + } + } + } +} diff --git a/src/vendor/tianai-captcha/captcha/image_click/image_click.js b/src/vendor/tianai-captcha/captcha/image_click/image_click.js new file mode 100644 index 0000000..b1e2b53 --- /dev/null +++ b/src/vendor/tianai-captcha/captcha/image_click/image_click.js @@ -0,0 +1,132 @@ +import "./image_click.less"; +import { + CommonCaptcha, + move, + initConfig, + destroyEvent, +} from "../common/common.js"; + +/** + * 滑动验证码 + */ + +const TYPE = "IMAGE_CLICK"; +function getTemplate(styleConfig) { + return ` +
+
+ ${styleConfig.i18n.image_click_title} + +
+
+
+ + +
+
+
+
+
确定
+
+`; +} +class ImageClick extends CommonCaptcha { + constructor(boxEl, styleConfig) { + super(); + this.boxEl = boxEl; + this.styleConfig = styleConfig; + this.type = TYPE; + this.currentCaptchaData = {}; + } + init(captchaData, endCallback, loadSuccessCallback) { + // 重载样式 + this.destroy(); + this.boxEl.append(getTemplate(this.styleConfig)); + this.el = this.boxEl.find("#tianai-captcha"); + // 绑定全局 + // window.currentCaptcha = this; + // 载入验证码 + this.loadCaptchaForData(this, captchaData); + this.endCallback = endCallback; + const moveFun = move.bind(null, this); + // 绑定事件 + this.el.find("#bg-img-click-mask").click((event) => { + if (event.target.className === "click-span") { + return; + } + this.currentCaptchaData.clickCount++; + const trackList = this.currentCaptchaData.trackList; + if (this.currentCaptchaData.clickCount === 1) { + this.currentCaptchaData.startTime = new Date(); + // move 轨迹 + window.addEventListener("mousemove", moveFun); + this.currentCaptchaData.startX = event.offsetX; + this.currentCaptchaData.startY = event.offsetY; + } + const startTime = this.currentCaptchaData.startTime; + trackList.push({ + x: Math.round(event.offsetX), + y: Math.round(event.offsetY), + type: "click", + t: new Date().getTime() - startTime.getTime(), + }); + const left = event.offsetX - 10; + const top = event.offsetY - 10; + this.el + .find("#bg-img-click-mask") + .append( + "" + + this.currentCaptchaData.clickCount + + "", + ); + // if (this.currentCaptchaData.clickCount === 4) { + // // 校验 + // this.currentCaptchaData.stopTime = new Date(); + // window.removeEventListener("mousemove", move); + // this.endCallback(this.currentCaptchaData,this); + // } + }); + this.el.find(".click-confirm-btn").click(() => { + if (this.currentCaptchaData.clickCount > 0) { + // 校验 + this.currentCaptchaData.stopTime = new Date(); + window.removeEventListener("mousemove", moveFun); + this.endCallback(this.currentCaptchaData, this); + } + }); + + if (loadSuccessCallback) { + // 加载成功 + loadSuccessCallback(this); + } + return this; + } + destroy() { + const existsCaptchaEl = this.boxEl.children("#tianai-captcha"); + if (existsCaptchaEl) { + existsCaptchaEl.remove(); + } + destroyEvent(); + } + loadCaptchaForData(that, data) { + const bgImg = that.el.find("#tianai-captcha-slider-bg-img"); + const tipImg = that.el.find("#tianai-captcha-tip-img"); + bgImg.on("load", () => { + that.currentCaptchaData = initConfig( + bgImg.width(), + bgImg.height(), + tipImg.width(), + tipImg.height(), + ); + that.currentCaptchaData.currentCaptchaId = data.data.id; + }); + bgImg.attr("src", data.data.backgroundImage); + tipImg.attr("src", data.data.templateImage); + } +} + +export default ImageClick; diff --git a/src/vendor/tianai-captcha/captcha/image_click/image_click.less b/src/vendor/tianai-captcha/captcha/image_click/image_click.less new file mode 100644 index 0000000..820a3df --- /dev/null +++ b/src/vendor/tianai-captcha/captcha/image_click/image_click.less @@ -0,0 +1,66 @@ +#tianai-captcha.tianai-captcha-word-click { + box-sizing: border-box; + .click-tip { + position: relative; + height: 40px; + width: 100%; + .tip-img { + height: 35px; + position: absolute; + right: 15px; + } + #tianai-captcha-click-track-font { + font-size: 18px; + display: inline-block; + height: 40px; + line-height: 40px; + position: absolute; + } + } + .slider-bottom { + position: relative; + top: 6px; + } + .content { + #bg-img-click-mask { + width: 100%; + height: 100%; + position: absolute; + left: 0; + top: 0; + .click-span { + position: absolute; + left: 0; + top: 0; + border-radius: 50px; + background-color: #409eff; + width: 20px; + height: 20px; + text-align: center; + line-height: 20px; + color: #fff; + border: 2px solid #fff; + box-sizing: content-box; + } + } + } + .click-confirm-btn { + width: 100%; + height: 35px; + border-radius: 4px; + background-image: linear-gradient( + 173deg, + hsl(38.09deg 91% 57.89%) 0%, + hsl(38.09deg 89.38% 71.74%) 100% + ); + font-size: 15px; + text-align: center; + box-sizing: border-box; + line-height: 35px; + color: #fff; + margin-top: 3px; + } + .click-confirm-btn:hover { + cursor: pointer; + } +} diff --git a/src/vendor/tianai-captcha/captcha/rotate/rotate.js b/src/vendor/tianai-captcha/captcha/rotate/rotate.js new file mode 100644 index 0000000..64513ff --- /dev/null +++ b/src/vendor/tianai-captcha/captcha/rotate/rotate.js @@ -0,0 +1,136 @@ +import "../slider/slider.less"; +import "./rotate.less"; +import { + CommonCaptcha, + down, + initConfig, + destroyEvent, +} from "../common/common.js"; + +/** + * 滑动验证码 + */ + +const TYPE = "ROTATE"; +function getTemplate(styleConfig) { + return ` +
+
+ ${styleConfig.i18n.rotate_title} +
+
+
+ + +
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+`; +} +class Rotate extends CommonCaptcha { + constructor(boxEl, styleConfig) { + super(); + this.boxEl = boxEl; + this.styleConfig = styleConfig; + this.type = TYPE; + this.currentCaptchaData = {}; + } + init(captchaData, endCallback, loadSuccessCallback) { + // 重载样式 + this.destroy(); + this.boxEl.append(getTemplate(this.styleConfig)); + this.el = this.boxEl.find("#tianai-captcha"); + this.loadStyle(); + // 按钮绑定事件 + this.el + .find("#tianai-captcha-slider-move-btn") + .mousedown(down.bind(null, this)); + this.el + .find("#tianai-captcha-slider-move-btn") + .touchstart(down.bind(null, this)); + // 绑定全局 + // window.currentCaptcha = this; + // 载入验证码 + this.loadCaptchaForData(this, captchaData); + this.endCallback = endCallback; + if (loadSuccessCallback) { + // 加载成功 + loadSuccessCallback(this); + } + return this; + } + + destroy() { + const existsCaptchaEl = this.boxEl.children("#tianai-captcha"); + if (existsCaptchaEl) { + existsCaptchaEl.remove(); + } + destroyEvent(); + } + doMove() { + const moveX = this.currentCaptchaData.moveX; + this.el + .find("#tianai-captcha-slider-move-btn") + .css("transform", "translate(" + moveX + "px, 0px)"); + this.el + .find("#tianai-captcha-slider-move-img") + .css( + "transform", + "rotate(" + moveX / (this.currentCaptchaData.end / 360) + "deg)", + ); + this.el + .find("#tianai-captcha-slider-move-track-mask") + .css("width", moveX + "px"); + } + loadStyle() { + let sliderImg = ""; + let moveTrackMaskBorderColor = "#00f4ab"; + let moveTrackMaskBgColor = "#a9ffe5"; + const styleConfig = this.styleConfig; + if (styleConfig) { + sliderImg = styleConfig.btnUrl; + moveTrackMaskBgColor = styleConfig.moveTrackMaskBgColor; + moveTrackMaskBorderColor = styleConfig.moveTrackMaskBorderColor; + } + this.el + .find(".slider-move .slider-move-btn") + .css("background-image", "url(" + sliderImg + ")"); + // this.el.find("#tianai-captcha-slider-move-track-font").text(title); + this.el + .find("#tianai-captcha-slider-move-track-mask") + .css("border-color", moveTrackMaskBorderColor); + this.el + .find("#tianai-captcha-slider-move-track-mask") + .css("background-color", moveTrackMaskBgColor); + } + loadCaptchaForData(that, data) { + const bgImg = that.el.find("#tianai-captcha-slider-bg-img"); + const sliderImg = that.el.find("#tianai-captcha-slider-move-img"); + bgImg.attr("src", data.data.backgroundImage); + sliderImg.attr("src", data.data.templateImage); + bgImg.on("load", () => { + that.currentCaptchaData = initConfig( + bgImg.width(), + bgImg.height(), + sliderImg.width(), + sliderImg.height(), + 300 - 63 + 5, + ); + that.currentCaptchaData.currentCaptchaId = data.data.id; + }); + } +} + +export default Rotate; diff --git a/src/vendor/tianai-captcha/captcha/rotate/rotate.less b/src/vendor/tianai-captcha/captcha/rotate/rotate.less new file mode 100644 index 0000000..441f2b0 --- /dev/null +++ b/src/vendor/tianai-captcha/captcha/rotate/rotate.less @@ -0,0 +1,12 @@ +#tianai-captcha.tianai-captcha-rotate { + .rotate-img-div { + height: 100%; + /*position: absolute;*/ + text-align: center; + img { + height: 100%; + transform: rotate(0deg); + display: inline-block; + } + } +} diff --git a/src/vendor/tianai-captcha/captcha/slider/slider.js b/src/vendor/tianai-captcha/captcha/slider/slider.js new file mode 100644 index 0000000..2d957d8 --- /dev/null +++ b/src/vendor/tianai-captcha/captcha/slider/slider.js @@ -0,0 +1,144 @@ +import "../common/common.less"; +import "./slider.less"; +import { + CommonCaptcha, + closeTips, + down, + initConfig, + showTips, + destroyEvent, +} from "../common/common.js"; + +/** + * 滑动验证码 + */ + +const TYPE = "SLIDER"; +function getTemplate(styleConfig) { + return ` +
+
+ ${styleConfig.i18n.slider_title} +
+
+
+ + +
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ +
+`; +} + +class Slider extends CommonCaptcha { + constructor(boxEl, styleConfig) { + super(); + this.boxEl = boxEl; + this.styleConfig = styleConfig; + this.type = TYPE; + this.currentCaptchaData = {}; + } + init(captchaData, endCallback, loadSuccessCallback) { + // 重载样式 + this.destroy(); + this.boxEl.append(getTemplate(this.styleConfig)); + this.el = this.boxEl.find("#tianai-captcha"); + this.loadStyle(); + // 按钮绑定事件 + this.el + .find("#tianai-captcha-slider-move-btn") + .mousedown(down.bind(null, this)); + this.el + .find("#tianai-captcha-slider-move-btn") + .touchstart(down.bind(null, this)); + // 绑定全局 + // window.currentCaptcha = this; + // 载入验证码 + this.loadCaptchaForData(this, captchaData); + this.endCallback = endCallback; + if (loadSuccessCallback) { + // 加载成功 + loadSuccessCallback(this); + } + return this; + } + showTips(msg, type, callback) { + showTips(this.el, msg, type, callback); + } + closeTips(callback) { + closeTips(this.el, callback); + } + + destroy() { + const existsCaptchaEl = this.boxEl.children("#tianai-captcha"); + if (existsCaptchaEl) { + existsCaptchaEl.remove(); + } + destroyEvent(); + } + doMove() { + const moveX = this.currentCaptchaData.moveX; + this.el + .find("#tianai-captcha-slider-move-btn") + .css("transform", "translate(" + moveX + "px, 0px)"); + this.el + .find("#tianai-captcha-slider-img-div") + .css("transform", "translate(" + moveX + "px, 0px)"); + this.el + .find("#tianai-captcha-slider-move-track-mask") + .css("width", moveX + "px"); + } + loadStyle() { + let sliderImg = ""; + let moveTrackMaskBorderColor = "#00f4ab"; + let moveTrackMaskBgColor = "#a9ffe5"; + const styleConfig = this.styleConfig; + if (styleConfig) { + sliderImg = styleConfig.btnUrl; + moveTrackMaskBgColor = styleConfig.moveTrackMaskBgColor; + moveTrackMaskBorderColor = styleConfig.moveTrackMaskBorderColor; + } + this.el + .find(".slider-move .slider-move-btn") + .css("background-image", "url(" + sliderImg + ")"); + // this.el.find("#tianai-captcha-slider-move-track-font").text(title); + this.el + .find("#tianai-captcha-slider-move-track-mask") + .css("border-color", moveTrackMaskBorderColor); + this.el + .find("#tianai-captcha-slider-move-track-mask") + .css("background-color", moveTrackMaskBgColor); + } + loadCaptchaForData(that, data) { + const bgImg = that.el.find("#tianai-captcha-slider-bg-img"); + const sliderImg = that.el.find("#tianai-captcha-slider-move-img"); + bgImg.attr("src", data.data.backgroundImage); + sliderImg.attr("src", data.data.templateImage); + bgImg.on("load", () => { + that.currentCaptchaData = initConfig( + bgImg.width(), + bgImg.height(), + sliderImg.width(), + sliderImg.height(), + 300 - 63 + 5, + ); + that.currentCaptchaData.currentCaptchaId = data.data.id; + }); + } +} + +export default Slider; diff --git a/src/vendor/tianai-captcha/captcha/slider/slider.less b/src/vendor/tianai-captcha/captcha/slider/slider.less new file mode 100644 index 0000000..9745e79 --- /dev/null +++ b/src/vendor/tianai-captcha/captcha/slider/slider.less @@ -0,0 +1,89 @@ +#tianai-captcha.tianai-captcha-slider { + z-index: 999; + position: absolute; + left: 0; + top: 0; + .content { + width: 100%; + height: 180px; + position: relative; + overflow: hidden; + } + .bg-img-div { + width: 100%; + height: 100%; + position: absolute; + transform: translate(0px, 0px); + img { + height: 100%; + width: 100%; + border-radius: 5px; + } + } + .slider-img-div { + height: 100%; + position: absolute; + left: 0; + transform: translate(0px, 0px); + #tianai-captcha-slider-move-img { + height: 100%; + } + } + .slider-move { + height: 34px; + width: 100%; + margin: 11px 0; + position: relative; + } + .slider-move-track { + position: relative; + height: 32px; + line-height: 32px; + text-align: center; + background: #f5f5f5; + color: #999; + transition: 0s; + font-size: 14px; + box-sizing: content-box; + border: 1px solid #f5f5f5; + border-radius: 4px; + } + .refresh-btn, + .close-btn { + display: inline-block; + } + .slider-move { + line-height: 38px; + font-size: 14px; + text-align: center; + white-space: nowrap; + color: #88949d; + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; + filter: opacity(0.8); + } + .slider-move .slider-move-btn { + transform: translate(0px, 0px); + position: absolute; + top: -6px; + left: 0; + width: 63px; + height: 45px; + background-color: #fff; + background-repeat: no-repeat; + background-size: contain; + border-radius: 5px; + } + .slider-tip { + margin-bottom: 5px; + font-weight: bold; + font-size: 15px; + line-height: normal; + color: black; + } + .slider-move-btn:hover { + cursor: pointer; + } + user-select: none; +} diff --git a/src/vendor/tianai-captcha/captcha/word_image_click/word_image_click.js b/src/vendor/tianai-captcha/captcha/word_image_click/word_image_click.js new file mode 100644 index 0000000..787d110 --- /dev/null +++ b/src/vendor/tianai-captcha/captcha/word_image_click/word_image_click.js @@ -0,0 +1,13 @@ +import ImageClick from "../image_click/image_click"; +/** + * 滑动验证码 + */ +const TYPE = "WORD_IMAGE_CLICK"; +class WordImageClick extends ImageClick { + constructor(divId, styleConfig) { + super(divId, styleConfig); + this.type = TYPE; + } +} + +export default WordImageClick; diff --git a/src/vendor/tianai-captcha/images/dun.jpeg b/src/vendor/tianai-captcha/images/dun.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..347a371cb4cbf05b15bc0546d520675bb2418819 GIT binary patch literal 8340 zcmbVxWmp``w)RYLhX4sK!66VVxCVD837$Z(!F|vG2@qrmF2QYJu;30McyI;@g9Z0N z2MdG`_CDv_eed)Ax%aK=s<&!&tzJ)8Jzdpn-Tu7&1t3;cR8a%~fe!#IcL{Ji2ap4x zJ-EkxiFOBcO!RwTV`5@p;$Y+A;$Y+8;NlbE2t8>-}Hi_8Wi%8&C^;iUuSBJRkw0kpOSI0kn6f0)QBI#eV>N zfQF8NiG_`GCzd1z+&%cgUj}2KVcgvV1l)^BFdt$u^68L1k$r?%u5vuC z7)VFcq+ytv0#oRl8R7I(GBlfUvi#R5k*ksiCX!mxp4j|;iNq;{;EfO`$uZN#E$X&0 z4W!KC8o~dekR^G5*LZbum8Ta}1V`y+Kdp(I!srF(5og0NwKR*-GrY7JUD;W6aH3Hg zg`By6t%3h40O+UaIeDT)+E|k%#_G`)o-V)H6;tErE6;W1NSA@hDEa;fK4jPs;p|oJ z*PE(SnQwbvg!;PA^a{3)Boh>4NoNIZ|4r=V3uu-F?d0>f^5ve$Zs0Pi1{0EnKU2V# z|7+q%88{|9tXO0CjwBPe#U!+>#`C++G^p-Lk;dXdze~O{oR9QIhTcHJYU09j>K2ff z8X*WI-c2~y_?D+AeE2mmlJyO~slb&L=RP}~3d=x^U3`GHIt@y%D)5KUhlN=Ay#&!y zSv_0Ltcb)#@xU#+Fx(bRev8~*buy8GkZ?*~?NwG>8mrE|a7wF*jZ<7f$U`ToT)|Hj zDQOp2D2nT(AF;#UYacj~a(Ll{S{c|<>^{V?j z5vTdhb3I=THr=p6D@Q3C@~mO@!*IoQ@qATgv>dd(e8o_v-@h1(Sk_K{)M^b)IG_F~ zhc@+DA2`9nDe7uqb=GYs!EOeRIo15s84q`PI2HC6L!wp zE4xZFxhElyNH8r=%Zgx9+Y@qjvD^nL?FT3UsaoX>@dL=E;@n)yetbe`l`^LzoU~TuUvX1Z&ITXP||Vtde2Erbs>m^Ch zh922cxZ`vN2{gC8dch(=cEV`iB~p2#aYvb2(!KL!l*yRw$)*j#sS}n-8CNo^u(%eq zfoufFoRfZ8*Z35pv-?+lte*TV@Qg6!7Em}&D-Y7UdIBn*3!b47pQfS;tM2idc+ za3Un9`}3m)b5DMpLuY=Z_Eb4eU~B%6_SgJboy!a$LqZqOyshxFU%aPX0JK!�MuV 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 N3?*}KN6_u;{{tW|-Jbve literal 0 HcmV?d00001 diff --git a/src/vendor/tianai-captcha/images/icon.png b/src/vendor/tianai-captcha/images/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..586a123e00915dd6a143d4d74f134c5faa4a9831 GIT binary patch literal 3100 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 +} + +export interface TianAiCaptchaConfig { + bindEl: TianAiCaptchaBindTarget + requestCaptchaDataUrl: string + validCaptchaUrl: string + requestHeaders?: Record + timeToTimestamp?: boolean + validSuccess?: (res: any, captcha: any, tac: TianAiCaptchaInstance) => void + validFail?: (res: any, captcha: any, tac: TianAiCaptchaInstance) => void + btnRefreshFun?: (el: Event, tac: TianAiCaptchaInstance) => void + btnCloseFun?: (el: Event, tac: TianAiCaptchaInstance) => void +} + +export interface TianAiCaptchaInstance { + init: () => TianAiCaptchaInstance + reloadCaptcha: () => void + destroyWindow: () => void +} + +export function createTianAiCaptcha( + config: TianAiCaptchaConfig, + style?: TianAiCaptchaStyle, +): TianAiCaptchaInstance { + return new TianAiCaptcha(config, style) as TianAiCaptchaInstance +} + +export { CaptchaConfig, TianAiCaptcha } diff --git a/src/views/debug/CaptchaSandbox.vue b/src/views/debug/CaptchaSandbox.vue new file mode 100644 index 0000000..eec2fd3 --- /dev/null +++ b/src/views/debug/CaptchaSandbox.vue @@ -0,0 +1,209 @@ + + + + +