|  | @@ -0,0 +1,258 @@
 | 
	
		
			
				|  |  | +import { defineComponent, onMounted, reactive } from 'vue';
 | 
	
		
			
				|  |  | +import styles from './index.module.less';
 | 
	
		
			
				|  |  | +import { postMessage } from '@/helpers/native-message';
 | 
	
		
			
				|  |  | +import icon_title from './images/icon-title.png';
 | 
	
		
			
				|  |  | +import icon_back from './images/icon-back.png';
 | 
	
		
			
				|  |  | +import icon_setting from './images/icon-setting.png';
 | 
	
		
			
				|  |  | +import iconPlay from './images/icon-play.png';
 | 
	
		
			
				|  |  | +import iconPause from './images/icon-pause.png';
 | 
	
		
			
				|  |  | +import beat from './images/btn-2.png';
 | 
	
		
			
				|  |  | +import tempo from './images/btn-3.png';
 | 
	
		
			
				|  |  | +import randDom from './images/btn-1.png';
 | 
	
		
			
				|  |  | +import iconPlus from './images/icon-plus.png';
 | 
	
		
			
				|  |  | +import iconAdd from './images/icon-add.png';
 | 
	
		
			
				|  |  | +import { getImage } from './images/music';
 | 
	
		
			
				|  |  | +import j1 from './images/music/j-1.png';
 | 
	
		
			
				|  |  | +// import j2 from './images/music/j-2.png';
 | 
	
		
			
				|  |  | +import { Popover, Popup, showToast } from 'vant';
 | 
	
		
			
				|  |  | +import SettingModal from './setting-modal';
 | 
	
		
			
				|  |  | +import {
 | 
	
		
			
				|  |  | +  randomScoreElement,
 | 
	
		
			
				|  |  | +  renderScore,
 | 
	
		
			
				|  |  | +  setting,
 | 
	
		
			
				|  |  | +  elementDirection
 | 
	
		
			
				|  |  | +} from './setting';
 | 
	
		
			
				|  |  | +import { handleStartTick, hendleEndTick } from './tick';
 | 
	
		
			
				|  |  | +import { handleStartBeat, hendleEndBeat } from './beat-tick';
 | 
	
		
			
				|  |  | +import { browser } from '@/helpers/utils';
 | 
	
		
			
				|  |  | +import { useRoute } from 'vue-router';
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +export default defineComponent({
 | 
	
		
			
				|  |  | +  name: 'tempo-practice',
 | 
	
		
			
				|  |  | +  setup() {
 | 
	
		
			
				|  |  | +    const route = useRoute();
 | 
	
		
			
				|  |  | +    const state = reactive({
 | 
	
		
			
				|  |  | +      platform: route.query.platform, // microapp 老师端应用里面打开单独处理返回逻辑
 | 
	
		
			
				|  |  | +      win: route.query.win,
 | 
	
		
			
				|  |  | +      settingStatus: false,
 | 
	
		
			
				|  |  | +      speedList: [
 | 
	
		
			
				|  |  | +        { text: '40', value: 40, color: '#060606' },
 | 
	
		
			
				|  |  | +        { text: '50', value: 50, color: '#060606' },
 | 
	
		
			
				|  |  | +        { text: '60', value: 60, color: '#060606' },
 | 
	
		
			
				|  |  | +        { text: '70', value: 70, color: '#060606' },
 | 
	
		
			
				|  |  | +        { text: '80', value: 80, color: '#060606' },
 | 
	
		
			
				|  |  | +        { text: '90', value: 90, color: '#060606' },
 | 
	
		
			
				|  |  | +        { text: '100', value: 100, color: '#060606' },
 | 
	
		
			
				|  |  | +        { text: '110', value: 110, color: '#060606' },
 | 
	
		
			
				|  |  | +        { text: '120', value: 120, color: '#060606' },
 | 
	
		
			
				|  |  | +        { text: '130', value: 130, color: '#060606' },
 | 
	
		
			
				|  |  | +        { text: '140', value: 140, color: '#060606' },
 | 
	
		
			
				|  |  | +        { text: '150', value: 150, color: '#060606' },
 | 
	
		
			
				|  |  | +        { text: '160', value: 160, color: '#060606' },
 | 
	
		
			
				|  |  | +        { text: '170', value: 170, color: '#060606' },
 | 
	
		
			
				|  |  | +        { text: '180', value: 180, color: '#060606' },
 | 
	
		
			
				|  |  | +        { text: '190', value: 190, color: '#060606' },
 | 
	
		
			
				|  |  | +        { text: '200', value: 200, color: '#060606' }
 | 
	
		
			
				|  |  | +      ]
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +    // 返回
 | 
	
		
			
				|  |  | +    const goback = () => {
 | 
	
		
			
				|  |  | +      if (state.platform === 'microapp') {
 | 
	
		
			
				|  |  | +        window.parent.postMessage(
 | 
	
		
			
				|  |  | +          {
 | 
	
		
			
				|  |  | +            api: 'iframe_exit'
 | 
	
		
			
				|  |  | +          },
 | 
	
		
			
				|  |  | +          '*'
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      if (!browser().isApp) {
 | 
	
		
			
				|  |  | +        window.close();
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      postMessage({ api: 'goBack' });
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /** 播放切换 */
 | 
	
		
			
				|  |  | +    const handlePlay = async () => {
 | 
	
		
			
				|  |  | +      if (setting.playState === 'pause') {
 | 
	
		
			
				|  |  | +        setting.playState = 'play';
 | 
	
		
			
				|  |  | +        if (setting.playType === 'beat') {
 | 
	
		
			
				|  |  | +          await handleStartTick();
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +          await handleStartBeat();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        handleStop();
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +    /** 播放类型 */
 | 
	
		
			
				|  |  | +    const handlePlayType = () => {
 | 
	
		
			
				|  |  | +      handleStop();
 | 
	
		
			
				|  |  | +      if (setting.playType === 'beat') {
 | 
	
		
			
				|  |  | +        setting.playType = 'tempo';
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        setting.playType = 'beat';
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const handleStop = () => {
 | 
	
		
			
				|  |  | +      setting.playState = 'pause';
 | 
	
		
			
				|  |  | +      if (setting.playType === 'beat') {
 | 
	
		
			
				|  |  | +        hendleEndTick();
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        hendleEndBeat();
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    onMounted(() => {
 | 
	
		
			
				|  |  | +      state.speedList.forEach((item: any) => {
 | 
	
		
			
				|  |  | +        if (item.value === setting.speed) item.color = '#1CACF1';
 | 
	
		
			
				|  |  | +      });
 | 
	
		
			
				|  |  | +      renderScore();
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +    return () => (
 | 
	
		
			
				|  |  | +      <div class={[styles.tempoPractice, state.win === 'pc' ? styles.pc : '']}>
 | 
	
		
			
				|  |  | +        <div class={styles.head}>
 | 
	
		
			
				|  |  | +          <div class={styles.back} onClick={goback}>
 | 
	
		
			
				|  |  | +            <img src={icon_back} />
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +          <div class={styles.title}>
 | 
	
		
			
				|  |  | +            <img src={icon_title} />
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +          <div class={styles.back} onClick={() => (state.settingStatus = true)}>
 | 
	
		
			
				|  |  | +            <img src={icon_setting} />
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        <div class={styles.conCon}>
 | 
	
		
			
				|  |  | +          <div class={styles.container}>
 | 
	
		
			
				|  |  | +            {setting.scorePart.map((item: any, i: number) => (
 | 
	
		
			
				|  |  | +              <div
 | 
	
		
			
				|  |  | +                class={[
 | 
	
		
			
				|  |  | +                  styles.beatSection,
 | 
	
		
			
				|  |  | +                  setting.scorePart.length >= 2 &&
 | 
	
		
			
				|  |  | +                    item.length !== 1 &&
 | 
	
		
			
				|  |  | +                    styles.small
 | 
	
		
			
				|  |  | +                ]}>
 | 
	
		
			
				|  |  | +                {item.map((child: any, jIndex: number) => (
 | 
	
		
			
				|  |  | +                  <div
 | 
	
		
			
				|  |  | +                    class={[styles.beat, child.selected ? styles.active : '']}>
 | 
	
		
			
				|  |  | +                    <div class={styles.direction}>
 | 
	
		
			
				|  |  | +                      <div
 | 
	
		
			
				|  |  | +                        class={styles.up}
 | 
	
		
			
				|  |  | +                        onClick={() => {
 | 
	
		
			
				|  |  | +                          if (setting.playState === 'play') return;
 | 
	
		
			
				|  |  | +                          if (setting.tempo.length <= 1) {
 | 
	
		
			
				|  |  | +                            showToast('无法切换,请选择至少2种节奏型');
 | 
	
		
			
				|  |  | +                            return;
 | 
	
		
			
				|  |  | +                          }
 | 
	
		
			
				|  |  | +                          // const obj = randomScoreElement(child.index);
 | 
	
		
			
				|  |  | +                          const obj = elementDirection('up', child.index);
 | 
	
		
			
				|  |  | +                          child.index = obj.index;
 | 
	
		
			
				|  |  | +                          child.url = obj.url;
 | 
	
		
			
				|  |  | +                        }}></div>
 | 
	
		
			
				|  |  | +                      <div
 | 
	
		
			
				|  |  | +                        class={styles.down}
 | 
	
		
			
				|  |  | +                        onClick={() => {
 | 
	
		
			
				|  |  | +                          if (setting.playState === 'play') return;
 | 
	
		
			
				|  |  | +                          if (setting.tempo.length <= 1) {
 | 
	
		
			
				|  |  | +                            showToast('无法切换,请选择至少2种节奏型');
 | 
	
		
			
				|  |  | +                            return;
 | 
	
		
			
				|  |  | +                          }
 | 
	
		
			
				|  |  | +                          // const obj = randomScoreElement(child.index);
 | 
	
		
			
				|  |  | +                          const obj = elementDirection('down', child.index);
 | 
	
		
			
				|  |  | +                          child.index = obj.index;
 | 
	
		
			
				|  |  | +                          child.url = obj.url;
 | 
	
		
			
				|  |  | +                        }}></div>
 | 
	
		
			
				|  |  | +                    </div>
 | 
	
		
			
				|  |  | +                    <div class={styles.imgSection}>
 | 
	
		
			
				|  |  | +                      <img src={getImage(child.url)} />
 | 
	
		
			
				|  |  | +                    </div>
 | 
	
		
			
				|  |  | +                  </div>
 | 
	
		
			
				|  |  | +                ))}
 | 
	
		
			
				|  |  | +              </div>
 | 
	
		
			
				|  |  | +            ))}
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        <div class={styles.footer}>
 | 
	
		
			
				|  |  | +          {/* 播放 */}
 | 
	
		
			
				|  |  | +          <div class={styles.play} onClick={handlePlay}>
 | 
	
		
			
				|  |  | +            {setting.playState === 'pause' ? (
 | 
	
		
			
				|  |  | +              <img src={iconPause} />
 | 
	
		
			
				|  |  | +            ) : (
 | 
	
		
			
				|  |  | +              <img src={iconPlay} />
 | 
	
		
			
				|  |  | +            )}
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +          {/* 播放类型 */}
 | 
	
		
			
				|  |  | +          <div class={styles.playType} onClick={handlePlayType}>
 | 
	
		
			
				|  |  | +            {setting.playType === 'beat' ? (
 | 
	
		
			
				|  |  | +              <img src={beat} />
 | 
	
		
			
				|  |  | +            ) : (
 | 
	
		
			
				|  |  | +              <img src={tempo} />
 | 
	
		
			
				|  |  | +            )}
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +          {/* 随机生成 */}
 | 
	
		
			
				|  |  | +          <div
 | 
	
		
			
				|  |  | +            class={styles.randomTempo}
 | 
	
		
			
				|  |  | +            onClick={() => {
 | 
	
		
			
				|  |  | +              renderScore();
 | 
	
		
			
				|  |  | +              handleStop();
 | 
	
		
			
				|  |  | +            }}>
 | 
	
		
			
				|  |  | +            <img src={randDom} />
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +          {/* 速度 */}
 | 
	
		
			
				|  |  | +          <div class={styles.speedChange}>
 | 
	
		
			
				|  |  | +            <img
 | 
	
		
			
				|  |  | +              src={iconPlus}
 | 
	
		
			
				|  |  | +              class={styles.speedPlus}
 | 
	
		
			
				|  |  | +              onClick={() => {
 | 
	
		
			
				|  |  | +                if (setting.speed <= 40) return;
 | 
	
		
			
				|  |  | +                setting.speed -= 1;
 | 
	
		
			
				|  |  | +                handleStop();
 | 
	
		
			
				|  |  | +              }}
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +            <Popover
 | 
	
		
			
				|  |  | +              placement="top"
 | 
	
		
			
				|  |  | +              class={styles.popupContainer}
 | 
	
		
			
				|  |  | +              actions={state.speedList}
 | 
	
		
			
				|  |  | +              onSelect={(val: any) => {
 | 
	
		
			
				|  |  | +                if (val.value === setting.speed) return;
 | 
	
		
			
				|  |  | +                state.speedList.forEach((item: any) => {
 | 
	
		
			
				|  |  | +                  if (item.value === val.value) {
 | 
	
		
			
				|  |  | +                    item.color = '#1CACF1';
 | 
	
		
			
				|  |  | +                    setting.speed = val.value;
 | 
	
		
			
				|  |  | +                  } else {
 | 
	
		
			
				|  |  | +                    item.color = '#060606';
 | 
	
		
			
				|  |  | +                  }
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  | +                handleStop();
 | 
	
		
			
				|  |  | +              }}>
 | 
	
		
			
				|  |  | +              {{
 | 
	
		
			
				|  |  | +                reference: () => (
 | 
	
		
			
				|  |  | +                  <div class={styles.speedNum}>{setting.speed}</div>
 | 
	
		
			
				|  |  | +                )
 | 
	
		
			
				|  |  | +              }}
 | 
	
		
			
				|  |  | +            </Popover>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            <img
 | 
	
		
			
				|  |  | +              src={iconAdd}
 | 
	
		
			
				|  |  | +              class={styles.speedAdd}
 | 
	
		
			
				|  |  | +              onClick={() => {
 | 
	
		
			
				|  |  | +                if (setting.speed >= 200) return;
 | 
	
		
			
				|  |  | +                setting.speed += 1;
 | 
	
		
			
				|  |  | +                handleStop();
 | 
	
		
			
				|  |  | +              }}
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        <Popup v-model:show={state.settingStatus} class={styles.settingPopup}>
 | 
	
		
			
				|  |  | +          <SettingModal onClose={() => (state.settingStatus = false)} />
 | 
	
		
			
				|  |  | +        </Popup>
 | 
	
		
			
				|  |  | +      </div>
 | 
	
		
			
				|  |  | +    );
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +});
 |