index.tsx 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164
  1. import { Transition, computed, defineComponent, onMounted, onUnmounted, reactive, ref, watch, toRef, ComputedRef, nextTick, defineAsyncComponent } 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, IPlayState, refreshMusicSvg, EnumMusicRenderType } from "/src/state";
  12. import { audioData, 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, resetSection } 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. import { EvaluatingDriver, FollowDriver, PractiseDriver } from "../custom-plugins/guide-driver";
  34. import { fingerRef } from "/src/page-instrument/view-detail/index"
  35. import WorkHomePop from "./workHomePop";
  36. import { handleLoadBeatMusic } from "/src/view/audio-list"
  37. const ModeView = defineAsyncComponent(() =>
  38. import('./modeView')
  39. )
  40. /** 头部数据和方法 */
  41. export const headTopData = reactive({
  42. /** 模式 */
  43. modeType: "" as "init" | "show",
  44. /** 显示返回按钮 */
  45. showBack: true,
  46. /** 设置弹窗 */
  47. settingMode: false,
  48. /* 节奏律动 */
  49. rhythmMode: false,
  50. // 节奏律动方向
  51. rhythmModeDirection: computed(()=> state.fingeringInfo.direction === "transverse" ? "vertical" : "transverse"),
  52. /** 切换模式 */
  53. handleChangeModeType(value: "practise" | "follow" | "evaluating") {
  54. // 后台设置为不能评测
  55. if (value === "evaluating" && !state.enableEvaluation) return;
  56. // 打击乐&节奏练习不支持跟练模式
  57. if (value === "follow" && state.isPercussion) return;
  58. // 跟练模式,光标只有音符模式,无节拍模式
  59. if (value === "follow" && metronomeData.cursorMode === 2) {
  60. metronomeData.cursorMode = 1;
  61. }
  62. if (value === "practise") {
  63. // 切回当前的时值
  64. const isModeChange = modeChangeHandleTimes("play", "music")
  65. // 没有切换的时候 不处理下面的
  66. if (isModeChange) {
  67. try {
  68. metronomeData.metro.calculation(state.times);
  69. } catch (error) {}
  70. console.log("重新之后的times", state.times, state.fixtime);
  71. }
  72. // state.playIngSpeed = state.speed
  73. }
  74. if (value === "evaluating") {
  75. // 如果延迟检测资源还在加载中,给出提示
  76. if (!evaluatingData.jsonLoadDone) {
  77. evaluatingData.jsonLoading = true;
  78. state.audioDone && showToast("资源加载中,请稍后"); //音频资源加载完之后才提示
  79. return;
  80. }
  81. // 如果是pc端, 评测模式暂不可用
  82. if (state.platform === IPlatform.PC) {
  83. showConfirmDialog({
  84. className: "modalTip",
  85. title: "温馨提示",
  86. message: "该功能暂未开放,敬请期待!",
  87. showCancelButton: false,
  88. });
  89. return;
  90. }
  91. // 评测模式,只有一行谱模式
  92. // if (!state.isSingleLine) {
  93. // state.isSingleLine = true;
  94. // refreshMusicSvg();
  95. // }
  96. /* 当前是唱名的模式 */
  97. if(state.playSource === "mingSong") {
  98. const isModeChange = modeChangeHandleTimes("play","mingSong","play","music")
  99. // 没有切换的时候 不处理下面的
  100. if (isModeChange) {
  101. try {
  102. metronomeData.metro.calculation(state.times);
  103. } catch (error) {}
  104. console.log("重新之后的times", state.times, state.fixtime);
  105. }
  106. }
  107. // 关闭节奏律动
  108. headTopData.rhythmMode = false
  109. smoothAnimationState.isShow.value = false; // 隐藏旋律线
  110. state.playIngSpeed = state.originSpeed;
  111. handleStartEvaluat();
  112. // 开发模式,把此处打开
  113. // state.modeType = "evaluating";
  114. // evaluatingData.rendered = true;
  115. // evaluatingData.soundEffectMode = true;
  116. } else if (value === "follow") {
  117. // 关闭节奏律动
  118. headTopData.rhythmMode = false
  119. // 跟练模式,只有一行谱模式
  120. if (!state.isSingleLine) {
  121. state.isSingleLine = true;
  122. refreshMusicSvg();
  123. }
  124. smoothAnimationState.isShow.value = false;
  125. toggleFollow();
  126. }
  127. headTopData.modeType = "show";
  128. },
  129. // 改变模式之前的状态
  130. oldPlayType: "play",
  131. // 记录切换模式前的状态
  132. oldModeType: "practise" as "practise" | "follow" | "evaluating",
  133. // 作业未完成弹窗
  134. workHomeNoDone: false,
  135. });
  136. export const headData = reactive({
  137. speedShow: false,
  138. musicTypeShow: false,
  139. });
  140. let resetBtn: ComputedRef<{
  141. display: boolean;
  142. disabled: boolean;
  143. }>;
  144. // 点击切换的时候才触发提醒
  145. let isClickMode = false;
  146. /**
  147. * 处理模式切换
  148. * @param oldPlayType 没改变之前的播放模式
  149. * @param oldPlaySource 没改变之前的播放类型
  150. * @param isforceReset 是否强制刷新播放状态 模式times时值改变时候也刷新
  151. */
  152. export async function handlerModeChange(oldPlayType: "play" | "sing", oldPlaySource: IPlayState, isforceReset?: boolean) {
  153. const isModeChange = modeChangeHandleTimes(oldPlayType, oldPlaySource);
  154. // 没有切换的时候 不处理下面的
  155. if (isModeChange) {
  156. try {
  157. metronomeData.metro.calculation(state.times);
  158. } catch (error) {}
  159. console.log("重新之后的times", state.times, state.fixtime);
  160. }
  161. if (isModeChange || isforceReset) {
  162. // 重置播放状态
  163. handleRessetState();
  164. // 隐藏重播按钮
  165. resetBtn && (resetBtn.value.display = false);
  166. // 如果是作业模式,切成场景(演奏、演唱切换)需要重新设置作业选段和速度
  167. if (getQuery().workRecord) {
  168. resetSection();
  169. }
  170. }
  171. // 节拍器音频加载
  172. await handleLoadBeatMusic()
  173. // 当模式改变的时候 放在这里是因为需要等谱面加载完成之后再提示(点击按钮模式切换才提示)
  174. if (isClickMode) {
  175. showToast({
  176. message: state.playType === "play" ? "已切换为演奏场景" : "已切换为演唱场景",
  177. position: "top",
  178. className: "selectionToast",
  179. });
  180. isClickMode = false;
  181. }
  182. }
  183. // 模式切换之后重新给times赋值
  184. function modeChangeHandleTimes(oldPlayType: "play" | "sing", oldPlaySource: IPlayState, nowPlayType?:"play" | "sing", nowPlaySource?: IPlayState) {
  185. const playType = nowPlayType || state.playType;
  186. const playSource = nowPlaySource || state.playSource;
  187. const { notBeatFixtime, xmlMp3BeatFixTime, difftime } = state.times[0];
  188. const { isOpenMetronome, isSingOpenMetronome } = state;
  189. // 因为演奏加了唱名,所以往跟练模式切换和评测模式切换的时候,刷新谱面的时候需要更新时值,这时候调用handleRessetState 会回到练习模式,这里是
  190. if(state.modeType === "follow" || state.modeType === "evaluating") {
  191. return false
  192. }
  193. // 当相同时候也不处理
  194. if(oldPlayType === playType && oldPlaySource === playSource) {
  195. return false
  196. }
  197. // 原声向伴奏和伴奏向原声不处理 范唱向伴唱和伴唱向范唱切不处理
  198. if((oldPlaySource==="music"&&playSource==="background")||(oldPlaySource==="background"&&playSource==="music")){
  199. return false
  200. }
  201. // 唱名到唱名时候不处理
  202. if(oldPlaySource === "mingSong" && playSource === "mingSong"){
  203. return false
  204. }
  205. // 原生伴奏向范唱伴唱,范唱伴唱向原生伴奏时候,isSingOpenMetronome和isOpenMetronome相等时候不处理
  206. if(["music","background"].includes(oldPlaySource)&&["music","background"].includes(playSource)&&isOpenMetronome===isSingOpenMetronome){
  207. return false
  208. }
  209. // 当切为 原生伴奏,或者范唱伴唱 时候
  210. if(playSource==="music" || playSource ==="background"){
  211. if(playType === "play"){
  212. // 有节拍器
  213. if (isOpenMetronome) {
  214. state.fixtime = notBeatFixtime + xmlMp3BeatFixTime;
  215. state.times.map((item) => {
  216. item.time = item.notBeatTime + xmlMp3BeatFixTime;
  217. item.endtime = item.notBeatEndTime + xmlMp3BeatFixTime;
  218. item.fixtime = notBeatFixtime + xmlMp3BeatFixTime;
  219. });
  220. return true;
  221. } else {
  222. state.fixtime = notBeatFixtime;
  223. state.times.map((item) => {
  224. item.time = item.notBeatTime;
  225. item.endtime = item.notBeatEndTime;
  226. item.fixtime = notBeatFixtime;
  227. });
  228. return true;
  229. }
  230. }
  231. if(playType==="sing"){
  232. // 有节拍器
  233. if (isSingOpenMetronome) {
  234. state.fixtime = notBeatFixtime + xmlMp3BeatFixTime;
  235. state.times.map((item) => {
  236. item.time = item.notBeatTime + xmlMp3BeatFixTime;
  237. item.endtime = item.notBeatEndTime + xmlMp3BeatFixTime;
  238. item.fixtime = notBeatFixtime + xmlMp3BeatFixTime;
  239. });
  240. return true;
  241. } else {
  242. state.fixtime = notBeatFixtime;
  243. state.times.map((item) => {
  244. item.time = item.notBeatTime;
  245. item.endtime = item.notBeatEndTime;
  246. item.fixtime = notBeatFixtime;
  247. });
  248. return true;
  249. }
  250. }
  251. }
  252. // 当切为唱名时候
  253. if(playSource==="mingSong"){
  254. // 唱名文件也要加上弱起时间 他们制作曲子加了弱起时间 注意这修改了之后给总控平台的时值也需要改
  255. state.fixtime = difftime;
  256. state.times.map((item) => {
  257. item.time = item.xmlNoteTime + difftime;
  258. item.endtime = item.xmlNoteEndTime + difftime;
  259. item.fixtime = difftime;
  260. });
  261. return true;
  262. }
  263. return false;
  264. }
  265. export default defineComponent({
  266. name: "header-top",
  267. emits: ["close"],
  268. setup(props, { emit }) {
  269. const query = getQuery();
  270. // 是否显示引导
  271. const showGuide = ref(false);
  272. const showStudentGuide = ref(false);
  273. const showWebGuide = ref(true);
  274. let displayFingeringCache = false; // 指法缓存
  275. /** 设置按钮 */
  276. const settingBtn = computed(() => {
  277. // 音频播放中 禁用
  278. if (state.playState === "play") return { display: true, disabled: true };
  279. // 评测开始 禁用, 跟练开始 禁用
  280. if (evaluatingData.startBegin || followData.start) return { display: true, disabled: true };
  281. return {
  282. display: true,
  283. disabled: false,
  284. };
  285. });
  286. /** 转谱按钮 */
  287. const converBtn = computed(() => {
  288. // 音频播放中 禁用
  289. if (state.playState === "play") return { display: true, disabled: true };
  290. // 评测开始 禁用
  291. if (evaluatingData.startBegin || followData.start) return { display: true, disabled: true };
  292. return {
  293. disabled: false,
  294. display: true,
  295. };
  296. });
  297. /** 速度按钮 */
  298. const speedBtn = computed(() => {
  299. // 选择模式, 跟练模式 不显示
  300. //if (headTopData.modeType !== "show" || state.modeType === "follow") return { display: false, disabled: true };
  301. if (state.modeType === "follow") return { display: false, disabled: true };
  302. // 评测模式, 音频播放中 禁用
  303. if (state.modeType === "evaluating" || state.playState === "play") return { display: true, disabled: true };
  304. return {
  305. disabled: false,
  306. display: true,
  307. };
  308. });
  309. /** 节拍器按钮 */
  310. const metronomeBtn = computed(() => {
  311. // 选择模式 不显示
  312. //if (headTopData.modeType !== "show") return { display: false, disabled: true };
  313. // 音频播放中 禁用
  314. if (state.playState === "play") return { display: true, disabled: true };
  315. return {
  316. disabled: false,
  317. display: true,
  318. };
  319. });
  320. /** 指法按钮 */
  321. const fingeringBtn = computed(() => {
  322. // 后台设置不显示指法
  323. if (!state.isShowFingering) return { display: true, disabled: true };
  324. // 没有指法 选择模式 评测模式 跟练模式 不显示
  325. //if (headTopData.modeType !== "show" || !state.fingeringInfo.name || ["evaluating", "follow"].includes(state.modeType)) return { display: false, disabled: true };
  326. if (!state.fingeringInfo.name || ["evaluating", "follow"].includes(state.modeType)) return { display: false, disabled: true };
  327. // 音频播放中 禁用
  328. if (state.playState === "play") return { display: true, disabled: true };
  329. return {
  330. disabled: false,
  331. display: true,
  332. };
  333. });
  334. /** 摄像头按钮 */
  335. const cameraBtn = computed(() => {
  336. // 选择模式 不显示
  337. if (headTopData.modeType !== "show" || state.modeType !== "evaluating") return { display: false, disabled: true };
  338. // 音频播放中 禁用
  339. if (state.playState === "play") return { display: true, disabled: true };
  340. return {
  341. disabled: false,
  342. display: true,
  343. };
  344. });
  345. /** 选段按钮 */
  346. const selectBtn = computed(() => {
  347. // 选择模式 不显示
  348. //if (headTopData.modeType !== "show" || ["follow"].includes(state.modeType)) return { display: false, disabled: true };
  349. if (["follow"].includes(state.modeType)) return { display: false, disabled: true };
  350. // 音频播放中 禁用
  351. if (state.playState === "play" || query.workRecord) return { display: true, disabled: true };
  352. return {
  353. disabled: false,
  354. display: true,
  355. };
  356. });
  357. /** 原声按钮 */
  358. const originBtn = computed(() => {
  359. // 没有音源不显示
  360. if (state.noMusicSource) return { display: false, disabled: false };
  361. // 选择模式,跟练模式 不显示
  362. //if (headTopData.modeType !== "show" || state.modeType === "follow") return { display: false, disabled: false };
  363. if (state.modeType === "follow") return { display: false, disabled: false };
  364. // 评测开始 禁用
  365. if (state.modeType === "evaluating") return { display: false, disabled: true };
  366. // 总谱渲染在播放过程中 不能切换
  367. if(state.isCombineRender && state.playState === "play") return { display: true, disabled: true }
  368. if (!state.isAppPlay) {
  369. // 播放过程中不能切换
  370. if (state.playState === "play") {
  371. return { display: true, disabled: true };
  372. }
  373. if (state.playType === "play") {
  374. let index = 0;
  375. state.music && index++;
  376. state.accompany && index++;
  377. state.mingSong && index++;
  378. if (index > 1) {
  379. return { display: true, disabled: false };
  380. }
  381. } else {
  382. // 范唱
  383. let index = 0;
  384. state.fanSong && index++;
  385. state.banSong && index++;
  386. state.mingSong && index++;
  387. if (index > 1) {
  388. return { display: true, disabled: false };
  389. }
  390. }
  391. }
  392. return {
  393. disabled: true,
  394. display: true,
  395. };
  396. });
  397. /** 播放类型按钮 */
  398. const playTypeBtn = computed(() => {
  399. // 选择模式,跟练模式,评测模式 不显示
  400. //if (headTopData.modeType !== "show" || state.modeType === "follow" || state.modeType === "evaluating" || query.workRecord) return { display: false, disabled: false };
  401. if (state.modeType === "follow" || state.modeType === "evaluating" || query.workRecord) return { display: false, disabled: false };
  402. if (!state.isAppPlay) {
  403. let index = 0;
  404. state.music && index++;
  405. state.accompany && index++;
  406. let songIndex = 0;
  407. state.fanSong && songIndex++;
  408. state.banSong && songIndex++;
  409. state.mingSong && songIndex++;
  410. // 演唱和演奏 都有数据的时间不禁用
  411. if (songIndex > 0 && index > 0) {
  412. // 音频播放中 禁用
  413. if (state.playState === "play") {
  414. return { display: true, disabled: true };
  415. }
  416. return { display: true, disabled: false };
  417. }
  418. }
  419. return {
  420. disabled: false,
  421. display: false,
  422. };
  423. });
  424. /** 模式切换按钮 */
  425. const toggleBtn = computed(() => {
  426. // 上课页面不显示,作业模式也不显示,嵌入课件页面也不显示
  427. if(state.isAttendClass || query.workRecord || query.iscurseplay == "play") return { display: false, disabled: false };
  428. // 老师端,打击乐&节奏练习不显示
  429. if (state.isPercussion && state.platform === IPlatform.PC) return { display: false, disabled: false };
  430. if(state.isCombineRender) return { display: false, disabled: false };
  431. // 没有音源不显示
  432. if (state.noMusicSource) return { display: false, disabled: false };
  433. // 不是演奏模式 影藏
  434. if (state.playType !== "play") return { display: false, disabled: false };
  435. // 选择模式, url设置模式 不显示
  436. if (headTopData.modeType !== "show" || !headTopData.showBack) return { display: false, disabled: false };
  437. // 跟练开始, 评测开始 播放开始 隐藏
  438. if (state.playState == "play" || followData.start || evaluatingData.startBegin) return { display: false, disabled: false };
  439. return {
  440. display: true,
  441. disabled: false,
  442. };
  443. });
  444. /** 播放按钮 */
  445. const playBtn = computed(() => {
  446. // 没有音源不显示
  447. if (state.noMusicSource) return { display: false, disabled: false };
  448. // 选择模式 不显示
  449. if (headTopData.modeType !== "show") return { display: false, disabled: false };
  450. // 评测模式 不显示,跟练模式 不显示
  451. if (["evaluating", "follow"].includes(state.modeType)) return { display: false, disabled: true };
  452. // midi音频未初始化完成不可点击
  453. if (state.isAppPlay && state.midiPlayIniting) return { display: true, disabled: true };
  454. return {
  455. display: true,
  456. disabled: false,
  457. };
  458. });
  459. /** 节奏律动 */
  460. const rhythmBtn = computed(() => {
  461. if(state.isCombineRender) return { display: false, disabled: false };
  462. // 跟练和评测显示
  463. if (["evaluating", "follow"].includes(state.modeType)) return { display: false, disabled: false, playIng: false };
  464. // 播放过程中不让切换
  465. if (state.playState == "play") {
  466. if(headTopData.rhythmMode) {
  467. return {
  468. display: true,
  469. disabled: true,
  470. playIng: true
  471. }
  472. }else{
  473. return {
  474. display: true,
  475. disabled: true,
  476. playIng: false
  477. }
  478. }
  479. };
  480. return {
  481. display: true,
  482. disabled: false,
  483. playIng: false
  484. };
  485. });
  486. /** 重播按钮 */
  487. resetBtn = computed(() => {
  488. // 没有音源不显示
  489. if (state.noMusicSource) return { display: false, disabled: false };
  490. // 选择模式 不显示
  491. if (headTopData.modeType !== "show") return { display: false, disabled: false };
  492. // 评测模式 不显示,跟练模式 不显示
  493. if (["evaluating", "follow"].includes(state.modeType)) return { display: false, disabled: true };
  494. // 播放状态 不显示
  495. if (state.playState === "play") return { display: false, disabled: true };
  496. // 播放进度为0 不显示
  497. const currentTime = getAudioCurrentTime();
  498. // midi音频未初始化完成不可点击
  499. if (state.isAppPlay && state.midiPlayIniting) return { display: false, disabled: true };
  500. if (!currentTime) return { display: false, disabled: true };
  501. return {
  502. display: true,
  503. disabled: false,
  504. };
  505. });
  506. const isAllBtns = computed(() => {
  507. const flag = converBtn.value.display && speedBtn.value.display && selectBtn.value.display && originBtn.value.display && toggleBtn.value.display && showGuide.value;
  508. return flag;
  509. });
  510. const isAllBtnsStudent = computed(() => {
  511. const flag = converBtn.value.display && speedBtn.value.display && selectBtn.value.display && originBtn.value.display && toggleBtn.value.display && showStudentGuide.value;
  512. return flag;
  513. });
  514. const showGuideIndex = computed(() => {
  515. // 从课堂乐器学生端课件预览默认不显示会员
  516. if (storeData.user.vipMember || state.paymentType === "FREE" || query.showCourseMember === "true") {
  517. // 学生端
  518. return true;
  519. } else {
  520. // vip
  521. return false;
  522. }
  523. });
  524. const browInfo = browser();
  525. // 返回校验, 如果是作业模式,并且作业没有达标需要给出弹窗提示
  526. const checkBack = () => {
  527. if (query.workRecord) {
  528. console.log('作业是否达标',state.isWorkDone)
  529. }
  530. if (query.workRecord && !state.isWorkDone) {
  531. headTopData.workHomeNoDone = true
  532. } else {
  533. handleBack()
  534. }
  535. }
  536. /** 返回 */
  537. const handleBack = () => {
  538. HANDLE_WORK_ADD();
  539. // 不在APP中,
  540. if (!storeData.isApp) {
  541. window.parent.postMessage(
  542. {
  543. api: "back",
  544. },
  545. "*"
  546. );
  547. window.close();
  548. return;
  549. }
  550. if ((browInfo.iPhone || browInfo.ios) && query.workRecord) {
  551. setTimeout(() => {
  552. api_back();
  553. }, 550);
  554. return;
  555. }
  556. api_back();
  557. };
  558. const handleResult = (type: any) => {
  559. if (type) {
  560. headTopData.workHomeNoDone = false
  561. } else {
  562. headTopData.workHomeNoDone = false
  563. handleBack()
  564. }
  565. }
  566. /** 根据参数设置模式 */
  567. const getQueryModelSetModelType = () => {
  568. /** 作业模式 start, 如果为作业模式不处理,让作业模块处理 */
  569. if (query.workRecord) {
  570. return;
  571. }
  572. /** 作业模式 end */
  573. if (state.defaultModeType == 1) {
  574. headTopData.handleChangeModeType("practise");
  575. // if (state.platform === IPlatform.PC || state.isPreView) {
  576. // headTopData.showBack = false;
  577. // }
  578. if (state.isPreView) {
  579. headTopData.showBack = false;
  580. }
  581. } else {
  582. if (query.modelType) {
  583. if (query.modelType === "practise") {
  584. headTopData.handleChangeModeType("practise");
  585. } else if (query.modelType === "evaluating") {
  586. headTopData.handleChangeModeType("evaluating");
  587. }
  588. headTopData.showBack = false;
  589. } else {
  590. setTimeout(() => {
  591. headTopData.modeType = "init";
  592. }, 500);
  593. }
  594. }
  595. };
  596. /** 课件播放 */
  597. const changePlay = (res: any) => {
  598. // console.log('监听上课页面message',res)
  599. if (res?.data?.api === "setPlayState") {
  600. togglePlay("paused", true);
  601. }
  602. if(res?.data?.api === 'togglePlayState') {
  603. // if(state.playState === "play") {
  604. // togglePlay("paused");
  605. // }
  606. // if(state.playState === 'paused') {
  607. // togglePlay("play");
  608. // }
  609. console.log('togglePlayState', state.playState)
  610. togglePlay(state.playState === "play" ? "paused" : "play");
  611. }
  612. // 上课页面,按钮方向
  613. if (res?.data?.api === "imagePos") {
  614. if (res?.data.data) {
  615. state.playBtnDirection = res.data.data === "right" ? "right" : "left";
  616. // if (state.fingeringInfo.direction === "vertical" && state.setting.displayFingering) {
  617. // state.musicScoreBtnDirection = state.playBtnDirection === 'right' ? 'left' : 'right';
  618. // } else {
  619. // state.musicScoreBtnDirection = state.playBtnDirection;
  620. // }
  621. state.musicScoreBtnDirection = state.playBtnDirection;
  622. }
  623. }
  624. };
  625. const parentClassName = "settingBoxClass_drag";
  626. const userId = storeData.user?.id ? String(storeData.user?.id) : "";
  627. const positionInfo =
  628. state.platform !== IPlatform.PC
  629. ? {
  630. styleDrag: { value: null },
  631. }
  632. : useDrag([`${parentClassName} .top_draging`, `${parentClassName} .bom_drag`], parentClassName, toRef(headTopData, "settingMode"), userId);
  633. const speedClassName = "speedBoxClass_drag";
  634. const speedInfo =
  635. state.platform !== IPlatform.PC
  636. ? {
  637. styleDrag: { value: null },
  638. }
  639. : useDrag([`${speedClassName} .top_draging`, `${speedClassName} .bom_drag`], speedClassName, toRef(headData, "speedShow"), userId);
  640. onMounted(() => {
  641. getQueryModelSetModelType();
  642. window.addEventListener("message", changePlay);
  643. if (state.platform === IPlatform.PC) {
  644. showGuide.value = true;
  645. } else {
  646. showStudentGuide.value = true;
  647. }
  648. if (query.showWebGuide === "false") {
  649. showWebGuide.value = false;
  650. }
  651. document.addEventListener("keydown", (e: KeyboardEvent) => {
  652. if (e.code === "Tab") {
  653. e.stopPropagation();
  654. e.preventDefault();
  655. // onStartPlayState();
  656. togglePlay(state.playState === "play" ? "paused" : "play");
  657. }
  658. });
  659. });
  660. onUnmounted(() => {
  661. window.removeEventListener("message", changePlay);
  662. });
  663. const noticeBarWidth = ref<number>();
  664. watch(
  665. () => smoothAnimationState.isShow.value,
  666. () => {
  667. // NoticeBar能不能滚动
  668. if ((smoothAnimationState.isShow.value || state.isCombineRender) && isMusicList.value) {
  669. nextTick(() => {
  670. const widthCon = (document.querySelector("#noticeBarRollDom .van-notice-bar__content") as any)?.offsetWidth || undefined;
  671. noticeBarWidth.value = widthCon;
  672. });
  673. }
  674. },
  675. { immediate: true }
  676. );
  677. // 设置改变触发
  678. watch(state.setting, () => {
  679. console.log(state.setting, "state.setting");
  680. store.set("musicscoresetting", state.setting);
  681. });
  682. // 获取引导页信息
  683. const getAllGuidance = async () => {
  684. let guideInfo: any = null;
  685. try {
  686. const res = await getGuidance({ guideTag: "guideInfo" });
  687. if (res.data) {
  688. guideInfo = JSON.parse(res.data?.guideValue) || null;
  689. } else {
  690. guideInfo = {};
  691. }
  692. state.guideInfo = guideInfo;
  693. } catch (e) {
  694. console.log(e);
  695. }
  696. };
  697. getAllGuidance();
  698. // 完成拖动弹窗引导页
  699. const handleGuide = async () => {
  700. state.guideInfo.teacherDrag = true;
  701. try {
  702. const res = await setGuidance({ guideTag: "guideInfo", guideValue: JSON.stringify(state.guideInfo) });
  703. } catch (e) {
  704. console.log(e);
  705. }
  706. };
  707. return () => (
  708. <>
  709. <div
  710. class={[styles.headerTop, styles[state.modeType] ,state.platform === IPlatform.PC && state.musicScoreBtnDirection === "left" ? styles.headerTopRight : ""]}
  711. onClick={(e: Event) => {
  712. e.stopPropagation();
  713. if (state.platform === IPlatform.PC) {
  714. // 显示隐藏菜单
  715. window.parent.postMessage(
  716. {
  717. api: "onAttendToggleMenu",
  718. },
  719. "*"
  720. );
  721. }
  722. }}
  723. >
  724. {/* 返回和标题 */}
  725. {!(state.playState == "play" || followData.start || evaluatingData.startBegin) && (
  726. <div id="noticeBarRollDom" class={styles.headTopLeftBox}>
  727. {
  728. !query.isMove && !state.isAttendClass && <img src={iconBack} class={["headTopBackBtn", styles.img, !headTopData.showBack && styles.hidenBack]} onClick={checkBack} />
  729. }
  730. {smoothAnimationState.isShow.value || state.isCombineRender ? (
  731. <div
  732. style={
  733. noticeBarWidth.value
  734. ? {
  735. "--noticeBarWidth": noticeBarWidth.value + "px",
  736. }
  737. : {}
  738. }
  739. class={[styles.title, state.isCbsView && styles.blackTitle, "headeTopTitleBtn"]}
  740. onClick={() => {
  741. isMusicList.value && !state.isAttendClass && (musicListShow.value = true);
  742. }}
  743. >
  744. {isMusicList.value && !state.isAttendClass && <div class={[styles.symbolNote, "driver-8"]}></div>}
  745. <NoticeBar text={state.examSongName} background="none" />
  746. </div>
  747. ) : (
  748. isMusicList.value && !state.isAttendClass && (
  749. <img
  750. src={listImg}
  751. class={[styles.img, styles.listImg, "driver-8"]}
  752. onClick={() => {
  753. musicListShow.value = true;
  754. }}
  755. />
  756. )
  757. )}
  758. </div>
  759. )}
  760. {/* 模式切换 */}
  761. {
  762. <div
  763. id={state.platform === IPlatform.PC ? "teacherTop-0" : "studnetT-0"}
  764. style={{ display: toggleBtn.value.display ? "" : "none" }}
  765. class={["driver-9", styles.modeChangeBox, toggleBtn.value.disabled && styles.disabled]}
  766. onClick={() => {
  767. headTopData.oldModeType = state.modeType;
  768. handleRessetState();
  769. headTopData.modeType = "init";
  770. }}
  771. >
  772. <img class={styles.img} src={iconMode} />
  773. <div class={styles.title}>{state.modeType === "practise" ? "练习模式" : state.modeType === "follow" ? "跟练模式" : state.modeType === "evaluating" ? "评测模式" : ""}</div>
  774. </div>
  775. }
  776. {/* 模式提醒 */}
  777. {state.modeType === "practise" && !rhythmBtn.value.playIng && (
  778. <div class={[styles.modeWarn, "practiseModeWarn", state.platform === IPlatform.PC && state.musicScoreBtnDirection === "left" ? styles.modeWarnRight : ""]}>
  779. <img src={state.playType === "play" ? headImg("perform1.png") : headImg("sing1.png")} />
  780. <div>{state.playType === "play" ? "演奏场景" : "演唱场景"}</div>
  781. </div>
  782. )}
  783. {/* 功能按钮 */}
  784. <div
  785. class={[styles.headRight]}
  786. onClick={(e: Event) => {
  787. e.stopPropagation();
  788. }}
  789. >
  790. {/* 一行谱模式,暂不支持节拍指针 */}
  791. {/* {!state.isSingleLine ? (
  792. <div
  793. class={[styles.btn, state.platform === IPlatform.PC ? styles.pcBtn : ""]}
  794. onClick={() => {
  795. // 切换光标模式
  796. let mode = metronomeData.cursorMode;
  797. if (["follow"].includes(state.modeType)) {
  798. mode = metronomeData.cursorMode === 1 ? 3 : 1;
  799. } else {
  800. mode = metronomeData.cursorMode === 3 ? 1 : metronomeData.cursorMode + 1;
  801. }
  802. metronomeData.cursorMode = mode;
  803. }}
  804. >
  805. <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" : "")} />
  806. <span class={styles.iconContent}>
  807. {metronomeData.cursorMode === 1 ? "音符指针" : metronomeData.cursorMode === 2 ? "节拍指针" : metronomeData.cursorMode === 3 ? "关闭指针" : ""}
  808. {metronomeData.cursorTips && (
  809. <>
  810. <i class={styles.arrowIcon}></i>
  811. <div class={[styles["botton-tips"], metronomeData.cursorMode === 3 ? styles.tipSpec : ""]}>{metronomeData.cursorTips}</div>
  812. </>
  813. )}
  814. </span>
  815. </div>
  816. ) : null} */}
  817. <div
  818. style={{ display: playTypeBtn.value.display ? "" : "none" }}
  819. class={["driver-2", styles.btn, playTypeBtn.value.disabled && styles.disabled, styles.playType]}
  820. onClick={() => {
  821. // 总谱 并且开启了单个声轨音频时候
  822. if(state.isCombineRender && audioData.combineIndex !== "-1") {
  823. audioData.combineIndex = "-1"
  824. state.music = ""
  825. // 有总谱范唱就切换到总谱范唱
  826. if(audioData.scoreAudioUrl){
  827. state.fanSong = audioData.scoreAudioUrl
  828. audioData.songCollection.fanSongEle = audioData.scoreAudioEle
  829. audioData.songCollection.beatFanSongEle = audioData.beatScoreAudioEle
  830. }else{
  831. state.fanSong = ""
  832. }
  833. }
  834. const oldPlayType = state.playType;
  835. headTopData.oldPlayType = oldPlayType;
  836. const oldPlaySource = state.playSource;
  837. if (state.playType === "play") {
  838. state.playType = "sing";
  839. state.playSource = state.fanSong ? "music" : state.banSong ? "background" : "mingSong";
  840. } else {
  841. state.playType = "play";
  842. state.playSource = state.music ? "music" : state.accompany ? "background" : "mingSong";
  843. }
  844. isClickMode = true;
  845. // 有指法并且显示指法的时候 切换到演唱模式 需要影藏指法
  846. let isRefresh = false;
  847. if (state.isShowFingering && state.fingeringInfo.name && (state.setting.displayFingering || displayFingeringCache)) {
  848. if (state.playType === "sing") {
  849. state.setting.displayFingering = false;
  850. displayFingeringCache = true;
  851. } else {
  852. state.setting.displayFingering = displayFingeringCache;
  853. displayFingeringCache = false;
  854. }
  855. // 如果是竖屏指法和一行谱的时候 改变指法值的时候state 会调用刷新 refreshMusicSvg 所以下面不调用
  856. if (state.fingeringInfo.direction === "vertical" && !state.isSingleLine) {
  857. isRefresh = true;
  858. }
  859. }
  860. // 有歌词的时候,切换播放模式,需要重新渲染谱面 指法不刷新谱面的时候
  861. if (state.xmlHasLyric && !isRefresh) {
  862. refreshMusicSvg();
  863. } else if (!isRefresh) {
  864. handlerModeChange(oldPlayType, oldPlaySource, true);
  865. }
  866. }}
  867. >
  868. <img style={{ display: state.playType === "play" ? "" : "none" }} class={styles.iconBtn} src={headImg(`perform.png`)} />
  869. <img style={{ display: state.playType === "play" ? "none" : "" }} class={styles.iconBtn} src={headImg(`sing.png`)} />
  870. <span>{state.playType === "play" ? "演奏" : "演唱"}</span>
  871. </div>
  872. <div
  873. id={state.platform === IPlatform.PC ? "teacherTop-1" : "studnetT-1"}
  874. style={{ display: originBtn.value.display ? "" : "none" }}
  875. class={["driver-3", styles.btn, originBtn.value.disabled && styles.disabled, state.playType === "play" ? styles.playSource : styles.songSource]}
  876. onClick={async () => {
  877. // 总谱 并且开启了单个声轨音频时候
  878. if(state.isCombineRender && audioData.combineIndex !== "-1") {
  879. audioData.combineIndex = "-1"
  880. // 区分演奏和演唱
  881. if(state.playType === "play") {
  882. state.music = ""
  883. }else{
  884. // 有总谱范唱就切换到总谱范唱
  885. if(audioData.scoreAudioUrl){
  886. state.fanSong = audioData.scoreAudioUrl
  887. audioData.songCollection.fanSongEle = audioData.scoreAudioEle
  888. audioData.songCollection.beatFanSongEle = audioData.beatScoreAudioEle
  889. }else{
  890. state.fanSong = ""
  891. }
  892. }
  893. }
  894. const oldPlayType = state.playType;
  895. const oldPlaySource = state.playSource;
  896. if (state.playType === "play") {
  897. if (state.playSource === "music") {
  898. state.playSource = state.accompany ? "background" : "mingSong";
  899. } else if (state.playSource === "background") {
  900. state.playSource = state.mingSong ? "mingSong" : "music";
  901. } else {
  902. state.playSource = state.music ? "music" : "background";
  903. }
  904. } else {
  905. if (state.playSource === "music") {
  906. state.playSource = state.banSong ? "background" : "mingSong";
  907. } else if (state.playSource === "background") {
  908. state.playSource = state.mingSong ? "mingSong" : "music";
  909. } else {
  910. state.playSource = state.fanSong ? "music" : "background";
  911. }
  912. }
  913. await handlerModeChange(oldPlayType, oldPlaySource);
  914. showToast({
  915. message: state.playType === "play" ? (state.playSource === "music" ? "已切换为原声" : state.playSource === "background" ? "已切换为伴奏" : "已切换为唱名") : state.playSource === "music" ? "已切换为范唱" : state.playSource === "background" ? "已切换为伴唱" : "已切换为唱名",
  916. position: "top",
  917. className: "selectionToast",
  918. });
  919. }}
  920. >
  921. <img style={{ display: state.playSource === "music" ? "" : "none" }} class={styles.iconBtn} src={state.playType === "play" ? headImg(`music.png`) : headImg(`music1.png`)} />
  922. <img style={{ display: state.playSource === "background" ? "" : "none" }} class={styles.iconBtn} src={state.playType === "play" ? headImg(`background.png`) : headImg(`background1.png`)} />
  923. <img style={{ display: state.playSource === "mingSong" ? "" : "none" }} class={styles.iconBtn} src={headImg(`mingsong.png`)} />
  924. <span>{state.playSource === "music" ? (state.playType === "play" ? "原声" : "范唱") : state.playSource === "background" ? (state.playType === "play" ? "伴奏" : "伴唱") : "唱名"}</span>
  925. </div>
  926. <div
  927. style={{ display: rhythmBtn.value.display ? "" : "none" }}
  928. class={["driver-777", styles.btn, styles.rhythmMode, headTopData.rhythmMode && styles.isrhythmMode, rhythmBtn.value.disabled && styles.disabled]}
  929. onClick={() => {
  930. headTopData.rhythmMode = !headTopData.rhythmMode
  931. }}
  932. >
  933. <img class={styles.iconBtn} src={headImg(`rhythm.png`)} />
  934. <span>律动</span>
  935. </div>
  936. <div
  937. id={state.platform === IPlatform.PC ? "teacherTop-2" : "studnetT-2"}
  938. style={{ display: selectBtn.value.display ? "" : "none" }}
  939. class={["driver-4", styles.btn, selectBtn.value.disabled && styles.disabled, styles.section, state.sectionStatus && styles.isSection]}
  940. onClick={() => handleChangeSection()}
  941. >
  942. <img style={{ display: state.section.length === 0 ? "" : "none" }} class={styles.iconBtn} src={headImg(`section0.png`)} />
  943. <img style={{ display: state.section.length === 1 ? "" : "none" }} class={styles.iconBtn} src={headImg(`section1.png`)} />
  944. <img style={{ display: state.section.length === 2 ? "" : "none" }} class={styles.iconBtn} src={headImg(`section2.png`)} />
  945. <span>选段</span>
  946. </div>
  947. {
  948. <>
  949. <div
  950. style={{ display: metronomeBtn.value.display ? "" : "none" }}
  951. class={["driver-5", styles.btn, styles.metronomeBtn, metronomeBtn.value.disabled && styles.disabled, headData.speedShow && styles.isSpeed, styles.speed]}
  952. onClick={async () => {
  953. headData.speedShow = !headData.speedShow;
  954. }}
  955. >
  956. <img style={{ display: metronomeData.disable ? "block" : "none" }} class={styles.iconBtn} src={headImg("tickon.png")} />
  957. <img style={{ display: !metronomeData.disable ? "block" : "none" }} class={styles.iconBtn} src={headImg("tickoff.png")} />
  958. <span style={{ whiteSpace: "nowrap" }}>节拍</span>
  959. <div class={styles.speedCon}>
  960. <img src={headImg(`${state.speedIcon}.png`)} />
  961. <div>{Math.floor(state.speed)}</div>
  962. </div>
  963. </div>
  964. {
  965. <Popup v-model:show={headData.speedShow} class="popup-custom van-scale center-closeBtn speedBoxClass_drag" transition="van-scale" teleport="body" style={speedInfo.styleDrag.value} overlay-style={{ background: "rgba(0, 0, 0, 0.7)" }}>
  966. <Speed />
  967. {state.platform === IPlatform.PC && <Dragbom showGuide={!state.guideInfo?.teacherDrag} onGuideDone={handleGuide} />}
  968. </Popup>
  969. }
  970. </>
  971. }
  972. {/* {state.enableNotation ? (
  973. <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]}>
  974. {{
  975. reference: () => (
  976. <div
  977. id={state.platform === IPlatform.PC ? "teacherTop-5" : "studnetT-5"}
  978. style={{ display: converBtn.value.display ? "" : "none" }}
  979. class={[styles.btn, converBtn.value.disabled && styles.disabled]}
  980. onClick={(e: Event) => {
  981. e.stopPropagation();
  982. headData.musicTypeShow = !headData.musicTypeShow;
  983. }}
  984. >
  985. <img class={styles.iconBtn} src={headImg("icon_zhuanpu.svg")} />
  986. <span>{state.musicRenderType === "staff" ? "转简谱" : "转五线谱"}</span>
  987. </div>
  988. ),
  989. default: () => <MusicType />,
  990. }}
  991. </Popover>
  992. ) : null} */}
  993. {state.musicRendered && !query.lessonTrainingId && !query.questionId && state.isConcert && (
  994. <div
  995. class={[styles.btn, state.playState === "play" && fingeringBtn.value.disabled && styles.disabled, toggleMusicSheet.show && styles.isMusicSheet, styles.musicSheet, "driver-10"]}
  996. onClick={() => {
  997. toggleMusicSheet.toggle(true);
  998. }}
  999. >
  1000. <img class={styles.iconBtn} src={headImg(`shenggui.png`)} />
  1001. <span>声部</span>
  1002. </div>
  1003. )}
  1004. <div
  1005. id={state.platform === IPlatform.PC ? "teacherTop-6" : "studnetT-6"}
  1006. style={{ display: settingBtn.value.display ? "" : "none" }}
  1007. class={["driver-6", styles.btn, settingBtn.value.disabled && styles.disabled, headTopData.settingMode && styles.isSettingMode, styles.settingMode]}
  1008. onClick={() => (headTopData.settingMode = true)}
  1009. >
  1010. <img class={styles.iconBtn} src={headImg("icon_menu.png")} />
  1011. <span>设置</span>
  1012. </div>
  1013. </div>
  1014. </div>
  1015. {/** 指法点击区域 */}
  1016. {
  1017. state.fingeringInfo.direction === "transverse" && state.setting.displayFingering ?
  1018. <div class={styles.headerMid} onClick={() => {
  1019. fingerRef.value?.doubeClick()
  1020. }}></div> : null
  1021. }
  1022. {/* 播放按钮 */}
  1023. <div
  1024. id="studnetT-7"
  1025. style={{
  1026. display: playBtn.value.display ? "" : "none" ,
  1027. opacity: rhythmBtn.value.playIng? "0.4" : "1"
  1028. }}
  1029. class={[
  1030. // 引导使用的类
  1031. "driver-1",
  1032. styles.playBtn,
  1033. playBtn.value.disabled && styles.disabled,
  1034. state.platform === IPlatform.PC && state.musicScoreBtnDirection === "left" ? styles.playLeftButton : state.platform === IPlatform.PC && state.musicScoreBtnDirection === "right" ? styles.playRightButton : "",
  1035. ]}
  1036. onClick={() => {
  1037. // C调能播放唱名,非C调时,只有谱面类型是首调时,才能播放唱名
  1038. if (!state.isCTone && state.playSource === 'mingSong') {
  1039. const notPlayDesc = state.musicRenderType === EnumMusicRenderType.staff ? '该曲目的五线谱目前还不支持播放唱名' : state.musicRenderType === EnumMusicRenderType.fixedTone ? '该曲目的固定调目前还不支持播放唱名' : '';
  1040. if (notPlayDesc) {
  1041. showToast({
  1042. message: notPlayDesc,
  1043. position: "top",
  1044. className: "selectionToast",
  1045. });
  1046. return
  1047. }
  1048. }
  1049. togglePlay(state.playState === "play" ? "paused" : "play")
  1050. }}
  1051. >
  1052. <div class={styles.btnWrap}>
  1053. <img style={{ display: state.playState === "play" ? "none" : "" }} class={styles.iconBtn} src={headImg("icon_play.png")} />
  1054. <img style={{ display: state.playState === "play" ? "" : "none" }} class={styles.iconBtn} src={headImg("icon_pause.png")} />
  1055. <Circle style={{ opacity: state.playState === "play" ? 1 : 0 }} class={styles.progress} stroke-width={60} stroke-linecap={"square"} currentRate={state.playProgress} rate={100} color="#FFE36A" layer-color="rgba(255,255,255,0.5)" />
  1056. </div>
  1057. </div>
  1058. {/* 重播按钮 */}
  1059. <div
  1060. id="tips-step-9"
  1061. style={{ display: resetBtn.value.display ? "" : "none" }}
  1062. class={[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 : ""]}
  1063. onClick={() => handleResetPlay()}
  1064. >
  1065. <img class={styles.iconBtn} src={headImg("icon_reset.png")} />
  1066. </div>
  1067. <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.7)" }}>
  1068. <Settting />
  1069. {state.platform === IPlatform.PC && <Dragbom showGuide={!state.guideInfo?.teacherDrag} onGuideDone={handleGuide} />}
  1070. </Popup>
  1071. {/* 模式切换 */}
  1072. {/* <ModeTypeMode /> */}
  1073. <ModeView></ModeView>
  1074. {/* isAllBtns */}
  1075. {/* {isAllBtns.value && !query.isCbs && showGuideIndex.value && <TeacherTop></TeacherTop>}
  1076. {isAllBtnsStudent.value && !query.isCbs && showGuideIndex.value && <StudentTop></StudentTop>} */}
  1077. {/* 练习模式功能引导 加载音频完成 不是会员 */}
  1078. {state.modeType === "practise" && headTopData.modeType !== "init" && !query.isCbs && state.audioDone && !state.isLoading && !state.isVip && showWebGuide.value && (
  1079. <PractiseDriver
  1080. statusAll={{
  1081. playBtnStatus: playBtn.value.display,
  1082. subjectStatus: state.musicRendered && !query.lessonTrainingId && !query.questionId && state.isConcert,
  1083. modelTypeStatus: toggleBtn.value.display,
  1084. playType: playTypeBtn.value.display,
  1085. originPlayType: state.playType === "play" ? true : false,
  1086. originBtnStatus: originBtn.value.display,
  1087. backTitle: !(state.playState == "play" || followData.start || evaluatingData.startBegin) && isMusicList.value,
  1088. titleType: smoothAnimationState.isShow.value ? "TEXT" : isMusicList.value ? "IMG" : "NONE",
  1089. }}
  1090. />
  1091. )}
  1092. {/* 跟练模式功能引导 加载音频完成 不是会员 */}
  1093. {state.modeType === "follow" && headTopData.modeType !== "init" && !query.isCbs && state.audioDone && !state.isLoading && !state.isVip && showWebGuide.value && (
  1094. <FollowDriver
  1095. statusAll={{
  1096. subjectStatus: state.musicRendered && !query.lessonTrainingId && !query.questionId && state.isConcert,
  1097. }}
  1098. />
  1099. )}
  1100. {/* 评测模式功能引导 加载音频完成 不是会员 */}
  1101. {state.modeType === "evaluating" && headTopData.modeType !== "init" && !evaluatingData.earphoneMode && !query.isCbs && state.audioDone && !state.isLoading && !state.isVip && evaluatingData.websocketState && !evaluatingData.startBegin && evaluatingData.checkEnd && showWebGuide.value && (
  1102. <EvaluatingDriver
  1103. statusAll={{
  1104. subjectStatus: state.musicRendered && !query.lessonTrainingId && !query.questionId && state.isConcert,
  1105. }}
  1106. />
  1107. )}
  1108. {/** 评测作业,没有完成时,提示弹窗 */}
  1109. <Popup v-model:show={headTopData.workHomeNoDone} class="popup-custom van-scale center-closeBtn" transition="van-scale" teleport="body" style={positionInfo.styleDrag.value} overlay-style={{ background: "rgba(0, 0, 0, 0.7)" }}>
  1110. <WorkHomePop onClose={handleResult} />
  1111. </Popup>
  1112. </>
  1113. );
  1114. },
  1115. });