Explorar o código

完善移动模块

liushengqiang %!s(int64=2) %!d(string=hai) anos
pai
achega
5097db5d73

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

@@ -327,8 +327,6 @@ export default defineComponent({
 							{storeData.platformType === "STUDENT" && (query.workRecord || query.evaluatingRecord) && <VipModel />}
 							{/* 引导 */}
 							<GuidePage />
-							{/* 移动模块 */}
-							{/* {query.isMove == "1" && <MoveMusicScore />} */}
 						</>
 					)}
 				</div>

+ 2 - 0
src/state.ts

@@ -45,6 +45,8 @@ const state = reactive({
 	examSongName: "",
 	/** 扩展字段 */
 	extConfigJson: {} as any,
+	/** 扩展样式字段 */
+	extStyleConfigJson: {} as any,
 	/** 是否开启节拍器 */
 	isOpenMetronome: false,
 	/** 是否显示指法 */

+ 41 - 0
src/view/plugins/move-music-score/index.module.less

@@ -0,0 +1,41 @@
+
+.noteMove {
+    position: absolute;
+    &::before{
+        content: '';
+        position: absolute;
+        left: -4px;
+        right: -4px;
+        bottom: -4px;
+        top: -4px;
+        border-radius: 2px;
+        background-color: rgba(0, 0, 0, .3);
+    }
+}
+.activeModel{
+    &::before{
+        background-color: rgba(255,145,0,.3);
+    }
+}
+
+.toolBox {
+    position: fixed;
+    left: 0;
+    top: 30%;
+    padding: 8px;
+    background: rgba(0, 0, 0, .3);
+    border-radius: 4px;
+    display: flex;
+    flex-direction: column;
+    z-index: 10;
+    backdrop-filter: blur(10px);
+    &>div,
+    &>button {
+        margin: 4px 0;
+    }
+}
+.moveDisabled{
+    .noteMove{
+        display: none;
+    }
+}

+ 178 - 140
src/view/plugins/move-music-score/index.tsx

@@ -1,12 +1,19 @@
-import { showToast } from "vant";
+import { Row, showToast } from "vant";
 import { defineComponent, onMounted, reactive } from "vue";
 import state from "/src/state";
-import { detailData_gym } from "../../../page-gym/detail";
 import request from "/src/utils/request";
 import { getQuery } from "/src/utils/queryString";
+import styles from "./index.module.less";
+import { Button, ButtonGroup, Icon, Switch, Tooltip } from "@varlet/ui";
+import "@varlet/ui/es/tooltip/style";
+import "@varlet/ui/es/button-group/style";
+import "@varlet/ui/es/switch/style";
 
 let extStyleConfigJson: any = {};
 export const moveData = reactive({
+	/** 开启移动 */
+	open: false,
+	zoom: state.zoom,
 	partIndex: "0",
 	hasExtJson: false,
 	isWeb: false,
@@ -20,12 +27,10 @@ export const moveData = reactive({
 
 function initSvgId() {
 	const svg = document.querySelector("#osmdSvgPage1");
-	console.log("🚀 ~ svg:", svg);
 	if (!svg) return;
 	const vfstavetempo: HTMLElement[] = Array.from(svg.querySelectorAll(".vf-stavetempo"));
 	const vftext: HTMLElement[] = Array.from(svg.querySelectorAll(".vf-text"));
-	console.log("🚀 ~ vftext:", vftext);
-	const vfstaveSection: HTMLElement[] = []//Array.from(svg.querySelectorAll(".vf-StaveSection"));
+	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;
@@ -70,51 +75,15 @@ function setEleId(ele: HTMLElement, eleId: string) {
 	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 musicContainer = document.getElementById("musicAndSelection")?.getBoundingClientRect() || { x: 0, y: 0 };
 	const parentLeft = musicContainer.x || 0;
 	const parentTop = musicContainer.y || 0;
 	const noteBbox = ele.getBoundingClientRect();
 	const bbox = {
-		left: noteBbox.x - parentLeft - noteBbox.width / 4 + "px",
+		left: noteBbox.x - parentLeft + "px",
 		top: noteBbox.y - parentTop + "px",
-		width: noteBbox.width * 1.5 + "px",
+		width: noteBbox.width + "px",
 		height: noteBbox.height + "px",
 	};
 	const type = ele.getAttribute("class");
@@ -129,7 +98,7 @@ function createModelBox(ele: SVGAElement) {
 		height: noteBbox.height,
 		x: 0,
 		y: 0,
-		zoom,
+		zoom: state.zoom,
 		isDelete: false,
 		d2: getLineGroupPathDx(ele as any),
 		dx: 0,
@@ -138,12 +107,15 @@ function createModelBox(ele: SVGAElement) {
 
 function getBox(ele: SVGAElement) {
 	if (!ele) return {};
-	const box = ele.getBBox();
+	const musicContainer = document.getElementById("musicAndSelection")?.getBoundingClientRect() || { x: 0, y: 0 };
+	const parentLeft = musicContainer.x || 0;
+	const parentTop = musicContainer.y || 0;
+	const box = ele.getBoundingClientRect();
 	return {
-		left: formateZoom(box.x - 5),
-		top: formateZoom(box.y - 5),
-		width: formateZoom(box.width + 10),
-		height: formateZoom(box.height + 10),
+		left: box.x - parentLeft,
+		top: box.y - parentTop,
+		width: box.width,
+		height: box.height,
 	};
 }
 
@@ -169,27 +141,32 @@ export const filterMoveData = async () => {
 				}
 				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("保存成功");
+		if (!list.length) {
+			showToast("请移动元素后再保存");
+			return
 		}
-		clearActiveModel();
+		extStyleConfigJson[moveData.partIndex] = list;
+		console.log("🚀 ~ extStyleConfigJson", extStyleConfigJson)
+		// const res = await request.post("/sysMusicScore/updateExtStyleConfigJson", {
+		// 	data: {
+		// 		sysMusicScoreId: examSongId,
+		// 		extStyleConfigJson: JSON.stringify(extStyleConfigJson),
+		// 	},
+		// });
+		// if (res && res.code == 200) {
+		// 	showToast("保存成功");
+		// }
+		// clearActiveModel();
 	}
 };
 
 // 移动
 const dragData = {
-	moving: false,
+	open: false,
 	startX: 0,
 	startY: 0,
+	x: 0,
+	y: 0,
 };
 
 // 记录
@@ -199,114 +176,105 @@ export const undoData = reactive({
 	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;
+		dragData.startX = e.clientX;
+		dragData.startY = e.clientY;
+		dragData.x = item.x;
+		dragData.y = item.y;
+		// console.log("🚀 ~ 按下", index, el, item.x, item.y);
+		document.onmousemove = onMove;
+		document.onmouseup = onUp;
+		dragData.open = true;
 		if (item.type === "vf-lineGroup") {
 			moveData.tool.isAddAndSub = true;
 		} else {
 			moveData.tool.isAddAndSub = false;
 		}
 		undoData.activeItem = { ...item };
+		return;
 	}
-	setActiveModel(el);
+	moveData.activeIndex = -1;
 }
 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);
+	if (dragData.open) {
+		const _x = e.clientX - dragData.startX + dragData.x;
+		const _y = e.clientY - dragData.startY + dragData.y;
+		setModelPostion(moveData.modelList[moveData.activeIndex], _x, _y);
 	}
 }
-function onUp() {
+function onUp(e: MouseEvent) {
 	// console.log("🚀 ~ 抬起");
-	document.removeEventListener("mousemove", onMove);
-	document.removeEventListener("mouseup", onUp);
-	dragData.moving = false;
-	if (undoData.activeItem) {
-		undoData.undoList.push({ ...(undoData.activeItem as any) });
+	document.onmousemove = null;
+	document.onmouseup = null;
+	dragData.open = false;
+	const _x = e.clientX - dragData.startX + dragData.x;
+	const _y = e.clientY - dragData.startY + dragData.y;
+	if (_x || _y) {
+		moveData.modelList[moveData.activeIndex].isMove = true;
+		moveData.modelList[moveData.activeIndex].x = _x;
+		moveData.modelList[moveData.activeIndex].y = _y;
+		if (undoData.activeItem) {
+			undoData.undoList.push({ ...(undoData.activeItem as any) });
+		}
 	}
 	undoData.activeItem = null;
 }
 
-function setModelPostion(item: any) {
+/** 渲染svg元素的属性 */
+const renderSvgItem = (item: any) => {
+	setModelPostion(item, item.x, item.y);
+	if (item.isDelete) {
+		const g = document.querySelector("#" + item.id)!;
+		g && ((g as any).style.display = "none");
+	} else {
+		const g = document.querySelector("#" + item.id)!;
+		g && ((g as any).style.display = "");
+	}
+};
+
+/** 设置元素位置 */
+function setModelPostion(item: any, x: number, y: number) {
 	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");
+		if (x === 0 && y === 0) {
+			g && g.removeAttribute("transform");
+			el && (el.style.transform = "");
 		} else {
-			g && ((g as any).style.display = "");
-			el && ((el as any).style.display = "");
+			g && g.setAttribute("transform", `translate(${x / moveData.zoom}, ${y / moveData.zoom})`);
+			el && (el.style.transform = `translate(${x}px, ${y}px)`);
 		}
 	}
 }
 
-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;
-		}
+/** 删除元素 */
+const handleDeleteMoveNote = () => {
+	const item = moveData.modelList[moveData.activeIndex];
+	if (item) {
+		moveData.modelList[moveData.activeIndex].isMove = true;
+		undoData.undoList.push({ ...moveData.modelList[moveData.activeIndex] });
+		moveData.modelList[moveData.activeIndex].isDelete = !item.isDelete;
+		const g = document.querySelector("#" + item.id)!;
+		g && ((g as any).style.display = moveData.modelList[moveData.activeIndex].isDelete ? "none" : '');
+	} else {
+		showToast("选中需要删除的元素");
 	}
-	showToast("选中需要删除的元素");
 };
-//重置数据
-export const resetMoveNote = () => {
+
+/** 重置数据 */
+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]);
+		renderSvgItem(moveData.modelList[i]);
 		if (moveData.modelList[i].type === "vf-lineGroup") {
 			renderLineGroup(moveData.modelList[i]);
 		}
@@ -326,7 +294,7 @@ function clearActiveModel() {
 }
 
 // 增加或减少, 渐强和渐弱的线长
-export const addAndSub = (type: string) => {
+const handleAddAndSub = (type: 'add' | 'sub') => {
 	if (!["add", "sub"].includes(type)) return;
 	const lineGroup = moveData.modelList[moveData.activeIndex];
 	if (!lineGroup || lineGroup.type !== "vf-lineGroup") return;
@@ -392,21 +360,50 @@ function renderLineGroup(lineGroup: any) {
 	}
 }
 
-// 撤销
-export const handleUndo = () => {
+/** 撤销 */
+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);
+			renderSvgItem(moveData.modelList[itemIndex])
 			if (preItem.type === "vf-lineGroup") {
 				renderLineGroup(preItem);
 			}
 		}
 	}
-	console.log(undoData.undoList);
+};
+
+/** 根据移动数据渲染 */
+const renderForMoveData = () => {
+	if (state.extStyleConfigJson) {
+		try {
+			extStyleConfigJson = JSON.parse(state.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) {
+				moveData.modelList[index] = {
+					...moveData.modelList[index],
+					...item
+				};
+				renderSvgItem(moveData.modelList[index]);
+				if (item.type === "vf-lineGroup") {
+					renderLineGroup(moveData.modelList[index]);
+				}
+			}
+		});
+	}
 };
 
 export default defineComponent({
@@ -419,9 +416,50 @@ export default defineComponent({
 			if (isOpen) {
 				initSvgId();
 			}
-			if (detailData_gym.extStyleConfigJson) {
-			}
+			renderForMoveData();
+			const toolBox = document.getElementById("toolBox");
+			toolBox && document.body.appendChild(toolBox);
 		});
-		return () => <div></div>;
+		return () => (
+			<div class={[moveData.open ? "" : styles.moveDisabled]}>
+				<div class={styles.toolBox} id="toolBox">
+					<Switch v-model={moveData.open} />
+					{moveData.open && (
+						<>
+							{moveData.tool.isAddAndSub && (
+								<ButtonGroup size="small" elevation={false}>
+									<Button onClick={() => handleAddAndSub('add')}>加</Button>
+									<Button onClick={() => handleAddAndSub('sub')}>减</Button>
+								</ButtonGroup>
+							)}
+							{/* <ButtonGroup size="small">
+								
+								<Button>
+									<Icon name="arrow-down" style={{ transform: "rotate(-90deg)" }} />
+								</Button>
+							</ButtonGroup> */}
+							<Button size="small" onClick={handleUndo} disabled={undoData.undoList.length ? false : true}>
+								<Icon name="arrow-down" style={{ transform: "rotate(90deg)" }} />
+							</Button>
+
+							<Button size="small" onClick={handleDeleteMoveNote} disabled={moveData.activeIndex > -1 ? false : true}>
+								{moveData.modelList[moveData.activeIndex]?.isDelete ? '显示元素' : '删除元素'}
+							</Button>
+							<Button size="small" onClick={resetMoveNote}>
+								重置数据
+							</Button>
+							<Button size="small" type="primary" onClick={filterMoveData}>
+								保存数据
+							</Button>
+						</>
+					)}
+				</div>
+				{moveData.modelList.map((item: any, index: number) => {
+					return (
+						<div class={[styles.noteMove, moveData.activeIndex === index && styles.activeModel]} style={item.bbox} data-id={item.id} onMousedown={onDown}></div>
+					);
+				})}
+			</div>
+		);
 	},
 });

+ 1 - 3
src/view/selection/index.module.less

@@ -14,9 +14,7 @@
 .note {
     // background-color: rgba(0, 0, 0, .3);
 }
-.noteMove{
-    background-color: rgba(0, 0, 0, .3);
-}
+
 
 .staveBox {
     background-color: var(--active-stave-box) !important;

+ 10 - 4
src/view/selection/index.tsx

@@ -5,7 +5,9 @@ import { metronomeData } from "/src/helpers/metronome";
 import { evaluatingData } from "../evaluating";
 import { leveByScoreMeasureIcons } from "../evaluating/evaluatResult";
 import { Icon } from "vant";
-import { moveData } from "../plugins/move-music-score";
+import MoveMusicScore from "../plugins/move-music-score";
+import { useRoute } from "vue-router";
+import { getQuery } from "/src/utils/queryString";
 
 const selectData = reactive({
 	notes: [] as any[],
@@ -121,6 +123,11 @@ export const recalculateNoteData = () => {
 export default defineComponent({
 	name: "selection",
 	setup() {
+		const route = useRoute();
+		const query: any = {
+			...getQuery(),
+			...route.query,
+		};
 		/** 是否可以点击音符 */
 		const disableClickNote = computed(() => {
 			return state.sectionStatus || state.modeType !== "practise";
@@ -218,9 +225,8 @@ export default defineComponent({
 					);
 				})}
 
-				{moveData.modelList.map((item: any) => {
-					return <div class={[styles.position, styles.noteMove]} style={item.bbox}></div>;
-				})}
+				{/* 移动模块 */}
+				{/* {query.isMove == "1" && <MoveMusicScore />} */}
 			</div>
 		);
 	},