Просмотр исходного кода

Merge branch 'iteration-20240808-music-score' into iteration-20240816-fire

lex 10 месяцев назад
Родитель
Сommit
06ec8d97bf
53 измененных файлов с 3011 добавлено и 2045 удалено
  1. 1 1
      dev-dist/sw.js
  2. BIN
      src/common/images/icon-play-active.png
  3. BIN
      src/common/images/icon-play-default.png
  4. BIN
      src/common/images/icon-sing-active.png
  5. BIN
      src/common/images/icon-sing-default.png
  6. BIN
      src/components/CCascader/images/icon-arrow-down_small.png
  7. BIN
      src/components/CCascader/images/icon-arrow-up_small.png
  8. 9 1
      src/components/CCascader/index.module.less
  9. 175 57
      src/components/CCascader/index.tsx
  10. 1 0
      src/components/TheSearch/index.module.less
  11. 69 65
      src/components/TheSearch/index.tsx
  12. 48 45
      src/components/card-preview/music-modal/index.tsx
  13. 292 248
      src/components/card-type/index.module.less
  14. 53 7
      src/components/card-type/index.tsx
  15. 253 199
      src/components/layout/modals/suggestion-list.tsx
  16. 301 301
      src/custom-plugins/guide-page/music-guide.tsx
  17. 3 0
      src/store/modules/catchData.ts
  18. 83 74
      src/utils/contants.ts
  19. 150 144
      src/views/attend-class/component/musicScore.tsx
  20. 1 1
      src/views/attend-class/index.module.less
  21. 5 1
      src/views/attend-class/index.tsx
  22. 105 104
      src/views/attend-class/model/source-list/index.tsx
  23. 37 0
      src/views/attend-class/model/train-type/index.module.less
  24. 24 0
      src/views/attend-class/model/train-type/index.tsx
  25. 4 1
      src/views/attend-class/model/train-update/index.tsx
  26. 110 112
      src/views/home/modals/subject-modal/index.tsx
  27. 10 2
      src/views/natural-resources/components/my-collect/index.tsx
  28. 107 41
      src/views/natural-resources/components/my-collect/search-group-resources.tsx
  29. 11 2
      src/views/natural-resources/components/my-resources/index.tsx
  30. 26 12
      src/views/natural-resources/components/my-resources/search-group-resources.tsx
  31. 15 2
      src/views/natural-resources/components/share-resources/index.tsx
  32. 103 53
      src/views/natural-resources/components/share-resources/search-group-resources.tsx
  33. 39 5
      src/views/prepare-lessons/components/directory-main/index.tsx
  34. 28 25
      src/views/prepare-lessons/components/lesson-main/courseware-presets/index.tsx
  35. 4 0
      src/views/prepare-lessons/components/lesson-main/courseware/addCourseware.tsx
  36. 108 154
      src/views/prepare-lessons/components/lesson-main/index.tsx
  37. 13 3
      src/views/prepare-lessons/components/resource-main/components/resource-item/index.tsx
  38. 20 1
      src/views/prepare-lessons/components/resource-main/components/resource-item/resource-search-group/index.tsx
  39. 12 1
      src/views/prepare-lessons/components/resource-main/components/select-music/index.tsx
  40. 1 1
      src/views/prepare-lessons/components/resource-main/components/select-music/resource-search-group/index.tsx
  41. 1 0
      src/views/prepare-lessons/components/resource-main/index.tsx
  42. 1 1
      src/views/prepare-lessons/index.tsx
  43. 9 1
      src/views/prepare-lessons/model/select-music/index.tsx
  44. 23 7
      src/views/prepare-lessons/model/select-music/select-item/index.tsx
  45. 17 1
      src/views/prepare-lessons/model/select-music/select-item/search-group.tsx
  46. 9 0
      src/views/prepare-lessons/model/select-resources/index.tsx
  47. 129 42
      src/views/prepare-lessons/model/select-resources/select-item/class-search-group/index.tsx
  48. 28 7
      src/views/prepare-lessons/model/select-resources/select-item/index.tsx
  49. 102 50
      src/views/prepare-lessons/model/select-resources/select-item/resource-search-group/index.tsx
  50. 182 202
      src/views/prepare-lessons/model/subject-sync/index.tsx
  51. 64 3
      src/views/xiaoku-music/index.module.less
  52. 223 68
      src/views/xiaoku-music/index.tsx
  53. 2 0
      src/views/xiaoku-music/type.ts

+ 1 - 1
dev-dist/sw.js

@@ -82,7 +82,7 @@ define(['./workbox-bb0550c6'], (function (workbox) { 'use strict';
     "revision": "3ca0b8505b4bec776b69afdba2768812"
   }, {
     "url": "index.html",
-    "revision": "0.f0i7vtfproo"
+    "revision": "0.oe0btcmloh8"
   }], {});
   workbox.cleanupOutdatedCaches();
   workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {

BIN
src/common/images/icon-play-active.png


BIN
src/common/images/icon-play-default.png


BIN
src/common/images/icon-sing-active.png


BIN
src/common/images/icon-sing-default.png


BIN
src/components/CCascader/images/icon-arrow-down_small.png


BIN
src/components/CCascader/images/icon-arrow-up_small.png


+ 9 - 1
src/components/CCascader/index.module.less

@@ -74,6 +74,14 @@
         height: inherit;
       }
     }
+
+    .arrowSmall {
+      margin-top: 2px;
+      width: 9Px;
+      height: 5Px;
+      display: flex;
+      align-items: center;
+    }
   }
 
   .n-base-selection-placeholder {
@@ -192,4 +200,4 @@
     background: linear-gradient(312deg, #1B7AF8 0%, #3CBBFF 100%);
     color: #FFFFFF;
   }
-}
+}

+ 175 - 57
src/components/CCascader/index.tsx

@@ -12,10 +12,23 @@ import {
 import styles from './index.module.less';
 import arrowDown from './images/icon-arrow-down.png';
 import arrowUp from './images/icon-arrow-up.png';
+import arrowDownSmall from './images/icon-arrow-down_small.png';
+import arrowUpSmall from './images/icon-arrow-up_small.png';
+import { audioPlayType } from '/src/utils/contants';
 
 export default defineComponent({
   name: 'c-cascader',
   props: {
+    /** 是否显示场景搜索条件 */
+    showAudioPlayType: {
+      type: Boolean,
+      default: false
+    },
+    /** 子选项是否显示全部类型 */
+    childShowAllCheck: {
+      type: Boolean,
+      default: true
+    },
     value: {
       type: String,
       default: ''
@@ -24,6 +37,10 @@ export default defineComponent({
       type: Array as PropType<any[]>,
       default: () => []
     },
+    arrowType: {
+      type: String as PropType<'default' | 'small'>,
+      default: 'default'
+    },
     placeholder: {
       type: String,
       default: '请选择'
@@ -42,12 +59,15 @@ export default defineComponent({
     const state = reactive({
       popoverShow: false,
       selectParents: {}, // 选中的数据
+      tempAudioPlayTypes: '',
+      audioPlayTypes: '',
       tagActiveId: '' as any,
       tagActive: {} as any,
       childSelectId: null as any,
       x: 0,
       y: 0
     });
+    const audioPlayTypeList = ref([] as any);
 
     // const formatParentCurrentValue = (ids: any, list: any) => {
     //   for (const item of list) {
@@ -72,20 +92,23 @@ export default defineComponent({
       let children: any;
       let columnName = '';
       if (subject.children) {
-        children = [
-          {
+        children = [...subject.children];
+        let activeIndex = children.length > 0 ? children[0].id : '';
+        if (props.childShowAllCheck) {
+          children.unshift({
             columnName: subject.children[0].columnName,
             name: '全部' + subject.children[0].columnName || '',
             id: ''
-          },
-          ...subject.children
-        ];
+          });
+          activeIndex = '';
+        }
         columnName = subject.children[0].columnName;
 
+        state.childSelectId = activeIndex;
         state.selectParents = {
           ...subject,
           columnName,
-          activeIndex: '',
+          activeIndex,
           children
         };
       } else {
@@ -120,9 +143,17 @@ export default defineComponent({
       const id = props.value;
       const values = getValues(id);
       const names: any = [];
-      values.forEach((item: any) => {
-        names.push(item.name);
+      audioPlayTypeList.value.forEach((item: any) => {
+        if (item.id === state.tempAudioPlayTypes && props.showAudioPlayType) {
+          names.push(item.name);
+        }
       });
+      if (state.tempAudioPlayTypes !== 'SING') {
+        values.forEach((item: any) => {
+          names.push(item.name);
+        });
+      }
+
       if (props.showPath) {
         return names.join(' / ');
       } else {
@@ -172,24 +203,51 @@ export default defineComponent({
     const onReset = () => {
       state.childSelectId = null;
       state.tagActiveId = '';
+      state.audioPlayTypes = '';
+      state.tempAudioPlayTypes = '';
       state.selectParents = {};
       emit('update:value', '');
       emit('moreId', {
         childId: '',
-        parentId: ''
+        parentId: '',
+        audioPlayTypes: ''
       });
       state.popoverShow = false;
     };
 
     // 提交
     const onConfirm = () => {
-      emit('update:value', state.childSelectId || state.tagActiveId);
-      emit('moreId', {
-        childId: state.childSelectId,
-        parentId: state.tagActiveId
-      });
+      if (state.audioPlayTypes !== 'SING') {
+        emit('update:value', state.childSelectId || state.tagActiveId);
+        emit('moreId', {
+          childId: state.childSelectId,
+          parentId: state.tagActiveId,
+          audioPlayTypes: state.audioPlayTypes
+        });
+      } else {
+        emit('update:value', '');
+        emit('moreId', {
+          childId: '',
+          parentId: '',
+          audioPlayTypes: state.audioPlayTypes
+        });
+        state.tagActiveId = '';
+        state.childSelectId = null;
+      }
+
+      state.tempAudioPlayTypes = state.audioPlayTypes;
       state.popoverShow = false;
     };
+    onMounted(() => {
+      // 场景
+      const tempAudio = Object.keys(audioPlayType).map(key => {
+        return {
+          id: key,
+          name: audioPlayType[key]
+        };
+      });
+      audioPlayTypeList.value = [{ name: '全部场景', id: '' }, ...tempAudio];
+    });
     return () => (
       <>
         <NPopover
@@ -204,10 +262,15 @@ export default defineComponent({
               <div
                 class={[
                   styles.nBaseCascaser,
+                  'nBaseCascaser',
                   state.popoverShow ? styles.nBaseCascaserActive : ''
                 ]}
                 title={valueText.value}>
-                <div class={styles['n-base-selection-tags']}>
+                <div
+                  class={[
+                    styles['n-base-selection-tags'],
+                    'n-base-selection-tags'
+                  ]}>
                   <div class={styles['n-base-selection-input']}>
                     <div class={styles['n-base-selection-input__content']}>
                       {valueText.value}
@@ -215,8 +278,21 @@ export default defineComponent({
                   </div>
 
                   <div class={[styles['n-base-suffix']]}>
-                    <div class={[styles.arrow]}>
-                      <img src={state.popoverShow ? arrowUp : arrowDown} />
+                    <div
+                      class={[
+                        styles.arrow,
+                        props.arrowType === 'small' ? styles.arrowSmall : ''
+                      ]}>
+                      {props.arrowType === 'default' && (
+                        <img src={state.popoverShow ? arrowUp : arrowDown} />
+                      )}
+                      {props.arrowType === 'small' && (
+                        <img
+                          src={
+                            state.popoverShow ? arrowUpSmall : arrowDownSmall
+                          }
+                        />
+                      )}
                     </div>
                   </div>
                 </div>
@@ -229,7 +305,11 @@ export default defineComponent({
                     <div class={styles.inner}>{props.placeholder}</div>
                   )}
                 </div>
-                <div class={styles['n-base-selection__border']}></div>
+                <div
+                  class={[
+                    styles['n-base-selection__border'],
+                    'n-base-selection__border'
+                  ]}></div>
                 <div class={styles['n-base-selection__state-border']}></div>
               </div>
             ),
@@ -238,35 +318,64 @@ export default defineComponent({
                 <NScrollbar
                   class={styles.baseScrollBar}
                   style={{ maxHeight: '400px' }}>
-                  <div class={styles.baseContentTitle}>
-                    {props.options[0].columnName}
-                  </div>
-                  <div class={styles.baseContentWrap}>
-                    {props.options.map((subject: any) => (
-                      <span
-                        class={[
-                          styles.tag,
-                          (state.tagActiveId || '') == subject.id &&
-                            styles.tagActive
-                        ]}
-                        onClick={() => {
-                          if (state.tagActiveId !== subject.id) {
-                            state.childSelectId = null;
-                          }
-                          state.tagActiveId = subject.id;
+                  {props.showAudioPlayType && (
+                    <>
+                      <div class={styles.baseContentTitle}>场景</div>
+                      <div class={styles.baseContentWrap}>
+                        {audioPlayTypeList.value.map((subject: any) => (
+                          <span
+                            class={[
+                              styles.tag,
+                              (state.audioPlayTypes || '') == subject.id &&
+                                styles.tagActive
+                            ]}
+                            onClick={() => {
+                              if (state.audioPlayTypes !== subject.id) {
+                                state.childSelectId = null;
+                              }
+                              state.audioPlayTypes = subject.id;
+                            }}>
+                            {subject.name}
+                          </span>
+                        ))}
+                      </div>
+                    </>
+                  )}
 
-                          initParentSelect(subject);
-                        }}>
-                        {subject.name}
-                      </span>
-                    ))}
-                  </div>
-                  <ChildNodeSearch
-                    activeRow={state.selectParents}
-                    onSelectChildTag={(val: any) => {
-                      state.childSelectId = val;
-                    }}
-                  />
+                  {state.audioPlayTypes !== 'SING' && (
+                    <>
+                      <div class={styles.baseContentTitle}>
+                        {props.options[0].columnName}
+                      </div>
+                      <div class={styles.baseContentWrap}>
+                        {props.options.map((subject: any) => (
+                          <span
+                            class={[
+                              styles.tag,
+                              (state.tagActiveId || '') == subject.id &&
+                                styles.tagActive
+                            ]}
+                            onClick={() => {
+                              if (state.tagActiveId !== subject.id) {
+                                state.childSelectId = null;
+                              }
+                              state.tagActiveId = subject.id;
+
+                              initParentSelect(subject);
+                            }}>
+                            {subject.name}
+                          </span>
+                        ))}
+                      </div>
+                      <ChildNodeSearch
+                        childShowAllCheck={props.childShowAllCheck}
+                        activeRow={state.selectParents}
+                        onSelectChildTag={(val: any) => {
+                          state.childSelectId = val;
+                        }}
+                      />
+                    </>
+                  )}
                 </NScrollbar>
                 <div class={styles.btnGroup}>
                   <div class={[styles.btn, styles.btnCancel]} onClick={onReset}>
@@ -290,6 +399,11 @@ export default defineComponent({
 const ChildNodeSearch = defineComponent({
   name: 'ChildNodeSearch',
   props: {
+    /** 子选项是否显示全部类型 */
+    childShowAllCheck: {
+      type: Boolean,
+      default: true
+    },
     activeRow: {
       type: Object,
       default: () => ({})
@@ -324,14 +438,14 @@ const ChildNodeSearch = defineComponent({
             let children: any;
             let columnName = '';
             if (subject.children) {
-              children = [
-                {
+              children = [...subject.children];
+              if (props.childShowAllCheck) {
+                children.unshift({
                   columnName: subject.children[0].columnName,
                   name: '全部' + subject.children[0].columnName || '',
                   id: ''
-                },
-                ...subject.children
-              ];
+                });
+              }
               columnName = subject.children[0].columnName;
 
               selectItem.value = {
@@ -340,6 +454,7 @@ const ChildNodeSearch = defineComponent({
                 activeIndex: subject.activeIndex || '',
                 children
               };
+              emit('selectChildTag', subject.activeIndex || '');
             }
           }
         });
@@ -372,20 +487,23 @@ const ChildNodeSearch = defineComponent({
                     let children: any;
                     let columnName = '';
                     if (subject.children) {
-                      children = [
-                        {
+                      children = [...subject.children];
+                      let activeIndex =
+                        children.length > 0 ? children[0].id : '';
+                      if (props.childShowAllCheck) {
+                        children.unshift({
                           columnName: subject.children[0].columnName,
                           name: '全部' + subject.children[0].columnName || '',
                           id: ''
-                        },
-                        ...subject.children
-                      ];
+                        });
+                        activeIndex = '';
+                      }
                       columnName = subject.children[0].columnName;
 
                       selectItem.value = {
                         ...subject,
                         columnName,
-                        activeIndex: '',
+                        activeIndex,
                         children
                       };
                     } else {

+ 1 - 0
src/components/TheSearch/index.module.less

@@ -11,6 +11,7 @@
       padding-left: 12px;
       padding-right: 4px;
       height: 42px !important;
+      --n-height: 42px !important;
     }
 
     .n-button {

+ 69 - 65
src/components/TheSearch/index.tsx

@@ -1,65 +1,69 @@
-import { PropType, defineComponent, reactive } from 'vue';
-import styles from './index.module.less';
-import { InputProps, NButton, NInput } from 'naive-ui';
-import icon_search from '/src/common/images/icon_search.png';
-import icon_searchActive from '/src/common/images/icon_searchActive.png';
-
-export default defineComponent({
-  name: 'TheSearch',
-  props: {
-    /** 圆角 */
-    round: {
-      type: Boolean as PropType<InputProps['round']>,
-      default: false
-    },
-    border: {
-      type: Boolean,
-      default: true
-    },
-    placeholder: {
-      type: String,
-      default: '请输入搜索关键词'
-    }
-  },
-  emits: ['search'],
-  setup(props, { emit }) {
-    const searchData = reactive({
-      value: ''
-    });
-    return () => (
-      <NInput
-        class={[styles.TheSearch, props.border ? '' : styles.noBorder]}
-        round={props.round}
-        placeholder={props.placeholder}
-        clearable
-        v-model:value={searchData.value}
-        onClear={() => emit('search', '')}
-        onKeyup={(e: KeyboardEvent) => {
-          e.stopPropagation();
-          if (e.code === 'Enter') {
-            emit('search', searchData.value ? searchData.value.trim() : '');
-          }
-        }}>
-        {{
-          prefix: () => (
-            <>
-              <img class={styles.default} src={icon_search} />
-              <img class={styles.active} src={icon_searchActive} />
-            </>
-          ),
-          suffix: () => (
-            <NButton
-              size="small"
-              round
-              type="primary"
-              onClick={() =>
-                emit('search', searchData.value ? searchData.value.trim() : '')
-              }>
-              搜索
-            </NButton>
-          )
-        }}
-      </NInput>
-    );
-  }
-});
+import { PropType, defineComponent, reactive } from 'vue';
+import styles from './index.module.less';
+import { InputProps, NButton, NInput } from 'naive-ui';
+import icon_search from '/src/common/images/icon_search.png';
+import icon_searchActive from '/src/common/images/icon_searchActive.png';
+
+export default defineComponent({
+  name: 'TheSearch',
+  props: {
+    /** 圆角 */
+    round: {
+      type: Boolean as PropType<InputProps['round']>,
+      default: false
+    },
+    border: {
+      type: Boolean,
+      default: true
+    },
+    placeholder: {
+      type: String,
+      default: '请输入搜索关键词'
+    }
+  },
+  emits: ['search'],
+  setup(props, { emit }) {
+    const searchData = reactive({
+      value: ''
+    });
+    return () => (
+      <NInput
+        class={[
+          styles.TheSearch,
+          props.border ? '' : styles.noBorder,
+          'TheSearch'
+        ]}
+        round={props.round}
+        placeholder={props.placeholder}
+        clearable
+        v-model:value={searchData.value}
+        onClear={() => emit('search', '')}
+        onKeyup={(e: KeyboardEvent) => {
+          e.stopPropagation();
+          if (e.code === 'Enter') {
+            emit('search', searchData.value ? searchData.value.trim() : '');
+          }
+        }}>
+        {{
+          prefix: () => (
+            <>
+              <img class={styles.default} src={icon_search} />
+              <img class={styles.active} src={icon_searchActive} />
+            </>
+          ),
+          suffix: () => (
+            <NButton
+              size="small"
+              round
+              type="primary"
+              onClick={() =>
+                emit('search', searchData.value ? searchData.value.trim() : '')
+              }>
+              搜索
+            </NButton>
+          )
+        }}
+      </NInput>
+    );
+  }
+});

+ 48 - 45
src/components/card-preview/music-modal/index.tsx

@@ -1,45 +1,48 @@
-import { defineComponent, ref } from 'vue';
-import styles from './index.module.less';
-import { useUserStore } from '/src/store/modules/users';
-import { vaildMusicScoreUrl } from '/src/utils/urlUtils';
-import { iframeDislableKeyboard } from '/src/utils';
-
-export default defineComponent({
-  name: 'song-modal',
-  props: {
-    item: {
-      type: Object,
-      default: () => ({})
-    },
-    /** 从哪里使用 */
-    from: {
-      type: String,
-      default: ''
-    }
-  },
-  setup(props) {
-    const userStore = useUserStore();
-    const iframeRef = ref();
-    const isLoaded = ref(false);
-    // const origin = /(localhost|192)/.test(location.host)
-    //   ? 'https://test.lexiaoya.cn'
-    //   : location.origin;
-    const src = `${vaildMusicScoreUrl()}/instrument?v=${+new Date()}&modelType=practise&id=${
-      props.item.content
-    }&Authorization=${userStore.getToken}&platform=pc&zoom=0.8`;
-    return () => (
-      <div class={styles.musicScore}>
-        <iframe
-          ref={iframeRef}
-          onLoad={(val: any) => {
-            // emit('setIframe', iframeRef.value);
-            isLoaded.value = true;
-            iframeDislableKeyboard(val.target);
-          }}
-          class={[styles.container, 'musicIframe']}
-          frameborder="0"
-          src={src}></iframe>
-      </div>
-    );
-  }
-});
+import { defineComponent, ref } from 'vue';
+import styles from './index.module.less';
+import { useUserStore } from '/src/store/modules/users';
+import { vaildMusicScoreUrl } from '/src/utils/urlUtils';
+import { iframeDislableKeyboard } from '/src/utils';
+
+export default defineComponent({
+  name: 'song-modal',
+  props: {
+    item: {
+      type: Object,
+      default: () => ({})
+    },
+    /** 从哪里使用 */
+    from: {
+      type: String,
+      default: ''
+    }
+  },
+  setup(props) {
+    const userStore = useUserStore();
+    const iframeRef = ref();
+    const isLoaded = ref(false);
+    // const origin = /(localhost|192)/.test(location.host)
+    //   ? 'https://test.lexiaoya.cn'
+    //   : location.origin;
+    let src = `${vaildMusicScoreUrl()}/instrument?v=${+new Date()}&modelType=practise&id=${
+      props.item.content
+    }&Authorization=${userStore.getToken}&platform=pc&zoom=0.8`;
+    if (props.item.instrumentId) {
+      src += '&instrumentId=' + props.item.instrumentId;
+    }
+    return () => (
+      <div class={styles.musicScore}>
+        <iframe
+          ref={iframeRef}
+          onLoad={(val: any) => {
+            // emit('setIframe', iframeRef.value);
+            isLoaded.value = true;
+            iframeDislableKeyboard(val.target);
+          }}
+          class={[styles.container, 'musicIframe']}
+          frameborder="0"
+          src={src}></iframe>
+      </div>
+    );
+  }
+});

+ 292 - 248
src/components/card-type/index.module.less

@@ -1,249 +1,293 @@
-:global {
-  .n-card--bordered {
-    border: 1Px solid rgba(202, 228, 244, 1) !important;
-
-    &:hover {
-      border: 1Px solid rgba(0, 122, 254, 1) !important;
-    }
-  }
-}
-
-.card-section-content {
-  border-radius: 14px;
-  background: linear-gradient(270deg, #DBF1FF 0%, #E7F9FF 100%) !important;
-
-  // :global {
-  //   .n-card-cover {
-  //     border-radius: 14px !important;
-  //   }
-  // }
-
-  // 图片禁止拖动
-  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 */
-  }
-
-  &.isActive {
-    border: 2px solid rgba(0, 122, 254, 1) !important;
-  }
-
-}
-
-.card-section {
-  position: relative;
-  box-sizing: border-box;
-  width: 300px;
-  height: 220px;
-  border-radius: 14px;
-  background: linear-gradient(270deg, #DBF1FF 0%, #E7F9FF 100%) !important;
-  display: inline-flex;
-  transition: all .3s ease-in-out;
-
-  &.cardDrag {
-    cursor: move;
-
-    :global {
-      .n-image:not(.n-image--preview-disabled) {
-        cursor: move !important;
-      }
-    }
-  }
-
-  &.course {
-    cursor: pointer;
-  }
-
-
-
-  // 鼠标经过时样式
-  &:hover,
-  &.showAddBtn {
-    transform: scale(1.01);
-    transition: all .3s ease-in-out;
-
-
-    .addBtn {
-      display: block;
-      opacity: 1;
-      transition: all .3s ease-in-out;
-    }
-  }
-
-
-  // 封面样式
-  .cover {
-    width: 100%;
-    height: 100%;
-    background-color: #fff;
-    border-radius: 14px 14px 0 0;
-    overflow: hidden;
-
-    img {
-      height: fit-content;
-      min-height: 100%;
-    }
-  }
-
-
-  :global {
-    .n-card__footer {
-      padding: 10px 12px;
-    }
-
-    .n-card-cover {
-      // height: 170px;
-      flex: 1 auto;
-    }
-  }
-
-  .footer {
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    // padding: 3px 0;
-  }
-
-  .title {
-    display: flex;
-    align-items: center;
-
-    .titleType {
-      width: 13Px;
-      height: 13Px;
-      margin-top: 1px;
-    }
-
-    .titleContent {
-      padding-left: 6px;
-      font-size: max(16px, 12Px);
-      max-width: 160px;
-      color: #131415;
-      font-weight: 600 !important;
-      flex: 1;
-    }
-  }
-
-  // 收藏按钮
-  .btnGroup {
-    position: absolute;
-    right: 12px;
-    display: flex;
-    align-items: center;
-
-    :global {
-      .n-spin-content {
-        display: flex;
-        align-items: center;
-      }
-    }
-  }
-
-
-  .btnItem+.btnItem {
-    margin-left: 12px;
-  }
-
-  .iconCollect {
-    width: 34px;
-    height: 34px;
-    // background: url('../../common/images/icon-collect-default.png') no-repeat center;
-    // background-size: contain;
-    // position: absolute;
-    // right: 0;
-    transition: transform .2s ease;
-
-    &:hover {
-      transform: scale(1.1);
-      transition: transform .2s ease;
-    }
-
-    &.isCollect {
-      cursor: pointer;
-    }
-  }
-
-  .iconDiv {
-    right: 12px;
-  }
-
-  // 精选
-  .iconSelected {
-    background: url('../../common/images/icon-selected.png') no-repeat center;
-    background-size: contain;
-    position: absolute;
-    top: 0px;
-    left: 0px;
-    z-index: 9;
-    width: 58px;
-    height: 29px;
-    border-top-left-radius: 14px;
-  }
-
-  // 添加
-  .addBtn {
-    position: absolute;
-    top: 6px;
-    right: 6px;
-    font-size: max(16px, 12Px);
-    font-weight: 600 !important;
-    height: 32px;
-    border-radius: 8px;
-    // display: none;
-    // opacity: 0;
-    z-index: 99;
-    transition: all .3s ease-in-out;
-
-    &.addBtnDisabled {
-      background-color: #fff;
-      color: #999;
-      font-weight: bold !important;
-      --n-border: 1px solid #fff !important;
-      --n-border-hover: 1px solid #fff !important;
-      --n-border-pressed: 1px solid #fff !important;
-      --n-border-focus: 1px solid #fff !important;
-      --n-border-disabled: 1px solid #fff !important;
-      --n-opacity-disabled: 1 !important;
-    }
-  }
-
-
-  .offShelfBg {
-    position: absolute;
-    top: 0;
-    left: 0;
-    width: 100%;
-    height: 100%;
-    border-radius: 14px;
-    background-color: rgba(0, 0, 0, 0.7);
-    z-index: 10;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    flex-direction: column;
-
-    .offShelfTips {
-      font-size: 22px;
-      font-weight: 600;
-      color: #FFFFFF;
-      line-height: 30px;
-      padding-bottom: 32px;
-    }
-
-    .offShelfBtn {
-      height: 44px;
-      border-radius: 10px;
-      min-width: 124px;
-    }
-  }
+:global {
+  .n-card--bordered {
+    border: 1Px solid rgba(202, 228, 244, 1) !important;
+
+    &:hover {
+      border: 1Px solid rgba(0, 122, 254, 1) !important;
+    }
+  }
+}
+
+.card-section-content {
+  border-radius: 14px;
+  background: linear-gradient(270deg, #DBF1FF 0%, #E7F9FF 100%) !important;
+
+  // :global {
+  //   .n-card-cover {
+  //     border-radius: 14px !important;
+  //   }
+  // }
+
+  // 图片禁止拖动
+  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 */
+  }
+
+  &.isActive {
+    border: 2px solid rgba(0, 122, 254, 1) !important;
+  }
+
+}
+
+.card-section {
+  position: relative;
+  box-sizing: border-box;
+  width: 300px;
+  height: 220px;
+  border-radius: 14px;
+  background: linear-gradient(270deg, #DBF1FF 0%, #E7F9FF 100%) !important;
+  display: inline-flex;
+  transition: all .3s ease-in-out;
+
+  &.cardDrag {
+    cursor: move;
+
+    :global {
+      .n-image:not(.n-image--preview-disabled) {
+        cursor: move !important;
+      }
+    }
+  }
+
+  &.course {
+    cursor: pointer;
+  }
+
+
+
+  // 鼠标经过时样式
+  &:hover,
+  &.showAddBtn {
+    transform: scale(1.01);
+    transition: all .3s ease-in-out;
+
+
+    .addBtn {
+      display: block;
+      opacity: 1;
+      transition: all .3s ease-in-out;
+    }
+  }
+
+
+  // 封面样式
+  .cover {
+    width: 100%;
+    height: 100%;
+    background-color: #fff;
+    border-radius: 14px 14px 0 0;
+    overflow: hidden;
+
+    img {
+      height: fit-content;
+      min-height: 100%;
+    }
+  }
+
+
+  :global {
+    .n-card__footer {
+      padding: 10px 12px;
+    }
+
+    .n-card-cover {
+      // height: 170px;
+      position: relative;
+      flex: 1 auto;
+    }
+  }
+
+  .audioPlayTypeSection {
+    position: absolute;
+    bottom: 10px;
+    right: 12px;
+    font-size: 0;
+    gap: 8px 10px !important;
+
+    &.audioPlayTypeSmall {
+      .iconType {
+        display: inline-block;
+        width: 22px;
+        height: 22px;
+      }
+
+    }
+
+    .iconType {
+      display: inline-block;
+      width: 26px;
+      height: 26px;
+    }
+
+    .iconPlay {
+      background: url('../../common/images/icon-play-default.png');
+      background-size: contain;
+
+      &:hover {
+        background: url('../../common/images/icon-play-active.png');
+        background-size: contain;
+      }
+    }
+
+    .iconSing {
+      background: url('../../common/images/icon-sing-default.png');
+      background-size: contain;
+
+      &:hover {
+        background: url('../../common/images/icon-sing-active.png');
+        background-size: contain;
+      }
+    }
+  }
+
+  .footer {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    // padding: 3px 0;
+  }
+
+  .title {
+    display: flex;
+    align-items: center;
+
+    .titleType {
+      width: 13Px;
+      height: 13Px;
+      margin-top: 1px;
+    }
+
+    .titleContent {
+      padding-left: 6px;
+      font-size: max(16px, 12Px);
+      max-width: 160px;
+      color: #131415;
+      font-weight: 600 !important;
+      flex: 1;
+    }
+  }
+
+  // 收藏按钮
+  .btnGroup {
+    position: absolute;
+    right: 12px;
+    display: flex;
+    align-items: center;
+
+    :global {
+      .n-spin-content {
+        display: flex;
+        align-items: center;
+      }
+    }
+  }
+
+
+  .btnItem+.btnItem {
+    margin-left: 12px;
+  }
+
+  .iconCollect {
+    width: 34px;
+    height: 34px;
+    // background: url('../../common/images/icon-collect-default.png') no-repeat center;
+    // background-size: contain;
+    // position: absolute;
+    // right: 0;
+    transition: transform .2s ease;
+
+    &:hover {
+      transform: scale(1.1);
+      transition: transform .2s ease;
+    }
+
+    &.isCollect {
+      cursor: pointer;
+    }
+  }
+
+  .iconDiv {
+    right: 12px;
+  }
+
+  // 精选
+  .iconSelected {
+    background: url('../../common/images/icon-selected.png') no-repeat center;
+    background-size: contain;
+    position: absolute;
+    top: 0px;
+    left: 0px;
+    z-index: 9;
+    width: 58px;
+    height: 29px;
+    border-top-left-radius: 14px;
+  }
+
+  // 添加
+  .addBtn {
+    position: absolute;
+    top: 6px;
+    right: 6px;
+    font-size: max(16px, 12Px);
+    font-weight: 600 !important;
+    height: 32px;
+    border-radius: 8px;
+    // display: none;
+    // opacity: 0;
+    z-index: 99;
+    transition: all .3s ease-in-out;
+
+    &.addBtnDisabled {
+      background-color: #fff;
+      color: #999;
+      font-weight: bold !important;
+      --n-border: 1px solid #fff !important;
+      --n-border-hover: 1px solid #fff !important;
+      --n-border-pressed: 1px solid #fff !important;
+      --n-border-focus: 1px solid #fff !important;
+      --n-border-disabled: 1px solid #fff !important;
+      --n-opacity-disabled: 1 !important;
+    }
+  }
+
+
+  .offShelfBg {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    border-radius: 14px;
+    background-color: rgba(0, 0, 0, 0.7);
+    z-index: 10;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    flex-direction: column;
+
+    .offShelfTips {
+      font-size: 22px;
+      font-weight: 600;
+      color: #FFFFFF;
+      line-height: 30px;
+      padding-bottom: 32px;
+    }
+
+    .offShelfBtn {
+      height: 44px;
+      border-radius: 10px;
+      min-width: 124px;
+    }
+  }
 }

+ 53 - 7
src/components/card-type/index.tsx

@@ -6,7 +6,9 @@ import {
   NCard,
   NImage,
   NModal,
+  NSpace,
   NSpin,
+  NTooltip,
   useMessage
 } from 'naive-ui';
 import iconImage from '@common/images/icon-image.png';
@@ -45,6 +47,7 @@ type itemType = {
   content?: string;
   title: string;
   isCollect: boolean;
+  audioPlayTypeArray?: string[];
   isSelected: boolean; // 精选
   exist?: boolean; // 是否已经选
 };
@@ -105,6 +108,10 @@ export default defineComponent({
     isDownload: {
       type: Boolean,
       default: false
+    },
+    audioPlayTypeSize: {
+      type: String as PropType<'default' | 'small'>,
+      deafult: 'default'
     }
   },
   /**
@@ -322,13 +329,52 @@ export default defineComponent({
                 )}
                 {/* 乐谱 */}
                 {props.item.type === 'MUSIC' && (
-                  <NImage
-                    class={[styles.cover, styles.image]}
-                    lazy
-                    previewDisabled={true}
-                    objectFit="contain"
-                    src={props.item.coverImg}
-                  />
+                  <>
+                    <NImage
+                      class={[styles.cover, styles.image]}
+                      lazy
+                      previewDisabled={true}
+                      objectFit="contain"
+                      src={props.item.coverImg}
+                    />
+                    <NSpace
+                      class={[
+                        styles.audioPlayTypeSection,
+                        props.audioPlayTypeSize === 'small'
+                          ? styles.audioPlayTypeSmall
+                          : ''
+                      ]}>
+                      {props.item.audioPlayTypeArray?.includes('PLAY') && (
+                        <NTooltip trigger="hover" showArrow={false}>
+                          {{
+                            trigger: () => (
+                              <span
+                                class={[
+                                  styles.iconType,
+                                  styles.iconPlay
+                                ]}></span>
+                            ),
+                            default: '演奏场景'
+                          }}
+                        </NTooltip>
+                      )}
+
+                      {props.item.audioPlayTypeArray?.includes('SING') && (
+                        <NTooltip trigger="hover" showArrow={false}>
+                          {{
+                            trigger: () => (
+                              <span
+                                class={[
+                                  styles.iconType,
+                                  styles.iconSing
+                                ]}></span>
+                            ),
+                            default: '演唱场景'
+                          }}
+                        </NTooltip>
+                      )}
+                    </NSpace>
+                  </>
                 )}
                 {/* 音频 */}
                 {props.item.type === 'SONG' && (

+ 253 - 199
src/components/layout/modals/suggestion-list.tsx

@@ -1,199 +1,253 @@
-import { PropType, defineComponent, onMounted, reactive, ref } from 'vue';
-import styles from './suggestion-list.module.less';
-import {
-  NInput,
-  NSelect,
-  NScrollbar,
-  NSpin,
-  NThing,
-  NImageGroup,
-  NSpace,
-  NImage,
-  NButton
-} from 'naive-ui';
-import { batchSetRead, getSysSuggestionList } from './api';
-import CDatePicker from '../../CDatePicker';
-import TheEmpty from '../../TheEmpty';
-import { useDebounceFn, useThrottleFn } from '@vueuse/core';
-import { eventGlobal, getTimes } from '/src/utils';
-
-export default defineComponent({
-  name: 'suggestion-list',
-  props: {
-    typeList: {
-      type: Array as PropType<any[]>,
-      default: () => []
-    }
-  },
-  setup(props) {
-    const state = reactive({
-      suggestionTypeList: [] as any,
-      loading: false,
-      finshed: false, // 是否加载完
-      pagination: {
-        page: 1,
-        rows: 20
-      },
-      searchGroup: {
-        suggestionTypeId: null,
-        timer: null as any
-      },
-      tableList: [] as any,
-      show: false,
-      item: {} as any
-    });
-
-    const getList = async () => {
-      try {
-        if (state.pagination.page === 1) {
-          state.loading = true;
-        }
-        const { timer, ...res } = state.searchGroup;
-        const { data } = await getSysSuggestionList({
-          ...state.searchGroup,
-          ...res,
-          ...getTimes(timer, ['startTime', 'endTime'])
-        });
-        state.loading = false;
-        const tempRows = data.rows || [];
-        tempRows.forEach((row: any) => {
-          const imgList =
-            (row.attachmentUrls && row.attachmentUrls.split(',')) || [];
-          row.imgList = imgList;
-        });
-        if (state.pagination.page === 1) {
-          state.tableList = tempRows;
-        } else {
-          state.tableList.push(...tempRows);
-        }
-        state.finshed = data.pages <= data.current ? true : false;
-      } catch {
-        state.loading = false;
-      }
-    };
-
-    const throttledFnSearch = useDebounceFn(item => {
-      state.pagination.page = state.pagination.page + 1;
-      state.pagination.page = 1;
-      state.tableList = [];
-      state.searchGroup = Object.assign(state.searchGroup, item);
-      getList();
-    }, 100);
-
-    const throttledFn = useThrottleFn(() => {
-      state.pagination.page = state.pagination.page + 1;
-      getList();
-    }, 500);
-
-    const getBatchSetRead = async () => {
-      try {
-        await batchSetRead({ messageType: 'SYS_SUGGEST_FEEDBACK_TEACHER' });
-
-        eventGlobal.emit('onSuggestionRead');
-      } catch {
-        //
-      }
-    };
-    onMounted(() => {
-      props.typeList.forEach((item: any) => {
-        state.suggestionTypeList.push({
-          label: item.name,
-          value: item.id
-        });
-      });
-      getBatchSetRead();
-      getList();
-    });
-    return () => (
-      <div class={styles.suggestionList}>
-        <div class={styles.attendClassSearch}>
-          <NSelect
-            placeholder="反馈类型"
-            clearable
-            options={
-              [
-                { label: '反馈类型', value: null },
-                ...state.suggestionTypeList
-              ] as any
-            }
-            v-model:value={state.searchGroup.suggestionTypeId}
-          />
-          <CDatePicker
-            v-model:value={state.searchGroup.timer}
-            separator={'至'}
-            start-placeholder="反馈开始日期"
-            end-placeholder="反馈结束日期"
-            type="daterange"
-            clearable={true}
-            timerValue={state.searchGroup.timer}></CDatePicker>
-
-          <NButton type="primary" class="searchBtn" onClick={throttledFnSearch}>
-            搜索
-          </NButton>
-        </div>
-        <NScrollbar
-          class={styles.classList}
-          onScroll={(e: any) => {
-            const clientHeight = e.target?.clientHeight;
-            const scrollTop = e.target?.scrollTop;
-            const scrollHeight = e.target?.scrollHeight;
-            // 是否到底,是否加载完
-            if (
-              clientHeight + scrollTop + 20 >= scrollHeight &&
-              !state.finshed &&
-              !state.loading
-            ) {
-              throttledFn();
-            }
-          }}>
-          <NSpin show={state.loading}>
-            <div
-              class={[
-                styles.listSection,
-                !state.loading && state.tableList.length <= 0
-                  ? styles.emptySection
-                  : ''
-              ]}>
-              {state.tableList.map((item: any) => (
-                <div>
-                  <NThing class={[styles.thingItem, 'isFull']}>
-                    <div class={styles.item}>
-                      <span>反馈类型:</span>
-                      {item.suggestionTypeName}
-                    </div>
-                    <div class={styles.item}>
-                      <span>反馈内容:</span>
-                      {item.content}
-                    </div>
-                    {item.imgList && item.imgList.length > 0 && (
-                      <div class={styles.item}>
-                        <NImageGroup class={styles.IMageWraps}>
-                          {item.imgList?.map((item: any, index: number) => (
-                            <NImage
-                              class={[styles.ShowImg]}
-                              src={item}
-                              objectFit="cover"></NImage>
-                          ))}
-                        </NImageGroup>
-                      </div>
-                    )}
-
-                    {item.handleStatus && (
-                      <div class={styles.itemResult}>
-                        <span>处理结果:</span>
-                        {item.handleAttitude === 'NO'
-                          ? '感谢你对音乐数字课堂的关注与支持,我们会认真处理您的反馈,尽快修复和完善相关功能!'
-                          : item.feedbackContent}
-                      </div>
-                    )}
-                  </NThing>
-                </div>
-              ))}
-              {!state.loading && state.tableList.length <= 0 && <TheEmpty />}
-            </div>
-          </NSpin>
-        </NScrollbar>
-      </div>
-    );
-  }
-});
+import { PropType, defineComponent, onMounted, reactive, ref } from 'vue';
+
+import styles from './suggestion-list.module.less';
+
+import {
+  NInput,
+  NSelect,
+  NScrollbar,
+  NSpin,
+  NThing,
+  NImageGroup,
+  NSpace,
+  NImage,
+  NButton
+} from 'naive-ui';
+
+import { batchSetRead, getSysSuggestionList } from './api';
+
+import CDatePicker from '../../CDatePicker';
+
+import TheEmpty from '../../TheEmpty';
+
+import { useDebounceFn, useThrottleFn } from '@vueuse/core';
+
+import { eventGlobal, getTimes } from '/src/utils';
+
+export default defineComponent({
+  name: 'suggestion-list',
+
+  props: {
+    typeList: {
+      type: Array as PropType<any[]>,
+
+      default: () => []
+    }
+  },
+
+  setup(props) {
+    const state = reactive({
+      suggestionTypeList: [] as any,
+
+      loading: false,
+
+      finshed: false, // 是否加载完
+
+      pagination: {
+        page: 1,
+
+        rows: 20
+      },
+
+      searchGroup: {
+        suggestionTypeId: null,
+
+        timer: null as any
+      },
+
+      tableList: [] as any,
+
+      show: false,
+
+      item: {} as any
+    });
+
+    const getList = async () => {
+      try {
+        if (state.pagination.page === 1) {
+          state.loading = true;
+        }
+
+        const { timer, ...res } = state.searchGroup;
+
+        const { data } = await getSysSuggestionList({
+          ...state.searchGroup,
+
+          ...res,
+
+          ...getTimes(timer, ['startTime', 'endTime'])
+        });
+
+        state.loading = false;
+
+        const tempRows = data.rows || [];
+
+        tempRows.forEach((row: any) => {
+          const imgList =
+            (row.attachmentUrls && row.attachmentUrls.split(',')) || [];
+
+          row.imgList = imgList;
+        });
+
+        if (state.pagination.page === 1) {
+          state.tableList = tempRows;
+        } else {
+          state.tableList.push(...tempRows);
+        }
+
+        state.finshed = data.pages <= data.current ? true : false;
+      } catch {
+        state.loading = false;
+      }
+    };
+
+    const throttledFnSearch = useDebounceFn(item => {
+      state.pagination.page = state.pagination.page + 1;
+
+      state.pagination.page = 1;
+
+      state.tableList = [];
+
+      state.searchGroup = Object.assign(state.searchGroup, item);
+
+      getList();
+    }, 100);
+
+    const throttledFn = useThrottleFn(() => {
+      state.pagination.page = state.pagination.page + 1;
+
+      getList();
+    }, 300);
+
+    const getBatchSetRead = async () => {
+      try {
+        await batchSetRead({ messageType: 'SYS_SUGGEST_FEEDBACK_TEACHER' });
+
+        eventGlobal.emit('onSuggestionRead');
+      } catch {
+        //
+      }
+    };
+
+    onMounted(() => {
+      props.typeList.forEach((item: any) => {
+        state.suggestionTypeList.push({
+          label: item.name,
+
+          value: item.id
+        });
+      });
+
+      getBatchSetRead();
+
+      getList();
+    });
+
+    return () => (
+      <div class={styles.suggestionList}>
+        <div class={styles.attendClassSearch}>
+          <NSelect
+            placeholder="反馈类型"
+            clearable
+            options={
+              [
+                { label: '反馈类型', value: null },
+
+                ...state.suggestionTypeList
+              ] as any
+            }
+            v-model:value={state.searchGroup.suggestionTypeId}
+          />
+
+          <CDatePicker
+            v-model:value={state.searchGroup.timer}
+            separator={'至'}
+            start-placeholder="反馈开始日期"
+            end-placeholder="反馈结束日期"
+            type="daterange"
+            clearable={true}
+            timerValue={state.searchGroup.timer}></CDatePicker>
+
+          <NButton type="primary" class="searchBtn" onClick={throttledFnSearch}>
+            搜索
+          </NButton>
+        </div>
+
+        <NScrollbar
+          class={styles.classList}
+          onScroll={(e: any) => {
+            const clientHeight = e.target?.clientHeight;
+
+            const scrollTop = e.target?.scrollTop;
+
+            const scrollHeight = e.target?.scrollHeight;
+
+            // 是否到底,是否加载完
+
+            if (
+              clientHeight + scrollTop + 20 >= scrollHeight &&
+              !state.finshed &&
+              !state.loading
+            ) {
+              throttledFn();
+            }
+          }}>
+          <NSpin show={state.loading}>
+            <div
+              class={[
+                styles.listSection,
+
+                !state.loading && state.tableList.length <= 0
+                  ? styles.emptySection
+                  : ''
+              ]}>
+              {state.tableList.map((item: any) => (
+                <div>
+                  <NThing class={[styles.thingItem, 'isFull']}>
+                    <div class={styles.item}>
+                      <span>反馈类型:</span>
+
+                      {item.suggestionTypeName}
+                    </div>
+
+                    <div class={styles.item}>
+                      <span>反馈内容:</span>
+
+                      {item.content}
+                    </div>
+
+                    {item.imgList && item.imgList.length > 0 && (
+                      <div class={styles.item}>
+                        <NImageGroup class={styles.IMageWraps}>
+                          {item.imgList?.map((item: any, index: number) => (
+                            <NImage
+                              class={[styles.ShowImg]}
+                              src={item}
+                              objectFit="cover"></NImage>
+                          ))}
+                        </NImageGroup>
+                      </div>
+                    )}
+
+                    {item.handleStatus && (
+                      <div class={styles.itemResult}>
+                        <span>处理结果:</span>
+
+                        {item.handleAttitude === 'NO'
+                          ? '感谢你对音乐数字课堂的关注与支持,我们会认真处理您的反馈,尽快修复和完善相关功能!'
+                          : item.feedbackContent}
+                      </div>
+                    )}
+                  </NThing>
+                </div>
+              ))}
+
+              {!state.loading && state.tableList.length <= 0 && <TheEmpty />}
+            </div>
+          </NSpin>
+        </NScrollbar>
+      </div>
+    );
+  }
+});
+

+ 301 - 301
src/custom-plugins/guide-page/music-guide.tsx

@@ -1,301 +1,301 @@
-import { NButton } from 'naive-ui';
-import {
-  defineComponent,
-  nextTick,
-  onMounted,
-  onUnmounted,
-  reactive,
-  ref,
-  watch
-} from 'vue';
-import styles from './index.module.less';
-import { getImage } from './images';
-import { eventGlobal, px2vw, px2vwH } from '@/utils/index';
-import { getGuidance, setGuidance } from './api';
-export default defineComponent({
-  name: 'music-guide',
-  emits: ['close'],
-  setup(props, { emit }) {
-    const data = reactive({
-      box: {
-        height: '0px'
-      } as any,
-      show: false,
-      /**
-       *
-            width:  px2vw(840),
-            height:  px2vw(295)
-       */
-      steps: [
-        {
-          ele: '',
-          eleRect: {} as DOMRect,
-          img: getImage('music1.png'),
-          handStyle: {
-            top: '0.91rem'
-          },
-          imgStyle: {
-            top: px2vw(-4),
-            left: px2vw(0),
-            width: px2vw(533),
-            height: px2vw(271)
-          },
-          btnsStyle: {
-            bottom: px2vw(40),
-            left: px2vw(-10)
-          },
-          eleRectPadding: {
-            left: 7,
-            top: 7,
-            width: 14,
-            height: 14
-          },
-          boxStyle: {}
-        },
-        {
-          ele: '',
-          img: getImage('music2.png'),
-          imgStyle: {
-            top: px2vw(-4),
-            left: px2vw(-205),
-            width: px2vw(420),
-            height: px2vw(228)
-          },
-          btnsStyle: {
-            bottom: px2vw(35),
-            left: px2vw(-48)
-          },
-          boxStyle: {
-            borderRadius: '25px'
-          },
-          eleRectPadding: {
-            left: 7,
-            top: 7,
-            width: 14,
-            height: 14
-          }
-        },
-        {
-          ele: '',
-          img: getImage('music3.png'),
-          imgStyle: {
-            top: '100%',
-            left: px2vw(-130),
-            width: px2vw(401),
-            height: px2vw(304)
-          },
-          btnsStyle: {
-            bottom: px2vw(100),
-            left: px2vw(30)
-          },
-          boxStyle: {
-            borderRadius: '40px'
-          },
-          eleRectPadding: {
-            left: 7,
-            top: 7,
-            width: 14,
-            height: 14
-          },
-          type: 'bottom'
-        }
-      ],
-      step: 0
-    });
-    const tipShow = ref(false);
-    const guideInfo = ref({} as any);
-    const getAllGuidance = async () => {
-      try {
-        const res = await getGuidance({ guideTag: 'teacher-guideInfo' });
-        if (res.data) {
-          guideInfo.value = JSON.parse(res.data?.guideValue) || null;
-        } else {
-          guideInfo.value = {};
-        }
-        if (guideInfo.value && guideInfo.value.musicGuide) {
-          tipShow.value = false;
-        } else {
-          tipShow.value = true;
-        }
-      } catch (e) {
-        console.log(e);
-      }
-      // const guideInfo = localStorage.getItem('teacher-guideInfo');
-    };
-    getAllGuidance();
-    // const guideInfo = localStorage.getItem('teacher-guideInfo');
-    // if (guideInfo && JSON.parse(guideInfo).musicGuide) {
-    //   tipShow.value = false;
-    // } else {
-    //   tipShow.value = true;
-    // }
-    const getStepELe = () => {
-      const ele: HTMLElement = document.getElementById(`music-${data.step}`)!;
-
-      if (ele) {
-        const eleRect = ele.getBoundingClientRect();
-        console.log(ele.style.display, 'ele');
-        if (ele.style.display == 'none') {
-          handleNext();
-          return;
-        }
-        const left = data.steps[data.step].eleRectPadding?.left || 0;
-        const top = data.steps[data.step].eleRectPadding?.top || 0;
-        const width = data.steps[data.step].eleRectPadding?.width || 0;
-        const height = data.steps[data.step].eleRectPadding?.height || 0;
-        data.box = {
-          left: eleRect.x - left + 'px',
-          top: eleRect.y - top + 'px',
-          width: eleRect.width + width + 'px',
-          height: eleRect.height + height + 'px'
-        };
-        // console.log(`coai-${data.step}`, data.box);
-      } else {
-        handleNext();
-      }
-    };
-    const onResetGuide = async (name: string) => {
-      try {
-        if (name !== 'xiaoku-music') return;
-        if (!guideInfo.value) {
-          guideInfo.value = { musicGuide: false };
-        } else {
-          guideInfo.value.musicGuide = false;
-        }
-        try {
-          await setGuidance({
-            guideTag: 'teacher-guideInfo',
-            guideValue: JSON.stringify(guideInfo.value)
-          });
-        } catch (e) {
-          console.log(e);
-        }
-        data.step = 0;
-        getStepELe();
-        tipShow.value = true;
-      } catch {
-        //
-      }
-    };
-    onMounted(() => {
-      getStepELe();
-      window.addEventListener('resize', resetSize);
-      eventGlobal.on('teacher-guideInfo', onResetGuide);
-    });
-    const resetSize = () => {
-      getStepELe();
-    };
-
-    onUnmounted(() => {
-      window.removeEventListener('resize', resetSize);
-      eventGlobal.off('teacher-guideInfo', onResetGuide);
-    });
-
-    const handleNext = () => {
-      if (data.step >= 3) {
-        endGuide();
-        return;
-      }
-      data.step = data.step + 1;
-      getStepELe();
-    };
-
-    const endGuide = async () => {
-      // let guideInfo =
-      //   JSON.parse(localStorage.getItem('teacher-guideInfo')|| '{}') || null;
-      if (!guideInfo.value) {
-        guideInfo.value = { musicGuide: true };
-      } else {
-        guideInfo.value.musicGuide = true;
-      }
-      // localStorage.setItem('teacher-guideInfo', JSON.stringify(guideInfo));
-      try {
-        const res = await setGuidance({
-          guideTag: 'teacher-guideInfo',
-          guideValue: JSON.stringify(guideInfo.value)
-        });
-      } catch (e) {
-        console.log(e);
-      }
-      tipShow.value = false;
-      //  localStorage.setItem('endC')
-    };
-    return () => (
-      <>
-        {tipShow.value ? (
-          <div
-            v-model:show={tipShow.value}
-            class={['n-modal-mask', 'n-modal-mask-guide']}>
-            <div class={styles.content} onClick={() => handleNext()}>
-              <div
-                class={styles.backBtn}
-                onClick={(e: Event) => {
-                  e.stopPropagation();
-                  endGuide();
-                }}>
-                跳过
-              </div>
-              <div
-                class={styles.box}
-                style={{ ...data.box, ...data.steps[data.step].boxStyle }}
-                id={`modeType-${data.step}`}>
-                {data.steps.map((item: any, index) => (
-                  <div
-                    onClick={(e: Event) => e.stopPropagation()}
-                    class={styles.item}
-                    style={
-                      item.type == 'bottom'
-                        ? {
-                            display: index === data.step ? '' : 'none',
-                            left: `${item.eleRect?.left}px`,
-                            top: `-${item.imgStyle?.height}`
-                          }
-                        : {
-                            display: index === data.step ? '' : 'none',
-                            left: `${item.eleRect?.left}px`,
-                            top: `${data.box?.height}`
-                          }
-                    }>
-                    <img
-                      class={styles.img}
-                      style={item.imgStyle}
-                      src={item.img}
-                    />
-                    {/* <img
-                      class={styles.iconHead}
-                      style={item.handStyle}
-                      src={getImage('indexDot.png')}
-                    /> */}
-                    <div class={styles.btns} style={item.btnsStyle}>
-                      {data.step + 1 == data.steps.length ? (
-                        <>
-                          <div
-                            class={[styles.endBtn]}
-                            onClick={() => endGuide()}>
-                            完成
-                          </div>
-                          <div
-                            class={styles.nextBtn}
-                            onClick={() => {
-                              data.step = 0;
-                              getStepELe();
-                            }}>
-                            再看一遍
-                          </div>
-                        </>
-                      ) : (
-                        <div class={styles.btn} onClick={() => handleNext()}>
-                          下一步 ({data.step + 1}/{data.steps.length})
-                        </div>
-                      )}
-                    </div>
-                  </div>
-                ))}
-              </div>
-            </div>
-          </div>
-        ) : null}
-      </>
-    );
-  }
-});
+import { NButton } from 'naive-ui';
+import {
+  defineComponent,
+  nextTick,
+  onMounted,
+  onUnmounted,
+  reactive,
+  ref,
+  watch
+} from 'vue';
+import styles from './index.module.less';
+import { getImage } from './images';
+import { eventGlobal, px2vw, px2vwH } from '@/utils/index';
+import { getGuidance, setGuidance } from './api';
+export default defineComponent({
+  name: 'music-guide',
+  emits: ['close'],
+  setup(props, { emit }) {
+    const data = reactive({
+      box: {
+        height: '0px'
+      } as any,
+      show: false,
+      /**
+       *
+            width:  px2vw(840),
+            height:  px2vw(295)
+       */
+      steps: [
+        {
+          ele: '',
+          eleRect: {} as DOMRect,
+          img: getImage('music1.png'),
+          handStyle: {
+            top: '0.91rem'
+          },
+          imgStyle: {
+            top: px2vw(-4),
+            left: px2vw(0),
+            width: px2vw(533),
+            height: px2vw(271)
+          },
+          btnsStyle: {
+            bottom: px2vw(40),
+            left: px2vw(-10)
+          },
+          eleRectPadding: {
+            left: 7,
+            top: 7,
+            width: 14,
+            height: 14
+          },
+          boxStyle: {}
+        },
+        {
+          ele: '',
+          img: getImage('music2.png'),
+          imgStyle: {
+            top: px2vw(-4),
+            left: px2vw(-205),
+            width: px2vw(420),
+            height: px2vw(228)
+          },
+          btnsStyle: {
+            bottom: px2vw(35),
+            left: px2vw(-48)
+          },
+          boxStyle: {
+            borderRadius: '25px'
+          },
+          eleRectPadding: {
+            left: 7,
+            top: 7,
+            width: 14,
+            height: 14
+          }
+        },
+        {
+          ele: '',
+          img: getImage('music3.png'),
+          imgStyle: {
+            top: '100%',
+            left: px2vw(-130),
+            width: px2vw(401),
+            height: px2vw(304)
+          },
+          btnsStyle: {
+            bottom: px2vw(100),
+            left: px2vw(30)
+          },
+          boxStyle: {
+            borderRadius: '40px'
+          },
+          eleRectPadding: {
+            left: 7,
+            top: 7,
+            width: 14,
+            height: 14
+          },
+          type: 'bottom'
+        }
+      ],
+      step: 0
+    });
+    const tipShow = ref(false);
+    const guideInfo = ref({} as any);
+    const getAllGuidance = async () => {
+      try {
+        const res = await getGuidance({ guideTag: 'teacher-guideInfo' });
+        if (res.data) {
+          guideInfo.value = JSON.parse(res.data?.guideValue) || null;
+        } else {
+          guideInfo.value = {};
+        }
+        if (guideInfo.value && guideInfo.value.musicGuide) {
+          tipShow.value = false;
+        } else {
+          tipShow.value = true;
+        }
+      } catch (e) {
+        console.log(e);
+      }
+      // const guideInfo = localStorage.getItem('teacher-guideInfo');
+    };
+    getAllGuidance();
+    // const guideInfo = localStorage.getItem('teacher-guideInfo');
+    // if (guideInfo && JSON.parse(guideInfo).musicGuide) {
+    //   tipShow.value = false;
+    // } else {
+    //   tipShow.value = true;
+    // }
+    const getStepELe = () => {
+      const ele: HTMLElement = document.getElementById(`music-${data.step}`)!;
+
+      if (ele) {
+        const eleRect = ele.getBoundingClientRect();
+        console.log(ele.style.display, 'ele');
+        if (ele.style.display == 'none') {
+          handleNext();
+          return;
+        }
+        const left = data.steps[data.step].eleRectPadding?.left || 0;
+        const top = data.steps[data.step].eleRectPadding?.top || 0;
+        const width = data.steps[data.step].eleRectPadding?.width || 0;
+        const height = data.steps[data.step].eleRectPadding?.height || 0;
+        data.box = {
+          left: eleRect.x - left + 'px',
+          top: eleRect.y - top + 'px',
+          width: eleRect.width + width + 'px',
+          height: eleRect.height + height + 'px'
+        };
+        // console.log(`coai-${data.step}`, data.box);
+      } else {
+        handleNext();
+      }
+    };
+    const onResetGuide = async (name: string) => {
+      try {
+        if (name !== 'xiaoku-music') return;
+        if (!guideInfo.value) {
+          guideInfo.value = { musicGuide: false };
+        } else {
+          guideInfo.value.musicGuide = false;
+        }
+        try {
+          await setGuidance({
+            guideTag: 'teacher-guideInfo',
+            guideValue: JSON.stringify(guideInfo.value)
+          });
+        } catch (e) {
+          console.log(e);
+        }
+        data.step = 0;
+        getStepELe();
+        tipShow.value = true;
+      } catch {
+        //
+      }
+    };
+    onMounted(() => {
+      getStepELe();
+      window.addEventListener('resize', resetSize);
+      eventGlobal.on('teacher-guideInfo', onResetGuide);
+    });
+    const resetSize = () => {
+      getStepELe();
+    };
+
+    onUnmounted(() => {
+      window.removeEventListener('resize', resetSize);
+      eventGlobal.off('teacher-guideInfo', onResetGuide);
+    });
+
+    const handleNext = () => {
+      if (data.step >= 3) {
+        endGuide();
+        return;
+      }
+      data.step = data.step + 1;
+      getStepELe();
+    };
+
+    const endGuide = async () => {
+      // let guideInfo =
+      //   JSON.parse(localStorage.getItem('teacher-guideInfo')|| '{}') || null;
+      if (!guideInfo.value) {
+        guideInfo.value = { musicGuide: true };
+      } else {
+        guideInfo.value.musicGuide = true;
+      }
+      // localStorage.setItem('teacher-guideInfo', JSON.stringify(guideInfo));
+      try {
+        const res = await setGuidance({
+          guideTag: 'teacher-guideInfo',
+          guideValue: JSON.stringify(guideInfo.value)
+        });
+      } catch (e) {
+        console.log(e);
+      }
+      tipShow.value = false;
+      //  localStorage.setItem('endC')
+    };
+    return () => (
+      <>
+        {tipShow.value ? (
+          <div
+            v-model:show={tipShow.value}
+            class={['n-modal-mask', 'n-modal-mask-guide']}>
+            <div class={styles.content} onClick={() => handleNext()}>
+              <div
+                class={styles.backBtn}
+                onClick={(e: Event) => {
+                  e.stopPropagation();
+                  endGuide();
+                }}>
+                跳过
+              </div>
+              <div
+                class={styles.box}
+                style={{ ...data.box, ...data.steps[data.step].boxStyle }}
+                id={`modeType-${data.step}`}>
+                {data.steps.map((item: any, index) => (
+                  <div
+                    onClick={(e: Event) => e.stopPropagation()}
+                    class={styles.item}
+                    style={
+                      item.type == 'bottom'
+                        ? {
+                            display: index === data.step ? '' : 'none',
+                            left: `${item.eleRect?.left}px`,
+                            top: `-${item.imgStyle?.height}`
+                          }
+                        : {
+                            display: index === data.step ? '' : 'none',
+                            left: `${item.eleRect?.left}px`,
+                            top: `${data.box?.height}`
+                          }
+                    }>
+                    <img
+                      class={styles.img}
+                      style={item.imgStyle}
+                      src={item.img}
+                    />
+                    {/* <img
+                      class={styles.iconHead}
+                      style={item.handStyle}
+                      src={getImage('indexDot.png')}
+                    /> */}
+                    <div class={styles.btns} style={item.btnsStyle}>
+                      {data.step + 1 == data.steps.length ? (
+                        <>
+                          <div
+                            class={[styles.endBtn]}
+                            onClick={() => endGuide()}>
+                            完成
+                          </div>
+                          {/* <div
+                            class={styles.nextBtn}
+                            onClick={() => {
+                              data.step = 0;
+                              getStepELe();
+                            }}>
+                            再看一遍
+                          </div> */}
+                        </>
+                      ) : (
+                        <div class={styles.btn} onClick={() => handleNext()}>
+                          下一步 ({data.step + 1}/{data.steps.length})
+                        </div>
+                      )}
+                    </div>
+                  </div>
+                ))}
+              </div>
+            </div>
+          </div>
+        ) : null}
+      </>
+    );
+  }
+});

+ 3 - 0
src/store/modules/catchData.ts

@@ -85,6 +85,9 @@ export const useCatchStore = defineStore('catch-store', {
         ...this.subjectInstruemnts
       ];
     },
+    getSubjectInstrumentOnly(): any[] {
+      return this.subjectInstruemnts;
+    },
     getMusicTagTree(): any[] {
       return this.musicTagTree;
     }

+ 83 - 74
src/utils/contants.ts

@@ -1,74 +1,83 @@
-/**
- * @description: 教材
- */
-export const teaching = {
-  1: '人教版',
-  2: '声部训练',
-  3: '小曲目',
-  4: '考级曲目'
-};
-
-/**
- * @description: 乐器
- */
-export const instrument = {
-  1: '坚笛',
-  2: '排萧',
-  3: '口风琴',
-  4: '陶笛',
-  5: '葫芦丝'
-};
-
-/**
- * @description: 资源类型
- */
-export const resourceType = {
-  MUSIC: '乐谱',
-  IMG: '图片',
-  SONG: '音频',
-  VIDEO: '视频',
-  PPT: 'PPT'
-};
-
-/**
- * @description: 评测难度
- * 入门:BEGINNER/进阶:ADVANCED/大师:PERFORMER")
- */
-export const evaluateDifficult = {
-  BEGINNER: '入门级',
-  ADVANCED: '进阶级',
-  PERFORMER: '大师级'
-} as any;
-
-/**
- * 训练完成状态
- */
-export const trainingStatus = {
-  UNSUBMITTED: '未提交',
-  SUBMITTED: '不合格',
-  TARGET: '合格'
-} as any;
-
-/** 周 */
-export const weekToCN = {
-  0: '星期天',
-  1: '星期一',
-  2: '星期二',
-  3: '星期三',
-  4: '星期四',
-  5: '星期五',
-  6: '星期六'
-} as any;
-
-/** 年级 */
-export const gradeToCN = {
-  1: '一年级',
-  2: '二年级',
-  3: '三年级',
-  4: '四年级',
-  5: '五年级',
-  6: '六年级',
-  7: '七年级',
-  8: '八年级',
-  9: '九年级'
-} as any;
+/**
+ * @description: 教材
+ */
+export const teaching = {
+  1: '人教版',
+  2: '声部训练',
+  3: '小曲目',
+  4: '考级曲目'
+};
+
+/**
+ * @description: 乐器
+ */
+export const instrument = {
+  1: '坚笛',
+  2: '排萧',
+  3: '口风琴',
+  4: '陶笛',
+  5: '葫芦丝'
+};
+
+/**
+ * @description: 资源类型
+ */
+export const resourceType = {
+  MUSIC: '乐谱',
+  IMG: '图片',
+  SONG: '音频',
+  VIDEO: '视频',
+  PPT: 'PPT'
+};
+
+/**
+ * @description: 评测难度
+ * 入门:BEGINNER/进阶:ADVANCED/大师:PERFORMER")
+ */
+export const evaluateDifficult = {
+  BEGINNER: '入门级',
+  ADVANCED: '进阶级',
+  PERFORMER: '大师级'
+} as any;
+
+/**
+ * 训练完成状态
+ */
+export const trainingStatus = {
+  UNSUBMITTED: '未提交',
+  SUBMITTED: '不合格',
+  TARGET: '合格'
+} as any;
+
+/** 周 */
+export const weekToCN = {
+  0: '星期天',
+  1: '星期一',
+  2: '星期二',
+  3: '星期三',
+  4: '星期四',
+  5: '星期五',
+  6: '星期六'
+} as any;
+
+/** 年级 */
+export const gradeToCN = {
+  1: '一年级',
+  2: '二年级',
+  3: '三年级',
+  4: '四年级',
+  5: '五年级',
+  6: '六年级',
+  7: '七年级',
+  8: '八年级',
+  9: '九年级'
+} as any;
+
+/**
+ * 场景
+ */
+export const audioPlayType = {
+  PLAY: '演奏',
+  SING: '演唱',
+  PLAY_SING: '演奏+演唱'
+} as any;

+ 150 - 144
src/views/attend-class/component/musicScore.tsx

@@ -1,144 +1,150 @@
-import { defineComponent, onMounted, onUnmounted, ref, watch } from 'vue';
-import { NSkeleton } from 'naive-ui';
-import styles from './musicScore.module.less';
-import { usePageVisibility } from '@vant/use';
-import { useUserStore } from '/src/store/modules/users';
-import { vaildMusicScoreUrl } from '/src/utils/urlUtils';
-import { iframeDislableKeyboard } from '/src/utils';
-
-export default defineComponent({
-  name: 'musicScore',
-  props: {
-    music: {
-      type: Object,
-      default: () => ({})
-    },
-    activeModel: {
-      type: Boolean
-    },
-    /** 当前是否为选中状态 */
-    activeStatus: {
-      type: Boolean
-    },
-    imagePos: {
-      type: String,
-      default: 'left'
-    }
-  },
-  emits: ['setIframe'],
-  setup(props, { emit }) {
-    const userStore = useUserStore();
-    const isLoading = ref(false);
-    const pageVisibility = usePageVisibility();
-    /** 页面显示和隐藏 */
-    watch(pageVisibility, value => {
-      console.log('🚀 ~ value:', value);
-      if (value == 'hidden') {
-        isLoading.value = false;
-      }
-    });
-    const iframeRef = ref();
-    const isLoaded = ref(false);
-    const renderError = ref(false);
-    const renderSuccess = ref(false);
-    // const origin = /(localhost|192)/.test(location.host)
-    //   ? 'https://test.lexiaoya.cn/instrument'
-    //   : // 'http://localhost:3000/instrument.html'
-    //     location.origin + '/instrument';
-    const src = `${vaildMusicScoreUrl()}/instrument/?v=${+new Date()}&showGuide=true&platform=pc&zoom=1.2&modelType=practise&id=${
-      props.music.content
-    }&Authorization=${userStore.getToken}&imagePos=${props.imagePos}`;
-    const checkView = () => {
-      fetch(src)
-        .then(() => {
-          renderSuccess.value = true;
-          renderError.value = false;
-        })
-        .catch(() => {
-          renderError.value = true;
-        });
-    };
-    watch(
-      () => props.music,
-      () => {
-        if (renderSuccess.value) return;
-        renderError.value = false;
-        if (props.music.display) {
-          checkView();
-        }
-      }
-    );
-
-    // 去云教练完整版
-    // const gotoAccomany = () => {
-    //   if (isLoading.value) return;
-    //   if (!browserInfo.ios) {
-    //     isLoading.value = true;
-    //   }
-    //   // const parmas = qs.stringify({
-    //   //   id: props.music.content
-    //   // });
-    //   // let src = `${location.origin}/orchestra-music-score/?` + parmas
-    //   const src = `https://test.lexiaoya.cn/orchestra-music-score/?_t=1687590480955&id=11707&modelType=practice&modeType=json&Authorization=bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib2F1dGgyLXJlc291cmNlIl0sImNsaWVudFR5cGUiOiJCQUNLRU5EIiwidXNlcl9uYW1lIjoiMTgxNjI4NTU4MDAiLCJzY29wZSI6WyJhbGwiXSwidXNlcklkIjoiMTAwMDE0OSIsImF1dGhvcml0aWVzIjpbIjE4MTYyODU1ODAwIl0sImp0aSI6IjY0MzA2NjllLTE5NGItNDk3Yy1hMDQ5LWM4YWUxMGU0NDNiOCIsImNsaWVudF9pZCI6ImptZWR1LWJhY2tlbmQifQ.aeJ0o-lSfx1Ok-YptZuC-AUY6M7k3LK9rr0Bmx7sj81pPt2HDiDqeT2PuriYdJacxWnxboyhdG_lwU0QK-W-vON97c45NQpSEFLVpZ0m1xdIqwllwf20xhyj5YJwdOFUzxf1TNEfGsHZg66J7wEJQBSzlmQwcxmEE5lqLVD8o_3f2SBqnWCj9RqE4air7FUemllMnZiu8HsS-TKtLDaGa_XW8Yb_Zjzzz6r5UcYNI-C1uKPXg18o1dhHBJ8O-Pl0U8WivPRub_opvO2NSn5L9YtPt7Dd50UeSwaIOdMeCGdii1bg__h77Stek1_5IaZLYkoo2gvmUA-xk09TwCQBpA`;
-    //   postMessage(
-    //     {
-    //       api: 'openAccompanyWebView',
-    //       content: {
-    //         url: src,
-    //         orientation: 0,
-    //         isHideTitle: true,
-    //         statusBarTextColor: false,
-    //         isOpenLight: true
-    //       }
-    //     },
-    //     () => {
-    //       if (browserInfo.ios) {
-    //         isLoading.value = true;
-    //       }
-    //     }
-    //   );
-    // };
-
-    watch(
-      () => props.activeModel,
-      () => {
-        if (iframeRef.value.contentWindow && props.activeStatus) {
-          // console.log(
-          //   iframeRef.value.contentWindow,
-          //   props.activeModel,
-          //   'iframeRef'
-          // );
-          iframeRef.value.contentWindow.postMessage(
-            {
-              api: 'attendClassBarStatus',
-              hideMenu: !props.activeModel
-            },
-            '*'
-          );
-        }
-      }
-    );
-
-    return () => (
-      <div class={styles.musicScore}>
-        <iframe
-          ref={iframeRef}
-          onLoad={(val: any) => {
-            emit('setIframe', iframeRef.value);
-            isLoaded.value = true;
-            iframeDislableKeyboard(val.target);
-          }}
-          class={[styles.container, 'musicIframe']}
-          frameborder="0"
-          src={src}></iframe>
-        {isLoaded.value && (
-          <div class={styles.skeletonWrap}>
-            <div>
-              <NSkeleton text repeat={8} />
-            </div>
-          </div>
-        )}
-      </div>
-    );
-  }
-});
+import { defineComponent, onMounted, onUnmounted, ref, watch } from 'vue';
+import { NSkeleton } from 'naive-ui';
+import styles from './musicScore.module.less';
+import { usePageVisibility } from '@vant/use';
+import { useUserStore } from '/src/store/modules/users';
+import { vaildMusicScoreUrl } from '/src/utils/urlUtils';
+import { iframeDislableKeyboard } from '/src/utils';
+
+export default defineComponent({
+  name: 'musicScore',
+  props: {
+    music: {
+      type: Object,
+      default: () => ({})
+    },
+    activeModel: {
+      type: Boolean
+    },
+    instrumentId: {
+      type: String
+    },
+    /** 当前是否为选中状态 */
+    activeStatus: {
+      type: Boolean
+    },
+    imagePos: {
+      type: String,
+      default: 'left'
+    }
+  },
+  emits: ['setIframe'],
+  setup(props, { emit }) {
+    const userStore = useUserStore();
+    const isLoading = ref(false);
+    const pageVisibility = usePageVisibility();
+    /** 页面显示和隐藏 */
+    watch(pageVisibility, value => {
+      console.log('🚀 ~ value:', value);
+      if (value == 'hidden') {
+        isLoading.value = false;
+      }
+    });
+    const iframeRef = ref();
+    const isLoaded = ref(false);
+    const renderError = ref(false);
+    const renderSuccess = ref(false);
+    // const origin = /(localhost|192)/.test(location.host)
+    //   ? 'https://test.lexiaoya.cn/instrument'
+    //   : // 'http://localhost:3000/instrument.html'
+    //     location.origin + '/instrument';
+    let src = `${vaildMusicScoreUrl()}/instrument/?v=${+new Date()}&showGuide=true&showWebGuide=false&platform=pc&zoom=1.2&modelType=practise&id=${
+      props.music.content
+    }&Authorization=${userStore.getToken}&imagePos=${props.imagePos}`;
+    if (props.instrumentId) {
+      src += `&instrumentId=${props.instrumentId}`;
+    }
+    const checkView = () => {
+      fetch(src)
+        .then(() => {
+          renderSuccess.value = true;
+          renderError.value = false;
+        })
+        .catch(() => {
+          renderError.value = true;
+        });
+    };
+    watch(
+      () => props.music,
+      () => {
+        if (renderSuccess.value) return;
+        renderError.value = false;
+        if (props.music.display) {
+          checkView();
+        }
+      }
+    );
+
+    // 去云教练完整版
+    // const gotoAccomany = () => {
+    //   if (isLoading.value) return;
+    //   if (!browserInfo.ios) {
+    //     isLoading.value = true;
+    //   }
+    //   // const parmas = qs.stringify({
+    //   //   id: props.music.content
+    //   // });
+    //   // let src = `${location.origin}/orchestra-music-score/?` + parmas
+    //   const src = `https://test.lexiaoya.cn/orchestra-music-score/?_t=1687590480955&id=11707&modelType=practice&modeType=json&Authorization=bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib2F1dGgyLXJlc291cmNlIl0sImNsaWVudFR5cGUiOiJCQUNLRU5EIiwidXNlcl9uYW1lIjoiMTgxNjI4NTU4MDAiLCJzY29wZSI6WyJhbGwiXSwidXNlcklkIjoiMTAwMDE0OSIsImF1dGhvcml0aWVzIjpbIjE4MTYyODU1ODAwIl0sImp0aSI6IjY0MzA2NjllLTE5NGItNDk3Yy1hMDQ5LWM4YWUxMGU0NDNiOCIsImNsaWVudF9pZCI6ImptZWR1LWJhY2tlbmQifQ.aeJ0o-lSfx1Ok-YptZuC-AUY6M7k3LK9rr0Bmx7sj81pPt2HDiDqeT2PuriYdJacxWnxboyhdG_lwU0QK-W-vON97c45NQpSEFLVpZ0m1xdIqwllwf20xhyj5YJwdOFUzxf1TNEfGsHZg66J7wEJQBSzlmQwcxmEE5lqLVD8o_3f2SBqnWCj9RqE4air7FUemllMnZiu8HsS-TKtLDaGa_XW8Yb_Zjzzz6r5UcYNI-C1uKPXg18o1dhHBJ8O-Pl0U8WivPRub_opvO2NSn5L9YtPt7Dd50UeSwaIOdMeCGdii1bg__h77Stek1_5IaZLYkoo2gvmUA-xk09TwCQBpA`;
+    //   postMessage(
+    //     {
+    //       api: 'openAccompanyWebView',
+    //       content: {
+    //         url: src,
+    //         orientation: 0,
+    //         isHideTitle: true,
+    //         statusBarTextColor: false,
+    //         isOpenLight: true
+    //       }
+    //     },
+    //     () => {
+    //       if (browserInfo.ios) {
+    //         isLoading.value = true;
+    //       }
+    //     }
+    //   );
+    // };
+
+    watch(
+      () => props.activeModel,
+      () => {
+        if (iframeRef.value.contentWindow && props.activeStatus) {
+          // console.log(
+          //   iframeRef.value.contentWindow,
+          //   props.activeModel,
+          //   'iframeRef'
+          // );
+          iframeRef.value.contentWindow.postMessage(
+            {
+              api: 'attendClassBarStatus',
+              hideMenu: !props.activeModel
+            },
+            '*'
+          );
+        }
+      }
+    );
+
+    return () => (
+      <div class={styles.musicScore}>
+        <iframe
+          ref={iframeRef}
+          onLoad={(val: any) => {
+            emit('setIframe', iframeRef.value);
+            isLoaded.value = true;
+            iframeDislableKeyboard(val.target);
+          }}
+          class={[styles.container, 'musicIframe']}
+          frameborder="0"
+          src={src}></iframe>
+        {isLoaded.value && (
+          <div class={styles.skeletonWrap}>
+            <div>
+              <NSkeleton text repeat={8} />
+            </div>
+          </div>
+        )}
+      </div>
+    );
+  }
+});

+ 1 - 1
src/views/attend-class/index.module.less

@@ -929,4 +929,4 @@
       }
     }
   }
-}
+}

+ 5 - 1
src/views/attend-class/index.tsx

@@ -260,6 +260,9 @@ export default defineComponent({
                 dataJson: child.dataJson,
                 isCollect: !!child.favoriteFlag,
                 isSelected: child.source === 'PLATFORM' ? true : false,
+                audioPlayTypeArray: child.audioPlayTypes
+                  ? child.audioPlayTypes.split(',')
+                  : [],
                 content: child.bizInfo.content,
                 parentIndex: index
               });
@@ -1887,6 +1890,7 @@ export default defineComponent({
                       ) : (
                         <MusicScore
                           activeModel={activeData.model}
+                          instrumentId={data.instrumentId}
                           activeStatus={popupData.activeIndex === mIndex}
                           data-vid={m.id}
                           music={m}
@@ -2389,7 +2393,7 @@ export default defineComponent({
           style={selResourDragData.styleDrag.value}
           preset="card"
           title={'选择资源'}>
-          <SelectResources from="class" />
+          <SelectResources from="class" instrumentId={data.instrumentId} />
           <Dragbom></Dragbom>
         </NModal>
         <NModal

+ 105 - 104
src/views/attend-class/model/source-list/index.tsx

@@ -1,104 +1,105 @@
-import { NCollapse, NCollapseItem, NScrollbar } from 'naive-ui';
-import { computed, defineComponent, ref, watch } from 'vue';
-import CardType from '/src/components/card-type';
-import styles from './index.module.less';
-
-export default defineComponent({
-  name: 'source-list',
-  props: {
-    knowledgePointList: {
-      type: Array,
-      default: () => []
-    },
-    activeItem: {
-      type: Object,
-      default: () => ({})
-    },
-    /** 当前播放的是第几个知识点组 */
-    courseActiveIndex: {
-      type: Number,
-      default: 0
-    },
-    teacherChapterName: {
-      type: String,
-      default: ''
-    }
-  },
-  emits: ['confirm'],
-  setup(props, { emit }) {
-    const parentIndex = ref(props.courseActiveIndex);
-
-    watch(
-      () => props.courseActiveIndex,
-      () => {
-        parentIndex.value = props.courseActiveIndex;
-      }
-    );
-
-    const childIndex = computed(() => {
-      let index = 0;
-      props.knowledgePointList.forEach((item: any) => {
-        item.list.forEach((child: any, j: number) => {
-          if (child.id === props.activeItem.id) {
-            index = j;
-          }
-        });
-      });
-      return index;
-    });
-    return () => (
-      <div class={styles.sourcelistBox}>
-        <div class={styles.treeBox}>
-          <div class={[styles.listSectionLeft]}>
-            <NScrollbar class={styles.leftscrollBar}>
-              {props.teacherChapterName && (
-                <div class={styles.className}>
-                  <i class={styles.classNameIcon}></i>
-                  <p class={styles.classNameContent}>
-                    {props.teacherChapterName}
-                  </p>
-                </div>
-              )}
-              {props.knowledgePointList.map((item: any, index: number) => (
-                <div
-                  class={[
-                    styles.treeParent,
-                    parentIndex.value === index && styles.parentSelect
-                  ]}
-                  key={'parent' + index}
-                  onClick={() => {
-                    parentIndex.value = index;
-                  }}>
-                  {item.title}
-                </div>
-              ))}
-            </NScrollbar>
-          </div>
-          <div class={[styles.listSectionRight]}>
-            <NScrollbar class={styles.rightscrollBar}>
-              {(props.knowledgePointList[parentIndex.value] as any)?.list &&
-                (props.knowledgePointList[parentIndex.value] as any).list.map(
-                  (child: any, j: number) => (
-                    <div class={[styles.cardContainer, 'drawerCardItemRef']}>
-                      <CardType
-                        item={child}
-                        isActive={
-                          childIndex.value === j &&
-                          parentIndex.value === props.courseActiveIndex
-                        }
-                        isCollect={false}
-                        isShowCollect={false}
-                        onClick={() => {
-                          emit('confirm', child);
-                        }}
-                      />
-                    </div>
-                  )
-                )}
-            </NScrollbar>
-          </div>
-        </div>
-      </div>
-    );
-  }
-});
+import { NCollapse, NCollapseItem, NScrollbar } from 'naive-ui';
+import { computed, defineComponent, ref, watch } from 'vue';
+import CardType from '/src/components/card-type';
+import styles from './index.module.less';
+
+export default defineComponent({
+  name: 'source-list',
+  props: {
+    knowledgePointList: {
+      type: Array,
+      default: () => []
+    },
+    activeItem: {
+      type: Object,
+      default: () => ({})
+    },
+    /** 当前播放的是第几个知识点组 */
+    courseActiveIndex: {
+      type: Number,
+      default: 0
+    },
+    teacherChapterName: {
+      type: String,
+      default: ''
+    }
+  },
+  emits: ['confirm'],
+  setup(props, { emit }) {
+    const parentIndex = ref(props.courseActiveIndex);
+
+    watch(
+      () => props.courseActiveIndex,
+      () => {
+        parentIndex.value = props.courseActiveIndex;
+      }
+    );
+
+    const childIndex = computed(() => {
+      let index = 0;
+      props.knowledgePointList.forEach((item: any) => {
+        item.list.forEach((child: any, j: number) => {
+          if (child.id === props.activeItem.id) {
+            index = j;
+          }
+        });
+      });
+      return index;
+    });
+    return () => (
+      <div class={styles.sourcelistBox}>
+        <div class={styles.treeBox}>
+          <div class={[styles.listSectionLeft]}>
+            <NScrollbar class={styles.leftscrollBar}>
+              {props.teacherChapterName && (
+                <div class={styles.className}>
+                  <i class={styles.classNameIcon}></i>
+                  <p class={styles.classNameContent}>
+                    {props.teacherChapterName}
+                  </p>
+                </div>
+              )}
+              {props.knowledgePointList.map((item: any, index: number) => (
+                <div
+                  class={[
+                    styles.treeParent,
+                    parentIndex.value === index && styles.parentSelect
+                  ]}
+                  key={'parent' + index}
+                  onClick={() => {
+                    parentIndex.value = index;
+                  }}>
+                  {item.title}
+                </div>
+              ))}
+            </NScrollbar>
+          </div>
+          <div class={[styles.listSectionRight]}>
+            <NScrollbar class={styles.rightscrollBar}>
+              {(props.knowledgePointList[parentIndex.value] as any)?.list &&
+                (props.knowledgePointList[parentIndex.value] as any).list.map(
+                  (child: any, j: number) => (
+                    <div class={[styles.cardContainer, 'drawerCardItemRef']}>
+                      <CardType
+                        item={child}
+                        audioPlayTypeSize="small"
+                        isActive={
+                          childIndex.value === j &&
+                          parentIndex.value === props.courseActiveIndex
+                        }
+                        isCollect={false}
+                        isShowCollect={false}
+                        onClick={() => {
+                          emit('confirm', child);
+                        }}
+                      />
+                    </div>
+                  )
+                )}
+            </NScrollbar>
+          </div>
+        </div>
+      </div>
+    );
+  }
+});

+ 37 - 0
src/views/attend-class/model/train-type/index.module.less

@@ -209,6 +209,8 @@
     }
   }
 
+
+
   &:hover {
     .preview {
       opacity: 1;
@@ -236,6 +238,41 @@
     height: 27px;
     cursor: pointer;
   }
+
+
+  .audioPlayTypeSection {
+    position: absolute;
+    bottom: 10px;
+    right: 10px;
+    font-size: 0;
+    gap: 8px 10px !important;
+
+    .iconType {
+      display: inline-block;
+      width: 26px;
+      height: 26px;
+    }
+
+    .iconPlay {
+      background: url('@/common/images/icon-play-default.png');
+      background-size: contain;
+
+      &:hover {
+        background: url('@/common/images/icon-play-active.png');
+        background-size: contain;
+      }
+    }
+
+    .iconSing {
+      background: url('@/common/images/icon-sing-default.png');
+      background-size: contain;
+
+      &:hover {
+        background: url('@/common/images/icon-sing-active.png');
+        background-size: contain;
+      }
+    }
+  }
 }
 
 .train-footer {

+ 24 - 0
src/views/attend-class/model/train-type/index.tsx

@@ -31,6 +31,7 @@ type ItemType = {
   coverImg: string;
   musicName: string;
   typeList: string[];
+  audioPlayTypeArray?: string[];
   allTimes?: number;
   trainingTimes?: number;
   recordId?: string | number; // 评测记录编号
@@ -202,6 +203,29 @@ export default defineComponent({
             previewDisabled
             objectFit="contain"
           />
+          <NSpace class={styles.audioPlayTypeSection}>
+            {props.item.audioPlayTypeArray?.includes('PLAY') && (
+              <NTooltip trigger="hover" showArrow={false}>
+                {{
+                  trigger: () => (
+                    <span class={[styles.iconType, styles.iconPlay]}></span>
+                  ),
+                  default: '演奏场景'
+                }}
+              </NTooltip>
+            )}
+
+            {props.item.audioPlayTypeArray?.includes('SING') && (
+              <NTooltip trigger="hover" showArrow={false}>
+                {{
+                  trigger: () => (
+                    <span class={[styles.iconType, styles.iconSing]}></span>
+                  ),
+                  default: '演唱场景'
+                }}
+              </NTooltip>
+            )}
+          </NSpace>
           {props.isDisabled && !props.isCLassWork ? (
             <div class={styles.disPreview}>
               <NProgress

+ 4 - 1
src/views/attend-class/model/train-update/index.tsx

@@ -53,6 +53,7 @@ export default defineComponent({
       maxScore: null as any,
       subjectId: '',
       coverImg: '',
+      audioPlayTypeArray: [] as any,
       practiceSpeed: null as any, // 练习速度
       practiceTimes: null as any, // 练习时长
       difficulty: 'BEGINNER', // 评测难度
@@ -72,6 +73,7 @@ export default defineComponent({
             trainingType: forms.type,
             musicId: forms.musicId,
             musicName: forms.musicName,
+            audioPlayTypeArray: forms.audioPlayTypeArray,
             coursewareKnowledgeDetailId: forms.coursewareKnowledgeDetailId,
             subjectId: forms.subjectId,
             id: forms.id,
@@ -112,7 +114,6 @@ export default defineComponent({
 
     onMounted(() => {
       const item = props.item;
-      console.log(item, 'item');
       if (item.trainId) {
         forms.id = item.trainId;
         forms.practiceSpeed = Number(item.practiceSpeed);
@@ -130,6 +131,8 @@ export default defineComponent({
         forms.minScore = 1;
         forms.maxScore = item.practiceChapterMax ? item.practiceChapterMax : 1;
       }
+      forms.audioPlayTypeArray = item.audioPlayTypeArray || [];
+
       forms.baseMaxScore = item.practiceChapterMax || 99;
       forms.musicId = item.id;
       forms.musicName = item.musicName;

+ 110 - 112
src/views/home/modals/subject-modal/index.tsx

@@ -1,112 +1,110 @@
-import { defineComponent, onMounted, ref } from 'vue';
-import styles from './index.module.less';
-import { NButton, NScrollbar, NSpace, NTabPane, NTabs } from 'naive-ui';
-import { useCatchStore } from '/src/store/modules/catchData';
-import iconSelect from '../../../prepare-lessons/images/icon-select.png';
-
-export default defineComponent({
-  name: 'subject-sync',
-  emits: ['close', 'confirm'],
-  setup(props, { emit }) {
-    const catchStore = useCatchStore();
-
-    const tabId = ref('' as any);
-    const selectSubjectId = ref(null as any);
-    const subjectList = ref([] as any);
-
-    const onSubmit = () => {
-      const item = subjectList.value.find(
-        (subject: any) => subject.id === selectSubjectId.value
-      );
-
-      emit('confirm', item);
-    };
-
-    const formatSubjectList = () => {
-      const subjects = catchStore.getEnableSubjects;
-      const temp: any = [];
-      subjects.forEach((subject: any) => {
-        console.log(
-          subject.id,
-          subject.instruments,
-          tabId.value && subject.instruments && tabId.value === subject.id
-        );
-        if (tabId.value === '' && subject.instruments) {
-          temp.push(...subject.instruments);
-        } else if (
-          tabId.value &&
-          subject.instruments &&
-          Number(tabId.value) === subject.id
-        ) {
-          temp.push(...subject.instruments);
-        }
-      });
-
-      subjectList.value = temp;
-    };
-    onMounted(async () => {
-      // await catchStore.getSubjects();
-      await catchStore.getSubjects();
-
-      formatSubjectList();
-    });
-    return () => (
-      <div class={styles.subjectSync}>
-        <NTabs
-          defaultValue=""
-          paneClass={styles.paneTitle}
-          justifyContent="start"
-          paneWrapperClass={styles.paneWrapperContainer}
-          value={tabId.value}
-          onUpdate:value={(val: any) => {
-            tabId.value = val;
-            formatSubjectList();
-          }}>
-          {[{ name: '全部声部', id: '' }, ...catchStore.getEnableSubjects].map(
-            (item: any) => (
-              <NTabPane
-                name={`${item.id}`}
-                tab={item.name}
-                displayDirective="if"></NTabPane>
-            )
-          )}
-        </NTabs>
-        <NScrollbar style={{ maxHeight: '50vh', minHeight: '50vh' }}>
-          <div class={styles.subjectList}>
-            {subjectList.value.map((subject: any) => (
-              <div
-                class={[
-                  styles.subjectItem,
-                  selectSubjectId.value === subject.id
-                    ? styles.subjectSelect
-                    : ''
-                ]}
-                onClick={() => {
-                  selectSubjectId.value = subject.id;
-                }}>
-                <div class={styles.imgSection}>
-                  <img src={subject.img} />
-
-                  {selectSubjectId.value === subject.id && (
-                    <img src={iconSelect} class={styles.iconSelect} />
-                  )}
-                </div>
-
-                <p class={styles.subjectName}>{subject.name}</p>
-              </div>
-            ))}
-          </div>
-        </NScrollbar>
-
-        <NSpace class={styles.btnGroupModal} justify="center">
-          <NButton round onClick={() => emit('close')}>
-            取消
-          </NButton>
-          <NButton round type="primary" onClick={onSubmit}>
-            确认选择
-          </NButton>
-        </NSpace>
-      </div>
-    );
-  }
-});
+import { defineComponent, onMounted, ref } from 'vue';
+import styles from './index.module.less';
+import { NButton, NScrollbar, NSpace, NTabPane, NTabs } from 'naive-ui';
+import { useCatchStore } from '/src/store/modules/catchData';
+import iconSelect from '../../../prepare-lessons/images/icon-select.png';
+
+export default defineComponent({
+  name: 'subject-sync',
+  emits: ['close', 'confirm'],
+  setup(props, { emit }) {
+    const catchStore = useCatchStore();
+
+    const tabId = ref('' as any);
+    const selectSubjectId = ref(null as any);
+    const subjectList = ref([] as any);
+
+    const onSubmit = () => {
+      const item = subjectList.value.find(
+        (subject: any) => subject.id === selectSubjectId.value
+      );
+
+      if (item) {
+        item.code = item.code ? item.code.split(',')[0] : '';
+      }
+      emit('confirm', item);
+    };
+
+    const formatSubjectList = () => {
+      const subjects = catchStore.getEnableSubjects;
+      const temp: any = [];
+      subjects.forEach((subject: any) => {
+        if (tabId.value === '' && subject.instruments) {
+          temp.push(...subject.instruments);
+        } else if (
+          tabId.value &&
+          subject.instruments &&
+          Number(tabId.value) === subject.id
+        ) {
+          temp.push(...subject.instruments);
+        }
+      });
+
+      subjectList.value = temp;
+    };
+    onMounted(async () => {
+      // await catchStore.getSubjects();
+      await catchStore.getSubjects();
+
+      formatSubjectList();
+    });
+    return () => (
+      <div class={styles.subjectSync}>
+        <NTabs
+          defaultValue=""
+          paneClass={styles.paneTitle}
+          justifyContent="start"
+          paneWrapperClass={styles.paneWrapperContainer}
+          value={tabId.value}
+          onUpdate:value={(val: any) => {
+            tabId.value = val;
+            formatSubjectList();
+          }}>
+          {[{ name: '全部声部', id: '' }, ...catchStore.getEnableSubjects].map(
+            (item: any) => (
+              <NTabPane
+                name={`${item.id}`}
+                tab={item.name}
+                displayDirective="if"></NTabPane>
+            )
+          )}
+        </NTabs>
+        <NScrollbar style={{ maxHeight: '50vh', minHeight: '50vh' }}>
+          <div class={styles.subjectList}>
+            {subjectList.value.map((subject: any) => (
+              <div
+                class={[
+                  styles.subjectItem,
+                  selectSubjectId.value === subject.id
+                    ? styles.subjectSelect
+                    : ''
+                ]}
+                onClick={() => {
+                  selectSubjectId.value = subject.id;
+                }}>
+                <div class={styles.imgSection}>
+                  <img src={subject.img} />
+
+                  {selectSubjectId.value === subject.id && (
+                    <img src={iconSelect} class={styles.iconSelect} />
+                  )}
+                </div>
+
+                <p class={styles.subjectName}>{subject.name}</p>
+              </div>
+            ))}
+          </div>
+        </NScrollbar>
+
+        <NSpace class={styles.btnGroupModal} justify="center">
+          <NButton round onClick={() => emit('close')}>
+            取消
+          </NButton>
+          <NButton round type="primary" onClick={onSubmit}>
+            确认选择
+          </NButton>
+        </NSpace>
+      </div>
+    );
+  }
+});

+ 10 - 2
src/views/natural-resources/components/my-collect/index.tsx

@@ -33,6 +33,7 @@ export default defineComponent({
         type: 'MUSIC', //
         name: '',
         bookVersionId: null,
+        musicalInstrumentId: null,
         subjectId: null,
         sourceType: 4
       },
@@ -66,6 +67,9 @@ export default defineComponent({
             content: row.content,
             subjectId: row.subjectIds,
             background: row.background,
+            audioPlayTypeArray: row.audioPlayTypes
+              ? row.audioPlayTypes.split(',')
+              : [],
             enableFlag: row.enableFlag ? 1 : 0,
             openFlag: row.openFlag
           });
@@ -124,7 +128,7 @@ export default defineComponent({
     };
 
     onMounted(() => {
-      getList();
+      // getList();
     });
     return () => (
       <>
@@ -146,7 +150,11 @@ export default defineComponent({
                     onClick={(val: any) => {
                       if (val.type === 'IMG' || !item.enableFlag) return;
                       state.show = true;
-                      state.item = val;
+                      state.item = {
+                        instrumentId:
+                          state.searchGroup.musicalInstrumentId || null,
+                        ...val
+                      };
                     }}
                     onCollect={(item: any) => onCollect(item)}
                   />

+ 107 - 41
src/views/natural-resources/components/my-collect/search-group-resources.tsx

@@ -12,6 +12,7 @@ import TheSearch from '/src/components/TheSearch';
 import { resourceTypeArray } from '/src/utils/searchArray';
 import { useCatchStore } from '/src/store/modules/catchData';
 import isCollaose from '../../images/isCollaose.png';
+import { audioPlayType } from '/src/utils/contants';
 
 export default defineComponent({
   name: 'search-group',
@@ -22,15 +23,27 @@ export default defineComponent({
     const forms = reactive({
       type: 'MUSIC', //
       name: '',
+      audioPlayTypes: '',
       bookVersionId: null,
       subjectId: null
     });
     const state = reactive({
       tempSubjectId: null
     });
+    const data = reactive({
+      audioPlayTypeList: [] as any
+    });
 
     const onSearch = () => {
-      emit('search', forms);
+      emit('search', {
+        ...forms,
+        subjectId: forms.audioPlayTypes !== 'SING' ? forms.subjectId : null,
+        audioPlayTypes: forms.audioPlayTypes
+          ? forms.audioPlayTypes === 'PLAY_SING'
+            ? ['PLAY', 'SING']
+            : [forms.audioPlayTypes]
+          : []
+      });
     };
 
     const collapseWrapRef = ref();
@@ -89,7 +102,29 @@ export default defineComponent({
       return obj;
     };
 
+    /** 默认选中第一个声部 */
+    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;
+        }
+      }
+    };
+
     onMounted(async () => {
+      // 场景
+      const tempAudio = Object.keys(audioPlayType).map(key => {
+        return {
+          value: key,
+          name: audioPlayType[key]
+        };
+      });
+      data.audioPlayTypeList = [{ name: '全部', value: '' }, ...tempAudio];
       resourceList.value = [
         // {
         //   label: '全部',
@@ -109,6 +144,8 @@ export default defineComponent({
       //   // 默认隐藏
       //   getLive();
       // }
+      formatFirstSubject();
+      onSearch();
     });
     return () => (
       <div class={styles.searchGroup}>
@@ -123,8 +160,8 @@ export default defineComponent({
                 focusable={false}
                 onClick={() => {
                   forms.type = item.value;
-                  forms.subjectId = null;
-                  state.tempSubjectId = null;
+                  forms.audioPlayTypes = '';
+                  formatFirstSubject();
                   onSearch();
 
                   nextTick(() => {
@@ -197,50 +234,79 @@ export default defineComponent({
               </NFormItem>
             </div>
           )} */}
-          <NFormItem label="乐器:">
-            <NSpace class={styles.spaceSection2}>
-              {catchStore.getSubjectInstruments.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;
+          <NFormItem label="场景:">
+            <NSpace class={styles.spaceSection}>
+              {data.audioPlayTypeList.map((subject: any) => (
+                <span
+                  class={[
+                    styles.textBtn,
 
-                      onSearch();
-                    }}
-                    key={subject.value}
-                    class={[styles.popSelect]}>
+                    forms.audioPlayTypes === subject.value &&
+                      styles.textBtnActive
+                  ]}
+                  onClick={() => {
+                    forms.audioPlayTypes = subject.value;
+                    // if (subject.value === 'SING') {
+                    //   state.tempSubjectId = null;
+                    //   forms.subjectId = null;
+                    // } else {
+                    //   formatFirstSubject();
+                    // }
+                    onSearch();
+                  }}>
+                  {subject.name}
+                </span>
+              ))}
+            </NSpace>
+          </NFormItem>
+          {forms.audioPlayTypes !== 'SING' && (
+            <NFormItem label="乐器:">
+              <NSpace class={styles.spaceSection2}>
+                {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,
-                        selectChildObj(subject.instruments).selected &&
+                        forms.subjectId === subject.value &&
                           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;
+                      ]}
+                      onClick={() => {
+                        forms.subjectId = subject.value;
 
-                      state.tempSubjectId = null;
-                      onSearch();
-                    }}>
-                    {subject.name}
-                  </span>
-                )
-              )}
-            </NSpace>
-          </NFormItem>
+                        state.tempSubjectId = null;
+                        onSearch();
+                      }}>
+                      {subject.name}
+                    </span>
+                  )
+                )}
+              </NSpace>
+            </NFormItem>
+          )}
 
           <TheSearch
             class={styles.inputSearch}

+ 11 - 2
src/views/natural-resources/components/my-resources/index.tsx

@@ -46,6 +46,7 @@ export default defineComponent({
         type: 'MUSIC', //
         name: '',
         bookVersionId: null,
+        musicalInstrumentId: null,
         subjectId: null,
         sourceType: 3
       },
@@ -90,6 +91,9 @@ export default defineComponent({
             instrumentIds: row.instrumentIds,
             sourceFrom: row.sourceFrom,
             background: row.background,
+            audioPlayTypeArray: row.audioPlayTypes
+              ? row.audioPlayTypes.split(',')
+              : [],
             enableFlag: row.enableFlag ? 1 : 0,
             openFlag: row.openFlag
           });
@@ -176,7 +180,7 @@ export default defineComponent({
     };
     const searchGroupResourcesRef = ref();
     onMounted(() => {
-      getList();
+      // getList();
     });
     return () => (
       <>
@@ -303,7 +307,12 @@ export default defineComponent({
                         onClick={(val: any) => {
                           if (val.type === 'IMG' || !item.enableFlag) return;
                           state.show = true;
-                          state.item = val;
+                          state.item = {
+                            instrumentId:
+                              state.searchGroup.musicalInstrumentId || null,
+                            ...val
+                          };
+                          console.log(state.item, 'item');
                         }}
                         onCollect={(item: any) => onCollect(item)}
                       />

+ 26 - 12
src/views/natural-resources/components/my-resources/search-group-resources.tsx

@@ -29,6 +29,7 @@ export default defineComponent({
     const forms = reactive({
       type: 'MUSIC', //
       name: '',
+      audioPlayTypes: ['PLAY'],
       bookVersionId: null,
       subjectId: null
     });
@@ -42,17 +43,26 @@ export default defineComponent({
       emit('search', forms);
     };
 
+    /** 默认选中第一个声部 */
+    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;
+        }
+      }
+
+      onSearch();
+    };
+
     onMounted(async () => {
-      resourceList.value = [
-        // {
-        //   label: '全部',
-        //   value: ''
-        // }
-      ];
+      resourceList.value = [];
       resourceTypeArray.forEach((item: any) => {
-        // if (item.value !== 'MUSIC') {
         resourceList.value.push(item);
-        // }
       });
 
       // 获取声部列表
@@ -61,6 +71,8 @@ export default defineComponent({
       if (forms.subjectId) {
         state.tempSubjectId = forms.subjectId;
       }
+
+      formatFirstSubject();
     });
 
     const selectChildObj = (item: any) => {
@@ -97,11 +109,13 @@ export default defineComponent({
                     state.isSelectAll = false;
                     emit('edit', state.isEdit);
                   }
+                  forms.audioPlayTypes = item.value === 'MUSIC' ? ['PLAY'] : [];
                   forms.type = item.value;
-                  forms.subjectId = null;
-                  state.tempSubjectId = null;
+                  // forms.subjectId = null;
+                  // state.tempSubjectId = null;
 
-                  onSearch();
+                  // onSearch();
+                  formatFirstSubject();
                 }}>
                 {item.label}
               </NButton>
@@ -206,7 +220,7 @@ export default defineComponent({
         <NForm labelAlign="left" labelPlacement="left">
           <NFormItem label="乐器:">
             <NSpace class={styles.spaceSection2}>
-              {catchStore.getSubjectInstruments.map((subject: any) =>
+              {catchStore.getSubjectInstrumentOnly.map((subject: any) =>
                 subject.instruments && subject.instruments.length > 1 ? (
                   <NPopselect
                     options={subject.instruments}

+ 15 - 2
src/views/natural-resources/components/share-resources/index.tsx

@@ -25,6 +25,8 @@ export default defineComponent({
       searchGroup: {
         type: 'MUSIC', //
         name: '',
+        audioPlayTypes: [] as any,
+        musicalInstrumentId: null,
         bookVersionId: null,
         subjectId: null,
         sourceType: 2
@@ -56,6 +58,9 @@ export default defineComponent({
             isCollect: !!row.favoriteFlag,
             isSelected: row.sourceFrom === 'PLATFORM' ? true : false,
             refFlag: row.refFlag,
+            audioPlayTypeArray: row.audioPlayTypes
+              ? row.audioPlayTypes.split(',')
+              : [],
             background: row.background,
             content: row.content
           });
@@ -120,7 +125,11 @@ export default defineComponent({
                       onClick={(val: any) => {
                         if (val.type === 'IMG') return;
                         state.show = true;
-                        state.item = val;
+                        state.item = {
+                          instrumentId:
+                            state.searchGroup.musicalInstrumentId || null,
+                          ...val
+                        };
                       }}
                       onCollect={(item: any) => onCollect(item)}
                     />
@@ -131,7 +140,11 @@ export default defineComponent({
                       onClick={(val: any) => {
                         if (val.type === 'IMG') return;
                         state.show = true;
-                        state.item = val;
+                        state.item = {
+                          instrumentId:
+                            state.searchGroup.musicalInstrumentId || null,
+                          ...val
+                        };
                       }}
                       onCollect={(item: any) => onCollect(item)}
                     />

+ 103 - 53
src/views/natural-resources/components/share-resources/search-group-resources.tsx

@@ -20,6 +20,7 @@ import {
 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 isCollaose from '../../images/isCollaose.png';
 
 const ChildNodeSearch = defineComponent({
@@ -118,6 +119,7 @@ export default defineComponent({
       type: 'MUSIC', //
       name: '',
       // grade: null as any,
+      audioPlayTypes: '',
       bookVersionId: null as any,
       // musicSheetCategoriesId: null as any,
       subjectId: null
@@ -126,6 +128,7 @@ export default defineComponent({
       tempSubjectId: null
     });
     const data = reactive({
+      audioPlayTypeList: [] as any, // 场景
       selectParents: {}, // 选中的数据
       tags: [] as any[],
       tagActiveId: '' as any,
@@ -136,6 +139,12 @@ export default defineComponent({
     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
       });
     };
@@ -236,7 +245,29 @@ export default defineComponent({
       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;
+        }
+      }
+    };
     onMounted(async () => {
+      // 场景
+      const tempAudio = Object.keys(audioPlayType).map(key => {
+        return {
+          value: key,
+          name: audioPlayType[key]
+        };
+      });
+      data.audioPlayTypeList = [{ name: '全部', value: '' }, ...tempAudio];
+
       // console.log('加载');
       // 获取教材分类列表
       // await catchStore.getMusicSheetCategory();
@@ -246,24 +277,12 @@ export default defineComponent({
       // 获取声部列表
       await catchStore.getSubjects();
 
+      formatFirstSubject();
       if (forms.type === 'MUSIC') {
         orginHeight.value = collapseWrapRef.value?.offsetHeight;
         // hiddenHeight.value = collapseWrapRef.value.offsetHeight / line.value;
         // 默认隐藏
         getLive();
-
-        // const musicTagTreeList = catchStore.getMusicTagTree;
-        // if (musicTagTreeList.length > 0) {
-        //   forms.bookVersionId = musicTagTreeList[0].id;
-        //   state.gradeList = musicTagTreeList[0].children || [];
-        //   if (state.gradeList.length > 0) {
-        //     forms.grade = state.gradeList[0].id;
-        //     state.musicCategory = state.gradeList[0].children || [];
-        //     if (state.musicCategory.length > 0) {
-        //       forms.musicSheetCategoriesId = state.musicCategory[0].id;
-        //     }
-        //   }
-        // }
       }
 
       onSearch();
@@ -281,12 +300,13 @@ export default defineComponent({
                 focusable={false}
                 onClick={() => {
                   forms.type = item.value;
-                  forms.subjectId = null;
-                  state.tempSubjectId = null;
+                  forms.audioPlayTypes = '';
                   data.tagActiveId = '';
                   data.childSelectId = null;
                   data.selectParents = {};
 
+                  formatFirstSubject();
+
                   onSearch();
 
                   nextTick(() => {
@@ -349,50 +369,80 @@ export default defineComponent({
             </>
           )}
 
-          <NFormItem label="乐器:">
+          <NFormItem label="场景:">
             <NSpace class={styles.spaceSection}>
-              {catchStore.getSubjectInstruments.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]}>
+              {data.audioPlayTypeList.map((subject: any) => (
+                <span
+                  class={[
+                    styles.textBtn,
+
+                    forms.audioPlayTypes === subject.value &&
+                      styles.textBtnActive
+                  ]}
+                  onClick={() => {
+                    forms.audioPlayTypes = subject.value;
+                    // if (subject.value === 'SING') {
+                    //   state.tempSubjectId = null;
+                    //   forms.subjectId = null;
+                    // } else {
+                    //   formatFirstSubject();
+                    // }
+                    onSearch();
+                  }}>
+                  {subject.name}
+                </span>
+              ))}
+            </NSpace>
+          </NFormItem>
+
+          {forms.audioPlayTypes !== 'SING' && (
+            <NFormItem label="乐器:">
+              <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,
-                        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;
+                        forms.subjectId === subject.value &&
+                          styles.textBtnActive
+                      ]}
+                      onClick={() => {
+                        forms.subjectId = subject.value;
 
-                      state.tempSubjectId = null;
-                      onSearch();
-                    }}>
-                    {subject.name}
-                  </span>
-                )
-              )}
-            </NSpace>
-          </NFormItem>
+                        state.tempSubjectId = null;
+                        onSearch();
+                      }}>
+                      {subject.name}
+                    </span>
+                  )
+                )}
+              </NSpace>
+            </NFormItem>
+          )}
 
           <TheSearch
             class={styles.inputSearch}

+ 39 - 5
src/views/prepare-lessons/components/directory-main/index.tsx

@@ -119,11 +119,48 @@ export default defineComponent({
           }
         });
         prepareStore.setTreeList(tempList);
+
+        const tempInstrumentId = prepareStore.getInstrumentId;
+        if (tempInstrumentId) {
+          const instrumentList = prepareStore.getFormatInstrumentList;
+          let status = false;
+          instrumentList.forEach((item: any) => {
+            if (item.instruments?.length > 0) {
+              item.instruments.forEach((child: any) => {
+                if (child.value == tempInstrumentId) {
+                  status = true;
+                }
+              });
+            }
+            if (item.value == tempInstrumentId) {
+              status = true;
+            }
+          });
+          if (!status) {
+            onShowDefaultInstrument();
+          }
+        } else {
+          onShowDefaultInstrument();
+        }
       } catch {
         //
       }
     };
 
+    const onShowDefaultInstrument = () => {
+      // 默认选中第一个声部
+      const instrumentList = prepareStore.getFormatInstrumentList;
+      if (instrumentList.length > 0) {
+        const tempList = instrumentList[0];
+        if (tempList.instruments.length > 1) {
+          const childTempList = tempList.instruments[0];
+          prepareStore.setInstrumentId(childTempList.value);
+        } else {
+          prepareStore.setInstrumentId(tempList.value);
+        }
+      }
+    };
+
     const formatParentId = (id: any, list: any, ids = [] as any) => {
       for (const item of list) {
         if (item.knowledgeList && item.knowledgeList.length > 0) {
@@ -169,7 +206,6 @@ export default defineComponent({
     const changeCourseware = async (item: any) => {
       prepareStore.setBaseCourseware(item);
       // prepareStore.setSubjectList(item.subjectList);
-
       if (item.instrumentIds) {
         const { data } = await getSubjectList2({
           instrumentIds: item.instrumentIds
@@ -192,14 +228,12 @@ export default defineComponent({
         });
         await getLessonCoursewareDetail();
         // 判断教材里面是否有当前选择的声部,如果没有则默认选择第一个
-        console.log(status, 'status');
+
         if (status) {
           const instrumentId = tempInstrumentId;
-          sessionStorage.removeItem('prepareLessonCourseWareSubjectIsNull');
           prepareStore.setInstrumentId(instrumentId);
         } else {
-          sessionStorage.removeItem('prepareLessonCourseWareSubjectIsNull');
-          prepareStore.setInstrumentId('');
+          onShowDefaultInstrument();
         }
       }
 

+ 28 - 25
src/views/prepare-lessons/components/lesson-main/courseware-presets/index.tsx

@@ -172,16 +172,15 @@ export default defineComponent({
 
     const checkInstrumentIds = () => {
       const instrumentsList = prepareStore.getSingleInstrumentList;
-
       // 并且没有声部时才会更新
       if (instrumentsList.length > 0) {
-        const prepareLessonCourseWareSubjectIsNull = sessionStorage.getItem(
-          'prepareLessonCourseWareSubjectIsNull'
-        );
-        if (prepareLessonCourseWareSubjectIsNull === 'true') {
-          prepareStore.setInstrumentId('');
-          return;
-        }
+        // const prepareLessonCourseWareSubjectIsNull = sessionStorage.getItem(
+        //   'prepareLessonCourseWareSubjectIsNull'
+        // );
+        // if (prepareLessonCourseWareSubjectIsNull === 'true') {
+        //   prepareStore.setInstrumentId('');
+        //   return;
+        // }
 
         // 并且声部在列表中
         const localStorageSubjectId = localStorage.getItem(
@@ -236,6 +235,10 @@ export default defineComponent({
         );
 
         subjectRef.value?.syncBarPosition();
+      } else {
+        if (forms.instrumentId) {
+          prepareStore.setInstrumentId(forms.instrumentId + '');
+        }
       }
     };
 
@@ -464,16 +467,16 @@ export default defineComponent({
                 }
               });
 
-              if (!val) {
-                prepareStore.setInstrumentId(val);
-                // 保存
-                forms.instrumentId = val;
-                forms.wikiCategoryIdChild = null;
-                sessionStorage.setItem(
-                  'prepareLessonCourseWareSubjectIsNull',
-                  val ? 'false' : 'true'
-                );
-              }
+              // if (!val) {
+              //   prepareStore.setInstrumentId(val);
+              //   // 保存
+              //   forms.instrumentId = val;
+              //   forms.wikiCategoryIdChild = null;
+              //   sessionStorage.setItem(
+              //     'prepareLessonCourseWareSubjectIsNull',
+              //     val ? 'false' : 'true'
+              //   );
+              // }
             }}
             v-slots={{
               suffix: () => (
@@ -497,7 +500,7 @@ export default defineComponent({
               )
             }}>
             {[
-              { name: '全部乐器', id: '', label: '全部乐器', value: '' },
+              // { name: '全部乐器', id: '', label: '全部乐器', value: '' },
               ...prepareStore.getFormatInstrumentList
             ].map((item: any, index: number) => (
               <NTabPane
@@ -518,12 +521,12 @@ export default defineComponent({
                           // 保存
                           forms.instrumentId = val;
 
-                          if (!val) {
-                            sessionStorage.setItem(
-                              'prepareLessonCourseWareSubjectIsNull',
-                              val ? 'false' : 'true'
-                            );
-                          }
+                          // if (!val) {
+                          //   sessionStorage.setItem(
+                          //     'prepareLessonCourseWareSubjectIsNull',
+                          //     val ? 'false' : 'true'
+                          //   );
+                          // }
                         }}
                         key={item.id}
                         class={styles.popSelect}>

+ 4 - 0
src/views/prepare-lessons/components/lesson-main/courseware/addCourseware.tsx

@@ -170,6 +170,9 @@ export default defineComponent({
                 dataJson: sub.dataJson,
                 // isCollect: !!sub.favoriteFlag,
                 isSelected: sub.source === 'PLATFORM' ? true : false,
+                audioPlayTypeArray: sub.audioPlayTypes
+                  ? sub.audioPlayTypes.split(',')
+                  : [],
                 content: sub.bizInfo.content,
                 removeFlag: sub.removeFlag
               });
@@ -928,6 +931,7 @@ export default defineComponent({
                                 offShelf={item.removeFlag ? true : false}
                                 // onOffShelf={() => onRemove(item)}
                                 item={item}
+                                audioPlayTypeSize="small"
                                 disabledMouseHover={false}
                                 onClick={() => {
                                   if (item.type === 'IMG') return;

+ 108 - 154
src/views/prepare-lessons/components/lesson-main/index.tsx

@@ -1,154 +1,108 @@
-import { defineComponent, nextTick, reactive, ref, watch } from 'vue';
-import styles from './index.module.less';
-// import { NTabPane, NTabs } from 'naive-ui';
-import Courseware from './courseware/addCourseware';
-// import Train from './train';
-import { usePrepareStore } from '/src/store/modules/prepareLessons';
-// import TrainPresets from './train-presets';
-import { eventGlobal } from '/src/utils';
-import CoursewarePresets from './courseware-presets';
-import CoursewareHead from './courseware-head';
-import { NButton, NSpace } from 'naive-ui';
-
-export default defineComponent({
-  name: 'lesson-main',
-  setup() {
-    const prepareStore = usePrepareStore();
-    const state = reactive({
-      editCoursewareShow: false, // 是否编辑课件
-      coursewareType: 'create' as 'create' | 'edit',
-      addParam: {
-        isAdd: false, // 是否添加
-        id: null,
-        addName: '' // 添加的名称
-      },
-      editCourseware: {} as any, //
-      // editWorkShow: false, // 是否编辑预设
-      editWork: {} as any // 预设模板编号
-    });
-    const coursewareHeadRef = ref();
-
-    // 取消
-    const onCancelCourseware = () => {
-      eventGlobal.emit('coursewareClosed', coursewareHeadRef.value?.getForms());
-    };
-
-    const onSaveCourseware = () => {
-      // console.log(
-      //   coursewareHeadRef.value,
-      //   coursewareHeadRef.value?.getForms(),
-      //   '12'
-      // );
-      eventGlobal.emit('coursewareSave', coursewareHeadRef.value?.getForms());
-    };
-
-    return () => (
-      <div
-        class={[state.editCoursewareShow && styles.coursewareSection]}
-        style={{ height: '100%' }}>
-        {/* 编辑作业头部标题 */}
-        {state.editCoursewareShow && (
-          <div class={styles.coursewareHeader}>
-            <CoursewareHead ref={coursewareHeadRef} />
-          </div>
-        )}
-
-        <div class={styles['lesson-main']}>
-          {state.editCoursewareShow ? (
-            // <NTabs
-            //   ref={lessonMainRef}
-            //   defaultValue="courseware"
-            //   paneClass={styles.paneTitle}
-            //   justifyContent="center"
-            //   paneWrapperClass={styles.paneWrapperContainer}
-            //   value={prepareStore.getTabType}
-            //   onUpdate:value={(val: string) => {
-            //     prepareStore.setTabType(val);
-            //     // 重置编辑状态
-            //     prepareStore.setIsEditResource(false);
-            //     prepareStore.setIsEditTrain(false);
-
-            //     eventGlobal.emit('teacher-slideshow', false);
-            //     if (val !== 'train') {
-            //       state.editWorkShow = false;
-            //     }
-            //   }}>
-            //   {!state.editWorkShow && (
-            //     <NTabPane
-            //       name="courseware"
-            //       tab={
-            //         state.editCoursewareShow
-            //           ? state.coursewareType === 'create'
-            //             ? '创建课件'
-            //             : '编辑课件'
-            //           : '课件'
-            //       }
-            //       displayDirective="if">
-            //       <Courseware
-            //         groupItem={state.editCourseware}
-            //         onChange={(val: any) => {
-            //           if (val.addParam) {
-            //             state.addParam = val.addParam;
-            //           }
-            //           state.editCoursewareShow = val.status;
-            //           prepareStore.setIsEditResource(val.status);
-            //           if (!val.status) {
-            //             eventGlobal.emit('teacher-slideshow', false);
-            //           }
-            //         }}
-            //       />
-            //     </NTabPane>
-            //   )}
-            // </NTabs>
-
-            <Courseware
-              groupItem={state.editCourseware}
-              onChange={(val: any) => {
-                if (val.addParam) {
-                  state.addParam = val.addParam;
-                }
-                state.editCoursewareShow = val.status;
-                prepareStore.setIsEditResource(val.status);
-                if (!val.status) {
-                  eventGlobal.emit('teacher-slideshow', false);
-                }
-              }}
-            />
-          ) : (
-            <CoursewarePresets
-              addParam={state.addParam}
-              onChange={(val: any) => {
-                state.coursewareType = val.type;
-                state.editCoursewareShow = val.status;
-                prepareStore.setIsEditResource(val.status);
-                state.editCourseware = val.groupItem;
-                state.addParam = {
-                  isAdd: false, // 是否添加
-                  id: null,
-                  addName: '' // 添加的名称
-                };
-              }}
-            />
-          )}
-        </div>
-
-        {/* 编辑作业底部操作 */}
-        {state.editCoursewareShow && (
-          <div class={styles.coursewareFooter}>
-            <NSpace>
-              <NButton
-                bordered={false}
-                type="error"
-                onClick={onCancelCourseware}>
-                取消
-              </NButton>
-              <NButton type="primary" onClick={onSaveCourseware}>
-                保存课件
-              </NButton>
-            </NSpace>
-          </div>
-        )}
-      </div>
-    );
-  }
-});
+import { defineComponent, nextTick, reactive, ref, watch } from 'vue';
+import styles from './index.module.less';
+// import { NTabPane, NTabs } from 'naive-ui';
+import Courseware from './courseware/addCourseware';
+// import Train from './train';
+import { usePrepareStore } from '/src/store/modules/prepareLessons';
+// import TrainPresets from './train-presets';
+import { eventGlobal } from '/src/utils';
+import CoursewarePresets from './courseware-presets';
+import CoursewareHead from './courseware-head';
+import { NButton, NSpace } from 'naive-ui';
+
+export default defineComponent({
+  name: 'lesson-main',
+  setup() {
+    const prepareStore = usePrepareStore();
+    const state = reactive({
+      editCoursewareShow: false, // 是否编辑课件
+      coursewareType: 'create' as 'create' | 'edit',
+      addParam: {
+        isAdd: false, // 是否添加
+        id: null,
+        addName: '' // 添加的名称
+      },
+      editCourseware: {} as any, //
+      // editWorkShow: false, // 是否编辑预设
+      editWork: {} as any // 预设模板编号
+    });
+    const coursewareHeadRef = ref();
+
+    // 取消
+    const onCancelCourseware = () => {
+      eventGlobal.emit('coursewareClosed', coursewareHeadRef.value?.getForms());
+    };
+
+    const onSaveCourseware = () => {
+      // console.log(
+      //   coursewareHeadRef.value,
+      //   coursewareHeadRef.value?.getForms(),
+      //   '12'
+      // );
+      eventGlobal.emit('coursewareSave', coursewareHeadRef.value?.getForms());
+    };
+
+    return () => (
+      <div
+        class={[state.editCoursewareShow && styles.coursewareSection]}
+        style={{ height: '100%' }}>
+        {/* 编辑作业头部标题 */}
+        {state.editCoursewareShow && (
+          <div class={styles.coursewareHeader}>
+            <CoursewareHead ref={coursewareHeadRef} />
+          </div>
+        )}
+
+        <div class={styles['lesson-main']}>
+          {state.editCoursewareShow ? (
+            <Courseware
+              groupItem={state.editCourseware}
+              onChange={(val: any) => {
+                if (val.addParam) {
+                  state.addParam = val.addParam;
+                }
+                state.editCoursewareShow = val.status;
+                prepareStore.setIsEditResource(val.status);
+                if (!val.status) {
+                  eventGlobal.emit('teacher-slideshow', false);
+                }
+              }}
+            />
+          ) : (
+            <CoursewarePresets
+              addParam={state.addParam}
+              onChange={(val: any) => {
+                state.coursewareType = val.type;
+                state.editCoursewareShow = val.status;
+                prepareStore.setIsEditResource(val.status);
+                state.editCourseware = val.groupItem;
+                state.addParam = {
+                  isAdd: false, // 是否添加
+                  id: null,
+                  addName: '' // 添加的名称
+                };
+              }}
+            />
+          )}
+        </div>
+
+        {/* 编辑作业底部操作 */}
+        {state.editCoursewareShow && (
+          <div class={styles.coursewareFooter}>
+            <NSpace>
+              <NButton
+                bordered={false}
+                type="error"
+                onClick={onCancelCourseware}>
+                取消
+              </NButton>
+              <NButton type="primary" onClick={onSaveCourseware}>
+                保存课件
+              </NButton>
+            </NSpace>
+          </div>
+        )}
+      </div>
+    );
+  }
+});

+ 13 - 3
src/views/prepare-lessons/components/resource-main/components/resource-item/index.tsx

@@ -57,6 +57,7 @@ export default defineComponent({
         bookVersionId: null,
         musicalInstrumentId: null,
         subjectId: null,
+        audioPlayTypes: [], // 场景
         sourceType: formatType(props.type),
         enableFlag: true
       },
@@ -97,7 +98,10 @@ export default defineComponent({
             isSelected: row.sourceFrom === 'PLATFORM' ? true : false,
             containAccompaniment: row.containAccompaniment,
             content: row.content,
-            sourceForm: 'resource-item'
+            sourceForm: 'resource-item',
+            audioPlayTypeArray: row.audioPlayTypes
+              ? row.audioPlayTypes.split(',')
+              : []
             // exist: index !== -1 ? true : false // 是否存在
           });
         });
@@ -126,7 +130,7 @@ export default defineComponent({
       state.tableList = [];
       state.searchGroup = Object.assign(state.searchGroup, item);
       getList();
-    }, 500);
+    }, 300);
 
     // 声部变化时
     watch(
@@ -152,6 +156,7 @@ export default defineComponent({
           title: item.title,
           isCollect: item.isCollect,
           isSelected: item.isSelected,
+          audioPlayTypeArray: item.audioPlayTypeArray,
           content: item.content,
           removeFlag: false
         });
@@ -294,7 +299,12 @@ export default defineComponent({
                               onClick={() => {
                                 if (item.type === 'IMG') return;
                                 state.show = true;
-                                state.item = item;
+                                state.item = {
+                                  instrumentId:
+                                    state.searchGroup.musicalInstrumentId ||
+                                    null,
+                                  ...item
+                                };
                               }}
                               onCollect={(item: any) => onCollect(item)}
                               // isShowAddDisabled={!prepareStore.getIsEditResource}

+ 20 - 1
src/views/prepare-lessons/components/resource-main/components/resource-item/resource-search-group/index.tsx

@@ -34,13 +34,24 @@ export default defineComponent({
       name: '',
       bookVersionId: null as any,
       subjectId: null as any,
+      audioPlayTypes: props.type === 'myResources' ? 'PLAY' : '',
       // musicSheetCategoriesId: null,
       musicalInstrumentId: ''
     });
     const resourceType = ref([] as any);
 
     const onSearch = () => {
-      emit('search', forms);
+      emit('search', {
+        ...forms,
+        audioPlayTypes:
+          forms.type === 'MUSIC'
+            ? forms.audioPlayTypes
+              ? forms.audioPlayTypes === 'PLAY_SING'
+                ? ['PLAY', 'SING']
+                : [forms.audioPlayTypes]
+              : []
+            : []
+      });
     };
 
     const debouncedRequest = useThrottleFn(() => onSearch(), 500);
@@ -80,6 +91,8 @@ export default defineComponent({
         },
         ...tags
       ];
+
+      console.log(tagSubjectList.value, 'tagSubjectList.value');
     };
     onMounted(async () => {
       // await catchStore.getMusicSheetCategory();
@@ -133,11 +146,17 @@ export default defineComponent({
             )}
             <CCascader
               placeholder="全部声部"
+              childShowAllCheck={false}
+              showPath
+              showAudioPlayType={props.type === 'myResources' ? false : true}
               v-model:value={subjects.value}
               options={tagSubjectList.value}
               onMoreId={(val: any) => {
                 forms.musicalInstrumentId = val.childId;
                 forms.subjectId = val.parentId;
+                if (props.type !== 'myResources') {
+                  forms.audioPlayTypes = val.audioPlayTypes;
+                }
                 onSearch();
               }}
             />

+ 12 - 1
src/views/prepare-lessons/components/resource-main/components/select-music/index.tsx

@@ -89,6 +89,10 @@ export default defineComponent({
         type: 'MUSIC', //
         musicSheetCategoriesId: '',
         musicalInstrumentId: '',
+        audioPlayTypes:
+          props.cardType === 'homerowk-record' || props.cardType === 'prepare'
+            ? ['PLAY']
+            : [],
         sourceType: formatType(props.type),
         status: 1,
         versionFlag: false,
@@ -137,6 +141,9 @@ export default defineComponent({
             refFlag: row.refFlag,
             isSelected: row.sourceFrom === 'PLATFORM' ? true : false,
             content: row.id,
+            audioPlayTypeArray: row.audioPlayTypes
+              ? row.audioPlayTypes.split(',')
+              : [],
             containAccompaniment: row.containAccompaniment,
             xmlFileUrl: row.xmlFileUrl
             // exist: index !== -1 ? true : false // 是否存在
@@ -298,7 +305,11 @@ export default defineComponent({
                       onClick={() => {
                         if (item.type === 'IMG') return;
                         state.show = true;
-                        state.item = item;
+                        state.item = {
+                          instrumentId:
+                            state.searchGroup.musicalInstrumentId || null,
+                          ...item
+                        };
                       }}
                       onAdd={(child: any) => onAdd(child)}
                       onCollect={(item: any) => onCollect(item)}

+ 1 - 1
src/views/prepare-lessons/components/resource-main/components/select-music/resource-search-group/index.tsx

@@ -117,7 +117,6 @@ export default defineComponent({
                 v-model:value={musics.value}
                 options={tagList.value}
                 onUpdate:value={(value: any) => {
-                  console.log(value, 'value');
                   forms.bookVersionId = value || '';
                   onSearch();
                 }}
@@ -125,6 +124,7 @@ export default defineComponent({
             )}
             <CCascader
               v-model:value={subjects.value}
+              childShowAllCheck={false}
               placement="bottom-end"
               placeholder="全部声部"
               options={tagSubjectList.value}

+ 1 - 0
src/views/prepare-lessons/components/resource-main/index.tsx

@@ -316,6 +316,7 @@ export default defineComponent({
           title={'选择曲目'}>
           <SelectMusicModal
             from={props.from}
+            cardType={props.cardType}
             onAdd={(item: any) => onAdd(item)}
           />
           {props.from === 'class' && <Dragbom></Dragbom>}

+ 1 - 1
src/views/prepare-lessons/index.tsx

@@ -68,7 +68,7 @@ export default defineComponent({
       prepareStore.setIsAddTrain(false);
       prepareStore.setIsEditResource(false);
       prepareStore.setIsEditTrain(false);
-      sessionStorage.removeItem('prepareLessonCourseWareSubjectIsNull');
+      // sessionStorage.removeItem('prepareLessonCourseWareSubjectIsNull');
     });
     onUnmounted(() => {
       prepareStore.setSubjectId('');

+ 9 - 1
src/views/prepare-lessons/model/select-music/index.tsx

@@ -1,5 +1,5 @@
 import { NTabPane, NTabs } from 'naive-ui';
-import { defineComponent, onMounted, ref, toRefs } from 'vue';
+import { PropType, defineComponent, onMounted, ref, toRefs } from 'vue';
 import styles from './index.module.less';
 import SelectItem from './select-item';
 import { useResizeObserver } from '@vueuse/core';
@@ -13,6 +13,11 @@ export default defineComponent({
       type: String,
       default: 'myResources'
     },
+    /** 类型 */
+    cardType: {
+      type: String as PropType<'' | 'homerowk-record' | 'prepare'>,
+      default: ''
+    },
     /** 从哪里使用 */
     from: {
       type: String,
@@ -56,6 +61,7 @@ export default defineComponent({
           }}>
           <NTabPane name="myResources" tab={'我的曲目'}>
             <SelectItem
+              cardType={props.cardType}
               from={props.from}
               type="myResources"
               onAdd={(item: any) => emit('add', item)}
@@ -64,6 +70,7 @@ export default defineComponent({
           <NTabPane name="shareResources" tab={'共享曲目'}>
             <SelectItem
               from={props.from}
+              cardType={props.cardType}
               type="shareResources"
               onAdd={(item: any) => emit('add', item)}
             />
@@ -71,6 +78,7 @@ export default defineComponent({
           <NTabPane name="myCollect" tab="收藏曲目">
             <SelectItem
               from={props.from}
+              cardType={props.cardType}
               type="myCollect"
               onAdd={(item: any) => emit('add', item)}
             />

+ 23 - 7
src/views/prepare-lessons/model/select-music/select-item/index.tsx

@@ -1,5 +1,5 @@
 import { NScrollbar, NSpin, NTabPane, NTabs } from 'naive-ui';
-import { defineComponent, onMounted, reactive, watch } from 'vue';
+import { PropType, defineComponent, onMounted, reactive, watch } from 'vue';
 import styles from './index.module.less';
 import CardType from '@/components/card-type';
 import SearchGroup from './search-group';
@@ -23,6 +23,11 @@ const formatType = (type: string) => {
 export default defineComponent({
   name: 'select-music',
   props: {
+    /** 类型 */
+    cardType: {
+      type: String as PropType<'' | 'homerowk-record' | 'prepare'>,
+      default: ''
+    },
     type: {
       type: String,
       default: ''
@@ -48,6 +53,10 @@ export default defineComponent({
         type: 'MUSIC', //
         musicSheetCategoriesId: '',
         musicalInstrumentId: '',
+        audioPlayTypes:
+          props.cardType === 'homerowk-record' || props.cardType === 'prepare'
+            ? ['PLAY']
+            : [],
         sourceType: formatType(props.type),
         status: 1,
         versionFlag: false,
@@ -86,6 +95,9 @@ export default defineComponent({
             refFlag: row.refFlag,
             content: row.id,
             xmlFileUrl: row.xmlFileUrl,
+            audioPlayTypeArray: row.audioPlayTypes
+              ? row.audioPlayTypes.split(',')
+              : [],
             containAccompaniment: row.containAccompaniment
             // exist: index !== -1 ? true : false // 是否存在
           });
@@ -122,12 +134,12 @@ export default defineComponent({
     };
     const throttledFnSearch = useDebounceFn(item => {
       onSearch(item);
-    }, 500);
+    }, 300);
 
     const throttledFn = useThrottleFn(() => {
       state.pagination.page = state.pagination.page + 1;
       getList();
-    }, 500);
+    }, 300);
 
     // 收藏
     const onCollect = async (item: any) => {
@@ -155,7 +167,7 @@ export default defineComponent({
       if (props.type === 'homework') {
         state.isShowAddDisabled = false;
       }
-      getList();
+      // getList();
     });
     return () => (
       <div class={styles.selectMusic}>
@@ -183,9 +195,9 @@ export default defineComponent({
               onSearch={(item: any, type: any) => {
                 if (type) {
                   onSearch(item);
-                  return;
+                } else {
+                  throttledFnSearch(item);
                 }
-                throttledFnSearch(item);
               }}
             />
           </div>
@@ -213,7 +225,11 @@ export default defineComponent({
                       onClick={() => {
                         if (item.type === 'IMG') return;
                         state.show = true;
-                        state.item = item;
+                        state.item = {
+                          instrumentId:
+                            state.searchGroup.musicalInstrumentId || null,
+                          ...item
+                        };
                       }}
                       onCollect={(item: any) => onCollect(item)}
                     />

+ 17 - 1
src/views/prepare-lessons/model/select-music/select-item/search-group.tsx

@@ -241,6 +241,20 @@ export default defineComponent({
       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.musicalInstrumentId = firstSubject.instruments[0]?.value;
+        } else {
+          forms.musicalInstrumentId = firstSubject.value;
+        }
+      }
+    };
+
     onMounted(async () => {
       // 获取教材分类列表
       // await catchStore.getMusicSheetCategory();
@@ -268,6 +282,8 @@ export default defineComponent({
       // }
       // console.log(state.musicCategory, 'state.musicCategory');
 
+      formatFirstSubject();
+
       onSearch('timer');
     });
     return () => (
@@ -380,7 +396,7 @@ export default defineComponent({
 
           <NFormItem label="乐器:">
             <NSpace class={styles.spaceSection2}>
-              {catchStore.getSubjectInstruments.map((subject: any) =>
+              {catchStore.getSubjectInstrumentOnly.map((subject: any) =>
                 subject.instruments && subject.instruments.length > 1 ? (
                   <NPopselect
                     options={subject.instruments}

+ 9 - 0
src/views/prepare-lessons/model/select-resources/index.tsx

@@ -20,6 +20,10 @@ export default defineComponent({
     from: {
       type: String,
       default: ''
+    },
+    instrumentId: {
+      type: String,
+      default: ''
     }
   },
   emits: ['select'],
@@ -64,6 +68,8 @@ export default defineComponent({
               <SelectItem
                 type="relateResources"
                 searchGroup={props.searchGroup}
+                from={props.from}
+                instrumentId={props.instrumentId}
               />
             </NTabPane>
           )}
@@ -74,6 +80,7 @@ export default defineComponent({
               type="shareResources"
               from={props.from}
               searchGroup={props.searchGroup}
+              instrumentId={props.instrumentId}
             />
           </NTabPane>
           <NTabPane
@@ -83,6 +90,7 @@ export default defineComponent({
               type="myResources"
               from={props.from}
               searchGroup={props.searchGroup}
+              instrumentId={props.instrumentId}
             />
           </NTabPane>
 
@@ -91,6 +99,7 @@ export default defineComponent({
               type="myCollect"
               from={props.from}
               searchGroup={props.searchGroup}
+              instrumentId={props.instrumentId}
             />
           </NTabPane>
         </NTabs>

+ 129 - 42
src/views/prepare-lessons/model/select-resources/select-item/class-search-group/index.tsx

@@ -21,6 +21,7 @@ import { useCatchStore } from '/src/store/modules/catchData';
 import { useThrottleFn } from '@vueuse/core';
 import TheSearch from '/src/components/TheSearch';
 import isCollaose from '/src/views/natural-resources/images/isCollaose.png';
+import { audioPlayType } from '/src/utils/contants';
 
 export default defineComponent({
   name: 'resource-search-group',
@@ -34,6 +35,11 @@ export default defineComponent({
     subjectId: {
       type: String,
       default: ''
+    },
+    // 从哪里来的
+    from: {
+      type: String,
+      default: ''
     }
   },
   emits: ['search'],
@@ -43,13 +49,28 @@ export default defineComponent({
     const forms = reactive({
       type: 'MUSIC', //
       name: '',
+      audioPlayTypes:
+        props.type === 'myResources' && props.from === 'class' ? 'PLAY' : '',
       subjectId: subjectId.value as any,
       bookVersionId: null
     });
     const resourceType = ref([] as any);
+    const audioPlayTypeList = ref([] as any);
 
-    const onSearch = () => {
-      emit('search', forms);
+    const onSearch = (type?: string) => {
+      emit(
+        'search',
+        {
+          ...forms,
+          subjectId: forms.audioPlayTypes !== 'SING' ? forms.subjectId : null,
+          audioPlayTypes: forms.audioPlayTypes
+            ? forms.audioPlayTypes === 'PLAY_SING'
+              ? ['PLAY', 'SING']
+              : [forms.audioPlayTypes]
+            : []
+        },
+        type
+      );
     };
 
     const throttleFn = useThrottleFn(() => onSearch(), 500);
@@ -64,7 +85,28 @@ export default defineComponent({
       });
       return obj;
     };
+
+    /** 默认选中第一个声部 */
+    const formatFirstSubject = () => {
+      const tempSubjects = catchStore.getSubjectInstrumentOnly;
+      if (tempSubjects.length > 0) {
+        const firstSubject = tempSubjects[0];
+        if (firstSubject.instruments && firstSubject.instruments.length > 1) {
+          forms.subjectId = firstSubject.instruments[0]?.value;
+        } else {
+          forms.subjectId = firstSubject.value;
+        }
+      }
+    };
     onMounted(async () => {
+      // 场景
+      const tempAudio = Object.keys(audioPlayType).map(key => {
+        return {
+          value: key,
+          name: audioPlayType[key]
+        };
+      });
+      audioPlayTypeList.value = [{ name: '全部', value: '' }, ...tempAudio];
       resourceTypeArray.forEach((item: any) => {
         resourceType.value.push(item);
       });
@@ -73,64 +115,109 @@ export default defineComponent({
       await catchStore.getMusicSheetCategory();
       // 获取声部
       await catchStore.getSubjects();
+
+      if (!props.subjectId) {
+        formatFirstSubject();
+      }
+
       catchStore.getSubjectInstruments.forEach((item: any) => {
-        if (item.id == props.subjectId) {
-          if (item.instruments.length > 0) {
-            forms.subjectId = item.instruments[0].value;
-          } else {
+        if (item.instruments?.length > 0) {
+          item.instruments.forEach((child: any) => {
+            if (child.id == props.subjectId) {
+              forms.subjectId = child.value;
+            }
+          });
+        } else {
+          if (item.id == props.subjectId) {
             forms.subjectId = item.value;
           }
         }
       });
+      onSearch('timer');
     });
     return () => (
       <div class={styles.searchGroup}>
         <NForm labelAlign="left" labelPlacement="left">
-          <NFormItem label="乐器:">
-            <NSpace
-              class={[
-                styles.spaceSection,
-                styles.spaceSection2,
-                'spaceSectionBox'
-              ]}>
-              {catchStore.getSubjectInstruments.map((subject: any) =>
-                subject.instruments && subject.instruments.length > 1 ? (
-                  <NPopselect
-                    options={subject.instruments}
-                    trigger="hover"
-                    scrollable
-                    v-model:value={forms.subjectId}
-                    onUpdate:value={() => {
-                      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>
-                ) : (
+          {props.type !== 'myResources' && (
+            <NFormItem label="场景:">
+              <NSpace
+                class={[
+                  styles.spaceSection,
+                  styles.spaceSection2,
+                  'spaceSectionBox'
+                ]}>
+                {audioPlayTypeList.value.map((subject: any) => (
                   <span
                     class={[
                       styles.textBtn,
-                      forms.subjectId === subject.value && styles.textBtnActive
+
+                      forms.audioPlayTypes === subject.value &&
+                        styles.textBtnActive
                     ]}
                     onClick={() => {
-                      forms.subjectId = subject.value;
+                      forms.audioPlayTypes = subject.value;
+                      // if (subject.value === 'SING') {
+                      //   forms.subjectId = null;
+                      // } else {
+                      //   formatFirstSubject();
+                      // }
                       onSearch();
                     }}>
                     {subject.name}
                   </span>
-                )
-              )}
-            </NSpace>
-          </NFormItem>
+                ))}
+              </NSpace>
+            </NFormItem>
+          )}
+          {forms.audioPlayTypes !== 'SING' && (
+            <NFormItem label="乐器:">
+              <NSpace
+                class={[
+                  styles.spaceSection,
+                  styles.spaceSection2,
+                  'spaceSectionBox'
+                ]}>
+                {catchStore.getSubjectInstrumentOnly.map((subject: any) =>
+                  subject.instruments && subject.instruments.length > 1 ? (
+                    <NPopselect
+                      options={subject.instruments}
+                      trigger="hover"
+                      scrollable
+                      v-model:value={forms.subjectId}
+                      onUpdate:value={() => {
+                        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;
+                        onSearch();
+                      }}>
+                      {subject.name}
+                    </span>
+                  )
+                )}
+              </NSpace>
+            </NFormItem>
+          )}
 
           <TheSearch
             class={styles.inputSearch}

+ 28 - 7
src/views/prepare-lessons/model/select-resources/select-item/index.tsx

@@ -48,6 +48,10 @@ export default defineComponent({
     from: {
       type: String,
       default: ''
+    },
+    instrumentId: {
+      type: String,
+      default: ''
     }
   },
   setup(props) {
@@ -70,6 +74,7 @@ export default defineComponent({
         name: '',
         bookVersionId: null,
         subjectId: null,
+        audioPlayTypes: props.type === 'myResources' ? ['PLAY'] : [],
         sourceType: formatType(type.value),
         musicalInstrumentId: null as any,
         enableFlag: true
@@ -106,6 +111,9 @@ export default defineComponent({
             isCollect: !!row.favoriteFlag,
             isSelected: row.sourceFrom === 'PLATFORM' ? true : false,
             refFlag: row.refFlag,
+            audioPlayTypeArray: row.audioPlayTypes
+              ? row.audioPlayTypes.split(',')
+              : [],
             containAccompaniment: row.containAccompaniment,
             content: row.content
           });
@@ -131,7 +139,7 @@ export default defineComponent({
     };
     const throttledFnSearch = useDebounceFn(item => {
       onSearch(item);
-    }, 500);
+    }, 300);
 
     // 添加资源
     const onAdd = async (item: any) => {
@@ -208,9 +216,9 @@ export default defineComponent({
         }
       );
 
-      if (props.type !== 'shareResources' || props.from === 'class') {
-        getList();
-      }
+      // if (props.type !== 'shareResources' || props.from === 'class') {
+      //   getList();
+      // }
 
       if (props.type === 'relateResources') {
         eventGlobal.on('onCoursewareUpdate', onUpdate);
@@ -258,9 +266,18 @@ export default defineComponent({
           <div class={className2}>
             {props.from === 'class' ? (
               <ClassSearchGroup
+                from={props.from}
                 type={props.type}
-                subjectId={prepareStore.getSubjectId as any}
-                onSearch={(item: any) => throttledFnSearch(item)}
+                subjectId={
+                  (prepareStore.getSubjectId as any) || props.instrumentId
+                }
+                onSearch={(item: any, type: any) => {
+                  if (type) {
+                    onSearch(item);
+                    return;
+                  }
+                  throttledFnSearch(item);
+                }}
               />
             ) : (
               <ResourceSearchGroup
@@ -302,7 +319,11 @@ export default defineComponent({
                           onClick={() => {
                             if (item.type === 'IMG') return;
                             state.show = true;
-                            state.item = item;
+                            state.item = {
+                              instrumentId:
+                                state.searchGroup.musicalInstrumentId,
+                              ...item
+                            };
                           }}
                         />
                       </div>

+ 102 - 50
src/views/prepare-lessons/model/select-resources/select-item/resource-search-group/index.tsx

@@ -23,6 +23,7 @@ import { useCatchStore } from '/src/store/modules/catchData';
 import { useThrottleFn } from '@vueuse/core';
 import TheSearch from '/src/components/TheSearch';
 import isCollaose from '/src/views/natural-resources/images/isCollaose.png';
+import { audioPlayType } from '/src/utils/contants';
 
 const ChildNodeSearch = defineComponent({
   name: 'ChildNodeSearch',
@@ -129,6 +130,7 @@ export default defineComponent({
       name: '',
       subjectId: subjectId.value as any,
       // grade: null as any,
+      audioPlayTypes: props.type == 'myResources' ? 'PLAY' : '',
       bookVersionId: null as any
       // musicSheetCategoriesId: null as any
     });
@@ -146,12 +148,19 @@ export default defineComponent({
     });
 
     const resourceType = ref([] as any);
+    const audioPlayTypeList = ref([] as any);
 
     const onSearch = (type?: string) => {
       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
         },
         type
@@ -259,7 +268,29 @@ export default defineComponent({
       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;
+        }
+      }
+    };
+
     onMounted(async () => {
+      // 场景
+      const tempAudio = Object.keys(audioPlayType).map(key => {
+        return {
+          value: key,
+          name: audioPlayType[key]
+        };
+      });
+      audioPlayTypeList.value = [{ name: '全部', value: '' }, ...tempAudio];
       resourceTypeArray.forEach((item: any) => {
         resourceType.value.push(item);
       });
@@ -282,9 +313,8 @@ export default defineComponent({
         getLive();
       }
 
-      if (props.type === 'shareResources') {
-        onSearch('timer');
-      }
+      formatFirstSubject();
+      onSearch('timer');
     });
     return () => (
       <div class={styles.searchGroup}>
@@ -303,6 +333,10 @@ export default defineComponent({
                   data.tagActiveId = '';
                   data.childSelectId = null;
                   data.selectParents = {};
+                  forms.audioPlayTypes =
+                    props.type === 'myResources' ? 'PLAY' : '';
+
+                  formatFirstSubject();
                   onSearch();
 
                   try {
@@ -368,63 +402,81 @@ export default defineComponent({
             </>
           )}
 
-          <NFormItem label="乐器:">
-            <NSpace class={styles.spaceSection2}>
-              {/* {catchStore.getSubjectAllList.map((music: any) => (
-                <NButton
-                  secondary={forms.subjectId === music.id}
-                  quaternary={forms.subjectId !== music.id}
-                  strong
-                  focusable={false}
-                  type={forms.subjectId === music.id ? 'primary' : 'default'}
-                  onClick={() => {
-                    forms.subjectId = music.id;
-                    onSearch();
-                  }}>
-                  {music.name}
-                </NButton>
-              ))} */}
-              {catchStore.getSubjectInstruments.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>
-                ) : (
+          {props.type !== 'myResources' && forms.type === 'MUSIC' && (
+            <NFormItem label="场景:">
+              <NSpace class={styles.spaceSection}>
+                {audioPlayTypeList.value.map((subject: any) => (
                   <span
                     class={[
                       styles.textBtn,
 
-                      forms.subjectId === subject.value && styles.textBtnActive
+                      forms.audioPlayTypes === subject.value &&
+                        styles.textBtnActive
                     ]}
                     onClick={() => {
-                      forms.subjectId = subject.value;
-                      state.tempSubjectId = null;
+                      forms.audioPlayTypes = subject.value;
+                      // if (subject.value === 'SING') {
+                      //   state.tempSubjectId = null;
+                      //   forms.subjectId = null;
+                      // } else {
+                      //   formatFirstSubject();
+                      // }
                       onSearch();
                     }}>
                     {subject.name}
                   </span>
-                )
-              )}
-            </NSpace>
-          </NFormItem>
+                ))}
+              </NSpace>
+            </NFormItem>
+          )}
+
+          {forms.audioPlayTypes !== 'SING' && (
+            <NFormItem label="乐器:">
+              <NSpace class={styles.spaceSection2}>
+                {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>
       </div>
     );

+ 182 - 202
src/views/prepare-lessons/model/subject-sync/index.tsx

@@ -1,202 +1,182 @@
-import { defineComponent, onMounted, ref } from 'vue';
-import styles from './index.module.less';
-import {
-  NButton,
-  NScrollbar,
-  NSpace,
-  NTabPane,
-  NTabs,
-  useMessage
-} from 'naive-ui';
-import { useCatchStore } from '/src/store/modules/catchData';
-import iconSelect from '../../images/icon-select.png';
-import { usePrepareStore } from '/src/store/modules/prepareLessons';
-import { PageEnum } from '/src/enums/pageEnum';
-
-export default defineComponent({
-  name: 'subject-sync',
-  props: {
-    subjectId: {
-      type: [String, Number],
-      default: ''
-    }
-  },
-  emits: ['close', 'confirm'],
-  setup(props, { emit }) {
-    const catchStore = useCatchStore();
-    const prepareStore = usePrepareStore();
-    const tabId = ref('' as any);
-    const message = useMessage();
-    const selectSubjectIds = ref([] as any);
-    const subjectList = ref([] as any);
-
-    const subjectImgs = {
-      Panpipes: 'https://oss.dayaedu.com/ktqy/17103860536976fd4a751.png',
-      // Ocarina: 'https://oss.dayaedu.com/ktqy/171038605369851874b22.png',
-      Ocarina: 'https://oss.dayaedu.com/ktqy/17143623857205dba41a5.png',
-      Whistling: 'https://oss.dayaedu.com/ktqy/1714362351692fcf8c0b8.png',
-      Woodwind: 'https://oss.dayaedu.com/ktqy/17103860536966826c50d.png',
-      'Tenor Recorder':
-        'https://oss.dayaedu.com/ktqy/17103860536950592e357.png',
-      Nai: 'https://oss.dayaedu.com/ktqy/1710386053697af4aa985.png',
-      'Baroque Recorder':
-        'https://oss.dayaedu.com/ktqy/1710386053698031e847a.png'
-    } as any;
-    /*
-      https://oss.dayaedu.com/ktqy/17103860536950592e357.png
-      https://oss.dayaedu.com/ktqy/17103860536966826c50d.png
-      https://oss.dayaedu.com/ktqy/1710386053697af4aa985.png
-      https://oss.dayaedu.com/ktqy/17103860536976fd4a751.png
-      https://oss.dayaedu.com/ktqy/171038605369851874b22.png
-      https://oss.dayaedu.com/ktqy/1710386053698031e847a.png
-    */
-    const onSubmit = () => {
-      if (selectSubjectIds.value.length <= 0) {
-        message.error('至少选择一个声部进行同步');
-        return;
-      }
-
-      const subjectCode: any[] = [];
-      // subjectList.value.forEach((subject: any) => {
-      //   if (selectSubjectIds.value.includes(subject.id)) {
-      //     subjectCode.push({
-      //       materialId: subject.id,
-      //       coverImg: subjectImgs[subject.code] || subjectImgs.Panpipes,
-      //       dataJson: null,
-      //       title: subject.name,
-      //       isCollect: false,
-      //       isSelected: false,
-      //       content: subject.code
-      //     });
-      //   }
-      // });
-      selectSubjectIds.value.forEach((id: any) => {
-        const item = subjectList.value.find(
-          (subject: any) => subject.id === id
-        );
-        console.log(item, 'item');
-        if (item) {
-          subjectCode.push({
-            materialId: item.id,
-            coverImg: subjectImgs[item.code] || subjectImgs.Panpipes,
-            dataJson: null,
-            title: item.name,
-            isCollect: false,
-            isSelected: false,
-            content: item.code
-          });
-        }
-      });
-      emit('confirm', { subjectIds: selectSubjectIds.value, subjectCode });
-    };
-
-    const formatSubjectList = () => {
-      const subjects = catchStore.getEnableSubjects;
-      const temp: any = [];
-      subjects.forEach((subject: any) => {
-        if (tabId.value === '' && subject.instruments) {
-          temp.push(...subject.instruments);
-        } else if (
-          tabId.value &&
-          subject.instruments &&
-          Number(tabId.value) === subject.id
-        ) {
-          temp.push(...subject.instruments);
-        }
-      });
-
-      subjectList.value = temp;
-    };
-    onMounted(async () => {
-      // 获取教材分类列表
-      // await catchStore.getMusicInstrument();
-      // subjectList.value = catchStore.getMusicInstruments;
-      await catchStore.getSubjects();
-
-      formatSubjectList();
-      // const teachingSubjectList = prepareStore.getSubjectList; // 教材自带声部;
-      // const tempSubjectList: any = [];
-      // baseAllSubjectList.forEach((subject: any) => {
-      //   const index = teachingSubjectList.findIndex(
-      //     (t: any) => t.id == subject.id
-      //   );
-      //   if (index != -1) {
-      //     tempSubjectList.push(subject);
-      //   }
-      // });
-
-      // subjectList.value = tempSubjectList;
-      if (props.subjectId) {
-        selectSubjectIds.value = [Number(props.subjectId)];
-      }
-    });
-    return () => (
-      <div class={styles.subjectSync}>
-        {/* <div class={styles.tips}>
-          请选择当前课件可使用的乐器
-          <span>(勾选后则对应乐器下的课件内容将被当前课件内容全部替换)</span>
-        </div> */}
-
-        <NTabs
-          defaultValue=""
-          paneClass={styles.paneTitle}
-          justifyContent="start"
-          paneWrapperClass={styles.paneWrapperContainer}
-          value={tabId.value}
-          onUpdate:value={(val: any) => {
-            tabId.value = val;
-            formatSubjectList();
-          }}>
-          {[{ name: '全部声部', id: '' }, ...catchStore.getEnableSubjects].map(
-            (item: any) => (
-              <NTabPane
-                name={`${item.id}`}
-                tab={item.name}
-                displayDirective="if"></NTabPane>
-            )
-          )}
-        </NTabs>
-        <NScrollbar style={{ maxHeight: '50vh', minHeight: '50vh' }}>
-          <div class={styles.subjectList}>
-            {subjectList.value.map((subject: any) => (
-              <div
-                class={[
-                  styles.subjectItem,
-                  selectSubjectIds.value.includes(subject.id)
-                    ? styles.subjectSelect
-                    : ''
-                ]}
-                onClick={() => {
-                  if (selectSubjectIds.value.includes(subject.id)) {
-                    const index = selectSubjectIds.value.indexOf(subject.id);
-                    selectSubjectIds.value.splice(index, 1);
-                  } else {
-                    selectSubjectIds.value.push(subject.id);
-                  }
-                }}>
-                <div class={styles.imgSection}>
-                  <img src={subject.img} />
-
-                  {selectSubjectIds.value.includes(subject.id) && (
-                    <img src={iconSelect} class={styles.iconSelect} />
-                  )}
-                </div>
-
-                <p class={styles.subjectName}>{subject.name}</p>
-              </div>
-            ))}
-          </div>
-        </NScrollbar>
-
-        <NSpace class={styles.btnGroupModal} justify="center">
-          <NButton round onClick={() => emit('close')}>
-            取消
-          </NButton>
-          <NButton round type="primary" onClick={onSubmit}>
-            确定
-          </NButton>
-        </NSpace>
-      </div>
-    );
-  }
-});
+import { defineComponent, onMounted, ref } from 'vue';
+import styles from './index.module.less';
+import {
+  NButton,
+  NScrollbar,
+  NSpace,
+  NTabPane,
+  NTabs,
+  useMessage
+} from 'naive-ui';
+import { useCatchStore } from '/src/store/modules/catchData';
+import iconSelect from '../../images/icon-select.png';
+import { usePrepareStore } from '/src/store/modules/prepareLessons';
+import { PageEnum } from '/src/enums/pageEnum';
+
+export default defineComponent({
+  name: 'subject-sync',
+  props: {
+    subjectId: {
+      type: [String, Number],
+      default: ''
+    }
+  },
+  emits: ['close', 'confirm'],
+  setup(props, { emit }) {
+    const catchStore = useCatchStore();
+    const prepareStore = usePrepareStore();
+    const tabId = ref('' as any);
+    const message = useMessage();
+    const selectSubjectIds = ref([] as any);
+    const subjectList = ref([] as any);
+
+    const subjectImgs = {
+      Panpipes: 'https://oss.dayaedu.com/ktqy/17103860536976fd4a751.png',
+      // Ocarina: 'https://oss.dayaedu.com/ktqy/171038605369851874b22.png',
+
+      Ocarina: 'https://oss.dayaedu.com/ktqy/17143623857205dba41a5.png',
+      'Alto Ocarina': 'https://oss.dayaedu.com/ktqy/17143623857205dba41a5.png',
+
+      Whistling: 'https://oss.dayaedu.com/ktqy/1714362351692fcf8c0b8.png',
+      'Soprano Ocarina':
+        'https://oss.dayaedu.com/ktqy/1714362351692fcf8c0b8.png',
+
+      Woodwind: 'https://oss.dayaedu.com/ktqy/17103860536966826c50d.png',
+      Hulusi: 'https://oss.dayaedu.com/ktqy/17103860536966826c50d.png',
+
+      'Tenor Recorder':
+        'https://oss.dayaedu.com/ktqy/17103860536950592e357.png',
+      'German Recorder':
+        'https://oss.dayaedu.com/ktqy/17103860536950592e357.png',
+
+      Nai: 'https://oss.dayaedu.com/ktqy/1710386053697af4aa985.png',
+      Melodica: 'https://oss.dayaedu.com/ktqy/1710386053697af4aa985.png',
+
+      'Baroque Recorder':
+        'https://oss.dayaedu.com/ktqy/1710386053698031e847a.png'
+    } as any;
+    const onSubmit = () => {
+      if (selectSubjectIds.value.length <= 0) {
+        message.error('至少选择一个声部进行同步');
+        return;
+      }
+
+      const subjectCode: any[] = [];
+      selectSubjectIds.value.forEach((id: any) => {
+        const item = subjectList.value.find(
+          (subject: any) => subject.id === id
+        );
+        console.log(item, 'item', item.code);
+
+        if (item) {
+          const tempCode = item.code ? item.code.split(',')[0] : '';
+          subjectCode.push({
+            materialId: item.id,
+            coverImg: subjectImgs[tempCode] || subjectImgs.Panpipes,
+            dataJson: null,
+            title: item.name,
+            isCollect: false,
+            isSelected: false,
+            content: item.code
+          });
+        }
+      });
+      emit('confirm', { subjectIds: selectSubjectIds.value, subjectCode });
+    };
+
+    const formatSubjectList = () => {
+      const subjects = catchStore.getEnableSubjects;
+      const temp: any = [];
+      subjects.forEach((subject: any) => {
+        if (tabId.value === '' && subject.instruments) {
+          temp.push(...subject.instruments);
+        } else if (
+          tabId.value &&
+          subject.instruments &&
+          Number(tabId.value) === subject.id
+        ) {
+          temp.push(...subject.instruments);
+        }
+      });
+
+      subjectList.value = temp;
+    };
+    onMounted(async () => {
+      // 获取教材分类列表
+      await catchStore.getSubjects();
+
+      formatSubjectList();
+      if (props.subjectId) {
+        selectSubjectIds.value = [Number(props.subjectId)];
+      }
+    });
+    return () => (
+      <div class={styles.subjectSync}>
+        {/* <div class={styles.tips}>
+          请选择当前课件可使用的乐器
+          <span>(勾选后则对应乐器下的课件内容将被当前课件内容全部替换)</span>
+        </div> */}
+
+        <NTabs
+          defaultValue=""
+          paneClass={styles.paneTitle}
+          justifyContent="start"
+          paneWrapperClass={styles.paneWrapperContainer}
+          value={tabId.value}
+          onUpdate:value={(val: any) => {
+            tabId.value = val;
+            formatSubjectList();
+          }}>
+          {[{ name: '全部声部', id: '' }, ...catchStore.getEnableSubjects].map(
+            (item: any) => (
+              <NTabPane
+                name={`${item.id}`}
+                tab={item.name}
+                displayDirective="if"></NTabPane>
+            )
+          )}
+        </NTabs>
+        <NScrollbar style={{ maxHeight: '50vh', minHeight: '50vh' }}>
+          <div class={styles.subjectList}>
+            {subjectList.value.map((subject: any) => (
+              <div
+                class={[
+                  styles.subjectItem,
+                  selectSubjectIds.value.includes(subject.id)
+                    ? styles.subjectSelect
+                    : ''
+                ]}
+                onClick={() => {
+                  if (selectSubjectIds.value.includes(subject.id)) {
+                    const index = selectSubjectIds.value.indexOf(subject.id);
+                    selectSubjectIds.value.splice(index, 1);
+                  } else {
+                    selectSubjectIds.value.push(subject.id);
+                  }
+                }}>
+                <div class={styles.imgSection}>
+                  <img src={subject.img} />
+
+                  {selectSubjectIds.value.includes(subject.id) && (
+                    <img src={iconSelect} class={styles.iconSelect} />
+                  )}
+                </div>
+
+                <p class={styles.subjectName}>{subject.name}</p>
+              </div>
+            ))}
+          </div>
+        </NScrollbar>
+
+        <NSpace class={styles.btnGroupModal} justify="center">
+          <NButton round onClick={() => emit('close')}>
+            取消
+          </NButton>
+          <NButton round type="primary" onClick={onSubmit}>
+            确定
+          </NButton>
+        </NSpace>
+      </div>
+    );
+  }
+});

+ 64 - 3
src/views/xiaoku-music/index.module.less

@@ -183,6 +183,37 @@
   }
 }
 
+.searchSection {
+  position: sticky;
+  top: 0;
+  left: 0;
+  z-index: 9;
+
+  padding: 24px;
+  background-color: #fff;
+
+  display: flex;
+  align-items: center;
+
+  :global {
+    .TheSearch {
+      background: #F5F6FA;
+      --n-color-focus: #F5F6FA !important;
+    }
+
+    .nBaseCascaser {
+      border-radius: 100px;
+      width: 170px;
+      background: #F5F6FA;
+      margin-right: 16px;
+
+      .n-base-selection__border {
+        border-color: #F5F6FA;
+      }
+    }
+  }
+}
+
 .itemContainer {
   width: 100%;
   border-radius: 16px;
@@ -273,6 +304,36 @@
       white-space: nowrap;
       text-overflow: ellipsis;
       overflow: hidden;
+      padding: 3px 0;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+
+      .composer {
+        // padding-top: 2px;
+      }
+    }
+
+    .iconType {
+      background: #fff;
+      border-radius: 3px;
+      padding: 1px 3px;
+      font-size: max(12px, 9Px);
+      text-align: center;
+      font-weight: 400;
+      line-height: 1;
+      border: 1px solid transparent;
+      margin-right: 5px;
+    }
+
+    .iconPlay {
+      border: 1px solid #15B2FD;
+      color: #00ADFF;
+    }
+
+    .iconSing {
+      border: 1px solid #CD8613;
+      color: #CE8208;
     }
   }
 
@@ -444,8 +505,8 @@
 
   .previewClose {
     position: absolute;
-    left: 40px;
-    top: 40px;
+    right: -80px;
+    top: 0px;
     width: 60px;
     height: 65px;
   }
@@ -532,4 +593,4 @@
       margin-top: 0;
     }
   }
-}
+}

+ 223 - 68
src/views/xiaoku-music/index.tsx

@@ -28,8 +28,8 @@ import {
 import TheSearch from '/src/components/TheSearch';
 import { IMusicItem } from './type';
 import icon_arrow from './images/icon_arrow.png';
-import icon_play from './images/icon_play.png';
-import icon_pause from './images/icon_pause.png';
+// import icon_play from './images/icon_play.png';
+// import icon_pause from './images/icon_pause.png';
 import icon_goXiaoku from './images/icon_goXiaoku.png';
 import icon_favitor from '/src/common/images/icon-collect-default.png';
 import icon_favitorActive from '/src/common/images/icon-collect-active.png';
@@ -44,8 +44,8 @@ import { useCatchStore } from '/src/store/modules/catchData';
 import {
   api_materialFavorite,
   api_materialFavoriteStatus,
-  api_musicSheetPage,
-  api_subjectList
+  api_musicSheetPage
+  // api_subjectList
 } from '../xiaoku-ai/api';
 import { useUserStore } from '/src/store/modules/users';
 import Musicguide from '@/custom-plugins/guide-page/music-guide';
@@ -53,7 +53,9 @@ import TheEmpty from '/src/components/TheEmpty';
 import { modalClickMask, state } from '/src/state';
 import { useResizeObserver } from '@vueuse/core';
 import { vaildMusicScoreUrl } from '/src/utils/urlUtils';
-import { getInstrumentName, sortMusical, trackToCode } from '/src/utils';
+import { getInstrumentName, sortMusical } from '/src/utils';
+import { audioPlayType } from '/src/utils/contants';
+import CCascader from '/src/components/CCascader';
 
 export default defineComponent({
   name: 'XiaokuMusic',
@@ -67,6 +69,7 @@ export default defineComponent({
       rows: 20,
       status: true,
       name: '', // 关键词
+      audioPlayTypes: '',
       musicSheetCategoriesId: route.query.id || ''
     });
     const data = reactive({
@@ -75,6 +78,8 @@ export default defineComponent({
       reshing: false,
       tags: [] as any[],
       tagIndex: 0,
+      musicalInstrumentId: '',
+      musicSubject: '',
       list: [] as unknown as IMusicItem[],
       listActive: 0,
       musicInstrumentIndex: 0,
@@ -84,31 +89,54 @@ export default defineComponent({
       showPreivew: false,
       previewUrl: '',
       showCloseBtn: true,
+      audioPlayTypeList: [] as any,
       iframeSrc: '',
       showMusicImg: 'staff' as 'staff' | 'first' | 'fixed', // 显示哪种曲谱
       trackList: [] as any, // 可筛选的分轨信息
       showTransBtn: true, // 是否显示转谱按钮
-      trackName: '切换声' as any // 分轨名字
+      trackName: '切换声' as any // 分轨名字
     });
+    const subjects = ref('');
     const showGuide = ref(false);
     const userStore = useUserStore();
     let musicsrc = '';
+    const formatParentCurrentValue = (list: any) => {
+      for (const item of list) {
+        if (item.instruments && item.instruments.length > 0) {
+          item.instruments.forEach((child: any) => {
+            child.columnName = '乐器';
+          });
+          item.children = item.instruments;
+          formatParentCurrentValue(item.instruments);
+        }
+      }
+    };
     const getSubjects = async () => {
       // const res = await api_subjectList();
       // if (Array.isArray(res?.data)) {
-      const tempSubjectList = catchStore.getSubjectInstruments;
+      const tempSubjectList = catchStore.getSubjectList;
       const subjectList = sessionStorage.getItem('musicSubjectList')
         ? JSON.parse(sessionStorage.getItem('musicSubjectList') as any)
         : [];
       const resultList: any[] = [];
+      console.log(tempSubjectList, subjectList, 'subjectList');
       tempSubjectList.forEach((item: any) => {
         const hasItem = subjectList.find((s: any) => s.id === item.id);
         if (hasItem) {
           resultList.push(item);
         }
       });
+      // data.tags = [
+      //   { name: '全部', id: 0, value: 0, label: '全部' },
+      //   ...resultList
+      // ];
+      formatParentCurrentValue(resultList);
       data.tags = [
-        { name: '全部', id: 0, value: 0, label: '全部' },
+        {
+          columnName: '声部',
+          name: '全部声部',
+          id: ''
+        },
         ...resultList
       ];
       // }
@@ -117,10 +145,16 @@ export default defineComponent({
       data.loading = true;
       let res = {} as any;
       try {
+        const { audioPlayTypes, ...result } = forms;
         res = await api_musicSheetPage({
-          ...forms,
-          // musicSubject: data.tagIndex ? data.tagIndex : ''
-          musicalInstrumentId: data.tagIndex ? data.tagIndex : ''
+          ...result,
+          audioPlayTypes: audioPlayTypes
+            ? audioPlayTypes === 'PLAY_SING'
+              ? ['PLAY', 'SING']
+              : [audioPlayTypes]
+            : [],
+          musicSubject: data.musicSubject,
+          musicalInstrumentId: data.musicalInstrumentId
         });
       } catch (error) {
         console.log(error);
@@ -133,8 +167,21 @@ export default defineComponent({
       }
 
       if (res?.code === 200 && Array.isArray(res?.data?.rows)) {
+        console.log(res?.data?.rows);
+        const tempResult = res?.data?.rows || [];
+        tempResult.forEach((item: any) => {
+          item.audioPlayTypeArray = item.audioPlayTypes
+            ? item.audioPlayTypes.split(',')
+            : [];
+        });
         data.list = [...data.list, ...res.data.rows];
         data.finshed = res.data.rows.length < forms.rows;
+
+        // 是否显示总谱
+        const selectMusic = data.list[data.listActive];
+        if (selectMusic && selectMusic.isScoreRender && data.listActive === 0) {
+          data.musicInstrumentIndex = 999;
+        }
       } else {
         data.finshed = true;
       }
@@ -170,6 +217,15 @@ export default defineComponent({
     };
 
     onMounted(async () => {
+      // 场景
+      const tempAudio = Object.keys(audioPlayType).map(key => {
+        return {
+          value: key,
+          label: audioPlayType[key]
+        };
+      });
+      data.audioPlayTypeList = [{ label: '全部', value: '' }, ...tempAudio];
+
       // 获取声部列表
       await catchStore.getSubjects();
       // musicList-container
@@ -195,6 +251,8 @@ export default defineComponent({
       });
       obv.observe(spinRef.value);
       analyzeXml();
+
+      musicIframeLoad();
       window.addEventListener('message', iframeHandle);
     });
     onUnmounted(() => {
@@ -288,7 +346,7 @@ export default defineComponent({
       return temp;
     });
 
-    // 根据musicSheetType返回的值,判断是否显示切换声按钮
+    // 根据musicSheetType返回的值,判断是否显示切换声按钮
     const isEnsemble = computed(() => {
       // const details: any = data.list[data.listActive];
       // const musics: any = details?.musicalInstruments;
@@ -348,6 +406,8 @@ export default defineComponent({
       }&modelType=practise&modeType=json&Authorization=${token}&isPreView=true&part-index=${
         data.musicInstrumentIndex
       }&musicRenderType=${musicRenderType}`;
+
+      console.log(data.iframeSrc, 'iframeSrc');
     };
 
     /** 音频控制 */
@@ -399,20 +459,6 @@ export default defineComponent({
       }
       return action;
     });
-    // const _actions = [
-    //   {
-    //     value: 'staff',
-    //     label: '五线谱'
-    //   },
-    //   {
-    //     value: 'first',
-    //     label: '首调'
-    //   },
-    //   {
-    //     value: 'fixed',
-    //     label: '固定调'
-    //   }
-    // ];
 
     // 解析xml,获取分轨信息
     const analyzeXml = async () => {
@@ -517,6 +563,20 @@ export default defineComponent({
         .filter((item: any) => item.canselect)
         .sort((a: any, b: any) => a.sortId - b.sortId);
       data.trackList = arr;
+
+      // 是否显示总谱
+      const selectMusic = data.list[data.listActive];
+      if (selectMusic) {
+        selectMusic.isScoreRender &&
+          data.trackList.unshift({
+            label: '总谱',
+            value: 999,
+            sortId: 0,
+            canselect: true,
+            track: 999
+          });
+      }
+
       // let track = arr.find(
       //   (item: any) => item.value === data.musicInstrumentIndex
       // )?.track;
@@ -563,25 +623,25 @@ export default defineComponent({
         analyzeXml();
       }
     );
-    watch(
-      () => data.musicInstrumentIndex,
-      async () => {
-        data.trackName =
-          data.trackList.find(
-            (item: any) => item.value === data.musicInstrumentIndex
-          )?.label || '切换声轨';
-        musicIframeLoad();
-      }
-    );
+    // watch(
+    //   () => data.musicInstrumentIndex,
+    //   async () => {
+    //     data.trackName =
+    //       data.trackList.find(
+    //         (item: any) => item.value === data.musicInstrumentIndex
+    //       )?.label || '切换声部';
+    //     musicIframeLoad();
+    //   }
+    // );
     // 合奏曲谱转换时,更新曲谱信息
-    watch(
-      () => data.showMusicImg,
-      () => {
-        if (isEnsemble.value) {
-          musicIframeLoad();
-        }
-      }
-    );
+    // watch(
+    //   () => data.showMusicImg,
+    //   () => {
+    //     if (isEnsemble.value) {
+    //       musicIframeLoad();
+    //     }
+    //   }
+    // );
 
     const musicImg = computed(() => {
       let imgs: any = [];
@@ -618,11 +678,39 @@ export default defineComponent({
         <div class={[styles.wrap, data.showPlayer ? styles.wrapBottom : '']}>
           <div class={styles.content}>
             <div class={styles.tools}>
-              <NSpace
-                style={{ width: '100%' }}
-                size={[24, 12]}
-                wrapItem={false}>
-                <div
+              <NSpace style={{ width: '100%' }} size={[12, 6]} wrapItem={false}>
+                {data.audioPlayTypeList.map((item: any) => (
+                  <NButton
+                    round
+                    textColor={
+                      forms.audioPlayTypes === item.value ? '#fff' : '#000'
+                    }
+                    color={
+                      forms.audioPlayTypes === item.value ? '#198CFE' : '#fff'
+                    }
+                    type={
+                      forms.audioPlayTypes === item.value
+                        ? 'primary'
+                        : 'default'
+                    }
+                    onClick={() => {
+                      forms.audioPlayTypes = item.value || '';
+                      if (item.value === 'SING') {
+                        data.musicalInstrumentId = '';
+                        data.musicSubject = '';
+                      }
+
+                      data.reshing = true;
+                      document
+                        .querySelector('.musicList-container')
+                        ?.scroll(0, 0);
+                      handleGetList();
+                    }}>
+                    {item.label}
+                  </NButton>
+                ))}
+
+                {/* <div
                   {...{
                     id: 'music-0'
                   }}>
@@ -642,7 +730,7 @@ export default defineComponent({
                             data.reshing = true;
                             document
                               .querySelector('.musicList-container')
-                              .scroll(0, 0);
+                              ?.scroll(0, 0);
                             handleGetList();
                           }}
                           key={item.value}
@@ -690,7 +778,7 @@ export default defineComponent({
                             data.reshing = true;
                             document
                               .querySelector('.musicList-container')
-                              .scroll(0, 0);
+                              ?.scroll(0, 0);
                             handleGetList();
                           }}>
                           {item.name}
@@ -698,22 +786,46 @@ export default defineComponent({
                       )
                     )}
                   </NSpace>
-                </div>
+                </div> */}
               </NSpace>
-              <TheSearch
-                style={{ marginLeft: 'auto' }}
-                round
-                border={false}
-                onSearch={val => {
-                  forms.name = val;
-                  data.reshing = true;
-                  handleGetList();
-                }}
-              />
             </div>
 
             <div class={styles.contentWrap}>
               <div class={[styles.musicList, 'musicList-container']}>
+                <div class={styles.searchSection}>
+                  {forms.audioPlayTypes !== 'SING' && (
+                    <CCascader
+                      placeholder="全部乐器"
+                      arrowType="small"
+                      childShowAllCheck={false}
+                      class={styles.instrumentSection}
+                      v-model:value={subjects.value}
+                      options={data.tags}
+                      onMoreId={(val: any) => {
+                        if (data.loading) return;
+                        data.musicalInstrumentId = val.childId;
+                        data.musicSubject = val.parentId;
+                        data.reshing = true;
+                        document
+                          .querySelector('.musicList-container')
+                          ?.scroll(0, 0);
+                        handleGetList();
+                      }}
+                    />
+                  )}
+
+                  <TheSearch
+                    style={{ marginLeft: 'auto' }}
+                    round
+                    border={false}
+                    onSearch={val => {
+                      if (data.loading) return;
+                      forms.name = val;
+                      data.reshing = true;
+                      handleGetList();
+                    }}
+                  />
+                </div>
                 <div class={[styles.wrapList, 'music-wrap-list']}>
                   {data.list.map((item: IMusicItem, index) => {
                     return (
@@ -723,8 +835,17 @@ export default defineComponent({
                             styles.item,
                             data.listActive === index && styles.active
                           ]}
-                          onClick={() => {
+                          onClick={async () => {
                             handleChange(item);
+                            await analyzeXml();
+                            // 是否显示总谱
+                            const selectMusic = data.list[data.listActive];
+                            console.log(selectMusic, 'selected music');
+                            if (selectMusic && selectMusic.isScoreRender) {
+                              data.musicInstrumentIndex = 999;
+                            } else {
+                              data.musicInstrumentIndex = 0;
+                            }
                             musicIframeLoad();
                           }}>
                           <div class={styles.img}>
@@ -750,9 +871,27 @@ export default defineComponent({
                             <div class={styles.titleName}>
                               <TheNoticeBar text={item.musicSheetName} />
                             </div>
-                            <div class={styles.titleDes}>{item.composer}</div>
+                            <div class={styles.titleDes}>
+                              {item.audioPlayTypeArray?.includes('PLAY') && (
+                                <span
+                                  class={[styles.iconType, styles.iconPlay]}>
+                                  演奏
+                                </span>
+                              )}
+
+                              {item.audioPlayTypeArray?.includes('SING') && (
+                                <span
+                                  class={[styles.iconType, styles.iconSing]}>
+                                  演唱
+                                </span>
+                              )}
+
+                              <span class={styles.composer}>
+                                {item.composer}
+                              </span>
+                            </div>
                           </div>
-                          {index == 0 ? (
+                          {/* {index == 0 ? (
                             <NButton
                               color="#259CFE"
                               textColor="#fff"
@@ -809,7 +948,7 @@ export default defineComponent({
                                 }
                               />
                             </NButton>
-                          )}
+                          )} */}
 
                           <img class={styles.arrow} src={icon_arrow} />
                         </div>
@@ -860,13 +999,17 @@ export default defineComponent({
                     } else if (data.showMusicImg === 'staff') {
                       lineType = 'staff';
                     }
-                    const src = `${vaildMusicScoreUrl()}/instrument?v=${+new Date()}&platform=pc&showGuide=true&id=${
+                    let src = `${vaildMusicScoreUrl()}/instrument?v=${+new Date()}&platform=pc&id=${
                       activeItem.value.id
                     }&Authorization=${
                       user.getToken
                     }&musicRenderType=${lineType}&showGuide=true&part-index=${
                       data.musicInstrumentIndex
                     }`;
+
+                    if (data.musicalInstrumentId) {
+                      src += '&instrumentId=' + data.musicalInstrumentId;
+                    }
                     if (
                       window.matchMedia('(display-mode: standalone)').matches
                     ) {
@@ -892,6 +1035,13 @@ export default defineComponent({
                       onUpdate:value={async (val: any) => {
                         await analyzeXml();
                         //
+
+                        data.trackName =
+                          data.trackList.find(
+                            (item: any) =>
+                              item.value === data.musicInstrumentIndex
+                          )?.label || '切换声部';
+                        musicIframeLoad();
                       }}
                       // key={item.id}
                       class={[styles.popSelect]}>
@@ -910,6 +1060,9 @@ export default defineComponent({
                       onUpdate:value={async (val: any) => {
                         data.showMusicImg = val;
                         // musicIframeLoad();
+                        if (isEnsemble.value) {
+                          musicIframeLoad();
+                        }
                       }}
                       // key={item.id}
                       class={[styles.popTrans]}>
@@ -938,7 +1091,9 @@ export default defineComponent({
                         // opacity: loading.value ? 0 : 1
                       }}
                       src={data.iframeSrc}
-                      onLoad={musicIframeLoad}></iframe>
+                      onLoad={() => {
+                        // musicIframeLoad();
+                      }}></iframe>
                   ) : (
                     <>
                       {/* <TransitionGroup name="van-fade"> */}

+ 2 - 0
src/views/xiaoku-music/type.ts

@@ -21,8 +21,10 @@ export interface IMusicItem {
   musicJianImg: string;
   musicSheetType: string;
   xmlFileUrl?: string;
+  isScoreRender?: boolean;
   multiTracksSelection?: string;
   musicalInstruments?: any[];
+  audioPlayTypeArray?: any[];
   scoreType: string;
   isConvertibleScore: boolean;
 }