/*
 * @Description: 移植自uniapp的滑块验证码插件
 * @Author: laoliu
 * @Date: 2022-4-20 11:43:52
 */
<template>
	<div class="pt">
		<div class="pt-verification-box">
			<div class="pt-verification-images">
				<div class="iconfont refresh" @click="refresh">
					<i class="el-icon-refresh" />
				</div>
				<img class="bg-img" :src="vcodeImg.backgroundImg" :disabled="true" alt=""
					:style="{width: vcodeImg.width + 'px', height: vcodeImg.height + 'px'}" />
				<img class="drag-img" :src="vcodeImg.slideBlockImg" alt=""
					:style="{left: dragWidth + 'px', width: vcodeImg.blockWidth + 'px', height: vcodeImg.height + 'px'}" />
			</div>
			<div class="pt-dragbar">
				<div :class="['pt-drag-area', {fail: fail, success: success}]" 
					:style="{ width: dragWidth + 'px'}" v-if="dragWidth"></div>
				<div class="pt-dragbar-area" :class="disabled ? 'click-disable' : ''" @mousemove="dragPC" @touchmove="dragM" >
					<!-- mousemove事件放在父级组件上，是为了避免鼠标移动过快而失效的现象 -->
					<div :class="['pt-dragbar-block', {active: dragWidth > 2, fail: fail, success: success}]"
						:style="{'margin-left': dragWidth + 'px', 'width': slideBlockWidth + 'px'}"
						@mousedown="dragStartPC" @mouseup="dragEnd" @mouseleave="dragLeavePC" @touchstart="dragStartM" 
						@touchend="dragEnd" @touchcancel="dragEnd">
						<i :class="success ? 'el-icon-check' : (fail ? 'el-icon-close' : 'el-icon-right')" />
					</div>
					<div v-if="dragWidth == 0" class="tips">{{tips}}</div>
				</div>
			</div>
		</div>
	</div>
</template>

<script>
export default {
	props: {
		vcodeImg: Object,
		validateFunc: Function,		//结果验证函数
		
		tips: {
			type: String,
			default: '向右拖动滑块填充拼图'
		}
	},
	
	data() {
		return {
			disabled: false,
			dragStartX: 0,
			dragWidth: 0,
			slideBlockWidth: 50,
			success: false,
			fail: false,

			//鼠标移出滑块区域后的计时器
			mouseLeaveTimer: null
		};
	},
	
	methods: {
		// 开始拖拽
		dragStartPC(e) {
			//只有在块的位置为0时，才记录起始偏移量
			if (this.dragWidth == 0) this.dragStartX = e.pageX;
		},
		
		// 拖拽中
		dragPC(e) {
			if (e.which == 0) return; 		//未按下鼠标键,则返回
			let maxPos = this.calcMaxPos();
			let delta = e.pageX - this.dragStartX;
			if (delta <= 0) {
				this.dragWidth = 0;
				return;
			}
			this.dragWidth = delta >= maxPos ? maxPos : delta;
		},
		
		// 停止滑动后判断前后误差不超过5px，可自行修改
		dragEnd(_e) {
			if (this.dragWidth == 0) return;

			this.disabled = true;
			this.validateFunc(this.dragWidth).then(result =>{
				if (!result) {
					this.fail = true;
					this.disabled = true;

					this.$message({message: '验证失败，再来一次吧', type: 'error'});
					this.clearMouseLeaveTimer();
					this.$emit('refresh');
					
					setTimeout(() => {
						this.dragWidth = 0;
						this.fail = false;
					}, 1000)
				} else {
					this.success = true;
					this.disabled = true;
					setTimeout(() => {
						this.$emit('success');
						this.dragWidth = 0;
						this.fail = false;
						this.success = false;
						this.disabled = false;
      				}, 1000);
				}
			});
		},
		
		dragLeavePC(e) {
			//鼠标离开滑块区域超过2s，则自动进入滑动结束状态
			if (e.which != 0 && !this.mouseLeaveTimer) {
				this.mouseLeaveTimer = setTimeout(() => {
					this.dragEnd(e);
					this.mouseLeaveTimer = null;
				}, 5000);
			}
		},

		// 开始拖拽
    dragStartM(e) {
      e.preventDefault();
      // 只有在块的位置为0时，才记录起始偏移量
      if (this.dragWidth == 0) this.dragStartX = e.touches[0].pageX;
    },

    // 拖拽中
    dragM(e) {
      e.preventDefault();

      if (e.touches.length === 0) return; // 触摸点数量为0，返回
      let maxPos = this.calcMaxPos();
      let delta = e.touches[0].pageX - this.dragStartX;
      if (delta <= 0) {
        this.dragWidth = 0;
        return;
      }
      this.dragWidth = delta >= maxPos ? maxPos : delta;
    },

		dragEnter(_e) {
			this.clearMouseLeaveTimer();
		},

		calcMaxPos() {
			return this.vcodeImg.width - this.slideBlockWidth - 5;
		},

		refresh() {
			this.dragWidth = 0;
			this.fail = false;
			this.success = false;
			this.disabled = true;
			this.$emit('refresh');
		},

		clearMouseLeaveTimer() {
			if (this.mouseLeaveTimer == null) return;
		
			clearTimeout(this.mouseLeaveTimer);
			this.mouseLeaveTimer = null;
		},
	},

	watch: {
		vcodeImg(_newVal, _oldVal) {
			this.disabled = false;
		}
  },
}
</script>

<style lang="scss" scoped>
.iconfont {
	font-size: 16px;
	font-style: normal;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}
.click-disable {
	pointer-events: none;
}
.pt {
	user-select: none;	//禁止元素被选中，解决移动滑块时鼠标移动背景图像上后导到滑块无法再移动的问题
	width: 100%;
	margin: 0 auto;
	&-verification-images {
		position: relative;
		.refresh {
			position: absolute;
			right: 15px;
			top: 15px;
			z-index: 10;
			color: #FFF;
			font-weight: bold;
		}
		.bg-img {
			width: 100%;
			vertical-align: top;
		}
		.drag-img {
			position: absolute;
			width: 112px;
			top: 0px;
			left: 0;
			z-index: 1;
		}
	}
	&-dragbar {
		position: relative;
		height: 50px;
		background-color: #F7F7F7;
		border: solid 2px #EEE;
		margin-top: 10px;
		.pt-drag-area {
			position: absolute;
			height: 50px;
			border: solid 2px #007aff;
			background-color: #D1E9F1;
			top: -2px;
			&.fail {
				border-color: #dd524d;
				background-color: #ffdbdb;
			}
			&.success {
				border-color: #4cd964;
				background-color: #d7ffe1;
			}
		}
		&-area {
			position: absolute;
			width: 100%;
			height: 100%;
			left: 0;
			top: 0;
			.tips{
				font-size: 16px;
				color: #999;
				position: absolute;
				left: 50%;
				top: 50%;
				transform: translate(-50%,-50%);
			}
		}
		&-block {
			width: 50px;
			height: 50px;
			display: flex;
			align-items: center;
			justify-content: center;
			border: solid 2px #EEE;
			background-color: #FFF;
			top: -2px;
			left: 0;
			&.active {
				background-color: #007aff;
				border-color: #007aff;
				color: #FFF;
			}
			&.fail {
				background-color: #dd524d;
				border-color: #dd524d;
			}
			&.success {
				border-color: #4cd964;
				background-color: #00a029;
			}
		}
	}
}
</style>
