瀏覽代碼

Merge branch 'feature-tianyong-newVersion' into kt-dev

TIANYONG 1 年之前
父節點
當前提交
8f50789bf8

+ 2 - 1
src/helpers/customMusicScore.ts

@@ -536,10 +536,11 @@ export const resetFormate = () => {
 		// 给小节添加背景色
 		staves.forEach((stave: any) => {
 			const list = [
+				Array.from(stave?.querySelectorAll(".vf-StaveSection") || []),
+				Array.from(stave?.querySelectorAll(".vf-Volta") || []),
 				Array.from(stave?.querySelectorAll(".vf-clef") || []),
 				Array.from(stave?.querySelectorAll(".vf-keysignature") || []),
 				Array.from(stave?.getElementsByTagName("text") || []),
-				Array.from(stave?.querySelectorAll(".vf-StaveSection") || []),
 			].flat();
 			try {
 				if (list.length) {

+ 1 - 1
src/helpers/formateMusic.ts

@@ -1224,7 +1224,7 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 				nodeDetail.endtime = nodeDetail.endtime + currentWaitTime;
 				usetime = usetime + currentWaitTime;
 				relativeTime = relativeTime + currentWaitTime;
-			}			
+			}		
 			nodeDetail.realKey = formatRealKey(note.halfTone - fixedKey * 12, nodeDetail);
 			nodeDetail.duration = nodeDetail.endtime - nodeDetail.time;
 			let tickables = activeVerticalMeasureList[0]?.vfVoices["1"]?.tickables || [];

二進制
src/page-instrument/header-top/image/sj.png


二進制
src/page-instrument/header-top/image/speed.png


+ 32 - 7
src/page-instrument/header-top/index.module.less

@@ -30,6 +30,21 @@
                 font-weight: 600;
                 font-size: 18px;
                 color: #FFFFFF;
+                .van-notice-bar__content{
+                    position: relative;
+                    padding-right: 16px;
+                    &::after{
+                        position: absolute;
+                        top: 50%;
+                        right: 0;
+                        transform: translateY(-50%);
+                        content: "";
+                        width: 11px;
+                        height: 6px;
+                        background: url("./image/sj.png") no-repeat;
+                        background-size: 100% 100%;                         
+                    }
+                }
             }
         }
     }
@@ -69,7 +84,7 @@
         flex-direction: column;
         align-items: center;
         cursor: pointer;
-        margin-right: 40px;
+        margin-right: 30px;
         &:last-child{
             margin-right: 0;
         }
@@ -88,23 +103,25 @@
     .metronomeBtn{
         position: relative;
         .speedCon{
-            padding: 1px 2px;
+            transform: scale(0.83);
+            transform-origin: left bottom;
+            padding: 2px;
             position: absolute;
             left: 14px;
-            top: -4px;
+            top: -9px;
             display: flex;
             align-items: center;
             background: #FFC121;
-            border-radius: 100px 100px 100px 1px;
+            border-radius: 120px 120px 120px 1px;
             border: 1px solid #FFFFFF;
             >img{
-                width: 12px;
-                height: 10px;
+                width: 15px;
+                height: 11px;
             }
             >div{
                 margin-left: 1px;
                 font-weight: 600;
-                font-size: 10px;
+                font-size: 12px;
                 color: #673207;
                 line-height: 1;
             }
@@ -216,6 +233,7 @@
         height: 38px;
         left: 27px;
         top: 17px;
+        cursor: pointer;
     }
     .name {
         position: absolute;
@@ -231,8 +249,15 @@
         display: flex;
         justify-content: space-between;
         padding: 0 36px;
+        &.twoModeBox{
+            justify-content: center;
+            > img + img{
+                margin-left: 150px;
+            }
+        }
         > img {
             width: calc((100% - 2*40px)/3);
+            max-width: 220px;
         }
     }
 }

+ 15 - 12
src/page-instrument/header-top/index.tsx

@@ -519,18 +519,21 @@ export default defineComponent({
             }
           </div>
           {/* 模式切换 */}
-          <div 
-            id={state.platform === IPlatform.PC ? "teacherTop-0" : "studnetT-0"}
-            style={{ display: toggleBtn.value.display ? "" : "none" }}
-            class={[styles.modeChangeBox, toggleBtn.value.disabled && styles.disabled]} 
-            onClick={() => {
-                handleRessetState();
-                headTopData.modeType = "init";
-            }}
-          >
-            <img class={styles.img} src={iconMode} />
-            <div class={styles.title}>{state.modeType==="practise" ? '练习模式' : state.modeType==="follow" ? "跟练模式" : state.modeType==="evaluating" ? "评测模式" : ""}</div>
-          </div>
+            { 
+            state.playType === "play" &&
+              <div 
+                id={state.platform === IPlatform.PC ? "teacherTop-0" : "studnetT-0"}
+                style={{ display: toggleBtn.value.display ? "" : "none" }}
+                class={[styles.modeChangeBox, toggleBtn.value.disabled && styles.disabled]} 
+                onClick={() => {
+                    handleRessetState();
+                    headTopData.modeType = "init";
+                }}
+              >
+                <img class={styles.img} src={iconMode} />
+                <div class={styles.title}>{state.modeType==="practise" ? '练习模式' : state.modeType==="follow" ? "跟练模式" : state.modeType==="evaluating" ? "评测模式" : ""}</div>
+              </div>
+          }
           {/* 功能按钮 */}
           <div
             class={[styles.headRight]}

+ 24 - 16
src/page-instrument/header-top/modeView.tsx

@@ -7,17 +7,11 @@ 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";
-
-
-/* todo */
-/*
-   打击乐和节奏练习 模式可能不是3个 到时候根据字段来判断
- */
+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",
@@ -26,7 +20,7 @@ export default defineComponent({
       const data = reactive({
          showPC: false,
          showStudent: false,
-         showVip: false,
+         showVip: false
       })
       const openGuid = () => {
          // 加载后 判断 端口号 加载对应的引导
@@ -71,12 +65,26 @@ export default defineComponent({
       })
       return () => (
          <div class={[styles.modeView, headTopData.modeType !== "init" && styles.hidden]}>
-            <img src={backImg} class={styles.back} />
+            <img
+               src={backImg}
+               class={styles.back}
+               onClick={() => {
+                  headTopData.modeType = "show"
+               }}
+            />
             <img src={nameImg} class={styles.name} />
-            <div class={styles.modeBox}>
+            <div
+               class={[
+                  styles.modeBox,
+                  ((!state.isPercussion && !state.enableEvaluation) ||
+                     (state.isPercussion && state.enableEvaluation) ||
+                     (state.isPercussion && !state.enableEvaluation)) &&
+                     styles.twoModeBox
+               ]}
+            >
                <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")} />
+               {!state.isPercussion && <img src={glImg} class={styles.modeImg} onClick={() => headTopData.handleChangeModeType("follow")} />}
+               {state.enableEvaluation && <img src={pcImg} class={styles.modeImg} onClick={() => headTopData.handleChangeModeType("evaluating")} />}
             </div>
             {data.showVip && <TheVip />}
          </div>

+ 15 - 3
src/page-instrument/header-top/settting/index.tsx

@@ -3,9 +3,10 @@ import styles from "./index.module.less"
 import { headImg } from "../image";
 import { headTopData } from "../index"
 import { Switch, showToast, Field, Popup } from "vant";
-import state from "/src/state"
+import state, { refreshMusicSvg } from "/src/state"
 import { smoothAnimationState} from "/src/page-instrument/view-detail/smoothAnimation"
 import Recommendation from "../../custom-plugins/helper-model/recommendation";
+import { resetRenderMusicScore } from "/src/view/music-score";
 
 export default defineComponent({
 	name: "settting",
@@ -72,7 +73,13 @@ export default defineComponent({
                             <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>
+                                        return <div class={ state.isSingleLine===item.value && styles.active } onClick={ ()=>{ 
+                                            state.isSingleLine = item.value 
+                                            // resetRenderMusicScore(state.musicRenderType)
+                                            headTopData.settingMode = false
+                                            refreshMusicSvg();
+                                            // musicScoreRef.value?.refreshMusicScore()
+                                        } }>{item.name}</div>
                                     })
                                 }
                             </div>
@@ -82,7 +89,12 @@ export default defineComponent({
                             <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>
+                                        return <div class={ state.musicRenderType===item.value && styles.active } onClick={ ()=>{ 
+                                            state.musicRenderType = item.value as any
+                                            // resetRenderMusicScore(state.musicRenderType)
+                                            headTopData.settingMode = false
+                                            refreshMusicSvg();
+                                        } }>{item.name}</div>
                                     })
                                 }
                             </div>

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

@@ -64,9 +64,10 @@
         margin-top: -13PX;
         border-radius: 4Px;
         background-color: rgba(25, 140, 254, 0.7);
-        opacity: var(--corsor-opacity);
+        // opacity: var(--corsor-opacity);
         //transform: translateX(10PX);
         z-index: 1 !important;
+        opacity: 0; // 新版小酷AI不显示光标指针
     }
 
     .staff {

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

@@ -1,5 +1,5 @@
 import { Popup, Skeleton } from "vant";
-import { computed, defineComponent, nextTick, onBeforeMount, onBeforeUnmount, onMounted, reactive, Transition, watch, watchEffect, defineAsyncComponent } from "vue";
+import { computed, defineComponent, nextTick, onBeforeMount, onBeforeUnmount, onMounted, reactive, Transition, watch, watchEffect, defineAsyncComponent, ref } from "vue";
 import { formateTimes } from "../../helpers/formateMusic";
 import Metronome, { metronomeData } from "../../helpers/metronome";
 import state, { EnumMusicRenderType, evaluatCreateMusicPlayer, handleSetSpeed, IAudioState, IPlatform, isRhythmicExercises, resetPlaybackToStart, togglePlay, getMusicDetail, addNoteBBox } from "/src/state";
@@ -78,6 +78,8 @@ const setNoteHalfTone = (list: any[]) => {
   return list;
 };
 
+export const musicScoreRef = ref();
+
 export default defineComponent({
   name: "music-list",
   setup() {
@@ -228,8 +230,7 @@ export default defineComponent({
        * 设置节拍器,跟练需要播放系统节拍器,所以不需要判断needTick状态
        */
       // if (state.needTick) {
-        const beatLengthInMilliseconds = (60 / state.speed) * 1000;
-        handleInitTick(beatLengthInMilliseconds, osmd?.Sheet?.SheetPlaybackSetting?.Rhythm?.Numerator || 4);
+        handleInitTick(osmd?.Sheet?.SheetPlaybackSetting?.Rhythm?.Numerator || 4);
       // }
       // api_cloudLoading();
       state.playBtnDirection = query.imagePos === 'right' ? 'right' : 'left';
@@ -456,6 +457,7 @@ export default defineComponent({
           {/* 曲谱渲染 */}
           {!detailData.isLoading && 
             <MusicScore 
+              ref={musicScoreRef}
               musicColor={'#FFFFFF'}
               showPartNames={state.isCombineRender}
               onRendered={handleRendered} 

+ 0 - 3
src/page-instrument/view-detail/smoothAnimation/index.less

@@ -25,9 +25,6 @@
     #cursorImg-0 {
         display: none;
     }
-    // .staveBox {
-    //     display: none !important;
-    // }
     .authorName{
         position: fixed;
         left: 0;

+ 48 - 6
src/page-instrument/view-detail/smoothAnimation/index.ts

@@ -17,6 +17,8 @@ type smoothAnimationType = {
    smoothBotDom: null | HTMLElement
    osmdCanvasPageDom: null | HTMLElement
    osdmScrollDom: null | HTMLElement
+   osdmScrollDomWith: number
+   selectionBoxDom: null | HTMLElement
    pointsPos: pointsPosType
    translateXNum: number
    aveSpeed: number
@@ -35,6 +37,8 @@ export const smoothAnimationState = {
    smoothBotDom: null,
    osmdCanvasPageDom: null,
    osdmScrollDom: null,
+   osdmScrollDomWith: 0,
+   selectionBoxDom: null,
    pointsPos: [], // 计算之后的点坐标数组
    translateXNum: 0, // 当前谱面的translateX的距离   谱面的位置信息 由translateX和scrollLeft的偏移一起决定
    aveSpeed: 0, // 谱面的一帧的平均速度
@@ -45,7 +49,6 @@ export const smoothAnimationState = {
 watch(smoothAnimationState.isShow, () => {
    if (smoothAnimationState.isShow.value) {
       smoothAnimationState.smoothAnimationBoxDom?.classList.remove("smoothAnimationBoxHide")
-      moveSmoothAnimation(moveState.progress, moveState.activeIndex)
    } else {
       smoothAnimationState.smoothAnimationBoxDom?.classList.add("smoothAnimationBoxHide")
    }
@@ -82,6 +85,7 @@ export function initSmoothAnimation() {
  * 销毁
  */
 export function destroySmoothAnimation() {
+   smoothAnimationState.isShow.value = false
    document.removeEventListener("resize", calcClientWidth)
    smoothAnimationState.smoothAnimationBoxDom?.remove()
    Object.assign(smoothAnimationState, {
@@ -98,6 +102,11 @@ export function destroySmoothAnimation() {
       aveSpeed: 0,
       clientWidth: 0
    })
+   Object.assign(moveState, {
+      oldIndex: -1,
+      progress: 0,
+      activeIndex: 0
+   })
 }
 
 /**
@@ -106,7 +115,7 @@ export function destroySmoothAnimation() {
 export function moveSmoothAnimationByPlayTime() {
    const currentTime = getAudioCurrentTime()
    if (currentTime <= state.fixtime) return
-   if (currentTime > state.times.last()?.time) return
+   if (currentTime > state.times.last()?.endtime) return
    // 当休止小节,可能当前音符在谱面上没有实际的音符(没有bbox),所以往后找谱面上有的音符
    let nextIndex = state.activeNoteIndex + 1
    let nextBBox = state.times[nextIndex]?.bbox
@@ -114,8 +123,10 @@ export function moveSmoothAnimationByPlayTime() {
       nextIndex += 1
       nextBBox = state.times[nextIndex]?.bbox
    }
-   // 当前的音符和下一个音符之间的时值
-   const noteDuration = state.times[nextIndex].time - state.times[state.activeNoteIndex]?.time
+   // 当前的音符和下一个音符之间的时值 (当是最后一个音符的时候,下一个音符的时间取当前音符的endtime)
+   const noteDuration =
+      (nextIndex > state.times.length - 1 ? state.times[state.activeNoteIndex]?.endtime : state.times[nextIndex].time) -
+      state.times[state.activeNoteIndex]?.time
    // 当前时值在该区间的占比
    const playProgress = (currentTime - state.times[state.activeNoteIndex]?.time) / noteDuration
    moveSmoothAnimation(playProgress, state.activeNoteIndex)
@@ -159,6 +170,13 @@ export function moveSmoothAnimation(progress: number, activeIndex: number) {
       smoothAnimationState.pointsPos,
       smoothAnimationState.pointsPos.slice(0, nowIndex)
    )
+   // 当移动到屏幕最右边时候 就不进行移动了
+   if (
+      (smoothAnimationState.osdmScrollDom?.scrollLeft || 0) + smoothAnimationState.translateXNum + smoothAnimationState.osdmScrollDomWith >
+      smoothAnimationState.canvasDomWith
+   ) {
+      return
+   }
    move_osmd(nowPointsPos)
 }
 
@@ -213,7 +231,16 @@ function move_osmd(nowPointsPos: pointsPosType[0]) {
    } else if (midBotNum > clientMidWidth + clientWidth * 0.45 && midBotNum <= clientMidWidth + clientWidth * 0.5) {
       smoothAnimationState.translateXNum += speed * 5
    }
-   smoothAnimationState.osmdCanvasPageDom!.style.transform = `translateX(-${smoothAnimationState.translateXNum}px)`
+   moveTranslateXNum(smoothAnimationState.translateXNum)
+}
+
+/**
+ * 根据 translateXNum 滚动到位置
+ */
+
+export function moveTranslateXNum(translateXNum: number) {
+   smoothAnimationState.osmdCanvasPageDom && (smoothAnimationState.osmdCanvasPageDom.style.transform = `translateX(-${translateXNum}px)`)
+   smoothAnimationState.selectionBoxDom && (smoothAnimationState.selectionBoxDom.style.transform = `translateX(-${translateXNum}px)`)
 }
 
 /**
@@ -236,9 +263,15 @@ function createSmoothAnimation() {
    // osdmScrollDom
    const osdmScrollDom = document.querySelector("#musicAndSelection") as HTMLElement
    smoothAnimationState.osdmScrollDom = osdmScrollDom
+   smoothAnimationState.osdmScrollDomWith = osdmScrollDom?.offsetWidth | 0
    // osmdCanvasPage
    const osmdCanvasPageDom = document.querySelector("#osmdCanvasPage1") as HTMLElement
    smoothAnimationState.osmdCanvasPageDom = osmdCanvasPageDom
+   // selectionBox
+   setTimeout(() => {
+      const selectionBoxDom = document.querySelector("#selectionBox") as HTMLElement
+      smoothAnimationState.selectionBoxDom = selectionBoxDom
+   }, 0)
    // box
    const smoothAnimationBoxDom = document.createElement("div")
    smoothAnimationBoxDom.className = "smoothAnimationBox"
@@ -286,13 +319,22 @@ function getPointsPosByBatePos(): pointsPosType {
          posArr.push({
             MeasureNumberXML: item.MeasureNumberXML,
             x: item.bbox.x,
+            // 当为休止符的时候 取最下面的位置*0.9,确保能显示完整
             y:
-               ((((item.frequency === -1 ? totalAv : item.frequency) - totalAv) / totalAv) * smoothAnimationState.canvasDomHeight) / 2 +
+               ((((item.frequency === -1 ? 2 * totalAv * 0.9 : item.frequency) - totalAv) / totalAv) * smoothAnimationState.canvasDomHeight) / 2 +
                smoothAnimationState.canvasDomHeight / 2 // cavans 高度为160 所以基准为80
          })
       }
       return posArr
    }, [])
+   // 最后一个音符延长(这里建立一个虚拟的音符延长)
+   const extendPoint = {
+      ...pointsPos[pointsPos.length - 1]
+   }
+   extendPoint.MeasureNumberXML++
+   // 当总长度减30小于最后一个音符时候,取最后一个音符加15
+   extendPoint.x = smoothAnimationState.canvasDomWith - 30 > extendPoint.x ? smoothAnimationState.canvasDomWith - 30 : extendPoint.x + 15
+   pointsPos.push(extendPoint)
    return pointsPos
 }
 

+ 138 - 10
src/state.ts

@@ -15,9 +15,10 @@ import { getMusicSheetDetail } from "./utils/baseApi"
 import { getQuery } from "/src/utils/queryString";
 import { followData } from "/src/view/follow-practice/index"
 import { changeSongSourceByBate } from "/src/view/audio-list"
-import { moveSmoothAnimation, smoothAnimationState, moveSmoothAnimationByPlayTime} from "/src/page-instrument/view-detail/smoothAnimation"
+import { moveSmoothAnimation, smoothAnimationState, moveSmoothAnimationByPlayTime, moveTranslateXNum, destroySmoothAnimation} from "/src/page-instrument/view-detail/smoothAnimation"
 import { storeData } from "/src/store";
 import { downloadXmlStr } from "./view/music-score"
+import { musicScoreRef } from "/src/page-instrument/view-detail/index"
 
 const query: any = getQuery();
 
@@ -499,6 +500,8 @@ const state = reactive({
   musicComposer: '',
   /** 作词家 */
   musicLyricist: '',
+  /** 加载中的文案 */
+  loadingText: '音频资源加载中,请稍后…',
 });
 const browserInfo = browser();
 let offset_duration = 0;
@@ -895,6 +898,7 @@ export const gotoNext = (note: any, skipNote?: boolean) => {
       console.log(error);
     }
     // 重置 或者切换演奏演唱的时候 可能出现 state.activeNoteIndex === note.i的情况 执行
+    fillWordColor();
     if (state.isSingleLine && state.playState === "paused") {
       moveSvgDom(skipNote);
     }
@@ -928,6 +932,7 @@ export const gotoNext = (note: any, skipNote?: boolean) => {
   } catch (error) {
     console.log(error);
   }
+  fillWordColor();
   // 一行谱,需要滚动小节
   if (state.isSingleLine) {
     moveSvgDom(skipNote);
@@ -1126,7 +1131,7 @@ export const hanldeDirectSelection = (list: any[]) => {
   setTimeout(() => {
     state.section = formateSelectMearure(list);
     console.log('选段小节', state.section)
-  }, 500);
+  }, 0);
 };
 let offsetTop = 0;
 /**
@@ -1519,8 +1524,8 @@ export const addNoteBBox = (list: any[]) => {
 
 }
 
-/** 跳动svgdom */
-export const moveSvgDom = (skipNote?: boolean) => {
+// 给歌词和音符添加动态颜色
+const fillWordColor = () => {
   // console.log('当前音符',state.activeNoteIndex)
   state.times.forEach((item: any, idx: number) => {
     const svgEl = document.getElementById(`vf-${state.times[idx]?.svgElement?.attrs?.id}`)
@@ -1545,8 +1550,11 @@ export const moveSvgDom = (skipNote?: boolean) => {
     if (index === currentNote.repeatIdx) {
       lyric?.classList.add('lyricActive')
     }
-  })
+  })  
+}
 
+/** 跳动svgdom */
+export const moveSvgDom = (skipNote?: boolean) => {
   /**
    * 计算需要移动的距离
    * 当前选中的音符和第一个音符之间的间距
@@ -1563,18 +1571,138 @@ export const moveSvgDom = (skipNote?: boolean) => {
   }
 }
 
+
+// 暂停的时候  恢复一行谱偏移位置信息
+watch(
+  () => state.playState,
+  () => {
+    if(state.isSingleLine){
+      // 当在播放中暂停 执行这个方法
+      if(!state.playEnd && state.playState === "paused") {
+        moveTranslateXNum(0)
+        const scrollLeft = smoothAnimationState.osdmScrollDom!.scrollLeft
+        smoothAnimationState.osdmScrollDom!.scrollLeft = scrollLeft + smoothAnimationState.translateXNum
+        smoothAnimationState.translateXNum = 0
+      }
+    }
+  }
+)
+
+
+/* 根据当前的小节获取前面有多少需要去除的合并小节 */
+function getNeedReduceMultipleRestNum(currMeasureIndex:number){
+  let needReduceMultipleRestNum = 0;
+  for(let noteIndex = 0; noteIndex < state.times.length; noteIndex++){
+    const note =  state.times[noteIndex];
+    if (note.MeasureNumberXML > currMeasureIndex) {
+      break;
+    }
+    if (note.multipleRestMeasures && note.multipleRestMeasures > 1) {
+      needReduceMultipleRestNum += 1;
+    }
+  }
+  return needReduceMultipleRestNum
+}
+
 watch(
 	() => state.activeMeasureIndex,
 	() => {
-    console.log('当前小节',state.activeMeasureIndex)
+    // 需要减去的合并小节数
+    const needReduceMultipleRestNum = getNeedReduceMultipleRestNum(state.activeMeasureIndex)
+    const matchMeasureNum = state.activeMeasureIndex - needReduceMultipleRestNum - 1
+    console.log('选中的小节',matchMeasureNum,'需要减去的小节',needReduceMultipleRestNum,'当前的小节',state.activeMeasureIndex)
     state.vfmeasures.forEach((item: any, idx: number) => {
-      if (idx === (state.activeMeasureIndex-1)) {
+      if (idx === matchMeasureNum) {
         item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#132D4C")
         item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#040D1E")
       } else {
-        item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#609FCF")
-        item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#2B70A5")
+        // 有选段只清除选段处的
+        if(state.section.length === 2){
+          // 把中间置灰
+          let leftMeasureNumberXML = state.section[0].MeasureNumberXML
+          let rightMeasureNumberXML = state.section[1].MeasureNumberXML
+          if(leftMeasureNumberXML > rightMeasureNumberXML){
+            leftMeasureNumberXML = state.section[1].MeasureNumberXML
+            rightMeasureNumberXML = state.section[0].MeasureNumberXML
+          }
+          const leftVfmeasuresIndex = leftMeasureNumberXML - getNeedReduceMultipleRestNum(leftMeasureNumberXML) - 1
+          const rightVfmeasuresIndex = rightMeasureNumberXML - getNeedReduceMultipleRestNum(rightMeasureNumberXML) - 1
+          if(idx >= leftVfmeasuresIndex && idx <= rightVfmeasuresIndex){
+            item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#609FCF")
+            item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#2B70A5")
+          }
+          // 预备小节
+          if(state.sectionFirst){
+            const sectionFirstVfmeasuresIndex = state.sectionFirst.MeasureNumberXML - getNeedReduceMultipleRestNum(state.sectionFirst.MeasureNumberXML) - 1
+            const sectionFirstDom = state.vfmeasures[sectionFirstVfmeasuresIndex]
+            sectionFirstDom?.querySelector('.vf-custom-bg')?.setAttribute("fill", "#71B8BD")
+            sectionFirstDom?.querySelector('.vf-custom-bot')?.setAttribute("fill", "#448F9C")
+          }
+        }else{
+          item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#609FCF")
+          item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#2B70A5")
+        }
       }
     })
 	}
-);
+);    
+
+
+
+watch(
+  () => state.section,
+  () => {
+    if(state.section.length === 2){
+      // 把前面和 后面置灰
+      let leftMeasureNumberXML = state.section[0].MeasureNumberXML
+      let rightMeasureNumberXML = state.section[1].MeasureNumberXML
+      if(leftMeasureNumberXML > rightMeasureNumberXML){
+        leftMeasureNumberXML = state.section[1].MeasureNumberXML
+        rightMeasureNumberXML = state.section[0].MeasureNumberXML
+      }
+      const leftVfmeasuresIndex = leftMeasureNumberXML - getNeedReduceMultipleRestNum(leftMeasureNumberXML) - 1
+      const rightVfmeasuresIndex = rightMeasureNumberXML - getNeedReduceMultipleRestNum(rightMeasureNumberXML) - 1
+      state.vfmeasures.forEach((item: any, idx: number) => {
+        // 小于选中置灰
+        if (idx < leftVfmeasuresIndex) {
+          item.querySelector('.vf-custom-bg')?.setAttribute("fill", "rgba(96,159,207,0.5)")
+          item.querySelector('.vf-custom-bot')?.setAttribute("fill", "rgba(43,112,165,0.5)")
+        }
+        // 大于选中置灰
+        if(idx > rightVfmeasuresIndex){
+          item.querySelector('.vf-custom-bg')?.setAttribute("fill", "rgba(96,159,207,0.5)")
+          item.querySelector('.vf-custom-bot')?.setAttribute("fill", "rgba(43,112,165,0.5)")
+        }
+      })
+      // 预备小节
+      if(state.sectionFirst){
+        const sectionFirstVfmeasuresIndex = state.sectionFirst.MeasureNumberXML - getNeedReduceMultipleRestNum(state.sectionFirst.MeasureNumberXML) - 1
+        const sectionFirstDom = state.vfmeasures[sectionFirstVfmeasuresIndex]
+        sectionFirstDom?.querySelector('.vf-custom-bg')?.setAttribute("fill", "#71B8BD")
+        sectionFirstDom?.querySelector('.vf-custom-bot')?.setAttribute("fill", "#448F9C")
+      }
+    }else{
+      // 恢复选段前
+      const matchMeasureNum = state.activeMeasureIndex - getNeedReduceMultipleRestNum(state.activeMeasureIndex) - 1
+      state.vfmeasures.forEach((item: any, idx: number) => {
+        if (idx === matchMeasureNum) {
+          item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#132D4C")
+          item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#040D1E")
+        } else {
+          item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#609FCF")
+          item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#2B70A5")
+        }
+      })
+    }
+  }
+)
+
+/** 刷新谱面 */
+export const refreshMusicSvg = () => {
+  state.loadingText = '正在加载中,请稍等…'
+  if(state.isSingleLine){
+    // 销毁旋律线
+    destroySmoothAnimation()
+  }
+  musicScoreRef.value?.refreshMusicScore()
+}

文件差異過大導致無法顯示
+ 0 - 0
src/view/audio-list/img/refresh_anim.json


+ 21 - 0
src/view/audio-list/index.module.less

@@ -65,4 +65,25 @@
             background-size: 100% 100%;
         }
     }
+}
+
+.loadingPop {
+    position: fixed;
+    left: 0;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    width: 100vw;
+    height: 100vh;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    z-index: 10000;
+    background: rgba(0, 0, 0, .6);
+    .loadingTip {
+        font-size: 14px;
+        color: #fff;
+        margin-top: 14px;
+    }
 }

+ 1 - 1
src/view/audio-list/index.tsx

@@ -363,7 +363,7 @@ export default defineComponent({
 		// console.log(state.playMode, state.midiUrl);
 		return () => (
 			<>
-				<Loading/>
+				<Loading tipText={state.loadingText} />
 				<div class={styles.audioList}>
 					{state.playMode === "MIDI" && state.speed != 0 && (
 						<iframe

+ 22 - 8
src/view/audio-list/loading.tsx

@@ -1,12 +1,21 @@
-import { defineComponent, ref } from "vue"
+import { defineComponent, ref, watch } from "vue"
 import icon_loading_img from "./img/icon_loading_img.png"
 import { Progress } from "vant"
 import styles from "./index.module.less"
 import state from "/src/state"
+import { Vue3Lottie } from "vue3-lottie";
+import animBg from "./img/refresh_anim.json";
 
 export default defineComponent({
    name: "loading",
-   setup() {
+   props: {
+		/** 提示文案 */
+		tipText: {
+			type: String,
+			default: '',
+		},
+	},
+   setup(props) {
       function fakeLoadingProgress(duration = 2000, callback: (num: number) => void) {
          let startTime = Date.now()
          let progress = 0
@@ -25,14 +34,19 @@ export default defineComponent({
       fakeLoadingProgress(2000, num => {
          loadingProress.value = num
       })
+      watch(
+         () => state.audioDone,
+         () => {
+           if (!state.audioDone) {
+            loadingProress.value = 0
+           }
+         }
+       );
       return () =>
          !state.audioDone && (
-            <div class={styles.loading}>
-               <div class={styles.loadingWrap}>
-                  <img class={styles.loadingIcon} src={icon_loading_img} />
-                  <Progress percentage={loadingProress.value} />
-                  <div class={styles.loadingTip}>音频资源加载中,请稍后</div>
-               </div>
+            <div class={styles.loadingPop}>
+               <Vue3Lottie animationData={animBg}></Vue3Lottie>
+               <div class={styles.loadingTip}>{props.tipText}</div>
             </div>
          )
    }

+ 35 - 3
src/view/music-score/index.tsx

@@ -9,6 +9,7 @@ import queryString from "query-string";
 import { getGradualLengthByXml } from "/src/helpers/calcSpeed";
 import { resetFormate, resetGivenFormate, setGlobalMusicSheet } from "/src/helpers/customMusicScore"
 import { setGlobalData } from "/src/utils";
+import Loading from "/src/view/audio-list/loading"
 
 export const musicRenderTypeKey = "musicRenderType";
 let osmd: any = null;
@@ -17,6 +18,7 @@ const musicData = reactive({
 	isRenderLoading: true,
 	score: "",
 	containerWidth: 0,
+	isRefreshLoading: false,
 });
 
 /** 重新渲染曲谱 */
@@ -25,7 +27,8 @@ export const resetRenderMusicScore = (type?: string) => {
 	const newSearch = queryString.stringify({
 		...search,
 		_t: Date.now(),
-		musicRenderType: type
+		musicRenderType: type,
+		isSingleLine: state.isSingleLine
 	});
 	location.search = "?" + newSearch;
 };
@@ -56,7 +59,7 @@ export default defineComponent({
 			default: false,
 		},
 	},
-	setup(props, { emit, slots }) {
+	setup(props, { emit, slots, expose }) {
 		/** 设置 曲谱模式,五线谱还是简谱 */
 		const setRenderType = () => {
 			const musicRenderType: any = sessionStorage.getItem(props.renderTypeKey || musicRenderTypeKey);
@@ -103,9 +106,10 @@ export default defineComponent({
 			// osmd.EngravingRules.PageRightMargin = state.isSingleLine ? (window.innerWidth+200)/10 : 2;
 			// osmd.EngravingRules.FixedMeasureWidth = state.isSingleLine ? true : false; // 是否固定小节的宽度(小节同一宽度渲染)
 			//osmd.EngravingRules.PageTopMargin = state.platform === IPlatform.PC ? 0 : 1; // 老师端顶部间距
-			osmd.EngravingRules.PageTopMargin = 0; // 老师端顶部间距
+			osmd.EngravingRules.PageTopMargin = 2; // 老师端顶部间距
 			osmd.EngravingRules.PageTopMarginNarrow = 3;
 			osmd.EngravingRules.PageLeftMargin = 2;
+			osmd.EngravingRules.PageRightMargin = 2;
 			osmd.EngravingRules.BreathMarkDistance = 0.1; // 呼吸标记距离音符的位置,百分比
 			// 老师端上课页面,左右两边有功能按钮,所以左右边距需要加大
 			// if (state.isAttendClass && state.platform === IPlatform.PC) {
@@ -160,6 +164,34 @@ export default defineComponent({
 			}
 			return result;
 		});
+
+		/** 刷新曲谱 */
+		const refreshMusicScore = async () => {
+			console.log('刷新谱面123')
+			const container = document.getElementById('musicAndSelection'), svgDom = document.getElementById('osmdCanvasPage1'), selectionBox = document.getElementById('selectionBox');
+			if (container && svgDom) {
+				container?.removeChild(svgDom)
+				container?.removeChild(selectionBox)
+			}
+			state.vfmeasures = [];
+			musicData.showSelection = false;
+			state.osmd.clear();
+			musicData.isRenderLoading = true;
+			musicData.isRefreshLoading = true;
+			state.audioDone = false;
+			getContainerWidth();
+			setRenderType();
+			await getXML();
+			await init();
+			musicData.isRenderLoading = false;
+			musicData.isRefreshLoading = false;
+			state.audioDone = true;
+			musicData.showSelection = true;
+		}
+		expose({
+			refreshMusicScore,
+		})
+
 		return () => (
 			<div
 				id="musicAndSelection"

二進制
src/view/selection/imgs/close.png


+ 26 - 65
src/view/selection/index.module.less

@@ -16,75 +16,36 @@
     // background: rgba(0,0,0,0.3);
 }
 
-
-.staveBox {
-    background-color: var(--active-stave-box) !important;
-}
-
-.leftStaveBox {
-    background-color: var(--active-stave-box);
-
-    &::before {
-        content: '';
-        position: absolute;
-        left: -5px;
-        top: -5px;
-        width: 5px;
-        height: 100%;
-        border-top: 5px solid var(--van-primary-color);
-        border-left: 5px solid var(--van-primary-color);
-        border-bottom: 5px solid var(--van-primary-color);
-    }
-}
-
-.rightStaveBox {
-    background-color: var(--active-stave-box);
-
-    &::after {
-        content: '';
-        position: absolute;
-        right: -5px;
-        top: -5px;
-        width: 5px;
-        height: 100%;
-        border-top: 5px solid var(--van-primary-color);
-        border-right: 5px solid var(--van-primary-color);
-        border-bottom: 5px solid var(--van-primary-color);
-    }
-}
-
-.centerStaveBox {
-    background-color: var(--active-stave-box);
-
-    &::before {
-        content: '';
-        position: absolute;
-        left: -5px;
-        top: -5px;
-        width: 5px;
-        height: 100%;
-        border-top: 5px solid var(--van-primary-color);
-        border-left: 5px solid var(--van-primary-color);
-        border-bottom: 5px solid var(--van-primary-color);
-    }
-
-    &::after {
-        content: '';
+.selectBox{
+    position: absolute;
+    width: 3Px;
+    background-color: #FFB800;
+    z-index: 9;
+    .selectHandle{
         position: absolute;
-        right: -5px;
-        top: -5px;
-        width: 5px;
-        height: 100%;
-        border-top: 5px solid var(--van-primary-color);
-        border-right: 5px solid var(--van-primary-color);
-        border-bottom: 5px solid var(--van-primary-color);
+        top: -22Px;
+        right: 0;
+        width: 22Px;
+        height: 22Px;
+        cursor: pointer;
+        background-color: #FFB800;
+        background-image: url("./imgs/close.png");
+        background-repeat: no-repeat;
+        background-size: 15Px 15Px;
+        background-position: 4Px 3Px;
+        border-radius: 100Px 0 0 100Px;
+        &.selectHandleRight{
+            right: -19Px;
+            background-position: 3Px 3Px;
+            border-radius: 0 100Px 100Px 0;
+        }
+        &.playIng{
+            pointer-events: none;
+            background-image:none; 
+        }
     }
 }
 
-.prepareStaveBox {
-    background-color: rgba(255, 98, 37, 0.18);
-}
-
 .disable {
     pointer-events: none;
 }

+ 59 - 46
src/view/selection/index.tsx

@@ -1,10 +1,10 @@
-import { computed, defineComponent, onMounted, reactive, Transition, nextTick } from "vue";
+import { computed, defineComponent, onMounted, reactive, Transition, nextTick, watch } from "vue";
 import state, { EnumMusicRenderType, handleSelection, skipNotePlay, IPlatform } from "/src/state";
 import styles from "./index.module.less";
 import { metronomeData } from "/src/helpers/metronome";
 import { evaluatingData } from "../evaluating";
 import { leveByScoreMeasureIcons } from "../evaluating/evaluatResult";
-import { Icon } from "vant";
+import { Icon, showToast } from "vant";
 import MoveMusicScore, { moveData, renderForMoveData } from "../plugins/move-music-score";
 import { useRoute } from "vue-router";
 import { getQuery } from "/src/utils/queryString";
@@ -173,53 +173,38 @@ export default defineComponent({
 		const disableClickNote = computed(() => {
 			return state.sectionStatus || state.modeType !== "practise";
 		});
-		const showClass = computed(() => {
-			return (item: any) => {
-				if (state.sectionStatus) {
-					if (state.section.length === 1) {
-						if (item.MeasureNumberXML == state.section[0].MeasureNumberXML) {
-							return styles.leftStaveBox;
+		// 选段符号
+		const sectionPosData = computed(() => {
+			if(state.sectionStatus) {
+				return state.section.map(((item,index) => {
+					if(index === 0){
+						const currItem = selectData.staves.find(stave => {
+							return stave.MeasureNumberXML === item.MeasureNumberXML	
+						})
+						return currItem && {
+							left: currItem.staveBox.left,
+							top: currItem.staveBox.top,
+							height: selectData.measureHeight + 'px'  // 小节的高度
 						}
-					}
-					if (state.section.length === 2) {
+					} else {
 						// 实际的结束位置
-						const actualEndIndex = state.userChooseEndIndex > state.section[1].MeasureNumberXML ? state.userChooseEndIndex : state.section[1].MeasureNumberXML
-						// 选段预备拍背景
-						if (state.sectionFirst && item.MeasureNumberXML === state.sectionFirst.MeasureNumberXML) {
-							item.staveBox.height = selectData.measureHeight + 'px';
-							return styles.prepareStaveBox;
+						const actualEndIndex = state.userChooseEndIndex > item.MeasureNumberXML ? state.userChooseEndIndex : item.MeasureNumberXML
+						const currItem = selectData.staves.find(stave => {
+							return stave.MeasureNumberXML === actualEndIndex
+						})
+						return currItem && {
+							left: parseFloat(currItem.staveBox.left)+parseFloat(currItem.staveBox.width)+"px",
+							top: currItem.staveBox.top,
+							height: selectData.measureHeight + 'px'
 						}
-						if (
-							item.MeasureNumberXML >= state.section[0].MeasureNumberXML &&
-							item.MeasureNumberXML <= actualEndIndex
-						) {
-							if (
-								item.MeasureNumberXML == state.section[0].MeasureNumberXML &&
-								item.MeasureNumberXML == actualEndIndex
-							) {
-								return styles.centerStaveBox;
-							}
-							if (item.MeasureNumberXML == state.section[0].MeasureNumberXML) {
-								return styles.leftStaveBox;
-							}
-							if (item.MeasureNumberXML == actualEndIndex) {
-								if (!item.staveBox?.height) {
-									item.staveBox.height = selectData.measureHeight + 'px'
-								}
-								return styles.rightStaveBox;
-							}
-							return styles.staveBox + " staveBox";  // 加上固定css 一行谱可以隐藏
-						}
-					}
-				} else {
-					if (state.activeMeasureIndex == item.MeasureNumberXML && !state.isReport) {
-						item.staveBox.height = selectData.measureHeight + 'px';
-						return styles.staveBox + " staveBox"; // 加上固定css 一行谱可以隐藏
 					}
-				}
-			};
-		});
+				}))
+			}
+			return []
+		})
 		onMounted(() => {
+			selectData.notes = [];
+			selectData.staves = [];
 			calcNoteData();
 			// 初始化谱面可移动的元素位置
 			try {
@@ -260,7 +245,6 @@ export default defineComponent({
 								<div
 									class={[
 										styles.position,
-										showClass.value(item),
 										scoreItem ? `scoreItemLeve${scoreItem.leve}` : "",
 										item.multipleRestMeasures <= 1 ? styles.staveBg : "",
 										(state.platform === IPlatform.PC && state.zoom > 0.8) ? styles.linePC : '',
@@ -320,7 +304,36 @@ export default defineComponent({
 						</div>
 					);
 				})}
-
+				{/* 选段 */}
+				{
+					sectionPosData.value.map((item,index) =>{
+						return (
+							item && <div class={styles.selectBox} style={item}>
+								<div class={[styles.selectHandle,index>0&&styles.selectHandleRight,state.playState==="play"&&styles.playIng]} onClick={()=>{
+									// 如果选择了2个 删除左边的时候
+									if(state.section.length===2&&index === 0){
+										state.section = []
+										showToast({
+											message: "请选择开始小节",
+											duration: 0,
+											position: "top",
+											className: "selectionToast",
+										});
+									}else{
+										state.section.splice(index,1)
+										state.section = [...state.section]  // 触发 watch
+										showToast({
+											message: state.section.length?"请选择结束小节":"请选择开始小节",
+											duration: 0,
+											position: "top",
+											className: "selectionToast",
+										});
+									}
+								}}></div>
+							</div>
+						)
+					})
+				}
 				{/* 移动模块 */}
 				{query.isMove == "1" && <MoveMusicScore />}
 			</div>

+ 26 - 31
src/view/tick/index.tsx

@@ -1,4 +1,4 @@
-import { defineComponent, reactive, onMounted } from "vue";
+import { defineComponent, reactive, onMounted, computed } from "vue";
 import tockAndTick from "/src/constant/tockAndTick.json";
 import { Howl } from "howler";
 import { Popup } from "vant";
@@ -9,17 +9,24 @@ import tickWav from "/src/assets/tick.mp3";
 import tockWav from "/src/assets/tock.mp3";
 
 const tickData = reactive({
-	list: [] as number[],
 	len: 0,
+	reduceLen: 0,
 	tickEnd: false,
 	/** 节拍器时间 */
 	beatLengthInMilliseconds: 0,
-	state: "",
-	source1: "" as unknown as Howl,
-	source2: "" as unknown as Howl,
 	index: 0,
-	show: false,
+	show: false
 });
+
+// 是否使用系统节拍器
+const isUseSystemBeat = computed(()=>{
+	return (state.playType === "play"&& !state.isOpenMetronome)||(state.playType === "sing" && !state.isSingOpenMetronome)
+})
+// 使用哪个节拍器个数
+const useLen = computed(()=>{
+	return isUseSystemBeat.value ? tickData.reduceLen : tickData.len
+})
+
 let _time: NodeJS.Timeout 
 // 关闭节拍器
 export function closeTick(){
@@ -37,11 +44,11 @@ const handlePlay = (i: number, source: any | null) => {
 				return
 			};
 			tickData.index++;
-			if (source) {
+			// 当系统节拍器才播放声音
+			if (source && isUseSystemBeat.value) {
 				const beatVolume = state.setting.beatVolume / 100
 				source.volume = beatVolume;
-				// 当mp3节拍器的时候不播放声音
-				if (source.volume <= 0 || state.isOpenMetronome || state.isSingOpenMetronome) {
+				if (source.volume <= 0) {
 					source.muted = true
 				} else {
 					source.muted = false
@@ -73,13 +80,15 @@ const createAudio = (src: string): Promise<HTMLAudioElement | null> => {
 };
 
 /** 设置节拍器
- * @param beatLengthInMilliseconds 节拍间隔时间
  * @param beat 节拍数
  */
-export const handleInitTick = (beatLengthInMilliseconds: number, beat: number) => {
-	tickData.state = "";
-	tickData.beatLengthInMilliseconds = beatLengthInMilliseconds
+export const handleInitTick = (beat: number) => {
 	tickData.len = beat;
+	// 节拍器的个数除以2 直到小于等于4为止 
+	while (beat > 4 && beat % 2 === 0) {
+        beat = beat / 2;
+    }
+	tickData.reduceLen = beat
 };
 
 /** 开始节拍器 */
@@ -87,27 +96,13 @@ export const handleInitTick = (beatLengthInMilliseconds: number, beat: number) =
 export const handleStartTick = async () => {
 	tickData.show = true;
 	tickData.tickEnd = false;
-	if (tickData.state !== "ok") {
-		// tickData.source1 = new Howl({
-		// 	src: tockAndTick.tick,
-		// 	// 如果是ios手机,需要强制使用audio,不然部分系统版本第一次播放没有声音
-		// 	html5: browserInfo.ios,
-		// });
-
-		// tickData.source2 = new Howl({
-		// 	src: tockAndTick.tock,
-		// });
-		tickData.state = "ok";
-	}
 	tickData.index = 0;
 	tickData.beatLengthInMilliseconds = (60 / state.speed) * 1000;
-	for(let i = 0; i <= tickData.len; i++){
+	for(let i = 0; i <= useLen.value; i++){
 		// 提前结束, 直接放回false
 		if (tickData.tickEnd) return false;
-		// Howl 插件播放音频
-		// const source = i === 0 ? tickData.source1 : i === tickData.len ? null : tickData.source2;
 		// Audio 标签播放音频
-		const source = i === 0 ? audioData.tick : i === tickData.len ? null : audioData.tock;
+		const source = i === 0 ? audioData.tick : i === useLen.value ? null : audioData.tock;
 		await handlePlay(i, source)
 	}
 	tickData.show = false;
@@ -150,8 +145,8 @@ export default defineComponent({
 				tickData.show && 
 				<div class={styles.dots} style={posObj}>
 					{
-						Array.from({ length: tickData.len }).map((item,index)=>{
-							return <div class={[styles.dot,((tickData.len - tickData.index)<=index)&&styles.hide]}></div>
+						Array.from({ length: useLen.value }).map((item,index)=>{
+							return <div class={[styles.dot,((useLen.value - tickData.index)<=index)&&styles.hide]}></div>
 						})
 					}
 				</div>

+ 1 - 1
vite.config.ts

@@ -78,7 +78,7 @@ export default defineConfig({
         // target: "https://kt.colexiu.com",
         target: "https://test.resource.colexiu.com", // 内容平台开发环境,内容平台开发,需在url链接上加上isCbs=true
         //target: "https://dev.resource.colexiu.com",
-        // target: "https://dev.kt.colexiu.com",
+        //target: "https://dev.kt.colexiu.com",
         //target: "https://mec.colexiu.com",
         changeOrigin: true,
         rewrite: (path) => path.replace(/^\/instrument/, ""),

部分文件因文件數量過多而無法顯示