<template>
	<div class="demo">
		<div
			class="control"
			:class="{ active: item.token === activeToken }"
			v-for="(item, index) in list"
			:key="item.token"
			@click="onSelect(item.token)"
		>
			<div>
				<b>{{ item.name }}</b>
				<button
					v-if="index !== 0"
					@click="onMove(item.token, list[index - 1].token)"
				>
					←
				</button>
				<button
					v-if="index !== list.length - 1"
					@click="onMove(item.token, list[index + 1].token)"
				>
					→
				</button>
				<button @click.stop="onDelete(item.token)">删除</button>
			</div>
			<div>
				<span>偏移X</span>
				<input type="number" v-model="item.location[0]" />
			</div>
			<div>
				<span>偏移Y</span>
				<input type="number" v-model="item.location[1]" />
			</div>
			<div>
				<span>角度</span>
				<input type="number" v-model="item.angle" />
			</div>
			<div>
				<span>缩放</span>
				<input type="number" v-model="item.scale[0]" />
			</div>
			<div>
				<span>水平间距</span>
				<input type="number" v-model="item.object.gapX" />
			</div>
			<div>
				<span>垂直间距</span>
				<input type="number" v-model="item.object.gapY" />
			</div>
			<hr />
			<hr />
			<div>
				<span>缩放X</span>
				<input type="number" v-model="item.object.scaleX" step="0.1" />
			</div>
			<div>
				<span>缩放Y</span>
				<input type="number" v-model="item.object.scaleY" step="0.1" />
			</div>
			<div>
				<span>X</span>
				<input type="number" v-model="item.object.left" />
			</div>
			<div>
				<span>Y</span>
				<input type="number" v-model="item.object.top" />
			</div>
			<div>
				<span>角度</span>
				<input type="number" v-model="item.object.angle" />
			</div>

			<div>
				<span>透明度</span>
				<input
					type="range"
					v-model="item.object.opacity"
					step="0.1"
					min="0"
					max="1"
				/>
			</div>
		</div>
		<button @click="onAdd">添加</button>
		<div class="box">
			<pingpu
				:list="list"
				ref="pingpuRef"
				@change-canvas="updateCanvas"
			/>
		</div>
	</div>
</template>

<script lang="ts" setup>
	import { ref, onMounted, watch } from "vue";
	import pingpu from "./index.vue";
	const ACTIONS = {
		ADD: "add",
		UPDATE: "update",
		DELETE: "delete",
		SELECT: "select",
		SORT: "sort",
	};

	const convertDotNotationToBracket = (str) =>
		str.replace(/(?:^|\.)(\d+)(?=\.|$)/g, "[#$1]").replace(/\[#/g, "[");
	const activeToken = ref("1");
	const list = ref([
		{
			token: "1",
			ifSingle: false,
			level2Type: "Pattern",
			designType: "Library",
			path: "/src/assets/images/canvas/yinhua1.jpg",
			location: [0, 0],
			scale: [1, 1],
			angle: 0,
			name: "Print1",
			priority: 1,
			object: {
				top: 0,
				left: 0,
				scaleX: 1,
				scaleY: 1,
				opacity: 1,
				angle: 0,
				flipX: false,
				flipY: false,
				blendMode: "multiply",
				gapX: 10,
				gapY: 20,
			},
		},
		{
			token: "2",
			ifSingle: false,
			level2Type: "Pattern",
			designType: "Library",
			path: "/src/assets/images/canvas/yinhua1.jpg",
			location: [0, 0],
			scale: [2, 2],
			angle: -45,
			name: "Print2",
			priority: 1,
			object: {
				top: 150,
				left: 250,
				scaleX: 0.5,
				scaleY: 0.5,
				opacity: 1,
				angle: 45,
				flipX: false,
				flipY: false,
				blendMode: "multiply",
				gapX: 0,
				gapY: 0,
			},
		},
	]);
	// 深拷贝
	const deepCopy = (obj) => JSON.parse(JSON.stringify(obj));
	const oldList = ref(deepCopy(list.value));
	const pingpuRef = ref(null);
	const updateCanvas = (arr) => {
		console.log(arr);
		oldList.value = deepCopy(list.value);
		arr.forEach((item) => {
			const obj = list.value.find((v) => v.token === item.token);
			if (item.action === ACTIONS.UPDATE) {
				if (item.action === ACTIONS.UPDATE) {
					try {
						const key = item.key;
						const str = /^\[/.test(item.key)
							? "obj" + key
							: "obj." + key;
						eval(`${str} = item.value`);
					} catch (error) {
						console.error(error);
					}
				}
			} else if (item.action === ACTIONS.SELECT) {
				activeToken.value = item.token;
			}
		});
	};

	const onSelect = (token) => {
		activeToken.value = token;
		pingpuRef.value.updataList([{ token, action: ACTIONS.SELECT }]);
	};
	const onMove = (token1, token2) => {
		const obj1 = list.value.find((v) => v.token === token1);
		const obj2 = list.value.find((v) => v.token === token2);
		const index1 = list.value.indexOf(obj1);
		const index2 = list.value.indexOf(obj2);
		if (index1 < index2) {
			list.value.splice(index2, 0, list.value.splice(index1, 1)[0]);
		} else {
			list.value.splice(index1, 0, list.value.splice(index2, 1)[0]);
		}
		const tokens = list.value.map((v) => v.token);
		pingpuRef.value.updataList([{ action: ACTIONS.SORT, tokens }]);
	};
	const onDelete = (token) => {
		list.value = list.value.filter((v) => v.token !== token);
		pingpuRef.value.updataList([{ token, action: ACTIONS.DELETE }]);
	};
	const onAdd = () => {
		const obj = {
			token: Date.now().toString(),
			ifSingle: false,
			level2Type: "Pattern",
			designType: "Library",
			path: "/src/assets/images/canvas/yinhua1.jpg",
			location: [0, 0],
			scale: [1, 1],
			angle: 0,
			name: "Print" + (list.value.length + 1),
			priority: 1,
			object: {
				top: 0,
				left: 0,
				scaleX: 1,
				scaleY: 1,
				opacity: 1,
				angle: 0,
				flipX: false,
				flipY: false,
				blendMode: "multiply",
				gapX: 10,
				gapY: 20,
			},
		};
		list.value.push(obj);
		pingpuRef.value.updataList([{ action: ACTIONS.ADD, data: obj }]);
	};
	watch(
		() => list.value,
		() => updateList(),
		{ deep: true }
	);
	// 监听列表变化属性变更
	const updateList = () => {
		const changeList = [];
		oldList.value.forEach((oldItem) => {
			const newItem = list.value.find((v) => v.token === oldItem.token);
			if (newItem) {
				const arr = findDiffProps(oldItem, newItem);
				arr.forEach((item) => {
					changeList.push({
						...item,
						token: oldItem.token,
						action: ACTIONS.UPDATE,
						key: convertDotNotationToBracket(item.key),
					});
				});
			} else {
				changeList.push({
					token: oldItem.token,
					action: ACTIONS.DELETE,
				});
			}
		});
		oldList.value = deepCopy(list.value);
		if (changeList.length) {
			pingpuRef.value.updataList(changeList);
		}
	};
	// 递归查找不同的属性
	const findDiffProps = (obj1, obj2, diffProps = [], path = "") => {
		for (const key in obj1) {
			if (typeof obj1[key] === "object") {
				findDiffProps(obj1[key], obj2[key], diffProps, `${path}${key}.`);
			} else if (obj1[key] !== obj2[key]) {
				diffProps.push({
					key: `${path}${key}`,
					value: obj2[key],
				});
			}
		}
		return diffProps;
	};
</script>

<style lang='less' scoped>
	.demo {
		> .control {
			display: inline-block;
			border: 1px solid #000;
			padding: 10px;
			margin: 10px;
			border-radius: 10px;
			&.active {
				border-color: rgb(17, 68, 223);
				box-shadow: 0 0 5px rgb(17, 68, 223);
			}
			> div {
				display: flex;
				align-items: center;
				margin-bottom: 5px;
				> * {
					margin-right: 10px;
					&:last-child {
						margin-right: 0;
					}
				}
				> span {
					width: 80px;
				}
				> input:not([type="range"]) {
					padding-left: 10px;
					border-radius: 5px;
				}
			}
		}
		> .box {
			width: 400px;
			height: 500px;
			overflow: hidden;
			border: 1px solid #000;
		}
	}
</style>