<template>
	<view class="p-row-32 white">
		<movable-area :style="{ height: `${areaHeight}px`}">
			<block v-for="(item, index) in list" :key="index">
				<movable-view :key="item.sign" @change="e => change(e, index)" @touchend="touchend"
					@touchstart="touchstart($event);touchStart(index)" class="drag_item"
					:y="item.y" direction="vertical" :disabled='disabled' :style="{zIndex:`${current==index?2:1}`}">
					<u-swipe-action :disabled="isSlide" :show="item.show" :index="index" :key="item.sign" @click="click"
						@open="open" :options="options" :style="{zIndex:list.length-index}">
						<view class="touch_view"
							:style="{minHeight: item.itemHeight?item.itemHeight+'px':itemHeight+'px',borderBottom: (index+1)!=list.length?'1px solid #E8E9EB':'1px solid #fff',paddingTop: ifCustomHeight?'48rpx':'32rpx'}"
							@click="$emit('click',item)">
							<view class="left">
								<text>{{ item[name]}}</text>
							</view>
							<view class="right">
								<u-icon size="40" color="#B7B7BA" name="list"></u-icon>
							</view>
						</view>
					</u-swipe-action>
				</movable-view>
			</block>
		</movable-area>
	</view>
</template>

<script>
	export default {
		props: {
			ifCustomHeight: {
				type: Boolean,
				default: false
			},
			propList: {
				type: Array,
				default: () => []
			},
			isSlide: {
				type: Boolean,
				default: false
			},
			height: {
				type: Number,
				default: 104
			},
			name: {
				type: String,
				default: 'name'
			},
		},
		data() {
			return {
				longpress: false,
				oldIndex: -1, //记录移动前的位置，为了和移动后进行比较是否发生了位移
				newIndex: -1, //当前移动到的位置
				direction: '',
				current: -1,
				itemHeight: uni.upx2px(this.height),
				difference: 0, //记录移动前的位置
				disabled: true, //是否可以拖动
				list: [], //渲染的list
				options: [{
					text: '删除',
					style: {
						backgroundColor: '#dd524d'
					}
				}],
				timer: null,
				startX: 0, //touchStart开始坐标
				startY: 0,
			};
		},
		created() {
			this.ifCustomHeight && this.getElRect()
		},
		computed: {
			areaHeight() {
				let height = this.list.reduce((to, item) => {
					to += (item.itemHeight || this.itemHeight)
					return to
				}, 0)
				return height
			},
		},
		watch: {
			propList: {
				handler(val) {
					this.list = this.updateList(val);
					this.cloneList = JSON.parse(JSON.stringify(this.list));
				},
				immediate: true,
				deep: true
			}
		},
		methods: {
			// 计算滑动角度
			touchstart(e) {
				this.startX = e.changedTouches[0].clientX,
					this.startY = e.changedTouches[0].clientY
			},
			//计算滑动角度 start 起点坐标 end 终点坐标
			angle(start, end) {
				var _X = end.X - start.X,
					_Y = end.Y - start.Y;
				//返回角度 Math.atan()返回数字的反正切值
				return 360 * Math.atan(_Y / _X) / (2 * Math.PI);
			},
			getDirection(e) {
				let {
					startX,
					startY
				} = this;
				let slidingRange = 45;
				let touchMoveX = e.changedTouches[0].clientX;
				let touchMoveY = e.changedTouches[0].clientY;
				let angle = this.angle({
					X: startX,
					Y: startY
				}, {
					X: touchMoveX,
					Y: touchMoveY
				});
				//为了方便计算取绝对值判断
				if (Math.abs(angle) > slidingRange && touchMoveY < startY) {
					// 向上滑动
					this.direction = 'up'
				};
				if (Math.abs(angle) > slidingRange && touchMoveY > startY) {
					// 向下滑动
					this.direction = 'down'
				}
			},
			// 获取一个目标元素的高度
			getElRect() {
				let query = uni.createSelectorQuery().in(this);
				query.selectAll('.drag_item').boundingClientRect(res => {
					// 如果节点尚未生成，res值为null，循环调用执行
					if (res.length == 0) {
						setTimeout(() => {
							this.getElRect();
						}, 10);
						return;
					}
					for (let i = 0; i < res.length; i++) {
						this.$set(this.list[i], 'itemHeight', res[i].height < this.itemHeight ? this.itemHeight :
							res[i].height)
						this.$set(this.list[i], 'y', this.getTop(this.list, i))
					}
					this.updateList(this.list)
					this.cloneList = JSON.parse(JSON.stringify(this.list));
				}).exec();
			},
			getTop(list = [], end = 0) {
				let itemHeight = 0
				for (let i = 0; i < list.length; i++) {
					if (end == i) {
						break
					}
					itemHeight += list[i]['itemHeight']
				}
				return itemHeight
			},
			// 添加或更新数组y值
			updateList(list = []) {
				return list.map((item, index) => {
					let obj = {
						...item,
						show: false,
						sign: Math.random() + index //防止不更新的情况和标识位
					}
					if (this.ifCustomHeight) {
						return obj;
					} else {
						return {
							...obj,
							y: index * this.itemHeight
						};
					}
				});
			},
			touchStart(index) {
				this.disabled = false
				this.current = index;
				this.oldIndex = index;
			},
			change(e, index) {
				// 不是当前元素位移直接不处理
				if (index != this.current) return;
				this.longpress = true
				if (this.ifCustomHeight) {
					this.difference = e.detail.y;
				} else {
					//位移的距离px
					let difference = e.detail.y - this.current * this.itemHeight;
					//计算位移几个位置
					let tempIndex = difference > 0 ? parseInt((difference + (this.itemHeight / 2)) / this.itemHeight) :
						parseInt((difference - (this.itemHeight / 2)) / this.itemHeight);
					//当前拖到的位置
					this.newIndex = Math.abs(this.current + tempIndex);
					if (this.newIndex > -1 && this.oldIndex > -1 && this.newIndex !== this.oldIndex) {
						this.changeList();
					}
				}
			},
			changeList() {
				// 没想到怎么改变原数组, 直接拷贝一份数组出来,不考虑情况 一把梭 直接遍历拷贝的原数组.
				//直接把改变位置赋值回去不行，不知道为什么，只能改变每一项的y值
				let arr = JSON.parse(JSON.stringify(this.cloneList));
				arr.splice(this.newIndex, 0, ...arr.splice(this.current, 1));
				this.list.forEach((item, index) => {
					if (index !== this.current) {
						item.y = arr.findIndex(citem => citem.sign == item.sign) * this.itemHeight;
					}
				});
				this.oldIndex = this.newIndex;
			},
			touchend(e) {
				if (!this.longpress) {
					return
				}
				if (this.ifCustomHeight) {
					if (!this.list[this.current] || this.current < 0) {
						return
					}
					this.getDirection(e)
					let itemHeight = this.list[this.current]['itemHeight'];
					console.log(this.difference);
					let difference = this.difference;
					let arr = JSON.parse(JSON.stringify(this.cloneList));
					let index = this.current;
					for (var i = 0; i < arr.length; i++) {
						let item = arr[i]['y'] + arr[i]['itemHeight'] / 2
						if (this.direction == 'down' && difference + itemHeight >= item) {
							index = i
						} else if (this.direction == 'up' && item >= difference) {
							index = i
							break
						}
					}
					index >= 0 && arr.splice(index, 0, ...arr.splice(this.current, 1));
					for (var i = 0; i < arr.length; i++) {
						arr[i]['y'] = this.getTop(arr, i)
					}
					this.list = this.updateList(arr);
				} else {
					if (this.newIndex > -1 && this.current > -1 && this.newIndex !== this.current) {
						this.cloneList.splice(this.newIndex, 0, ...this.cloneList.splice(this.current, 1));
						this.list = this.updateList(this.cloneList);
					}
				}
				this.cloneList = JSON.parse(JSON.stringify(this.list));
				this.emitChang(this.list)
				this.current = -1;
				this.oldIndex = -1;
				this.newIndex = -1;
				this.disabled = true
				this.difference=0
				this.longpress = false
			},
			click(index, index1) {
				if (index1 == 0) {
					this.$emit('del', index)
				}
			},
			// 如果打开一个的时候，不需要关闭其他，则无需实现本方法
			open(index) {
				// 先将正在被操作的swipeAction标记为打开状态，否则由于props的特性限制，
				// 原本为'false'，再次设置为'false'会无效
				this.list[index].show = true;
				this.list.map((val, idx) => {
					if (index != idx) this.list[idx].show = false;
				});
			},
			emitChang(arr) {
				let tempArr = JSON.parse(JSON.stringify(arr))
				tempArr.forEach(item => {
					delete item.y
					delete item.show
					delete item.sign
				})
				this.$emit('change', tempArr)
			}
		}
	};
</script>

<style lang="scss">
	.drag_item {
		width: 686rpx;
		background-color: #fff;
		height: max-content;
	}

	movable-area {
		width: 686rpx;
		background-color: #fff;
	}

	.touch_view {
		width: 686rpx;
		display: flex;
		justify-content: space-between;
		align-items: flex-start;

		.left {
			display: flex;
			align-items: center;
			padding-bottom: 16rpx;
			padding-right: 16rpx;

			text {
				font-size: 28rpx;
				color: #31353D;
			}
		}

		.right {
			width: 40rpx;
			height: 40rpx;
			background: #FFFFFF;
			box-shadow: 0px 0px 8rpx 0px rgba(0, 0, 0, 0.08);
			border-radius: 4rpx;
		}
	}
</style>
