index.tsx 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. import { Transition, computed, defineComponent, onMounted, onUnmounted, reactive, ref, watch, toRef } from "vue";
  2. import styles from "./index.module.less";
  3. import iconBack from "./image/icon-back.png";
  4. import listImg from "./image/list.png";
  5. import iconMode from "./image/mode.png";
  6. import { headImg } from "./image";
  7. import { Badge, Circle, Popover, Popup, showConfirmDialog, showToast, NoticeBar } from "vant";
  8. import Speed from "./speed";
  9. import { evaluatingData, handleStartEvaluat } from "/src/view/evaluating";
  10. import Settting from "./settting";
  11. import state, { IPlatform, handleChangeSection, handleResetPlay, handleRessetState, togglePlay } from "/src/state";
  12. import { getAudioCurrentTime } from "/src/view/audio-list";
  13. import { followData, toggleFollow } from "/src/view/follow-practice";
  14. import { api_back } from "/src/helpers/communication";
  15. import MusicType from "./music-type";
  16. import ModeTypeMode from "../component/mode-type-mode";
  17. import { getQuery } from "/src/utils/queryString";
  18. import { storeData } from "/src/store";
  19. import TeacherTop from "../custom-plugins/guide-page/teacher-top";
  20. import StudentTop from "../custom-plugins/guide-page/student-top";
  21. import { HANDLE_WORK_ADD } from "../custom-plugins/work-index";
  22. import { browser } from "/src/utils";
  23. import store from "store";
  24. import "../component/the-modal-tip/index.module.less";
  25. import { metronomeData } from "../../helpers/metronome";
  26. import { toggleMusicSheet } from "/src/view/plugins/toggleMusicSheet";
  27. import useDrag from "/src/view/plugins/useDrag/index";
  28. import Dragbom from "/src/view/plugins/useDrag/dragbom";
  29. import { getGuidance, setGuidance } from "../custom-plugins/guide-page/api";
  30. import ModeView from "./modeView"
  31. import { smoothAnimationState } from "../view-detail/smoothAnimation"
  32. import { isMusicList, musicListShow } from "../component/the-music-list";
  33. /** 头部数据和方法 */
  34. export const headTopData = reactive({
  35. /** 模式 */
  36. modeType: "" as "init" | "show",
  37. /** 显示返回按钮 */
  38. showBack: true,
  39. /** 设置弹窗 */
  40. settingMode: false,
  41. /** 切换模式 */
  42. handleChangeModeType(value: "practise" | "follow" | "evaluating") {
  43. // 后台设置为不能评测
  44. if (value === "evaluating" && !state.enableEvaluation) return;
  45. // 打击乐&节奏练习不支持跟练模式
  46. if (value === "follow" && state.isPercussion) return;
  47. // 跟练模式,光标只有音符模式,无节拍模式
  48. if (value === "follow" && metronomeData.cursorMode === 2) {
  49. metronomeData.cursorMode = 1;
  50. }
  51. if (value === "practise") {
  52. // state.playIngSpeed = state.speed
  53. }
  54. if (value === "evaluating") {
  55. // 如果延迟检测资源还在加载中,给出提示
  56. if (!evaluatingData.jsonLoadDone) {
  57. evaluatingData.jsonLoading = true;
  58. state.audioDone && showToast("资源加载中,请稍后"); //音频资源加载完之后才提示
  59. return;
  60. }
  61. // 如果是pc端, 评测模式暂不可用
  62. if (state.platform === IPlatform.PC) {
  63. showConfirmDialog({
  64. className: "modalTip",
  65. title: "温馨提示",
  66. message: "该功能暂未开放,敬请期待!",
  67. showCancelButton: false,
  68. });
  69. return;
  70. }
  71. state.playIngSpeed = state.originSpeed;
  72. handleStartEvaluat();
  73. // 开发模式,把此处打开
  74. // state.modeType = "evaluating"
  75. // evaluatingData.rendered = true;
  76. // evaluatingData.soundEffectMode = true;
  77. } else if (value === "follow") {
  78. toggleFollow();
  79. }
  80. headTopData.modeType = "show";
  81. },
  82. });
  83. export const headData = reactive({
  84. speedShow: false,
  85. musicTypeShow: false,
  86. });
  87. export default defineComponent({
  88. name: "header-top",
  89. emits: ["close"],
  90. setup(props, { emit }) {
  91. const query = getQuery();
  92. // 是否显示引导
  93. const showGuide = ref(false);
  94. const showStudentGuide = ref(false);
  95. /** 设置按钮 */
  96. const settingBtn = computed(() => {
  97. // 音频播放中 禁用
  98. if (state.playState === "play") return { display: true, disabled: true };
  99. // 评测开始 禁用, 跟练开始 禁用
  100. if (evaluatingData.startBegin || followData.start) return { display: true, disabled: true };
  101. return {
  102. display: true,
  103. disabled: false,
  104. };
  105. });
  106. /** 转谱按钮 */
  107. const converBtn = computed(() => {
  108. // 音频播放中 禁用
  109. if (state.playState === "play") return { display: true, disabled: true };
  110. // 评测开始 禁用
  111. if (evaluatingData.startBegin || followData.start) return { display: true, disabled: true };
  112. return {
  113. disabled: false,
  114. display: true,
  115. };
  116. });
  117. /** 速度按钮 */
  118. const speedBtn = computed(() => {
  119. // 选择模式, 跟练模式 不显示
  120. if (headTopData.modeType !== "show" || state.modeType === "follow") return { display: false, disabled: true };
  121. // 评测模式, 音频播放中 禁用
  122. if (state.modeType === "evaluating" || state.playState === "play") return { display: true, disabled: true };
  123. return {
  124. disabled: false,
  125. display: true,
  126. };
  127. });
  128. /** 节拍器按钮 */
  129. const metronomeBtn = computed(() => {
  130. // 选择模式 不显示
  131. if (headTopData.modeType !== "show") return { display: false, disabled: true };
  132. // 音频播放中 禁用
  133. if (state.playState === "play") return { display: true, disabled: true };
  134. return {
  135. disabled: false,
  136. display: true,
  137. };
  138. });
  139. /** 指法按钮 */
  140. const fingeringBtn = computed(() => {
  141. // 后台设置不显示指法
  142. if (!state.isShowFingering) return { display: true, disabled: true };
  143. // 没有指法 选择模式 评测模式 跟练模式 不显示
  144. if (headTopData.modeType !== "show" || !state.fingeringInfo.name || ["evaluating", "follow"].includes(state.modeType)) return { display: false, disabled: true };
  145. // 音频播放中 禁用
  146. if (state.playState === "play") return { display: true, disabled: true };
  147. return {
  148. disabled: false,
  149. display: true,
  150. };
  151. });
  152. /** 摄像头按钮 */
  153. const cameraBtn = computed(() => {
  154. // 选择模式 不显示
  155. if (headTopData.modeType !== "show" || state.modeType !== "evaluating") return { display: false, disabled: true };
  156. // 音频播放中 禁用
  157. if (state.playState === "play") return { display: true, disabled: true };
  158. return {
  159. disabled: false,
  160. display: true,
  161. };
  162. });
  163. /** 选段按钮 */
  164. const selectBtn = computed(() => {
  165. // 选择模式 不显示
  166. if (headTopData.modeType !== "show" || ["evaluating", "follow"].includes(state.modeType)) return { display: false, disabled: true };
  167. // 音频播放中 禁用
  168. if (state.playState === "play") return { display: true, disabled: true };
  169. return {
  170. disabled: false,
  171. display: true,
  172. };
  173. });
  174. /** 原声按钮 */
  175. const originBtn = computed(() => {
  176. // 选择模式,跟练模式 不显示
  177. if (headTopData.modeType !== "show" || state.modeType === "follow") return { display: false, disabled: false };
  178. // 评测开始 禁用
  179. if (state.modeType === "evaluating") return { display: false, disabled: true };
  180. if (!state.isAppPlay) {
  181. if(state.playType === "play"){
  182. // 原声, 伴奏 少一个,就不能切换
  183. if (state.music && state.accompany) return { display: true, disabled: false };
  184. } else {
  185. let index = 0
  186. state.fanSong && index++
  187. state.banSong && index++
  188. state.mingSong && index++
  189. if(index > 1) {
  190. return { display: true, disabled: false };
  191. }
  192. }
  193. }
  194. return {
  195. disabled: true,
  196. display: true,
  197. };
  198. });
  199. /** 播放类型按钮 */
  200. const playTypeBtn = computed(() => {
  201. // 选择模式,跟练模式 不显示
  202. if (headTopData.modeType !== "show" || state.modeType === "follow") return { display: false, disabled: false };
  203. // 评测开始 禁用
  204. if (state.modeType === "evaluating") return { display: false, disabled: true };
  205. // 音频播放中 禁用
  206. if (state.playState === "play") return { display: true, disabled: true };
  207. if (!state.isAppPlay) {
  208. if(!state.isConcert){
  209. let index = 0
  210. state.fanSong && index++
  211. state.banSong && index++
  212. state.mingSong && index++
  213. if(index > 0) {
  214. return { display: true, disabled: false };
  215. }
  216. }
  217. }
  218. return {
  219. disabled: true,
  220. display: true,
  221. };
  222. })
  223. /** 模式切换按钮 */
  224. const toggleBtn = computed(() => {
  225. // 选择模式, url设置模式 不显示
  226. if (headTopData.modeType !== "show" || !headTopData.showBack) return { display: false, disabled: false };
  227. // 跟练开始, 评测开始 禁用
  228. if (followData.start || evaluatingData.startBegin) return { display: true, disabled: true };
  229. return {
  230. display: true,
  231. disabled: false,
  232. };
  233. });
  234. /** 播放按钮 */
  235. const playBtn = computed(() => {
  236. // 选择模式 不显示
  237. if (headTopData.modeType !== "show") return { display: false, disabled: false };
  238. // 评测模式 不显示,跟练模式 不显示
  239. if (["evaluating", "follow"].includes(state.modeType)) return { display: false, disabled: true };
  240. // midi音频未初始化完成不可点击
  241. if (state.isAppPlay && state.midiPlayIniting) return { display: true, disabled: true };
  242. return {
  243. display: true,
  244. disabled: false,
  245. };
  246. });
  247. /** 重播按钮 */
  248. const resetBtn = computed(() => {
  249. // 选择模式 不显示
  250. if (headTopData.modeType !== "show") return { display: false, disabled: false };
  251. // 评测模式 不显示,跟练模式 不显示
  252. if (["evaluating", "follow"].includes(state.modeType)) return { display: false, disabled: true };
  253. // 播放状态 不显示
  254. if (state.playState === "play") return { display: false, disabled: true };
  255. // 播放进度为0 不显示
  256. const currentTime = getAudioCurrentTime();
  257. // midi音频未初始化完成不可点击
  258. if (state.isAppPlay && state.midiPlayIniting) return { display: false, disabled: true };
  259. if (!currentTime) return { display: false, disabled: true };
  260. return {
  261. display: true,
  262. disabled: false,
  263. };
  264. });
  265. const isAllBtns = computed(() => {
  266. const flag = converBtn.value.display && speedBtn.value.display && selectBtn.value.display && originBtn.value.display && toggleBtn.value.display && showGuide.value;
  267. return flag;
  268. });
  269. const isAllBtnsStudent = computed(() => {
  270. const flag = converBtn.value.display && speedBtn.value.display && selectBtn.value.display && originBtn.value.display && toggleBtn.value.display && showStudentGuide.value;
  271. return flag;
  272. });
  273. const showGuideIndex = computed(() => {
  274. // 从课堂乐器学生端课件预览默认不显示会员
  275. if (storeData.user.vipMember || state.paymentType === "FREE" || query.showCourseMember === "true") {
  276. // 学生端
  277. return true;
  278. } else {
  279. // vip
  280. return false;
  281. }
  282. });
  283. const browInfo = browser();
  284. /** 返回 */
  285. const handleBack = () => {
  286. HANDLE_WORK_ADD();
  287. // 不在APP中,
  288. if (!storeData.isApp) {
  289. window.close();
  290. return;
  291. }
  292. if ((browInfo.iPhone || browInfo.ios) && query.workRecord) {
  293. setTimeout(() => {
  294. api_back();
  295. }, 550);
  296. return;
  297. }
  298. api_back();
  299. };
  300. /** 根据参数设置模式 */
  301. const getQueryModelSetModelType = () => {
  302. /** 作业模式 start, 如果为作业模式不处理,让作业模块处理 */
  303. if (query.workRecord) {
  304. return;
  305. }
  306. /** 作业模式 end */
  307. if (state.defaultModeType == 1) {
  308. headTopData.handleChangeModeType("practise");
  309. if (state.platform === IPlatform.PC || state.isPreView) {
  310. headTopData.showBack = false;
  311. }
  312. } else {
  313. if (query.modelType) {
  314. if (query.modelType === "practise") {
  315. headTopData.handleChangeModeType("practise");
  316. } else if (query.modelType === "evaluating") {
  317. headTopData.handleChangeModeType("evaluating");
  318. }
  319. headTopData.showBack = false;
  320. } else {
  321. setTimeout(() => {
  322. headTopData.modeType = "init";
  323. }, 500);
  324. }
  325. }
  326. };
  327. /** 课件播放 */
  328. const changePlay = (res: any) => {
  329. // console.log('监听上课页面message',res)
  330. if (res?.data?.api === "setPlayState") {
  331. togglePlay("paused", "courseware");
  332. }
  333. // 上课页面,按钮方向
  334. if (res?.data?.api === "imagePos") {
  335. if (res?.data.data) {
  336. state.playBtnDirection = res.data.data === "right" ? "right" : "left";
  337. // if (state.fingeringInfo.direction === "vertical" && state.setting.displayFingering) {
  338. // state.musicScoreBtnDirection = state.playBtnDirection === 'right' ? 'left' : 'right';
  339. // } else {
  340. // state.musicScoreBtnDirection = state.playBtnDirection;
  341. // }
  342. state.musicScoreBtnDirection = state.playBtnDirection;
  343. }
  344. }
  345. };
  346. const parentClassName = "settingBoxClass_drag";
  347. const userId = storeData.user?.id ? String(storeData.user?.id) : "";
  348. const positionInfo =
  349. state.platform !== IPlatform.PC
  350. ? {
  351. styleDrag: { value: null },
  352. }
  353. : useDrag([`${parentClassName} .top_drag`, `${parentClassName} .bom_drag`], parentClassName, toRef(headTopData, "settingMode"), userId);
  354. onMounted(() => {
  355. getQueryModelSetModelType();
  356. window.addEventListener("message", changePlay);
  357. if (state.platform === IPlatform.PC) {
  358. showGuide.value = true;
  359. } else {
  360. showStudentGuide.value = true;
  361. }
  362. });
  363. onUnmounted(() => {
  364. window.removeEventListener("message", changePlay);
  365. });
  366. // 设置改变触发
  367. watch(state.setting, () => {
  368. console.log(state.setting, "state.setting");
  369. store.set("musicscoresetting", state.setting);
  370. });
  371. // 获取引导页信息
  372. const getAllGuidance = async () => {
  373. let guideInfo: any = null;
  374. try {
  375. const res = await getGuidance({ guideTag: "guideInfo" });
  376. if (res.data) {
  377. guideInfo = JSON.parse(res.data?.guideValue) || null;
  378. } else {
  379. guideInfo = {};
  380. }
  381. state.guideInfo = guideInfo;
  382. } catch (e) {
  383. console.log(e);
  384. }
  385. };
  386. getAllGuidance();
  387. // 完成拖动弹窗引导页
  388. const handleGuide = async () => {
  389. state.guideInfo.teacherDrag = true;
  390. try {
  391. const res = await setGuidance({ guideTag: "guideInfo", guideValue: JSON.stringify(state.guideInfo) });
  392. } catch (e) {
  393. console.log(e);
  394. }
  395. };
  396. // 切换 演唱和演奏模式的时候处理
  397. function handlerRefreshPlayType() {
  398. // 妙极客的 曲子 时间是不变的,所以不做处理
  399. if( !state.isEvxml ) {
  400. // 重新计算state.times
  401. const { isOpenMetronome, isSingOpenMetronome } = state
  402. const { xmlMp3BeatFixTime } = metronomeData
  403. if(state.playType === "play"){
  404. if(isOpenMetronome && !isSingOpenMetronome){
  405. state.fixtime = state.fixtime + xmlMp3BeatFixTime
  406. } else if(!isOpenMetronome && isSingOpenMetronome){
  407. state.fixtime = state.fixtime - xmlMp3BeatFixTime
  408. }
  409. }else{
  410. if(isSingOpenMetronome && !isOpenMetronome){
  411. state.fixtime = state.fixtime + xmlMp3BeatFixTime
  412. } else if(!isSingOpenMetronome && isOpenMetronome){
  413. state.fixtime = state.fixtime - xmlMp3BeatFixTime
  414. }
  415. }
  416. const fixtime = state.fixtime
  417. state.times.map(item => {
  418. if(state.playType === "play"){
  419. if(isOpenMetronome && !isSingOpenMetronome){
  420. item.time = item.time + xmlMp3BeatFixTime
  421. item.endtime = item.endtime + xmlMp3BeatFixTime
  422. item.fixtime = fixtime
  423. } else if(!isOpenMetronome && isSingOpenMetronome){
  424. item.time = item.time - xmlMp3BeatFixTime
  425. item.endtime = item.endtime - xmlMp3BeatFixTime
  426. item.fixtime = fixtime
  427. }
  428. }else{
  429. if(isSingOpenMetronome && !isOpenMetronome){
  430. item.time = item.time + xmlMp3BeatFixTime
  431. item.endtime = item.endtime + xmlMp3BeatFixTime
  432. item.fixtime = fixtime
  433. } else if(!isSingOpenMetronome && isOpenMetronome){
  434. item.time = item.time - xmlMp3BeatFixTime
  435. item.endtime = item.endtime - xmlMp3BeatFixTime
  436. item.fixtime = fixtime
  437. }
  438. }
  439. })
  440. try {
  441. metronomeData.metro.calculation(state.times);
  442. } catch (error) {}
  443. console.log("重新之后的times", state.times, fixtime)
  444. }
  445. // 重置播放状态
  446. handleRessetState()
  447. // 隐藏重播按钮
  448. resetBtn.value.display = false
  449. }
  450. return () => (
  451. <>
  452. <div
  453. class={[styles.headerTop]}
  454. onClick={(e: Event) => {
  455. e.stopPropagation();
  456. if (state.platform === IPlatform.PC) {
  457. // 显示隐藏菜单
  458. window.parent.postMessage(
  459. {
  460. api: "onAttendToggleMenu",
  461. },
  462. "*"
  463. );
  464. }
  465. }}
  466. >
  467. {/* 返回和标题 */}
  468. <div class={styles.headTopLeftBox}>
  469. <img src={iconBack} class={['headTopBackBtn', styles.img, !headTopData.showBack && styles.hidenBack]} onClick={handleBack} />
  470. {
  471. state.modeType === "practise" && smoothAnimationState.isShow.value ?
  472. <div class={styles.title} onClick={()=>{
  473. isMusicList.value && (musicListShow.value = true)
  474. }}>
  475. <NoticeBar
  476. text={state.examSongName}
  477. background="none"
  478. />
  479. </div> :
  480. <img src={listImg} class={[styles.img]} onClick={()=>{
  481. isMusicList.value && (musicListShow.value = true)
  482. }} />
  483. }
  484. </div>
  485. {/* 模式切换 */}
  486. <div
  487. id={state.platform === IPlatform.PC ? "teacherTop-0" : "studnetT-0"}
  488. style={{ display: toggleBtn.value.display ? "" : "none" }}
  489. class={[styles.modeChangeBox, toggleBtn.value.disabled && styles.disabled]}
  490. onClick={() => {
  491. handleRessetState();
  492. headTopData.modeType = "init";
  493. }}
  494. >
  495. <img class={styles.img} src={iconMode} />
  496. <div class={styles.title}>{state.modeType==="practise" ? '练习模式' : state.modeType==="follow" ? "跟练模式" : state.modeType==="evaluating" ? "评测模式" : ""}</div>
  497. </div>
  498. {/* 功能按钮 */}
  499. <div
  500. class={[styles.headRight]}
  501. onClick={(e: Event) => {
  502. e.stopPropagation();
  503. }}
  504. >
  505. {/* 一行谱模式,暂不支持节拍指针 */}
  506. {/* {!state.isSingleLine ? (
  507. <div
  508. class={[styles.btn, state.platform === IPlatform.PC ? styles.pcBtn : ""]}
  509. onClick={() => {
  510. // 切换光标模式
  511. let mode = metronomeData.cursorMode;
  512. if (["follow"].includes(state.modeType)) {
  513. mode = metronomeData.cursorMode === 1 ? 3 : 1;
  514. } else {
  515. mode = metronomeData.cursorMode === 3 ? 1 : metronomeData.cursorMode + 1;
  516. }
  517. metronomeData.cursorMode = mode;
  518. }}
  519. >
  520. <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" : "")} />
  521. <span class={styles.iconContent}>
  522. {metronomeData.cursorMode === 1 ? "音符指针" : metronomeData.cursorMode === 2 ? "节拍指针" : metronomeData.cursorMode === 3 ? "关闭指针" : ""}
  523. {metronomeData.cursorTips && (
  524. <>
  525. <i class={styles.arrowIcon}></i>
  526. <div class={[styles["botton-tips"], metronomeData.cursorMode === 3 ? styles.tipSpec : ""]}>{metronomeData.cursorTips}</div>
  527. </>
  528. )}
  529. </span>
  530. </div>
  531. ) : null} */}
  532. <div
  533. style={{ display: playTypeBtn.value.display ? "" : "none" }}
  534. class={[styles.btn, playTypeBtn.value.disabled && styles.disabled]}
  535. onClick={() => {
  536. if(state.playType === "play"){
  537. state.playType = "sing"
  538. state.playSource = state.fanSong?"music":state.banSong?"background":"mingSong"
  539. } else {
  540. state.playType = "play"
  541. state.playSource = state.music?"music":"background"
  542. }
  543. handlerRefreshPlayType()
  544. }}
  545. >
  546. <img style={{ display: state.playType === "play" ? "" : "none" }} class={styles.iconBtn} src={headImg(`perform.png`)} />
  547. <img style={{ display: state.playType === "play" ? "none" : "" }} class={styles.iconBtn} src={headImg(`sing.png`)} />
  548. <span>{state.playType === "play" ? "演奏" : "演唱"}</span>
  549. </div>
  550. <div
  551. id={state.platform === IPlatform.PC ? "teacherTop-1" : "studnetT-1"}
  552. style={{ display: originBtn.value.display ? "" : "none" }}
  553. class={[styles.btn, originBtn.value.disabled && styles.disabled]}
  554. onClick={() => {
  555. if(state.playType === 'play'){
  556. state.playSource = state.playSource === "music" ? "background" : "music";
  557. }else{
  558. if(state.playSource === "music"){
  559. state.playSource = state.banSong ? "background" :"mingSong"
  560. }else if(state.playSource === "background"){
  561. state.playSource = state.mingSong ? "mingSong" :"music"
  562. }else {
  563. state.playSource = state.fanSong ? "music" :"background"
  564. }
  565. }
  566. }}
  567. >
  568. <img style={{ display: state.playSource === "music" ? "" : "none" }} class={styles.iconBtn} src={state.playType === 'play'?headImg(`music.png`):headImg(`music1.png`)} />
  569. <img style={{ display: state.playSource === "background" ? "" : "none" }} class={styles.iconBtn} src={state.playType === 'play'?headImg(`background.png`):headImg(`background1.png`)} />
  570. <img style={{ display: state.playSource === "mingSong" ? "" : "none" }} class={styles.iconBtn} src={headImg(`mingsong.png`)} />
  571. <span>{state.playSource === "music" ? (state.playType ==="play" ? "原声" : "范唱") : state.playSource === "background" ? (state.playType ==="play" ? "伴奏" : "伴唱") : "唱名"}</span>
  572. </div>
  573. <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()}>
  574. <img style={{ display: state.section.length === 0 ? "" : "none" }} class={styles.iconBtn} src={headImg(`section0.png`)} />
  575. <img style={{ display: state.section.length === 1 ? "" : "none" }} class={styles.iconBtn} src={headImg(`section1.png`)} />
  576. <img style={{ display: state.section.length === 2 ? "" : "none" }} class={styles.iconBtn} src={headImg(`section2.png`)} />
  577. <span>选段</span>
  578. </div>
  579. {state.modeType !== "evaluating" && (
  580. <>
  581. <div
  582. style={{ display: metronomeBtn.value.display ? "" : "none" }}
  583. class={[styles.btn, styles.metronomeBtn, metronomeBtn.value.disabled && styles.disabled]}
  584. onClick={async () => {
  585. headData.speedShow = !headData.speedShow;
  586. }}
  587. >
  588. <img style={{ display: metronomeData.disable ? "block" : "none" }} class={styles.iconBtn} src={headImg("tickon.png")} />
  589. <img style={{ display: !metronomeData.disable ? "block" : "none" }} class={styles.iconBtn} src={headImg("tickoff.png")} />
  590. <span style={{ whiteSpace: "nowrap" }}>节拍</span>
  591. <div class={styles.speedCon}>
  592. <img src={headImg("speed.png")} />
  593. <div>{state.speed}</div>
  594. </div>
  595. </div>
  596. {
  597. <Popup v-model:show={headData.speedShow} class="popup-custom van-scale center-closeBtn settingBoxClass_drag" transition="van-scale" teleport="body" style={positionInfo.styleDrag.value} overlay-style={{background:'rgba(0, 0, 0, 0.3)'}}>
  598. <Speed />
  599. {state.platform === IPlatform.PC && <Dragbom showGuide={!state.guideInfo?.teacherDrag} onGuideDone={handleGuide} />}
  600. </Popup>
  601. }
  602. </>
  603. )}
  604. {/* {state.enableNotation ? (
  605. <Popover trigger="manual" v-model:show={headData.musicTypeShow} class={state.platform === IPlatform.PC && styles.pcTransPop} placement={state.platform === IPlatform.PC ? "top-end" : "bottom-end"} overlay={false} offset={state.platform === IPlatform.PC ? [0, 40] : [0, 8]}>
  606. {{
  607. reference: () => (
  608. <div
  609. id={state.platform === IPlatform.PC ? "teacherTop-5" : "studnetT-5"}
  610. style={{ display: converBtn.value.display ? "" : "none" }}
  611. class={[styles.btn, converBtn.value.disabled && styles.disabled]}
  612. onClick={(e: Event) => {
  613. e.stopPropagation();
  614. headData.musicTypeShow = !headData.musicTypeShow;
  615. }}
  616. >
  617. <img class={styles.iconBtn} src={headImg("icon_zhuanpu.svg")} />
  618. <span>{state.musicRenderType === "staff" ? "转简谱" : "转五线谱"}</span>
  619. </div>
  620. ),
  621. default: () => <MusicType />,
  622. }}
  623. </Popover>
  624. ) : null} */}
  625. {state.musicRendered && !query.lessonTrainingId && !query.questionId && state.isConcert && (
  626. <div
  627. class={[styles.btn, state.playState === "play" && fingeringBtn.value.disabled && styles.disabled]}
  628. onClick={() => {
  629. toggleMusicSheet.toggle(true);
  630. }}
  631. >
  632. <img class={styles.iconBtn} src={headImg(`shenggui.png`)} />
  633. <span>声轨</span>
  634. </div>
  635. )}
  636. <div id={state.platform === IPlatform.PC ? "teacherTop-6" : "studnetT-6"} style={{ display: settingBtn.value.display ? "" : "none" }} class={[styles.btn, settingBtn.value.disabled && styles.disabled]} onClick={() => (headTopData.settingMode = true)}>
  637. <img class={styles.iconBtn} src={headImg("icon_menu.png")} />
  638. <span>设置</span>
  639. </div>
  640. </div>
  641. </div>
  642. {/* 播放按钮 */}
  643. <div
  644. id="studnetT-7"
  645. style={{ display: playBtn.value.display ? "" : "none" }}
  646. class={[
  647. styles.playBtn,
  648. playBtn.value.disabled && styles.disabled,
  649. state.platform === IPlatform.PC && state.musicScoreBtnDirection === "left" ? styles.playLeftButton : state.platform === IPlatform.PC && state.musicScoreBtnDirection === "right" ? styles.playRightButton : "",
  650. ]}
  651. onClick={() => togglePlay()}
  652. >
  653. <div class={styles.btnWrap}>
  654. <img style={{ display: state.playState === "play" ? "none" : "" }} class={styles.iconBtn} src={headImg("icon_play.png")} />
  655. <img style={{ display: state.playState === "play" ? "" : "none" }} class={styles.iconBtn} src={headImg("icon_pause.png")} />
  656. <Circle style={{ opacity: state.playState === "play" ? 1 : 0 }} class={styles.progress} stroke-width={80} currentRate={state.playProgress} rate={100} color="#FFED78" layer-color="rgba(0,0,0,0)" />
  657. </div>
  658. </div>
  659. {/* 重播按钮 */}
  660. <div
  661. id="tips-step-9"
  662. style={{ display: resetBtn.value.display ? "" : "none" }}
  663. class={[
  664. styles.resetBtn,
  665. resetBtn.value.disabled && styles.disabled,
  666. state.platform === IPlatform.PC && state.musicScoreBtnDirection === "left" ? styles.pauseLeftButton : state.platform === IPlatform.PC && state.musicScoreBtnDirection === "right" ? styles.pauseRightButton : "",
  667. ]}
  668. onClick={() => handleResetPlay()}
  669. >
  670. <img class={styles.iconBtn} src={headImg("icon_reset.png")} />
  671. </div>
  672. <Popup v-model:show={headTopData.settingMode} class="popup-custom van-scale center-closeBtn settingBoxClass_drag" transition="van-scale" teleport="body" style={positionInfo.styleDrag.value} overlay-style={{background:'rgba(0, 0, 0, 0.3)'}}>
  673. <Settting />
  674. {state.platform === IPlatform.PC && <Dragbom showGuide={!state.guideInfo?.teacherDrag} onGuideDone={handleGuide} />}
  675. </Popup>
  676. {/* 模式切换 */}
  677. {/* <ModeTypeMode /> */}
  678. <ModeView></ModeView>
  679. {/* isAllBtns */}
  680. {isAllBtns.value && !query.isCbs && showGuideIndex.value && <TeacherTop></TeacherTop>}
  681. {isAllBtnsStudent.value && !query.isCbs && showGuideIndex.value && <StudentTop></StudentTop>}
  682. </>
  683. );
  684. },
  685. });