<template>
	<view class="u-code-wrap">

	</view>
</template>

<script>
	/**
	 * verificationCode 验证码输入框
	 * @description 考虑到用户实际发送验证码的场景，可能是一个按钮，也可能是一段文字，提示语各有不同，所以本组件 不提供界面显示，只提供提示语，由用户将提示语嵌入到具体的场景
	 * @tutorial https://www.uviewui.com/components/verificationCode.html
	 * @property {Number String} seconds 倒计时所需的秒数（默认60）
	 * @property {String} start-text 开始前的提示语，见官网说明（默认获取验证码）
	 * @property {String} change-text 倒计时期间的提示语，必须带有字母"x"，见官网说明（默认X秒重新获取）
	 * @property {String} end-text 倒计结束的提示语，见官网说明（默认重新获取）
	 * @property {Boolean} keep-running 是否在H5刷新或各端返回再进入时继续倒计时（默认false）
	 * @event {Function} change 倒计时期间，每秒触发一次
	 * @event {Function} start 开始倒计时触发
	 * @event {Function} end 结束倒计时触发
	 * @example <u-verification-code :seconds="seconds" @end="end" @start="start" ref="uCode" 
	 */
	export default {
		name: "u-verification-code",
		props: {
			// 倒计时总秒数
			seconds: {
				type: [String, Number],
				default: 60
			},
			// 尚未开始时提示
			startText: {
				type: String,
				default: '获取验证码'
			},
			// 正在倒计时中的提示
			changeText: {
				type: String,
				default: 'X秒重新获取'
			},
			// 倒计时结束时的提示
			endText: {
				type: String,
				default: '重新获取'
			},
			// 是否在H5刷新或各端返回再进入时继续倒计时
			keepRunning: {
				type: Boolean,
				default: false
			}
		},
		data() {
			return {
				secNum: this.seconds,
				timer: null,
				canGetCode: true, // 是否可以执行验证码操作
			}
		},
		mounted() {
			this.checkKeepRunning();
		},
		watch: {
			seconds: {
				immediate: true,
				handler(n) {
					this.secNum = n;
				}
			}
		},
		methods: {
			checkKeepRunning() {
				// 获取上一次退出页面(H5还包括刷新)时的时间戳，如果没有上次的保存，此值可能为空
				let lastTimestamp = Number(uni.getStorageSync('$uCountDownTimestamp'));
				// 当前秒的时间戳
				let nowTimestamp = Math.floor((+ new Date()) / 1000);
				// 判断当前的时间戳，是否小于上一次的本该按设定结束，却提前结束的时间戳
				if(this.keepRunning && lastTimestamp && lastTimestamp > nowTimestamp) {
					// 剩余尚未执行完的倒计秒数
					this.secNum = lastTimestamp - nowTimestamp;
					// 清除本地保存的变量
					uni.setStorageSync('$uCountDownTimestamp', 0);
					// 开始倒计时
					this.start();
				} else {
					// 如果不存在需要继续上一次的倒计时，执行正常的逻辑
					this.changeEvent(this.startText);
				}
			},
			// 开始倒计时
			start() {
				//this.secNum = this.seconds;
				this.$emit('start');
				this.canGetCode = false;
				// 这里放这句，是为了一开始时就提示，否则要等setInterval的1秒后才会有提示
				this.changeEvent(this.changeText.replace(/x|X/, this.secNum));
				this.timer = setInterval(() => {
					if (--this.secNum) {
						// 用当前倒计时的秒数替换提示字符串中的"x"字母
						this.changeEvent(this.changeText.replace(/x|X/, this.secNum));
					} else {
						clearInterval(this.timer);
						this.changeEvent(this.endText);
						this.secNum = this.seconds;
						this.$emit('end');
						this.canGetCode = true;
					}
					this.setTimeToStorage();
				}, 1000);
			},
			// 重置，可以让用户再次获取验证码
			reset() {
				this.canGetCode = true;
				clearInterval(this.timer);
				this.secNum = this.seconds;
				this.changeEvent(this.endText);
			},
			changeEvent(text) {
				this.$emit('change', text);
			},
			// 保存时间戳，为了防止倒计时尚未结束，H5刷新或者各端的右上角返回上一页再进来
			setTimeToStorage() {
				if(!this.keepRunning) return ;
				// 记录当前的时间戳，为了下次进入页面，如果还在倒计时内的话，继续倒计时
				// 倒计时尚未结束，结果大于0；倒计时已经开始，就会小于初始值，如果等于初始值，说明没有开始倒计时，无需处理
				if(this.secNum > 0 && this.secNum < this.seconds) {
					// 获取当前时间戳(+ new Date()为特殊写法)，除以1000变成秒，再去除小数部分
					let nowTimestamp = Math.floor((+ new Date()) / 1000);
					// 将本该结束时候的时间戳保存起来 => 当前时间戳 + 剩余的秒数
					uni.setStorage({
						key: '$uCountDownTimestamp',
						data: nowTimestamp + this.secNum
					})
				}
			}
		},
		// 组件销毁的时候，清除定时器，否则定时器会继续存在，系统不会自动清除
		beforeDestroy() {
			clearTimeout(this.timer);
			this.timer = null;
			this.setTimeToStorage();
		}
	}
</script>

<style lang="scss" scoped>
	.u-code-wrap {
		width: 0;
		height: 0;
		position: fixed;
		z-index: -1;
	}
</style>
