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, 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_setRequestedOrientation } from "/src/helpers/communication"; import Hammer from "hammerjs"; import { Button, Icon, Loading, Popup, Progress, Space } from "vant"; import GuideIndex from "./guide/guide-index"; import { getQuery } from "/src/utils/queryString"; import { browser } from "/src/utils"; import { usePageVisibility } from "@vant/use"; import { watch } from "vue"; import { Vue3Lottie } from "vue3-lottie"; import refesh_anim from "./refresh_anim.json"; import icon_loading_img from './image/icon_loading_img.png' export default defineComponent({ name: "viewFigner", emits: ["close"], props: { isComponent: { type: Boolean, default: false, }, subject: { type: String as PropType, default: "", }, }, setup(props, { emit }) { const query = getQuery(); const browsInfo = browser(); const code = mappingVoicePart(query.code, "INSTRUMENT") const subject = props.isComponent ? props.subject || "pan-flute" : code || "pan-flute"; 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, 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, huaweiPad: navigator?.userAgent?.includes('UAWEIVRD-W09') ? true : false }); const fingerData = reactive({ relationshipIndex: 0, subject: null as unknown as ITypeFingering, fingeringInfo: subjectFingering(data.subject), }); 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) { data.notes = fignerData[`list${data.activeTone.realName || ""}`]; } }; const getFingeringData = async () => { const subject: any = data.subject + (data.viewIndex === 0 ? "" : data.viewIndex); console.log("🚀 ~ subject:", subject); fingerData.subject = await getFingeringConfig(subject); setTimeout(() => { if (!props.isComponent){ console.log(fingerData.fingeringInfo.orientation) if (fingerData.fingeringInfo.orientation === 1){ api_setRequestedOrientation(fingerData.fingeringInfo.orientation); // fingerData.fingeringInfo.orientation = 1 } } }, 2000) }; 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; 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); } setTimeout(() => { data.loadingSoundFonts = false; }, 300); // console.log("🚀 ~ data.soundFonts:", data.soundFonts); }; onBeforeMount(() => { getNotes(); getFingeringData(); getSounFonts(); }); 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 === 1){ api_setRequestedOrientation(0); } } // 不在APP中, if (!storeData.isApp) { window.close(); return; } api_back(); }; onMounted(() => { loadElement(); }); 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 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); }); return () => { 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 (
{data.subject === "pan-flute" && (
{ data.viewIndex++; if (data.viewIndex > 2) { data.viewIndex = 0; } getFingeringData(); }} > 切换视图
)}
resetElement()}> 还原
{ resetElement(); data.tipShow = !data.tipShow; }} > 使用说明
{rs.map((key: number | string, index: number) => { const nk: string = typeof key === "string" ? key.replace("active-", "") : String(key); return ; })}
(fingerData.relationshipIndex = fingerData.relationshipIndex === 0 ? 1 : 0) } > 替指
{data.notes.map((note: IFIGNER_INSTRUMENT_Note, index: number) => { const steps = new Array(Math.abs(note.step)).fill(1); return (
noteClick(note)} > {data.realKey === note.realKey ? ( ) : ( )}
{note.step > 0 ? steps.map((n) => ) : null}
{note.mark && (note.mark === "rise" ? "#" : "b")} {note.key}
{note.step < 0 ? steps.map((n) => ) : null}
); })}
{fingerData.fingeringInfo.code}使用说明
{data.tips.map((tip, tipIndex) => (
{tipIndex + 1}
{tip.name}: {tip.realName}
))}
{data.loadingSoundFonts && (
)}
{!!data.tones.length && ( <> {fingerData.fingeringInfo.name == "hulusi-flute" ? (
(data.tnoteShow = true)} >
全按作
{data.activeTone.step > 0 ? : null}
{data.activeTone.mark && (data.activeTone.mark === "rise" ? "#" : "b")} {data.activeTone.key}
{data.activeTone.step < 0 ? : null}
) : (
(data.tnoteShow = true)}>
{data.activeTone.mark && (data.activeTone.mark === "rise" ? "#" : "b")} {data.activeTone.name}
)} )}
移调
{data.tones.map((tone: IFIGNER_INSTRUMENT_Note) => { const steps = new Array(Math.abs(tone.step)).fill(1); return ( ); })}
{!data.loading && }
); }; }, });