Browse Source

添加优化

lex-xin 8 months ago
parent
commit
907ebed4ec

+ 23 - 0
src/api/cloudPractice.api.ts

@@ -26,6 +26,29 @@ export const queryPage2_gym = (data: any) => {
       params: data
    })
 }
+
 /**
  * 管乐团
  */
+export const queryTree_gyt = () => {
+   return httpAxios_gym.axioseRquest({
+      method: "post",
+      url: "/api-teacher/musicSheetCategories/page"
+   })
+}
+
+export const querySubjectIds_gyt = (data?: any) => {
+   return httpAxios_gym.axioseRquest({
+      method: "get",
+      url: "/api-teacher/subject/musicList",
+      params: data
+   })
+}
+
+export const queryPage2_gyt = (data: any) => {
+   return httpAxios_gym.axioseRquest({
+      method: "get",
+      url: "/api-teacher/musicSheet/page",
+      params: data
+   })
+}

BIN
src/img/cloudPractice/song-arrow.png


+ 6 - 2
src/store/modules/user.ts

@@ -17,6 +17,7 @@ interface userType {
       username?: string
       realName?: string
       phone?: string
+      subjectId?: string
    }
    roles?: rolesType
 }
@@ -107,22 +108,25 @@ export default () => {
 }
 
 function handleUserInfo(userType: rolesType, userInfo: Record<string, any>) {
-   let avatar, username, realName, phone
+   let avatar, username, realName, phone, subjectId
    if (["GYM", "KLX"].includes(userType)) {
       avatar = userInfo.avatar
       username = userInfo.username
       realName = userInfo.realName
       phone = userInfo.phone
+      subjectId = userInfo.subjectId
    } else {
       avatar = userInfo.avatar
       username = userInfo.nickname
       realName = userInfo.realName
       phone = userInfo.phone
+      subjectId = userInfo.subjectId
    }
    return {
       avatar,
       username,
       realName,
-      phone
+      phone,
+      subjectId
    }
 }

+ 356 - 86
src/views/cloudPractice/cloudPractice.tsx

@@ -6,23 +6,27 @@ import Dictionary from "@/components/dictionary"
 import MyInput from "@/components/myInput"
 import { NImage, NPopselect, NSpin } from "naive-ui"
 // import PlayLoading from "./component/play-loading"
+import PlayItem from "./component/play-item"
 import icon_default from "../../img/cloudPractice/icon_default.png"
-// import iconBtnPause from "../../img/cloudPractice/icon-btn-pause.png"
+import iconBtnPause from "../../img/cloudPractice/icon-btn-pause.png"
 import iconBtnPlay from "../../img/cloudPractice/icon-btn-play.png"
 import btnSubmit from "../../img/cloudPractice/btn-submit.png"
 import iconTransfer from "../../img/cloudPractice/icon-transfer.png"
 import { httpAjaxErrMsg } from "@/plugin/httpAjax"
-import { queryPage2_gym, querySubjectIds_gym, queryTree_gym } from "@/api/cloudPractice.api"
+import { queryPage2_gym, queryPage2_gyt, querySubjectIds_gym, querySubjectIds_gyt, queryTree_gym, queryTree_gyt } from "@/api/cloudPractice.api"
 // import { getToken } from "@/libs/auth"
-import { URL_TEACH_GYM } from "@/config"
+// import { URL_TEACH_GYM } from "@/config"
 import axios from "axios"
 import { getInstrumentName } from "@/libs/instruments"
 import { formatXML, getCustomInfo, onlyVisible } from "./instrument"
-// import { useDataSearchObj } from "./useData"
+import { useFunction } from "./useData"
+import userStore from "@/store/modules/user"
 
 export default defineComponent({
    name: "cloudPractice",
    setup() {
+      const userStoreHook = userStore()
+      const { goToCloud } = useFunction()
       const navs = [
          {
             name: "主页",
@@ -53,20 +57,54 @@ export default defineComponent({
          list: [] as any[],
          searchStatus: false,
          queryStr: "", // 搜索条件
-         selectedPartIndex: 0
+         partList: [] as any[],
+         partNames: [] as any[],
+         selectedPartName: "" as any,
+         selectedPartIndex: 0,
+         partXmlIndex: 0,
+         playState: "pause" as "play" | "pause", // 播放状态
+         showPlayer: false // 是否显示播放器
       })
+      const partColumns = ref<any>([])
 
       /** 选中的item */
       const activeItem = computed(() => {
-         return state.list[state.listActive] || {}
+         const list = state.list[state.listActive] || {}
+         const mp3 = {
+            GYT: "",
+            GYM: list?.musicSheetType === "CONCERT" ? list?.metronomeUrl : list?.metronomeMp3Url || list?.mp3Url,
+            KLX: ""
+         }
+
+         return {
+            id: list?.id,
+            name: list?.name,
+            background: list?.background,
+            xmlUrl: list?.xmlUrl,
+            musicSheetType: list?.musicSheetType,
+            audioFileUrl: mp3[userStoreHook.roles!]
+         }
       })
-      // 固定五线谱
-      const musicImg = computed(() => {
-         const img = activeItem.value?.musicImg || activeItem.value?.musicSvg
-         return img ? img.split(",") : []
+
+      const songPrevNextStatus = computed(() => {
+         let prev = true,
+            next = true
+         if (state.listActive === 0) {
+            prev = false
+         }
+
+         if (state.listActive >= state.list.length - 1) {
+            next = false
+         }
+
+         return {
+            prev,
+            next
+         }
       })
 
       const loading = ref(false)
+      const staffLoading = ref(false)
       const storeData = shallowRef<any[]>([])
       const handleSearchList_gym = async () => {
          loading.value = true
@@ -99,6 +137,17 @@ export default defineComponent({
                   label: "全部声部",
                   value: -1
                })
+
+               const userSubjectId = userStoreHook.userInfo.subjectId
+               if (userSubjectId) {
+                  const tempSubjectId = userSubjectId.split(",")[0]
+                  state.subjectList.forEach((item: any) => {
+                     // 判断是否存在声部编号
+                     if (item.value === Number(tempSubjectId)) {
+                        state.subjectId = Number(tempSubjectId)
+                     }
+                  })
+               }
             }
          })
       }
@@ -126,15 +175,76 @@ export default defineComponent({
                if (Array.isArray(result.rows)) {
                   state.list = [...state.list, ...result.rows]
                   state.finshed = state.page >= result.totalPage
+               } else {
+                  state.finshed = true
+               }
+            }
+         })
+      }
+
+      /** 管乐团数据查询 */
+      const handleSearchList_gyt = async () => {
+         loading.value = true
+         await httpAjaxErrMsg(queryTree_gyt).then(res => {
+            loading.value = false
+            if (res.code === 200) {
+               storeData.value = res.data || []
+
+               setDefaultData()
+            }
+         })
+      }
 
-                  // 是否显示总谱
-                  // const selectMusic = data.list[data.listActive];
-                  // if (selectMusic && selectMusic.isScoreRender && data.listActive === 0) {
-                  //   data.musicInstrumentIndex = 999;
-                  // }
+      const handleGetSubject_gyt = async () => {
+         loading.value = true
+         await httpAjaxErrMsg(querySubjectIds_gyt, {
+            enableFlag: true,
+            page: 1,
+            rows: 100
+         }).then(res => {
+            loading.value = false
+            if (res.code === 200) {
+               const result = res.data || []
 
-                  // await analyzeXml();
-                  // musicIframeLoad();
+               state.subjectList = result.map((item: any) => {
+                  return {
+                     label: item.name,
+                     value: item.id
+                  }
+               })
+
+               state.subjectList.unshift({
+                  label: "全部声部",
+                  value: -1
+               })
+            }
+         })
+      }
+
+      const handleGetList_gyt = async () => {
+         loading.value = true
+         const params = {
+            page: state.page,
+            rows: state.rows,
+            musicSubject: state.subjectId === -1 ? null : state.subjectId,
+            musicSheetCategoriesId: state.typeId === -1 ? state.levelId : state.typeId,
+            keyword: state.queryStr,
+            status: 1
+         }
+         console.log(state.typeId, state.levelId, "level")
+         await httpAjaxErrMsg(queryPage2_gyt, params).then(res => {
+            loading.value = false
+            if (res.code === 200) {
+               const result = res.data || []
+
+               if (state.reshing) {
+                  state.list = []
+                  state.reshing = false
+               }
+
+               if (Array.isArray(result.rows)) {
+                  state.list = [...state.list, ...result.rows]
+                  state.finshed = state.page >= result.totalPage
                } else {
                   state.finshed = true
                }
@@ -142,15 +252,49 @@ export default defineComponent({
          })
       }
 
+      /** 条件查询 */
+      const handleAllSearchList = async () => {
+         //  GYM,GYT,KLX 区分   查询搜索条件数据
+         if (userStoreHook.roles === "GYM") {
+            await handleSearchList_gym()
+         } else if (userStoreHook.roles === "GYT") {
+            await handleSearchList_gyt()
+         } else if (userStoreHook.roles === "KLX") {
+            //
+         }
+      }
+
+      const handleAllGetSubject = async () => {
+         //  GYM,GYT,KLX 区分   查询声部数据
+         if (userStoreHook.roles === "GYM") {
+            await handleGetSubject_gym()
+         } else if (userStoreHook.roles === "GYT") {
+            await handleGetSubject_gyt()
+         } else if (userStoreHook.roles === "KLX") {
+            //
+         }
+      }
+
+      const handleAllGetList = async () => {
+         //  GYM,GYT,KLX 区分   查询声部数据·
+         if (userStoreHook.roles === "GYM") {
+            await handleGetList_gym()
+         } else if (userStoreHook.roles === "GYT") {
+            await handleGetList_gyt()
+         } else if (userStoreHook.roles === "KLX") {
+            //
+         }
+      }
+
       /** 初始化数据 */
       const setDefaultData = (type?: "first" | "category" | "level" | "type") => {
-         if (storeData.value.length > 0) {
+         if (storeData.value.length > 0 && !["category", "level", "type"].includes(type as any)) {
             let result: any = []
             if (type === "first" && state.firstTreeId) {
                result = storeData.value.find((item: any) => item.id === state.firstTreeId)?.sysMusicScoreCategoriesList || []
             } else {
-               state.firstTreeId = storeData.value[1]?.id
-               result = storeData.value[1]?.sysMusicScoreCategoriesList || []
+               state.firstTreeId = storeData.value[0]?.id
+               result = storeData.value[0]?.sysMusicScoreCategoriesList || []
             }
             state.categoryList = result.map((item: any) => {
                return {
@@ -160,7 +304,7 @@ export default defineComponent({
                }
             })
          }
-         if (state.categoryList.length > 0) {
+         if (state.categoryList.length > 0 && !["level", "type"].includes(type as any)) {
             let result: any = []
             if (type === "category" && state.categoryId) {
                result = state.categoryList.find((item: any) => item.value === state.categoryId)?.sysMusicScoreCategoriesList || []
@@ -202,10 +346,10 @@ export default defineComponent({
       }
 
       const __init = async () => {
-         await handleSearchList_gym()
-         handleGetSubject_gym()
-         await handleGetList_gym()
-
+         await handleAllSearchList()
+         await handleAllGetSubject()
+         await handleAllGetList()
+         await toDetail()
          renderStaff()
       }
 
@@ -214,23 +358,69 @@ export default defineComponent({
       const handleResh = () => {
          if (loading.value || state.finshed) return
          state.page = state.page + 1
-         handleGetList_gym()
+         handleAllGetList()
       }
 
       const handleGetList = async () => {
          state.listActive = 0
-         // data.showPlayer = false;
-         // data.playState = 'pause';
+         state.showPlayer = false
+         state.playState = "pause"
          document.querySelector(".musicList-container")?.scroll(0, 0)
          state.page = 1
          state.finshed = false
          state.reshing = true
-         await handleGetList_gym()
+         await handleAllGetList()
+      }
+
+      const toDetail = async () => {
+         const row: any = activeItem.value
+         if (row.musicSheetType === "SINGLE") {
+            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"))
+         partColumns.value = partList.map((item: any, index: number) => {
+            const instrumentName = getInstrumentName(item.track)
+            const xmlIndex = state.partNames.findIndex((name: any) => name === item.track)
+            return {
+               text: item.track + (instrumentName ? `(${instrumentName})` : ""),
+               instrumentName: instrumentName,
+               xmlIndex,
+               value: index
+            }
+         })
+         // 初始化数据
+         const defaultShowStaff = partColumns.value[state.selectedPartIndex]
+         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")
+            for (const item of xml.getElementsByTagName("part-name")) {
+               if (item.textContent) {
+                  partNames.push(item.textContent)
+               }
+            }
+         } catch (error) {
+            //
+         }
+         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)
@@ -241,6 +431,7 @@ export default defineComponent({
       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)
@@ -258,6 +449,43 @@ export default defineComponent({
          }
       }
 
+      /** 音频控制 */
+      const handleChangeAudio = (type: "play" | "pause" | "pre" | "next") => {
+         if (type === "play") {
+            state.playState = "play"
+         } else if (type === "pause") {
+            state.playState = "pause"
+         } else if (type === "pre") {
+            if (state.list[state.listActive - 1]) {
+               handlePlay(state.list[state.listActive - 1])
+            }
+         } else if (type === "next") {
+            if (state.list[state.listActive + 1]) {
+               handlePlay(state.list[state.listActive + 1])
+            }
+         }
+      }
+
+      /** 播放曲目 */
+      const handlePlay = (item: any) => {
+         const index = state.list.findIndex((_item: any) => _item.id === item.id)
+         if (index > -1) {
+            if (state.listActive === index) {
+               state.playState = state.playState === "play" ? "pause" : "play"
+            } else {
+               state.playState = "play"
+            }
+            state.showPlayer = true
+            state.listActive = index
+         }
+      }
+
+      const showLoading = async (e: any) => {
+         if (e.data?.api === "musicStaffRender") {
+            staffLoading.value = e.data.loading
+         }
+      }
+
       onMounted(() => {
          const obv = new IntersectionObserver(entries => {
             if (entries[0].intersectionRatio > 0) {
@@ -265,6 +493,8 @@ export default defineComponent({
             }
          })
          obv.observe(spinRef.value)
+
+         window.addEventListener("message", showLoading)
       })
       return () => (
          <NavContainer navs={navs}>
@@ -292,26 +522,29 @@ export default defineComponent({
 
                         <div class={[styles.musicList, "musicList-container"]}>
                            <div class={styles.searchHeader}>
-                              <div class={[styles.categorySection]}>
-                                 <NPopselect
-                                    options={state.categoryList}
-                                    v-model:value={state.categoryId}
-                                    onUpdate:value={(val: any) => {
-                                       const item = state.categoryList.find((item: any) => item.value === val)
-                                       console.log(item, "item")
-                                       if (item) {
-                                          state.categoryName = item.label
-                                          state.categoryId = item.value
-                                          setDefaultData("category")
-                                          handleGetList()
-                                       }
-                                    }}
-                                    trigger="click"
-                                    class={"PopSelect"}
-                                 >
-                                    <span class={styles.iconTagName}>{state.categoryName}</span>
-                                 </NPopselect>
-                              </div>
+                              {state.categoryList.length > 1 && (
+                                 <div class={[styles.categorySection]}>
+                                    <NPopselect
+                                       options={state.categoryList}
+                                       v-model:value={state.categoryId}
+                                       onUpdate:value={(val: any) => {
+                                          const item = state.categoryList.find((item: any) => item.value === val)
+                                          console.log(item, "item")
+                                          if (item) {
+                                             state.categoryName = item.label
+                                             state.categoryId = item.value
+                                             setDefaultData("category")
+                                             handleGetList()
+                                          }
+                                       }}
+                                       trigger="click"
+                                       class={"PopSelect"}
+                                    >
+                                       <span class={styles.iconTagName}>{state.categoryName}</span>
+                                    </NPopselect>
+                                 </div>
+                              )}
+
                               <div class={styles.searchMore}>
                                  <div class={styles.searchSection}>
                                     <Dictionary
@@ -357,15 +590,18 @@ export default defineComponent({
                                     v-model={state.queryStr}
                                     height={42}
                                     placeholder="请输入曲目关键词"
-                                    // @keyup.enter="handleQuery"
-                                    // @input="handleInputQuery"
+                                    onKeyup={(e: any) => {
+                                       if (e.code === "Enter" || e.key === "Enter") {
+                                          handleGetList()
+                                       }
+                                    }}
                                     onHandleQuery={handleGetList}
                                     clearable
                                  />
                               )}
                            </div>
 
-                           <div class={styles.wrapList}>
+                           <div class={[styles.wrapList, !state.list.length && !loading.value && styles.wrapListEmpty]}>
                               {state.list.map((item: any, index: number) => (
                                  <div
                                     class={[styles.item, index === state.listActive && styles.active]}
@@ -401,55 +637,81 @@ export default defineComponent({
                                        </div>
                                     </div>
                                     <div class={styles.btnSection}>
-                                       <div class={styles.btn}>
-                                          播放
-                                          <img src={iconBtnPlay as any} />
+                                       <div
+                                          class={styles.btn}
+                                          onClick={(e: any) => {
+                                             e.stopPropagation()
+                                             handlePlay(item)
+                                             if (state.listActive === index && state.playState === "play") {
+                                                musicIframeLoad()
+                                             }
+                                          }}
+                                       >
+                                          {state.listActive === index && (
+                                             <>
+                                                {state.playState === "pause" ? "播放" : "暂停"}
+                                                <img src={state.playState === "pause" ? iconBtnPlay : (iconBtnPause as any)} />
+                                             </>
+                                          )}
+                                          {state.listActive !== index && (
+                                             <>
+                                                播放
+                                                <img src={iconBtnPlay as any} />
+                                             </>
+                                          )}
                                        </div>
                                     </div>
                                  </div>
                               ))}
 
+                              {!state.list.length && !loading.value && (
+                                 <ElEmpty class={styles.empty} image={require("@/img/layout/empty.png")} description="暂无结果" />
+                              )}
+
                               <div ref={spinRef} class={[styles.loadingWrap, state.finshed && styles.showLoading]}>
                                  <NSpin show={true} stroke="#FF531C"></NSpin>
                               </div>
                            </div>
-                           {/*  <el-empty class="empty" v-if="!listData.length && !loading" :image="require('@/img/layout/empty.png')" description="暂无搜索结果" /> */}
                         </div>
                      </div>
                   </div>
                   <div class={styles.rightContainer}>
-                     <div class={styles.musicName}>{activeItem.value.name}</div>
-                     <div class={styles.staffImgs}>
-                        {state.iframeSrc || musicImg.value.length > 0 ? (
-                           <iframe
-                              id="staffIframeRef"
-                              style={{
-                                 // opacity: loading.value ? 0 : 1,
-                                 width: "100%",
-                                 height: "100%"
-                              }}
-                              src={state.iframeSrc}
-                              onLoad={musicIframeLoad}
-                           ></iframe>
-                        ) : (
-                           musicImg.value.map((item: string) => {
-                              return <img src={item} key={item} />
-                           })
-                        )}
-                     </div>
+                     <i class={styles.leftArrow}></i>
+
+                     <NSpin show={staffLoading.value} stroke="#FF531C">
+                        <div class={styles.musicName}>{activeItem.value.name}</div>
+                        <div class={[styles.staffImgs, !state.list.length && !loading.value && styles.staffImgsEmpty]}>
+                           {state.iframeSrc && activeItem.value?.id && (
+                              <iframe
+                                 id="staffIframeRef"
+                                 style={{
+                                    // opacity: loading.value ? 0 : 1,
+                                    width: "100%",
+                                    height: "100%"
+                                 }}
+                                 src={state.iframeSrc}
+                                 onLoad={musicIframeLoad}
+                              ></iframe>
+                           )}
+
+                           {!loading.value && !activeItem.value?.id && (
+                              <ElEmpty class={styles.empty} image={require("@/img/layout/empty.png")} description="暂无结果" />
+                           )}
+                        </div>
+                     </NSpin>
 
                      <img
-                        // style={{
-                        //   display: activeItem.value.id ? '' : 'none'
-                        // }}
+                        style={{
+                           display: activeItem.value?.id ? "" : "none"
+                        }}
                         class={[styles.goBtn]}
                         src={btnSubmit as any}
-                        onClick={() => {}}
+                        onClick={() => goToCloud(activeItem.value.id)}
                      />
 
                      <div
                         class={styles.rightBtns}
-                        // style={{ display: activeItem.value.id ? '' : 'none' }}
+                        style={{ display: activeItem.value.id && activeItem.value.musicSheetType === "CONCERT" ? "" : "none" }}
                      >
                         <NPopselect
                            //  options={data.trackList}
@@ -458,12 +720,7 @@ export default defineComponent({
                            onUpdate:value={async () => {
                               // await analyzeXml();
                               // //
-                              // data.trackName =
-                              //   data.trackList.find(
-                              //     (item: any) =>
-                              //       item.value === data.musicInstrumentIndex
-                              //   )?.label || '切换声部';
-                              // musicIframeLoad();
+                              // musicIfrcmeLoad();
                            }}
                            class={[styles.popSelect]}
                         >
@@ -473,6 +730,19 @@ export default defineComponent({
                   </div>
                </div>
             </ElScrollbar>
+
+            {state.list.length !== 0 && activeItem.value.audioFileUrl && (
+               <PlayItem
+                  show={state.showPlayer}
+                  playState={state.playState}
+                  songPrevNextStatus={songPrevNextStatus.value}
+                  item={activeItem.value}
+                  onChange={value => handleChangeAudio(value)}
+                  onShow={(status: boolean) => {
+                     state.showPlayer = status
+                  }}
+               />
+            )}
          </NavContainer>
       )
    }

+ 191 - 148
src/views/cloudPractice/component/play-item/index.module.scss

@@ -1,174 +1,217 @@
 .container {
-  position: fixed;
-  left: 100px;
-  bottom: 0;
-  right: 0;
-  display: flex;
-  align-items: center;
-  height: 108px;
-  padding: 0 60px;
-  background-color: #fff;
-  box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.1);
-  z-index: 10;
-  transition: all .3s;
-
-  &.previewcontainer {
-    left: 0;
-    padding-right: 380px;
-  }
-
-  &.containerModal {
-    position: absolute;
-    left: 0;
-
-  }
+   position: fixed;
+   left: 0;
+   bottom: 0;
+   right: 0;
+   display: flex;
+   align-items: center;
+   height: 108px;
+   padding: 0 160px 0 60px;
+   background-color: #fff;
+   box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.1);
+   z-index: 10;
+   transition: all 0.3s;
+
+   &.previewcontainer {
+      left: 0;
+      padding-right: 380px;
+   }
+
+   &.containerModal {
+      position: absolute;
+      left: 0;
+   }
 }
 
 .hidden {
-  transform: translateY(100%);
-  opacity: 0;
-  display: none;
+   transform: translateY(100%);
+   &.item {
+      opacity: 0;
+      display: none;
+   }
 }
 
 .item {
-  position: relative;
-  display: flex;
-  align-items: center;
-  width: 100%;
-
-  .img {
-    position: relative;
-    width: 64px;
-    height: 64px;
-    border-radius: 50%;
-    margin-right: 12px;
-    background-color: #000;
-    box-shadow: 0 0 10px 4px rgba(27, 35, 55, .1);
-    padding: 7px;
-    overflow: hidden;
-    flex-shrink: 0;
-
-    :global {
-      .n-image {
-        border-radius: 50%;
-        width: 100%;
-        height: 100%;
+   position: relative;
+   display: flex;
+   align-items: center;
+   width: 100%;
+
+   .img {
+      position: relative;
+      width: 64px;
+      height: 64px;
+      border-radius: 50%;
+      margin-right: 12px;
+      background-color: #000;
+      box-shadow: 0 0 10px 4px rgba(27, 35, 55, 0.1);
+      padding: 7px;
+      overflow: hidden;
+      flex-shrink: 0;
+
+      :global {
+         .n-image {
+            border-radius: 50%;
+            width: 100%;
+            height: 100%;
+         }
       }
-    }
-
-    img {
-      transition: opacity .3s;
-      opacity: 0;
-      animation: rotateImg 6s linear infinite;
-    }
 
-    &.imgRotate {
       img {
-        animation-play-state: paused;
+         transition: opacity 0.3s;
+         opacity: 0;
+         animation: rotateImg 6s linear infinite;
       }
-    }
-
-    img[data-loaded="true"] {
-      opacity: 1;
-    }
-  }
-
-  .svgcontainer {
-    position: fixed;
-    z-index: -1000;
-    pointer-events: none;
-  }
-
-  .progress {
-    position: absolute;
-    left: 4px;
-    top: 4px;
-    width: 56px;
-    pointer-events: none;
-    transform: rotate(180deg);
-
-    :global {
-      .n-progress-graph .n-progress-graph-circle .n-progress-graph-circle-fill {
-        stroke: url(#GradientProgress);
+
+      &.imgRotate {
+         img {
+            animation-play-state: paused;
+         }
       }
-    }
-  }
-
-  .title {
-    margin-right: 15px;
-    width: 200px;
-
-    .titleName {
-      font-size: max(16px, 13Px);
-      font-weight: 600;
-      color: #131415;
-      line-height: 28px;
-      white-space: nowrap;
-    }
 
-    .titleDes {
-      font-size: max(14px, 12Px);
-      font-weight: 400;
-      color: #777777;
-      line-height: 20px;
-      white-space: nowrap;
-    }
-  }
+      img[data-loaded="true"] {
+         opacity: 1;
+      }
+   }
+
+   .svgcontainer {
+      position: fixed;
+      z-index: -1000;
+      pointer-events: none;
+   }
+
+   .progress {
+      position: absolute;
+      left: 4px;
+      top: 4px;
+      width: 56px;
+      pointer-events: none;
+      transform: rotate(180deg);
+
+      :global {
+         .n-progress-graph .n-progress-graph-circle .n-progress-graph-circle-fill {
+            stroke: url(#GradientProgress);
+         }
+      }
+   }
+
+   .title {
+      margin-right: 15px;
+      width: 200px;
+
+      .titleName {
+         font-size: max(16px, 13px);
+         font-weight: 600;
+         color: #131415;
+         line-height: 28px;
+         white-space: nowrap;
+      }
+
+      .titleDes {
+         font-size: max(14px, 12px);
+         font-weight: 400;
+         color: #777777;
+         line-height: 20px;
+         white-space: nowrap;
+      }
+   }
 }
 
 @keyframes rotateImg {
-
-  100% {
-    transform: rotate(360deg);
-  }
+   100% {
+      transform: rotate(360deg);
+   }
 }
 
 .playBtns {
-  margin-left: 140px;
-  display: flex;
-  align-items: center;
+   margin-left: 140px;
+   display: flex;
+   align-items: center;
+
+   :global {
+      .n-button {
+         width: 40px;
+         height: 40px;
+
+         img {
+            width: 100%;
+            height: 100%;
+         }
+      }
+   }
 
-  :global {
-    .n-button {
-      width: 40px;
-      height: 40px;
+   .disabled {
+      opacity: 0.7;
+      cursor: not-allowed;
+   }
+
+   .playBtn {
+      margin: 0 48px;
+      width: 50px;
+      height: 50px;
 
       img {
-        width: 100%;
-        height: 100%;
+         display: block;
+         width: 100%;
+         height: 100%;
       }
-    }
-  }
-
-  .playBtn {
-    width: 50px;
-    height: 50px;
-    margin: 0 48px;
-    background: linear-gradient(to right bottom, #44CAFE, #007AFE);
-
-    img {
-      display: block;
-      // width: 18px;
-      height: 20px;
-    }
-  }
+   }
 }
 
 .timeWrap {
-  flex: 1;
-  display: flex;
-  align-items: center;
-  margin-left: 88px;
-
-  .timeProgress {
-    margin-right: 24px;
-    border-radius: 6px;
-    --n-rail-height: 8px !important;
-  }
-
-  .time {
-    width: 90px;
-    white-space: nowrap;
-    flex-shrink: 0;
-  }
-}
+   flex: 1;
+   display: flex;
+   align-items: center;
+   margin-left: 88px;
+
+   .timeProgress {
+      margin-right: 24px;
+      border-radius: 6px;
+      --n-rail-height: 5px !important;
+      --n-fill-color: #ff531c !important;
+      --n-fill-color-hover: #ff531c !important;
+   }
+
+   .time {
+      width: 90px;
+      white-space: nowrap;
+      flex-shrink: 0;
+      color: #777777;
+   }
+}
+
+.iconArrow {
+   position: absolute;
+   top: -24px;
+   right: 30px;
+   display: flex;
+   align-items: center;
+   justify-content: center;
+   background-color: #fff;
+   cursor: pointer;
+   background: #ffffff;
+   border-radius: 100px 100px 0px 0px;
+   width: 44px;
+   height: 24px;
+   img {
+      margin-top: 3px;
+      width: 14px;
+      height: 14px;
+   }
+   //  &::before {
+   //     content: "";
+   //     display: inline-block;
+   //     background: url("../../../../img/cloudPractice/song-arrow.png") no-repeat center #fff;
+   //     background-size: contain;
+   //     width: 14px;
+   //     height: 14px;
+   //     margin-top: -4px;
+   //  }
+
+   &.down {
+      img {
+        margin-top: 0px;
+         transform: rotate(180deg);
+      }
+   }
+}

+ 211 - 210
src/views/cloudPractice/component/play-item/index.tsx

@@ -1,225 +1,226 @@
-import {
-  PropType,
-  Transition,
-  computed,
-  defineComponent,
-  reactive,
-  ref,
-  watch
-} from 'vue';
-import styles from './index.module.scss';
-import { NButton, NImage, NProgress, NSlider } from 'naive-ui';
+import { PropType, computed, defineComponent, reactive, ref, watch } from "vue"
+import styles from "./index.module.scss"
+import { NButton, NImage, NProgress, NSlider } from "naive-ui"
 // import { IMusicItem } from '../../type';
-import icon_pre from '../../img/cloudPractice/icon_pre.png';
-import icon_next from '../../img/cloudPractice/icon_next.png';
-import icon_play from '../../img/cloudPractice/icon_play.png';
-import icon_pause from '../../img/cloudPractice/icon_pause.png';
-import { getSecondRPM } from '@/libs/utils';
+import icon_pre from "../../../../img/cloudPractice/icon_pre.png"
+import icon_next from "../../../../img/cloudPractice/icon_next.png"
+import icon_play from "../../../../img/cloudPractice/icon_play.png"
+import icon_pause from "../../../../img/cloudPractice/icon_pause.png"
+import song_arrow from "../../../../img/cloudPractice/song-arrow.png"
+import { getSecondRPM } from "@/libs/utils"
 // import TheNoticeBar from '/src/components/TheNoticeBar';
 
 export default defineComponent({
-  name: 'playItem',
-  props: {
-    item: {
-      type: Object as PropType<any>,
-      default: () => ({})
-    },
-    show: {
-      type: Boolean,
-      default: false
-    },
-    playState: {
-      type: String as PropType<'play' | 'pause'>,
-      default: 'pause'
-    },
-    type: {
-      type: String,
-      default: ''
-    }
-  },
-  emits: ['change'],
-  setup(props, { emit }) {
-    let timer = null as any;
-    const audioData = reactive({
-      isFirst: true,
-      duration: 0,
-      currentTime: 0
-    });
-    const audioRef = ref();
-    /** 加载成功 */
-    const onLoadedmetadata = () => {
-      audioData.duration = audioRef.value?.duration;
-      if (audioData.isFirst) {
-        audioData.isFirst = false;
-        return;
-      }
-      if (props.playState === 'play') {
-        audioRef.value.play();
+   name: "playItem",
+   props: {
+      item: {
+         type: Object as PropType<any>,
+         default: () => ({})
+      },
+      show: {
+         type: Boolean,
+         default: false
+      },
+      playState: {
+         type: String as PropType<"play" | "pause">,
+         default: "pause"
+      },
+      type: {
+         type: String,
+         default: ""
+      },
+      songPrevNextStatus: {
+         type: Object,
+         default: () => ({})
       }
+   },
+   emits: ["change", "show"],
+   setup(props, { emit }) {
+      let timer = null as any
+      const audioData = reactive({
+         isFirst: true,
+         duration: 0,
+         currentTime: 0
+      })
+      const audioRef = ref()
+      /** 加载成功 */
+      const onLoadedmetadata = () => {
+         audioData.duration = audioRef.value?.duration
+         if (audioData.isFirst) {
+            audioData.isFirst = false
+            return
+         }
+         if (props.playState === "play") {
+            audioRef.value.play()
+         }
 
-      // 判断是否有链接
-      if (!props.item.audioFileUrl && !props.item.metronomeUrl) {
-        emit('change', 'pause');
+         // 判断是否有链接
+         if (!props.item.audioFileUrl && !props.item.metronomeUrl) {
+            emit("change", "pause")
+         }
       }
-    };
-    /** 改变时间 */
-    const handleChangeTime = (val: number) => {
-      audioRef.value.pause();
-      audioData.currentTime = val;
-      clearTimeout(timer);
-      timer = setTimeout(() => {
-        audioRef.value.currentTime = val;
-        if (props.playState === 'play') {
-          audioRef.value.play();
-        }
-        timer = null;
-      }, 300);
-    };
-    const time = computed(() => {
-      return `${getSecondRPM(audioData.currentTime)} / ${getSecondRPM(
-        audioData.duration
-      )}`;
-    });
-
-    watch(
-      () => props.playState,
-      val => {
-        if (val === 'play') {
-          audioRef.value.play().catch((err: any) => {
-            console.log(err, '22');
-            audioRef.value.play();
-          });
-        } else {
-          audioRef.value.pause();
-        }
+      /** 改变时间 */
+      const handleChangeTime = (val: number) => {
+         audioRef.value.pause()
+         audioData.currentTime = val
+         clearTimeout(timer)
+         timer = setTimeout(() => {
+            audioRef.value.currentTime = val
+            if (props.playState === "play") {
+               audioRef.value.play()
+            }
+            timer = null
+         }, 300)
       }
-    );
+      const time = computed(() => {
+         return `${getSecondRPM(audioData.currentTime)} / ${getSecondRPM(audioData.duration)}`
+      })
 
-    watch(
-      () => props.item,
-      () => {
-        // 判断是否有链接
-        if (!props.item.audioFileUrl && !props.item.metronomeUrl) {
-          emit('change', 'pause');
-        }
-      }
-    );
+      watch(
+         () => props.playState,
+         val => {
+            console.log(props.playState, "props.playState")
+            if (val === "play") {
+               audioRef.value.play().catch(() => {
+                  audioRef.value.play()
+               })
+            } else {
+               audioRef.value.pause()
+            }
+         }
+      )
+
+      watch(
+         () => props.item,
+         () => {
+            // 判断是否有链接
+            console.log(props.item, "props.item")
+            if (!props.item.audioFileUrl && !props.item.metronomeUrl) {
+               emit("change", "pause")
+            }
+         }
+      )
 
-    return () => (
-      <div
-        class={[
-          styles.container,
-          props.type === 'preview' && styles.previewcontainer,
-          props.type === 'modal' && styles.containerModal,
-          props.show ? styles.show : styles.hidden
-        ]}>
-        <div class={[styles.item]}>
-          <div
+      return () => (
+         <div
             class={[
-              styles.img,
-              props.playState !== 'play' && styles.imgRotate
-            ]}>
-            <NImage
-              lazy
-              objectFit="cover"
-              previewDisabled={true}
-              src={
-                props.item.titleImg ||
-                'https://oss.dayaedu.com/klx/16983720423251690789356356.png'
-              }
-              onLoad={(e: any) => {
-                (e.target as any).dataset.loaded = 'true';
-              }}
-            />
+               styles.container,
+               props.type === "preview" && styles.previewcontainer,
+               props.type === "modal" && styles.containerModal,
+               props.show ? styles.show : styles.hidden
+            ]}
+         >
+            <div class={[styles.item]}>
+               <div class={[styles.img, props.playState !== "play" && styles.imgRotate]}>
+                  <NImage
+                     lazy
+                     objectFit="cover"
+                     previewDisabled={true}
+                     src={props.item.titleImg || "https://oss.dayaedu.com/klx/16983720423251690789356356.png"}
+                     onLoad={(e: any) => {
+                        ;(e.target as any).dataset.loaded = "true"
+                     }}
+                  />
 
-            <svg class={styles.svgcontainer}>
-              <defs>
-                <linearGradient id="GradientProgress">
-                  <stop stop-color="#5BECFF" offset="0%" />
-                  <stop stop-color="#259CFE" offset="100%" />
-                </linearGradient>
-              </defs>
-            </svg>
+                  <svg class={styles.svgcontainer}>
+                     <defs>
+                        <linearGradient id="GradientProgress">
+                           <stop stop-color="#FF5B20" offset="0%" />
+                           <stop stop-color="#FF9946" offset="100%" />
+                        </linearGradient>
+                     </defs>
+                  </svg>
 
-            <NProgress
-              type="circle"
-              class={styles.progress}
-              showIndicator={false}
-              percentage={(audioData.currentTime / audioData.duration) * 100}
-            />
-          </div>
-          <div class={styles.title}>
-            <div class={styles.titleName}>
-              {/* <TheNoticeBar text={props.item.musicSheetName} /> */}
-              {props.item.musicSheetName}
-            </div>
-            <div class={styles.titleDes}>{props.item.composer}</div>
-          </div>
+                  <NProgress
+                     type="circle"
+                     class={styles.progress}
+                     showIndicator={false}
+                     percentage={(audioData.currentTime / audioData.duration) * 100}
+                  />
+               </div>
+               <div class={styles.title}>
+                  <div class={styles.titleName}>
+                     {/* <TheNoticeBar text={props.item.musicSheetName} /> */}
+                     {props.item.name}
+                  </div>
+                  {/* <div class={styles.titleDes}>{props.item.composer}</div> */}
+               </div>
+
+               <div class={styles.playBtns}>
+                  <NButton
+                     color="rgba(246,246,246,1)"
+                     class={!props.songPrevNextStatus.prev && styles.disabled}
+                     circle
+                     bordered={false}
+                     onClick={() => emit("change", "pre")}
+                  >
+                     <img src={icon_pre as any} />
+                  </NButton>
+                  <NButton
+                     color="rgba(246,246,246,1)"
+                     class={styles.playBtn}
+                     circle
+                     bordered={false}
+                     onClick={() => emit("change", props.playState === "pause" ? "play" : "pause")}
+                  >
+                     <img
+                        style={{
+                           display: props.playState === "pause" ? "" : "none"
+                        }}
+                        src={icon_play as any}
+                     />
+                     <img
+                        style={{
+                           display: props.playState === "play" ? "" : "none"
+                        }}
+                        src={icon_pause as any}
+                     />
+                  </NButton>
+                  <NButton
+                     color="rgba(246,246,246,1)"
+                     class={!props.songPrevNextStatus.next && styles.disabled}
+                     circle
+                     bordered={false}
+                     onClick={() => emit("change", "next")}
+                  >
+                     <img src={icon_next as any} />
+                  </NButton>
+               </div>
 
-          <div class={styles.playBtns}>
-            <NButton
-              color="rgba(246,246,246,1)"
-              circle
-              bordered={false}
-              onClick={() => emit('change', 'pre')}>
-              <img src={icon_pre as any} />
-            </NButton>
-            <NButton
-              color="rgba(57,130,246,1)"
-              class={styles.playBtn}
-              circle
-              bordered={false}
-              onClick={() =>
-                emit('change', props.playState === 'pause' ? 'play' : 'pause')
-              }>
-              <img
-                style={{
-                  display: props.playState === 'pause' ? '' : 'none'
-                  // transform: 'scale(1.5) translateX(1px)'
-                }}
-                src={icon_play as any}
-              />
-              <img
-                style={{
-                  display: props.playState === 'play' ? '' : 'none'
-                  // transform: 'scale(1.5)'
-                }}
-                src={icon_pause as any}
-              />
-            </NButton>
-            <NButton
-              color="rgba(246,246,246,1)"
-              circle
-              bordered={false}
-              onClick={() => emit('change', 'next')}>
-              <img src={icon_next as any} />
-            </NButton>
-          </div>
+               <div class={styles.timeWrap}>
+                  <NSlider
+                     tooltip={false}
+                     step={0.01}
+                     class={styles.timeProgress}
+                     value={audioData.currentTime}
+                     max={audioData.duration}
+                     onUpdate:value={(val: any) => handleChangeTime(val)}
+                  />
+                  <div class={styles.time}>{time.value}</div>
+                  <audio
+                     ref={audioRef}
+                     src={props.item.audioFileUrl || props.item.metronomeUrl}
+                     onLoadedmetadata={onLoadedmetadata}
+                     onEnded={() => {
+                        emit("change", "pause")
+                     }}
+                     onTimeupdate={() => {
+                        if (timer) return
+                        audioData.currentTime = audioRef.value?.currentTime
+                     }}
+                  ></audio>
+               </div>
+            </div>
 
-          <div class={styles.timeWrap}>
-            <NSlider
-              tooltip={false}
-              step={0.01}
-              class={styles.timeProgress}
-              value={audioData.currentTime}
-              max={audioData.duration}
-              onUpdate:value={(val: any) => handleChangeTime(val)}
-            />
-            <div class={styles.time}>{time.value}</div>
-            <audio
-              ref={audioRef}
-              src={props.item.audioFileUrl || props.item.metronomeUrl}
-              onLoadedmetadata={onLoadedmetadata}
-              onEnded={() => {
-                emit('change', 'pause');
-              }}
-              onTimeupdate={() => {
-                if (timer) return;
-                audioData.currentTime = audioRef.value?.currentTime;
-              }}></audio>
-          </div>
-        </div>
-      </div>
-    );
-  }
-});
+            <div
+               class={[styles.iconArrow, props.show ? "" : styles.down]}
+               onClick={() => {
+                  emit("show", !props.show)
+               }}
+            >
+               <img src={song_arrow as any} />
+            </div>
+         </div>
+      )
+   }
+})

+ 115 - 28
src/views/cloudPractice/index.module.scss

@@ -18,10 +18,37 @@
 :global {
    .PopSelect {
       width: 184px;
-      background: #FFFFFF;
-      box-shadow: 0px 2px 17px 0px rgba(0,0,0,0.08);
+      background: #ffffff;
+      box-shadow: 0px 2px 17px 0px rgba(0, 0, 0, 0.08);
       border-radius: 12px;
       --n-space-arrow: 12px !important;
+      --n-option-height: 40px !important;
+
+      .n-base-select-menu-option-wrapper {
+         padding-top: 4px;
+         padding-bottom: 4px;
+      }
+      .n-base-select-option:hover::before {
+         background: #fff3d7 !important;
+      }
+      .n-base-select-option {
+         font-size: 16px !important;
+      }
+      .n-base-select-option.n-base-select-option--selected {
+         font-weight: 600;
+
+         color: #994d1c;
+      }
+      .n-base-select-option::before {
+         left: 6px;
+         right: 6px;
+      }
+      .n-base-select-option.n-base-select-option--selected.n-base-select-option--pending::before {
+         background-color: inherit;
+      }
+      .n-base-select-option .n-base-select-option__check {
+         display: none;
+      }
    }
 }
 .leftContainer {
@@ -120,8 +147,8 @@
       border-radius: 36px 36px 0 0;
 
       .categorySection {
-         border-bottom: 1px solid #F2F2F2;
-         padding: 0 30px 16px;
+         border-bottom: 1px solid #f2f2f2;
+         padding: 0 20px 16px;
          margin-bottom: 18px;
       }
       .iconTagName {
@@ -143,7 +170,7 @@
          height: 22px;
 
          &::after {
-            content: '';
+            content: "";
             display: inline-block;
             margin-left: 8px;
             width: 12px;
@@ -157,7 +184,7 @@
    .searchMore {
       display: flex;
       justify-content: space-between;
-      padding: 0 30px;
+      padding: 0 20px;
    }
 
    .searchSection {
@@ -214,6 +241,23 @@
       padding: 0 20px;
       // background: #fff;
       // border-radius: 16px;
+      &.wrapListEmpty {
+         display: flex;
+         align-items: center;
+         justify-content: center;
+
+         .empty {
+            margin-top: -180px;
+            --el-empty-image-width: 277px;
+            :global {
+               .el-empty__description p {
+                  font-weight: 400;
+                  font-size: 22px;
+                  color: #aaaaaa;
+               }
+            }
+         }
+      }
       .item {
          position: relative;
          display: flex;
@@ -303,14 +347,14 @@
       display: flex;
       justify-content: center;
       min-height: 80px;
-    
+
       &.showLoading {
-        height: 0;
-        opacity: 0;
-        min-height: 0;
-        display: none;
+         height: 0;
+         opacity: 0;
+         min-height: 0;
+         display: none;
       }
-    }
+   }
 }
 
 .rightContainer {
@@ -323,6 +367,19 @@
    position: relative;
    display: flex;
    flex-direction: column;
+
+   .leftArrow {
+      position: absolute;
+      top: 245px;
+      left: -17px;
+      display: inline-block;
+      width: 28px;
+      height: 28px;
+      background: #ffffff;
+      border-radius: 6px;
+      transform: rotate(45deg);
+   }
+
    .goBtn {
       position: absolute;
       left: 50%;
@@ -346,31 +403,49 @@
       flex: 1;
       // overflow-y: auto;
       height: 100%;
+      width: 100%;
       padding: 0 30px;
 
       & > img {
          width: 100%;
       }
 
+      &.staffImgsEmpty {
+         display: flex;
+         align-items: center;
+         justify-content: center;
+         .empty {
+            margin-top: -80px;
+            --el-empty-image-width: 277px;
+            :global {
+               .el-empty__description p {
+                  font-weight: 400;
+                  font-size: 22px;
+                  color: #aaaaaa;
+               }
+            }
+         }
+      }
+
       :global {
          iframe {
-           // visibility: hidden;
-           border: none;
-           width: 100%;
-           // height: 500px;
-           flex: 1 auto;
-           overflow: hidden;
-     
-           body {
-             ::-webkit-scrollbar-thumb {
-               background-color: #efeff0;
-               border: 1px solid transparent;
-               background-clip: padding-box;
-               border-radius: 5px;
-             }
-           }
+            // visibility: hidden;
+            border: none;
+            width: 100%;
+            // height: 500px;
+            flex: 1 auto;
+            overflow: hidden;
+
+            body {
+               ::-webkit-scrollbar-thumb {
+                  background-color: #efeff0;
+                  border: 1px solid transparent;
+                  background-clip: padding-box;
+                  border-radius: 5px;
+               }
+            }
          }
-       }
+      }
    }
 
    .rightBtns {
@@ -405,4 +480,16 @@
          }
       }
    }
+
+   :global {
+      .n-spin-container {
+         height: 100%;
+      }
+      .n-spin-content {
+         height: 100%;
+         display: flex;
+         align-items: center;
+         flex-direction: column;
+      }
+   }
 }

+ 9 - 9
src/views/cloudPractice/instrument.ts

@@ -191,7 +191,7 @@ export const onlyVisible = (xml: string, partIndex: number): string => {
          }
       })
       // 处理装饰音问题
-      const notes = xmlParse.getElementsByTagName("note")
+      // const notes = xmlParse.getElementsByTagName("note")
       // const getNextvNoteDuration = (i: number) => {
       //    let nextNote = notes[i + 1]
       //    // 可能存在多个装饰音问题,取下一个非装饰音时值
@@ -205,14 +205,14 @@ export const onlyVisible = (xml: string, partIndex: number): string => {
       //    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))
-            // }
-         }
-      })
+      // Array.from(notes).forEach((note) => {
+      //    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))

+ 20 - 121
src/views/cloudPractice/useData.ts

@@ -1,141 +1,40 @@
 // 处理 区分处理管乐迷 管乐团的数据
 
-import { queryTree_gym } from "@/api/cloudPractice.api"
+// import { queryTree_gym } from "@/api/cloudPractice.api"
+import { URL_TEACH_GYM, URL_TEACH_GYT, URL_TEACH_KLX } from "@/config"
+import { getToken } from "@/libs/auth"
 
-import { httpAjaxErrMsg, httpAjax } from "@/plugin/httpAjax"
+// import { httpAjaxErrMsg, httpAjax } from "@/plugin/httpAjax"
 // import { CODE_ERR_CANCELED } from "@/libs/auth"
 // import { ElMessage } from "element-plus"
 
 import userStore from "@/store/modules/user"
-import { ref, shallowRef } from "vue"
+import { ref } from "vue"
 
 /**
  * 搜索数据
  */
-export const useDataSearchObj = () => {
+export const useFunction = () => {
    const userStoreHook = userStore()
    const loading = ref(false)
-   // let coursewareController: AbortController
-   const storeData = shallowRef<any[]>([])
 
-   async function handleSearchList_gym() {
-      loading.value = true
-      await httpAjaxErrMsg(queryTree_gym).then(res => {
-         loading.value = false
-         if (res.code === 200) {
-            storeData.value = res.data || []
-         }
-      })
+   /** 跳转云教练 */
+   const goToCloud = (musicId: string) => {
+      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`
+      }
+      window.open(urlObj[userStoreHook.roles!], "_blank")
    }
 
-   function handleGetSearchList() {
-      userStoreHook.roles === "GYM" ? handleSearchList_gym() : () => {}
-   }
-
-   return { loading, storeData, handleGetSearchList }
+   return { loading, goToCloud }
 }
 
-// type listType = {
-//    type: string
-//    name: string
-//    img: string
-//    id: string
-//    courseNum: number // 课程数量
-// }[][]
-
-/**
- * 列表数据
- */
-// export const useDataList = () => {
-//    const userStoreHook = userStore()
-//    const listData = shallowRef<listType>([])
-//    let storeData: listType[number] = []
-//    const loading = ref(false)
-//    let coursewareController: AbortController
-
-//    function handleGetList() {
-//       userStoreHook.roles === "GYM" ? handleGetList_gym("", "") : handleGetList_gyt()
-//    }
-//    function handleListQuery(type: string, queryStr: string) {
-//       userStoreHook.roles === "GYM" ? handleQueryGetList_gym(type, queryStr) : handleQueryGetList_gyt(type, queryStr)
-//    }
-
-//    // 获取管乐团数据
-//    function handleGetList_gyt() {
-//       loading.value = true
-//       httpAjaxErrMsg(getMyCourseware_gyt).then(res => {
-//          loading.value = false
-//          if (res.code === 200) {
-//             storeData = (res.data || []).map((item: any) => {
-//                return {
-//                   name: item.name,
-//                   type: item.courseTypeCode,
-//                   img: item.coverImg,
-//                   id: item.id,
-//                   courseNum: item.courseNum
-//                }
-//             })
-//             listData.value = chunkArray(storeData, 5)
-//          }
-//       })
-//    }
-//    // 管乐团数据查询
-//    function handleQueryGetList_gyt(type: string, queryStr: string) {
-//       const computeData = storeData.filter(item => {
-//          return (type ? item.type === type : true) && (queryStr ? item.name.includes(queryStr) : true)
-//       })
-//       listData.value = chunkArray(computeData, 5)
-//    }
-//    // 获取管乐迷数据
-//    function handleGetList_gym(type: string, queryStr: string) {
-//       if (coursewareController) {
-//          coursewareController.abort()
-//       }
-//       coursewareController = new AbortController()
-//       loading.value = true
-//       httpAjax(queryLessonCourseware_gym, type, coursewareController).then(res => {
-//          // 自己关闭的时候不取消加载
-//          if (res.code === CODE_ERR_CANCELED) {
-//             return
-//          }
-//          loading.value = false
-//          if (res.code === 200) {
-//             const data = (res.data?.rows || []).reduce((arr: any[], item: any) => {
-//                if ((type ? item.subjectId === type : true) && (queryStr ? item.name.includes(queryStr) : true)) {
-//                   arr.push({
-//                      name: item.name,
-//                      type: item.subjectId,
-//                      img: item.cover,
-//                      id: item.lessonCoursewareId,
-//                      courseNum: item.courseNum
-//                   })
-//                }
-//                return arr
-//             }, [])
-//             listData.value = chunkArray(data, 5)
-//          } else {
-//             if (res.code !== 511) {
-//                ElMessage({
-//                   showClose: true,
-//                   message: res.message,
-//                   type: "error"
-//                })
-//             }
-//          }
-//       })
-//    }
-//    // 管乐迷数据查询
-//    function handleQueryGetList_gym(type: string, queryStr: string) {
-//       handleGetList_gym(type, queryStr)
+// function chunkArray(array: any[], size: number) {
+//    const result = []
+//    for (let i = 0; i < array.length; i += size) {
+//       result.push(array.slice(i, i + size))
 //    }
-
-//    return { loading, listData, handleGetList, handleListQuery }
+//    return result
 // }
-
-function chunkArray(array: any[], size: number) {
-   const result = []
-   for (let i = 0; i < array.length; i += size) {
-      result.push(array.slice(i, i + size))
-   }
-   return result
-}