index.tsx 25 KB

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