|
@@ -0,0 +1,1060 @@
|
|
|
+import { PropType, computed, defineComponent, nextTick, onBeforeMount, onMounted, onUnmounted, reactive, ref } from "vue";
|
|
|
+import styles from "./index.module.less";
|
|
|
+import icons from "./image/icons.json";
|
|
|
+import { FIGNER_INSTRUMENT_DATA, FIGNER_INSTRUMENT_REALKEY, IFIGNER_INSTRUMENT_Note } from "/src/view/figner-preview";
|
|
|
+import { ITypeFingering, IVocals, getFingeringConfig, mappingVoicePart, subjectFingering } from "/src/view/fingering/fingering-config";
|
|
|
+import { Howl } from "howler";
|
|
|
+import { storeData } from "/src/store";
|
|
|
+import { api_back, api_cloudLoading, api_setRequestedOrientation, api_setStatusBarVisibility, isSpecialShapedScreen } from "/src/helpers/communication";
|
|
|
+import Hammer from "hammerjs";
|
|
|
+import { Button, Icon, Loading, Popover, Popup, Progress, Space } from "vant";
|
|
|
+// import GuideIndex from "./guide/guide-index";
|
|
|
+import qs from "query-string";
|
|
|
+import { getQuery } from "/src/utils/queryString";
|
|
|
+import { browser } from "/src/utils";
|
|
|
+import { usePageVisibility } from "@vant/use";
|
|
|
+import { watch } from "vue";
|
|
|
+import icon_loading_img from "./image/icon_loading_img.png";
|
|
|
+import state, { IPlatform } from "/src/state";
|
|
|
+
|
|
|
+export default defineComponent({
|
|
|
+ name: "viewFigner",
|
|
|
+ emits: ["close"],
|
|
|
+ props: {
|
|
|
+ show: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true,
|
|
|
+ },
|
|
|
+ // isComponent: {
|
|
|
+ // type: Boolean,
|
|
|
+ // default: false,
|
|
|
+ // },
|
|
|
+ // subject: {
|
|
|
+ // type: String as PropType<IVocals>,
|
|
|
+ // default: "",
|
|
|
+ // },
|
|
|
+ },
|
|
|
+ setup(props, { emit }) {
|
|
|
+ const query = getQuery();
|
|
|
+ const browsInfo = browser();
|
|
|
+ const code = query.subjectCode || mappingVoicePart(storeData.user?.subjectId, "INSTRUMENT");
|
|
|
+ const subject = code || "pan-flute";
|
|
|
+
|
|
|
+ // 设置屏幕方向
|
|
|
+ api_setRequestedOrientation(["hulusi-flute", "piccolo"].includes(subject) ? 1 : 0);
|
|
|
+
|
|
|
+ const data = reactive({
|
|
|
+ loading: true,
|
|
|
+ subject: subject as any,
|
|
|
+ realKey: 0,
|
|
|
+ notes: [] as IFIGNER_INSTRUMENT_Note[],
|
|
|
+ tones: [] as IFIGNER_INSTRUMENT_Note[],
|
|
|
+ activeTone: {} as IFIGNER_INSTRUMENT_Note,
|
|
|
+ popupActiveTone: {} as IFIGNER_INSTRUMENT_Note,
|
|
|
+ activeToneName: "",
|
|
|
+ soundFonts: {} as any,
|
|
|
+ viewIndex: 0,
|
|
|
+ viewTotal: 1,
|
|
|
+ noteAudio: null as unknown as Howl,
|
|
|
+ transform: {
|
|
|
+ scale: 1,
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ startScale: 1,
|
|
|
+ startX: 0,
|
|
|
+ startY: 0,
|
|
|
+ transition: "",
|
|
|
+ },
|
|
|
+ tipShow: false,
|
|
|
+ tips: [] as IFIGNER_INSTRUMENT_Note[],
|
|
|
+ tnoteShow: false,
|
|
|
+ loadingSoundFonts: true,
|
|
|
+ loadingSoundProgress: 0,
|
|
|
+
|
|
|
+ huaweiPad: navigator?.userAgent?.includes("UAWEIVRD-W09") ? true : false,
|
|
|
+ paddingTop: "",
|
|
|
+ paddingLeft: "",
|
|
|
+
|
|
|
+ subjects: [
|
|
|
+ {
|
|
|
+ text: "排箫",
|
|
|
+ value: "pan-flute",
|
|
|
+ className: "",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: "陶笛",
|
|
|
+ value: "ocarina",
|
|
|
+ className: "",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: "葫芦丝",
|
|
|
+ value: "hulusi-flute",
|
|
|
+ className: "",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: "竖笛",
|
|
|
+ value: "piccolo",
|
|
|
+ className: "",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: "口风琴",
|
|
|
+ value: "melodica",
|
|
|
+ className: "",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ fingeringModeList: [
|
|
|
+ {
|
|
|
+ text: "指法模式",
|
|
|
+ value: "fingeringMode",
|
|
|
+ className: styles.selected,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: "听音模式",
|
|
|
+ value: "listenMode",
|
|
|
+ className: "",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ fingeringMode: "fingeringMode" as "fingeringMode" | "listenMode", // 模式
|
|
|
+ noteType: "all" as "#c" | "all", // 音调
|
|
|
+ });
|
|
|
+
|
|
|
+ const fingerData = reactive({
|
|
|
+ relationshipIndex: 0,
|
|
|
+ subject: null as unknown as ITypeFingering,
|
|
|
+ fingeringInfo: subjectFingering(data.subject),
|
|
|
+ });
|
|
|
+ // if (!props.isComponent) {
|
|
|
+ // state.fingeringInfo = fingerData.fingeringInfo;
|
|
|
+ // }
|
|
|
+
|
|
|
+ const getAPPData = async (type: "top" | "left") => {
|
|
|
+ const screenData = await isSpecialShapedScreen();
|
|
|
+ if (screenData?.content) {
|
|
|
+ // console.log("🚀 ~ screenData:", screenData.content);
|
|
|
+ const { isSpecialShapedScreen, notchHeight } = screenData.content;
|
|
|
+ if (isSpecialShapedScreen) {
|
|
|
+ if (type === "top") {
|
|
|
+ data.paddingTop = 25 + "px";
|
|
|
+ }
|
|
|
+ if (type === "left") {
|
|
|
+ data.paddingLeft = 25 + "px";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const getHeadTop = () => {
|
|
|
+ if (!browsInfo.ios && fingerData.fingeringInfo.orientation === 1) {
|
|
|
+ getAPPData("top");
|
|
|
+ }
|
|
|
+ if (!browsInfo.ios && fingerData.fingeringInfo.orientation === 0) {
|
|
|
+ getAPPData("left");
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const getNotes = () => {
|
|
|
+ const fignerData = FIGNER_INSTRUMENT_DATA[data.subject as keyof typeof FIGNER_INSTRUMENT_DATA];
|
|
|
+ if (fignerData) {
|
|
|
+ data.tones = fignerData.tones || [];
|
|
|
+ if (data.tones.length) {
|
|
|
+ data.activeTone = data.tones[0];
|
|
|
+ data.popupActiveTone = data.tones[0];
|
|
|
+ }
|
|
|
+ data.tips = fignerData.tips || [];
|
|
|
+ setNotes();
|
|
|
+ setTimeout(() => {
|
|
|
+ data.loading = false;
|
|
|
+ }, 600);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ const setNotes = () => {
|
|
|
+ const fignerData = FIGNER_INSTRUMENT_DATA[data.subject as keyof typeof FIGNER_INSTRUMENT_DATA];
|
|
|
+ if (fignerData) {
|
|
|
+ const tempNotes = fignerData[`list${data.activeTone.realName || ""}`];
|
|
|
+ const appendNote: any = [];
|
|
|
+ tempNotes.forEach((note: any) => {
|
|
|
+ note.steps = new Array(Math.abs(note.step)).fill(1);
|
|
|
+ if (FIGNER_INSTRUMENT_REALKEY.includes(note.realKey)) {
|
|
|
+ appendNote.push(note);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // 判断是音符状态
|
|
|
+ data.notes = data.noteType === "#c" ? appendNote : tempNotes;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ const getFingeringData = async () => {
|
|
|
+ const subject: any = data.subject + (data.viewIndex === 0 ? "" : data.viewIndex);
|
|
|
+ console.log("🚀 ~ subject:", subject);
|
|
|
+ fingerData.subject = await getFingeringConfig(subject);
|
|
|
+ };
|
|
|
+ const createAudio = (url: string) => {
|
|
|
+ return new Promise((resolve) => {
|
|
|
+ const noteAudio = new Howl({
|
|
|
+ src: url,
|
|
|
+ loop: true,
|
|
|
+ onload: () => {
|
|
|
+ resolve(noteAudio);
|
|
|
+ },
|
|
|
+ });
|
|
|
+ });
|
|
|
+ };
|
|
|
+ const getSounFonts = async () => {
|
|
|
+ const pathname = /(192|localhost)/.test(location.origin) ? "/" : location.pathname;
|
|
|
+ data.loadingSoundFonts = true;
|
|
|
+ data.loadingSoundProgress = 0;
|
|
|
+ for (let i = 0; i < data.notes.length; i++) {
|
|
|
+ const note = data.notes[i];
|
|
|
+ // console.log("🚀 ~ note:", i);
|
|
|
+ let url = `${pathname}soundfonts/${data.subject}/`;
|
|
|
+ url += note.realName;
|
|
|
+ url += ".mp3";
|
|
|
+ data.soundFonts[note.realKey] = await createAudio(url);
|
|
|
+ data.loadingSoundProgress = Math.floor(((i + 1) / data.notes.length) * 100);
|
|
|
+ }
|
|
|
+ data.loadingSoundProgress = 100;
|
|
|
+ api_cloudLoading();
|
|
|
+ data.loadingSoundFonts = false;
|
|
|
+ // console.log("🚀 ~ data.soundFonts:", data.soundFonts);
|
|
|
+ };
|
|
|
+
|
|
|
+ const selectSubjectType = (subject: string) => {
|
|
|
+ data.subjects.forEach((item: any) => {
|
|
|
+ if (item.value === subject) {
|
|
|
+ item.className = styles.selected;
|
|
|
+ } else {
|
|
|
+ item.className = "";
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ onBeforeMount(() => {
|
|
|
+ getNotes();
|
|
|
+
|
|
|
+ if (["pan-flute", "ocarina"].includes(data.subject)) {
|
|
|
+ data.viewIndex = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ selectSubjectType(data.subject);
|
|
|
+ // const o: any = {
|
|
|
+ // "pan-flute": 2,
|
|
|
+ // ocarina: 2,
|
|
|
+ // piccolo: 2,
|
|
|
+ // "hulusi-flute": 2,
|
|
|
+ // };
|
|
|
+ // data.viewTotal = o[data.subject] || 1;
|
|
|
+ getFingeringData();
|
|
|
+ getSounFonts();
|
|
|
+ getHeadTop();
|
|
|
+ });
|
|
|
+
|
|
|
+ const noteClick = (item: IFIGNER_INSTRUMENT_Note) => {
|
|
|
+ if (data.noteAudio) {
|
|
|
+ data.noteAudio.stop();
|
|
|
+ if (data.realKey === item.realKey) {
|
|
|
+ data.realKey = 0;
|
|
|
+ data.noteAudio = null as unknown as Howl;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ data.realKey = item.realKey;
|
|
|
+ data.noteAudio = data.soundFonts[item.realKey];
|
|
|
+ data.noteAudio.play();
|
|
|
+ };
|
|
|
+ const handleStop = () => {
|
|
|
+ if (data.noteAudio) {
|
|
|
+ data.noteAudio.stop();
|
|
|
+ data.realKey = 0;
|
|
|
+ data.noteAudio = null as unknown as Howl;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ /** 返回 */
|
|
|
+ const handleBack = () => {
|
|
|
+ handleStop();
|
|
|
+ // if (props.isComponent) {
|
|
|
+ // console.log("关闭");
|
|
|
+ // emit("close");
|
|
|
+ // return;
|
|
|
+ // } else {
|
|
|
+ // // if (fingerData.fingeringInfo.orientation === 0) {
|
|
|
+ // // api_setRequestedOrientation(1);
|
|
|
+ // // }
|
|
|
+ // }
|
|
|
+ // 不在APP中,
|
|
|
+ if (!storeData.isApp) {
|
|
|
+ window.close();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ api_back();
|
|
|
+ };
|
|
|
+
|
|
|
+ onMounted(() => {
|
|
|
+ loadElement();
|
|
|
+ api_setStatusBarVisibility();
|
|
|
+ });
|
|
|
+ const loadElement = () => {
|
|
|
+ const fingeringContainer = document.getElementById("fingeringContainer");
|
|
|
+ // console.log("🚀 ~ fingeringContainer:", fingeringContainer);
|
|
|
+ const mc = new Hammer.Manager(fingeringContainer as HTMLElement);
|
|
|
+ mc.add(new Hammer.Pan({ threshold: 0, pointers: 0 }));
|
|
|
+ mc.add(new Hammer.Pinch({ threshold: 0 })).recognizeWith([mc.get("pan")]);
|
|
|
+ // mc.get("pan").set({ direction: Hammer.DIRECTION_ALL });
|
|
|
+ // mc.get("pinch").set({ enable: true });
|
|
|
+ mc.on("panstart pinchstart", function (ev) {
|
|
|
+ data.transform.transition = "";
|
|
|
+ });
|
|
|
+ mc.on("panmove pinchmove", function (ev) {
|
|
|
+ if (ev.type === "pinchmove") {
|
|
|
+ // console.log("🚀 ~ ev:", ev.type, ev.scale, ev.deltaX, ev.deltaY);
|
|
|
+ data.transform.scale = ev.scale * data.transform.startScale;
|
|
|
+ data.transform.x = data.transform.startX + ev.deltaX;
|
|
|
+ data.transform.y = data.transform.startY + ev.deltaY;
|
|
|
+ }
|
|
|
+ if (ev.type === "panmove") {
|
|
|
+ // console.log("🚀 ~ ev:", ev.type, ev.deltaX, ev.deltaY);
|
|
|
+ data.transform.x = data.transform.startX + ev.deltaX;
|
|
|
+ data.transform.y = data.transform.startY + ev.deltaY;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ //
|
|
|
+ mc.on("hammer.input", function (ev) {
|
|
|
+ // console.log("🚀 ~ ev:", ev.type, ev.isFinal);
|
|
|
+ if (ev.isFinal) {
|
|
|
+ data.transform.startScale = data.transform.scale;
|
|
|
+ data.transform.startX = data.transform.x;
|
|
|
+ data.transform.startY = data.transform.y;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+ const resetElement = () => {
|
|
|
+ data.transform.transition = "all 0.3s";
|
|
|
+ nextTick(() => {
|
|
|
+ data.transform.scale = 1;
|
|
|
+ data.transform.x = 0;
|
|
|
+ data.transform.y = 0;
|
|
|
+ data.transform.startScale = 1;
|
|
|
+ data.transform.startX = 0;
|
|
|
+ data.transform.startY = 0;
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ const pageVisible = usePageVisibility();
|
|
|
+ watch(
|
|
|
+ () => pageVisible.value,
|
|
|
+ (val) => {
|
|
|
+ if (val === "hidden") {
|
|
|
+ console.log("页面隐藏停止播放");
|
|
|
+ handleStop();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ /** 课件播放 */
|
|
|
+ const changePlay = (res: any) => {
|
|
|
+ if (res?.data?.api === "setPlayState") {
|
|
|
+ handleStop();
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const noteBoxRef = ref();
|
|
|
+ const scrollNoteBox = (type: "left" | "right") => {
|
|
|
+ const width = noteBoxRef.value.offsetWidth / 2;
|
|
|
+ (noteBoxRef.value as unknown as HTMLElement).scrollBy({
|
|
|
+ left: type === "left" ? -width : width,
|
|
|
+ behavior: "smooth",
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ const playStatus = reactive({
|
|
|
+ gamut: false, // 是否播放音阶
|
|
|
+ answer: false, // 是否显示答案
|
|
|
+ action: false, // 是否开始播放
|
|
|
+ });
|
|
|
+
|
|
|
+ /** 音符切换 */
|
|
|
+ const noteChangeShow = () => {
|
|
|
+ // 播放音阶时不能切换
|
|
|
+ if (playStatus.gamut) return;
|
|
|
+ // 开始答题不能切换
|
|
|
+ if (playStatus.action) return;
|
|
|
+ if (data.noteType === "all") {
|
|
|
+ data.noteType = "#c";
|
|
|
+ } else {
|
|
|
+ data.noteType = "all";
|
|
|
+ }
|
|
|
+ getNotes();
|
|
|
+ };
|
|
|
+
|
|
|
+ // 开始播放音阶
|
|
|
+ const onGamutPlayOrPause = async () => {
|
|
|
+ if (playStatus.gamut) {
|
|
|
+ playStatus.gamut = false;
|
|
|
+ gaumntPause();
|
|
|
+ } else {
|
|
|
+ // 不管当前显示在哪个音老师滚动到开始位置
|
|
|
+ (noteBoxRef.value as unknown as HTMLElement).scroll({
|
|
|
+ left: 0,
|
|
|
+ top: 0,
|
|
|
+ behavior: "smooth",
|
|
|
+ });
|
|
|
+ playStatus.gamut = true;
|
|
|
+ const notes = data.notes;
|
|
|
+ let step = 7;
|
|
|
+ for (let i = 0; i < notes.length; i++) {
|
|
|
+ if (!playStatus.gamut) return false;
|
|
|
+
|
|
|
+ if (i % 8 === 0 && i !== 0) {
|
|
|
+ scrollNoteBox("right");
|
|
|
+ step = notes[i].step;
|
|
|
+ }
|
|
|
+ await gaumtPlay(notes[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // // 处理播放到最后一个
|
|
|
+ setTimeout(() => {
|
|
|
+ playStatus.gamut = false;
|
|
|
+ gaumntPause();
|
|
|
+ }, 667);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ const gaumtPlay = (note: any, status?: boolean) => {
|
|
|
+ return new Promise((resolve) => {
|
|
|
+ setTimeout(() => {
|
|
|
+ if (playStatus.gamut || status) {
|
|
|
+ noteClick(note);
|
|
|
+ }
|
|
|
+
|
|
|
+ resolve(note);
|
|
|
+ }, 667);
|
|
|
+ });
|
|
|
+ };
|
|
|
+ const gaumntPause = () => {
|
|
|
+ if (data.noteAudio) {
|
|
|
+ data.noteAudio.stop();
|
|
|
+ data.realKey = 0;
|
|
|
+ data.noteAudio = null as unknown as Howl;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ /** 开始播放 */
|
|
|
+ const playAction = reactive({
|
|
|
+ exampleAnser: {} as any, // 示例声音
|
|
|
+ standardAnswer: {} as any, // 标准答案key
|
|
|
+ showAnswerLoading: false, // 显示按答案中
|
|
|
+ listenModeStatus: false, // 听音模式
|
|
|
+ listenLock: false,
|
|
|
+ /** 0: 未答,1: 答对,2: 答错 */
|
|
|
+ userAnswerStatus: 0 as 0 | 1 | 2, // 用户回答状态
|
|
|
+ userAnswer: {} as any, // 用户答的数据
|
|
|
+ });
|
|
|
+ const onActionPlay = async () => {
|
|
|
+ if (playAction.listenLock) return;
|
|
|
+ playStatus.action = true;
|
|
|
+ playStatus.answer = true;
|
|
|
+ // 先暂停播放声音
|
|
|
+ gaumntPause();
|
|
|
+ if (data.fingeringMode === "fingeringMode") {
|
|
|
+ onFingeringMode();
|
|
|
+ } else if (data.fingeringMode === "listenMode") {
|
|
|
+ if (playAction.listenModeStatus) {
|
|
|
+ playAction.listenLock = true;
|
|
|
+ await fingeringPlay(playAction.standardAnswer);
|
|
|
+ gaumntPause();
|
|
|
+ playAction.listenLock = false;
|
|
|
+ } else {
|
|
|
+ onListenMode();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 指法模式
|
|
|
+ const fingeringPlay = (note: any, timer = 1500) => {
|
|
|
+ return new Promise((resolve) => {
|
|
|
+ noteClick(note);
|
|
|
+ setTimeout(() => {
|
|
|
+ resolve(note);
|
|
|
+ }, timer);
|
|
|
+ });
|
|
|
+ };
|
|
|
+ const onFingeringMode = () => {
|
|
|
+ const randomIndex = Math.floor(Math.random() * data.notes.length);
|
|
|
+ playAction.standardAnswer = data.notes[randomIndex];
|
|
|
+ data.realKey = data.notes[randomIndex].realKey;
|
|
|
+ };
|
|
|
+ // 听音模式
|
|
|
+ const onListenMode = async () => {
|
|
|
+ playAction.listenModeStatus = true; // 是否开始听音
|
|
|
+ playAction.listenLock = true; // 锁
|
|
|
+ let randomIndex = Math.floor(Math.random() * data.notes.length);
|
|
|
+ playAction.exampleAnser = data.notes[randomIndex];
|
|
|
+ data.realKey = playAction.exampleAnser.realKey;
|
|
|
+ scrollAnswer();
|
|
|
+ await fingeringPlay(playAction.exampleAnser);
|
|
|
+ data.realKey = 0;
|
|
|
+ playAction.exampleAnser = {};
|
|
|
+ gaumntPause();
|
|
|
+ setTimeout(async () => {
|
|
|
+ randomIndex = Math.floor(Math.random() * data.notes.length);
|
|
|
+ playAction.standardAnswer = data.notes[randomIndex];
|
|
|
+ await fingeringPlay(data.notes[randomIndex]);
|
|
|
+ gaumntPause();
|
|
|
+ playAction.listenLock = false;
|
|
|
+ }, 1000);
|
|
|
+ };
|
|
|
+
|
|
|
+ // 显示答案
|
|
|
+ const onShowAnswer = async () => {
|
|
|
+ if (data.fingeringMode === "fingeringMode") {
|
|
|
+ playAction.showAnswerLoading = true;
|
|
|
+ scrollAnswer();
|
|
|
+ ressetMode();
|
|
|
+ } else if (data.fingeringMode === "listenMode") {
|
|
|
+ if (playAction.listenLock) return;
|
|
|
+ playAction.showAnswerLoading = true;
|
|
|
+ scrollAnswer(playAction.standardAnswer.realKey);
|
|
|
+ await fingeringPlay(playAction.standardAnswer);
|
|
|
+ ressetMode(true, 0);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ // 滚动到对应答案位置
|
|
|
+ const scrollAnswer = (realKey?: any) => {
|
|
|
+ const index = data.notes.findIndex((item: any) => item.realKey === realKey || data.realKey);
|
|
|
+ const activeDom = document.querySelectorAll(".note-class")[index] as any;
|
|
|
+ if (activeDom) {
|
|
|
+ const aWidth = activeDom.offsetWidth;
|
|
|
+ const width = noteBoxRef.value.offsetWidth - aWidth;
|
|
|
+ const wLeft = noteBoxRef.value.offsetLeft;
|
|
|
+ const aLeft = Math.max(activeDom?.offsetLeft - aWidth, 0);
|
|
|
+
|
|
|
+ console.log(aLeft - wLeft - width / 2);
|
|
|
+ (noteBoxRef.value as unknown as HTMLElement).scroll({
|
|
|
+ left: aLeft - wLeft - width / 2,
|
|
|
+ top: 0,
|
|
|
+ behavior: "smooth",
|
|
|
+ });
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const ressetMode = (status = true, timer = 2000) => {
|
|
|
+ // 2秒钟后重置
|
|
|
+ setTimeout(() => {
|
|
|
+ gaumntPause();
|
|
|
+ if (status) {
|
|
|
+ playAction.standardAnswer = {};
|
|
|
+ playAction.showAnswerLoading = false;
|
|
|
+ playAction.userAnswerStatus = 0;
|
|
|
+ playAction.userAnswer = {};
|
|
|
+ playAction.listenModeStatus = false;
|
|
|
+ playStatus.action = false;
|
|
|
+ playStatus.answer = false;
|
|
|
+ data.realKey = 0;
|
|
|
+ } else {
|
|
|
+ playAction.userAnswerStatus = 0;
|
|
|
+ playAction.userAnswer = {};
|
|
|
+ }
|
|
|
+ }, timer);
|
|
|
+ };
|
|
|
+
|
|
|
+ /** 滚轮缩放 */
|
|
|
+ const handleWheel = (e: WheelEvent) => {
|
|
|
+ e.preventDefault();
|
|
|
+ if (e.deltaY > 0) {
|
|
|
+ data.transform.scale -= 0.1;
|
|
|
+ if (data.transform.scale <= 0.5) {
|
|
|
+ data.transform.scale = 0.5;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ data.transform.scale += 0.1;
|
|
|
+ if (data.transform.scale >= 2) {
|
|
|
+ data.transform.scale = 2;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ onMounted(() => {
|
|
|
+ window.addEventListener("message", changePlay);
|
|
|
+ const fingeringContainer = document.getElementById("fingeringContainer");
|
|
|
+ fingeringContainer?.addEventListener("wheel", handleWheel);
|
|
|
+ });
|
|
|
+
|
|
|
+ onUnmounted(() => {
|
|
|
+ window.removeEventListener("message", changePlay);
|
|
|
+ const fingeringContainer = document.getElementById("fingeringContainer");
|
|
|
+ fingeringContainer?.removeEventListener("wheel", handleWheel);
|
|
|
+ });
|
|
|
+
|
|
|
+ const containerBox = computed(() => {
|
|
|
+ if (state.platform === IPlatform.PC || query.modelType) {
|
|
|
+ return {
|
|
|
+ paddingTop: "1rem",
|
|
|
+ paddingBottom: "",
|
|
|
+ };
|
|
|
+ }
|
|
|
+ if (data.subject === "hulusi-flute") {
|
|
|
+ return {
|
|
|
+ paddingTop: "2.6rem",
|
|
|
+ paddingBottom: ".6rem",
|
|
|
+ };
|
|
|
+ } else if (data.subject === "piccolo") {
|
|
|
+ return {
|
|
|
+ paddingTop: "3.5rem",
|
|
|
+ paddingBottom: ".6rem",
|
|
|
+ };
|
|
|
+ } else if (data.subject === "pan-flute") {
|
|
|
+ return {
|
|
|
+ paddingTop: "0",
|
|
|
+ paddingBottom: "0",
|
|
|
+ };
|
|
|
+ } else if (data.subject === "ocarina") {
|
|
|
+ return {
|
|
|
+ paddingTop: "1rem",
|
|
|
+ paddingBottom: "0",
|
|
|
+ };
|
|
|
+ } else if (data.subject === "melodica") {
|
|
|
+ return {
|
|
|
+ paddingTop: "2.8rem",
|
|
|
+ paddingBottom: "1rem",
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ return {
|
|
|
+ paddingTop: "",
|
|
|
+ paddingBottom: "",
|
|
|
+ };
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ const listenText = computed(() => {
|
|
|
+ if (data.fingeringMode === "fingeringMode") {
|
|
|
+ if (playStatus.action) {
|
|
|
+ return "换一换";
|
|
|
+ } else {
|
|
|
+ return "开始";
|
|
|
+ }
|
|
|
+ } else if (data.fingeringMode === "listenMode") {
|
|
|
+ if (playStatus.action) {
|
|
|
+ return "再听一遍";
|
|
|
+ } else {
|
|
|
+ return "开始听音";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return "开始听音";
|
|
|
+ });
|
|
|
+
|
|
|
+ const modeText = computed(() => {
|
|
|
+ let text = "";
|
|
|
+ data.fingeringModeList.forEach((item: any) => {
|
|
|
+ if (item.value === data.fingeringMode) {
|
|
|
+ text = item.text;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return text;
|
|
|
+ });
|
|
|
+
|
|
|
+ const resultImg = (note: any) => {
|
|
|
+ if (data.realKey === note.realKey && !playStatus.action) {
|
|
|
+ return {
|
|
|
+ icon: icons.icon_btn_ylow,
|
|
|
+ status: false,
|
|
|
+ };
|
|
|
+ } else if (playAction.exampleAnser.realKey === note.realKey) {
|
|
|
+ return {
|
|
|
+ icon: icons.icon_btn_ylow,
|
|
|
+ status: false,
|
|
|
+ };
|
|
|
+ } else if (playAction.standardAnswer.realKey === note.realKey) {
|
|
|
+ // 没有开始答题
|
|
|
+ if (!playStatus.action) {
|
|
|
+ return {
|
|
|
+ icon: icons.icon_btn_ylow,
|
|
|
+ status: false,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ // 显示答案中
|
|
|
+ if (playAction.showAnswerLoading) {
|
|
|
+ return {
|
|
|
+ icon: icons.icon_btn_green,
|
|
|
+ status: true,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ // 用户答对
|
|
|
+ if (playAction.userAnswerStatus === 1) {
|
|
|
+ return {
|
|
|
+ icon: icons.icon_btn_green,
|
|
|
+ status: true,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 用户答错
|
|
|
+ if (playAction.userAnswerStatus === 2 && playAction.userAnswer.realKey === note.realKey) {
|
|
|
+ return {
|
|
|
+ icon: icons.icon_btn_red,
|
|
|
+ status: true,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ icon: icons.icon_btn_blue,
|
|
|
+ status: true,
|
|
|
+ };
|
|
|
+ };
|
|
|
+
|
|
|
+ const relactionObj = computed(() => {
|
|
|
+ const relationship = fingerData.subject?.relationship?.[data.realKey] || [];
|
|
|
+ const rs: number[] = Array.isArray(relationship[1]) ? relationship[fingerData.relationshipIndex] : relationship;
|
|
|
+ const canTizhi = Array.isArray(relationship[1]);
|
|
|
+ return {
|
|
|
+ rs,
|
|
|
+ canTizhi,
|
|
|
+ };
|
|
|
+ });
|
|
|
+ return () => {
|
|
|
+ return (
|
|
|
+ <div class={[styles.fingerBox, state.platform !== IPlatform.PC && !query.modelType && fingerData.fingeringInfo.orientation === 1 ? styles.fingerBottom : styles.fingerRight]}>
|
|
|
+ <div
|
|
|
+ class={styles.head}
|
|
|
+ style={{
|
|
|
+ paddingTop: data.paddingTop ? data.paddingTop : "",
|
|
|
+ paddingLeft: data.paddingLeft ? data.paddingLeft : "",
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <div class={styles.left}>
|
|
|
+ <button class={[styles.backBtn]} onClick={() => handleBack()}>
|
|
|
+ <img src={icons.icon_back} />
|
|
|
+ </button>
|
|
|
+ <Popover
|
|
|
+ placement="bottom"
|
|
|
+ class={styles.popoverContainer}
|
|
|
+ actions={data.subjects}
|
|
|
+ onSelect={(val: any) => {
|
|
|
+ //
|
|
|
+ selectSubjectType(val.value);
|
|
|
+ const _url =
|
|
|
+ location.origin +
|
|
|
+ location.pathname +
|
|
|
+ "#/view-figner-listen?" +
|
|
|
+ qs.stringify({
|
|
|
+ ...query,
|
|
|
+ _t: new Date().valueOf(),
|
|
|
+ subjectCode: val.value,
|
|
|
+ });
|
|
|
+ location.href = _url;
|
|
|
+ window.location.reload();
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {{
|
|
|
+ reference: () => (
|
|
|
+ <div
|
|
|
+ class={styles.baseBtn}
|
|
|
+ onClick={() => {
|
|
|
+ //
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <img src={icons.icon_change_instrument} />
|
|
|
+ <span>切换乐器</span>
|
|
|
+ </div>
|
|
|
+ ),
|
|
|
+ }}
|
|
|
+ </Popover>
|
|
|
+ </div>
|
|
|
+ <div class={styles.rightBtn}>
|
|
|
+ <Popover
|
|
|
+ placement="bottom"
|
|
|
+ class={styles.popoverContainer}
|
|
|
+ actions={data.fingeringModeList}
|
|
|
+ onSelect={(val: any) => {
|
|
|
+ //
|
|
|
+ if (playAction.listenLock) return;
|
|
|
+ data.fingeringModeList.forEach((item: any) => {
|
|
|
+ if (item.value === val.value) {
|
|
|
+ item.className = styles.selected;
|
|
|
+ } else {
|
|
|
+ item.className = styles.normal;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ data.fingeringMode = val.value;
|
|
|
+
|
|
|
+ // 重置
|
|
|
+ ressetMode(true, 0);
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {{
|
|
|
+ reference: () => (
|
|
|
+ <div class={styles.baseBtn}>
|
|
|
+ <img src={icons.icon_mode} />
|
|
|
+ <span>{modeText.value}</span>
|
|
|
+ </div>
|
|
|
+ ),
|
|
|
+ }}
|
|
|
+ </Popover>
|
|
|
+
|
|
|
+ <div class={styles.baseBtn} onClick={() => resetElement()}>
|
|
|
+ <img src={icons.icon_2_0} />
|
|
|
+ <span>还原</span>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class={styles.baseBtn}
|
|
|
+ onClick={() => {
|
|
|
+ resetElement();
|
|
|
+ data.tipShow = !data.tipShow;
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <img src={icons.icon_2_1} />
|
|
|
+ <span>使用说明</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class={styles.fingerContent}>
|
|
|
+ <div class={styles.wrapFinger}>
|
|
|
+ <div
|
|
|
+ id="fingeringContainer"
|
|
|
+ class={styles.boxFinger}
|
|
|
+ style={{
|
|
|
+ paddingTop: containerBox.value.paddingTop,
|
|
|
+ paddingBottom: containerBox.value.paddingBottom,
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ transform: `translate3d(${data.transform.x}px,${data.transform.y}px,0px) scale(${data.transform.scale})`,
|
|
|
+ transition: data.transform.transition,
|
|
|
+ }}
|
|
|
+ class={[styles.fingeringContainer]}
|
|
|
+ >
|
|
|
+ <div class={styles.imgs}>
|
|
|
+ <img src={fingerData.subject?.json?.full1} />
|
|
|
+ {relactionObj.value.rs.map((key: number | string, index: number) => {
|
|
|
+ const nk: string = typeof key === "string" ? key.replace("active-", "") : String(key);
|
|
|
+ return <img data-index={nk} src={fingerData.subject?.json?.[nk]} />;
|
|
|
+ })}
|
|
|
+ <div style={{ left: data.viewIndex == 2 ? "0" : "64%" }} class={[styles.tizhi, relactionObj.value.canTizhi && styles.canDisplay]} onClick={() => (fingerData.relationshipIndex = fingerData.relationshipIndex === 0 ? 1 : 0)}>
|
|
|
+ 替指
|
|
|
+ </div>
|
|
|
+ <div id="finger-note-2" style={{ left: "50%", transform: "translateX(-50%)" }} class={styles.tizhi} onClick={() => (fingerData.relationshipIndex = fingerData.relationshipIndex === 0 ? 1 : 0)}></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class={styles.notes}
|
|
|
+ style={{
|
|
|
+ paddingLeft: data.paddingLeft ? data.paddingLeft : "",
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Button class={styles.noteBtn} onClick={() => scrollNoteBox("left")}>
|
|
|
+ <Icon name="arrow-left" />
|
|
|
+ </Button>
|
|
|
+ <div class={[styles.noteContent, browsInfo.ios ? "" : styles.noteContentWrap, data.huaweiPad && styles.huaweiPad]}>
|
|
|
+ <div draggable={false} class={styles.note} onClick={noteChangeShow}>
|
|
|
+ <img draggable={false} src={icons.icon_btn_orange} />
|
|
|
+ <div class={[styles.noteKey]}>
|
|
|
+ <div class={[styles.noteName, styles.noteFixed]}>{data.noteType === "all" ? "全按键" : "C调"}</div>
|
|
|
+ <span class={styles.dotFixed}></span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div ref={noteBoxRef} id="noteBox1" class={styles.noteBox}>
|
|
|
+ {data.notes.map((note: any, index: number) => (
|
|
|
+ <div
|
|
|
+ id={index == 0 ? "finger-note-0" : ""}
|
|
|
+ draggable={false}
|
|
|
+ class={[styles.note, "note-class"]}
|
|
|
+ key={note.realKey}
|
|
|
+ onClick={async () => {
|
|
|
+ // 判断是否在播放音阶
|
|
|
+ if (playStatus.gamut) return;
|
|
|
+ if (playAction.listenLock) return;
|
|
|
+ if (playStatus.action) {
|
|
|
+ playAction.userAnswer = note;
|
|
|
+ // 判断用户答题
|
|
|
+ playAction.userAnswerStatus = note.realKey === playAction.standardAnswer.realKey ? 1 : 2;
|
|
|
+ if (data.fingeringMode === "listenMode") {
|
|
|
+ playAction.listenLock = true;
|
|
|
+ data.realKey = note.realKey;
|
|
|
+ await fingeringPlay(note, 1000);
|
|
|
+ ressetMode(note.realKey === playAction.standardAnswer.realKey ? true : false, 0);
|
|
|
+ data.realKey = 0;
|
|
|
+ playAction.listenLock = false;
|
|
|
+ } else {
|
|
|
+ ressetMode(note.realKey === playAction.standardAnswer.realKey ? true : false);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ noteClick(note);
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <img draggable={false} src={resultImg(note).icon} />
|
|
|
+
|
|
|
+ {playStatus.action && ((playAction.showAnswerLoading && playAction.standardAnswer.realKey === note.realKey) || (playAction.userAnswerStatus === 1 && playAction.userAnswer.realKey === note.realKey)) ? <span class={styles.showAnswer}></span> : ""}
|
|
|
+ {playStatus.action && playAction.userAnswerStatus === 2 && playAction.userAnswer.realKey === note.realKey ? <span class={[styles.showAnswer, styles.errorAnswer]}></span> : ""}
|
|
|
+
|
|
|
+ <div
|
|
|
+ class={[
|
|
|
+ styles.noteKey,
|
|
|
+ ((data.realKey === note.realKey && !playStatus.action) ||
|
|
|
+ (playStatus.action && ((playAction.showAnswerLoading && playAction.standardAnswer.realKey === note.realKey) || (playAction.userAnswerStatus === 1 && playAction.userAnswer.realKey === note.realKey))) ||
|
|
|
+ (playStatus.action && playAction.userAnswerStatus === 2 && playAction.userAnswer.realKey === note.realKey)) &&
|
|
|
+ styles.keyActive,
|
|
|
+ ]}
|
|
|
+ >
|
|
|
+ {/* 显示对应的点 */}
|
|
|
+ {note.step > 0 ? note.steps.map((n: any) => <span class={styles.dot}></span>) : null}
|
|
|
+
|
|
|
+ <div class={styles.noteName}>
|
|
|
+ <sup>{note.mark && (note.mark === "rise" ? "#" : "b")}</sup>
|
|
|
+ {note.key}
|
|
|
+ </div>
|
|
|
+ {/* 显示对应的点 */}
|
|
|
+ {note.step < 0 ? note.steps.map((n: any) => <span class={styles.dot}></span>) : null}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <Button class={styles.noteBtn} onClick={() => scrollNoteBox("right")}>
|
|
|
+ <Icon name="arrow" />
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+ <div class={styles.optionBtns}>
|
|
|
+ {/* , styles.disabled */}
|
|
|
+ <Button class={[styles.oBtn, styles.gamut, playStatus.action && styles.disabled]} round onClick={onGamutPlayOrPause}>
|
|
|
+ {playStatus.gamut ? "暂停" : "播放音阶"}
|
|
|
+ </Button>
|
|
|
+ <Button class={[styles.oBtn, styles.play, playStatus.gamut && styles.disabled]} round onClick={onActionPlay}>
|
|
|
+ {listenText.value}
|
|
|
+ </Button>
|
|
|
+ <Button class={[styles.oBtn, styles.success, !playStatus.answer && styles.disabled]} round onClick={onShowAnswer}>
|
|
|
+ 显示答案
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class={[styles.tips, data.tipShow ? "" : styles.tipHidden]}>
|
|
|
+ <div class={styles.tipTitle}>
|
|
|
+ <div class={styles.tipTitleName}>{fingerData.fingeringInfo.code}使用说明</div>
|
|
|
+ <Button class={styles.tipClose} onClick={() => (data.tipShow = false)}>
|
|
|
+ <Icon name="cross" size={19} color="#fff" />
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+ <div class={styles.iconBook}></div>
|
|
|
+ <div class={styles.tipContentbox}>
|
|
|
+ <div class={styles.tipContent}>
|
|
|
+ {data.tips.map((tip, tipIndex) => (
|
|
|
+ <div class={styles.tipItem}>
|
|
|
+ <div class={styles.iconWrap}>
|
|
|
+ <div class={styles.tipItemIcon}>{tipIndex + 1}</div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ {tip.name}: {tip.realName}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ {data.loadingSoundFonts && (
|
|
|
+ <div class={styles.loading}>
|
|
|
+ <div class={styles.loadingWrap}>
|
|
|
+ <img class={styles.loadingIcon} src={icon_loading_img} />
|
|
|
+ <Progress percentage={data.loadingSoundProgress} />
|
|
|
+ <div class={styles.loadingTip}>加载中,请稍后…</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ {!!data.tones.length && (
|
|
|
+ <>
|
|
|
+ {fingerData.fingeringInfo.name == "hulusi-flute" ? (
|
|
|
+ <div id="finger-note-1" class={[styles.toggleBtn, styles.toggleBtnhulusi]} onClick={() => (data.tnoteShow = true)}>
|
|
|
+ <div>
|
|
|
+ 全按作
|
|
|
+ <div class={[styles.noteKey]}>
|
|
|
+ {data.activeTone.step > 0 ? <span class={styles.dot}></span> : null}
|
|
|
+
|
|
|
+ <div class={styles.noteName}>
|
|
|
+ <sup>{data.activeTone.mark && (data.activeTone.mark === "rise" ? "#" : "b")}</sup>
|
|
|
+ {data.activeTone.key}
|
|
|
+ </div>
|
|
|
+ {data.activeTone.step < 0 ? <span class={styles.dot}></span> : null}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <img src={icons.icon_arrow} />
|
|
|
+ </div>
|
|
|
+ ) : (
|
|
|
+ <div id="finger-note-1" class={styles.toggleBtn} onClick={() => (data.tnoteShow = true)}>
|
|
|
+ <div style={{ marginTop: "-4px" }}>
|
|
|
+ <sup>{data.activeTone.mark && (data.activeTone.mark === "rise" ? "#" : "b")}</sup>
|
|
|
+ {data.activeTone.name}
|
|
|
+ </div>
|
|
|
+ 调
|
|
|
+ <img src={icons.icon_arrow} />
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </>
|
|
|
+ )}
|
|
|
+
|
|
|
+ <Popup class="tonePopup" v-model:show={data.tnoteShow} position={state.platform !== IPlatform.PC && !query.modelType && fingerData.fingeringInfo.orientation === 1 ? "bottom" : "right"}>
|
|
|
+ <div class={styles.tones}>
|
|
|
+ <div class={styles.toneTitle}>
|
|
|
+ <div class={styles.tipTitleName}>移调</div>
|
|
|
+ <Button class={styles.tipClose} onClick={() => (data.tnoteShow = false)}>
|
|
|
+ <Icon name="cross" size={19} color="#fff" />
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+ <div class={styles.tipContentbox}>
|
|
|
+ <div class={styles.tipContent}>
|
|
|
+ <div class={styles.tipWrap}>
|
|
|
+ <Space size={0} class={styles.toneContent}>
|
|
|
+ {data.tones.map((tone: IFIGNER_INSTRUMENT_Note) => {
|
|
|
+ const steps = new Array(Math.abs(tone.step)).fill(1);
|
|
|
+ return (
|
|
|
+ <Button
|
|
|
+ class={[fingerData.fingeringInfo.name == "hulusi-flute" && styles.hulusiBtn]}
|
|
|
+ round
|
|
|
+ plain
|
|
|
+ type={data.popupActiveTone.realName === tone.realName ? "primary" : "default"}
|
|
|
+ onClick={() => {
|
|
|
+ data.popupActiveTone = tone;
|
|
|
+ setNotes();
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {fingerData.fingeringInfo.name == "hulusi-flute" ? (
|
|
|
+ <div style={{ display: "flex", alignItems: "center" }}>
|
|
|
+ 全按作
|
|
|
+ <div class={[styles.noteKey, styles.hulusiNoteKey]}>
|
|
|
+ {tone.step > 0 ? <span class={styles.dot}></span> : null}
|
|
|
+ <div class={styles.noteName} style={{ fontSize: "0.25rem" }}>
|
|
|
+ <sup>{tone.mark && (tone.mark === "rise" ? "#" : "b")}</sup>
|
|
|
+ {tone.key}
|
|
|
+ </div>
|
|
|
+ {tone.step < 0 ? <span class={styles.dot}></span> : null}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ ) : (
|
|
|
+ <div class={styles.noteName}>
|
|
|
+ <sup>{tone.mark && (tone.mark === "rise" ? "#" : "b")}</sup>
|
|
|
+ {tone.name}
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </Button>
|
|
|
+ );
|
|
|
+ })}
|
|
|
+ </Space>
|
|
|
+ </div>
|
|
|
+ <div class={styles.toneAction}>
|
|
|
+ <img onClick={() => (data.tnoteShow = false)} src={icons.icon_action_cancel} />
|
|
|
+ <img
|
|
|
+ onClick={() => {
|
|
|
+ data.activeTone = data.popupActiveTone;
|
|
|
+ setNotes();
|
|
|
+ data.tnoteShow = false;
|
|
|
+ }}
|
|
|
+ src={icons.icon_action_confirm}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </Popup>
|
|
|
+
|
|
|
+ {/* {props.show && !data.loading && !data.loadingSoundFonts && <GuideIndex showGuide={false} list={["finger"]} />} */}
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ };
|
|
|
+ },
|
|
|
+});
|