Quellcode durchsuchen

增加管乐迷移动模块

liushengqiang vor 2 Jahren
Ursprung
Commit
1dce3288b2

+ 434 - 0
src/page-gym/custom-plugins/move-music-score/index.tsx

@@ -0,0 +1,434 @@
+import { showToast } from "vant";
+import { defineComponent, onMounted, reactive } from "vue";
+import { useRoute } from "vue-router";
+import state from "/src/state";
+import { detailData_gym } from "../../detail";
+import request from "/src/utils/request";
+import { getQuery } from "/src/utils/queryString";
+
+let extStyleConfigJson: any = {};
+export const moveData = reactive({
+	partIndex: "0",
+	hasExtJson: false,
+	isWeb: false,
+	modelList: [] as any[],
+	activeIndex: -1,
+	sw: 0,
+	tool: {
+		isAddAndSub: false,
+	},
+});
+
+function initSvgId() {
+	const svg = document.querySelector("#osmdSvgPage1");
+	if (!svg) return;
+	const vfstavetempo: HTMLElement[] = Array.from(svg.querySelectorAll(".vf-stavetempo"));
+	const vftext: HTMLElement[] = Array.from(svg.querySelectorAll(".vf-text"));
+	const vfstaveSection: HTMLElement[] = Array.from(svg.querySelectorAll(".vf-StaveSection"));
+	const vfRepetition: HTMLElement[] = Array.from(svg.querySelectorAll(".vf-Repetition"));
+	const vflineGroup: HTMLElement[] = Array.from(svg.querySelectorAll(".vf-lineGroup"));
+	let tempIndex = 1;
+	[...vfstavetempo].forEach((ele) => {
+		setEleId(ele, "temp" + tempIndex);
+		tempIndex++;
+	});
+	let textIndex = 1;
+	[...vftext].forEach((ele) => {
+		setEleId(ele, "text" + textIndex);
+		textIndex++;
+	});
+	let sectionIndex = 1;
+	[...vfstaveSection].forEach((ele) => {
+		setEleId(ele, "section" + sectionIndex);
+		sectionIndex++;
+	});
+	let repIndex = 1;
+	[...vfRepetition].forEach((ele) => {
+		setEleId(ele, "repet" + repIndex);
+		repIndex++;
+	});
+	let lineIndex = 1;
+	[...vflineGroup].forEach((ele) => {
+		setEleId(ele, "line" + lineIndex);
+		lineIndex++;
+	});
+	readerModelBox();
+	// if (moveData.isWeb) {
+	// 	readerModelBox();
+	// }
+	// if (moveData.hasExtJson) {
+	// 	setTimeout(reloadReader, 2);
+	// }
+}
+/**赋值id */
+function setEleId(ele: HTMLElement, eleId: string) {
+	if (!ele || !eleId) return;
+	const id = ele.getAttribute("id");
+	if (!id) {
+		ele.setAttribute("id", eleId);
+	}
+	createModelBox(ele as any);
+}
+
+const reloadReader = () => {
+	const detail = detailData_gym;
+	if (detail.extStyleConfigJson) {
+		try {
+			extStyleConfigJson = JSON.parse(detail.extStyleConfigJson);
+		} catch (error) {
+			extStyleConfigJson = {};
+		}
+	}
+
+	if (!extStyleConfigJson || !extStyleConfigJson?.[moveData.partIndex]) return;
+	const list = extStyleConfigJson?.[moveData.partIndex];
+	if (list && Array.isArray(list)) {
+		console.log("🚀 ~ list", list);
+		list.forEach((item: any) => {
+			const index = moveData.modelList.findIndex((n: any) => n.id === item.id);
+			if (index > -1) {
+				item.x = moveData.sw && item.w ? item.x * (moveData.sw / item.w) : item.x;
+				moveData.modelList[index] = {
+					...moveData.modelList[index],
+					...item,
+				};
+				setModelPostion(moveData.modelList[index]);
+				if (item.type === "vf-lineGroup") {
+					renderLineGroup(moveData.modelList[index]);
+				}
+			}
+		});
+	}
+};
+const zoom = 0.7;
+
+function formateZoom(n: number) {
+	return n * zoom;
+}
+
+function createModelBox(ele: SVGAElement) {
+	const { left, top, width, height } = getBox(ele);
+	const type = ele.getAttribute("class");
+	moveData.modelList.push({
+		id: ele.getAttribute("id"),
+		type,
+		isMove: false,
+		left,
+		top,
+		width,
+		height,
+		x: 0,
+		y: 0,
+		zoom,
+		isDelete: false,
+		d2: getLineGroupPathDx(ele as any),
+		dx: 0,
+	});
+}
+
+function readerModelBox() {
+	const container = document.querySelector(".moveModelWrap");
+	if (!container) return;
+	// console.log("🚀 ~ moveData.modelList", moveData.modelList);
+	for (let i = 0; i < moveData.modelList.length; i++) {
+		const item = moveData.modelList[i];
+		const div = document.createElement("div");
+		div.classList.add("moveModel");
+		div.style.left = item.left + "px";
+		div.style.top = item.top + "px";
+		div.style.width = item.width + "px";
+		div.style.height = item.height + "px";
+		div.dataset.id = item.id;
+		dragmove(div);
+		container.appendChild(div);
+	}
+}
+
+function getBox(ele: SVGAElement) {
+	if (!ele) return {};
+	const box = ele.getBBox();
+	return {
+		left: formateZoom(box.x - 5),
+		top: formateZoom(box.y - 5),
+		width: formateZoom(box.width + 10),
+		height: formateZoom(box.height + 10),
+	};
+}
+
+// 过滤数据
+export const filterMoveData = async () => {
+	const examSongId = state.examSongId;
+	if (examSongId) {
+		const list = moveData.modelList
+			.filter((n) => n.isMove)
+			.map((n) => {
+				const item: any = {
+					id: n.id,
+					isMove: n.isMove,
+					isDelete: n.isDelete,
+					x: n.x,
+					y: n.y,
+					zoom: n.zoom,
+					w: moveData.sw,
+					type: n.type,
+				};
+				if (n.type === "vf-lineGroup") {
+					item.dx = n.dx;
+				}
+				return item;
+			});
+		extStyleConfigJson[moveData.partIndex] = list;
+		// console.log("🚀 ~ extStyleConfigJson", extStyleConfigJson)
+		const res = await request.post("/sysMusicScore/updateExtStyleConfigJson", {
+			data: {
+				sysMusicScoreId: examSongId,
+				extStyleConfigJson: JSON.stringify(extStyleConfigJson),
+			},
+		});
+		// console.log(res)
+		if (res && res.code == 200) {
+			showToast("保存成功");
+		}
+		clearActiveModel();
+	}
+};
+
+// 移动
+const dragData = {
+	moving: false,
+	startX: 0,
+	startY: 0,
+};
+
+// 记录
+export const undoData = reactive({
+	undoList: [] as Array<any>, // 撤销列表
+	redoList: [] as Array<any>, // 回退列表
+	activeItem: null,
+});
+
+function dragmove(div: HTMLElement) {
+	div.addEventListener("mousedown", onDown);
+}
+
+function onDown(e: MouseEvent) {
+	if (dragData.moving) return;
+	const el: any = e.target;
+	const index = moveData.modelList.findIndex((n) => n.id === el.dataset.id);
+	if (index > -1) {
+		// console.log("🚀 ~ 按下", index, el);
+		const item = moveData.modelList[index];
+		moveData.activeIndex = index;
+		e.stopPropagation();
+		e.preventDefault();
+		dragData.startX = e.clientX - item.x;
+		dragData.startY = e.clientY - item.y;
+		document.addEventListener("mousemove", onMove);
+		document.addEventListener("mouseup", onUp);
+		dragData.moving = true;
+		if (item.type === "vf-lineGroup") {
+			moveData.tool.isAddAndSub = true;
+		} else {
+			moveData.tool.isAddAndSub = false;
+		}
+		undoData.activeItem = { ...item };
+	}
+	setActiveModel(el);
+}
+function onMove(e: MouseEvent) {
+	if (dragData.moving) {
+		const _x = e.clientX - dragData.startX;
+		const _y = e.clientY - dragData.startY;
+		moveData.modelList[moveData.activeIndex].isMove = true;
+		moveData.modelList[moveData.activeIndex].x = _x;
+		moveData.modelList[moveData.activeIndex].y = _y;
+		const item = moveData.modelList[moveData.activeIndex];
+		setModelPostion(item);
+	}
+}
+function onUp() {
+	// console.log("🚀 ~ 抬起");
+	document.removeEventListener("mousemove", onMove);
+	document.removeEventListener("mouseup", onUp);
+	dragData.moving = false;
+	if (undoData.activeItem) {
+		undoData.undoList.push({ ...(undoData.activeItem as any) });
+	}
+	undoData.activeItem = null;
+}
+
+function setModelPostion(item: any) {
+	if (item) {
+		const g = document.querySelector("#" + item.id)!;
+		g && g.setAttribute("transform", `translate(${item.x / zoom}, ${item.y / zoom})`);
+		const el: HTMLElement = document.querySelector(`[data-id=${item.id}]`)!;
+		if (el) {
+			el.style.left = item.left + item.x + "px";
+			el.style.top = item.top + item.y + "px";
+			el.style.width = item.width + "px";
+			el.style.height = item.height + "px";
+		}
+		if (item.isDelete) {
+			g && ((g as any).style.display = "none");
+			el && ((el as any).style.display = "none");
+		} else {
+			g && ((g as any).style.display = "");
+			el && ((el as any).style.display = "");
+		}
+	}
+}
+
+function setActiveModel(_div: HTMLElement) {
+	if (!_div) return;
+	moveData.modelList.forEach((n) => {
+		const el: HTMLElement = document.querySelector(`[data-id=${n.id}]`)!;
+		if (el) {
+			if (n.id == _div.dataset.id) {
+				_div.classList.add("activeModel");
+			} else {
+				el.classList.remove("activeModel");
+			}
+		}
+	});
+}
+
+//删除可移动元素
+export const deleteMoveNote = () => {
+	for (let i = 0; i < moveData.modelList.length; i++) {
+		const item: HTMLElement = document.querySelector(`[data-id=${moveData.modelList[i].id}]`)!;
+		if (item?.classList?.contains("activeModel")) {
+			moveData.modelList[i].isMove = true;
+			undoData.undoList.push({ ...moveData.modelList[i] });
+			moveData.modelList[i].isDelete = true;
+			setModelPostion(moveData.modelList[i]);
+			return;
+		}
+	}
+	showToast("选中需要删除的元素");
+};
+//重置数据
+export const resetMoveNote = () => {
+	for (let i = 0; i < moveData.modelList.length; i++) {
+		moveData.modelList[i].x = 0;
+		moveData.modelList[i].y = 0;
+		moveData.modelList[i].isMove = false;
+		moveData.modelList[i].isDelete = false;
+		moveData.modelList[i].dx = 0;
+		setModelPostion(moveData.modelList[i]);
+		if (moveData.modelList[i].type === "vf-lineGroup") {
+			renderLineGroup(moveData.modelList[i]);
+		}
+	}
+	clearActiveModel();
+};
+
+function clearActiveModel() {
+	for (let i = 0; i < moveData.modelList.length; i++) {
+		const item: HTMLElement = document.querySelector(`[data-id=${moveData.modelList[i].id}]`)!;
+		if (item?.classList?.contains("activeModel")) {
+			item.classList.remove("activeModel");
+		}
+	}
+	moveData.activeIndex = -1;
+	moveData.tool.isAddAndSub = false;
+}
+
+// 增加或减少, 渐强和渐弱的线长
+export const addAndSub = (type: string) => {
+	if (!["add", "sub"].includes(type)) return;
+	const lineGroup = moveData.modelList[moveData.activeIndex];
+	if (!lineGroup || lineGroup.type !== "vf-lineGroup") return;
+	lineGroup.isMove = true;
+	const step = type === "add" ? 10 : -10;
+	undoData.undoList.push({ ...moveData.modelList[moveData.activeIndex] });
+	moveData.modelList[moveData.activeIndex].dx = lineGroup.dx + step;
+	renderLineGroup(moveData.modelList[moveData.activeIndex]);
+};
+
+// 获取line的dx
+function getLineGroupPathDx(lineGroup: HTMLElement) {
+	if (!lineGroup) return 0;
+	const lines = lineGroup.querySelectorAll("path");
+	if (lines?.length) {
+		for (let i = 0; i < lines.length; i++) {
+			const path = lines[i];
+			let d = path.getAttribute("d");
+			if (d) {
+				let dx1: any = d.split("M")?.[1]?.split(" ") || [];
+				let dx2: any = d.split("L")?.[1]?.split(" ") || [];
+				dx1 = dx1[0] && !isNaN(Number(dx1[0])) ? Number(dx1[0]) : 0;
+				dx2 = dx2[0] && !isNaN(Number(dx2[0])) ? Number(dx2[0]) : 0;
+				if (dx1 && dx2) {
+					if (dx1 < dx2) {
+						return dx2;
+					} else {
+						return dx1;
+					}
+				}
+			}
+		}
+	}
+	return 0;
+}
+function renderLineGroup(lineGroup: any) {
+	const group = document.querySelector("#" + lineGroup.id);
+	if (!group) return;
+	const lines = group.querySelectorAll("path");
+	if (lines?.length) {
+		for (let i = 0; i < lines.length; i++) {
+			const path = lines[i];
+			let d = path.getAttribute("d");
+			if (d) {
+				let dx1: any = d.split("M")?.[1]?.split(" ") || [];
+				let dx2: any = d.split("L")?.[1]?.split(" ") || [];
+				dx1 = dx1[0] && !isNaN(Number(dx1[0])) ? Number(dx1[0]) : 0;
+				dx2 = dx2[0] && !isNaN(Number(dx2[0])) ? Number(dx2[0]) : 0;
+
+				if (dx1 && dx2) {
+					if (dx1 < dx2) {
+						d = d.replace(dx2, lineGroup.d2 + lineGroup.dx + "");
+					} else {
+						d = d.replace(dx1, lineGroup.d2 + lineGroup.dx + "");
+					}
+					path.setAttribute("d", d);
+				}
+			}
+		}
+		const { width } = getBox(group as any);
+		const div: HTMLElement = document.querySelector(`[data-id=${lineGroup.id}]`)!;
+		div && (div.style.width = width + "px");
+	}
+}
+
+// 撤销
+export const handleUndo = () => {
+	const preItem = undoData.undoList.pop();
+	// console.log("🚀 ~ preItem", preItem)
+	if (preItem) {
+		const itemIndex = moveData.modelList.findIndex((n: any) => n.id === preItem.id);
+		if (itemIndex > -1) {
+			moveData.modelList[itemIndex] = preItem;
+			setModelPostion(preItem);
+			if (preItem.type === "vf-lineGroup") {
+				renderLineGroup(preItem);
+			}
+		}
+	}
+	console.log(undoData.undoList);
+};
+
+export default defineComponent({
+	name: "move-music-score",
+	setup() {
+		const query = getQuery();
+		const isOpen = query.isMove === "1" ? true : false;
+		onMounted(() => {
+			if (isOpen) {
+				initSvgId();
+			}
+			if (detailData_gym.extStyleConfigJson) {
+			}
+		});
+		return () => <div style={{ display: "none" }}></div>;
+	},
+});

+ 7 - 0
src/page-gym/detail/index.tsx

@@ -28,7 +28,11 @@ import GuidePage from "../custom-plugins/guide-page";
 import { handleSetCustomRender, setCustomGradual, setCustomNoteRealValue } from "../custom-plugins/custom-gradual";
 import { getStorageSpeed, setGlobalData } from "/src/utils";
 import { getInstrumentsClassfiy } from "/src/constant/instrumentsClassfiy";
+import MoveMusicScore from "../custom-plugins/move-music-score";
 
+export const detailData_gym = reactive({
+	extStyleConfigJson: null as any
+})
 //特殊教材分类id
 const classIds = [1, 30, 97]; // [大雅金唐, 竖笛教程, 声部训练]
 const classKey = "sysMusicScoreCategoriesList";
@@ -291,6 +295,9 @@ export default defineComponent({
 							<Fingering />
 						</div>
 					)}
+
+					{/* 移动模块 */}
+					{/* {query.isMove == '1' && <MoveMusicScore />} */}
 				</div>
 
 				{/* 插件模块 */}