index.tsx 24 KB

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