index.tsx 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. import { computed, defineComponent, onMounted, reactive, ref } 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 icons from "./image/headerTop.json";
  7. import { Badge, Circle, Popover } from "vant";
  8. import { metronomeData } from "../../helpers/metronome";
  9. import Speed from "./speed";
  10. import { evaluatingData, handleStartEvaluat } from "/src/view/evaluating";
  11. import { Popup } from "@varlet/ui";
  12. import Settting from "./settting";
  13. import ModeTypeMode from "./mode-type-mode";
  14. import state, { handleChangeSection, handleResetPlay, handleRessetState, togglePlay } from "/src/state";
  15. import { getAudioCurrentTime } from "/src/view/audio-list";
  16. import { toggleFollow } from "/src/view/follow-practice";
  17. import { api_back } from "/src/helpers/communication";
  18. import MusicType from "./music-type";
  19. export const headData = reactive({
  20. speedShow: false,
  21. musicTypeShow: false,
  22. });
  23. export default defineComponent({
  24. name: "header-top",
  25. setup() {
  26. const headerData = reactive({
  27. settingMode: false,
  28. modeMode: true, // 模式弹框
  29. });
  30. const headRef = ref();
  31. const toggleEvaluat = () => {
  32. handleStartEvaluat();
  33. };
  34. /** 切换模式 */
  35. const handleChangeModeType = (value: "practise" | "follow" | "evaluating") => {
  36. if (value === "evaluating") {
  37. toggleEvaluat();
  38. } else if (value === "follow") {
  39. toggleFollow();
  40. }
  41. headerData.modeMode = false;
  42. };
  43. const disabledList = ["evaluating"];
  44. /** 按钮禁用 */
  45. /** 重播按钮显示条件 */
  46. const resetBtnDisplay = computed(() => {
  47. const currentTime = getAudioCurrentTime();
  48. const playState = state.playState;
  49. const modeType = state.modeType;
  50. return currentTime !== 0 && playState !== "play" && modeType === "practise";
  51. });
  52. /** 播放按钮显示条件 */
  53. const playBtnDisplay = computed(() => {
  54. const modeType = state.modeType;
  55. return modeType === "practise";
  56. });
  57. /** 指法显示条件 */
  58. const fingeringDisplay = computed(() => {
  59. return state.fingeringInfo.name;
  60. });
  61. /** 返回 */
  62. const handleBack = () => {
  63. api_back();
  64. };
  65. return () => (
  66. <div ref={headRef} class={styles.headerTop}>
  67. <div class={styles.back} onClick={handleBack}>
  68. <img src={iconBack} />
  69. </div>
  70. <Title text={state.examSongName} rightView={false} />
  71. <div class={styles.headRight} style={{ display: headerData.modeMode ? "none" : "" }}>
  72. <div
  73. class={styles.btn}
  74. onClick={() => {
  75. handleRessetState();
  76. headerData.modeMode = true;
  77. }}
  78. >
  79. <img class={styles.iconBtn} src={headImg(`modeType.svg`)} />
  80. <span>模式</span>
  81. </div>
  82. <div
  83. class={[styles.btn, disabledList.includes(state.modeType) && styles.disable]}
  84. id="tips-step-6"
  85. onClick={() => {
  86. state.playSource = state.playSource === "music" ? "background" : "music";
  87. }}
  88. >
  89. <img class={styles.iconBtn} src={state.playSource === "music" ? icons.music : icons.background} />
  90. <span>{state.playSource === "music" ? "原声" : "伴奏"}</span>
  91. </div>
  92. <div class={[styles.btn, disabledList.includes(state.modeType) && styles.disable]} id="tips-step-4" onClick={() => handleChangeSection()}>
  93. <img class={styles.iconBtn} src={headImg(`section${state.section.length}.svg`)} />
  94. <span>选段</span>
  95. </div>
  96. <div
  97. style={{ display: fingeringDisplay.value ? "" : "none" }}
  98. class={[styles.btn, disabledList.includes(state.modeType) && styles.disable]}
  99. onClick={() => {
  100. state.setting.displayFingering = !state.setting.displayFingering;
  101. }}
  102. >
  103. <img class={styles.iconBtn} src={state.setting.displayFingering ? icons.fingeringOn : icons.fingeringOff} />
  104. <span>指法</span>
  105. </div>
  106. {/* <div
  107. class={[styles.btn]}
  108. onClick={async () => {
  109. metronomeData.lineShow = !metronomeData.lineShow;
  110. }}
  111. >
  112. <img class={styles.iconBtn} src={headImg("iconStep.png")} />
  113. <span>{metronomeData.lineShow ? "高级" : "初级"}</span>
  114. </div> */}
  115. {/* <div
  116. class={styles.btn}
  117. onClick={async () => {
  118. metronomeData.disable = !metronomeData.disable;
  119. metronomeData.metro?.initPlayer();
  120. }}
  121. >
  122. <img style={{ display: metronomeData.disable ? "block" : "none" }} class={styles.iconBtn} src={headImg("tickoff.png")} />
  123. <img style={{ display: !metronomeData.disable ? "block" : "none" }} class={styles.iconBtn} src={headImg("tickon.png")} />
  124. <span style={{ whiteSpace: "nowrap" }}>节拍器</span>
  125. </div> */}
  126. <Popover trigger="manual" v-model:show={headData.speedShow} placement="bottom" overlay={false}>
  127. {{
  128. reference: () => (
  129. <div
  130. id="tips-step-8"
  131. class={[styles.btn, disabledList.includes(state.modeType) && styles.disable]}
  132. onClick={(e: Event) => {
  133. e.stopPropagation();
  134. headData.speedShow = !headData.speedShow;
  135. }}
  136. >
  137. <Badge class={styles.badge} content={state.speed}>
  138. <img class={styles.iconBtn} src={headImg("speed.svg")} />
  139. </Badge>
  140. <span>速度</span>
  141. </div>
  142. ),
  143. default: () => <Speed />,
  144. }}
  145. </Popover>
  146. <Popover trigger="manual" v-model:show={headData.musicTypeShow} placement="bottom-end" overlay={false}>
  147. {{
  148. reference: () => (
  149. <div
  150. class={[styles.btn, disabledList.includes(state.modeType) && styles.disable]}
  151. onClick={(e: Event) => {
  152. e.stopPropagation();
  153. headData.musicTypeShow = !headData.musicTypeShow;
  154. }}
  155. >
  156. <img class={styles.iconBtn} src={headImg("icon-zhuanpu.svg")} />
  157. <span>转简谱</span>
  158. </div>
  159. ),
  160. default: () => <MusicType />,
  161. }}
  162. </Popover>
  163. <div class={[styles.btn, disabledList.includes(state.modeType) && styles.disable]} onClick={() => (headerData.settingMode = true)}>
  164. <img class={styles.iconBtn} src={headImg("menu.svg")} />
  165. <span>设置</span>
  166. </div>
  167. <div
  168. style={{ display: playBtnDisplay.value ? "" : "none" }}
  169. class={[styles.btn, styles.playBtn, disabledList.includes(state.modeType) && styles.disable]}
  170. id="tips-step-5"
  171. onClick={() => togglePlay()}
  172. >
  173. <div class={styles.btnWrap}>
  174. <img class={styles.iconBtn} src={state.playState === "paused" ? icons.play : icons.pause} />
  175. <Circle
  176. style={{ opacity: state.playState === "play" ? 1 : 0 }}
  177. class={styles.progress}
  178. stroke-width={80}
  179. currentRate={state.playProgress}
  180. rate={100}
  181. color="#FFC830"
  182. />
  183. </div>
  184. </div>
  185. <div
  186. style={{ display: resetBtnDisplay.value ? "" : "none" }}
  187. class={[styles.btn, styles.resetBtn, disabledList.includes(state.modeType) && styles.disable]}
  188. id="tips-step-7"
  189. onClick={() => handleResetPlay()}
  190. >
  191. <img class={styles.iconBtn} src={headImg("replay.svg")} />
  192. </div>
  193. </div>
  194. <Popup teleport="body" defaultStyle={false} v-model:show={headerData.settingMode}>
  195. <Settting onClose={() => (headerData.settingMode = false)} />
  196. </Popup>
  197. <Popup teleport="body" position="bottom" closeOnClickOverlay={false} overlay={false} defaultStyle={false} v-model:show={headerData.modeMode}>
  198. <ModeTypeMode onClose={(value) => handleChangeModeType(value)} />
  199. </Popup>
  200. </div>
  201. );
  202. },
  203. });