<template>
	<view>
		<el-empty v-if="data.status == 'empty'" mode="data"></el-empty>
		<scroll-view 
		v-else
		:style="{ 'min-height': scrollHeight != 'auto' ? scrollHeight + 'px' : 'auto','background-color': background}" 
		:scroll-y="data.allow_scroll_y" 
		:scroll-with-animation="true"
		:scroll-anchoring="true"
		@scroll="scroll"
		@scrolltolower="scrolltolower">
			<view class="refresh-moudle" @touchstart="touchStart($event)" @touchmove="touchMove($event)" @touchend="touchEnd($event)" :style="{ transform: 'translate3d(0,' + data.top + 'px, 0)','min-height': scrollHeight != 'auto' ? scrollHeight + 'px' : 'auto' }">
				<view class="pull-refresh">
					<slot name="refresh">
						<view class="refresh-box">
							<view class="tips-box" v-if="data.dropDownState==1">
								<el-loading-icon :modelValue="true"></el-loading-icon>
								<view class="text" :style="{ color: fontColor }">{{ data.dropDownInfo.downText }}</view>
							</view>
							<view class="tips-box" v-if="data.dropDownState==2">
								<el-loading-icon :modelValue="true"></el-loading-icon>
								<view class="text" :style="{ color: fontColor }">{{ data.dropDownInfo.upText }}</view>
							</view>
							<view class="tips-box" v-if="data.dropDownState==3">
								<el-loading-icon :modelValue="true"></el-loading-icon>
								<view class="text" :style="{ color: fontColor }">{{ data.dropDownInfo.refreshText }}</view>
							</view>
						</view>
					</slot>
				</view>
				<slot></slot>
				<slot name="more">
					<view class="more-wrap" v-if="inArray(data.status,['loading','end'])">
						<view v-if="data.status == 'loading'">
							<el-loading-icon :modelValue="true"></el-loading-icon>
							<text class="more-text" :style="{ color: fontColor }">加载中...</text>
						</view>
						<view v-if="data.status == 'end'">
							<text class="more-text" :style="{ color: fontColor }">没有更多了~</text>
						</view>
					</view>
				</slot>
			</view>
		</scroll-view>
	</view>
</template>

<script setup>
	import { computed,ref,nextTick } from "vue";
	import { inArray } from "@/el-ui/libs/check.js";
	
	const props = defineProps({
		scrollHeight: {
			type: [Number,String],
			default: 'auto'
		},
		defaultOffset: {
			type: Number,
			default: 60
		},
		fontColor: {
			type: String,
			default: "#303133"
		},
		background: {
			type: String,
			default: "transparent"
		}
	});
	
	const emits = defineEmits(["refresh","scrolltolower"]);
	
	let data = ref({
		top: 0,
		startY: 0,
		isDropDown: false, // 是否下拉
		isRefreshing: false, // 是否正在刷新
		dropDownState: 1, // 显示1: 下拉可以刷新, 2: 松开立即刷新, 3: 正在刷新数据中...
		dropDownInfo: {
			downText: '下拉更新', // 释放更新
			upText: '释放更新',
			refreshText: '加载中...'
		},
		scrollTop: 0,
		allow_scroll_y: true,
		allowTouchMove: true,
		/**
		 * more: 更多数据
		 * loading: 加载中
		 * end: 没有更多了
		 * endLock: 和end相同，但不会显示上拉没有数据内容提示
		 * empty: 页面为空
		 */
		status: "more"
	});
	
	let pageNum   = ref(1);
	let pageSize  = ref(0);
	let pageTotal = ref(0);
	const scrolltolower = ()=>{
		if(data.value.status == "end" || data.value.status == "endLock"){
			return ;
		}
		
		emits('scrolltolower',{ page: pageNum.value, size: pageSize.value, total: pageTotal.value });
	}
	
	const scroll = (e)=>{
		nextTick(()=>{
			data.value.scrollTop = e.detail.scrollTop;
		});
	}
	
	/**
	 * 触摸开始，手指点击屏幕时
	 * @param {object} e Touch 对象包含的属性
	 */
	const touchStart = (e)=>{
		data.value.startY 			= e.changedTouches[0].pageY;
		data.value.startScrollTop 	= data.value.scrollTop;
		data.value.allowTouchMove 	= true;
	}
	
	/**
	* 接触点改变，滑动时
	* @param {object} e Touch 对象包含的属性
	*/
	const touchMove = (e)=>{
		if(!data.value.allowTouchMove) {
			return;
		}

		nextTick(()=>{
			if(data.value.scrollTop < 0) {
				data.value.allow_scroll_y = false;
			} else {
				data.value.allow_scroll_y = true;
			}
		});

		if(data.value.scrollTop <= 0) {
			if (e.changedTouches[0].pageY > data.value.startY) {
				data.value.isDropDown = true
				if (!data.value.isRefreshing) {
					let diff = e.changedTouches[0].pageY - data.value.startY -  data.value.startScrollTop;
					data.value.top = Math.pow(diff, 0.8) + (data.value.dropDownState === 3 ? props.defaultOffset : 0);
					if (data.value.top >= props.defaultOffset) {
						data.value.dropDownState = 2;
						//e.preventDefault();
					} else { 
						data.value.dropDownState = 1;
						//e.preventDefault();
					}
				}
			} else {
				data.value.isDropDown 		= false;
				data.value.dropDownState 	= 1;
			}
		}
	}
	
	/**
	* 触摸结束，手指离开屏幕时
	* @param {object} e Touch 对象包含的属性
	*/
	const touchEnd = (e)=>{
		nextTick(()=>{
			data.value.allow_scroll_y = true;
		});

		if (data.value.isDropDown && !data.value.isRefreshing) {
			if (data.value.top >= props.defaultOffset) {
				data.value.isRefreshing 	= true;
				refresh();
			} else {
				data.value.isRefreshing 	= false;
				data.value.isDropDown 		= false;
				data.value.dropDownState 	= 1;
				data.value.top 				= 0;
			}
		}
	}
	
	/**
	 * 刷新
	 */
	const refresh = ()=>{
		data.value.dropDownState 	= 3;
		data.value.top 				= props.defaultOffset;
		data.value.status 			= "more";
		pageNum.value               = 1;
		setTimeout(() => {
			emits('refresh');
			refreshDone();
		},600);
	}
	
	/**
	* 刷新完成
	*/
	const refreshDone = ()=>{
		data.value.isRefreshing 	= false;
		data.value.isDropDown 		= false;
		data.value.dropDownState 	= 1;
		data.value.top 				= 0;
	}
	
	/**
	 * @param string|number  total 总页数
	 * @param string|number  size 当前数据请求个数
	 */
	const setData = (total=10,size=10)=>{
		pageSize.value  = size;
		pageTotal.value = total;
		if(pageNum.value >= total || size <= 0){
			endPage();
		}else{
			pageNum.value += 1;
			morePage();
		}
	}
	
	const resetPage = ()=>{
		morePage();
		emits('scrolltolower',{ page: 1, size: pageSize.value, total: pageTotal.value });
	}
	
	const emptyPage = ()=>{
		data.value.status = "empty";
	}
	
	const morePage = ()=>{
		data.value.status = "more";
	}
	
	const loadingPage = ()=>{
		data.value.status = "loading";
	}
	
	const endPage = ()=>{
		data.value.status = "end";
	}
	
	const endLockPage = ()=>{
		data.value.status = "endLock";
	}
	
	const isStatus = (value)=>{
		return data.value.status == value;
	}
	
	const isEmpty = ()=>{
		return isStatus("empty");
	}
	
	const isMore = ()=>{
		return isStatus("more");
	}
	
	const isLoading = ()=>{
		return isStatus("loading");
	}
	
	const isEnd = ()=>{
		return isStatus("end");
	}
	
	defineExpose({
		refresh,
		setData,
		resetPage,
		emptyPage,
		morePage,
		loadingPage,
		endPage,
		endLockPage,
		isStatus,
		isEmpty,
		isMore,
		isLoading,
		isEnd
	});
	
</script>

<style lang="scss" scoped>
	.refresh-moudle {
		width: 100%;
		margin-top: -30px;
		-webkit-overflow-scrolling: touch;
		.more-wrap {
			display: flex;
			align-items: center;
			justify-content: center;
			box-sizing: border-box;
			min-height: 110rpx;
			padding: 30rpx 0;
			.more-text {
				padding: 0 20rpx;
				font-size: 28rpx;
			}
		}
		.pull-refresh {
			width: 100%;
			color: #999;
			transition-duration: 200ms;
			font-size: 28rpx;
			.refresh-box {
				.tips-box {
					display: flex;
					align-items: center;
					justify-content: center;
					height: 30px;
					.text {
						padding: 0 20rpx;
						font-size: 28rpx;
					}
				}
			}
			@keyframes anticlockwise {
			  0% {
				transform: rotate(-180deg);
			  }
			  100% {
				transform: rotate(0deg);
			  }
			}
			@keyframes clockwise {
			  0% {
				transform: rotate(0deg);
			  }
			  100% {
				transform: rotate(-180deg);
			  }
			}
			@keyframes rotating {
			  0% {
				transform: rotate(0deg);
			  }
			  100% {
				transform: rotate(1turn);
			  }
			}
		}
	}
</style>