123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585 |
- import { Transition, computed, defineComponent, onMounted, onUnmounted, reactive, ref, watch, toRef } 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, showToast } 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"
- import useDrag from "/src/view/plugins/useDrag/index";
- import Dragbom from "/src/view/plugins/useDrag/dragbom";
- import { getGuidance, setGuidance } from "../custom-plugins/guide-page/api";
- /** 头部数据和方法 */
- 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") {
- // 如果延迟检测资源还在加载中,给出提示
- if (!evaluatingData.jsonLoadDone) {
- evaluatingData.jsonLoading = true
- showToast('资源加载中,请稍后')
- return
- }
- // 如果是pc端, 评测模式暂不可用
- if (state.platform === IPlatform.PC) {
- showConfirmDialog({
- className: "modalTip",
- title: "温馨提示",
- message: "该功能暂未开放,敬请期待!",
- showCancelButton: false,
- });
- return;
- }
- state.playIngSpeed = state.originSpeed
- handleStartEvaluat();
- // 开发模式,把此处打开
- // state.modeType = "evaluating"
- // evaluatingData.rendered = true;
- // evaluatingData.soundEffectMode = true;
-
- } 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) => {
- // console.log('监听上课页面message',res)
- if (res?.data?.api === "setPlayState") {
- togglePlay("paused");
- }
- // 菜单状态
- if ((state.platform === IPlatform.PC && res?.data?.api) === "attendClassBarStatus") {
- // state.attendHideMenu = res?.data?.hideMenu;
- }
- // 上课页面,按钮方向
- if (res?.data?.api === "imagePos") {
- if (res?.data.data) {
- state.playBtnDirection = res.data.data === 'right' ? 'right' : 'left';
- if (state.fingeringInfo.direction === "vertical" && state.setting.displayFingering) {
- state.musicScoreBtnDirection = state.playBtnDirection === 'right' ? 'left' : 'right';
- } else {
- state.musicScoreBtnDirection = state.playBtnDirection;
- }
- }
- }
- };
- const parentClassName = "settingBoxClass_drag";
- const userId = storeData.user?.id ? String(storeData.user?.id) : '';
- const positionInfo = state.platform !== IPlatform.PC ? {
- styleDrag: { value: null }
- } : useDrag(
- [
- `${parentClassName} .top_drag`,
- `${parentClassName} .bom_drag`
- ],
- parentClassName,
- toRef(headTopData, 'settingMode'),
- userId
- )
- 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);
- });
- // 获取引导页信息
- const getAllGuidance = async()=>{
- let guideInfo: any = null;
- try{
- const res = await getGuidance({guideTag:'guideInfo'})
- if(res.data){
- guideInfo = JSON.parse(res.data?.guideValue) || null
- }else{
- guideInfo = {}
- }
- state.guideInfo = guideInfo;
- }catch(e){
- console.log(e)
- }
-
- }
- getAllGuidance()
- // 完成拖动弹窗引导页
- const handleGuide = async () => {
- state.guideInfo.teacherDrag = true;
- try{
- const res = await setGuidance({guideTag:'guideInfo',guideValue:JSON.stringify(state.guideInfo)})
- }catch(e){
- console.log(e)
- }
- }
- return () => (
- <>
- <div
- class={[styles.headerTop, state.platform === IPlatform.PC && styles.headRightTop, state.platform === IPlatform.PC && !state.attendHideMenu && styles.headRightTopHide]}
- onClick={(e: Event) => {
- e.stopPropagation();
- if (state.platform === IPlatform.PC) {
- // 显示隐藏菜单
- window.parent.postMessage(
- {
- api: "onAttendToggleMenu",
- },
- "*"
- );
- }
- }}
- >
- <div class={[styles.back, "headTopBackBtn", !headTopData.showBack && styles.hidenBack]} onClick={handleBack}>
- <img src={iconBack} />
- </div>
- {(query.iscurseplay === "play" || state.platform === IPlatform.PC) ? null : <Title class="pcTitle" text={state.examSongName} rightView={false} />}
- <div
- class={[styles.headRight, state.platform === IPlatform.PC && styles.pcHeadRight]}
- 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>
- {/* 一行谱模式,暂不支持节拍指针 */}
- {
- !state.isSingleLine ?
- <div class={[styles.btn, state.platform === IPlatform.PC ? styles.pcBtn : ""]} 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> : null
- }
- {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={state.platform === IPlatform.PC ? "top" : "bottom"} overlay={false} offset={state.platform === IPlatform.PC ? [8,40] : [0,8]}>
- {{
- 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={state.platform === IPlatform.PC ? "top-end" : "bottom-end"} overlay={false} offset={state.platform === IPlatform.PC ? [0,40] : [0,8]}>
- {{
- 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 && state.musicScoreBtnDirection === 'left' ? styles.playLeftButton : state.platform === IPlatform.PC && state.musicScoreBtnDirection === 'right' ? styles.playRightButton : '', 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(state.platform === IPlatform.PC ? "pc_icon_playbtn.png" : "icon_play.svg")} />
- <img style={{ display: state.playState === "play" ? "" : "none" }} class={styles.iconBtn} src={headImg(state.platform === IPlatform.PC ? "pc_icon_pausebtn.png" : "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 && state.musicScoreBtnDirection === 'left' ? styles.pauseLeftButton : state.platform === IPlatform.PC && state.musicScoreBtnDirection === 'right' ? styles.pauseRightButton : '', state.platform === IPlatform.PC && !state.attendHideMenu && styles.playButtonHide]}
- onClick={() => handleResetPlay()}
- >
- <img class={styles.iconBtn} src={headImg(state.platform === IPlatform.PC ? "pc_icon_resetbtn.png" : "icon_resetbtn.svg")} />
- </div>
- <Popup v-model:show={headTopData.settingMode} class="popup-custom van-scale center-closeBtn settingBoxClass_drag" transition="van-scale" teleport="body" closeable style={positionInfo.styleDrag.value}>
- <Settting />
- { state.platform === IPlatform.PC && <Dragbom showGuide={!state.guideInfo?.teacherDrag} onGuideDone={handleGuide} /> }
- </Popup>
- {/* 模式切换 */}
- <ModeTypeMode />
- {/* isAllBtns */}
- {isAllBtns.value && !query.isCbs && <TeacherTop></TeacherTop>}
- {isAllBtnsStudent.value && !query.isCbs && <StudentTop></StudentTop>}
- </>
- );
- },
- });
|