Przeglądaj źródła

更新设置和节拍器弹窗

黄琪勇 1 rok temu
rodzic
commit
4d32ba0607
35 zmienionych plików z 1168 dodań i 740 usunięć
  1. 1 0
      src/helpers/metronome.ts
  2. BIN
      src/page-instrument/header-top/image/addImg.png
  3. 0 0
      src/page-instrument/header-top/image/back.png
  4. 0 0
      src/page-instrument/header-top/image/bg.png
  5. BIN
      src/page-instrument/header-top/image/closeImg.png
  6. BIN
      src/page-instrument/header-top/image/cutImg.png
  7. 0 0
      src/page-instrument/header-top/image/gl.png
  8. BIN
      src/page-instrument/header-top/image/guan.png
  9. BIN
      src/page-instrument/header-top/image/headImg.png
  10. BIN
      src/page-instrument/header-top/image/headTit.png
  11. BIN
      src/page-instrument/header-top/image/kai.png
  12. 0 0
      src/page-instrument/header-top/image/lx.png
  13. 0 0
      src/page-instrument/header-top/image/pc.png
  14. BIN
      src/page-instrument/header-top/image/qipao.png
  15. BIN
      src/page-instrument/header-top/image/radio.png
  16. BIN
      src/page-instrument/header-top/image/radioActive.png
  17. BIN
      src/page-instrument/header-top/image/settingName.png
  18. BIN
      src/page-instrument/header-top/image/speed.png
  19. BIN
      src/page-instrument/header-top/image/speedBtn.png
  20. BIN
      src/page-instrument/header-top/image/tpbz.png
  21. BIN
      src/page-instrument/header-top/image/yjfk.png
  22. 0 0
      src/page-instrument/header-top/image/zt.png
  23. 67 14
      src/page-instrument/header-top/index.module.less
  24. 27 48
      src/page-instrument/header-top/index.tsx
  25. 79 0
      src/page-instrument/header-top/modeView.tsx
  26. 151 225
      src/page-instrument/header-top/settting/index.module.less
  27. 72 309
      src/page-instrument/header-top/settting/index.tsx
  28. 235 0
      src/page-instrument/header-top/settting1/index.module.less
  29. 330 0
      src/page-instrument/header-top/settting1/index.tsx
  30. 149 40
      src/page-instrument/header-top/speed/index.module.less
  31. 52 36
      src/page-instrument/header-top/speed/index.tsx
  32. 1 37
      src/page-instrument/view-detail/index.module.less
  33. 1 5
      src/page-instrument/view-detail/index.tsx
  34. 0 25
      src/page-instrument/view-detail/modeView.tsx
  35. 3 1
      src/state.ts

+ 1 - 0
src/helpers/metronome.ts

@@ -110,6 +110,7 @@ class Metronome {
 	init(times: any[]) {
 		this.calculation(times);
 		metronomeData.activeList = [];
+		this.initPlayer()
 	}
 	initPlayer() {
 		// if (!this.source1) {

BIN
src/page-instrument/header-top/image/addImg.png


+ 0 - 0
src/page-instrument/view-detail/images/back.png → src/page-instrument/header-top/image/back.png


+ 0 - 0
src/page-instrument/view-detail/images/bg.png → src/page-instrument/header-top/image/bg.png


BIN
src/page-instrument/header-top/image/closeImg.png


BIN
src/page-instrument/header-top/image/cutImg.png


+ 0 - 0
src/page-instrument/view-detail/images/gl.png → src/page-instrument/header-top/image/gl.png


BIN
src/page-instrument/header-top/image/guan.png


BIN
src/page-instrument/header-top/image/headImg.png


BIN
src/page-instrument/header-top/image/headTit.png


BIN
src/page-instrument/header-top/image/kai.png


+ 0 - 0
src/page-instrument/view-detail/images/lx.png → src/page-instrument/header-top/image/lx.png


+ 0 - 0
src/page-instrument/view-detail/images/pc.png → src/page-instrument/header-top/image/pc.png


BIN
src/page-instrument/header-top/image/qipao.png


BIN
src/page-instrument/header-top/image/radio.png


BIN
src/page-instrument/header-top/image/radioActive.png


BIN
src/page-instrument/header-top/image/settingName.png


BIN
src/page-instrument/header-top/image/speed.png


BIN
src/page-instrument/header-top/image/speedBtn.png


BIN
src/page-instrument/header-top/image/tpbz.png


BIN
src/page-instrument/header-top/image/yjfk.png


+ 0 - 0
src/page-instrument/view-detail/images/zt.png → src/page-instrument/header-top/image/zt.png


+ 67 - 14
src/page-instrument/header-top/index.module.less

@@ -38,7 +38,6 @@
     position: fixed;
     top: 20px;
     right: 30px;
-    width: 100px;
     height: 32px;
     background: rgba(0, 0, 0, .4);
     border-radius: 16px;
@@ -82,6 +81,31 @@
             line-height: 17px;
         }
     }
+    .metronomeBtn{
+        position: relative;
+        .speedCon{
+            padding: 1px 2px;
+            position: absolute;
+            left: 14px;
+            top: -4px;
+            display: flex;
+            align-items: center;
+            background: #FFC121;
+            border-radius: 100px 100px 100px 1px;
+            border: 1px solid #FFFFFF;
+            >img{
+                width: 12px;
+                height: 10px;
+            }
+            >div{
+                margin-left: 1px;
+                font-weight: 600;
+                font-size: 10px;
+                color: #673207;
+                line-height: 1;
+            }
+        }
+    }
 }
 
 .disabled {
@@ -89,19 +113,6 @@
     opacity: .5;
 }
 
-.badge {
-    :global {
-        .van-badge {
-            border: none;
-            color: #135D4F;
-            background: linear-gradient(180deg, #FFF884 0%, #FFC850 100%);
-            border: 1px solid #FFFFFF;
-            font-weight: 400;
-            box-shadow: 0 0 5px rgba(0, 0, 0, .1);
-        }
-    }
-}
-
 .playBtn {
     position: fixed;
     right: 30px;
@@ -178,4 +189,46 @@
 
 .pcTransPop {
     z-index: 999 !important;
+}
+
+.modeView {
+    position: fixed;
+    z-index: 10000;
+    top: 0;
+    left: 0;
+    width: 100vw;
+    height: 100vh;
+    background: url(./image/bg.png) no-repeat;
+    background-size: 100% 100%;
+    transition: all .3s;
+    &.hidden{
+        opacity: 0;
+        transform: translateY(100%);
+        pointer-events: none;
+    }
+    .back {
+        position: absolute;
+        width: 38px;
+        height: 38px;
+        left: 27px;
+        top: 17px;
+    }
+    .name {
+        position: absolute;
+        left: 50%;
+        top: 23px;
+        transform: translateX(-50%);
+        width: 87px;
+        height: 21px;
+    }
+    .modeBox {
+        width: 100%;
+        margin-top: 90px;
+        display: flex;
+        justify-content: space-between;
+        padding: 0 36px;
+        > img {
+            width: calc((100% - 2*40px)/3);
+        }
+    }
 }

+ 27 - 48
src/page-instrument/header-top/index.tsx

@@ -27,6 +27,7 @@ import { toggleMusicSheet } from "/src/view/plugins/toggleMusicSheet";
 import useDrag from "/src/view/plugins/useDrag/index";
 import Dragbom from "/src/view/plugins/useDrag/dragbom";
 import { getGuidance, setGuidance } from "../custom-plugins/guide-page/api";
+import ModeView from "./modeView"
 
 /** 头部数据和方法 */
 export const headTopData = reactive({
@@ -495,53 +496,30 @@ export default defineComponent({
               <span>选段</span>
             </div>
             {state.modeType !== "evaluating" && (
-              <div
-                style={{ display: metronomeBtn.value.display ? "" : "none" }}
-                class={[styles.btn, metronomeBtn.value.disabled && styles.disabled]}
-                onClick={async () => {
-                  metronomeData.disable = !metronomeData.disable;
-                  metronomeData.metro?.initPlayer();
-                }}
-              >
-                <img style={{ display: metronomeData.disable ? "block" : "none" }} class={styles.iconBtn} src={headImg("tickon.png")} />
-                <img style={{ display: !metronomeData.disable ? "block" : "none" }} class={styles.iconBtn} src={headImg("tickoff.png")} />
-                <span style={{ whiteSpace: "nowrap" }}>节拍器</span>
-              </div>
-            )}
-            {/* <div
-              id={state.platform === IPlatform.PC ? "teacherTop-3" : "studnetT-3"}
-              style={{ display: fingeringBtn.value.display ? "" : "none" }}
-              class={[styles.btn, fingeringBtn.value.disabled && styles.disabled]}
-              onClick={() => {
-                state.setting.displayFingering = !state.setting.displayFingering;
-              }}
-            >
-              <img style={{ display: state.setting.displayFingering ? "" : "none" }} class={styles.iconBtn} src={headImg(`icon_evaluatingOn.svg`)} />
-              <img style={{ display: state.setting.displayFingering ? "none" : "" }} class={styles.iconBtn} src={headImg(`icon_evaluatingOff.svg`)} />
-              <span>指法</span>
-            </div> */}
-
-            {/* <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]}>
-              {{
-                reference: () => (
-                  <div
-                    id={state.platform === IPlatform.PC ? "teacherTop-4" : "studnetT-4"}
-                    style={{ display: speedBtn.value.display ? "" : "none" }}
-                    class={[styles.btn, speedBtn.value.disabled && styles.disabled]}
-                    onClick={(e: Event) => {
-                      e.stopPropagation();
-                      headData.speedShow = !headData.speedShow;
-                    }}
-                  >
-                    <Badge class={styles.badge} content={state.playState === "play" ? Math.floor(state.playIngSpeed) : Math.floor(state.speed)}>
-                      <img class={styles.iconBtn} src={headImg("icon_speed.svg")} />
-                    </Badge>
-                    <span>速度</span>
+              <>
+                <div
+                  style={{ display: metronomeBtn.value.display ? "" : "none" }}
+                  class={[styles.btn, styles.metronomeBtn, metronomeBtn.value.disabled && styles.disabled]}
+                  onClick={async () => {
+                    headData.speedShow = !headData.speedShow;
+                  }}
+                >
+                  <img style={{ display: metronomeData.disable ? "block" : "none" }} class={styles.iconBtn} src={headImg("tickon.png")} />
+                  <img style={{ display: !metronomeData.disable ? "block" : "none" }} class={styles.iconBtn} src={headImg("tickoff.png")} />
+                  <span style={{ whiteSpace: "nowrap" }}>节拍</span>
+                  <div class={styles.speedCon}>
+                    <img src={headImg("speed.png")} />
+                    <div>{state.speed}</div>
                   </div>
-                ),
-                default: () => <Speed />,
-              }}
-            </Popover> */}
+                </div>          
+                {
+                  <Popup v-model:show={headData.speedShow} 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.3)'}}>
+                    <Speed />
+                    {state.platform === IPlatform.PC && <Dragbom showGuide={!state.guideInfo?.teacherDrag} onGuideDone={handleGuide} />}
+                  </Popup>
+                }
+              </>             
+            )}
             {/* {state.enableNotation ? (
               <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]}>
                 {{
@@ -613,13 +591,14 @@ export default defineComponent({
           <img class={styles.iconBtn} src={headImg("icon_reset.png")} />
         </div>
 
-        <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}>
+        <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.3)'}}>
           <Settting />
           {state.platform === IPlatform.PC && <Dragbom showGuide={!state.guideInfo?.teacherDrag} onGuideDone={handleGuide} />}
         </Popup>
 
         {/* 模式切换 */}
-        <ModeTypeMode />
+        {/* <ModeTypeMode /> */}
+        <ModeView></ModeView>
 
         {/* isAllBtns */}
         {isAllBtns.value && !query.isCbs && showGuideIndex.value && <TeacherTop></TeacherTop>}

+ 79 - 0
src/page-instrument/header-top/modeView.tsx

@@ -0,0 +1,79 @@
+import { defineComponent, onMounted, watch, reactive } from "vue"
+import styles from "./index.module.less"
+import backImg from "./image/back.png"
+import nameImg from "./image/zt.png"
+import lxImg from "./image/lx.png"
+import glImg from "./image/gl.png"
+import pcImg from "./image/pc.png"
+import { headTopData } from "./index"
+import TheVip from "../custom-plugins/the-vip"
+import { getQuery } from "/src/utils/queryString";
+import { storeData } from "/src/store";
+import state from "/src/state";
+import { studentQueryUserInfo } from "../api";
+import { usePageVisibility } from "@vant/use";
+
+export default defineComponent({
+   name: "modeView",
+   setup() {
+      const query = getQuery()
+      const data = reactive({
+         showPC: false,
+         showStudent: false,
+         showVip: false,
+      })
+      const openGuid = () => {
+         // 加载后 判断 端口号 加载对应的引导
+         if (storeData.platformType !== "STUDENT" || storeData.user.clientType !== "STUDENT") {
+            // PC
+            data.showPC = true
+         } else {
+            // 从课堂乐器学生端课件预览默认不显示会员
+            if (storeData.user.vipMember || state.paymentType === "FREE" || query.showCourseMember === "true") {
+               // 学生端
+               data.showStudent = true
+            } else {
+               // vip
+               data.showVip = true
+            }
+         }
+      }
+
+      const getUserInfo = async () => {
+         const res = await studentQueryUserInfo()
+         const student = res?.data || {}
+         storeData.user.vipMember = student.vipMember
+         // console.log("🚀 ~ student:", student);
+         if (storeData.user.vipMember) {
+            data.showVip = false
+            openGuid()
+         }
+      }
+      const pageVisible = usePageVisibility()
+      watch(
+         () => pageVisible.value,
+         val => {
+            if (val === "visible") {
+               if (storeData.user.vipMember) return
+               console.log("页面显示")
+               getUserInfo()
+            }
+         }
+      )
+      onMounted(() => {
+         openGuid()
+      })
+      return () => (
+         <div class={[styles.modeView, headTopData.modeType !== "init" && styles.hidden]}>
+            <img src={backImg} class={styles.back} />
+            <img src={nameImg} class={styles.name} />
+            <div class={styles.modeBox}>
+               <img src={lxImg} class={styles.modeImg} onClick={() => headTopData.handleChangeModeType("practise")} />
+               <img src={glImg} class={styles.modeImg} onClick={() => headTopData.handleChangeModeType("follow")} />
+               <img src={pcImg} class={styles.modeImg} onClick={() => headTopData.handleChangeModeType("evaluating")} />
+            </div>
+            {data.showVip && <TheVip />}
+         </div>
+      )
+   }
+})

+ 151 - 225
src/page-instrument/header-top/settting/index.module.less

@@ -1,235 +1,161 @@
-.header-settting {
-    position: relative;
-}
-
-.content {
-    position: relative;
-    overflow: hidden;
-    border-radius: 16PX;
-    width: 300px;
-    height: 86vh;
-    background-color: #fff;
-    max-height: 340px;
-    --van-tabs-line-height: 50px;
-    --van-tab-active-text-color: var(--van-primary-color);
-
-    :global {
-        .van-tab__panel {
-            position: relative;
-            height: calc(86vh - 50px);
-            max-height: calc(340px - 50px);
+.settting{
+    .head{
+        background: url("../image/headImg.png") no-repeat;
+        background-size: 100% 100%;
+        width: 372px;
+        height: 57px;
+        position: relative;
+        .headTit{
+            position: absolute;
+            bottom: 9px;
+            left: 50%;
+            transform: translateX(-50%);
+            width: 38px;
+            height: 18px;
+        }        
+        .closeImg{
+            position: absolute;
+            top: 0;
+            right: -38px;
+            width: 32px;
+            height: 32px;
+            cursor: pointer;
+        }
+    }
+    .content{
+        width: 354px;
+        height: 284px;
+        background: #B0D8FF;
+        box-shadow: 0px 4px 0px 0px #7AAEE0;
+        border-radius: 0px 0px 24px 24px;
+        margin: 0 auto;
+        padding: 10px;
+        .conBox{
+            width: 100%;
+            height: 100%;
+            background: #EAF2FB;
+            border-radius: 12px;
             overflow-y: auto;
-            padding: 0 20px 10px 20px;
-
+            padding: 0 16px;
             &::-webkit-scrollbar {
                 width: 0;
                 display: none;
             }
-        }
-
-        .van-tabs__nav--line {
-            padding-bottom: 0;
-        }
-
-        .van-tabs__wrap::after {
-            display: none;
-        }
-
-        .van-tabs__line {
-            width: 18px;
-            bottom: 8px;
-        }
-
-        .van-cell {
-            padding-left: 0;
-            padding-right: 0;
-
-            &:after {
-                left: 0;
-                right: 0;
-                border-color: #F0F0F0;
+            .cellBox{
+                padding: 14px 0;
+                display: flex;
+                justify-content: space-between;
+                align-items: center;
+                border-bottom: 1px solid #D5E0ED;
+                :global{
+                    .van-switch{
+                        width: 42px;
+                        height: 21px;
+                        background-color: transparent!important;
+                        background-image: url("../image/guan.png");
+                        background-repeat: no-repeat;
+                        background-size: 100% 100%;
+                        border-radius: 0;
+                        &.van-switch--on{
+                            background-image: url("../image//kai.png");
+                        }
+                        .van-switch__node{
+                            display: none;
+                        }
+                    }
+                }
+                .tit{
+                    font-weight: 600;
+                    font-size: 15px;
+                    color: #000000;
+                    line-height: 21px;
+                }
+                .radioBox{
+                    display: flex;
+                    > div{
+                        width: 66px;
+                        height: 28px;
+                        font-weight: 600;
+                        font-size: 14px;
+                        color: #757C87;
+                        text-align: center;
+                        line-height: 26px;
+                        background: url("../image/radio.png") no-repeat;
+                        background-size: 100% 100%;
+                        margin-right: 10px;
+                        cursor: pointer;
+                        &:last-child{
+                            margin-right: 0;
+                        }
+                        &.active{
+                            background: url("../image/radioActive.png") no-repeat;
+                            background-size: 100% 100%; 
+                            color: #ffffff;
+                        }
+                    }
+                }
+                .frequency{
+                    display: flex;
+                    align-items: center;
+                    .frequencyNum{
+                        margin: 0 10px;
+                        width: 63px;
+                        height: 29px;
+                        background: #FFFFFF;
+                        border-radius: 6px;
+                        text-align: center;
+                        line-height: 29px;
+                        font-weight: 600;
+                        font-size: 15px;
+                        color: #1CACF1;
+                    }
+                    .btn{
+                        width: 24px;
+                        height: 24px;
+                        flex-shrink: 0;
+                        cursor: pointer;
+                    }
+                }
+                .reactionTimeBox{
+                    display: flex;
+                    align-items: center;
+                    .reactionTime{
+                        width: 63px;
+                        height: 29px;
+                        background: #FFFFFF;
+                        border-radius: 6px;
+                        padding: 0;
+                        line-height: 29px;
+                        :global{
+                            .van-field__control{
+                                font-weight: 600;
+                                font-size: 15px;
+                                color: #1CACF1;
+                            }
+                        }
+                    }
+                    .timeName{
+                        margin-left: 8px;
+                        font-weight: 600;
+                        font-size: 15px;
+                        color: #000000;
+                    }
+                }
             }
-        }
-
-        .van-switch {
-            width: 46px;
-            height: 23px;
-            background-color: transparent !important;
-            background-image: url('../image/off.svg');
-            background-repeat: no-repeat;
-            background-size: 100% 100%;
-            background-position: center;
-            border-radius: 0;
-
-            &.van-switch--on {
-                background-image: url('../image/on.svg');
-            }
-
-            .van-switch__node {
-                display: none;
+            .cellBtnBox{
+                display: flex;
+                justify-content: center;
+                align-items: center;
+                padding: 14px 0;
+                >img{
+                    width: 118px;
+                    height: 39px;
+                    cursor: pointer;
+                    &:first-child{
+                        margin-right: 20px;
+                    }
+                }
             }
         }
-
-        .van-notice-bar__content {
-            font-size: 12px;
-        }
-    }
-
-    &.pcContent {
-        height: 230px;
-        .pcDragTop {
-            position: absolute;
-            left: 0;
-            top: 0;
-            width: 100%;
-            height: 20px;
-            z-index: 1;
-            cursor: move;
-        }
-        :global {
-            .van-tab__panel {
-                height: 180px;
-            } 
-        }
-    }
-}
-
-.noticebar {
-    border-radius: 6px;
-    background: linear-gradient(45deg, #FFF6EE, #FFECDD);
-    color: #FEAD15;
-}
-
-.reactionTime {
-    :global {
-        .van-cell__title {
-            width: 60%;
-        }
-
-        .van-cell__value {
-            text-align: right;
-        }
-    }
-}
-
-.radioGroup {
-    display: flex;
-    align-items: center;
-    border-radius: 14px;
-    background: linear-gradient(180deg, #5BECFF, #259CFE);
-    padding: 4px;
-
-    :global {
-        .van-radio {
-            display: flex;
-            align-items: center;
-            justify-content: center;
-            height: 22px;
-            margin: 0 3px;
-            border-radius: 6px;
-            padding: 0 4px;
-        }
-
-        .van-radio__icon {
-            display: none;
-        }
-
-        .van-radio__label {
-            margin: 0 auto;
-            font-size: 10px;
-            color: #fff;
-            font-weight: bold;
-            white-space: nowrap;
-            text-align: center;
-        }
-
-        .van-radio[aria-checked='true'] {
-            background: linear-gradient(180deg, #FFFFFF, #DAF1FF);
-            box-shadow: 0px 0px 1px 0px #DAF1FF;
-
-            .van-radio__label {
-                color: var(--van-primary-color);
-                font-weight: bold;
-            }
-        }
-    }
-}
-
-.sliderWrap {
-    :global {
-        .var-cell__extra {
-            flex: 2;
-        }
-    }
-}
-
-.slider {
-    width: 60%;
-    margin-right: 20px;
-
-    .sliderBtn {
-        width: 40px;
-        color: #fff;
-        font-size: 12px;
-        line-height: 20px;
-        text-align: center;
-        background-color: var(--van-primary-color);
-        border-radius: 20px;
-    }
-}
-.sliderVolume {
-    width: 55%;
-}
-.btnsbar {
-    position: absolute;
-    bottom: 12px;
-    left: 0;
-    width: 100%;
-    display: flex;
-    align-items: center;
-    justify-content: space-evenly;
-
-    .btn {
-        display: flex;
-        justify-content: space-evenly;
-        align-items: center;
-        width: 42%;
-        height: 30px;
-        padding: 0 6px;
-        border-radius: 6px;
-        font-size: 10px;
-        background: #fff6e8;
-        color: #6c442d;
-        border: none;
-        white-space: nowrap;
-        & > img {
-            width: 22px;
-            height: 22px;
-        }
-        &:active {
-            opacity: .8;
-        }
-    }
-}
-
-.disabled{
-    opacity: .3;
-    pointer-events: none;
-}
-
-.operateHz {
-    display: flex;
-    align-items: center;
-    font-size: 14px;
-    color: var(--van-primary-color);
-    font-weight: 500;
-    img {
-        width: 28px;
-        height: 28px;
-    }
-    span {
-        margin: 0 6px;
-        width: 50px;
-        text-align: center;
     }
 }

+ 72 - 309
src/page-instrument/header-top/settting/index.tsx

@@ -1,95 +1,14 @@
-import { defineComponent, nextTick, reactive, watch, toRef } from "vue";
-import styles from "./index.module.less";
-import iconClose from "../image/close2.svg";
-import {
-	Cell,
-	Field,
-	NoticeBar,
-	Popup,
-	Radio,
-	RadioGroup,
-	Slider,
-	Switch,
-	Tab,
-	Tabs,
-	closeToast,
-	showLoadingToast,
-	showToast,
-} from "vant";
-import state, { IPlatform } from "/src/state";
-import { api_closeCamera, api_openCamera, api_savePicture } from "/src/helpers/communication";
-
-import iconInfo from "../image/info.svg";
-import iconDown from "../image/down.svg";
-import iconTv from "../image/tv.svg";
-import iconYijian from "../image/yijian.svg";
-import iconSubtract from "../image/subtract.png";
-import iconAdd from "../image/add.png";
-import ScreenModel from "../../custom-plugins/helper-model/screen-model";
-import Recommendation from "../../custom-plugins/helper-model/recommendation";
-import { svg2canvas } from "/src/utils/svg2canvas";
-import { getQuery } from "/src/utils/queryString";
-import { browser } from "/src/utils";
-import { storeData } from "/src/store";
-import useDrag from "/src/view/plugins/useDrag/index";
-import Dragbom from "/src/view/plugins/useDrag/dragbom";
-import { setGuidance } from "/src/page-instrument/custom-plugins/guide-page/api";
+import { defineComponent } from "vue";
+import styles from "./index.module.less"
+import { headImg } from "../image";
+import { headTopData } from "../index"
+import { Switch, showToast, Field } from "vant";
+import state from "/src/state"
 
 export default defineComponent({
-	name: "header-settting",
+	name: "settting",
 	setup() {
-		const query = getQuery();
-		const helperData = reactive({
-			show: false,
-			recommendationShow: false, // 建议
-		});
-		const downPng = () => {
-			showLoadingToast({ message: "下载中", duration: 0 });
-			setTimeout(async () => {
-				const svg: any = document.getElementById("osmdSvgPage1")?.cloneNode(true);
-				if (!svg) return showToast({ message: "保存失败", type: "fail" });
-				const cw = svg.width.animVal.value;
-				const ch = svg.height.animVal.value;
-				const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
-				rect.setAttribute("x", "0");
-				rect.setAttribute("y", "0");
-				rect.setAttribute("width", `${cw * 2}`);
-				rect.setAttribute("height", `${ch * 2}`);
-				rect.setAttribute("fill", "#fff");
-				svg.prepend(rect);
-				if (svg) {
-					const _canvas = svg2canvas(svg.outerHTML);
-					const browserInfo = browser();
-					if (state.platform === IPlatform.PC || !browserInfo.isApp) {
-						let el: any = document.createElement("a");
-						// 设置 href 为图片经过 base64 编码后的字符串,默认为 png 格式
-						el.href = _canvas.toDataURL();
-						el.download = state.examSongName;
-
-						// 创建一个点击事件并对 a 标签进行触发
-						const event = new MouseEvent("click");
-						el.dispatchEvent(event);
-						setTimeout(() => {
-							showToast({ message: "保存成功", type: "success" });
-							el = null;
-						}, 300);
-					} else {
-						const base64 = _canvas.toDataURL("image/png", 1);
-						const res = await api_savePicture({
-							base64,
-						});
-						if (res?.content?.status === "success") {
-							showToast({ message: "保存成功", type: "success" });
-						} else {
-							showToast({ message: "保存失败", type: "fail" });
-						}
-					}
-				}
-			}, 500);
-		};
-
-		const formatterTimeMs = (value: any) => value = String(Math.min(3000, value));
-		// 加减评测频率
+        // 加减评测频率
 		const operateHz = (type: number) => {
 			const minFrequency = state.baseFrequency - 10, maxFrequency = state.baseFrequency + 10
 			let currentFrequency = state.setting.frequency
@@ -102,228 +21,72 @@ export default defineComponent({
 			}
 			state.setting.frequency = currentFrequency >= 0 ? currentFrequency : 0
 		}
-
-		const parentClassName = "recommenBoxClass_drag";
-		const userId = storeData.user?.id ? String(storeData.user?.id) : '';
-		const positionInfo = state.platform !== IPlatform.PC ? {
-			styleDrag: { value: null }
-		  } : useDrag(
-		  [
-			`${parentClassName} .top_drag`,
-			`${parentClassName} .bom_drag`
-		  ],
-		  parentClassName,
-		  toRef(helperData, 'recommendationShow'),
-		  userId
-		)
-	    // 完成拖动弹窗引导页
-		const handleGuide = async () => {
-			state.guideInfo.teacherDrag = true;
-				  try{
-					  const res = await setGuidance({guideTag:'guideInfo',guideValue:JSON.stringify(state.guideInfo)})
-			}catch(e){
-			  console.log(e)
-			}   
-		}
-
+        const formatterTimeMs = (value: any) => value = String(Math.min(3000, value));
 		return () => (
-			<div class={styles["header-settting"]}>
-				<div class={[styles.content, state.platform === IPlatform.PC && styles.pcContent]}>
-				{ state.platform === IPlatform.PC && <div class={'top_drag'}></div> }
-					<Tabs border animated swipeable>
-						<Tab title="全局设置">
-							<NoticeBar
-								class={styles.noticebar}
-								left-icon={iconInfo}
-								text="全局设置会更改所有乐谱练习及评测"
-							/>
-							<Cell title="护眼模式" center>
-								{{
-									extra: () => <Switch v-model={state.setting.eyeProtection}></Switch>,
-								}}
-							</Cell>
-							{/* 节拍器 音量注释掉了  这里的代码也一并注释了 state.setting.beatVolume = state.setting.beatVolume || 50 */}
-							{/* <Cell
-								title="节拍器音量"
-								class={styles.sliderWrap}
-								center
-							>
-								{{
-									extra: () => (
-										<Slider
-											class={[styles.slider, styles.sliderVolume]}
-											min={0}
-											max={100}
-											v-model:modelValue={state.setting.beatVolume}
-										>
-											{{
-												button: () => <div class={styles.sliderBtn}>{state.setting.beatVolume}</div>,
-											}}
-										</Slider>
-									),
-								}}
-							</Cell>							 */}
-							<div class={styles.btnsbar}>
-								{/* <div class={styles.btn} onClick={downPng}>
-									<img src={iconDown} />
-									下载曲谱
-								</div> */}
-								<div class={styles.btn} onClick={() => (helperData.show = true)}>
-									<img src={iconTv} />
-									投屏帮助
-								</div>
-								<div class={styles.btn} onClick={() => (helperData.recommendationShow = true)}>
-									<img src={iconYijian} />
-									意见反馈
-								</div>
-							</div>
-						</Tab>
-						<Tab title="练习设置">
-							<Cell title="循环播放" center>
-								{{
-									extra: () => <Switch v-model={state.setting.repeatAutoPlay}></Switch>,
-								}}
-							</Cell>
-							<Cell class={[state.modeType == "evaluating" && styles.disabled]} title="显示指法" center>
-								{{
-									extra: () => <Switch v-model={state.setting.displayFingering} disabled={!state.fingeringInfo.name || !state.isShowFingering}></Switch>,
-								}}
-							</Cell>
-						</Tab>
-						<Tab title="评测设置">
-							<Cell class={[query.workRecord && styles.disabled]} title="评测难度" center>
-								{{
-									extra: () => (
-										<RadioGroup
-											iconSize={20}
-											class={styles.radioGroup}
-											v-model={state.setting.evaluationDifficulty}
-										>
-											<Radio name="BEGINNER">入门</Radio>
-											<Radio name="ADVANCED">进阶</Radio>
-											<Radio name="PERFORMER">大师</Radio>
-										</RadioGroup>
-									),
-								}}
-							</Cell>
-
-							<Cell title="延迟检测" center>
-								{{
-									extra: () => <Switch v-model={state.setting.soundEffect}></Switch>,
-								}}
-							</Cell>
-							<Cell title="摄像头" center>
-								{{
-									extra: () => (
-										<Switch
-											v-model={state.setting.camera}
-											onChange={ async (value) => {
-												if (value) {
-													const res = await api_openCamera();
-													// 没有授权
-													if (res?.content?.reson) {
-														state.setting.camera = false
-													}
-												} else {
-													api_closeCamera();
-												}
-											}}
-										></Switch>
-									),
-								}}
-							</Cell>
-							<Cell
-								style={{ display: state.setting.camera ? "" : "none" }}
-								title="透明度"
-								class={styles.sliderWrap}
-								center
-							>
-								{{
-									extra: () => (
-										<Slider
-											class={styles.slider}
-											min={0}
-											max={100}
-											v-model:modelValue={state.setting.cameraOpacity}
-										>
-											{{
-												button: () => <div class={styles.sliderBtn}>{state.setting.cameraOpacity}</div>,
-											}}
-										</Slider>
-									),
-								}}
-							</Cell>
-							{/* <Cell title="保存到相册" center>
-								{{
-									extra: () => <Switch v-model={state.setting.saveToAlbum}></Switch>,
-								}}
-							</Cell> */}
-							<Cell title="开启伴奏" center>
-								{{
-									extra: () => <Switch v-model={state.setting.enableAccompaniment}></Switch>,
-								}}
-							</Cell>
-							<Cell title="标准音高" center>
-								{/* {{
-									extra: () => (
-										<RadioGroup
-											iconSize={20}
-											class={styles.radioGroup}
-											v-model={state.setting.frequency}
-										>
-											<Radio name={440}>440Hz</Radio>
-											<Radio name={442}>442Hz</Radio>
-										</RadioGroup>
-									),
-								}} */}
-								{{
-									extra: () => (
-										<div class={styles.operateHz}>
-											<img src={iconSubtract} onClick={() => operateHz(1)} />
-											<span>{state.setting.frequency}HZ</span>
-											<img src={iconAdd} onClick={() => operateHz(2)} />
-										</div>
-									)
-								}}
-							</Cell>
-
-							<Field class={styles.reactionTime} label="反应时间(毫秒)" type="digit" 
-								placeholder="最大可输入3000毫秒"
-								formatter={formatterTimeMs}
-								v-model:modelValue={state.setting.reactionTimeMs} />
-						</Tab>
-					</Tabs>
+			<div class={styles.settting}>
+                <div class={styles.head}>
+					<img class={styles.headTit} src={headImg("settingName.png")} />
+					<img class={styles.closeImg} src={headImg("closeImg.png")} onClick={()=>{ headTopData.settingMode = false }} />
 				</div>
-				<Popup
-					class={["popup-custom", styles.screen]}
-					v-model:show={helperData.show}
-					onClose={() => {
-						helperData.show = false;
-					}}
-					position="right"
-					teleport="body"
-				>
-					<ScreenModel
-						onClose={(open: Boolean) => {
-							helperData.show = false;
-						}}
-					/>
-				</Popup>
-				<Popup
-					v-model:show={helperData.recommendationShow}
-					class="popup-custom van-scale center-closeBtn recommenBoxClass_drag"
-					transition="van-scale"
-					teleport="body"
-					closeable
-					style={positionInfo.styleDrag.value}
-				>
-					<Recommendation
-						onClose={() => {
-							helperData.recommendationShow = false;
-						}}
-					/>
-					{ state.platform === IPlatform.PC && <Dragbom showGuide={!state.guideInfo?.teacherDrag} /> }
-				</Popup>
+                <div class={styles.content}>
+                    <div class={styles.conBox}>
+                        <div class={styles.cellBox}>
+                            <div class={styles.tit}>指法</div>
+                            <Switch v-model={state.setting.displayFingering}></Switch>
+                        </div>
+                        <div class={styles.cellBox}>
+                            <div class={styles.tit}>循环播放</div>
+                            <Switch v-model={state.setting.repeatAutoPlay}></Switch>
+                        </div>
+                        <div class={styles.cellBox}>
+                            <div class={styles.tit}>旋律线</div>
+                            <Switch v-model={state.setting.melodyLine}></Switch>
+                        </div>                       
+                        <div class={styles.cellBox}>
+                            <div class={styles.tit}>标准音高</div>
+                            <div class={styles.frequency}>
+                                <img src={headImg("cutImg.png")} class={[styles.btn]} onClick={() => operateHz(1)} />
+                                <div class={styles.frequencyNum}>{state.setting.frequency}HZ</div>
+                                <img src={headImg("addImg.png")} class={[styles.btn]} onClick={() => operateHz(2)} />
+                            </div>
+                        </div>                        
+                        <div class={styles.cellBox}>
+                            <div class={styles.tit}>反应时间</div>
+                            <div class={styles.reactionTimeBox}>
+                                <Field class={styles.reactionTime} type="digit" 
+                                    placeholder="最大可输入3000毫秒"
+                                    formatter={formatterTimeMs}
+                                    input-align={'center'}
+                                    v-model:modelValue={state.setting.reactionTimeMs} />
+                                <div class={styles.timeName}>毫秒</div>    
+                            </div>
+                        </div>
+                        <div class={styles.cellBox}>
+                            <div class={styles.tit}>切换谱面</div>
+                            <div class={styles.radioBox}>
+                                {
+                                    [{name:'单行谱',value:true},{name:'多行谱',value:false}].map(item=>{
+                                        return <div class={ state.isSingleLine===item.value && styles.active } onClick={ ()=>{ state.isSingleLine = item.value } }>{item.name}</div>
+                                    })
+                                }
+                            </div>
+                        </div>
+                        <div class={styles.cellBox}>
+                            <div class={styles.tit}>转谱</div>
+                            <div class={styles.radioBox}>
+                                {
+                                    [{name:'五线谱',value:'staff'},{name:'首调',value:'firstTone'},{name:'固定谱',value:'fixedTone'}].map(item=>{
+                                        return <div class={ state.musicRenderType===item.value && styles.active } onClick={ ()=>{ state.musicRenderType = item.value as any} }>{item.name}</div>
+                                    })
+                                }
+                            </div>
+                        </div>
+                        <div class={styles.cellBtnBox}>
+                            <img  src={headImg("tpbz.png")} />
+                            <img  src={headImg("yjfk.png")} />
+                        </div>
+                    </div>  
+                </div>
 			</div>
 		);
 	},

+ 235 - 0
src/page-instrument/header-top/settting1/index.module.less

@@ -0,0 +1,235 @@
+.header-settting {
+    position: relative;
+}
+
+.content {
+    position: relative;
+    overflow: hidden;
+    border-radius: 16PX;
+    width: 300px;
+    height: 86vh;
+    background-color: #fff;
+    max-height: 340px;
+    --van-tabs-line-height: 50px;
+    --van-tab-active-text-color: var(--van-primary-color);
+
+    :global {
+        .van-tab__panel {
+            position: relative;
+            height: calc(86vh - 50px);
+            max-height: calc(340px - 50px);
+            overflow-y: auto;
+            padding: 0 20px 10px 20px;
+
+            &::-webkit-scrollbar {
+                width: 0;
+                display: none;
+            }
+        }
+
+        .van-tabs__nav--line {
+            padding-bottom: 0;
+        }
+
+        .van-tabs__wrap::after {
+            display: none;
+        }
+
+        .van-tabs__line {
+            width: 18px;
+            bottom: 8px;
+        }
+
+        .van-cell {
+            padding-left: 0;
+            padding-right: 0;
+
+            &:after {
+                left: 0;
+                right: 0;
+                border-color: #F0F0F0;
+            }
+        }
+
+        .van-switch {
+            width: 46px;
+            height: 23px;
+            background-color: transparent !important;
+            background-image: url('../image/off.svg');
+            background-repeat: no-repeat;
+            background-size: 100% 100%;
+            background-position: center;
+            border-radius: 0;
+
+            &.van-switch--on {
+                background-image: url('../image/on.svg');
+            }
+
+            .van-switch__node {
+                display: none;
+            }
+        }
+
+        .van-notice-bar__content {
+            font-size: 12px;
+        }
+    }
+
+    &.pcContent {
+        height: 230px;
+        .pcDragTop {
+            position: absolute;
+            left: 0;
+            top: 0;
+            width: 100%;
+            height: 20px;
+            z-index: 1;
+            cursor: move;
+        }
+        :global {
+            .van-tab__panel {
+                height: 180px;
+            } 
+        }
+    }
+}
+
+.noticebar {
+    border-radius: 6px;
+    background: linear-gradient(45deg, #FFF6EE, #FFECDD);
+    color: #FEAD15;
+}
+
+.reactionTime {
+    :global {
+        .van-cell__title {
+            width: 60%;
+        }
+
+        .van-cell__value {
+            text-align: right;
+        }
+    }
+}
+
+.radioGroup {
+    display: flex;
+    align-items: center;
+    border-radius: 14px;
+    background: linear-gradient(180deg, #5BECFF, #259CFE);
+    padding: 4px;
+
+    :global {
+        .van-radio {
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            height: 22px;
+            margin: 0 3px;
+            border-radius: 6px;
+            padding: 0 4px;
+        }
+
+        .van-radio__icon {
+            display: none;
+        }
+
+        .van-radio__label {
+            margin: 0 auto;
+            font-size: 10px;
+            color: #fff;
+            font-weight: bold;
+            white-space: nowrap;
+            text-align: center;
+        }
+
+        .van-radio[aria-checked='true'] {
+            background: linear-gradient(180deg, #FFFFFF, #DAF1FF);
+            box-shadow: 0px 0px 1px 0px #DAF1FF;
+
+            .van-radio__label {
+                color: var(--van-primary-color);
+                font-weight: bold;
+            }
+        }
+    }
+}
+
+.sliderWrap {
+    :global {
+        .var-cell__extra {
+            flex: 2;
+        }
+    }
+}
+
+.slider {
+    width: 60%;
+    margin-right: 20px;
+
+    .sliderBtn {
+        width: 40px;
+        color: #fff;
+        font-size: 12px;
+        line-height: 20px;
+        text-align: center;
+        background-color: var(--van-primary-color);
+        border-radius: 20px;
+    }
+}
+.sliderVolume {
+    width: 55%;
+}
+.btnsbar {
+    position: absolute;
+    bottom: 12px;
+    left: 0;
+    width: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: space-evenly;
+
+    .btn {
+        display: flex;
+        justify-content: space-evenly;
+        align-items: center;
+        width: 42%;
+        height: 30px;
+        padding: 0 6px;
+        border-radius: 6px;
+        font-size: 10px;
+        background: #fff6e8;
+        color: #6c442d;
+        border: none;
+        white-space: nowrap;
+        & > img {
+            width: 22px;
+            height: 22px;
+        }
+        &:active {
+            opacity: .8;
+        }
+    }
+}
+
+.disabled{
+    opacity: .3;
+    pointer-events: none;
+}
+
+.operateHz {
+    display: flex;
+    align-items: center;
+    font-size: 14px;
+    color: var(--van-primary-color);
+    font-weight: 500;
+    img {
+        width: 28px;
+        height: 28px;
+    }
+    span {
+        margin: 0 6px;
+        width: 50px;
+        text-align: center;
+    }
+}

+ 330 - 0
src/page-instrument/header-top/settting1/index.tsx

@@ -0,0 +1,330 @@
+import { defineComponent, nextTick, reactive, watch, toRef } from "vue";
+import styles from "./index.module.less";
+import iconClose from "../image/close2.svg";
+import {
+	Cell,
+	Field,
+	NoticeBar,
+	Popup,
+	Radio,
+	RadioGroup,
+	Slider,
+	Switch,
+	Tab,
+	Tabs,
+	closeToast,
+	showLoadingToast,
+	showToast,
+} from "vant";
+import state, { IPlatform } from "/src/state";
+import { api_closeCamera, api_openCamera, api_savePicture } from "/src/helpers/communication";
+
+import iconInfo from "../image/info.svg";
+import iconDown from "../image/down.svg";
+import iconTv from "../image/tv.svg";
+import iconYijian from "../image/yijian.svg";
+import iconSubtract from "../image/subtract.png";
+import iconAdd from "../image/add.png";
+import ScreenModel from "../../custom-plugins/helper-model/screen-model";
+import Recommendation from "../../custom-plugins/helper-model/recommendation";
+import { svg2canvas } from "/src/utils/svg2canvas";
+import { getQuery } from "/src/utils/queryString";
+import { browser } from "/src/utils";
+import { storeData } from "/src/store";
+import useDrag from "/src/view/plugins/useDrag/index";
+import Dragbom from "/src/view/plugins/useDrag/dragbom";
+import { setGuidance } from "/src/page-instrument/custom-plugins/guide-page/api";
+
+export default defineComponent({
+	name: "header-settting",
+	setup() {
+		const query = getQuery();
+		const helperData = reactive({
+			show: false,
+			recommendationShow: false, // 建议
+		});
+		const downPng = () => {
+			showLoadingToast({ message: "下载中", duration: 0 });
+			setTimeout(async () => {
+				const svg: any = document.getElementById("osmdSvgPage1")?.cloneNode(true);
+				if (!svg) return showToast({ message: "保存失败", type: "fail" });
+				const cw = svg.width.animVal.value;
+				const ch = svg.height.animVal.value;
+				const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
+				rect.setAttribute("x", "0");
+				rect.setAttribute("y", "0");
+				rect.setAttribute("width", `${cw * 2}`);
+				rect.setAttribute("height", `${ch * 2}`);
+				rect.setAttribute("fill", "#fff");
+				svg.prepend(rect);
+				if (svg) {
+					const _canvas = svg2canvas(svg.outerHTML);
+					const browserInfo = browser();
+					if (state.platform === IPlatform.PC || !browserInfo.isApp) {
+						let el: any = document.createElement("a");
+						// 设置 href 为图片经过 base64 编码后的字符串,默认为 png 格式
+						el.href = _canvas.toDataURL();
+						el.download = state.examSongName;
+
+						// 创建一个点击事件并对 a 标签进行触发
+						const event = new MouseEvent("click");
+						el.dispatchEvent(event);
+						setTimeout(() => {
+							showToast({ message: "保存成功", type: "success" });
+							el = null;
+						}, 300);
+					} else {
+						const base64 = _canvas.toDataURL("image/png", 1);
+						const res = await api_savePicture({
+							base64,
+						});
+						if (res?.content?.status === "success") {
+							showToast({ message: "保存成功", type: "success" });
+						} else {
+							showToast({ message: "保存失败", type: "fail" });
+						}
+					}
+				}
+			}, 500);
+		};
+
+		const formatterTimeMs = (value: any) => value = String(Math.min(3000, value));
+		// 加减评测频率
+		const operateHz = (type: number) => {
+			const minFrequency = state.baseFrequency - 10, maxFrequency = state.baseFrequency + 10
+			let currentFrequency = state.setting.frequency
+			if (type === 1) {
+				if (currentFrequency - 1 < minFrequency) return showToast({ message: `最低标准音高${minFrequency}HZ` })
+				currentFrequency = currentFrequency - 1
+			} else {
+				if (currentFrequency + 1 > maxFrequency) return showToast({ message: `最高标准音高${maxFrequency}HZ` })
+				currentFrequency = currentFrequency + 1
+			}
+			state.setting.frequency = currentFrequency >= 0 ? currentFrequency : 0
+		}
+
+		const parentClassName = "recommenBoxClass_drag";
+		const userId = storeData.user?.id ? String(storeData.user?.id) : '';
+		const positionInfo = state.platform !== IPlatform.PC ? {
+			styleDrag: { value: null }
+		  } : useDrag(
+		  [
+			`${parentClassName} .top_drag`,
+			`${parentClassName} .bom_drag`
+		  ],
+		  parentClassName,
+		  toRef(helperData, 'recommendationShow'),
+		  userId
+		)
+	    // 完成拖动弹窗引导页
+		const handleGuide = async () => {
+			state.guideInfo.teacherDrag = true;
+				  try{
+					  const res = await setGuidance({guideTag:'guideInfo',guideValue:JSON.stringify(state.guideInfo)})
+			}catch(e){
+			  console.log(e)
+			}   
+		}
+
+		return () => (
+			<div class={styles["header-settting"]}>
+				<div class={[styles.content, state.platform === IPlatform.PC && styles.pcContent]}>
+				{ state.platform === IPlatform.PC && <div class={'top_drag'}></div> }
+					<Tabs border animated swipeable>
+						<Tab title="全局设置">
+							<NoticeBar
+								class={styles.noticebar}
+								left-icon={iconInfo}
+								text="全局设置会更改所有乐谱练习及评测"
+							/>
+							<Cell title="护眼模式" center>
+								{{
+									extra: () => <Switch v-model={state.setting.eyeProtection}></Switch>,
+								}}
+							</Cell>
+							{/* 节拍器 音量注释掉了  这里的代码也一并注释了 state.setting.beatVolume = state.setting.beatVolume || 50 */}
+							{/* <Cell
+								title="节拍器音量"
+								class={styles.sliderWrap}
+								center
+							>
+								{{
+									extra: () => (
+										<Slider
+											class={[styles.slider, styles.sliderVolume]}
+											min={0}
+											max={100}
+											v-model:modelValue={state.setting.beatVolume}
+										>
+											{{
+												button: () => <div class={styles.sliderBtn}>{state.setting.beatVolume}</div>,
+											}}
+										</Slider>
+									),
+								}}
+							</Cell>							 */}
+							<div class={styles.btnsbar}>
+								{/* <div class={styles.btn} onClick={downPng}>
+									<img src={iconDown} />
+									下载曲谱
+								</div> */}
+								<div class={styles.btn} onClick={() => (helperData.show = true)}>
+									<img src={iconTv} />
+									投屏帮助
+								</div>
+								<div class={styles.btn} onClick={() => (helperData.recommendationShow = true)}>
+									<img src={iconYijian} />
+									意见反馈
+								</div>
+							</div>
+						</Tab>
+						<Tab title="练习设置">
+							<Cell title="循环播放" center>
+								{{
+									extra: () => <Switch v-model={state.setting.repeatAutoPlay}></Switch>,
+								}}
+							</Cell>
+							<Cell class={[state.modeType == "evaluating" && styles.disabled]} title="显示指法" center>
+								{{
+									extra: () => <Switch v-model={state.setting.displayFingering} disabled={!state.fingeringInfo.name || !state.isShowFingering}></Switch>,
+								}}
+							</Cell>
+						</Tab>
+						<Tab title="评测设置">
+							<Cell class={[query.workRecord && styles.disabled]} title="评测难度" center>
+								{{
+									extra: () => (
+										<RadioGroup
+											iconSize={20}
+											class={styles.radioGroup}
+											v-model={state.setting.evaluationDifficulty}
+										>
+											<Radio name="BEGINNER">入门</Radio>
+											<Radio name="ADVANCED">进阶</Radio>
+											<Radio name="PERFORMER">大师</Radio>
+										</RadioGroup>
+									),
+								}}
+							</Cell>
+
+							<Cell title="延迟检测" center>
+								{{
+									extra: () => <Switch v-model={state.setting.soundEffect}></Switch>,
+								}}
+							</Cell>
+							<Cell title="摄像头" center>
+								{{
+									extra: () => (
+										<Switch
+											v-model={state.setting.camera}
+											onChange={ async (value) => {
+												if (value) {
+													const res = await api_openCamera();
+													// 没有授权
+													if (res?.content?.reson) {
+														state.setting.camera = false
+													}
+												} else {
+													api_closeCamera();
+												}
+											}}
+										></Switch>
+									),
+								}}
+							</Cell>
+							<Cell
+								style={{ display: state.setting.camera ? "" : "none" }}
+								title="透明度"
+								class={styles.sliderWrap}
+								center
+							>
+								{{
+									extra: () => (
+										<Slider
+											class={styles.slider}
+											min={0}
+											max={100}
+											v-model:modelValue={state.setting.cameraOpacity}
+										>
+											{{
+												button: () => <div class={styles.sliderBtn}>{state.setting.cameraOpacity}</div>,
+											}}
+										</Slider>
+									),
+								}}
+							</Cell>
+							{/* <Cell title="保存到相册" center>
+								{{
+									extra: () => <Switch v-model={state.setting.saveToAlbum}></Switch>,
+								}}
+							</Cell> */}
+							<Cell title="开启伴奏" center>
+								{{
+									extra: () => <Switch v-model={state.setting.enableAccompaniment}></Switch>,
+								}}
+							</Cell>
+							<Cell title="标准音高" center>
+								{/* {{
+									extra: () => (
+										<RadioGroup
+											iconSize={20}
+											class={styles.radioGroup}
+											v-model={state.setting.frequency}
+										>
+											<Radio name={440}>440Hz</Radio>
+											<Radio name={442}>442Hz</Radio>
+										</RadioGroup>
+									),
+								}} */}
+								{{
+									extra: () => (
+										<div class={styles.operateHz}>
+											<img src={iconSubtract} onClick={() => operateHz(1)} />
+											<span>{state.setting.frequency}HZ</span>
+											<img src={iconAdd} onClick={() => operateHz(2)} />
+										</div>
+									)
+								}}
+							</Cell>
+
+							<Field class={styles.reactionTime} label="反应时间(毫秒)" type="digit" 
+								placeholder="最大可输入3000毫秒"
+								formatter={formatterTimeMs}
+								v-model:modelValue={state.setting.reactionTimeMs} />
+						</Tab>
+					</Tabs>
+				</div>
+				<Popup
+					class={["popup-custom", styles.screen]}
+					v-model:show={helperData.show}
+					onClose={() => {
+						helperData.show = false;
+					}}
+					position="right"
+					teleport="body"
+				>
+					<ScreenModel
+						onClose={(open: Boolean) => {
+							helperData.show = false;
+						}}
+					/>
+				</Popup>
+				<Popup
+					v-model:show={helperData.recommendationShow}
+					class="popup-custom van-scale center-closeBtn recommenBoxClass_drag"
+					transition="van-scale"
+					teleport="body"
+					closeable
+					style={positionInfo.styleDrag.value}
+				>
+					<Recommendation
+						onClose={() => {
+							helperData.recommendationShow = false;
+						}}
+					/>
+					{ state.platform === IPlatform.PC && <Dragbom showGuide={!state.guideInfo?.teacherDrag} /> }
+				</Popup>
+			</div>
+		);
+	},
+});

+ 149 - 40
src/page-instrument/header-top/speed/index.module.less

@@ -1,42 +1,151 @@
-.speedContainer {
-  position: relative;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  background-color: #fff;
-  padding: 4px;
-}
-
-.btn {
-  width: 30px;
-  height: 30px;
-  border: none;
-  background-color: transparent;
-  padding: 0;
-  font-size: 18px;
-}
-
-.slider {
-  width: 4px;
-  height: 40vh;
-  margin: 10px 0;
-
-  :global {
-    .van-slider__bar {
-      background: #FFD571;
+.speedContainer{
+    .head{
+        background: url("../image/headImg.png") no-repeat;
+        background-size: 100% 100%;
+        width: 372px;
+        height: 57px;
+        position: relative;
+        .headTit{
+            position: absolute;
+            bottom: 9px;
+            left: 50%;
+            transform: translateX(-50%);
+            width: 95px;
+            height: 20px;
+        }        
+        .closeImg{
+            position: absolute;
+            top: 0;
+            right: -38px;
+            width: 32px;
+            height: 32px;
+            cursor: pointer;
+        }
+    }
+    .content{
+        width: 354px;
+        height: 225px;
+        background: #B0D8FF;
+        box-shadow: 0px 4px 0px 0px #7AAEE0;
+        border-radius: 0px 0px 24px 24px;
+        margin: 0 auto;
+        padding: 10px;
+        .conBox{
+            width: 100%;
+            height: 100%;
+            background: #EAF2FB;
+            border-radius: 12px;
+            overflow-y: auto;
+            padding: 12px 16px 0;
+            &::-webkit-scrollbar {
+                width: 0;
+                display: none;
+            }
+            .tit{
+                font-weight: 600;
+                font-size: 15px;
+                color: #000000;
+                line-height: 21px;
+            }
+            .spendCon{
+                margin-top: 20px;
+                display: flex;
+                align-items: center;
+                padding: 3px 0;
+                .btn{
+                    width: 24px;
+                    height: 24px;
+                    flex-shrink: 0;
+                    cursor: pointer;
+                }
+                .sliderCon{
+                    padding: 0 18px;
+                    flex-grow: 1;
+                    :global{
+                        .van-slider{
+                            height: 10px;
+                            background: #94ACC4;
+                            box-shadow: inset 0px 2px 3px 0px #647F98;
+                            .van-slider__bar{
+                                background: linear-gradient( 270deg, #7ADEFF 0%, #29A9FF 100%);
+                                box-shadow: inset 1px 0px 5px 0px rgba(150,254,255,0.79);
+                                border: 1px solid #4A91D4;
+                                .van-slider__button-wrapper{
+                                    bottom: 0;
+                                    top: initial;
+                                    transform: translate3d(50%,12px,0);
+                                }
+                            }
+                        }
+                    }
+                    .customButton{
+                        display: flex;
+                        flex-direction: column;
+                        align-items: center;
+                        .speedVal{
+                            width: 34px;
+                            height: 31px;
+                            background: url("../image/qipao.png") no-repeat;
+                            background-size: 100% 100%;
+                            font-weight: 600;
+                            font-size: 14px;
+                            color: #FFFFFF;
+                            line-height: 20px;
+                            text-align: center;
+                            padding-top: 3px;
+                        }
+                        .speedBtn{
+                            width: 16px;
+                            height: 30px;
+                            background: url("../image/speedBtn.png") no-repeat;
+                            background-size: 100% 100%;
+                        }
+                    }
+                }
+            }
+            .speedSel{
+                margin-top: 20px;
+                padding-bottom: 18px;
+                border-bottom: 1px solid #D5E0ED;
+                display: flex;
+                justify-content: space-between;
+                & > div{
+                    padding: 3px 13px;
+                    background: #FFFFFF;
+                    border-radius: 14px;
+                    font-weight: 400;
+                    font-size: 13px;
+                    color: rgba(0,0,0,0.6);
+                    line-height: 18px;
+                    cursor: pointer;
+                    &:active{
+                        background: linear-gradient( 131deg, #44CAFF 0%, #259CFE 100%);
+                    }
+                }
+            }
+            .metronome{
+                margin-top: 18px;
+                display: flex;
+                justify-content: space-between;
+                align-items: center;
+                :global{
+                    .van-switch{
+                        width: 42px;
+                        height: 21px;
+                        background-color: transparent!important;
+                        background-image: url("../image/guan.png");
+                        background-repeat: no-repeat;
+                        background-size: 100% 100%;
+                        border-radius: 0;
+                        &.van-switch--on{
+                            background-image: url("../image//kai.png");
+                        }
+                        .van-switch__node{
+                            display: none;
+                        }
+                    }
+                }
+            }
+        }
     }
-  }
-}
-
-.customButton {
-  width: 30px;
-  border-radius: 9px;
-  box-shadow: 0 5px 10px rgba(0, 0, 0, .1);
-  background: linear-gradient(180deg, #FFF884 0%, #FFC850 100%);
-  font-size: 11px;
-  font-weight: 500;
-  color: #135D4F;
-  line-height: 17px;
-  border: 1px solid #FFFFFF;
-  text-align: center;
 }

+ 52 - 36
src/page-instrument/header-top/speed/index.tsx

@@ -1,17 +1,15 @@
-import { defineComponent, reactive, ref, watch } from "vue";
-import { Button, Slider } from "vant";
-import styles from "./index.module.less";
+import { computed, defineComponent, ref, watch } from "vue";
+import { Switch, Slider } from "vant";
+import styles from "./index.module.less"
+import { headData } from "../index" 
 import { headImg } from "../image";
 import state, { handleSetSpeed } from "../../../state";
-import { useClickAway } from "@vant/use";
-import { headData } from "..";
+import { metronomeData } from "../../../helpers/metronome"; 
 
 export default defineComponent({
 	name: "speed",
-	setup(props) {
-		const speed = reactive({
-			value: state.speed,
-		});
+	setup() {
+		const speed = ref(state.speed);
 
 		const minusSpeed = () => {
 			speed.value = Math.max(speed.value - 1, 45);
@@ -20,40 +18,58 @@ export default defineComponent({
 		const plusSpeed = () => {
 			speed.value = Math.min(speed.value + 1, 270);
 		};
-
-		/** 重置速度 */
-		const resetSpeed = () => {
-			speed.value = Math.floor(state.originSpeed);
-		};
-
 		watch(
 			() => speed.value,
 			() => {
 				handleSetSpeed(speed.value);
-				// if ( Math.abs(Number(speed.value) - Number(state.speed)) >= 1 ) {
-				// 	speed.value = Math.floor(speed.value)
-				// 	handleSetSpeed(speed.value);
-				// } else {
-				// 	//speed.value = state.speed;
-				// }
 			}
 		);
-
-		const speedRef = ref();
-		useClickAway(speedRef, () => {
-			headData.speedShow = false;
-		});
-
+		const metronomeDisable = computed({
+			get(){
+				return !metronomeData.disable
+			},
+			set(val){
+				metronomeData.disable = !val
+			}
+		})
 		return () => (
-			<div class={styles.speedContainer} ref={speedRef}>
-				<Button class={styles.btn} icon={headImg("icon_plus.svg")} disabled={state.speed == 270} onClick={plusSpeed} />
-				<Slider class={styles.slider} max={270} min={45} vertical v-model={speed.value} reverse>
-					{{
-						button: () => <div class={styles.customButton}>{speed.value}</div>,
-					}}
-				</Slider>
-				<Button class={styles.btn} icon={headImg("icon_minus.svg")} disabled={state.speed == 45} onClick={minusSpeed} />
-				<Button class={styles.btn} icon={headImg("icon_speedRest.svg")} onClick={resetSpeed} />
+			<div class={styles.speedContainer}>
+				<div class={styles.head}>
+					<img class={styles.headTit} src={headImg("headTit.png")} />
+					<img class={styles.closeImg} src={headImg("closeImg.png")} onClick={()=>{ headData.speedShow = false }} />
+				</div>
+				<div class={styles.content}>
+					<div class={styles.conBox}>
+						<div class={styles.tit}>速度</div>
+						<div class={styles.spendCon}>
+							<img src={headImg("cutImg.png")} class={[styles.btn]} onClick={minusSpeed} />
+							<div class={styles.sliderCon}>
+								<Slider class={styles.slider} max={270} min={45} v-model={speed.value}>
+									{{
+										button: () => 
+										<div class={styles.customButton}>
+											<div class={styles.speedVal}>{ speed.value }</div>
+											<div class={styles.speedBtn}></div>
+										</div>
+									}}
+								</Slider>
+							</div>
+							<img src={headImg("addImg.png")} class={[styles.btn]} onClick={plusSpeed} />	
+						</div>
+						<div class={styles.speedSel}>
+							<div onClick={()=>{ speed.value = state.originSpeed }}>原速</div>
+							<div onClick={()=>{ speed.value = 70 }}>70</div>
+							<div onClick={()=>{ speed.value = 80 }}>80</div>
+							<div onClick={()=>{ speed.value = 90 }}>90</div>
+							<div onClick={()=>{ speed.value = 100 }}>100</div>
+							<div onClick={()=>{ speed.value = 110 }}>110</div>
+						</div>
+						<div class={styles.metronome}>
+							<div class={styles.tit}>节拍器</div>
+							<Switch v-model={metronomeDisable.value}></Switch>
+						</div>
+					</div>
+				</div>
 			</div>
 		);
 	},

+ 1 - 37
src/page-instrument/view-detail/index.module.less

@@ -28,7 +28,7 @@
         width: 100%;
         height: var(--header-height);
         transition: all .3s;
-        z-index: 10;
+        z-index: 99;
 
         &.headHide {
             margin-bottom: calc(0Px - var(--header-height));
@@ -222,40 +222,4 @@
     100% {
         transform: translateY(0%);
     }
-}
-
-.modeView {
-    position: fixed;
-    z-index: 99;
-    top: 0;
-    left: 0;
-    width: 100vw;
-    height: 100vh;
-    background: url(./images/bg.png) no-repeat;
-    background-size: 100% 100%;
-    .back {
-        position: absolute;
-        width: 38px;
-        height: 38px;
-        left: 27px;
-        top: 17px;
-    }
-    .name {
-        position: absolute;
-        left: 50%;
-        top: 23px;
-        transform: translateX(-50%);
-        width: 87px;
-        height: 21px;
-    }
-    .modeBox {
-        width: 100%;
-        margin-top: 90px;
-        display: flex;
-        justify-content: space-between;
-        padding: 0 36px;
-        > img {
-            width: calc((100% - 2*40px)/3);
-        }
-    }
 }

+ 1 - 5
src/page-instrument/view-detail/index.tsx

@@ -9,7 +9,7 @@ import MusicScore, { resetMusicScore } from "../../view/music-score";
 import TestCheck from "/src/view/music-score/testCheck";
 import { sysMusicScoreAccompanimentQueryPage } from "../api";
 import EvaluatModel from "../evaluat-model";
-import HeaderTop, { headTopData } from "../header-top";
+import HeaderTop from "../header-top";
 import styles from "./index.module.less";
 import { api_cloudAccompanyMessage, api_cloudLoading, api_keepScreenLongLight, api_openCamera, api_openWebView, api_setEventTracking, api_setRequestedOrientation, api_setStatusBarVisibility, isSpecialShapedScreen } from "/src/helpers/communication";
 import { getQuery } from "/src/utils/queryString";
@@ -33,8 +33,6 @@ import { usePageVisibility } from "@vant/use";
 import { initMidi } from "/src/helpers/midiPlay"
 import TheAudio from "/src/components/the-audio"
 import tickWav from "/src/assets/tick.mp3";
-import Title from "../header-top/title";
-import ModeView from "./modeView"
 
 const DelayCheck = defineAsyncComponent(() =>
   import('/src/page-instrument/evaluat-model/delay-check')
@@ -498,8 +496,6 @@ export default defineComponent({
             {state.playState == "play" || followData.start || evaluatingData.startBegin || query.workRecord || query.modelType || state.platform === IPlatform.PC || query.isCbs ? null : <TheMusicList />}
           </>
         )}
-        {/* 模式切换 */}
-        { headTopData.modeType === "init" && <ModeView></ModeView>}
         <Popup
           zIndex={5050}
           teleport="body"

+ 0 - 25
src/page-instrument/view-detail/modeView.tsx

@@ -1,25 +0,0 @@
-import { defineComponent } from "vue"
-import styles from "./index.module.less"
-import backImg from "./images/back.png"
-import nameImg from "./images/zt.png"
-import lxImg from "./images/lx.png"
-import glImg from "./images/gl.png"
-import pcImg from "./images/pc.png"
-import { headTopData } from "../header-top"
-
-export default defineComponent({
-   name: "modeView",
-   setup() {
-      return () => (
-         <div class={styles.modeView}>
-            <img src={backImg} class={styles.back} />
-            <img src={nameImg} class={styles.name} />
-            <div class={styles.modeBox}>
-               <img src={lxImg} class={styles.modeImg} onClick={() => headTopData.handleChangeModeType("practise")} />
-               <img src={glImg} class={styles.modeImg} onClick={() => headTopData.handleChangeModeType("follow")} />
-               <img src={pcImg} class={styles.modeImg} onClick={() => headTopData.handleChangeModeType("evaluating")} />
-            </div>
-         </div>
-      )
-   }
-})

+ 3 - 1
src/state.ts

@@ -373,7 +373,9 @@ const state = reactive({
     /** 反应时间 */
     reactionTimeMs: 0,
     /** 节拍器音量 */
-    beatVolume: 50,
+    beatVolume: 50,    
+    /** 旋律线是否显示 */
+    melodyLine: true
   },
   /** 后台设置的基准评测频率 */
   baseFrequency: 440,