Kaynağa Gözat

修改问题

lex-xin 10 ay önce
ebeveyn
işleme
7d090e0a6e

BIN
src/img/cloudPractice/icon-left-active.png


+ 36 - 44
src/views/cloudPractice/cloudPractice.tsx

@@ -32,6 +32,7 @@ import { getInstrumentName } from "@/libs/instruments"
 import { formatXML, getCustomInfo, onlyVisible } from "./instrument"
 import { useFunction } from "./useData"
 import userStore from "@/store/modules/user"
+import PlayLoading from "./component/play-loading"
 
 export default defineComponent({
    name: "cloudPractice",
@@ -73,6 +74,7 @@ export default defineComponent({
          selectedPartName: "" as any,
          selectedPartIndex: 0,
          partXmlIndex: 0,
+         categoryShow: false, // 是否展开
          playState: "pause" as "play" | "pause", // 播放状态
          showPlayer: false // 是否显示播放器
       })
@@ -671,6 +673,11 @@ export default defineComponent({
          state.listActive = 0
          state.showPlayer = false
          state.playState = "pause"
+         state.partNames = []
+         state.partList = []
+         state.selectedPartName = ""
+         state.selectedPartIndex = 0
+         state.partXmlIndex = 0
          document.querySelector(".musicList-container")?.scroll(0, 0)
          state.page = 1
          state.finshed = false
@@ -685,7 +692,6 @@ export default defineComponent({
             loading.value = false
             return
          }
-         console.log(row, "row")
          state.partNames = await getPartNames(row.xmlUrl)
          let partList = row.background || []
          partList = partList.filter((item: any) => !item.track?.toLocaleUpperCase()?.includes("COMMON"))
@@ -704,16 +710,13 @@ export default defineComponent({
          console.log(defaultShowStaff, partList)
          state.selectedPartName = defaultShowStaff?.instrumentName
          state.partXmlIndex = defaultShowStaff?.xmlIndex
-
-         console.log(partColumns.value, "partColumns partColumns")
       }
 
       const getPartNames = async (xmlUrl: string) => {
          const partNames: string[] = []
          try {
             const res: any = await axios.get(xmlUrl)
-            const xml: any = new DOMParser().parseFromString(res, "text/xml")
-            console.log(xml, "xmlxmlxmlxml")
+            const xml: any = new DOMParser().parseFromString(res.data, "text/xml")
             for (const item of xml.getElementsByTagName("part-name")) {
                if (item.textContent) {
                   partNames.push(item.textContent)
@@ -725,28 +728,6 @@ export default defineComponent({
          return partNames.filter((text: string) => text.toLocaleUpperCase() !== "COMMON") || []
       }
 
-      // const musicIframeLoad = async () => {
-      //    const iframeRef: any = document.getElementById("staffIframeRef")
-      //    if (iframeRef && iframeRef.contentWindow?.renderXml) {
-      //       staffLoading.value = true
-      //       const res = await axios.get(activeItem.value.xmlUrl)
-      //       const parseXmlInfo = getCustomInfo(res.data)
-      //       const xml = formatXML(parseXmlInfo.parsedXML)
-      //       const currentXml = onlyVisible(xml, state.selectedPartIndex)
-      //       iframeRef.contentWindow.renderXml(currentXml, state.selectedPartIndex)
-      //    }
-      // }
-      // const resetRender = async () => {
-      //    const iframeRef: any = document.getElementById("staffIframeRef")
-      //    if (iframeRef && iframeRef.contentWindow?.renderXml) {
-      //       staffLoading.value = true
-      //       const res = await axios.get(activeItem.value.xmlUrl)
-      //       const parseXmlInfo = getCustomInfo(res.data)
-      //       const xml = formatXML(parseXmlInfo.parsedXML)
-      //       const currentXml = onlyVisible(xml, state.selectedPartIndex)
-      //       iframeRef.contentWindow.renderXml(currentXml, state.selectedPartIndex)
-      //    }
-      // }
       const musicIframeLoad = async () => {
          const iframeRef: any = document.getElementById("staffIframeRef")
          if (iframeRef && iframeRef.contentWindow.renderXml) {
@@ -766,13 +747,13 @@ export default defineComponent({
          const iframeRef: any = document.getElementById("staffIframeRef")
          if (iframeRef && iframeRef.contentWindow.renderXml) {
             staffLoading.value = true
-            loading.value = true
             const res: any = await axios.get(activeItem.value.xmlUrl)
             const parseXmlInfo = getCustomInfo(res.data)
             const xml = formatXML(parseXmlInfo.parsedXML)
             if (activeItem.value.isComberRender) {
                iframeRef.contentWindow.renderXml(xml, state.partXmlIndex, activeItem.value.isComberRender)
             } else {
+               console.log(state.partXmlIndex, " state.partXmlIndex")
                const currentXml = onlyVisible(xml, state.partXmlIndex)
                iframeRef.contentWindow.renderXml(currentXml, 0, activeItem.value.isComberRender)
             }
@@ -848,9 +829,11 @@ export default defineComponent({
                                  <div
                                     class={[styles.leftSection_item, item.id === state.firstTreeId && styles.leftSection_item__active]}
                                     onClick={async () => {
+                                       if (loading.value) return
                                        state.firstTreeId = item.id
                                        await setDefaultData("first")
-                                       handleGetList()
+                                       await handleGetList()
+                                       await toDetail()
                                     }}
                                  >
                                     {item.name}
@@ -864,6 +847,8 @@ export default defineComponent({
                               {state.categoryList.length > 1 && (
                                  <div class={[styles.categorySection]}>
                                     <NPopselect
+                                       placement="bottom-start"
+                                       disabled={loading.value}
                                        options={state.categoryList}
                                        v-model:value={state.categoryId}
                                        onUpdate:value={async (val: any) => {
@@ -872,13 +857,17 @@ export default defineComponent({
                                              state.categoryName = item.label
                                              state.categoryId = item.value
                                              await setDefaultData("category")
-                                             handleGetList()
+                                             await handleGetList()
+                                             await toDetail()
                                           }
                                        }}
+                                       onUpdate:show={(value: any) => {
+                                          state.categoryShow = value
+                                       }}
                                        trigger="click"
                                        class={"PopSelect"}
                                     >
-                                       <span class={styles.iconTagName}>{state.categoryName}</span>
+                                       <span class={[styles.iconTagName, state.categoryShow && styles.show]}>{state.categoryName}</span>
                                     </NPopselect>
                                  </div>
                               )}
@@ -889,6 +878,7 @@ export default defineComponent({
                                        popperClass="classTypePopper"
                                        v-model={state.subjectId}
                                        height={42}
+                                       // disabled={loading.value}
                                        options={state.subjectList}
                                        placeholder="全部声部"
                                        onChange={handleGetList}
@@ -898,6 +888,7 @@ export default defineComponent({
                                           popperClass="classTypePopper"
                                           v-model={state.levelId}
                                           height={42}
+                                          // disabled={loading.value}
                                           options={state.levelList}
                                           placeholder="级别"
                                           onChange={() => {
@@ -911,6 +902,7 @@ export default defineComponent({
                                           popperClass="classTypePopper"
                                           v-model={state.typeId}
                                           height={42}
+                                          // disabled={loading.value}
                                           options={state.typeList}
                                           propsOpt={{
                                              labelField: "name",
@@ -964,14 +956,9 @@ export default defineComponent({
                                                 ;(e.target as any).dataset.loaded = "true"
                                              }}
                                           />
-                                          {/* <PlayLoading
-                                       class={[
-                                         data.listActive === index &&
-                                         data.playState === 'play'
-                                           ? ''
-                                           : styles.showPlayLoading
-                                       ]}
-                                       /> */}
+                                          <PlayLoading
+                                             class={[state.listActive === index && state.playState === "play" ? "" : styles.showPlayLoading]}
+                                          />
                                        </div>
                                        <div class={styles.title}>
                                           <div class={styles.titleName}>
@@ -985,8 +972,8 @@ export default defineComponent({
                                           onClick={(e: any) => {
                                              e.stopPropagation()
                                              handlePlay(item)
-                                             if (state.listActive === index && state.playState === "play") {
-                                                musicIframeLoad()
+                                             if (state.listActive !== index) {
+                                                resetRender()
                                              }
                                           }}
                                        >
@@ -1022,7 +1009,10 @@ export default defineComponent({
                      {/* <i class={styles.leftArrow}></i> */}
 
                      <NSpin show={staffLoading.value} stroke="#FF531C">
-                        <div class={styles.musicName}>{activeItem.value.name}</div>
+                        <div class={styles.musicName}>
+                           {activeItem.value.name}
+                           {activeItem.value.musicSheetType === "CONCERT" && state.selectedPartName ? `(${state.selectedPartName})` : ""}
+                        </div>
                         <div class={[styles.staffImgs, !loading.value && !activeItem.value?.id && styles.staffImgsEmpty]}>
                            {state.iframeSrc && activeItem.value?.id && (
                               <iframe
@@ -1049,7 +1039,10 @@ export default defineComponent({
                         }}
                         class={[styles.goBtn]}
                         src={btnSubmit as any}
-                        onClick={() => goToCloud(activeItem.value.id)}
+                        onClick={() => {
+                           handleChangeAudio("pause")
+                           goToCloud(activeItem.value.id, state.partXmlIndex)
+                        }}
                      />
 
                      <div
@@ -1064,7 +1057,6 @@ export default defineComponent({
                            onUpdate:value={async (value: any) => {
                               console.log(value, "value")
                               const item = partColumns.value.find((item: any) => item.value === value)
-
                               state.selectedPartIndex = value
                               state.selectedPartName = item.instrumentName
                               state.partXmlIndex = item.xmlIndex

+ 1 - 1
src/views/cloudPractice/component/play-loading/index.module.scss

@@ -13,7 +13,7 @@
     div {
         width: 5px;
         height: 20px;
-        background: linear-gradient(135deg, #34FFC5 0%, #1BD2FF 100%);
+        background: linear-gradient(135deg, #FF9946 0%, #FF5B20 100%);
         transform-origin: bottom;
         border-radius: 5px 5px 0 0;
         margin: 0 2px;

+ 27 - 6
src/views/cloudPractice/index.module.scss

@@ -123,6 +123,7 @@
          background: url("@/img/cloudPractice/icon-left-active.png");
          background-size: contain;
          color: #fe7846;
+         text-shadow: none;
       }
    }
 
@@ -130,6 +131,8 @@
       height: 100%;
       overflow-x: hidden;
       overflow-y: auto;
+      display: flex;
+      flex-direction: column;
 
       &::-webkit-scrollbar {
          width: 0;
@@ -178,6 +181,12 @@
             background: url("../../img/cloudPractice/icon-arrow-down.png") no-repeat center;
             background-size: contain;
          }
+
+         &.show {
+            &::after {
+               transform: rotate(180deg);
+            }
+         }
       }
    }
 
@@ -191,6 +200,12 @@
       gap: 0 16px;
       display: flex;
       margin-right: 16px;
+
+      :global {
+         .el-cascader .el-input .el-input__inner {
+            color: #994D1C;
+         }
+      }
    }
 
    :global {
@@ -204,6 +219,7 @@
          font-size: 16px;
          .el-input__icon {
             margin-left: 0;
+            color: #994D1C;
          }
       }
       .el-cascader:not(.is-disabled):hover .el-input__wrapper {
@@ -245,9 +261,10 @@
          display: flex;
          align-items: center;
          justify-content: center;
-
+         min-height: auto;
+         flex: 1;
          .empty {
-            margin-top: -180px;
+            margin-top: -100px;
             --el-empty-image-width: 277px;
             :global {
                .el-empty__description p {
@@ -268,9 +285,9 @@
 
          cursor: pointer;
 
-         &:hover {
-            background: #fff3d7;
-         }
+         // &:hover {
+         //    background: #fff3d7;
+         // }
 
          &.active {
             background: #fff3d7;
@@ -305,6 +322,10 @@
             img[data-loaded="true"] {
                opacity: 1;
             }
+
+            .showPlayLoading {
+               opacity: 0;
+            }
          }
 
          .itemInfo {
@@ -385,7 +406,7 @@
       left: 50%;
       bottom: 46px;
       transform: translateX(-50%);
-      height: 102px;
+      height: 94px;
       cursor: pointer;
       transition: all 0.2s ease-in;
    }

+ 296 - 301
src/views/cloudPractice/instrument.ts

@@ -1,261 +1,256 @@
 // import { isSpecialMark, isSpeedKeyword, isGradientWords, GRADIENT_SPEED_RESET_TAG } from "./speed-tag"
 
-
 // import { isSpecialMark, isSpeedKeyword, isGradientWords, GRADIENT_SPEED_RESET_TAG } from "./speed-tag"
 
 export class StringUtil {
-  public static StringContainsSeparatedWord(str: string, wordRegExString: string, ignoreCase = false): boolean {
-    const regExp = new RegExp("( |^)" + wordRegExString + "([ .]|$)", ignoreCase ? "i" : undefined)
-    return regExp.test(str)
-  }
+   public static StringContainsSeparatedWord(str: string, wordRegExString: string, ignoreCase = false): boolean {
+      const regExp = new RegExp("( |^)" + wordRegExString + "([ .]|$)", ignoreCase ? "i" : undefined)
+      return regExp.test(str)
+   }
 }
 
 export const formatXML = (xml: string): string => {
-  if (!xml) return ""
-  const xmlParse = new DOMParser().parseFromString(xml, "text/xml")
-  const measures: any = xmlParse.getElementsByTagName("measure")
-  // const repeats: any = Array.from(xmlParse.querySelectorAll('repeat'))
-  // 处理重复小节信息
-  // let speed = -1
-  let beats = -1
-  let beatType = -1
-  // 小节中如果没有节点默认为休止符
-  for (const measure of measures) {
-    if (beats === -1 && measure.getElementsByTagName("beats").length) {
-      beats = parseInt(measure.getElementsByTagName("beats")[0].textContent || "4")
-    }
-    if (beatType === -1 && measure.getElementsByTagName("beat-type").length) {
-      beatType = parseInt(measure.getElementsByTagName("beat-type")[0].textContent || "4")
-    }
-    // if (speed === -1 && measure.getElementsByTagName('per-minute').length) {
-    //   speed = parseInt(measure.getElementsByTagName('per-minute')[0].textContent || this.firstLib?.speed)
-    // }
-    const divisions = parseInt(measure.getElementsByTagName("divisions")[0]?.textContent || "256")
-    if (measure.getElementsByTagName("note").length === 0) {
-      const forwardTimeElement = measure.getElementsByTagName("forward")[0]?.getElementsByTagName("duration")[0]
-      if (forwardTimeElement) {
-        forwardTimeElement.textContent = "0"
+   if (!xml) return ""
+   const xmlParse = new DOMParser().parseFromString(xml, "text/xml")
+   const measures: any = xmlParse.getElementsByTagName("measure")
+   // const repeats: any = Array.from(xmlParse.querySelectorAll('repeat'))
+   // 处理重复小节信息
+   // let speed = -1
+   let beats = -1
+   let beatType = -1
+   // 小节中如果没有节点默认为休止符
+   for (const measure of measures) {
+      if (beats === -1 && measure.getElementsByTagName("beats").length) {
+         beats = parseInt(measure.getElementsByTagName("beats")[0].textContent || "4")
+      }
+      if (beatType === -1 && measure.getElementsByTagName("beat-type").length) {
+         beatType = parseInt(measure.getElementsByTagName("beat-type")[0].textContent || "4")
       }
-      measure.innerHTML =
-        measure.innerHTML +
-        `
+      // if (speed === -1 && measure.getElementsByTagName('per-minute').length) {
+      //   speed = parseInt(measure.getElementsByTagName('per-minute')[0].textContent || this.firstLib?.speed)
+      // }
+      const divisions = parseInt(measure.getElementsByTagName("divisions")[0]?.textContent || "256")
+      if (measure.getElementsByTagName("note").length === 0) {
+         const forwardTimeElement = measure.getElementsByTagName("forward")[0]?.getElementsByTagName("duration")[0]
+         if (forwardTimeElement) {
+            forwardTimeElement.textContent = "0"
+         }
+         measure.innerHTML =
+            measure.innerHTML +
+            `
         <note>
           <rest measure="yes"/>
           <duration>${divisions * beats}</duration>
           <voice>1</voice>
           <type>whole</type>
         </note>`
-    }
-  }
-  return new XMLSerializer().serializeToString(xmlParse)
+      }
+   }
+   return new XMLSerializer().serializeToString(xmlParse)
 }
 
-
-
 export const onlyVisible = (xml: string, partIndex: number): string => {
-  if (!xml) return ""
-  const xmlParse = new DOMParser().parseFromString(xml, "text/xml")
-  const partList = xmlParse.getElementsByTagName("part-list")?.[0]?.getElementsByTagName("score-part") || []
-  const partListNames = Array.from(partList).map((item) => item.getElementsByTagName("part-name")?.[0].textContent || "")
-  const parts: any = xmlParse.getElementsByTagName("part")
-  // const firstTimeInfo = parts[0]?.getElementsByTagName('metronome')[0]?.parentElement?.parentElement?.cloneNode(true)
-  const part: any = parts[0]
-  const firstMeasures = [...part.getElementsByTagName("measure")]
-  const metronomes = [...part.getElementsByTagName("metronome")]
-  const words = [...part.getElementsByTagName("words")]
-  const codas = [...part.getElementsByTagName("coda")]
-  const rehearsals = [...part.getElementsByTagName("rehearsal")]
+   if (!xml) return ""
+   const xmlParse = new DOMParser().parseFromString(xml, "text/xml")
+   const partList = xmlParse.getElementsByTagName("part-list")?.[0]?.getElementsByTagName("score-part") || []
+   const partListNames = Array.from(partList).map(item => item.getElementsByTagName("part-name")?.[0].textContent || "")
+   const parts: any = xmlParse.getElementsByTagName("part")
+   // const firstTimeInfo = parts[0]?.getElementsByTagName('metronome')[0]?.parentElement?.parentElement?.cloneNode(true)
+   const part: any = parts[0]
+   const firstMeasures = [...part.getElementsByTagName("measure")]
+   const metronomes = [...part.getElementsByTagName("metronome")]
+   //  const words = [...part.getElementsByTagName("words")]
+   //  const codas = [...part.getElementsByTagName("coda")]
+   //  const rehearsals = [...part.getElementsByTagName("rehearsal")]
 
-  /** 第一分谱如果是约定的配置分谱则跳过 */
-  if (partListNames[0]?.toLocaleUpperCase?.() === "COMMON") {
-    partIndex++
-    partListNames.shift()
-  }
-  const visiblePartInfo = partList[partIndex]
-  // console.log(visiblePartInfo, partIndex)
-  if (visiblePartInfo) {
-    const id = visiblePartInfo.getAttribute("id")
-    Array.from(parts).forEach((part: any) => {
-      if (part && part.getAttribute("id") !== id) {
-        part.parentNode?.removeChild(part)
-        // 不等于第一行才添加避免重复添加
-      } else if (part && part.getAttribute("id") !== "P1") {
-        // 速度标记仅保留最后一个
-        const metronomeData: {
-          [key in string]: Element
-        } = {}
-        for (let i = 0; i < metronomes.length; i++) {
-          const metronome = metronomes[i]
-          const metronomeContainer = metronome.parentElement?.parentElement?.parentElement
-          if (metronomeContainer) {
-            const index = firstMeasures.indexOf(metronomeContainer)
-            metronomeData[index] = metronome
-          }
-        }
-        Object.values(metronomeData).forEach((metronome) => {
-          const metronomeContainer: any = metronome.parentElement?.parentElement
-          const parentMeasure: any = metronomeContainer?.parentElement
-          const measureMetronomes = [...(parentMeasure?.childNodes || [])]
-          const metronomesIndex = metronomeContainer ? measureMetronomes.indexOf(metronomeContainer) : -1
-          // console.log(parentMeasure)
-          if (parentMeasure && metronomesIndex > -1) {
-            const index = firstMeasures.indexOf(parentMeasure)
-            const activeMeasure = part.getElementsByTagName("measure")[index]
-            setElementNoteBefore(metronomeContainer, parentMeasure, activeMeasure)
-            //   console.log(measureMetronomes, metronomesIndex, activeMeasure?.childNodes, activeMeasure?.childNodes[metronomesIndex])
-            //   activeMeasure?.insertBefore(metronomeContainer.cloneNode(true), activeMeasure?.childNodes[metronomesIndex])
-            //   // part.getElementsByTagName('measure')[index]?.appendChild(metronomeContainer.cloneNode(true))
-            //   // console.log(index, parentMeasure, firstMeasures.indexOf(parentMeasure))
-          }
-        })
-        /** word比较特殊需要精确到note位置 */
-        // words.forEach((word) => {
-        //   let text = word.textContent || ""
-        //   text = ["cresc."].includes(text) ? "" : text
-        //   if ((isSpecialMark(text) || isSpeedKeyword(text) || isGradientWords(text) || isRepeatWord(text) || GRADIENT_SPEED_RESET_TAG) && text) {
-        //     const wordContainer = word.parentElement?.parentElement
-        //     const parentMeasure = wordContainer?.parentElement
-        //     const measureWords = [...(parentMeasure?.childNodes || [])]
-        //     const wordIndex = wordContainer ? measureWords.indexOf(wordContainer) : -1
-        //     if (wordContainer && parentMeasure && wordIndex > -1) {
-        //       const index = firstMeasures.indexOf(parentMeasure)
-        //       const activeMeasure = part.getElementsByTagName("measure")[index]
-        //       // 找当前小节是否包含word标签
-        //       const _words: any = Array.from(activeMeasure?.getElementsByTagName("words") || [])
-        //       // 遍历word标签,检查是否和第一小节重复,如果有重复则不平移word
-        //       const total = _words.reduce((total: any, _word) => {
-        //         if (_word.textContent?.includes(text)) {
-        //           total++
-        //         }
-        //         return total
-        //       }, 0)
-        //       if (total === 0) {
-        //         setElementNoteBefore(wordContainer, parentMeasure, activeMeasure)
+   /** 第一分谱如果是约定的配置分谱则跳过 */
+   if (partListNames[0]?.toLocaleUpperCase?.() === "COMMON") {
+      partIndex++
+      partListNames.shift()
+   }
+   const visiblePartInfo = partList[partIndex]
+   // console.log(visiblePartInfo, partIndex)
+   if (visiblePartInfo) {
+      const id = visiblePartInfo.getAttribute("id")
+      Array.from(parts).forEach((part: any) => {
+         if (part && part.getAttribute("id") !== id) {
+            part.parentNode?.removeChild(part)
+            // 不等于第一行才添加避免重复添加
+         } else if (part && part.getAttribute("id") !== "P1") {
+            // 速度标记仅保留最后一个
+            const metronomeData: {
+               [key in string]: Element
+            } = {}
+            for (let i = 0; i < metronomes.length; i++) {
+               const metronome = metronomes[i]
+               const metronomeContainer = metronome.parentElement?.parentElement?.parentElement
+               if (metronomeContainer) {
+                  const index = firstMeasures.indexOf(metronomeContainer)
+                  metronomeData[index] = metronome
+               }
+            }
+            Object.values(metronomeData).forEach(metronome => {
+               const metronomeContainer: any = metronome.parentElement?.parentElement
+               const parentMeasure: any = metronomeContainer?.parentElement
+               const measureMetronomes = [...(parentMeasure?.childNodes || [])]
+               const metronomesIndex = metronomeContainer ? measureMetronomes.indexOf(metronomeContainer) : -1
+               // console.log(parentMeasure)
+               if (parentMeasure && metronomesIndex > -1) {
+                  const index = firstMeasures.indexOf(parentMeasure)
+                  const activeMeasure = part.getElementsByTagName("measure")[index]
+                  setElementNoteBefore(metronomeContainer, parentMeasure, activeMeasure)
+                  //   console.log(measureMetronomes, metronomesIndex, activeMeasure?.childNodes, activeMeasure?.childNodes[metronomesIndex])
+                  //   activeMeasure?.insertBefore(metronomeContainer.cloneNode(true), activeMeasure?.childNodes[metronomesIndex])
+                  //   // part.getElementsByTagName('measure')[index]?.appendChild(metronomeContainer.cloneNode(true))
+                  //   // console.log(index, parentMeasure, firstMeasures.indexOf(parentMeasure))
+               }
+            })
+            /** word比较特殊需要精确到note位置 */
+            // words.forEach((word) => {
+            //   let text = word.textContent || ""
+            //   text = ["cresc."].includes(text) ? "" : text
+            //   if ((isSpecialMark(text) || isSpeedKeyword(text) || isGradientWords(text) || isRepeatWord(text) || GRADIENT_SPEED_RESET_TAG) && text) {
+            //     const wordContainer = word.parentElement?.parentElement
+            //     const parentMeasure = wordContainer?.parentElement
+            //     const measureWords = [...(parentMeasure?.childNodes || [])]
+            //     const wordIndex = wordContainer ? measureWords.indexOf(wordContainer) : -1
+            //     if (wordContainer && parentMeasure && wordIndex > -1) {
+            //       const index = firstMeasures.indexOf(parentMeasure)
+            //       const activeMeasure = part.getElementsByTagName("measure")[index]
+            //       // 找当前小节是否包含word标签
+            //       const _words: any = Array.from(activeMeasure?.getElementsByTagName("words") || [])
+            //       // 遍历word标签,检查是否和第一小节重复,如果有重复则不平移word
+            //       const total = _words.reduce((total: any, _word) => {
+            //         if (_word.textContent?.includes(text)) {
+            //           total++
+            //         }
+            //         return total
+            //       }, 0)
+            //       if (total === 0) {
+            //         setElementNoteBefore(wordContainer, parentMeasure, activeMeasure)
 
-        //       }
-        //     }
-        //   }
-        // })
-        /** word比较特殊需要精确到note位置 */
-        // codas.forEach((coda) => {
-        //   const wordContainer = coda.parentElement?.parentElement
-        //   const parentMeasure = wordContainer?.parentElement
-        //   const measureWords = [...(parentMeasure?.childNodes || [])]
-        //   const wordIndex = wordContainer ? measureWords.indexOf(wordContainer) : -1
-        //   if (wordContainer && parentMeasure && wordIndex > -1) {
-        //     const index = firstMeasures.indexOf(parentMeasure)
-        //     const activeMeasure = part.getElementsByTagName("measure")[index]
+            //       }
+            //     }
+            //   }
+            // })
+            /** word比较特殊需要精确到note位置 */
+            // codas.forEach((coda) => {
+            //   const wordContainer = coda.parentElement?.parentElement
+            //   const parentMeasure = wordContainer?.parentElement
+            //   const measureWords = [...(parentMeasure?.childNodes || [])]
+            //   const wordIndex = wordContainer ? measureWords.indexOf(wordContainer) : -1
+            //   if (wordContainer && parentMeasure && wordIndex > -1) {
+            //     const index = firstMeasures.indexOf(parentMeasure)
+            //     const activeMeasure = part.getElementsByTagName("measure")[index]
 
-        //     setElementNoteBefore(wordContainer, parentMeasure, activeMeasure)
+            //     setElementNoteBefore(wordContainer, parentMeasure, activeMeasure)
 
-        //   }
-        // })
-        // rehearsals.forEach((rehearsal) => {
-        //   const container = rehearsal.parentElement?.parentElement
-        //   const parentMeasure = container?.parentElement
-        //   // console.log(rehearsal)
-        //   if (parentMeasure) {
-        //     const index = firstMeasures.indexOf(parentMeasure)
-        //     part.getElementsByTagName("measure")[index]?.appendChild(container.cloneNode(true))
-        //     // console.log(index, parentMeasure, firstMeasures.indexOf(parentMeasure))
-        //   }
-        // })
-      } else {
-        // words.forEach((word) => {
-        //   const text = word.textContent || ""
-        //   if (isSpeedKeyword(text) && text) {
-        //     const wordContainer = word.parentElement?.parentElement?.parentElement
-        //     if (wordContainer && wordContainer.firstElementChild && wordContainer.firstElementChild !== word) {
-        //       const wordParent = word.parentElement?.parentElement
-        //       const fisrt = wordContainer.firstElementChild
-        //       wordContainer.insertBefore(wordParent, fisrt)
-        //     }
-        //   }
-        // })
-      }
+            //   }
+            // })
+            // rehearsals.forEach((rehearsal) => {
+            //   const container = rehearsal.parentElement?.parentElement
+            //   const parentMeasure = container?.parentElement
+            //   // console.log(rehearsal)
+            //   if (parentMeasure) {
+            //     const index = firstMeasures.indexOf(parentMeasure)
+            //     part.getElementsByTagName("measure")[index]?.appendChild(container.cloneNode(true))
+            //     // console.log(index, parentMeasure, firstMeasures.indexOf(parentMeasure))
+            //   }
+            // })
+         } else {
+            // words.forEach((word) => {
+            //   const text = word.textContent || ""
+            //   if (isSpeedKeyword(text) && text) {
+            //     const wordContainer = word.parentElement?.parentElement?.parentElement
+            //     if (wordContainer && wordContainer.firstElementChild && wordContainer.firstElementChild !== word) {
+            //       const wordParent = word.parentElement?.parentElement
+            //       const fisrt = wordContainer.firstElementChild
+            //       wordContainer.insertBefore(wordParent, fisrt)
+            //     }
+            //   }
+            // })
+         }
 
-      // 最后一个小节的结束线元素不在最后 调整
-      if (part && part.getAttribute("id") === id) {
-        const barlines = part.getElementsByTagName("barline")
-        const lastParent = barlines[barlines.length - 1]?.parentElement
-        if (lastParent?.lastElementChild?.tagName !== "barline") {
-          const children: any = lastParent?.children || []
-          for (const el of children) {
-            if (el.tagName === "barline") {
-              // 将结束线元素放到最后
-              lastParent?.appendChild(el)
-              break
+         // 最后一个小节的结束线元素不在最后 调整
+         if (part && part.getAttribute("id") === id) {
+            const barlines = part.getElementsByTagName("barline")
+            const lastParent = barlines[barlines.length - 1]?.parentElement
+            if (lastParent?.lastElementChild?.tagName !== "barline") {
+               const children: any = lastParent?.children || []
+               for (const el of children) {
+                  if (el.tagName === "barline") {
+                     // 将结束线元素放到最后
+                     lastParent?.appendChild(el)
+                     break
+                  }
+               }
             }
-          }
-        }
-      }
-    })
-    Array.from(partList).forEach((part) => {
-      if (part && part.getAttribute("id") !== id) {
-        part.parentNode?.removeChild(part)
-      }
-    })
-    // 处理装饰音问题
-    // const notes = xmlParse.getElementsByTagName("note")
-    // const getNextvNoteDuration = (i: number) => {
-    //   let nextNote = notes[i + 1]
-    //   // 可能存在多个装饰音问题,取下一个非装饰音时值
-    //   for (let index = i index < notes.length index++) {
-    //     const note = notes[index]
-    //     if (!note.getElementsByTagName("grace")?.length) {
-    //       nextNote = note
-    //       break
-    //     }
-    //   }
-    //   const nextNoteDuration = nextNote?.getElementsByTagName("duration")[0]
-    //   return nextNoteDuration
-    // }
-    // Array.from(notes).forEach((note, i) => {
-    //   const graces = note.getElementsByTagName("grace")
-    //   if (graces && graces.length) {
-    //     // if (i !== 0) {
-    //     // note.appendChild(getNextvNoteDuration(i)?.cloneNode(true))
-    //     // }
-    //   }
-    // })
-  }
-  // console.log(xmlParse)
-  return new XMLSerializer().serializeToString(appoggianceFormate(xmlParse))
+         }
+      })
+      Array.from(partList).forEach(part => {
+         if (part && part.getAttribute("id") !== id) {
+            part.parentNode?.removeChild(part)
+         }
+      })
+      // 处理装饰音问题
+      // const notes = xmlParse.getElementsByTagName("note")
+      // const getNextvNoteDuration = (i: number) => {
+      //   let nextNote = notes[i + 1]
+      //   // 可能存在多个装饰音问题,取下一个非装饰音时值
+      //   for (let index = i index < notes.length index++) {
+      //     const note = notes[index]
+      //     if (!note.getElementsByTagName("grace")?.length) {
+      //       nextNote = note
+      //       break
+      //     }
+      //   }
+      //   const nextNoteDuration = nextNote?.getElementsByTagName("duration")[0]
+      //   return nextNoteDuration
+      // }
+      // Array.from(notes).forEach((note, i) => {
+      //   const graces = note.getElementsByTagName("grace")
+      //   if (graces && graces.length) {
+      //     // if (i !== 0) {
+      //     // note.appendChild(getNextvNoteDuration(i)?.cloneNode(true))
+      //     // }
+      //   }
+      // })
+   }
+   // console.log(xmlParse)
+   return new XMLSerializer().serializeToString(appoggianceFormate(xmlParse))
 }
 
-
 // 倚音后连音线
 export const appoggianceFormate = (xmlParse: Document): Document => {
-  if (!xmlParse) return xmlParse
-  const graces: any = xmlParse.querySelectorAll("grace")
-  if (!graces.length) return xmlParse
-  const getNextElement = (el: HTMLElement): HTMLElement => {
-    if (el.querySelector("grace")) {
-      return getNextElement(el?.nextElementSibling as HTMLElement)
-    }
-    return el
-  }
-  for (const grace of graces) {
-    const notations = grace.parentElement?.querySelector("notations")
-    if (notations && notations.querySelectorAll("slur").length > 1) {
-      const nextEle: Element = getNextElement(grace.parentElement?.nextElementSibling as HTMLElement)
-      if (nextEle && nextEle.querySelectorAll("slur").length > 0) {
-        const slurNumber = Array.from(nextEle.querySelector("notations")?.children || []).map((el: Element) => {
-          return el.getAttribute("number")
-        })
-        const slurs = notations.querySelectorAll("slur")
-        for (const nota of slurs) {
-          if (!slurNumber.includes(nota.getAttribute("number"))) {
-            nextEle.querySelector("notations")?.appendChild(nota)
-          }
-        }
+   if (!xmlParse) return xmlParse
+   const graces: any = xmlParse.querySelectorAll("grace")
+   if (!graces.length) return xmlParse
+   const getNextElement = (el: HTMLElement): HTMLElement => {
+      if (el.querySelector("grace")) {
+         return getNextElement(el?.nextElementSibling as HTMLElement)
       }
-    }
-  }
-  return xmlParse
+      return el
+   }
+   for (const grace of graces) {
+      const notations = grace.parentElement?.querySelector("notations")
+      if (notations && notations.querySelectorAll("slur").length > 1) {
+         const nextEle: Element = getNextElement(grace.parentElement?.nextElementSibling as HTMLElement)
+         if (nextEle && nextEle.querySelectorAll("slur").length > 0) {
+            const slurNumber = Array.from(nextEle.querySelector("notations")?.children || []).map((el: Element) => {
+               return el.getAttribute("number")
+            })
+            const slurs = notations.querySelectorAll("slur")
+            for (const nota of slurs) {
+               if (!slurNumber.includes(nota.getAttribute("number"))) {
+                  nextEle.querySelector("notations")?.appendChild(nota)
+               }
+            }
+         }
+      }
+   }
+   return xmlParse
 }
 
-
 /**
  * 添加第一分谱信息至当前分谱
  * @param ele 需要插入的元素
@@ -263,43 +258,43 @@ export const appoggianceFormate = (xmlParse: Document): Document => {
  * @param parent 需要添加的分谱
  */
 const setElementNoteBefore = (ele: Element, fitstParent: Element, parent?: Element | null) => {
-  let noteIndex = 0
-  if (!fitstParent) {
-    return
-  }
-  for (let index = 0; index < fitstParent.childNodes.length; index++) {
-    const element = fitstParent.childNodes[index]
-    if (element.nodeName === "note") {
-      noteIndex++
-    }
-    if (element === ele) {
-      break
-    }
-  }
-  if (noteIndex === 0 && parent) {
-    parent.insertBefore(ele, parent.childNodes[0])
-    return
-  }
-  if (parent && parent.childNodes.length > 0) {
-    let noteIndex2 = 0
-    const notes = Array.from(parent.childNodes).filter((child) => child.nodeName === "note")
-    const lastNote = notes[notes.length - 1]
-    if (noteIndex >= notes.length && lastNote) {
-      parent.insertBefore(ele, parent.childNodes[Array.from(parent.childNodes).indexOf(lastNote)])
+   let noteIndex = 0
+   if (!fitstParent) {
       return
-    }
-    for (let index = 0; index < notes.length; index++) {
-      const element = notes[index]
+   }
+   for (let index = 0; index < fitstParent.childNodes.length; index++) {
+      const element = fitstParent.childNodes[index]
       if (element.nodeName === "note") {
-        noteIndex2 = noteIndex2 + 1
-        if (noteIndex2 === noteIndex) {
-          parent.insertBefore(ele, element)
-          break
-        }
+         noteIndex++
+      }
+      if (element === ele) {
+         break
+      }
+   }
+   if (noteIndex === 0 && parent) {
+      parent.insertBefore(ele, parent.childNodes[0])
+      return
+   }
+   if (parent && parent.childNodes.length > 0) {
+      let noteIndex2 = 0
+      const notes = Array.from(parent.childNodes).filter(child => child.nodeName === "note")
+      const lastNote = notes[notes.length - 1]
+      if (noteIndex >= notes.length && lastNote) {
+         parent.insertBefore(ele, parent.childNodes[Array.from(parent.childNodes).indexOf(lastNote)])
+         return
+      }
+      for (let index = 0; index < notes.length; index++) {
+         const element = notes[index]
+         if (element.nodeName === "note") {
+            noteIndex2 = noteIndex2 + 1
+            if (noteIndex2 === noteIndex) {
+               parent.insertBefore(ele, element)
+               break
+            }
+         }
       }
-    }
-  }
-  // console.log(noteIndex, parent)
+   }
+   // console.log(noteIndex, parent)
 }
 
 /**
@@ -308,49 +303,49 @@ const setElementNoteBefore = (ele: Element, fitstParent: Element, parent?: Eleme
  * @returns 是否是重复关键词
  */
 export const isRepeatWord = (text: string): boolean => {
-  if (text) {
-    const innerText = text.toLocaleLowerCase()
-    const dsRegEx = "d\\s?\\.s\\."
-    const dcRegEx = "d\\.\\s?c\\."
+   if (text) {
+      const innerText = text.toLocaleLowerCase()
+      const dsRegEx = "d\\s?\\.s\\."
+      const dcRegEx = "d\\.\\s?c\\."
 
-    return (
-      innerText === "@" ||
-      StringUtil.StringContainsSeparatedWord(innerText, dsRegEx + " al fine", true) ||
-      StringUtil.StringContainsSeparatedWord(innerText, dsRegEx + " al coda", true) ||
-      StringUtil.StringContainsSeparatedWord(innerText, dcRegEx + " al fine", true) ||
-      StringUtil.StringContainsSeparatedWord(innerText, dcRegEx + " al coda", true) ||
-      StringUtil.StringContainsSeparatedWord(innerText, dcRegEx) ||
-      StringUtil.StringContainsSeparatedWord(innerText, "da\\s?capo", true) ||
-      StringUtil.StringContainsSeparatedWord(innerText, dsRegEx, true) ||
-      StringUtil.StringContainsSeparatedWord(innerText, "dal\\s?segno", true) ||
-      StringUtil.StringContainsSeparatedWord(innerText, "al\\s?coda", true) ||
-      StringUtil.StringContainsSeparatedWord(innerText, "to\\s?coda", true) ||
-      StringUtil.StringContainsSeparatedWord(innerText, "a (la )?coda", true) ||
-      StringUtil.StringContainsSeparatedWord(innerText, "fine", true) ||
-      StringUtil.StringContainsSeparatedWord(innerText, "coda", true) ||
-      StringUtil.StringContainsSeparatedWord(innerText, "segno", true)
-    )
-  }
-  return false
+      return (
+         innerText === "@" ||
+         StringUtil.StringContainsSeparatedWord(innerText, dsRegEx + " al fine", true) ||
+         StringUtil.StringContainsSeparatedWord(innerText, dsRegEx + " al coda", true) ||
+         StringUtil.StringContainsSeparatedWord(innerText, dcRegEx + " al fine", true) ||
+         StringUtil.StringContainsSeparatedWord(innerText, dcRegEx + " al coda", true) ||
+         StringUtil.StringContainsSeparatedWord(innerText, dcRegEx) ||
+         StringUtil.StringContainsSeparatedWord(innerText, "da\\s?capo", true) ||
+         StringUtil.StringContainsSeparatedWord(innerText, dsRegEx, true) ||
+         StringUtil.StringContainsSeparatedWord(innerText, "dal\\s?segno", true) ||
+         StringUtil.StringContainsSeparatedWord(innerText, "al\\s?coda", true) ||
+         StringUtil.StringContainsSeparatedWord(innerText, "to\\s?coda", true) ||
+         StringUtil.StringContainsSeparatedWord(innerText, "a (la )?coda", true) ||
+         StringUtil.StringContainsSeparatedWord(innerText, "fine", true) ||
+         StringUtil.StringContainsSeparatedWord(innerText, "coda", true) ||
+         StringUtil.StringContainsSeparatedWord(innerText, "segno", true)
+      )
+   }
+   return false
 }
 
 /** 从xml中获取自定义信息,并删除多余的字符串 */
 export const getCustomInfo = (xml: string): any => {
-  const data = {
-    showSpeed: true,
-    parsedXML: xml,
-  }
-  const xmlParse = new DOMParser().parseFromString(xml, "text/xml")
-  const words: any = xmlParse.getElementsByTagName("words")
-  for (const word of words) {
-    if (word && word.textContent?.trim() === "隐藏速度") {
-      data.showSpeed = false
-      word.textContent = ""
-    }
-    if (word && word.textContent?.trim() === "@") {
-      word.textContent = "segno"
-    }
-  }
-  data.parsedXML = new XMLSerializer().serializeToString(xmlParse)
-  return data
+   const data = {
+      showSpeed: true,
+      parsedXML: xml
+   }
+   const xmlParse = new DOMParser().parseFromString(xml, "text/xml")
+   const words: any = xmlParse.getElementsByTagName("words")
+   for (const word of words) {
+      if (word && word.textContent?.trim() === "隐藏速度") {
+         data.showSpeed = false
+         word.textContent = ""
+      }
+      if (word && word.textContent?.trim() === "@") {
+         word.textContent = "segno"
+      }
+   }
+   data.parsedXML = new XMLSerializer().serializeToString(xmlParse)
+   return data
 }

+ 4 - 4
src/views/cloudPractice/useData.ts

@@ -19,11 +19,11 @@ export const useFunction = () => {
    const loading = ref(false)
 
    /** 跳转云教练 */
-   const goToCloud = (musicId: string) => {
+   const goToCloud = (musicId: string, partIndex = 0) => {
       const urlObj = {
-         GYT: `${URL_TEACH_GYT}?id=${musicId}&modelType=practice&modeType=json&Authorization=${getToken()}`,
-         GYM: `${URL_TEACH_GYM}?Authorization=${getToken()}&platform=web&liveConfig=1#/detail/${musicId}?isHideBack=true`,
-         KLX: `${URL_TEACH_KLX}??Authorization=${getToken()}&id=${musicId}&isHideBack=true&limitModel=practice`
+         GYT: `${URL_TEACH_GYT}?id=${musicId}&modelType=practice&modeType=json&part-index=${partIndex}&Authorization=${getToken()}`,
+         GYM: `${URL_TEACH_GYM}?Authorization=${getToken()}&platform=web&part-index=${partIndex}&liveConfig=1#/detail/${musicId}?isHideBack=true`,
+         KLX: `${URL_TEACH_KLX}??Authorization=${getToken()}&id=${musicId}&isHideBack=true&part-index=${partIndex}&limitModel=practice`
       }
       window.open(urlObj[userStoreHook.roles!], "_blank")
    }