<template>
	<view>
		<view class="cu-modal" :class="show?'show':''" @click.stop="close()">
			<view @click.stop @touchmove.stop="'diyname'" class="cu-dialog captchaDialog bg-white text-left"
				style="border-radius: 40rpx">
				<view class="padding-xs margin-top text-center">
					<text class="text-grey text-df">人机验证</text>
				</view>
				<view class="margin-top-xs text-center">
					<text class="text-lg text-black">{{title}}</text>
				</view>
				<view class="margin-top-lg flex justify-center text-sl">
					<view class="captchaImage flex-center bg-white">
						<view v-if="captchaSrc!=''" class="captchaData" :style="{ transform:  `rotate(${imageTransform}deg)`, backgroundImage: `url(${captchaSrc})` }"></view>
						<text v-if="pageLoading || captchaSrcLoading" class="captchaIcon wlIcon-jiazai2 text-orange wlIconfont-spin"></text>
						<text v-if="captchaError" name="close" class="captchaIcon wlIcon-31guanbi text-white"></text>
						<template v-if="isDrag">
							<!-- 辅助虚线 -->
							<view class="verticalArrow"></view>
							<view class="transverseArrow"></view>
						</template>
					</view>
				</view>
				<view class="capFoot margin-top-lg margin-bottom-sm padding-lr-sm">
					<view class="slider solid" id="slider">
						<view class="sliderItem clickActive-gray text-xxl" :class="captchaError?'shake':''" id="sliderItem"
							@touchstart="dragStart" @touchmove.prevent="dragMove" @touchend="dragEnd"
							@mousedown="dragStart" @mousemove.prevent="dragMove" @mouseup="dragEnd"
							@dragstart="dragStart" @dragend="dragEnd" @dragover.stop @drop="dragMove" :style="{
							left: `${sliderItemLeft}px`,
							backgroundColor: captchaError?'red':(isDrag?'#fe6600':'#fff')
						}">
							<text v-if="dragLoading || pageLoading || captchaSrcLoading" class="wlIcon-jiazai2 wlIconfont-spin"></text>
							<text v-else :class="dragIcon" class="wlIcon-shoushouzhang"></text>
						</view>
					</view>
				</view>
				<view class="text-center text-sm margin-bottom">
					<view class="text-xs text-gray">
						<text>由</text>
						<text class="padding-lr-xs text-red">Wanl</text>
						<text>提供技术支持</text>
					</view>
				</view>
				<view class="captchaCloseView">
					<text @click="close" name="close" class="wlIcon-31guanbi text-white text-sl"></text>
				</view>
			</view>
		</view>

	</view>
</template>
<script>
	let pmsSuccess = null; //验证成功事件
	let pmsError = null; //弹窗关闭事件
	export default {
		data() {
			return {
				title: '',
				show: false, //控制弹窗是否展示
				captchaSrc: "", //验证码图片 base64
				
				isDrag: false, //是否拖动中
				dragStartTime: 0, //拖动开始时间
				dragUseTime: 0, //拖动用时
				mouseTrackList: [], //鼠标轨迹列表

				sliderItemInitX: 0, //滑动按钮初始X坐标
				sliderItemLeftMax: 0, //滑块允许距离左边最大长度
				sliderItemLeft: 0,

				captchaSrcLoading: false, //请求图片验证码中
				pageLoading: false, //页面加载中，验证码图片加载中
				dragLoading: false, //拖动按钮loading状态
				captchaError: false, //是否验证失败
				append: {} //附加信息
			}
		},
		computed: {
			/**
			 * 图片旋转角度
			 */
			imageTransform() {
				if (this.sliderItemLeft == 0) return 0;
				return Math.ceil((360 / this.sliderItemLeftMax) * this.sliderItemLeft * 100) / 100;
			},
			/**
			 * 拖动条上的图标
			 */
			dragIcon() {
				let white = 'text-white';
				let black = 'text-black';
				if (this.captchaError) return white;
				if (this.isDrag) return white;
				return black;
			}
		},
		methods: {
			/**
			 * 外部调用
			 */
			init(append) {
				return new Promise((yes, err) => {
					pmsSuccess = yes;
					pmsError = err;
					this.append = append;
					this.captchaSrc = false;
					this.captchaError = false;
					this.isDrag = false;
					this.captchaSrcLoading = false;
					this.pageLoading = false;
					this.dragLoading = false;
					this.show = true;
					if (this.sliderItemLeftMax == 0) {
						this.pageLoading = true;
						setTimeout(() => {
							this.$nextTick(() => {
								this.getRect('#slider').then(res => {
									let sliderWidth = res.width;
									this.getRect('#sliderItem').then(res => {
										this.sliderItemInitX = res.left;
										this.sliderItemLeftMax = sliderWidth - res.width;
										this.pageLoading = false;
										this.getCaptchaSrc()
									}).catch((err) => {
										console.log("获取节点信息失败 2 -> ", err);
									})
								}).catch((err) => {
									console.log("获取节点信息失败 1 -> ", err);
								})
							})
						}, 500)
					} else {
						this.getCaptchaSrc()
					}
				})
			},
			/**
			 * 手动关闭弹窗
			 */
			close() {
				this.show = false;
				pmsError(); //执行关闭回调事件
			},
			/**
			 * 拖动开始事件
			 */
			dragStart(e) {
				let that = this;
				if (that.dragLoading) return false;
				if (that.pageLoading) return false;
				if (that.captchaSrcLoading) return false;
				that.mouseTrackList = []; //初始化轨迹列表
				that.dragStartTime = new Date().getTime(); //记录开始时间
				that.isDrag = true;
				that.addMouseTrack(e);
			},
			/**
			 * 手指移动事件
			 */
			dragMove(e) {
				let that = this;
				if (that.dragLoading) return false;
				if (that.pageLoading) return false;
				if (that.captchaSrcLoading) return false;
				if (!that.isDrag) return false;
				let maringLeft = (e.clientX ? e.clientX : e.changedTouches[0].clientX) - that.sliderItemInitX - 30;
				if (maringLeft < 0) maringLeft = 0;
				if (maringLeft > that.sliderItemLeftMax) maringLeft = that.sliderItemLeftMax;
				that.sliderItemLeft = maringLeft;
				that.addMouseTrack(e);
			},
			/**
			 * 拖动结束事件
			 */
			dragEnd(e) {
				let that = this;
				if (that.dragLoading) return false;
				if (that.pageLoading) return false;
				if (that.captchaSrcLoading) return false;
				that.addMouseTrack(e);
				that.isDrag = false;
				that.dragLoading = true; //开启loading准备ajax
				that.dragUseTime = new Date().getTime() - that.dragStartTime; //计算拖动时间
				that.checkCaptcha();
			},
			/**
			 * 加载验证码
			 */
			getCaptchaSrc() {
				this.captchaSrcLoading = true;
				this.sliderItemLeft = 0;
				this.captchaSrc = '';
				this.title = '拖动滑块使图片角度为正';
				uni.request({
					url: '/wanlshop/sms/captcha',
					method: 'POST',
					withCredentials: true,
					complete: res => {
						this.captchaSrcLoading = false;
						if(res.res.code == 1){
							this.dragLoading = false;
							this.captchaSrc = `data:image/png;base64,${res.res.data.captchaSrc}`
							// // #ifdef MP
							// uni.removeStorageSync('wanlshop:cookie');
							// uni.setStorageSync('wanlshop:cookie', res.header['Set-Cookie'].split(";")[0]);
							// // #endif
							// #ifdef MP || H5
							uni.removeStorageSync('wanlshop:cookie');
							uni.setStorageSync('wanlshop:cookie', res.res.data.captchaCookie);
							// #endif
							
						}else{
							this.$wanlshop.msg(res.res.msg);
							setTimeout(()=>{ // 防止闪烁，延迟一秒
							  this.close(); //关闭验证码
							},1600)
						}
					}
				});
			},
			/**
			 * 提交效验
			 */
			checkCaptcha() {
				uni.request({
					url: '/wanlshop/sms/check',
					method: 'POST',
					withCredentials: true,
					// #ifdef MP || H5
					header:{
						'Cookie': uni.getStorageSync('wanlshop:cookie')
					},
					// #endif
					data: {
						append: JSON.stringify(this.append),
						rotationAngle: this.imageTransform, //旋转角度，为'坏人'增加繁琐的工作
						mouseTrackList: JSON.stringify(this.mouseTrackList), //滑动轨迹
						dragUseTime: this.dragUseTime, //拖动用时
						dragStartTime: this.dragStartTime, //拖动开始时间
						keyO: Math.ceil(new Date().getTime() * Math.random() * 678951),
						keyA: Math.ceil(new Date().getTime() * Math.random() * 123456),
						keyD: Math.ceil(new Date().getTime() * Math.random() * 781545),
						hash: Math.ceil(new Date().getTime() * Math.random() * 456789),
						md5Key: Math.ceil(new Date().getTime() * Math.random() * 7891),
					},
					complete: res => {
						if(res.res.code == 1){
							this.title = '恭喜你，验证成功！';
							this.show = false;
							pmsSuccess(); //回调
						}else{
							this.title = res.res.msg;
							this.dragLoading = false;
							this.captchaError = true;
							setTimeout(() => {
								this.captchaError = false;
								if(res.res.code == 0){
									this.getCaptchaSrc();
								}else{
									if(res.res.data.getNewCaptcha){
										this.getCaptchaSrc();
									}else{
										this.captchaSrcLoading = false;
										this.sliderItemLeft = 0;
									}
								}
							}, 1000)
						}
					}
				});
			},
			/**
			 * 添加滑动数据进鼠标轨迹列表
			 */
			addMouseTrack() {
				let lastTime = this.mouseTrackList == '' ? this.dragStartTime : this.mouseTrackList[this.mouseTrackList
					.length - 1].t;
				let now = new Date().getTime();
				if (lastTime + 200 <= now) {
					this.mouseTrackList.push({
						r: Math.ceil(this.imageTransform / 360 * 10000) / 100, //当前角度
						t: now, //当前时间戳
					})
				}
			},
			getRect(selector, all) {
				return new Promise(resolve => {
					let query = null;
					// 支付宝小程序不能加后面的.in(this)，是它自身的限制
					// #ifndef MP-ALIPAY
					query = uni.createSelectorQuery().in(this)
					// #endif
					// #ifdef MP-ALIPAY
					query = uni.createSelectorQuery()
					// #endif
					query[all ? 'selectAll' : 'select'](selector)
						.boundingClientRect(rect => {
							if (all && Array.isArray(rect) && rect.length) {
								resolve(rect)
							}
							if (!all && rect) {
								resolve(rect)
							}
						})
						.exec()
				})
			}
		}
	}
</script>
<style lang="scss" scoped>
	.captchaImage {
		height: 320rpx;
		width: 320rpx;
		border-radius: 50%;
		overflow: hidden;
		position: relative;
		display: flex;
		align-items: center;
		justify-content: center;
		.captchaData{
			height: 320rpx;
			width: 320rpx;
			border-radius: 50%;
			overflow: hidden;
			background-color: #f5f5f5;
			background-position: center center;
			background-size: cover;
			background-repeat: no-repeat;
		}
		
		.captchaIcon {
			position: absolute;
		}

		.verticalArrow {
			position: absolute;
			height: 320rpx;
			border-left: 1px dashed #fff;
			margin-left: 1px;
			width: 1px;
		}

		.transverseArrow {
			position: absolute;
			height: 1px;
			width: 320rpx;
			border-top: 1px dashed #fff;
			margin-top: 1px;
			overflow: visible;
		}
	}

	.capFoot {
		height: 60px;
		display: flex;
		flex-direction: row;
		justify-content: center;

		.slider {
			width: 580rpx;
			height: 90rpx;
			background-color: #f5f5f5;
			border-radius: 900rpx;
			overflow: hidden;
			position: relative;

			.sliderItem {
				height: 88rpx;
				width: 110rpx;
				border-radius: 900rpx;
				background-color: white;
				position: absolute;
				left: 0;
				top: 1rpx;
				cursor: pointer;
				display: flex;
				justify-content: center;
				align-items: center;
				-webkit-box-shadow: 0 21px 52px 0 rgba(82, 82, 82, .2);
				box-shadow: 0 21px 52px 0 rgba(82, 82, 82, .2);
			}
		}
	}

	.shake {
		animation: shake 800ms ease-in-out;
	}

	@keyframes shake {

		/* 水平抖动，核心代码 */
		10%,
		90% {
			transform: translate3d(-1px, 0, 0);
		}

		20%,
		80% {
			transform: translate3d(+2px, 0, 0);
		}

		30%,
		70% {
			transform: translate3d(-3px, 0, 0);
		}

		40%,
		60% {
			transform: translate3d(+3px, 0, 0);
		}

		50% {
			transform: translate3d(-3px, 0, 0);
		}
	}

	.captchaDialog {
		position: relative;
		overflow: visible;
	}

	.captchaCloseView {
		position: absolute;
		bottom: -150rpx;
		width: 100%;
		height: 100rpx;
		display: flex;
		align-items: center;
		justify-content: center;
	}
</style>