Browse Source

Merge branch 'iteration-20250313-light' into jenkins-test

lex-xin 3 months ago
parent
commit
f7fb8e541a
27 changed files with 1740 additions and 1665 deletions
  1. 1 1
      dev-dist/sw.js
  2. 61 60
      src/components/CBreadcrumb/index.module.less
  3. 1 0
      src/components/card-preview/video-modal/index.module.less
  4. 1 2
      src/components/card-type/index.tsx
  5. 14 0
      src/styles/index.less
  6. 1 1
      src/views/classList/index.tsx
  7. 4 4
      src/views/content-information/content-instrument/detail.module.less
  8. 4 4
      src/views/content-information/content-knowledge/index.module.less
  9. 4 4
      src/views/content-information/content-music/detail.module.less
  10. 8 7
      src/views/content-information/content-music/detail.tsx
  11. 71 69
      src/views/content-information/useSpeak.ts
  12. 34 12
      src/views/home/components/practiceData.tsx
  13. 4 4
      src/views/prepare-lessons/model/source-instrument/detail.module.less
  14. 6 6
      src/views/prepare-lessons/model/source-knowledge/index.module.less
  15. 4 4
      src/views/prepare-lessons/model/source-music/detail.module.less
  16. 2 3
      src/views/setting/components/personInfo.tsx
  17. 1 5
      src/views/setting/components/schoolInfo/index.module.less
  18. 9 10
      src/views/setting/components/schoolInfo/index.tsx
  19. 8 1
      src/views/setting/index.module.less
  20. 6 6
      src/views/studentList/components/evaluationRecords.tsx
  21. 2 2
      src/views/studentList/index.module.less
  22. 512 509
      src/views/xiaoku-list/detail.module.less
  23. 445 435
      src/views/xiaoku-list/detail.tsx
  24. 18 18
      src/views/xiaoku-list/images/icon-arrow-up.svg
  25. 499 493
      src/views/xiaoku-list/search-group-resources.tsx
  26. 19 4
      src/views/xiaoku-music/component/play-item/index.module.less
  27. 1 1
      vite.config.ts

+ 1 - 1
dev-dist/sw.js

@@ -85,7 +85,7 @@ define(['./workbox-16108a29'], (function (workbox) { 'use strict';
     "revision": "3ca0b8505b4bec776b69afdba2768812"
   }, {
     "url": "index.html",
-    "revision": "0.3ahmnbktjto"
+    "revision": "0.dtujgcro8to"
   }], {});
   workbox.cleanupOutdatedCaches();
   workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {

+ 61 - 60
src/components/CBreadcrumb/index.module.less

@@ -1,61 +1,62 @@
-.CBreadcrumb {
-  margin-bottom: 20px;
-
-  .icon_back {
-    width: 36px;
-    height: 36px;
-  }
-
-  :global {
-    .option.n-base-select-option {
-      justify-content: center;
-    }
-
-    .option.n-base-select-option.n-base-select-option--pending::before {
-      background-color: #198cfe !important;
-    }
-
-    .option.n-base-select-option.n-base-select-option--pending .n-base-select-option__content {
-      color: #fff !important;
-      text-align: center;
-    }
-  }
-
-  :global {
-    .n-breadcrumb>ul {
-      display: flex !important;
-      align-items: center !important;
-
-      .n-breadcrumb-item {
-        display: flex !important;
-        align-items: center !important;
-      }
-
-      .n-breadcrumb-item__separator {
-        display: none !important;
-      }
-
-      .n-breadcrumb-item__link {
-        padding: 5px 18px !important;
-        background: #ffffff !important;
-        border-radius: 16px;
-        color: #21225d !important;
-        line-height: 20px !important;
-      }
-    }
-
-    .n-breadcrumb .n-breadcrumb-item:last-child .n-breadcrumb-item__link {
-      color: #fff !important;
-      background: var(--product-color) !important;
-    }
-  }
-
-  &> :global(.n-space) {
-    height: 36px !important;
-  }
-
-  .separator {
-    height: 18px !important;
-    margin: 0 16px !important;
-  }
+.CBreadcrumb {
+  margin-bottom: 20px;
+
+  .icon_back {
+    width: 36px;
+    height: 36px;
+  }
+
+  :global {
+    .option.n-base-select-option {
+      justify-content: center;
+      padding-left: 0;
+    }
+
+    .option.n-base-select-option.n-base-select-option--pending::before {
+      background-color: #198cfe !important;
+    }
+
+    .option.n-base-select-option.n-base-select-option--pending .n-base-select-option__content {
+      color: #fff !important;
+      text-align: center;
+    }
+  }
+
+  :global {
+    .n-breadcrumb>ul {
+      display: flex !important;
+      align-items: center !important;
+
+      .n-breadcrumb-item {
+        display: flex !important;
+        align-items: center !important;
+      }
+
+      .n-breadcrumb-item__separator {
+        display: none !important;
+      }
+
+      .n-breadcrumb-item__link {
+        padding: 5px 18px !important;
+        background: #ffffff !important;
+        border-radius: 16px;
+        color: #21225d !important;
+        line-height: 20px !important;
+      }
+    }
+
+    .n-breadcrumb .n-breadcrumb-item:last-child .n-breadcrumb-item__link {
+      color: #fff !important;
+      background: var(--product-color) !important;
+    }
+  }
+
+  &> :global(.n-space) {
+    height: 36px !important;
+  }
+
+  .separator {
+    height: 18px !important;
+    margin: 0 16px !important;
+  }
 }

+ 1 - 0
src/components/card-preview/video-modal/index.module.less

@@ -9,6 +9,7 @@
 // }
 
 .videoWrap {
+  margin-top: -1px;
   width: 100%;
   height: 100%;
   height: 518px;

+ 1 - 2
src/components/card-type/index.tsx

@@ -322,12 +322,11 @@ export default defineComponent({
                     previewSrc={props.item.content}
                     renderToolbar={({ nodes }: ImageRenderToolbarProps) => {
                       return [
-                        nodes.prev,
-                        nodes.next,
                         nodes.rotateCounterclockwise,
                         nodes.rotateClockwise,
                         nodes.resizeToOriginalSize,
                         nodes.zoomOut,
+                        nodes.zoomIn,
                         nodes.close
                       ];
                     }}

+ 14 - 0
src/styles/index.less

@@ -587,6 +587,20 @@ body > .n-drawer-container-relative {
   }
 }
 
+label.showBgColor {
+  background-color: #e1f0ff;
+}
+label.showBgColor.highlight {
+  color: #0378ec;
+  background-color: #e1f0ff;
+}
+label.highlight {
+  .showBgColor {
+    color: #0378ec;
+    background-color: #e1f0ff;
+  }
+}
+
 .cardPreviewGuide {
   width: 920px;
   overflow: hidden;

+ 1 - 1
src/views/classList/index.tsx

@@ -675,7 +675,7 @@ export default defineComponent({
           <div class={styles.studentRemove}>
             <p>
               确定要删除班级么?
-              <span>删除班级信息将会清空</span>
+              <span>删除班级信息将会清空</span>
             </p>
 
             <NSpace class={styles.btnGroup} justify="center">

+ 4 - 4
src/views/content-information/content-instrument/detail.module.less

@@ -37,10 +37,10 @@
     }
 
 
-    .highlight {
-      color: #0378EC;
-      background-color: #E1F0FF;
-    }
+    // .highlight {
+    //   color: #0378EC;
+    //   background-color: #E1F0FF;
+    // }
 
     .speak-label {
       cursor: pointer;

+ 4 - 4
src/views/content-information/content-knowledge/index.module.less

@@ -36,10 +36,10 @@
       background: var(--product-color);
     }
 
-    .highlight {
-      color: #0378EC;
-      background-color: #E1F0FF;
-    }
+    // .highlight {
+    //   color: #0378EC;
+    //   background-color: #E1F0FF;
+    // }
 
     .speak-label {
       cursor: pointer;

+ 4 - 4
src/views/content-information/content-music/detail.module.less

@@ -36,10 +36,10 @@
       background: var(--product-color);
     }
 
-    .highlight {
-      color: #0378EC;
-      background-color: #E1F0FF;
-    }
+    // .highlight {
+    //   color: #0378EC;
+    //   background-color: #E1F0FF;
+    // }
 
     .speak-label {
       cursor: pointer;

+ 8 - 7
src/views/content-information/content-music/detail.tsx

@@ -128,12 +128,13 @@ export default defineComponent({
       const doc = parser.parseFromString(res.data.intros, 'text/html');
 
       // 提取并分割 HTML 文档中的内容
-      const result = document.createElement("div")
-        result.classList.add("html-to-dom")
-        result.appendChild(speak.processNode(doc.body))
-      document
-        .querySelector('#musicContent')
-        ?.appendChild(result);
+      const result = document.createElement('div');
+      result.classList.add('html-to-dom');
+      result.appendChild(speak.processNode(doc.body));
+      // result.appendChild(doc.body);
+
+      // console.log(result.outerHTML)
+      document.querySelector('#musicContent')?.appendChild(result);
       data.details = res.data;
       data.loading = false;
     };
@@ -394,7 +395,7 @@ export default defineComponent({
             item={activeItem.value}
             onChange={value => handleChangeAudio(value)}
             onShow={(status: boolean) => {
-              data.showPlayer = status
+              data.showPlayer = status;
             }}
           />
         )}

+ 71 - 69
src/views/content-information/useSpeak.ts

@@ -89,7 +89,7 @@ export const useSpeak = (musicContent?: string, selectionCouser?: string) => {
     const selection: any = window.getSelection();
     const range = selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
 
-    // console.log(selection, 'selection');
+
     if (selection.toString().length > 0) {
       state.showDom = true;
       const textContainer: any = document.querySelector(_musicContent);
@@ -99,7 +99,7 @@ export const useSpeak = (musicContent?: string, selectionCouser?: string) => {
         anchorOffset = 0,
         endIndex = 0,
         focusOffset = 0;
-      // console.log(selection, 'selection');
+      console.log(selection, 'selection');
 
       // 都为0的情况下判断为选中某一个段
       if (selection.focusOffset === 0 && selection.anchorOffset === 0) {
@@ -178,7 +178,7 @@ export const useSpeak = (musicContent?: string, selectionCouser?: string) => {
         const firstRect = rects[rects.length - 1];
         const x = firstRect.right;
         const y = firstRect.top;
-        const bottom = firstRect.bottom;
+        // const bottom = firstRect.bottom;
         const fHeight = firstRect.height;
         const musicContent: any = document.querySelector(_musicContent);
         const parentRect: any = musicContent?.getBoundingClientRect();
@@ -186,15 +186,6 @@ export const useSpeak = (musicContent?: string, selectionCouser?: string) => {
         const showDomRect = showDom?.getBoundingClientRect();
         if (showDom) {
           // 判断 上边超出边界
-          // if (y - parentRect?.top > showDomRect.height + fHeight / 2) {
-          //   showDom.style.top =
-          //     (
-          //       y -
-          //       parentRect?.top -
-          //       (showDomRect.height + fHeight / 2) +
-          //       musicContent?.scrollTop
-          //     ).toFixed(2) + 'px';
-          // } else {
           showDom.style.top =
             (
               y -
@@ -202,23 +193,6 @@ export const useSpeak = (musicContent?: string, selectionCouser?: string) => {
               (showDomRect.height + fHeight / 2) +
               musicContent?.scrollTop
             ).toFixed(2) + 'px';
-          // }
-
-          // console.log({
-
-          //   PWidth: parentRect?.width,
-          //   PLeft: parentRect?.left,
-          //   PRight: parentRect?.right,
-          //   x,
-          //   diff: parentRect?.right - x
-          // });
-          // console.log(
-          //   y -
-          //   parentRect?.top +
-          //   (showDomRect.height + fHeight / 2) +
-          //   musicContent?.scrollTop,
-          //   parentRect?.right - x - 6
-          // );
 
           if (parentRect?.right - x >= parentRect?.width - showDomRect.width) {
             showDom.style.right =
@@ -275,6 +249,23 @@ export const useSpeak = (musicContent?: string, selectionCouser?: string) => {
     // state.selectOptions.focusOffset = 0;
   }
 
+  // 清除所有高亮
+  function clearAllHighlights() {
+    const textContainer: any = document.querySelector(_musicContent);
+    const highlights = document.querySelectorAll('.showBgColor');
+    highlights.forEach(h => {
+      if (h.classList.contains('speak-label')) {
+        h.classList.toggle('showBgColor');
+      } else {
+        const parent: any = h.parentNode;
+        const textContent: any = h.textContent;
+        parent.replaceChild(document.createTextNode(textContent), h);
+      }
+    });
+    // 合并相邻的文本节点
+    textContainer?.normalize();
+  }
+
   /** 关闭朗读 */
   const onCloseSpeak = () => {
     // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -287,6 +278,8 @@ export const useSpeak = (musicContent?: string, selectionCouser?: string) => {
     sentences?.forEach((sentence: any, i: number) => {
       sentence.classList.toggle('highlight', i === -1);
     });
+
+    clearAllHighlights();
     clearSelection();
   };
 
@@ -330,6 +323,7 @@ export const useSpeak = (musicContent?: string, selectionCouser?: string) => {
       // });
       scrollToElement(highlightText);
     };
+
     function getOffsetTopRelativeToParent(element: any, parent: any) {
       let offsetTop = 0;
       while (element && element !== parent) {
@@ -346,7 +340,7 @@ export const useSpeak = (musicContent?: string, selectionCouser?: string) => {
       const diffTop = getOffsetTopRelativeToParent(element, musicContent);
       const musicHeight = musicRect.height / 2;
       let height = 0;
-      console.log(getOffsetTopRelativeToParent(element, musicContent), '12121');
+      // console.log(getOffsetTopRelativeToParent(element, musicContent), '12121');
       if (diffTop - musicHeight >= 0) {
         height = diffTop - musicHeight;
       } else {
@@ -359,16 +353,57 @@ export const useSpeak = (musicContent?: string, selectionCouser?: string) => {
       });
     }
 
+    // 初始化高亮显示
+    const initLightText = () => {
+
+      sentences?.forEach((sentence: any, i: number) => {
+        if (i >= currentSentenceIndex && i <= end) {
+          const text = sentence.textContent;
+
+          if (currentSentenceIndex === end) {
+            const range = document.createRange();
+            range.setStart(sentence.firstChild, options.anchorOffset || 0);
+            range.setEnd(
+              sentence.firstChild,
+              options?.focusOffset || text.length
+            );
+            const label = document.createElement('label');
+            label.classList.add('showBgColor');
+            range.surroundContents(label);
+          } else {
+            if (currentSentenceIndex === i) {
+              const range = document.createRange();
+              range.setStart(sentence.firstChild, options.anchorOffset || 0);
+              range.setEnd(sentence.firstChild, text.length);
+              const label = document.createElement('label');
+              label.classList.add('showBgColor');
+              range.surroundContents(label);
+            } else if (end === i) {
+              const range = document.createRange();
+              range.setStart(sentence.firstChild, 0);
+              range.setEnd(
+                sentence.firstChild,
+                options?.focusOffset || text.length
+              );
+              const label = document.createElement('label');
+              label.classList.add('showBgColor');
+              range.surroundContents(label);
+            } else {
+              sentence.classList.add('showBgColor');
+            }
+          }
+        }
+        // sentence.classList.toggle('highlight', i === index);
+      });
+    };
+
+    initLightText();
+
     // 开始播放
     const speaker = () => {
       try {
         state.synth = window.speechSynthesis;
 
-        // 获取可用的 voice 列表
-        // const voices = speechSynthesis.getVoices();
-        // 选择一个特定的 voice
-        // const voice = voices.find(voice => voice.lang === 'zh-CN');
-        // console.log(voice, 'voice');
         // 如果当前正在播放,先暂停
         if (state.synth.speaking) {
           state.synth.cancel(); // 取消当前播放
@@ -409,7 +444,6 @@ export const useSpeak = (musicContent?: string, selectionCouser?: string) => {
           });
         }
 
-        console.log(sentence, currentSentenceIndex, end, '---------');
         const utterance = new SpeechSynthesisUtterance(sentence);
         utterance.lang = 'zh-CN';
         utterance.volume = 1;
@@ -423,8 +457,6 @@ export const useSpeak = (musicContent?: string, selectionCouser?: string) => {
           utterance.onerror = null;
         }
 
-        // console.log(sentence, utterance);
-
         utterance.onstart = () => {
           state.isSpeak = true;
           highlightSentence(currentSentenceIndex);
@@ -437,6 +469,7 @@ export const useSpeak = (musicContent?: string, selectionCouser?: string) => {
           } else {
             currentSentenceIndex = 0; // 结束后重置索引
             highlightSentence(-1); // 清除高亮
+            clearAllHighlights();
             state.isSpeak = false;
           }
         };
@@ -454,37 +487,6 @@ export const useSpeak = (musicContent?: string, selectionCouser?: string) => {
       } catch (e) {
         console.log(e, 'e');
       }
-
-      // 事件监听(如果需要)
-      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
-      // @ts-ignore
-      // responsiveVoice.speak(sentence, 'Chinese Male', {
-      //   onstart: () => {
-      //     console.log('开始朗读');
-      //     state.isSpeak = true;
-      //     highlightSentence(currentSentenceIndex);
-      //   },
-      //   onend: () => {
-      //     console.log('朗读结束');
-      //     currentSentenceIndex++;
-      //     if (currentSentenceIndex <= end && state.isSpeak) {
-      //       speaker(); // 继续下一个句子
-      //     } else {
-      //       currentSentenceIndex = 0; // 结束后重置索引
-      //       highlightSentence(-1); // 清除高亮
-      //       state.isSpeak = false;
-      //     }
-      //   },
-      //   onerror: (e: any) => {
-      //     console.error('朗读错误:', e);
-      //     currentSentenceIndex++;
-      //     if (currentSentenceIndex <= end && state.isSpeak) {
-      //       speaker(); // 继续下一个句子
-      //     } else {
-      //       state.isSpeak = false;
-      //     }
-      //   }
-      // });
     };
 
     speaker();

+ 34 - 12
src/views/home/components/practiceData.tsx

@@ -479,20 +479,42 @@ export default defineComponent({
         series: [
           {
             data: payForm.timeList,
-            type: 'bar',
-            barWidth: '48px',
-
+            type: 'line',
+            // name: '达标人数',
+            symbolSize: 10,
+            symbol: 'circle',
+            smooth: true,
             itemStyle: {
-              normal: {
-                //这里设置柱形图圆角 [左上角,右上角,右下角,左下角]
-                barBorderRadius: [8, 8, 0, 0],
-                color: '#CDE5FF'
-              },
-              emphasis: {
-                focus: 'series',
-                color: '#3583FA' //hover时改变柱子颜色
+              color: '#198CFE',
+              borderColor: '#fff',
+              borderWidth: 3
+            },
+            lineStyle: {
+              width: 2 //设置线条粗细
+            },
+            areaStyle: {
+              color: {
+                type: 'linear',
+                x: 0,
+                y: 0,
+                x2: 0,
+                y2: 1,
+                colorStops: [
+                  {
+                    offset: 0,
+                    color: 'rgba(212, 231, 255, 1)'
+                    // 0% 处的颜色
+                  },
+                  {
+                    offset: 1,
+                    color: 'rgba(221, 235, 254, 0)' // 100% 处的颜色
+                  }
+                ]
               }
-            } as any
+            },
+            emphasis: {
+              disabled: true
+            }
           }
         ],
 

+ 4 - 4
src/views/prepare-lessons/model/source-instrument/detail.module.less

@@ -33,10 +33,10 @@
   }
 
   :global {
-    .highlight {
-      color: #0378EC;
-      background-color: #E1F0FF;
-    }
+    // .highlight {
+    //   color: #0378EC;
+    //   background-color: #E1F0FF;
+    // }
 
     .speak-label {
       cursor: pointer;

+ 6 - 6
src/views/prepare-lessons/model/source-knowledge/index.module.less

@@ -269,7 +269,7 @@
     position: relative;
     user-select: text;
     position: relative;
-    
+
     ::selection {
       background-color: #E1F0FF;
     }
@@ -281,11 +281,11 @@
     }
 
     :global {
-      .highlight {
-        color: #0378EC;
-        background-color: #E1F0FF;
-      }
-  
+      // .highlight {
+      //   color: #0378EC;
+      //   background-color: #E1F0FF;
+      // }
+
       .speak-label {
         cursor: pointer;
       }

+ 4 - 4
src/views/prepare-lessons/model/source-music/detail.module.less

@@ -21,10 +21,10 @@
   }
 
   :global {
-    .highlight {
-      color: #0378EC;
-      background-color: #E1F0FF;
-    }
+    // .highlight {
+    //   color: #0378EC;
+    //   background-color: #E1F0FF;
+    // }
 
     .speak-label {
       cursor: pointer;

+ 2 - 3
src/views/setting/components/personInfo.tsx

@@ -13,13 +13,12 @@ import {
   SelectOption,
   useMessage,
   NModal,
-  NCalendar,
   NCascader
 } from 'naive-ui';
 import headerD from '../images/headerD.png';
 import defultHeade from '@/components/layout/images/teacherIcon.png';
-import maleIcon from '../images/maleIcon.png';
-import femaleIcon from '../images/femaleIcon.png';
+// import maleIcon from '../images/maleIcon.png';
+// import femaleIcon from '../images/femaleIcon.png';
 import { useUserStore } from '/src/store/modules/users';
 import { api_teacherUpdate } from '/src/api/user';
 import UploadFile from '/src/components/upload-file';

+ 1 - 5
src/views/setting/components/schoolInfo/index.module.less

@@ -119,11 +119,7 @@
   }
 
   .errorBtn {
-    :global {
-      .n-button__content {
-        color: #FF4D4F;
-      }
-    }
+    color: #FF4D4F;
   }
 
 }

+ 9 - 10
src/views/setting/components/schoolInfo/index.tsx

@@ -123,11 +123,9 @@ export default defineComponent({
             return (
               <div>
                 {row.status === 'ACTIVATION' ? (
-                  <NButton text>启用</NButton>
+                  '启用'
                 ) : (
-                  <NButton class={styles.errorBtn} text>
-                    冻结
-                  </NButton>
+                  <div class={styles.errorBtn}>冻结</div>
                 )}
               </div>
             );
@@ -181,21 +179,22 @@ export default defineComponent({
                   解冻
                 </NButton>
               )}
-
             </NSpace>
           )
         }
       ];
     };
 
-
     const btnStatus = (row: any, type?: string) => {
       // 管理员
-      if(user.info.teacherJobType === "ADMIN" && ["ADMIN", "HEADMASTER"].includes(row.jobType)) {
-        return true
+      if (
+        user.info.teacherJobType === 'ADMIN' &&
+        ['ADMIN', 'HEADMASTER'].includes(row.jobType)
+      ) {
+        return true;
       }
-      return false
-    }
+      return false;
+    };
 
     const getAreaList = async () => {
       const res = await api_sysAreaQueryAllProvince();

+ 8 - 1
src/views/setting/index.module.less

@@ -1,10 +1,16 @@
 @img: './images';
 
 .listWrap {
-  min-height: 805px;
+  // min-height: 805px;
+  height: 100%;
   padding: 32px;
   background-color: #fff;
   border-radius: 20px;
+  overflow-x: hidden;
+  overflow-y: auto;
+  &::-webkit-scrollbar {
+    display: none;
+  }
 
   .customTabs {
     :global {
@@ -226,6 +232,7 @@
 :global {
   .option.n-base-select-option {
     justify-content: center;
+    padding-left: 0;
   }
 
   .option.n-base-select-option.n-base-select-option--pending::before {

+ 6 - 6
src/views/studentList/components/evaluationRecords.tsx

@@ -319,10 +319,10 @@ export default defineComponent({
                       gotoDownload(row);
                     }}>
                     下载作品
-                  </NButton></> : ''}</> 
+                  </NButton></> : ''}</>
                   : ''}
-                
-                
+
+
               </NSpace>
             );
           }
@@ -486,7 +486,7 @@ export default defineComponent({
         .catch(() => {
           message.error('下载失败');
         });
-    
+
     }
     const search = () => {
       state.pagination.page = 1;
@@ -506,7 +506,7 @@ export default defineComponent({
           getNowDateAndSunday(new Date().getTime())
         ];
       }
-      
+
       state.searchForm = {
         musicSheetName: '',
         heardLevel: null, //
@@ -625,7 +625,7 @@ export default defineComponent({
                   { label: '是', value: true },
                   { label: '否', value: false }
                 ],
-                placeholder: '请选择是否发布作品',
+                placeholder: '是否发布作品',
                 clearable: true,
                 inline: true
               } as any)}

+ 2 - 2
src/views/studentList/index.module.less

@@ -15,7 +15,7 @@
 .datePicker {
   :global {
     .n-input {
-      width: 320px !important;
+      width: 340px !important;
     }
   }
 }
@@ -166,7 +166,7 @@
 
  &.homeTrainDataPractice {
   margin-top: 20px;
- } 
+ }
 }
 
 .TrainDataTop {

+ 512 - 509
src/views/xiaoku-list/detail.module.less

@@ -1,509 +1,512 @@
-.xiaokuDetail {
-  min-height: 100%;
-  display: flex;
-  flex-direction: column;
-  img {
-    -moz-user-select: none;
-    /* 火狐浏览器 */
-    -webkit-user-drag: none;
-    /* 谷歌、Safari和Opera浏览器 */
-    -webkit-user-select: none;
-    /* 谷歌、Safari和Opera浏览器 */
-    -ms-user-select: none;
-    /* IE10+浏览器 */
-    user-select: none;
-    /* 通用 */
-    -webkit-touch-callout: none;
-    /* iOS Safari */
-  }
-}
-.detailContainer {
-  flex: 1 auto;
-  background: #ffffff;
-  border-radius: 20px;
-  :global {
-    .n-tabs-tab-pad {
-      width: 40px !important;
-    }
-
-    .n-tabs-nav {
-      padding: 22px 32px 18px;
-    }
-
-    .n-tabs-tab {
-      color: #8b8d98;
-      font-size: max(20px, 15Px);
-      padding-top: 8px;
-      padding-bottom: 8px;
-      line-height: 28px;
-
-      &.n-tabs-tab--active {
-        font-weight: 600 !important;
-        color: #131415 !important;
-      }
-    }
-
-    .n-tabs-tab__label {
-      z-index: 10;
-    }
-
-    .n-tabs-bar {
-      height: 10px;
-      background: linear-gradient(
-        90deg,
-        #77bbff 0%,
-        rgba(163, 231, 255, 0.22) 100%
-      );
-      z-index: 0;
-      bottom: 8px;
-      transition-duration: 0.03;
-    }
-
-    .n-tabs-bar--disabled {
-      background-color: #fff !important;
-    }
-
-    .n-tab-pane {
-      padding-top: 0px !important;
-    }
-  }
-
-  .inputSearch {
-    width: 480px;
-    :global {
-      .n-button {
-        padding: 0 24px;
-        // font-size: max(16px, 13px) !important;
-        color: #ffffff;
-        --n-border: none !important;
-        background: linear-gradient(312deg, #1b7af8 0%, #3cbbff 100%);
-      }
-      .n-input__input-el {
-        // font-size: max(16px, 13px) !important;
-        color: #000000;
-      }
-
-      .n-input__placeholder {
-        // font-size: max(16px, 13px) !important;
-      }
-    }
-  }
-
-  .searchSection {
-    position: relative;
-    margin: 0 32px;
-  }
-
-  .searchSectionHide {
-    visibility: hidden;
-    opacity: 0;
-    height: 0 !important;
-    line-height: 0 !important;
-  }
-}
-
-.searchGroup {
-  background: #f5f6f7;
-  border-radius: 12px;
-  padding: 20px 24px 30px;
-  position: relative;
-
-  &.searchGroupOnly {
-    padding-bottom: 6px;
-  }
-
-  .hideItem {
-    visibility: hidden;
-    opacity: 0;
-    height: 0 !important;
-    line-height: 0 !important;
-  }
-
-  .btnType {
-    gap: 0px 24px !important;
-
-    :global {
-      .n-button {
-        height: 37px;
-        padding: 0 24px;
-        font-size: max(18px, 13px);
-        color: rgba(0, 0, 0, 0.6);
-
-        &.n-button--primary-type {
-          font-weight: bold;
-          color: #fff;
-        }
-      }
-    }
-  }
-
-  :global {
-    .n-form {
-      position: relative;
-    }
-
-    .n-form-item {
-      .n-form-item-label,  .n-form-item-blank {
-        min-height: auto !important;
-      }
-      .n-form-item-label__text {
-        font-size: max(17px, 13Px);
-        // cursor: pointer;
-        display: flex;
-        align-items: center;
-        padding: 4px 0;
-        font-weight: 600;
-        color: #131415;
-        line-height: 24px;
-      }
-
-      .n-button {
-        height: 32px;
-        font-size: max(17px, 13Px);
-        border-radius: 8px;
-        color: rgba(0, 0, 0, 0.6);
-      }
-
-      .n-button--primary-type {
-        color: #131415;
-        background-color: #d2ecff !important;
-      }
-    }
-
-    .n-form-item-feedback-wrapper {
-      min-height: 14px;
-    }
-  }
-
-  .moreSearch {
-    position: absolute;
-    bottom: 0;
-    left: 50%;
-    transform: translateX(-50%);
-    font-size: max(17px, 12Px);
-    color: rgba(0,0,0,0.6);
-    cursor: pointer;
-    background: url('./images/search-bg.png') no-repeat center;
-    background-size: contain;
-    width: 222px;
-    line-height: 34px;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-
-    &::after {
-      content: '';
-      display: inline-block;
-      width: 12px;
-      height: 12px;
-      background: url('./images/icon-arrow-down.svg') no-repeat center;
-      background-size: contain;
-      margin-left: 6px;
-      margin-top: -1px;
-    }
-
-    &:hover {
-      color: #1677FF;
-      &::after {
-        background-image: url('./images/icon-arrow-up.svg');
-      }
-    }
-
-    &.activeSearch::after {
-      transform: rotate(180deg);
-      // background-image: url('./images/icon-arrow-up.svg');
-    }
-  }
-}
-
-.teachingModal {
-  width: 1100px;
-}
-
-.spaceSection {
-  width: 100%;
-  transition: 1s all ease-in;
-
-  & > div {
-    height: 34px !important;
-    display: flex !important;
-    align-items: center;
-    line-height: var(--n-blank-height);
-  }
-}
-
-.collapseWrap {
-  width: 98%;
-  display: flex;
-  flex-direction: row;
-  align-items: flex-end;
-}
-
-.collaoseGroup {
-  position: absolute;
-  display: flex;
-  align-items: center;
-  padding-left: 8px;
-}
-
-.collaoseBtn {
-  width: 32px;
-  height: 32px;
-  cursor: pointer;
-}
-
-.collaoseBtn.isStart {
-  transform: rotate(-180deg);
-}
-
-.collapsSection {
-  // padding-top: 10px;
-}
-
-.isHidden {
-  overflow: hidden;
-  transition: 1s all ease-in;
-}
-
-.hideButton {
-  visibility: hidden;
-  height: 0 !important;
-  line-height: 0 !important;
-}
-
-.popSelect {
-  font-size: 16px;
-  width: 200px;
-  box-shadow: 0px 2px 16px 0px rgba(0, 0, 0, 0.08);
-  border-radius: 11px;
-  --n-option-height: 34px;
-
-  :global {
-    .n-base-select-option__content {
-      width: 80% !important;
-    }
-  }
-}
-
-.spaceSection2 {
-  width: 100%;
-  transition: 1s all ease-in;
-  padding-right: 40px;
-
-  & > div {
-    // height: 34Px !important;
-    // display: flex !important;
-    // align-items: center;
-    &:last-child {
-      // margin-left: -12Px;
-    }
-  }
-}
-
-.textBtn {
-  background: transparent;
-  border-radius: 8px;
-  padding: 4px 20px;
-  font-size: max(17px, 13Px);
-  color: rgba(0, 0, 0, 0.6);
-  cursor: pointer;
-  display: flex;
-  align-items: center;
-  font-weight: 500;
-  line-height: 24px;
-
-  .iconArrow {
-    display: inline-block;
-    margin-left: 8px;
-    width: 8px;
-    height: 5px;
-    background: url('../content-information/images/icon-arrow2.png') no-repeat
-      center center / contain;
-    transform: rotate(180deg);
-  }
-
-  &:hover,
-  &.textBtnActive {
-    background: #d2ecff;
-    font-weight: 500;
-    color: #131415;
-  }
-
-  &:hover {
-    .iconArrow {
-      transform: rotate(0deg);
-    }
-  }
-}
-
-.sectionContainer {
-  padding: 24px 32px;
-  gap: 24px;
-  flex: 1 auto;
-  display: flex;
-  flex-wrap: wrap;
-
-  &.noSearchContainer {
-    padding-top: 0;
-  }
-}
-
-.wrapList {
-  min-height: 100%;
-  height: calc(100vh - 64px - 64px - 56px - 80px);
-
-  &.wrapListEmpty {
-    :global {
-      .n-scrollbar-content {
-        min-height: 100%;
-        display: flex;
-        flex-direction: column;
-      }
-    }
-    .empty {
-      height: 100%;
-      flex: 1 auto;
-    }
-  }
-  .loadingSection {
-    min-height: calc(100vh - 64px - 64px - 56px - 80px);
-  }
-  .loadingSectionEmpty {
-    display: flex;
-    flex-direction: column;
-  }
-}
-
-.empty {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  // height: 50vh;
-  // height: 100%;
-}
-
-.loadingWrap {
-  display: flex;
-  justify-content: center;
-  min-height: 80px;
-  position: relative;
-
-  &.showLoading {
-    height: 0;
-    opacity: 0;
-    min-height: 0;
-    display: none;
-  }
-}
-
-.sectionItem {
-  display: flex;
-  align-items: center;
-  cursor: pointer;
-  padding: 20px;
-  border-radius: 12px;
-  width: 402px;
-  background: #f5f6f7;
-  cursor: pointer;
-  transition: all .2s ease;
-  border: 2px solid #f7f8f9;
-  box-sizing: border-box;
-  &:hover {
-    transform: scale(1.01);
-    border: 2px solid rgba(0, 122, 254, 1);
-    transition: all .2s ease;
-  }
-
-  .img {
-    width: 60px;
-    height: 60px;
-    background: #ddf2ff;
-    border-radius: 8px;
-    overflow: hidden;
-    margin-right: 16px;
-    img {
-      width: inherit;
-      height: inherit;
-    }
-  }
-
-  .infos {
-    display: flex;
-    flex-direction: column;
-
-    .topName {
-      font-weight: 600;
-      font-size: max(20px, 14Px);
-      color: #131415;
-      line-height: 28px;
-      white-space: nowrap;
-      overflow: hidden;
-      text-overflow: ellipsis;
-      max-width: 270px;
-
-      span {
-        color: #198cfe;
-        font-weight: bold;
-      }
-    }
-
-    .types {
-      display: flex;
-      padding-top: 4px;
-      & > div {
-        margin-right: 4px;
-      }
-
-      .hot {
-        background: #fff3f3;
-        border-radius: 3px;
-        border: 1px solid rgba(254, 67, 67, 0.5);
-        font-size: max(12px, 11Px);
-        color: #fe4343;
-        padding: 0 5px;
-        line-height: 14Px;
-        display: flex;
-        align-items: center;
-        &::before {
-          content: '';
-          display: inline-block;
-          width: 10px;
-          height: 12px;
-          background: url('./images/icon-fire.png') no-repeat center;
-          background-size: contain;
-          margin-right: 3px;
-          vertical-align: middle;
-        }
-        span {
-          vertical-align: text-top;
-        }
-      }
-      .sing,
-      .song {
-        background: #ffffff;
-        font-size: max(12px, 11Px);
-        border-radius: 3px;
-        line-height: 16Px;
-        padding: 0 4px;
-        line-height: 1;
-        display: flex;
-        align-items: center;
-      }
-      .sing {
-        border: 1px solid rgba(243, 130, 26, 0.5);
-        color: #f3821a;
-      }
-      .song {
-        border: 1px solid rgba(21, 178, 253, 0.5);
-        color: #00adff;
-      }
-      .author {
-        color: #777777;
-        font-size: max(14px, 12Px);
-        display: flex;
-        align-items: center;
-        line-height: 1;
-      }
-    }
-  }
-}
+.xiaokuDetail {
+  min-height: 100%;
+  display: flex;
+  flex-direction: column;
+  img {
+    -moz-user-select: none;
+    /* 火狐浏览器 */
+    -webkit-user-drag: none;
+    /* 谷歌、Safari和Opera浏览器 */
+    -webkit-user-select: none;
+    /* 谷歌、Safari和Opera浏览器 */
+    -ms-user-select: none;
+    /* IE10+浏览器 */
+    user-select: none;
+    /* 通用 */
+    -webkit-touch-callout: none;
+    /* iOS Safari */
+  }
+}
+.detailContainer {
+  flex: 1 auto;
+  background: #ffffff;
+  border-radius: 20px;
+  :global {
+    .n-tabs-tab-pad {
+      width: 40px !important;
+    }
+
+    .n-tabs-nav {
+      padding: 22px 32px 18px;
+    }
+
+    .n-tabs-tab {
+      color: #8b8d98;
+      font-size: max(20px, 15Px);
+      padding-top: 8px;
+      padding-bottom: 8px;
+      line-height: 28px;
+
+      &.n-tabs-tab--active {
+        font-weight: 600 !important;
+        color: #131415 !important;
+      }
+    }
+
+    .n-tabs-tab__label {
+      z-index: 10;
+    }
+
+    .n-tabs-bar {
+      height: 10px;
+      background: linear-gradient(
+        90deg,
+        #77bbff 0%,
+        rgba(163, 231, 255, 0.22) 100%
+      );
+      z-index: 0;
+      bottom: 8px;
+      transition-duration: 0.03;
+    }
+
+    .n-tabs-bar--disabled {
+      background-color: #fff !important;
+    }
+
+    .n-tab-pane {
+      padding-top: 0px !important;
+    }
+  }
+
+  .inputSearch {
+    width: 480px;
+    :global {
+      .n-button {
+        padding: 0 24px;
+        // font-size: max(16px, 13px) !important;
+        color: #ffffff;
+        --n-border: none !important;
+        background: linear-gradient(312deg, #1b7af8 0%, #3cbbff 100%);
+      }
+      .n-input__input-el {
+        // font-size: max(16px, 13px) !important;
+        color: #000000;
+      }
+
+      .n-input__placeholder {
+        // font-size: max(16px, 13px) !important;
+      }
+    }
+  }
+
+  .searchSection {
+    position: sticky;
+    top: 0;
+    margin: 0 32px;
+    z-index: 10;
+  }
+
+  .searchSectionHide {
+    visibility: hidden;
+    opacity: 0;
+    height: 0 !important;
+    line-height: 0 !important;
+  }
+}
+
+.searchGroup {
+  background: #fff;
+  border-radius: 12px;
+  padding: 0 0 30px;
+  position: relative;
+
+  &.searchGroupOnly {
+    padding-bottom: 6px;
+  }
+
+  .hideItem {
+    visibility: hidden;
+    opacity: 0;
+    height: 0 !important;
+    line-height: 0 !important;
+  }
+
+  .btnType {
+    gap: 0px 24px !important;
+
+    :global {
+      .n-button {
+        height: 37px;
+        padding: 0 24px;
+        font-size: max(18px, 13px);
+        color: rgba(0, 0, 0, 0.6);
+
+        &.n-button--primary-type {
+          font-weight: bold;
+          color: #fff;
+        }
+      }
+    }
+  }
+
+  :global {
+    .n-form {
+      position: relative;
+    }
+
+    .n-form-item {
+      .n-form-item-label,  .n-form-item-blank {
+        min-height: auto !important;
+      }
+      .n-form-item-label__text {
+        font-size: max(17px, 13Px);
+        // cursor: pointer;
+        display: flex;
+        align-items: center;
+        padding: 4px 0;
+        font-weight: 600;
+        color: #131415;
+        line-height: 24px;
+      }
+
+      .n-button {
+        height: 32px;
+        font-size: max(17px, 13Px);
+        border-radius: 8px;
+        color: rgba(0, 0, 0, 0.6);
+      }
+
+      .n-button--primary-type {
+        color: #131415;
+        background-color: #d2ecff !important;
+      }
+    }
+
+    .n-form-item-feedback-wrapper {
+      min-height: 14px;
+    }
+  }
+
+  .moreSearch {
+    position: absolute;
+    bottom: 0;
+    left: 50%;
+    transform: translateX(-50%);
+    font-size: max(17px, 12Px);
+    color: #198CFE;
+    cursor: pointer;
+    // background: url('./images/search-bg.png') no-repeat center;
+    // background-size: contain;
+    width: 222px;
+    line-height: 34px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+
+    &::after {
+      content: '';
+      display: inline-block;
+      width: 12px;
+      height: 12px;
+      background: url('./images/icon-arrow-up.svg') no-repeat center;
+      background-size: contain;
+      margin-left: 6px;
+      margin-top: -1px;
+    }
+
+    // &:hover {
+    //   color: #198CFE;
+    //   &::after {
+    //     background-image: url('./images/icon-arrow-up.svg');
+    //   }
+    // }
+
+    &.activeSearch::after {
+      transform: rotate(180deg);
+      // background-image: url('./images/icon-arrow-up.svg');
+    }
+  }
+}
+
+.teachingModal {
+  width: 1100px;
+}
+
+.spaceSection {
+  width: 100%;
+  transition: 1s all ease-in;
+
+  & > div {
+    height: 34px !important;
+    display: flex !important;
+    align-items: center;
+    line-height: var(--n-blank-height);
+  }
+}
+
+.collapseWrap {
+  width: 98%;
+  display: flex;
+  flex-direction: row;
+  align-items: flex-end;
+}
+
+.collaoseGroup {
+  position: absolute;
+  display: flex;
+  align-items: center;
+  padding-left: 8px;
+}
+
+.collaoseBtn {
+  width: 32px;
+  height: 32px;
+  cursor: pointer;
+}
+
+.collaoseBtn.isStart {
+  transform: rotate(-180deg);
+}
+
+.collapsSection {
+  // padding-top: 10px;
+}
+
+.isHidden {
+  overflow: hidden;
+  transition: 1s all ease-in;
+}
+
+.hideButton {
+  visibility: hidden;
+  height: 0 !important;
+  line-height: 0 !important;
+}
+
+.popSelect {
+  font-size: 16px;
+  width: 200px;
+  box-shadow: 0px 2px 16px 0px rgba(0, 0, 0, 0.08);
+  border-radius: 11px;
+  --n-option-height: 34px;
+
+  :global {
+    .n-base-select-option__content {
+      width: 80% !important;
+    }
+  }
+}
+
+.spaceSection2 {
+  width: 100%;
+  transition: 1s all ease-in;
+  padding-right: 40px;
+
+  & > div {
+    // height: 34Px !important;
+    // display: flex !important;
+    // align-items: center;
+    &:last-child {
+      // margin-left: -12Px;
+    }
+  }
+}
+
+.textBtn {
+  background: transparent;
+  border-radius: 8px;
+  padding: 4px 16px;
+  font-size: max(17px, 13Px);
+  color: rgba(0, 0, 0, 0.6);
+  background: #F5F6FA;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  font-weight: 500;
+  line-height: 24px;
+
+  .iconArrow {
+    display: inline-block;
+    margin-left: 8px;
+    width: 8px;
+    height: 5px;
+    background: url('../content-information/images/icon-arrow2.png') no-repeat
+      center center / contain;
+    transform: rotate(180deg);
+  }
+
+  &:hover,
+  &.textBtnActive {
+    background: #D2ECFF;
+    font-weight: 500;
+    color: #131415;
+  }
+
+  &:hover {
+    .iconArrow {
+      transform: rotate(0deg);
+    }
+  }
+}
+
+.sectionContainer {
+  padding: 0 32px 24px;
+  gap: 24px;
+  flex: 1 auto;
+  display: flex;
+  flex-wrap: wrap;
+
+  &.noSearchContainer {
+    padding-top: 0;
+  }
+}
+
+.wrapList {
+  min-height: 100%;
+  height: calc(100vh - 64px - 64px - 56px - 80px);
+
+  &.wrapListEmpty {
+    :global {
+      .n-scrollbar-content {
+        min-height: 100%;
+        display: flex;
+        flex-direction: column;
+      }
+    }
+    .empty {
+      height: 100%;
+      flex: 1 auto;
+    }
+  }
+  .loadingSection {
+    min-height: calc(100vh - 64px - 64px - 56px - 80px);
+  }
+  .loadingSectionEmpty {
+    display: flex;
+    flex-direction: column;
+  }
+}
+
+.empty {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  // height: 50vh;
+  // height: 100%;
+}
+
+.loadingWrap {
+  display: flex;
+  justify-content: center;
+  min-height: 80px;
+  position: relative;
+
+  &.showLoading {
+    height: 0;
+    opacity: 0;
+    min-height: 0;
+    display: none;
+  }
+}
+
+.sectionItem {
+  display: flex;
+  align-items: center;
+  cursor: pointer;
+  padding: 20px;
+  border-radius: 12px;
+  width: 402px;
+  background: #f5f6f7;
+  cursor: pointer;
+  transition: all .2s ease;
+  border: 2px solid #f7f8f9;
+  box-sizing: border-box;
+  &:hover {
+    transform: scale(1.01);
+    border: 2px solid rgba(0, 122, 254, 1);
+    transition: all .2s ease;
+  }
+
+  .img {
+    width: 60px;
+    height: 60px;
+    background: #ddf2ff;
+    border-radius: 8px;
+    overflow: hidden;
+    margin-right: 16px;
+    img {
+      width: inherit;
+      height: inherit;
+    }
+  }
+
+  .infos {
+    display: flex;
+    flex-direction: column;
+
+    .topName {
+      font-weight: 600;
+      font-size: max(20px, 14Px);
+      color: #131415;
+      line-height: 28px;
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      max-width: 270px;
+
+      span {
+        color: #198cfe;
+        font-weight: bold;
+      }
+    }
+
+    .types {
+      display: flex;
+      padding-top: 4px;
+      & > div {
+        margin-right: 4px;
+      }
+
+      .hot {
+        background: #fff3f3;
+        border-radius: 3px;
+        border: 1px solid rgba(254, 67, 67, 0.5);
+        font-size: max(12px, 11Px);
+        color: #fe4343;
+        padding: 0 5px;
+        line-height: 14Px;
+        display: flex;
+        align-items: center;
+        &::before {
+          content: '';
+          display: inline-block;
+          width: 10px;
+          height: 12px;
+          background: url('./images/icon-fire.png') no-repeat center;
+          background-size: contain;
+          margin-right: 3px;
+          vertical-align: middle;
+        }
+        span {
+          vertical-align: text-top;
+        }
+      }
+      .sing,
+      .song {
+        background: #ffffff;
+        font-size: max(12px, 11Px);
+        border-radius: 3px;
+        line-height: 16Px;
+        padding: 0 4px;
+        line-height: 1;
+        display: flex;
+        align-items: center;
+      }
+      .sing {
+        border: 1px solid rgba(243, 130, 26, 0.5);
+        color: #f3821a;
+      }
+      .song {
+        border: 1px solid rgba(21, 178, 253, 0.5);
+        color: #00adff;
+      }
+      .author {
+        color: #777777;
+        font-size: max(14px, 12Px);
+        display: flex;
+        align-items: center;
+        line-height: 1;
+      }
+    }
+  }
+}

+ 445 - 435
src/views/xiaoku-list/detail.tsx

@@ -1,435 +1,445 @@
-import {
-  computed,
-  defineComponent,
-  nextTick,
-  onMounted,
-  onUnmounted,
-  reactive,
-  ref
-} from 'vue';
-import styles from './detail.module.less';
-import CBreadcrumb from '/src/components/CBreadcrumb';
-import { useRoute } from 'vue-router';
-import { NScrollbar, NSpin, NTabPane, NTabs } from 'naive-ui';
-import SearchGroupResources from './search-group-resources';
-import TheSearch from '/src/components/TheSearch';
-import TheEmpty from '/src/components/TheEmpty';
-import { api_musicSheetPage } from '../xiaoku-ai/api';
-import { formatUsedNum } from '.';
-import { vaildMusicScoreUrl } from '/src/utils/urlUtils';
-import { exitFullscreen, fscreen } from '/src/utils';
-import { state as baseState } from '/src/state';
-import { useUserStore } from '/src/store/modules/users';
-import PreviewWindow from '../preview-window';
-
-export default defineComponent({
-  name: 'xiaoku-detail',
-  setup() {
-    const route = useRoute();
-    const userStore = useUserStore();
-    const routerList = ref([
-      { name: 'AI学练', path: '/xiaoku-list' },
-      { name: '曲目列表', path: '' }
-    ]);
-    const forms = reactive({
-      page: 1,
-      rows: 32,
-      status: true,
-      searchType: ''
-    });
-    const state = reactive({
-      countPage: 1,
-      loading: true,
-      finshed: false,
-      reshing: false,
-      tabName: '' as '' | 'RECOMMEND' | 'HOT' | 'NEW',
-      list: [] as any,
-      allSearch: {
-        name: '',
-        musicTagIds: '',
-        audioPlayTypes: null as any,
-        bookVersionId: null as any,
-        musicalInstrumentId: null as any,
-        subjectId: null
-      },
-      hotSearch: {
-        name: '',
-        musicalInstrumentId: null as any
-      },
-      newSearch: {
-        name: '',
-        musicalInstrumentId: null as any
-      },
-      recommendSearch: {
-        name: '',
-        musicalInstrumentId: null as any
-      },
-      previewModal: false,
-      previewParams: {
-        type: '',
-        src: ''
-      } as any
-    });
-
-    const searchValue = computed(() => {
-      if (state.tabName === 'RECOMMEND') {
-        return state.recommendSearch.name;
-      } else if (state.tabName === 'HOT') {
-        return state.hotSearch.name;
-      } else if (state.tabName === 'NEW') {
-        return state.newSearch.name;
-      } else {
-        return state.allSearch.name;
-      }
-    });
-    const musicalInstrumentId = computed(() => {
-      let id = state.allSearch.musicalInstrumentId;
-      if (state.tabName === 'RECOMMEND') {
-        id = state.recommendSearch.musicalInstrumentId;
-      } else if (state.tabName === 'HOT') {
-        id = state.hotSearch.musicalInstrumentId;
-      } else if (state.tabName === 'NEW') {
-        id = state.newSearch.musicalInstrumentId;
-      }
-      return id;
-    });
-
-    const onSearch = async (item: any) => {
-      forms.page = 1;
-      state.reshing = true;
-      state.finshed = false;
-
-      const { subjectId, ...res } = item;
-      if (state.tabName === 'HOT') {
-        state.hotSearch = Object.assign(state.hotSearch, {
-          musicalInstrumentId: subjectId
-        });
-      } else if (state.tabName == 'NEW') {
-        state.newSearch = Object.assign(state.newSearch, {
-          musicalInstrumentId: subjectId
-        });
-      } else if (state.tabName === 'RECOMMEND') {
-        state.recommendSearch = Object.assign(state.recommendSearch, {
-          musicalInstrumentId: subjectId
-        });
-      } else {
-        state.allSearch = Object.assign(state.allSearch, {
-          ...res,
-          musicalInstrumentId: subjectId,
-          subjectId: null
-        });
-      }
-
-      getList();
-      nextTick(() => {
-        __initSpin();
-      });
-    };
-
-    const spinRef = ref();
-    const handleResh = () => {
-      if (state.loading || state.finshed) return;
-      forms.page = forms.page + 1;
-      getList();
-    };
-
-    const getList = async () => {
-      if(forms.page == 1) {
-        state.loading = true;
-      }
-      let res = {} as any;
-      const { ...result } = forms;
-      let params = {
-        ...result,
-        searchType: state.tabName
-      } as any;
-      if (state.tabName === 'RECOMMEND') {
-        params = Object.assign(params, state.recommendSearch);
-        params.rows = 60
-        params.page = 1
-      } else if (state.tabName === 'HOT') {
-        params = Object.assign(params, state.hotSearch);
-        params.rows = 60
-        params.page = 1
-      } else if (state.tabName === 'NEW') {
-        params = Object.assign(params, state.newSearch);
-        params.rows = 60
-        params.page = 1
-      } else {
-        params.name = state.allSearch.name;
-        const { ...more } = state.allSearch;
-        params = Object.assign(params, { ...more });
-      }
-      try {
-        res = await api_musicSheetPage(params);
-      } catch (error) {
-        console.log(error);
-      }
-      if (state.reshing) {
-        state.list = [];
-        state.reshing = false;
-      }
-
-      if (res?.code === 200 && Array.isArray(res?.data?.rows)) {
-        const tempResult = res?.data?.rows || [];
-        tempResult.forEach((item: any) => {
-          item.audioPlayTypeArray = item.audioPlayTypes
-            ? item.audioPlayTypes.split(',')
-            : [];
-
-          if (item.musicSheetName) {
-            const regex = new RegExp(params.name, 'gi');
-            const highlightedText = item.musicSheetName.replace(
-              regex,
-              `<span>$&</span>`
-            );
-            item.musicNameReg = highlightedText;
-          }
-        });
-        state.list = [...state.list, ...res.data.rows];
-        state.finshed = forms.page >= res.data.pages;
-        state.countPage = res.data.pages
-      } else {
-        state.finshed = true;
-      }
-      state.loading = false;
-    };
-
-    const __initSpin = () => {
-      // const obv = new IntersectionObserver(entries => {
-      //   if (entries[0].intersectionRatio > 0) {
-      //     handleResh();
-      //   }
-      // });
-      // obv.observe(spinRef.value);
-    };
-
-    // 查看详情
-    const onDetail = (item: any) => {
-      // 默认进页面显示对应的曲谱
-      // let lineType = item.scoreType || 'FIRST';
-      const lineType = item.scoreType === 'FIRST'
-        ? 'firstTone'
-        : item.scoreType === 'JIAN'
-        ? 'fixedTone'
-        : item.scoreType === 'STAVE'
-        ? 'staff'
-        : 'firstTone';
-      let src = `${vaildMusicScoreUrl()}/instrument?v=${+new Date()}&platform=pc&id=${
-        item.id
-      }&Authorization=${
-        userStore.getToken
-      }&musicRenderType=${lineType}&showGuide=true&part-index=${0}`;
-
-      let musicalInstrumentId = ''
-      if (state.tabName === 'RECOMMEND') {
-        musicalInstrumentId = state.recommendSearch.musicalInstrumentId;
-      } else if (state.tabName === 'HOT') {
-        musicalInstrumentId = state.hotSearch.musicalInstrumentId;
-      } else if (state.tabName === 'NEW') {
-        musicalInstrumentId = state.newSearch.musicalInstrumentId;
-      } else {
-        musicalInstrumentId = state.allSearch.musicalInstrumentId;
-      }
-      if (musicalInstrumentId) {
-        src += '&instrumentId=' + musicalInstrumentId;
-      }
-      if (window.matchMedia('(display-mode: standalone)').matches) {
-        baseState.application = window.matchMedia(
-          '(display-mode: standalone)'
-        ).matches;
-        state.previewModal = true;
-        fscreen();
-        state.previewParams = {
-          type: 'music',
-          src
-        };
-      } else {
-        window.open(src, +new Date() + '');
-      }
-    };
-
-    const iframeHandle = (ev: MessageEvent) => {
-      if (ev.data?.api === 'back') {
-        exitFullscreen();
-        state.previewModal = !state.previewModal;
-      }
-    };
-
-    onMounted(async () => {
-      if (route.query.type) {
-        state.tabName = route.query.type as any;
-      }
-
-      // getList();
-      __initSpin();
-      window.addEventListener('message', iframeHandle);
-    });
-
-    onUnmounted(() => {
-      window.removeEventListener('message', iframeHandle);
-    });
-    return () => (
-      <div class={styles.xiaokuDetail}>
-        <CBreadcrumb list={routerList.value}></CBreadcrumb>
-        <div class={styles.detailContainer}>
-          <NTabs
-            paneClass={styles.paneTitle}
-            justifyContent="start"
-            // animated
-            paneWrapperClass={styles.paneWrapperContainer}
-            v-model:value={state.tabName}
-            onUpdate:value={(val: any) => {
-              forms.page = 1;
-              state.finshed = false;
-              state.reshing = true;
-              state.list = [];
-              if(musicalInstrumentId.value) {
-                getList();
-                __initSpin();
-              }
-            }}
-            v-slots={{
-              suffix: () => (
-                <TheSearch
-                  placeholder="请输入曲目名称"
-                  round
-                  value={searchValue.value}
-                  onUpdate:value={(val: string) => {
-                    // 重置搜索条件
-                    if (state.tabName === 'RECOMMEND') {
-                     state.recommendSearch.name = val
-                    } else if (state.tabName === 'HOT') {
-                     state.hotSearch.name = val
-                    } else if (state.tabName === 'NEW') {
-                     state.newSearch.name = val
-                    } else {
-                     state.allSearch.name = val
-                    }
-                  }}
-                  class={styles.inputSearch}
-                  onSearch={val => {
-                    if (state.tabName === 'RECOMMEND') {
-                      state.recommendSearch.name = val;
-                    } else if (state.tabName === 'HOT') {
-                      state.hotSearch.name = val;
-                    } else if (state.tabName === 'NEW') {
-                      state.newSearch.name = val;
-                    } else {
-                      state.allSearch.name = val;
-                    }
-                    forms.page = 1;
-                    state.finshed = false;
-                    state.list = [];
-                    getList();
-                  }}
-                />
-              )
-            }}>
-            <NTabPane name={``} tab={'全部曲目'}></NTabPane>
-            <NTabPane name={`RECOMMEND`} tab={'推荐曲目'}></NTabPane>
-            <NTabPane name={`HOT`} tab={'热门曲目'}></NTabPane>
-            <NTabPane name={`NEW`} tab={'最新曲目'}></NTabPane>
-          </NTabs>
-
-          <NScrollbar
-            class={[
-              [
-                styles.wrapList,
-                !state.loading &&
-                  state.list.length === 0 &&
-                  styles.wrapListEmpty
-              ]
-            ]}
-            onScroll={async (e: any) => {
-              if(state.tabName) {
-                return
-              }
-              const clientHeight = e.target?.clientHeight;
-              const scrollTop = e.target?.scrollTop;
-              const scrollHeight = e.target?.scrollHeight;
-              // 是否到底,是否加载完
-              if (
-                clientHeight + scrollTop + 20 >= scrollHeight &&
-                !state.finshed &&
-                !state.loading
-              ) {
-                if(forms.page >= state.countPage) return
-                forms.page = forms.page + 1;
-                await getList();
-              }
-            }}
-            >
-            {/* , state.tabName ? styles.searchSectionHide : '' */}
-            <NSpin show={state.loading}>
-            <div class={[styles.loadingSection, !state.loading && state.list.length === 0 && styles.loadingSectionEmpty]}>
-            <div class={[styles.searchSection]}>
-              <SearchGroupResources
-                type={state.tabName}
-                musicalInstrumentId={musicalInstrumentId.value}
-                onSearch={(val: any) => {
-                  onSearch(val);
-                }}
-              />
-            </div>
-
-            {state.list.length > 0 && (
-              <div
-                class={[
-                  styles.sectionContainer
-                  // state.tabName && styles.noSearchContainer
-                ]}>
-                {state.list.map((item: any) => (
-                  <div
-                    class={styles.sectionItem}
-                    onClick={() => onDetail(item)}>
-                    <div class={styles.img}>
-                      <img referrerpolicy="no-referrer" src={item.titleImg} />
-                    </div>
-                    <div class={styles.infos}>
-                      <div class={styles.topName} v-html={item.musicNameReg}></div>
-                      <div class={styles.types}>
-                        <div class={styles.hot}>
-                          <span>{formatUsedNum(item.usedNum)}</span>
-                        </div>
-                        {item.audioPlayTypes?.includes('SING') && (
-                          <div class={styles.sing}>演唱</div>
-                        )}
-                        {item.audioPlayTypes?.includes('PLAY') && (
-                          <div class={styles.song}>演奏</div>
-                        )}
-
-                        <div class={styles.author}>{item.composer}</div>
-                      </div>
-                    </div>
-                  </div>
-                ))}
-              </div>
-            )}
-
-            {/* <div
-              // ref={spinRef}
-              class={[styles.loadingWrap, (state.finshed || !state.loading) && styles.showLoading]}>
-              <NSpin show={true}></NSpin>
-            </div> */}
-
-            {!state.loading && state.list.length === 0 && (
-              <div class={styles.empty}>
-                <TheEmpty></TheEmpty>
-              </div>
-            )}
-            </div>
-            </NSpin>
-          </NScrollbar>
-        </div>
-
-        {/* 应用内预览或上课 */}
-        <PreviewWindow
-          v-model:show={state.previewModal}
-          type="music"
-          params={state.previewParams}
-        />
-      </div>
-    );
-  }
-});
+import {
+  computed,
+  defineComponent,
+  nextTick,
+  onMounted,
+  onUnmounted,
+  reactive,
+  ref
+} from 'vue';
+import styles from './detail.module.less';
+import CBreadcrumb from '/src/components/CBreadcrumb';
+import { useRoute } from 'vue-router';
+import { NScrollbar, NSpin, NTabPane, NTabs } from 'naive-ui';
+import SearchGroupResources from './search-group-resources';
+import TheSearch from '/src/components/TheSearch';
+import TheEmpty from '/src/components/TheEmpty';
+import { api_musicSheetPage } from '../xiaoku-ai/api';
+import { formatUsedNum } from '.';
+import { vaildMusicScoreUrl } from '/src/utils/urlUtils';
+import { exitFullscreen, fscreen } from '/src/utils';
+import { state as baseState } from '/src/state';
+import { useUserStore } from '/src/store/modules/users';
+import PreviewWindow from '../preview-window';
+
+export default defineComponent({
+  name: 'xiaoku-detail',
+  setup() {
+    const route = useRoute();
+    const userStore = useUserStore();
+    const routerList = ref([
+      { name: 'AI学练', path: '/xiaoku-list' },
+      { name: '曲目列表', path: '' }
+    ]);
+    const forms = reactive({
+      page: 1,
+      rows: 32,
+      status: true,
+      searchType: ''
+    });
+    const state = reactive({
+      countPage: 1,
+      loading: true,
+      finshed: false,
+      reshing: false,
+      tabName: '' as '' | 'RECOMMEND' | 'HOT' | 'NEW',
+      list: [] as any,
+      allSearch: {
+        name: '',
+        musicTagIds: '',
+        audioPlayTypes: null as any,
+        bookVersionId: null as any,
+        musicalInstrumentId: null as any,
+        subjectId: null
+      },
+      hotSearch: {
+        name: '',
+        musicalInstrumentId: null as any
+      },
+      newSearch: {
+        name: '',
+        musicalInstrumentId: null as any
+      },
+      recommendSearch: {
+        name: '',
+        musicalInstrumentId: null as any
+      },
+      previewModal: false,
+      previewParams: {
+        type: '',
+        src: ''
+      } as any
+    });
+
+    const searchValue = computed(() => {
+      if (state.tabName === 'RECOMMEND') {
+        return state.recommendSearch.name;
+      } else if (state.tabName === 'HOT') {
+        return state.hotSearch.name;
+      } else if (state.tabName === 'NEW') {
+        return state.newSearch.name;
+      } else {
+        return state.allSearch.name;
+      }
+    });
+    const musicalInstrumentId = computed(() => {
+      let id = state.allSearch.musicalInstrumentId;
+      if (state.tabName === 'RECOMMEND') {
+        id = state.recommendSearch.musicalInstrumentId;
+      } else if (state.tabName === 'HOT') {
+        id = state.hotSearch.musicalInstrumentId;
+      } else if (state.tabName === 'NEW') {
+        id = state.newSearch.musicalInstrumentId;
+      }
+      return id;
+    });
+
+    const onSearch = async (item: any) => {
+      forms.page = 1;
+      state.reshing = true;
+      state.finshed = false;
+
+      const { subjectId, ...res } = item;
+      if (state.tabName === 'HOT') {
+        state.hotSearch = Object.assign(state.hotSearch, {
+          musicalInstrumentId: subjectId
+        });
+      } else if (state.tabName == 'NEW') {
+        state.newSearch = Object.assign(state.newSearch, {
+          musicalInstrumentId: subjectId
+        });
+      } else if (state.tabName === 'RECOMMEND') {
+        state.recommendSearch = Object.assign(state.recommendSearch, {
+          musicalInstrumentId: subjectId
+        });
+      } else {
+        state.allSearch = Object.assign(state.allSearch, {
+          ...res,
+          musicalInstrumentId: subjectId,
+          subjectId: null
+        });
+      }
+
+      getList();
+      nextTick(() => {
+        __initSpin();
+      });
+    };
+
+    const spinRef = ref();
+    const handleResh = () => {
+      if (state.loading || state.finshed) return;
+      forms.page = forms.page + 1;
+      getList();
+    };
+
+    const getList = async () => {
+      if (forms.page == 1) {
+        state.loading = true;
+      }
+      let res = {} as any;
+      const { ...result } = forms;
+      let params = {
+        ...result,
+        searchType: state.tabName
+      } as any;
+      if (state.tabName === 'RECOMMEND') {
+        params = Object.assign(params, state.recommendSearch);
+        params.rows = 60;
+        params.page = 1;
+      } else if (state.tabName === 'HOT') {
+        params = Object.assign(params, state.hotSearch);
+        params.rows = 60;
+        params.page = 1;
+      } else if (state.tabName === 'NEW') {
+        params = Object.assign(params, state.newSearch);
+        params.rows = 60;
+        params.page = 1;
+      } else {
+        params.name = state.allSearch.name;
+        const { ...more } = state.allSearch;
+        params = Object.assign(params, { ...more });
+      }
+      try {
+        res = await api_musicSheetPage(params);
+      } catch (error) {
+        console.log(error);
+      }
+      if (state.reshing) {
+        state.list = [];
+        state.reshing = false;
+      }
+
+      if (res?.code === 200 && Array.isArray(res?.data?.rows)) {
+        const tempResult = res?.data?.rows || [];
+        tempResult.forEach((item: any) => {
+          item.audioPlayTypeArray = item.audioPlayTypes
+            ? item.audioPlayTypes.split(',')
+            : [];
+
+          if (item.musicSheetName) {
+            const regex = new RegExp(params.name, 'gi');
+            const highlightedText = item.musicSheetName.replace(
+              regex,
+              `<span>$&</span>`
+            );
+            item.musicNameReg = highlightedText;
+          }
+        });
+        state.list = [...state.list, ...res.data.rows];
+        state.finshed = forms.page >= res.data.pages;
+        state.countPage = res.data.pages;
+      } else {
+        state.finshed = true;
+      }
+      state.loading = false;
+    };
+
+    const __initSpin = () => {
+      // const obv = new IntersectionObserver(entries => {
+      //   if (entries[0].intersectionRatio > 0) {
+      //     handleResh();
+      //   }
+      // });
+      // obv.observe(spinRef.value);
+    };
+
+    // 查看详情
+    const onDetail = (item: any) => {
+      // 默认进页面显示对应的曲谱
+      // let lineType = item.scoreType || 'FIRST';
+      const lineType =
+        item.scoreType === 'FIRST'
+          ? 'firstTone'
+          : item.scoreType === 'JIAN'
+          ? 'fixedTone'
+          : item.scoreType === 'STAVE'
+          ? 'staff'
+          : 'firstTone';
+      let src = `${vaildMusicScoreUrl()}/instrument?v=${+new Date()}&platform=pc&id=${
+        item.id
+      }&Authorization=${
+        userStore.getToken
+      }&musicRenderType=${lineType}&showGuide=true&part-index=${0}`;
+
+      let musicalInstrumentId = '';
+      if (state.tabName === 'RECOMMEND') {
+        musicalInstrumentId = state.recommendSearch.musicalInstrumentId;
+      } else if (state.tabName === 'HOT') {
+        musicalInstrumentId = state.hotSearch.musicalInstrumentId;
+      } else if (state.tabName === 'NEW') {
+        musicalInstrumentId = state.newSearch.musicalInstrumentId;
+      } else {
+        musicalInstrumentId = state.allSearch.musicalInstrumentId;
+      }
+      if (musicalInstrumentId) {
+        src += '&instrumentId=' + musicalInstrumentId;
+      }
+      if (window.matchMedia('(display-mode: standalone)').matches) {
+        baseState.application = window.matchMedia(
+          '(display-mode: standalone)'
+        ).matches;
+        state.previewModal = true;
+        fscreen();
+        state.previewParams = {
+          type: 'music',
+          src
+        };
+      } else {
+        window.open(src, +new Date() + '');
+      }
+    };
+
+    const iframeHandle = (ev: MessageEvent) => {
+      if (ev.data?.api === 'back') {
+        exitFullscreen();
+        state.previewModal = !state.previewModal;
+      }
+    };
+
+    onMounted(async () => {
+      if (route.query.type) {
+        state.tabName = route.query.type as any;
+      }
+
+      // getList();
+      __initSpin();
+      window.addEventListener('message', iframeHandle);
+    });
+
+    onUnmounted(() => {
+      window.removeEventListener('message', iframeHandle);
+    });
+    return () => (
+      <div class={styles.xiaokuDetail}>
+        <CBreadcrumb list={routerList.value}></CBreadcrumb>
+        <div class={styles.detailContainer}>
+          <NTabs
+            paneClass={styles.paneTitle}
+            justifyContent="start"
+            // animated
+            paneWrapperClass={styles.paneWrapperContainer}
+            v-model:value={state.tabName}
+            onUpdate:value={(val: any) => {
+              forms.page = 1;
+              state.finshed = false;
+              state.reshing = true;
+              state.list = [];
+              if (musicalInstrumentId.value) {
+                getList();
+                __initSpin();
+              }
+            }}
+            v-slots={{
+              suffix: () => (
+                <TheSearch
+                  placeholder="请输入曲目名称"
+                  round
+                  value={searchValue.value}
+                  onUpdate:value={(val: string) => {
+                    // 重置搜索条件
+                    if (state.tabName === 'RECOMMEND') {
+                      state.recommendSearch.name = val;
+                    } else if (state.tabName === 'HOT') {
+                      state.hotSearch.name = val;
+                    } else if (state.tabName === 'NEW') {
+                      state.newSearch.name = val;
+                    } else {
+                      state.allSearch.name = val;
+                    }
+                  }}
+                  class={styles.inputSearch}
+                  onSearch={val => {
+                    if (state.tabName === 'RECOMMEND') {
+                      state.recommendSearch.name = val;
+                    } else if (state.tabName === 'HOT') {
+                      state.hotSearch.name = val;
+                    } else if (state.tabName === 'NEW') {
+                      state.newSearch.name = val;
+                    } else {
+                      state.allSearch.name = val;
+                    }
+                    forms.page = 1;
+                    state.finshed = false;
+                    state.list = [];
+                    getList();
+                  }}
+                />
+              )
+            }}>
+            <NTabPane name={``} tab={'全部曲目'}></NTabPane>
+            <NTabPane name={`RECOMMEND`} tab={'推荐曲目'}></NTabPane>
+            <NTabPane name={`HOT`} tab={'热门曲目'}></NTabPane>
+            <NTabPane name={`NEW`} tab={'最新曲目'}></NTabPane>
+          </NTabs>
+
+          <NScrollbar
+            class={[
+              [
+                styles.wrapList,
+                !state.loading &&
+                  state.list.length === 0 &&
+                  styles.wrapListEmpty
+              ]
+            ]}
+            onScroll={async (e: any) => {
+              if (state.tabName) {
+                return;
+              }
+              const clientHeight = e.target?.clientHeight;
+              const scrollTop = e.target?.scrollTop;
+              const scrollHeight = e.target?.scrollHeight;
+              // 是否到底,是否加载完
+              if (
+                clientHeight + scrollTop + 20 >= scrollHeight &&
+                !state.finshed &&
+                !state.loading
+              ) {
+                if (forms.page >= state.countPage) return;
+                forms.page = forms.page + 1;
+                await getList();
+              }
+            }}>
+            {/* , state.tabName ? styles.searchSectionHide : '' */}
+            <NSpin show={state.loading}>
+              <div
+                class={[
+                  styles.loadingSection,
+                  !state.loading &&
+                    state.list.length === 0 &&
+                    styles.loadingSectionEmpty
+                ]}>
+                <div class={[styles.searchSection]}>
+                  <SearchGroupResources
+                    type={state.tabName}
+                    musicalInstrumentId={musicalInstrumentId.value}
+                    onSearch={(val: any) => {
+                      onSearch(val);
+                    }}
+                  />
+                </div>
+                {state.list.length > 0 && (
+                  <div
+                    class={[
+                      styles.sectionContainer
+                      // state.tabName && styles.noSearchContainer
+                    ]}>
+                    {state.list.map((item: any) => (
+                      <div
+                        class={styles.sectionItem}
+                        onClick={() => onDetail(item)}>
+                        <div class={styles.img}>
+                          <img
+                            referrerpolicy="no-referrer"
+                            src={item.titleImg}
+                          />
+                        </div>
+                        <div class={styles.infos}>
+                          <div
+                            class={styles.topName}
+                            v-html={item.musicNameReg}></div>
+                          <div class={styles.types}>
+                            <div class={styles.hot}>
+                              <span>{formatUsedNum(item.usedNum)}</span>
+                            </div>
+                            {item.audioPlayTypes?.includes('SING') && (
+                              <div class={styles.sing}>演唱</div>
+                            )}
+                            {item.audioPlayTypes?.includes('PLAY') && (
+                              <div class={styles.song}>演奏</div>
+                            )}
+
+                            <div class={styles.author}>{item.composer}</div>
+                          </div>
+                        </div>
+                      </div>
+                    ))}
+                  </div>
+                )}
+
+                {/* <div
+              // ref={spinRef}
+              class={[styles.loadingWrap, (state.finshed || !state.loading) && styles.showLoading]}>
+              <NSpin show={true}></NSpin>
+            </div> */}
+
+                {!state.loading && state.list.length === 0 && (
+                  <div class={styles.empty}>
+                    <TheEmpty></TheEmpty>
+                  </div>
+                )}
+              </div>
+            </NSpin>
+          </NScrollbar>
+        </div>
+
+        {/* 应用内预览或上课 */}
+        <PreviewWindow
+          v-model:show={state.previewModal}
+          type="music"
+          params={state.previewParams}
+        />
+      </div>
+    );
+  }
+});

+ 18 - 18
src/views/xiaoku-list/images/icon-arrow-up.svg

@@ -1,19 +1,19 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="12px" height="13px" viewBox="0 0 12 13" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-    <title>小箭头/展开</title>
-    <g id="AI学练" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g id="5、全部曲目备份" transform="translate(-1357, -408)" fill="#1677FF" fill-rule="nonzero">
-            <g id="编组-17-+-编组-18-+-编组-13蒙版" transform="translate(132, 140)">
-                <g id="编组-13" transform="translate(32, 93)">
-                    <g id="编组-10备份" transform="translate(1051, 164)">
-                        <g id="编组-7" transform="translate(68, 5.2213)">
-                            <g id="小箭头/展开" transform="translate(74.8206, 8.9994)">
-                                <path d="M3.56433292,-1.95456088 L3.58024499,-1.93904332 L7.93910126,2.41974719 C8.25425238,2.73496407 8.25944681,3.24283539 7.95455306,3.56429874 L7.93910126,3.58027657 L3.58024499,7.93900133 C3.25983368,8.25954414 2.74025843,8.25954414 2.41971562,7.93900133 C2.1045645,7.62385021 2.09937006,7.11597888 2.40426381,6.79451553 L2.41978137,6.77853771 L6.19837295,3.00001188 L2.41978137,-0.7785797 C2.1045645,-1.09379657 2.09937006,-1.60160214 2.40426381,-1.92313124 L2.41978137,-1.93904332 C2.73499824,-2.25426019 3.24280382,-2.25945463 3.56433292,-1.95456088 Z" id="路径备份" transform="translate(5.1794, 3) rotate(-270) translate(-5.1794, -3)"></path>
-                            </g>
-                        </g>
-                    </g>
-                </g>
-            </g>
-        </g>
-    </g>
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="12px" height="13px" viewBox="0 0 12 13" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>小箭头/展开</title>
+    <g id="AI学练" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="5、全部曲目备份" transform="translate(-1357, -408)" fill="#198CFE" fill-rule="nonzero">
+            <g id="编组-17-+-编组-18-+-编组-13蒙版" transform="translate(132, 140)">
+                <g id="编组-13" transform="translate(32, 93)">
+                    <g id="编组-10备份" transform="translate(1051, 164)">
+                        <g id="编组-7" transform="translate(68, 5.2213)">
+                            <g id="小箭头/展开" transform="translate(74.8206, 8.9994)">
+                                <path d="M3.56433292,-1.95456088 L3.58024499,-1.93904332 L7.93910126,2.41974719 C8.25425238,2.73496407 8.25944681,3.24283539 7.95455306,3.56429874 L7.93910126,3.58027657 L3.58024499,7.93900133 C3.25983368,8.25954414 2.74025843,8.25954414 2.41971562,7.93900133 C2.1045645,7.62385021 2.09937006,7.11597888 2.40426381,6.79451553 L2.41978137,6.77853771 L6.19837295,3.00001188 L2.41978137,-0.7785797 C2.1045645,-1.09379657 2.09937006,-1.60160214 2.40426381,-1.92313124 L2.41978137,-1.93904332 C2.73499824,-2.25426019 3.24280382,-2.25945463 3.56433292,-1.95456088 Z" id="路径备份" transform="translate(5.1794, 3) rotate(-270) translate(-5.1794, -3)"></path>
+                            </g>
+                        </g>
+                    </g>
+                </g>
+            </g>
+        </g>
+    </g>
 </svg>

+ 499 - 493
src/views/xiaoku-list/search-group-resources.tsx

@@ -1,493 +1,499 @@
-import {
-  defineComponent,
-  nextTick,
-  onMounted,
-  reactive,
-  ref,
-  watch,
-  toRefs,
-  PropType,
-  computed
-} from 'vue';
-import styles from './detail.module.less';
-import {
-  NButton,
-  NForm,
-  NFormItem,
-  NImage,
-  NPopselect,
-  NSpace
-} from 'naive-ui';
-// import iconAdd from '../../images/icon-add.png';
-// import TheSearch from '/src/components/TheSearch';
-// import { resourceTypeArray } from '/src/utils/searchArray';
-import { useCatchStore } from '/src/store/modules/catchData';
-import { audioPlayType } from '/src/utils/contants';
-import { api_musicSheetTagQueryList } from './api';
-// import isCollaose from '../../images/isCollaose.png';
-
-const ChildNodeSearch = defineComponent({
-  name: 'ChildNodeSearch',
-  props: {
-    activeRow: {
-      type: Object,
-      default: () => ({})
-    },
-    list: {
-      type: Array,
-      default: () => []
-    },
-    isHide: {
-      type: Boolean,
-      default: false,
-    }
-  },
-  emits: ['selectChildTag'],
-  setup(props, { emit }) {
-    const { activeRow } = toRefs(props);
-    const selectItem = ref({});
-
-    watch(
-      () => props.activeRow,
-      () => {
-        activeRow.value = props.activeRow;
-        selectItem.value = {};
-      }
-    );
-    return () => (
-      <>
-        {activeRow.value?.id && (
-          <>
-            <NFormItem label={activeRow.value.columnName + ':'} class={props.isHide && styles.hideItem}>
-              <NSpace class={styles.spaceSection}>
-                {activeRow.value?.children.map((subject: any) => (
-                  <span
-                    class={[
-                      styles.textBtn,
-                      (activeRow.value.activeIndex || '') == subject.id &&
-                        styles.textBtnActive
-                    ]}
-                    onClick={() => {
-                      activeRow.value.activeIndex = subject.id;
-                      let children: any;
-                      let columnName = '';
-                      if (subject.children) {
-                        children = [
-                          {
-                            columnName: subject.children[0].columnName,
-                            name: '全部',
-                            id: ''
-                          },
-                          ...subject.children
-                        ];
-                        columnName = subject.children[0].columnName;
-
-                        selectItem.value = {
-                          ...subject,
-                          columnName,
-                          activeIndex: '',
-                          children
-                        };
-                      } else {
-                        selectItem.value = {};
-                      }
-                      emit('selectChildTag', activeRow.value.activeIndex);
-                    }}>
-                    {subject.name}
-                  </span>
-                ))}
-              </NSpace>
-            </NFormItem>
-
-            <ChildNodeSearch
-              isHide={props.isHide}
-              activeRow={selectItem.value}
-              onSelectChildTag={(item: any) => {
-                emit('selectChildTag', item || activeRow.value.activeIndex);
-              }}
-            />
-          </>
-        )}
-      </>
-    );
-  }
-});
-
-export default defineComponent({
-  name: 'search-group',
-  props: {
-    type: {
-      type: String as PropType<'' | 'RECOMMEND' | 'HOT' | 'NEW'>,
-      default: ''
-    },
-    musicalInstrumentId: {
-      type: String,
-      default: ''
-    }
-  },
-  emits: ['search', 'add'],
-  expose: ['init'],
-  setup(props, { emit }) {
-    const catchStore = useCatchStore();
-    const forms = reactive({
-      musicTagIds: '',
-      audioPlayTypes: '',
-      bookVersionId: null as any,
-      subjectId: null as any
-    });
-    const state = reactive({
-      showMore: false,
-      tempSubjectId: null as any
-    });
-    const data = reactive({
-      audioPlayTypeList: [] as any, // 场景
-      selectParents: {}, // 选中的数据
-      newTags: [] as any, // 最新标签
-      tags: [] as any[],
-      tagActiveId: '' as any,
-      tagActive: {} as any,
-      childSelectId: null as any
-    });
-
-    watch(
-      () => props.musicalInstrumentId,
-      () => {
-        if (props.musicalInstrumentId) {
-          backInstruments();
-        } else {
-          formatFirstSubject();
-        }
-      }
-    );
-
-    watch(() => props.type, () => {
-      if(!props.musicalInstrumentId) {
-        formatFirstSubject();
-        onSearch()
-      }
-    })
-
-    // 是否显示声部
-    const isShowInstrument = computed(() => {
-      if (props.type) {
-        return true;
-      } else {
-        return false;
-      }
-    });
-
-    const onSearch = () => {
-      emit('search', {
-        ...forms,
-        subjectId: forms.audioPlayTypes !== 'SING' ? forms.subjectId : null,
-        audioPlayTypes: forms.audioPlayTypes
-          ? forms.audioPlayTypes === 'PLAY_SING'
-            ? ['PLAY', 'SING']
-            : [forms.audioPlayTypes]
-          : [],
-        bookVersionId: data.childSelectId || data.tagActiveId
-      });
-    };
-
-    const onShowMore = () => {
-      state.showMore = !state.showMore;
-    };
-
-    const selectChildObj = (item: any) => {
-      const obj: any = {};
-      item?.forEach((child: any) => {
-        if (child.id === forms.subjectId) {
-          obj.selected = true;
-          obj.name = child.name;
-        }
-      });
-      return obj;
-    };
-
-    const _initTags = () => {
-      const tags = catchStore.getMusicTagTree;
-      // 去掉上下册
-      tags.forEach((item: any) => {
-        if (item.children && item.children.length > 0) {
-          const child = item.children;
-          child?.forEach((c: any) => {
-            c.children = null;
-          });
-        }
-      });
-      data.tags = [
-        {
-          columnName: tags[0].columnName,
-          name: '全部',
-          id: ''
-        },
-        ...tags
-      ];
-      data.tagActiveId = data.tags[0].id;
-    };
-
-    const changeTag = (item: any) => {
-      data.tagActiveId = item.id;
-      data.childSelectId = null;
-      let children: any;
-      let columnName = '';
-      if (item.children) {
-        children = [
-          {
-            columnName: item.children[0].columnName,
-            name: '全部',
-            id: ''
-          },
-          ...item.children
-        ];
-        columnName = item.children[0].columnName;
-        data.selectParents = {
-          ...item,
-          columnName,
-          activeIndex: '',
-          children
-        };
-      } else {
-        data.selectParents = {};
-      }
-
-      onSearch();
-    };
-
-    /** 默认选中第一个声部 */
-    const formatFirstSubject = () => {
-      const tempSubjects = catchStore.getSubjectInstrumentOnly;
-      if (tempSubjects.length > 0) {
-        const firstSubject = tempSubjects[0];
-        if (firstSubject.instruments && firstSubject.instruments.length > 1) {
-          state.tempSubjectId = firstSubject.instruments[0]?.value;
-          forms.subjectId = firstSubject.instruments[0]?.value;
-        } else {
-          forms.subjectId = firstSubject.value;
-        }
-      }
-    };
-
-    const backInstruments = () => {
-      let childInstruments: any[] = [];
-      catchStore.getSubjectInstrumentOnly.forEach((item: any) => {
-        if(props.musicalInstrumentId === item.value) {
-          childInstruments = item.instruments || [];
-              
-          forms.subjectId = props.musicalInstrumentId;
-          state.tempSubjectId = props.musicalInstrumentId;
-        } else {
-          if (Array.isArray(item.instruments)) {
-            item.instruments.forEach((child: any) => {
-              if (props.musicalInstrumentId === child.value) {
-                childInstruments = item.instruments || [];
-                
-                forms.subjectId = props.musicalInstrumentId;
-                state.tempSubjectId = props.musicalInstrumentId;
-              }
-            });
-          }
-        }
-        
-      });
-      if (childInstruments.length > 0) {
-        selectChildObj(childInstruments);
-      }
-    };
-
-    const getTags = async () => {
-      try {
-        const res = await api_musicSheetTagQueryList();
-        const result = res.data || [];
-        data.newTags = [
-          {
-            name: '全部',
-            id: ''
-          },
-          ...result.map((item: any) => {
-            return {
-              name: item.name,
-              id: item.id
-            };
-          })
-        ];
-      } catch {
-        //
-      }
-    };
-
-    onMounted(async () => {
-      // 场景
-      const tempAudio = Object.keys(audioPlayType).map(key => {
-        return {
-          value: key,
-          name: audioPlayType[key]
-        };
-      });
-      data.audioPlayTypeList = [{ name: '全部', value: '' }, ...tempAudio];
-
-      await getTags();
-      // 获取教材分类列表
-      await catchStore.getMusicTagTreeApi();
-      _initTags();
-      // console.log(data, 'data');
-      // 获取声部列表
-      await catchStore.getSubjects();
-
-      if (props.musicalInstrumentId) {
-        backInstruments();
-      } else {
-        formatFirstSubject();
-      }
-      onSearch();
-    });
-    return () => (
-      <div
-        class={[
-          styles.searchGroup,
-          isShowInstrument.value && styles.searchGroupOnly
-        ]}>
-        <NForm labelAlign="left" labelPlacement="left">
-          {data.newTags.length > 1 && (
-            <NFormItem
-              label={'标签:'}
-              class={isShowInstrument.value && styles.hideItem}>
-              <NSpace class={styles.spaceSection}>
-                {data.newTags.map((subject: any) => (
-                  <span
-                    class={[
-                      styles.textBtn,
-                      forms.musicTagIds === subject.id && styles.textBtnActive
-                    ]}
-                    onClick={() => {
-                      forms.musicTagIds = subject.id;
-                      onSearch();
-                    }}>
-                    {subject.name}
-                  </span>
-                ))}
-              </NSpace>
-            </NFormItem>
-          )}
-
-          {data.tags.length > 0 && (
-            <NFormItem
-              label={data.tags[0]?.columnName + ':'}
-              class={isShowInstrument.value && styles.hideItem}>
-              <NSpace class={styles.spaceSection}>
-                {data.tags.map((subject: any) => (
-                  <span
-                    class={[
-                      styles.textBtn,
-                      data.tagActiveId === subject.id && styles.textBtnActive
-                    ]}
-                    onClick={() => {
-                      changeTag(subject);
-                    }}>
-                    {subject.name}
-                  </span>
-                ))}
-              </NSpace>
-            </NFormItem>
-          )}
-
-          <ChildNodeSearch
-            isHide={isShowInstrument.value}
-            activeRow={data.selectParents}
-            onSelectChildTag={(val: any) => {
-              data.childSelectId = val;
-              onSearch();
-            }}
-          />
-
-          <NFormItem
-            label="场景:"
-            class={[
-              !state.showMore && styles.hideItem,
-              isShowInstrument.value && styles.hideItem
-            ]}>
-            <NSpace class={styles.spaceSection}>
-              {data.audioPlayTypeList.map((subject: any) => (
-                <span
-                  class={[
-                    styles.textBtn,
-
-                    forms.audioPlayTypes === subject.value &&
-                      styles.textBtnActive
-                  ]}
-                  onClick={() => {
-                    forms.audioPlayTypes = subject.value;
-                    onSearch();
-                  }}>
-                  {subject.name}
-                </span>
-              ))}
-            </NSpace>
-          </NFormItem>
-
-          {(forms.audioPlayTypes !== 'SING' || isShowInstrument.value) && (
-            <NFormItem
-              label="乐器:"
-              class={
-                !state.showMore && !isShowInstrument.value && styles.hideItem
-              }>
-              <NSpace class={styles.spaceSection}>
-                {catchStore.getSubjectInstrumentOnly.map((subject: any) =>
-                  subject.instruments && subject.instruments.length > 1 ? (
-                    <NPopselect
-                      options={subject.instruments}
-                      trigger="hover"
-                      scrollable
-                      v-model:value={state.tempSubjectId}
-                      onUpdate:value={() => {
-                        forms.subjectId = state.tempSubjectId;
-                        onSearch();
-                      }}
-                      key={subject.value}
-                      class={[styles.popSelect]}>
-                      <span
-                        class={[
-                          styles.textBtn,
-                          selectChildObj(subject.instruments).selected &&
-                            styles.textBtnActive
-                        ]}>
-                        {selectChildObj(subject.instruments).name ||
-                          subject.name}
-                        <i class={styles.iconArrow}></i>
-                      </span>
-                    </NPopselect>
-                  ) : (
-                    <span
-                      class={[
-                        styles.textBtn,
-                        forms.subjectId === subject.value &&
-                          styles.textBtnActive
-                      ]}
-                      onClick={() => {
-                        forms.subjectId = subject.value;
-
-                        state.tempSubjectId = null;
-                        onSearch();
-                      }}>
-                      {subject.name}
-                    </span>
-                  )
-                )}
-              </NSpace>
-            </NFormItem>
-          )}
-        </NForm>
-        {!isShowInstrument.value && (
-          <div
-            class={[
-              styles.moreSearch,
-              state.showMore ? styles.activeSearch : ''
-            ]}
-            onClick={onShowMore}>
-            {state.showMore ? '收起选项' : '展开更多'}
-          </div>
-        )}
-      </div>
-    );
-  }
-});
+import {
+  defineComponent,
+  nextTick,
+  onMounted,
+  reactive,
+  ref,
+  watch,
+  toRefs,
+  PropType,
+  computed
+} from 'vue';
+import styles from './detail.module.less';
+import {
+  NButton,
+  NForm,
+  NFormItem,
+  NImage,
+  NPopselect,
+  NSpace
+} from 'naive-ui';
+// import iconAdd from '../../images/icon-add.png';
+// import TheSearch from '/src/components/TheSearch';
+// import { resourceTypeArray } from '/src/utils/searchArray';
+import { useCatchStore } from '/src/store/modules/catchData';
+import { audioPlayType } from '/src/utils/contants';
+import { api_musicSheetTagQueryList } from './api';
+// import isCollaose from '../../images/isCollaose.png';
+
+const ChildNodeSearch = defineComponent({
+  name: 'ChildNodeSearch',
+  props: {
+    activeRow: {
+      type: Object,
+      default: () => ({})
+    },
+    list: {
+      type: Array,
+      default: () => []
+    },
+    isHide: {
+      type: Boolean,
+      default: false
+    }
+  },
+  emits: ['selectChildTag'],
+  setup(props, { emit }) {
+    const { activeRow } = toRefs(props);
+    const selectItem = ref({});
+
+    watch(
+      () => props.activeRow,
+      () => {
+        activeRow.value = props.activeRow;
+        selectItem.value = {};
+      }
+    );
+    return () => (
+      <>
+        {activeRow.value?.id && (
+          <>
+            <NFormItem
+              label={activeRow.value.columnName + ':'}
+              class={props.isHide && styles.hideItem}>
+              <NSpace class={styles.spaceSection}>
+                {activeRow.value?.children.map((subject: any) => (
+                  <span
+                    class={[
+                      styles.textBtn,
+                      (activeRow.value.activeIndex || '') == subject.id &&
+                        styles.textBtnActive
+                    ]}
+                    onClick={() => {
+                      activeRow.value.activeIndex = subject.id;
+                      let children: any;
+                      let columnName = '';
+                      if (subject.children) {
+                        children = [
+                          {
+                            columnName: subject.children[0].columnName,
+                            name: '全部',
+                            id: ''
+                          },
+                          ...subject.children
+                        ];
+                        columnName = subject.children[0].columnName;
+
+                        selectItem.value = {
+                          ...subject,
+                          columnName,
+                          activeIndex: '',
+                          children
+                        };
+                      } else {
+                        selectItem.value = {};
+                      }
+                      emit('selectChildTag', activeRow.value.activeIndex);
+                    }}>
+                    {subject.name}
+                  </span>
+                ))}
+              </NSpace>
+            </NFormItem>
+
+            <ChildNodeSearch
+              isHide={props.isHide}
+              activeRow={selectItem.value}
+              onSelectChildTag={(item: any) => {
+                emit('selectChildTag', item || activeRow.value.activeIndex);
+              }}
+            />
+          </>
+        )}
+      </>
+    );
+  }
+});
+
+export default defineComponent({
+  name: 'search-group',
+  props: {
+    type: {
+      type: String as PropType<'' | 'RECOMMEND' | 'HOT' | 'NEW'>,
+      default: ''
+    },
+    musicalInstrumentId: {
+      type: String,
+      default: ''
+    }
+  },
+  emits: ['search', 'add'],
+  expose: ['init'],
+  setup(props, { emit }) {
+    const catchStore = useCatchStore();
+    const forms = reactive({
+      musicTagIds: '',
+      audioPlayTypes: '',
+      bookVersionId: null as any,
+      subjectId: null as any
+    });
+    const state = reactive({
+      showMore: false,
+      tempSubjectId: null as any
+    });
+    const data = reactive({
+      audioPlayTypeList: [] as any, // 场景
+      selectParents: {}, // 选中的数据
+      newTags: [] as any, // 最新标签
+      tags: [] as any[],
+      tagActiveId: '' as any,
+      tagActive: {} as any,
+      childSelectId: null as any
+    });
+
+    watch(
+      () => props.musicalInstrumentId,
+      () => {
+        if (props.musicalInstrumentId) {
+          backInstruments();
+        } else {
+          formatFirstSubject();
+        }
+      }
+    );
+
+    watch(
+      () => props.type,
+      () => {
+        if (!props.musicalInstrumentId) {
+          formatFirstSubject();
+          onSearch();
+        }
+      }
+    );
+
+    // 是否显示声部
+    const isShowInstrument = computed(() => {
+      if (props.type) {
+        return true;
+      } else {
+        return false;
+      }
+    });
+
+    const onSearch = () => {
+      emit('search', {
+        ...forms,
+        subjectId: forms.audioPlayTypes !== 'SING' ? forms.subjectId : null,
+        audioPlayTypes: forms.audioPlayTypes
+          ? forms.audioPlayTypes === 'PLAY_SING'
+            ? ['PLAY', 'SING']
+            : [forms.audioPlayTypes]
+          : [],
+        bookVersionId: data.childSelectId || data.tagActiveId
+      });
+    };
+
+    const onShowMore = () => {
+      state.showMore = !state.showMore;
+    };
+
+    const selectChildObj = (item: any) => {
+      const obj: any = {};
+      item?.forEach((child: any) => {
+        if (child.id === forms.subjectId) {
+          obj.selected = true;
+          obj.name = child.name;
+        }
+      });
+      return obj;
+    };
+
+    const _initTags = () => {
+      const tags = catchStore.getMusicTagTree;
+      // 去掉上下册
+      tags.forEach((item: any) => {
+        if (item.children && item.children.length > 0) {
+          const child = item.children;
+          child?.forEach((c: any) => {
+            c.children = null;
+          });
+        }
+      });
+      data.tags = [
+        {
+          columnName: tags[0].columnName,
+          name: '全部',
+          id: ''
+        },
+        ...tags
+      ];
+      data.tagActiveId = data.tags[0].id;
+    };
+
+    const changeTag = (item: any) => {
+      data.tagActiveId = item.id;
+      data.childSelectId = null;
+      let children: any;
+      let columnName = '';
+      if (item.children) {
+        children = [
+          {
+            columnName: item.children[0].columnName,
+            name: '全部',
+            id: ''
+          },
+          ...item.children
+        ];
+        columnName = item.children[0].columnName;
+        data.selectParents = {
+          ...item,
+          columnName,
+          activeIndex: '',
+          children
+        };
+      } else {
+        data.selectParents = {};
+      }
+
+      onSearch();
+    };
+
+    /** 默认选中第一个声部 */
+    const formatFirstSubject = () => {
+      const tempSubjects = catchStore.getSubjectInstrumentOnly;
+      if (tempSubjects.length > 0) {
+        const firstSubject = tempSubjects[0];
+        if (firstSubject.instruments && firstSubject.instruments.length > 1) {
+          state.tempSubjectId = firstSubject.instruments[0]?.value;
+          forms.subjectId = firstSubject.instruments[0]?.value;
+        } else {
+          forms.subjectId = firstSubject.value;
+        }
+      }
+    };
+
+    const backInstruments = () => {
+      let childInstruments: any[] = [];
+      catchStore.getSubjectInstrumentOnly.forEach((item: any) => {
+        if (props.musicalInstrumentId === item.value) {
+          childInstruments = item.instruments || [];
+
+          forms.subjectId = props.musicalInstrumentId;
+          state.tempSubjectId = props.musicalInstrumentId;
+        } else {
+          if (Array.isArray(item.instruments)) {
+            item.instruments.forEach((child: any) => {
+              if (props.musicalInstrumentId === child.value) {
+                childInstruments = item.instruments || [];
+
+                forms.subjectId = props.musicalInstrumentId;
+                state.tempSubjectId = props.musicalInstrumentId;
+              }
+            });
+          }
+        }
+      });
+      if (childInstruments.length > 0) {
+        selectChildObj(childInstruments);
+      }
+    };
+
+    const getTags = async () => {
+      try {
+        const res = await api_musicSheetTagQueryList();
+        const result = res.data || [];
+        data.newTags = [
+          {
+            name: '全部',
+            id: ''
+          },
+          ...result.map((item: any) => {
+            return {
+              name: item.name,
+              id: item.id
+            };
+          })
+        ];
+      } catch {
+        //
+      }
+    };
+
+    onMounted(async () => {
+      // 场景
+      const tempAudio = Object.keys(audioPlayType).map(key => {
+        return {
+          value: key,
+          name: audioPlayType[key]
+        };
+      });
+      data.audioPlayTypeList = [{ name: '全部', value: '' }, ...tempAudio];
+
+      await getTags();
+      // 获取教材分类列表
+      await catchStore.getMusicTagTreeApi();
+      _initTags();
+      // console.log(data, 'data');
+      // 获取声部列表
+      await catchStore.getSubjects();
+
+      if (props.musicalInstrumentId) {
+        backInstruments();
+      } else {
+        formatFirstSubject();
+      }
+      onSearch();
+    });
+    return () => (
+      <div
+        class={[
+          styles.searchGroup,
+          isShowInstrument.value && styles.searchGroupOnly
+        ]}>
+        <NForm labelAlign="left" labelPlacement="left">
+          {data.newTags.length > 1 && (
+            <NFormItem
+              label={'标签:'}
+              class={isShowInstrument.value && styles.hideItem}>
+              <NSpace class={styles.spaceSection}>
+                {data.newTags.map((subject: any) => (
+                  <span
+                    class={[
+                      styles.textBtn,
+                      forms.musicTagIds === subject.id && styles.textBtnActive
+                    ]}
+                    onClick={() => {
+                      forms.musicTagIds = subject.id;
+                      onSearch();
+                    }}>
+                    {subject.name}
+                  </span>
+                ))}
+              </NSpace>
+            </NFormItem>
+          )}
+
+          <div class={!state.showMore && styles.hideItem}>
+            {data.tags.length > 0 && (
+              <NFormItem
+                label={data.tags[0]?.columnName + ':'}
+                class={isShowInstrument.value && styles.hideItem}>
+                <NSpace class={styles.spaceSection}>
+                  {data.tags.map((subject: any) => (
+                    <span
+                      class={[
+                        styles.textBtn,
+                        data.tagActiveId === subject.id && styles.textBtnActive
+                      ]}
+                      onClick={() => {
+                        changeTag(subject);
+                      }}>
+                      {subject.name}
+                    </span>
+                  ))}
+                </NSpace>
+              </NFormItem>
+            )}
+
+            <ChildNodeSearch
+              isHide={isShowInstrument.value}
+              activeRow={data.selectParents}
+              onSelectChildTag={(val: any) => {
+                data.childSelectId = val;
+                onSearch();
+              }}
+            />
+          </div>
+
+          <NFormItem
+            label="场景:"
+            class={[
+              !state.showMore && styles.hideItem,
+              isShowInstrument.value && styles.hideItem
+            ]}>
+            <NSpace class={styles.spaceSection}>
+              {data.audioPlayTypeList.map((subject: any) => (
+                <span
+                  class={[
+                    styles.textBtn,
+
+                    forms.audioPlayTypes === subject.value &&
+                      styles.textBtnActive
+                  ]}
+                  onClick={() => {
+                    forms.audioPlayTypes = subject.value;
+                    onSearch();
+                  }}>
+                  {subject.name}
+                </span>
+              ))}
+            </NSpace>
+          </NFormItem>
+
+          {(forms.audioPlayTypes !== 'SING' || isShowInstrument.value) && (
+            <NFormItem
+              label="乐器:"
+              class={
+                !state.showMore && !isShowInstrument.value && styles.hideItem
+              }>
+              <NSpace class={styles.spaceSection}>
+                {catchStore.getSubjectInstrumentOnly.map((subject: any) =>
+                  subject.instruments && subject.instruments.length > 1 ? (
+                    <NPopselect
+                      options={subject.instruments}
+                      trigger="hover"
+                      scrollable
+                      v-model:value={state.tempSubjectId}
+                      onUpdate:value={() => {
+                        forms.subjectId = state.tempSubjectId;
+                        onSearch();
+                      }}
+                      key={subject.value}
+                      class={[styles.popSelect]}>
+                      <span
+                        class={[
+                          styles.textBtn,
+                          selectChildObj(subject.instruments).selected &&
+                            styles.textBtnActive
+                        ]}>
+                        {selectChildObj(subject.instruments).name ||
+                          subject.name}
+                        <i class={styles.iconArrow}></i>
+                      </span>
+                    </NPopselect>
+                  ) : (
+                    <span
+                      class={[
+                        styles.textBtn,
+                        forms.subjectId === subject.value &&
+                          styles.textBtnActive
+                      ]}
+                      onClick={() => {
+                        forms.subjectId = subject.value;
+
+                        state.tempSubjectId = null;
+                        onSearch();
+                      }}>
+                      {subject.name}
+                    </span>
+                  )
+                )}
+              </NSpace>
+            </NFormItem>
+          )}
+        </NForm>
+        {!isShowInstrument.value && (
+          <div
+            class={[
+              styles.moreSearch,
+              state.showMore ? styles.activeSearch : ''
+            ]}
+            onClick={onShowMore}>
+            {state.showMore ? '收起' : '展开'}
+          </div>
+        )}
+      </div>
+    );
+  }
+});

+ 19 - 4
src/views/xiaoku-music/component/play-item/index.module.less

@@ -31,6 +31,7 @@
 
 .hidden {
   transform: translateY(100%);
+  display: flex;
   &.item {
      opacity: 0;
      display: none;
@@ -182,7 +183,7 @@
   }
 
   .time {
-    width: 90px;
+    width: 110px;
     white-space: nowrap;
     flex-shrink: 0;
   }
@@ -193,6 +194,7 @@
   position: absolute;
   top: -24px;
   right: 30px;
+  z-index: 2;
   display: flex;
   align-items: center;
   justify-content: center;
@@ -200,12 +202,25 @@
   cursor: pointer;
   background: #ffffff;
   border-radius: 100px 100px 0px 0px;
+  box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.1);
   width: 44px;
   height: 24px;
+  &::before {
+    content: '';
+    position: absolute;
+    top: 24px;
+    left: -30px;
+    background-color: #fff;
+    width: 100px;
+    height: 14px;
+    // border-radius: 100px 100px 0px 0px;
+  }
   img {
-     margin-top: 3px;
-     width: 14px;
-     height: 14px;
+    position: relative;
+    z-index: 2;
+    margin-top: 3px;
+    width: 14px !important;
+    height: 14px !important;
   }
 
   &.down {

+ 1 - 1
vite.config.ts

@@ -23,7 +23,7 @@ function resolve(dir: string) {
 }
 // https://vitejs.dev/config/
 // https://github.com/vitejs/vite/issues/1930 .env
-const proxyUrl = 'https://dev.kt.colexiu.com/';
+const proxyUrl = 'https://test.kt.colexiu.com/';
 // const proxyUrl = 'https://test.kt.colexiu.com';
 // const proxyUrl = 'http://192.168.3.14:7989';
 const now = new Date().getTime();