import { Component } from "react"; import Taro from "@tarojs/taro"; import { Image, Text, View } from "@tarojs/components"; import auth from "@/services/auth"; import { CSSTransition } from "react-transition-group"; import "./index.css"; import { aesEncrypt, uuid } from "./utils"; class Captcha extends Component { constructor(props) { super(props); this.state = { blockSize: { width: "50px", height: "50px", }, setSize: { imgHeight: 155, imgWidth: 310, barHeight: 40, barWidth: 310, }, backImgBase: "", blockBackImgBase: "", backToken: "", startMoveTime: "", secretKey: "", captchaType: "blockPuzzle", moveBlockBackgroundColor: "rgb(255, 255, 255)", leftBarBorderColor: "", iconColor: "", barAreaLeft: 0, barAreaOffsetWidth: 0, startLeft: null, moveBlockLeft: null, leftBarWidth: null, status: false, isEnd: false, passFlag: "", tipWords: "", text: "向右滑动完成验证", }; } componentDidMount() { this.uuid(); this.init(); // 组件卸载时移除事件监听 Taro.eventCenter.off("touchmove", this.touchMoveHandler); Taro.eventCenter.off("touchend", this.touchEndHandler); // 调用 setBarArea 方法 setTimeout(() => { this.setBarArea(this.bararea); }, 0); } // 初始化 uuid uuid() { const s = uuid(); const slider = "slider" + "-" + s; const point = "point" + "-" + s; if (!Taro.getStorageSync("slider")) { Taro.setStorageSync("slider", slider); } if (!Taro.getStorageSync("point")) { Taro.setStorageSync("point", point); } } init() { this.getData(); } getData() { auth.captcha .get({ captchaType: this.state.captchaType, clientUid: Taro.getStorageSync("slider"), ts: Date.now(), }) .then((res) => { if (res.data.repCode === "0000") { console.log(res.data.repData, "res.data.repData"); // 在组件中使用转换后的URL加载图片 // const imgUrl = base64ToURL(res.data.repData.originalImageBase64); // console.log(imgUrl,'imgUrl'); this.setState({ backImgBase: res.data.repData.originalImageBase64, blockBackImgBase: res.data.repData.jigsawImageBase64, backToken: res.data.repData.token, secretKey: res.data.repData.secretKey, }); } // 请求次数超限 if (res.data.repCode === "6201") { this.setState({ backImgBase: null, blockBackImgBase: null, leftBarBorderColor: "#d9534f", iconColor: "#fff", // eslint-disable-next-line react/no-unused-state iconClass: "icon-close", passFlag: false, tipWords: res.data.repMsg, }); setTimeout(() => { this.setState({ tipWords: "", }); }, 1000); } }); } refresh = () => { this.getData(); this.setState({ moveBlockLeft: "", leftBarWidth: "", text: "向右滑动完成验证", moveBlockBackgroundColor: "#fff", leftBarBorderColor: "#337AB7", iconColor: "#fff", status: false, isEnd: false, }); }; setBarArea = (barArea) => { if (barArea) { Taro.createSelectorQuery() .select(".verify-bar-area") .boundingClientRect((rect) => { console.log("setBarArea", rect.left, rect.width); if (rect) { this.setState({ barAreaLeft: rect.left, barAreaOffsetWidth: rect.width, }); } }) .exec(); } }; // 鼠标按下时的事件处理函数 start = (e) => { console.log(e, "按下"); this.setState({ startMoveTime: new Date().getTime(), //记录开始滑动的时间 }); if (!this.state.isEnd) { this.setState({ text: "", moveBlockBackgroundColor: "#337ab7", //移动块背景颜色 leftBarBorderColor: "#337AB7", //左侧滑块边框颜色 iconColor: "#fff", //图标颜色 status: true, //状态标识为true }); e.stopPropagation(); //阻止事件冒泡 } }; // 鼠标/触摸移动时的事件处理函数 move = (e) => { console.log(e, "滑动滑动"); if (this.state.status && !this.state.isEnd) { // 兼容触摸事件和鼠标事件 let x = e.touches ? e.touches[0].pageX : e.pageX; // 获取鼠标/触摸点的X坐标 console.log(x); let bar_area_left = this.state.barAreaLeft; // 滑块区域左侧距离 let move_block_left = x - bar_area_left; // 计算移动块的左侧距离 console.log( move_block_left >= this.state.barAreaOffsetWidth - parseInt(parseInt(this.state.blockSize.width) / 2) - 2, ); if ( move_block_left >= this.state.barAreaOffsetWidth - parseInt(parseInt(this.state.blockSize.width) / 2) - 2 ) { console.log("第一个判断计算"); move_block_left = this.state.barAreaOffsetWidth - parseInt(parseInt(this.state.blockSize.width) / 2) - 2; } if (move_block_left <= 0) { console.log("第二个判断计算"); move_block_left = parseInt(this.state.blockSize.width / 2); } let moveBlockLeft = Math.floor(move_block_left - this.state.startLeft) + "px"; //计算移动块的左侧位置并取整 let leftBarWidth = Math.floor(move_block_left - this.state.startLeft) + "px"; //计算左侧滑块的宽度并取整 console.log(moveBlockLeft, leftBarWidth); //打印移动块左侧位置和左侧滑块宽度 this.setState({ moveBlockLeft: moveBlockLeft, //更新移动块左侧位置 leftBarWidth: leftBarWidth, //更新左侧滑块宽度 }); } }; end = () => { console.log("鼠标放下"); let endMoveTime = +new Date(); if (this.state.status && !this.state.isEnd) { let moveLeftDistance = parseInt( (this.state.moveBlockLeft || "").replace("px", ""), ); moveLeftDistance = (moveLeftDistance * 310) / parseInt(this.state.setSize.imgWidth); let data = { captchaType: this.state.captchaType, pointJson: this.state.secretKey ? aesEncrypt( JSON.stringify({ x: moveLeftDistance, y: 5.0, }), this.state.secretKey, ) : JSON.stringify({ x: moveLeftDistance, y: 5.0 }), token: this.state.backToken, clientUid: Taro.getStorageSync("slider"), ts: Date.now(), }; auth.captcha.check(data).then((res) => { if (res.data.repCode === "0000") { this.setState({ isEnd: true, passFlag: true, tipWords: `${((endMoveTime - this.state.startMoveTime) / 1000).toFixed(2)}s验证成功`, }); setTimeout(() => { this.setState({ tipWords: "", }); const captchaVerification = this.state.secretKey ? aesEncrypt( this.state.backToken + "---" + JSON.stringify({ x: moveLeftDistance, y: 5.0, }), this.state.secretKey, ) : this.state.backToken + "---" + JSON.stringify({ x: moveLeftDistance, y: 5.0 }); this.props.handleClick(captchaVerification); this.refresh(); }, 1000); } else { this.setState({ isEnd: true, moveBlockBackgroundColor: "#d9534f", leftBarBorderColor: "#d9534f", iconColor: "#fff", // eslint-disable-next-line react/no-unused-state iconClass: "icon-close", passFlag: false, tipWords: res.data.repMsg || "验证失败", }); setTimeout(() => { this.refresh(); this.setState({ tipWords: "", }); }, 1000); } }); this.setState({ status: false, }); } }; render() { const { vSpace, barSize, transitionWidth, finishText, transitionLeft } = this.props; return ( {/* 其他内容 */} 0} timeout={150} classNames="tips" unmountOnExit > {this.state.tipWords} (this.bararea = ref)} > {this.state.text} {finishText} ); } } Captcha.defaultProps = { mode: "fixed", vSpace: 5, imgSize: { width: "310px", height: "200px", }, barSize: { width: "310px", height: "40px", }, setSize: { imgHeight: 200, imgWidth: 310, barHeight: 0, barWidth: 0, }, }; export default Captcha;