import { Transition, computed, defineComponent, onMounted, onUnmounted, reactive, ref, watch } from "vue"; import styles from "./index.module.less"; import iconBack from "./image/icon-back.svg"; import Title from "./title"; import { headImg } from "./image"; import { Badge, Circle, Popover, Popup, showConfirmDialog } from "vant"; import Speed from "./speed"; import { evaluatingData, handleStartEvaluat } from "/src/view/evaluating"; import Settting from "./settting"; import state, { IPlatform, handleChangeSection, handleResetPlay, handleRessetState, togglePlay } from "/src/state"; import { getAudioCurrentTime } from "/src/view/audio-list"; import { followData, toggleFollow } from "/src/view/follow-practice"; import { api_back } from "/src/helpers/communication"; import MusicType from "./music-type"; import ModeTypeMode from "../component/mode-type-mode"; import { getQuery } from "/src/utils/queryString"; import { storeData } from "/src/store"; import TeacherTop from "../custom-plugins/guide-page/teacher-top"; import StudentTop from "../custom-plugins/guide-page/student-top"; import { HANDLE_WORK_ADD } from "../custom-plugins/work-index"; import { browser } from "/src/utils"; import store from "store"; import "../component/the-modal-tip/index.module.less"; import { metronomeData } from "../../helpers/metronome"; import { toggleMusicSheet } from "/src/view/plugins/toggleMusicSheet" /** 头部数据和方法 */ export const headTopData = reactive({ /** 模式 */ modeType: "" as "init" | "show", /** 显示返回按钮 */ showBack: true, /** 设置弹窗 */ settingMode: false, /** 切换模式 */ handleChangeModeType(value: "practise" | "follow" | "evaluating") { // 后台设置为不能评测 if (value === 'evaluating' && !state.enableEvaluation) return // 打击乐&节奏练习不支持跟练模式 if (value === 'follow' && state.isPercussion) return // 跟练模式,光标只有音符模式,无节拍模式 if (value === 'follow' && metronomeData.cursorMode === 2) { metronomeData.cursorMode = 1 } if (value === 'practise') { // state.playIngSpeed = state.speed } if (value === "evaluating") { // 如果是pc端, 评测模式暂不可用 if (state.platform === IPlatform.PC) { showConfirmDialog({ className: "modalTip", title: "温馨提示", message: "该功能暂未开放,敬请期待!", showCancelButton: false, }); return; } state.playIngSpeed = state.originSpeed handleStartEvaluat(); } else if (value === "follow") { toggleFollow(); } headTopData.modeType = "show"; }, }); export const headData = reactive({ speedShow: false, musicTypeShow: false, }); export default defineComponent({ name: "header-top", emits: ["close"], setup(props, { emit }) { const query = getQuery(); // 是否显示引导 const showGuide = ref(false); const showStudentGuide = ref(false); /** 设置按钮 */ const settingBtn = computed(() => { // 音频播放中 禁用 if (state.playState === "play") return { display: true, disabled: true }; // 评测开始 禁用, 跟练开始 禁用 if (evaluatingData.startBegin || followData.start) return { display: true, disabled: true }; return { display: true, disabled: false, }; }); /** 转谱按钮 */ const converBtn = computed(() => { // 音频播放中 禁用 if (state.playState === "play") return { display: true, disabled: true }; // 评测开始 禁用 if (evaluatingData.startBegin || followData.start) return { display: true, disabled: true }; return { disabled: false, display: true, }; }); /** 速度按钮 */ const speedBtn = computed(() => { // 选择模式, 跟练模式 不显示 if (headTopData.modeType !== "show" || state.modeType === "follow") return { display: false, disabled: true }; // 评测模式, 音频播放中 禁用 if (state.modeType === "evaluating" || state.playState === "play") return { display: true, disabled: true }; return { disabled: false, display: true, }; }); /** 指法按钮 */ const fingeringBtn = computed(() => { // 后台设置不显示指法 if (!state.isShowFingering) return { display: true, disabled: true }; // 没有指法 选择模式 评测模式 跟练模式 不显示 if (headTopData.modeType !== "show" || !state.fingeringInfo.name || ["evaluating", "follow"].includes(state.modeType)) return { display: false, disabled: true }; // 音频播放中 禁用 if (state.playState === "play") return { display: true, disabled: true }; return { disabled: false, display: true, }; }); /** 摄像头按钮 */ const cameraBtn = computed(() => { // 选择模式 不显示 if (headTopData.modeType !== "show" || state.modeType !== "evaluating") return { display: false, disabled: true }; // 音频播放中 禁用 if (state.playState === "play") return { display: true, disabled: true }; return { disabled: false, display: true, }; }); /** 选段按钮 */ const selectBtn = computed(() => { // 选择模式 不显示 if (headTopData.modeType !== "show" || ["evaluating", "follow"].includes(state.modeType)) return { display: false, disabled: true }; // 音频播放中 禁用 if (state.playState === "play") return { display: true, disabled: true }; return { disabled: false, display: true, }; }); /** 原声按钮 */ const originBtn = computed(() => { // 选择模式,跟练模式 不显示 if (headTopData.modeType !== "show" || state.modeType === "follow") return { display: false, disabled: false }; // 评测开始 禁用 if (state.modeType === "evaluating") return { display: false, disabled: true }; if (!state.isAppPlay) { // 原声, 伴奏 少一个,就不能切换 if (!state.music || !state.accompany) return { display: true, disabled: true }; } return { disabled: false, display: true, }; }); /** 模式切换按钮 */ const toggleBtn = computed(() => { // 选择模式, url设置模式 不显示 if (headTopData.modeType !== "show" || !headTopData.showBack) return { display: false, disabled: false }; // 跟练开始, 评测开始 禁用 if (followData.start || evaluatingData.startBegin) return { display: true, disabled: true }; return { display: true, disabled: false, }; }); /** 播放按钮 */ const playBtn = computed(() => { // 选择模式 不显示 if (headTopData.modeType !== "show") return { display: false, disabled: false }; // 评测模式 不显示,跟练模式 不显示 if (["evaluating", "follow"].includes(state.modeType)) return { display: false, disabled: true }; // midi音频未初始化完成不可点击 if (state.isAppPlay && state.midiPlayIniting) return { display: true, disabled: true }; return { display: true, disabled: false, }; }); /** 重播按钮 */ const resetBtn = computed(() => { // 选择模式 不显示 if (headTopData.modeType !== "show") return { display: false, disabled: false }; // 评测模式 不显示,跟练模式 不显示 if (["evaluating", "follow"].includes(state.modeType)) return { display: false, disabled: true }; // 播放状态 不显示 if (state.playState === "play") return { display: false, disabled: true }; // 播放进度为0 不显示 const currentTime = getAudioCurrentTime(); // midi音频未初始化完成不可点击 if (state.isAppPlay && state.midiPlayIniting) return { display: false, disabled: true }; if (!currentTime) return { display: false, disabled: true }; return { display: true, disabled: false, }; }); const isAllBtns = computed(() => { const flag = converBtn.value.display && speedBtn.value.display && selectBtn.value.display && originBtn.value.display && toggleBtn.value.display && showGuide.value; return flag; }); const isAllBtnsStudent = computed(() => { const flag = converBtn.value.display && speedBtn.value.display && selectBtn.value.display && originBtn.value.display && toggleBtn.value.display && showStudentGuide.value; return flag; }); const browInfo = browser(); /** 返回 */ const handleBack = () => { HANDLE_WORK_ADD(); // 不在APP中, if (!storeData.isApp) { window.close(); return; } if ((browInfo.iPhone || browInfo.ios) && query.workRecord) { setTimeout(() => { api_back(); }, 550); return; } api_back(); }; /** 根据参数设置模式 */ const getQueryModelSetModelType = () => { /** 作业模式 start, 如果为作业模式不处理,让作业模块处理 */ if (query.workRecord) { return; } /** 作业模式 end */ if (query.modelType) { if (query.modelType === "practise") { headTopData.handleChangeModeType("practise"); } else if (query.modelType === "evaluating") { headTopData.handleChangeModeType("evaluating"); } headTopData.showBack = false; } else { setTimeout(() => { headTopData.modeType = "init"; }, 500); } }; /** 课件播放 */ const changePlay = (res: any) => { if (res?.data?.api === "setPlayState") { togglePlay("paused"); } // 菜单状态 if ((state.platform === IPlatform.PC && res?.data?.api) === "attendClassBarStatus") { state.attendHideMenu = res?.data?.hideMenu; } }; onMounted(() => { getQueryModelSetModelType(); window.addEventListener("message", changePlay); if (state.platform === IPlatform.PC) { showGuide.value = true; } else { showStudentGuide.value = true; } }); onUnmounted(() => { window.removeEventListener("message", changePlay); }); // 设置改变触发 watch(state.setting, () => { console.log(state.setting, "state.setting"); store.set("musicscoresetting", state.setting); }); return () => ( <>
{ e.stopPropagation(); if (state.platform === IPlatform.PC) { // 显示隐藏菜单 window.parent.postMessage( { api: "onAttendToggleMenu", }, "*" ); } }} >
{query.iscurseplay === "play" ? null : } <div class={[styles.headRight]} onClick={(e: Event) => { e.stopPropagation(); }} > <div id={state.platform === IPlatform.PC ? "teacherTop-0" : "studnetT-0"} style={{ display: toggleBtn.value.display ? "" : "none" }} class={[styles.btn, toggleBtn.value.disabled && styles.disabled]} onClick={() => { handleRessetState(); headTopData.modeType = "init"; }} > <img class={styles.iconBtn} src={headImg(`modeType.svg`)} /> <span>模式</span> </div> <div class={[styles.btn]} onClick={() => { // 切换光标模式 let mode = metronomeData.cursorMode if (['follow'].includes(state.modeType)) { mode = metronomeData.cursorMode === 1 ? 3 : 1 } else { mode = metronomeData.cursorMode === 3 ? 1 : metronomeData.cursorMode + 1 } metronomeData.cursorMode = mode }}> <img class={styles.iconBtn} src={headImg(metronomeData.cursorMode === 1 ? 'cursor-icon-1.svg' : metronomeData.cursorMode === 2 ? 'cursor-icon-2.svg' : metronomeData.cursorMode === 3 ? 'cursor-icon-3.svg' : '')} /> <span class={styles.iconContent}> {metronomeData.cursorMode === 1 ? '音符指针' : metronomeData.cursorMode === 2 ? '节拍指针' : metronomeData.cursorMode === 3 ? '关闭指针' : ''} {metronomeData.cursorTips && <> <i class={styles.arrowIcon}></i> <div class={[styles['botton-tips'],metronomeData.cursorMode === 3 ? styles.tipSpec : '']}>{metronomeData.cursorTips}</div> </>} </span> </div> {state.musicRendered && !query.lessonTrainingId && !query.questionId && state.isConcert && ( <div class={[styles.btn, (state.playState === "play" && fingeringBtn.value.disabled) && styles.disabled]} onClick={() => { toggleMusicSheet.toggle(true) }}> <img class={styles.iconBtn} src={headImg(`shenggui.svg`)} /> <span>声轨</span> </div> )} <div id={state.platform === IPlatform.PC ? "teacherTop-1" : "studnetT-1"} style={{ display: originBtn.value.display ? "" : "none" }} class={[styles.btn, originBtn.value.disabled && styles.disabled]} onClick={() => { state.playSource = state.playSource === "music" ? "background" : "music"; }} > <img style={{ display: state.playSource === "music" ? "" : "none" }} class={styles.iconBtn} src={headImg(`music.svg`)} /> <img style={{ display: state.playSource === "music" ? "none" : "" }} class={styles.iconBtn} src={headImg(`background.svg`)} /> <span>{state.playSource === "music" ? "原声" : "伴奏"}</span> </div> { state.modeType !== "evaluating" && <div class={[styles.btn]} onClick={async () => { metronomeData.disable = !metronomeData.disable; metronomeData.metro?.initPlayer(); }} > <img style={{ display: metronomeData.disable ? "block" : "none" }} class={styles.iconBtn} src={headImg("tickoff.svg")} /> <img style={{ display: !metronomeData.disable ? "block" : "none" }} class={styles.iconBtn} src={headImg("tickon.svg")} /> <span style={{ whiteSpace: "nowrap" }}>节拍器</span> </div> } <div id={state.platform === IPlatform.PC ? "teacherTop-2" : "studnetT-2"} style={{ display: selectBtn.value.display ? "" : "none" }} class={[styles.btn, selectBtn.value.disabled && styles.disabled]} onClick={() => handleChangeSection()}> <img style={{ display: state.section.length === 0 ? "" : "none" }} class={styles.iconBtn} src={headImg(`section0.svg`)} /> <img style={{ display: state.section.length === 1 ? "" : "none" }} class={styles.iconBtn} src={headImg(`section1.svg`)} /> <img style={{ display: state.section.length === 2 ? "" : "none" }} class={styles.iconBtn} src={headImg(`section2.svg`)} /> <span>选段</span> </div> <div id={state.platform === IPlatform.PC ? "teacherTop-3" : "studnetT-3"} style={{ display: fingeringBtn.value.display ? "" : "none" }} class={[styles.btn, fingeringBtn.value.disabled && styles.disabled]} onClick={() => { state.setting.displayFingering = !state.setting.displayFingering; }} > <img style={{ display: state.setting.displayFingering ? "" : "none" }} class={styles.iconBtn} src={headImg(`icon_evaluatingOn.svg`)} /> <img style={{ display: state.setting.displayFingering ? "none" : "" }} class={styles.iconBtn} src={headImg(`icon_evaluatingOff.svg`)} /> <span>指法</span> </div> <Popover trigger="manual" v-model:show={headData.speedShow} placement="bottom" overlay={false}> {{ reference: () => ( <div id={state.platform === IPlatform.PC ? "teacherTop-4" : "studnetT-4"} style={{ display: speedBtn.value.display ? "" : "none" }} class={[styles.btn, speedBtn.value.disabled && styles.disabled]} onClick={(e: Event) => { e.stopPropagation(); headData.speedShow = !headData.speedShow; }} > <Badge class={styles.badge} content={state.playState === "play" ? state.playIngSpeed : state.speed}> <img class={styles.iconBtn} src={headImg("icon_speed.svg")} /> </Badge> <span>速度</span> </div> ), default: () => <Speed />, }} </Popover> { state.enableNotation ? <Popover trigger="manual" v-model:show={headData.musicTypeShow} placement="bottom-end" overlay={false}> {{ reference: () => ( <div id={state.platform === IPlatform.PC ? "teacherTop-5" : "studnetT-5"} style={{ display: converBtn.value.display ? "" : "none" }} class={[styles.btn, converBtn.value.disabled && styles.disabled]} onClick={(e: Event) => { e.stopPropagation(); headData.musicTypeShow = !headData.musicTypeShow; }} > <img class={styles.iconBtn} src={headImg("icon_zhuanpu.svg")} /> <span>{state.musicRenderType === "staff" ? "转简谱" : "转五线谱"}</span> </div> ), default: () => <MusicType />, }} </Popover> : null } <div id={state.platform === IPlatform.PC ? "teacherTop-6" : "studnetT-6"} style={{ display: settingBtn.value.display ? "" : "none" }} class={[styles.btn, styles.setBtn, settingBtn.value.disabled && styles.disabled]} onClick={() => (headTopData.settingMode = true)}> <img class={styles.iconBtn} src={headImg("icon_menu.svg")} /> <span>设置</span> </div> </div> </div> {/* 播放按钮 */} <div id="studnetT-7" style={{ display: playBtn.value.display ? "" : "none" }} class={[styles.btn, styles.playBtn, playBtn.value.disabled && styles.disabled, state.platform === IPlatform.PC && styles.playButton, state.platform === IPlatform.PC && !state.attendHideMenu && styles.playButtonHide]} onClick={() => togglePlay()} > <div class={styles.btnWrap}> <img style={{ display: state.playState === "play" ? "none" : "" }} class={styles.iconBtn} src={headImg("icon_play.svg")} /> <img style={{ display: state.playState === "play" ? "" : "none" }} class={styles.iconBtn} src={headImg("icon_pause.svg")} /> <Circle style={{ opacity: state.playState === "play" ? 1 : 0 }} class={styles.progress} stroke-width={80} currentRate={state.playProgress} rate={100} color="#FFC830" /> </div> </div> {/* 重播按钮 */} <div id="tips-step-9" style={{ display: resetBtn.value.display ? "" : "none" }} class={[styles.btn, styles.resetBtn, resetBtn.value.disabled && styles.disabled, state.platform === IPlatform.PC && styles.pauseButton, state.platform === IPlatform.PC && !state.attendHideMenu && styles.playButtonHide]} onClick={() => handleResetPlay()} > <img class={styles.iconBtn} src={headImg("icon_resetbtn.svg")} /> </div> <Popup v-model:show={headTopData.settingMode} class="popup-custom van-scale center-closeBtn" transition="van-scale" teleport="body" closeable> <Settting /> </Popup> {/* 模式切换 */} <ModeTypeMode /> {/* isAllBtns */} {isAllBtns.value && !query.isCbs && <TeacherTop></TeacherTop>} {isAllBtnsStudent.value && !query.isCbs && <StudentTop></StudentTop>} </> ); }, });