Ver Fonte

Merge branch 'iteration-20240816-fire' into dev

lex há 10 meses atrás
pai
commit
05aa3652d9
68 ficheiros alterados com 3978 adições e 2978 exclusões
  1. 1 1
      dev-dist/sw.js
  2. BIN
      src/common/images/bg.png
  3. 35 18
      src/components/CCascader/index.tsx
  4. 1 1
      src/components/TheSearch/index.module.less
  5. 67 66
      src/components/card-preview/listen-modal/index.tsx
  6. 48 45
      src/components/card-preview/music-modal/index.tsx
  7. 5 3
      src/components/card-preview/song-modal/index.module.less
  8. 2 0
      src/components/card-preview/song-modal/index.tsx
  9. 5 3
      src/components/card-preview/video-modal/index.module.less
  10. 3 1
      src/components/card-preview/video-modal/index.tsx
  11. 3 3
      src/components/card-type/index.module.less
  12. 0 1
      src/components/card-type/index.tsx
  13. 26 5
      src/components/layout/index.module.less
  14. 20 9
      src/components/layout/layoutTop.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. 9 0
      src/utils/contants.ts
  19. 3 0
      src/views/attend-class/component/audio-pay.tsx
  20. 150 144
      src/views/attend-class/component/musicScore.tsx
  21. 49 28
      src/views/attend-class/index.tsx
  22. 2 2
      src/views/attend-class/model/train-type/index.module.less
  23. 503 372
      src/views/classList/components/testRecode.tsx
  24. 19 0
      src/views/classList/index.module.less
  25. 14 4
      src/views/home/index.tsx
  26. 209 203
      src/views/home/modals/class-modal/index.module.less
  27. 346 342
      src/views/home/modals/class-modal/index.tsx
  28. 110 112
      src/views/home/modals/subject-modal/index.tsx
  29. 7 2
      src/views/natural-resources/components/my-collect/index.tsx
  30. 46 25
      src/views/natural-resources/components/my-collect/search-group-resources.tsx
  31. 8 2
      src/views/natural-resources/components/my-resources/index.tsx
  32. 24 12
      src/views/natural-resources/components/my-resources/search-group-resources.tsx
  33. 11 2
      src/views/natural-resources/components/share-resources/index.tsx
  34. 44 25
      src/views/natural-resources/components/share-resources/search-group-resources.tsx
  35. 40 9
      src/views/prepare-lessons/components/directory-main/index.tsx
  36. 2 2
      src/views/prepare-lessons/components/directory-main/select-lessonware/index.module.less
  37. 28 25
      src/views/prepare-lessons/components/lesson-main/courseware-presets/index.tsx
  38. 30 1
      src/views/prepare-lessons/components/lesson-main/courseware/addCourseware.module.less
  39. 116 39
      src/views/prepare-lessons/components/lesson-main/courseware/addCourseware.tsx
  40. 108 154
      src/views/prepare-lessons/components/lesson-main/index.tsx
  41. 124 23
      src/views/prepare-lessons/components/resource-main/components/resource-item/index.tsx
  42. 1 0
      src/views/prepare-lessons/components/resource-main/components/resource-item/resource-search-group/index.tsx
  43. 5 1
      src/views/prepare-lessons/components/resource-main/components/select-music/index.tsx
  44. 1 1
      src/views/prepare-lessons/components/resource-main/components/select-music/resource-search-group/index.tsx
  45. 32 6
      src/views/prepare-lessons/components/resource-main/index.tsx
  46. 1 1
      src/views/prepare-lessons/index.tsx
  47. 7 3
      src/views/prepare-lessons/model/select-music/select-item/index.tsx
  48. 17 1
      src/views/prepare-lessons/model/select-music/select-item/search-group.tsx
  49. 32 4
      src/views/prepare-lessons/model/select-resources/index.tsx
  50. 47 17
      src/views/prepare-lessons/model/select-resources/select-item/class-search-group/index.tsx
  51. 28 7
      src/views/prepare-lessons/model/select-resources/select-item/index.tsx
  52. 186 32
      src/views/prepare-lessons/model/select-resources/select-item/resource-search-group/index.tsx
  53. 1 1
      src/views/prepare-lessons/model/source-rhythm/index.tsx
  54. 182 202
      src/views/prepare-lessons/model/subject-sync/index.tsx
  55. 13 7
      src/views/setting/components/personInfo.tsx
  56. 14 14
      src/views/setting/components/schoolInfo/index.module.less
  57. 16 6
      src/views/setting/components/schoolInfo/index.tsx
  58. 309 296
      src/views/setting/index.module.less
  59. 2 1
      src/views/setting/index.tsx
  60. 10 1
      src/views/xiaoku-ai/index.module.less
  61. 126 146
      src/views/xiaoku-ai/index.tsx
  62. BIN
      src/views/xiaoku-music/images/icon-collect-active.png
  63. BIN
      src/views/xiaoku-music/images/icon-collect-default.png
  64. BIN
      src/views/xiaoku-music/images/icon_trans_default.png
  65. 63 14
      src/views/xiaoku-music/index.module.less
  66. 106 31
      src/views/xiaoku-music/index.tsx
  67. 2 0
      src/views/xiaoku-music/type.ts
  68. 2 2
      vite.config.ts

+ 1 - 1
dev-dist/sw.js

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

BIN
src/common/images/bg.png


+ 35 - 18
src/components/CCascader/index.tsx

@@ -24,6 +24,11 @@ export default defineComponent({
       type: Boolean,
       default: false
     },
+    /** 子选项是否显示全部类型 */
+    childShowAllCheck: {
+      type: Boolean,
+      default: true
+    },
     value: {
       type: String,
       default: ''
@@ -87,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 {
@@ -146,7 +154,6 @@ export default defineComponent({
         });
       }
 
-      console.log(values, names, 'names', props.value);
       if (props.showPath) {
         return names.join(' / ');
       } else {
@@ -361,6 +368,7 @@ export default defineComponent({
                         ))}
                       </div>
                       <ChildNodeSearch
+                        childShowAllCheck={props.childShowAllCheck}
                         activeRow={state.selectParents}
                         onSelectChildTag={(val: any) => {
                           state.childSelectId = val;
@@ -391,6 +399,11 @@ export default defineComponent({
 const ChildNodeSearch = defineComponent({
   name: 'ChildNodeSearch',
   props: {
+    /** 子选项是否显示全部类型 */
+    childShowAllCheck: {
+      type: Boolean,
+      default: true
+    },
     activeRow: {
       type: Object,
       default: () => ({})
@@ -425,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 = {
@@ -441,6 +454,7 @@ const ChildNodeSearch = defineComponent({
                 activeIndex: subject.activeIndex || '',
                 children
               };
+              emit('selectChildTag', subject.activeIndex || '');
             }
           }
         });
@@ -473,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 - 1
src/components/TheSearch/index.module.less

@@ -16,7 +16,7 @@
 
     .n-button {
       height: 34px;
-      font-size: max(16px, 13Px);
+      font-size: max(16px, 13Px) !important;
       font-weight: 500;
       width: auto;
       opacity: 0.7;

+ 67 - 66
src/components/card-preview/listen-modal/index.tsx

@@ -1,66 +1,67 @@
-import { defineComponent, ref, watch } 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: () => ({})
-    },
-    activeStatus: {
-      type: Boolean,
-      default: false
-    }
-  },
-  emits: ['setIframe'],
-  setup(props, { emit }) {
-    const userStore = useUserStore();
-    const iframeRef = ref();
-    const isLoaded = ref(false);
-
-    const src = `${vaildMusicScoreUrl()}/instrument?v=${new Date().getTime()}/#/view-figner?Authorization=${
-      userStore.getToken
-    }&code=${props.item.content}&platform=pc&type=listenMode&linkSource=class`;
-    // if (/(localhost|192)/.test(location.host)) {
-    //   src = `http://localhost:3001/instrument.html#/view-figner?Authorization=${userStore.getToken}&code=${props.item.content}&platform=pc&type=listenMode`;
-    // }
-    // if (props.item.dataJson) {
-    //   src += '&dataJson=' + props.item.dataJson;
-    // }
-
-    watch(
-      () => props.activeStatus,
-      () => {
-        if (!props.activeStatus) {
-          iframeRef.value?.contentWindow?.postMessage(
-            {
-              api: 'setPlayState',
-              data: {
-                code: props.item.content
-              }
-            },
-            '*'
-          );
-        }
-      }
-    );
-    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, watch } 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: () => ({})
+    },
+    activeStatus: {
+      type: Boolean,
+      default: false
+    }
+  },
+  emits: ['setIframe'],
+  setup(props, { emit }) {
+    const userStore = useUserStore();
+    const iframeRef = ref();
+    const isLoaded = ref(false);
+
+    const src = `${vaildMusicScoreUrl()}/instrument?v=${new Date().getTime()}/#/view-figner?Authorization=${
+      userStore.getToken
+    }&code=${props.item.content}&platform=pc&type=listenMode&linkSource=class`;
+    // if (/(192)/.test(location.host)) {
+    //   src = `http://192.168.3.220:3000/instrument.html#/view-figner?Authorization=${userStore.getToken}&code=${props.item.content}&platform=pc&type=listenMode&linkSource=class`;
+    // }
+    // if (props.item.dataJson) {
+    //   src += '&dataJson=' + props.item.dataJson;
+    // }
+
+    console.log(src, 'src');
+    watch(
+      () => props.activeStatus,
+      () => {
+        if (!props.activeStatus) {
+          iframeRef.value?.contentWindow?.postMessage(
+            {
+              api: 'setPlayState',
+              data: {
+                code: props.item.content
+              }
+            },
+            '*'
+          );
+        }
+      }
+    );
+    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>
+    );
+  }
+});

+ 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>
+    );
+  }
+});

+ 5 - 3
src/components/card-preview/song-modal/index.module.less

@@ -44,8 +44,10 @@
   left: 0;
   right: 0;
   width: 100%;
-  background: rgba(0, 0, 0, 0.6);
-  backdrop-filter: blur(26px);
+  // background: rgba(0, 0, 0, 0.6);
+  // backdrop-filter: blur(26px);
+  background: url('../../../common/images/bg.png') no-repeat;
+  background-size: 100% 100%;
   height: 80px;
   padding: 0 24px 0 24px !important;
   transition: all 0.3s;
@@ -186,4 +188,4 @@
   margin-bottom: -80px;
   // transform: translateY(100%);
   transition: all .3s;
-}
+}

+ 2 - 0
src/components/card-preview/song-modal/index.tsx

@@ -250,6 +250,8 @@ export default defineComponent({
                 Math.floor(audio.value?.duration)
               );
               audioForms.durationNum = audio.value?.duration;
+
+              onToggleAudio();
             }}></audio>
 
           <canvas ref={canvas}></canvas>

+ 5 - 3
src/components/card-preview/video-modal/index.module.less

@@ -46,8 +46,10 @@
     left: 0;
     right: 0;
     width: 100%;
-    background: rgba(0, 0, 0, 0.6);
-    backdrop-filter: blur(26px);
+    // background: rgba(0, 0, 0, 0.6);
+    background: url('../../../common/images/bg.png') no-repeat;
+    background-size: 100% 100%;
+    // backdrop-filter: blur(26px);
     height: 80px;
     padding: 0 26px 0 26px !important;
     transition: all 0.3s;
@@ -411,4 +413,4 @@
 //       }
 //     }
 //   }
-// }
+// }

+ 3 - 1
src/components/card-preview/video-modal/index.tsx

@@ -156,6 +156,7 @@ export default defineComponent({
           videoFroms.durationNum = videoItem.value.duration();
 
           emit('loadedmetadata', videoItem.value);
+          onToggleVideo();
         });
 
         // 视频播放时加载
@@ -222,7 +223,8 @@ export default defineComponent({
     onMounted(() => {
       videoItem.value = TCPlayer(videoID, {
         appID: '',
-        controls: false
+        controls: false,
+        autoPlay: true
       }); // player-container-id 为播放器容器 ID,必须与 html 中一致
       __init();
       window.addEventListener('fullscreenchange', onFullScreenChange);

+ 3 - 3
src/components/card-type/index.module.less

@@ -126,8 +126,8 @@
 
     .iconType {
       display: inline-block;
-      width: 24px;
-      height: 24px;
+      width: 26px;
+      height: 26px;
     }
 
     .iconPlay {
@@ -290,4 +290,4 @@
       min-width: 124px;
     }
   }
-}
+}

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

@@ -277,7 +277,6 @@ export default defineComponent({
           isAnimation.value = false;
         }}
         onDragstart={(e: any) => {
-          console.log('dragstart', Date.now());
           e.dataTransfer.setData('text', JSON.stringify(props.item));
         }}>
         {/* 判断是否下架 */}

+ 26 - 5
src/components/layout/index.module.less

@@ -41,7 +41,7 @@
   }
 
   .sliderList {
-    margin-top: 10px;
+    // margin-top: 10px;
     max-height: calc(100vh - 92px);
     --n-scrollbar-width: 0 !important;
 
@@ -67,6 +67,10 @@
   border-radius: 20px;
   cursor: pointer;
 
+  &:first-child {
+    margin-top: 18px;
+  }
+
   .radiusIcon {
     img {
       width: 26px;
@@ -321,8 +325,8 @@
     padding-bottom: 20px;
 
     .teacherIcon {
-      width: 48px;
-      height: 48px;
+      width: 56px;
+      height: 56px;
       border-radius: 50%;
       border: 1px solid #ffffff;
       overflow: hidden;
@@ -331,14 +335,31 @@
 
     .teacherName {
       flex: 1;
-      font-size: 22px;
+      font-size: max(17px, 13Px);
       font-weight: 600;
       color: #333333;
-      margin-left: 16px;
       overflow: hidden;
       text-overflow: ellipsis;
       white-space: nowrap;
     }
+
+    .userInfos {
+      margin-left: 16px;
+      display: flex;
+      align-items: flex-start;
+      flex-direction: column;
+
+      .roleType {
+        margin-top: 3px;
+        font-size: max(12px, 11Px);
+        color: #2089FF;
+        background: #E8F4FF;
+        border-radius: 3px;
+        border: 1px solid rgba(25, 140, 254, 0.5);
+        padding: 0 4px;
+        line-height: 1.3;
+      }
+    }
   }
 
   .propWrapList {

+ 20 - 9
src/components/layout/layoutTop.tsx

@@ -42,6 +42,7 @@ import { usePrepareStore } from '/src/store/modules/prepareLessons';
 import { schoolDetail } from '/src/views/studentList/api';
 import AddStudentModel from '/src/views/studentList/modals/addStudentModel';
 import { modalClickMask } from '/src/state';
+import { teacherJobType } from '/src/utils/contants';
 
 export default defineComponent({
   name: 'layoutTop',
@@ -380,14 +381,23 @@ export default defineComponent({
                     class={styles.teacherIcon}
                     src={info.value.avatar ? info.value.avatar : teacherIcon}
                     previewDisabled></NImage>
-                  <NTooltip class={styles.nameTool}>
-                    {{
-                      trigger: () => (
-                        <p class={styles.teacherName}>{info.value.nickname}</p>
-                      ),
-                      default: () => info.value.nickname
-                    }}
-                  </NTooltip>
+                  <div class={styles.userInfos}>
+                    <NTooltip class={styles.nameTool}>
+                      {{
+                        trigger: () => (
+                          <p class={styles.teacherName}>
+                            {info.value.nickname}
+                          </p>
+                        ),
+                        default: () => info.value.nickname
+                      }}
+                    </NTooltip>
+                    {info.value.teacherJobType && (
+                      <span class={styles.roleType}>
+                        {teacherJobType[info.value.teacherJobType]}
+                      </span>
+                    )}
+                  </div>
                 </div>
                 <div class={styles.propWrapList}>
                   <div
@@ -399,7 +409,8 @@ export default defineComponent({
                       previewDisabled></NImage>
                     <p class={styles.smallTitle}>个人信息</p>
                   </div>
-                  {info.value.isSuperAdmin ? (
+                  {info.value.isSuperAdmin ||
+                  info.value.teacherJobType === 'HEADMASTER' ? (
                     <div
                       class={styles.propWrapItem}
                       onClick={() => {

+ 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;
     }

+ 9 - 0
src/utils/contants.ts

@@ -81,3 +81,12 @@ export const audioPlayType = {
   SING: '演唱',
   PLAY_SING: '演奏+演唱'
 } as any;
+
+/**
+ * 管理权限
+ */
+export const teacherJobType = {
+  TEACHER: '音乐老师',
+  ADMIN: '管理员',
+  HEADMASTER: '校长'
+} as any;

+ 3 - 0
src/views/attend-class/component/audio-pay.tsx

@@ -442,6 +442,9 @@ export default defineComponent({
               audioForms.paused = true;
               emit('ended');
             }}
+            onPlay={() => {
+              audioForms.paused = audio.value?.paused;
+            }}
             onTimeupdate={() => {
               audioForms.currentTime = timeFormat(
                 Math.round(audio.value?.currentTime || 0)

+ 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>
+    );
+  }
+});

+ 49 - 28
src/views/attend-class/index.tsx

@@ -368,18 +368,6 @@ export default defineComponent({
       //   console.log('Event:', event.type, event);
       // }
 
-      // document.addEventListener('keydown', handleEvent);
-      // document.addEventListener('keyup', handleEvent);
-      // document.addEventListener('keypress', handleEvent);
-      // document.addEventListener('pointerdown', handleEvent);
-      // document.addEventListener('pointerup', handleEvent);
-      // document.addEventListener('pointermove', handleEvent);
-      // document.addEventListener('mousedown', handleEvent);
-      // document.addEventListener('mouseup', handleEvent);
-      // document.addEventListener('mousemove', handleEvent);
-      // document.addEventListener('focus', handleEvent, true);
-      // document.addEventListener('blur', handleEvent, true);
-
       if (data.classId) {
         const res = await api_cousseScheduleDetail(data.classId);
         data.courseId = res.data.useChapterLessonCoursewareId;
@@ -405,6 +393,8 @@ export default defineComponent({
       window.addEventListener('offline', handleOffline);
 
       document.addEventListener('keydown', (e: KeyboardEvent) => {
+        e.stopPropagation();
+        e.preventDefault();
         if (
           data.nextEndShow ||
           data.removeVisiable ||
@@ -430,22 +420,46 @@ export default defineComponent({
           // if (popupData.activeIndex === data.itemList.length - 1) return;
           setModalOpen();
           handlePreAndNext('down');
-        } else if (e.code === 'Space') {
-          // const activeItem = data.itemList[popupData.activeIndex];
+        } else if (e.code === 'Tab') {
+          console.log('Space clicked');
+
+          const activeItem = data.itemList[popupData.activeIndex];
           // console.log(activeItem, activeItem.videoEle);
-          // // 暂停视频和曲谱的播放
-          // if (activeItem.type === 'VIDEO' && activeItem.videoEle) {
-          //   activeItem.videoEle?.play();
-          // }
-          // if (activeItem.type === 'SONG' && activeItem.audioEle) {
-          //   activeItem.audioEle?.play();
-          // }
-          // if (activeItem.type === 'MUSIC') {
-          //   activeItem.iframeRef?.contentWindow?.postMessage(
-          //     { api: 'setPlayState' },
-          //     '*'
-          //   );
-          // }
+          // 暂停视频和曲谱的播放
+          if (activeItem.type === 'VIDEO' && activeItem.videoEle) {
+            activeItem.videoEle?.play();
+          }
+          if (activeItem.type === 'SONG' && activeItem.audioEle) {
+            activeItem.audioEle?.play();
+          }
+          if (activeItem.type === 'MUSIC') {
+            activeItem.iframeRef?.contentWindow?.postMessage(
+              { api: 'startPlayState' },
+              '*'
+            );
+          }
+          if (activeItem.type === 'LISTEN') {
+            console.log(activeItem.type, 'listening');
+            activeItem.iframeRef?.contentWindow?.postMessage(
+              { api: 'startPlayState' },
+              '*'
+            );
+          }
+          if (activeItem.type === 'RHYTHM') {
+            activeItem.iframeRef?.contentWindow?.postMessage(
+              { api: 'setPlayState', data: true },
+              '*'
+            );
+          }
+
+          if (activeItem.type === 'PPT') {
+            console.log(activeItem.iframeRef, 'activeItem.iframeRef;');
+            activeItem.iframeRef?.focus();
+
+            // 将焦点传递给 iframe 内部内容
+            const iframeWindow = activeItem.iframeRef?.contentWindow;
+            iframeWindow.postMessage({ type: 'focus' }, '*');
+          }
         }
       });
     });
@@ -1826,6 +1840,12 @@ export default defineComponent({
                           src={`https://view.officeapps.live.com/op/embed.aspx?src=${encodeURIComponent(
                             m.content
                           )}`}
+                          onLoad={(e: any) => {
+                            nextTick(() => {
+                              console.log(e, 'ppt', e.target);
+                              m.iframeRef = e.target;
+                            });
+                          }}
                           width="100%"
                           height="100%"
                           frameborder="1"></iframe>
@@ -1873,6 +1893,7 @@ export default defineComponent({
                       ) : (
                         <MusicScore
                           activeModel={activeData.model}
+                          instrumentId={data.instrumentId}
                           activeStatus={popupData.activeIndex === mIndex}
                           data-vid={m.id}
                           music={m}
@@ -2375,7 +2396,7 @@ export default defineComponent({
           style={selResourDragData.styleDrag.value}
           preset="card"
           title={'选择资源'}>
-          <SelectResources from="class" />
+          <SelectResources from="class" instrumentId={data.instrumentId} />
           <Dragbom></Dragbom>
         </NModal>
         <NModal

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

@@ -231,8 +231,8 @@
     top: 8px;
     right: 10px;
     z-index: 98;
-    opacity: 0;
-    visibility: hidden;
+    // opacity: 0;
+    // visibility: hidden;
     transition: all .2s ease;
     width: 27px;
     height: 27px;

+ 503 - 372
src/views/classList/components/testRecode.tsx

@@ -1,372 +1,503 @@
-import { defineComponent, onMounted, reactive, ref } from 'vue';
-import styles from '../index.module.less';
-import {
-  NButton,
-  NDataTable,
-  NForm,
-  NFormItem,
-  NGi,
-  NGrid,
-  NImage,
-  NModal,
-  NNumberAnimation,
-  NSelect,
-  NSpace
-} from 'naive-ui';
-import SearchInput from '@/components/searchInput';
-import CSelect from '@/components/CSelect';
-import Pagination from '@/components/pagination';
-import add from './images/add.png';
-import {
-  getNowDateAndMonday,
-  getNowDateAndSunday,
-  getTimes,
-  getMinutes,
-  getSecend
-} from '/src/utils/dateFormat';
-import { getTestList, getTrainingStat } from '../api';
-import CDatePicker from '/src/components/CDatePicker';
-import { useRoute, useRouter } from 'vue-router';
-import TheEmpty from '/src/components/TheEmpty';
-import { initCache, setCache } from '/src/hooks/use-async';
-
-export default defineComponent({
-  name: 'student-studentList',
-  setup(props, { emit }) {
-    const state = reactive({
-      searchForm: {
-        keyword: '',
-        trainingStatus: null as any,
-        vipFlag: '' as any
-      },
-      searchWord: '',
-      orchestraType: null,
-      courseTypeCode: null,
-      subjectId: null,
-      classId: null,
-      studentType: null,
-      loading: false,
-      pagination: {
-        page: 1,
-        rows: 10,
-        pageTotal: 4
-      },
-      tableList: [] as any,
-      memberNumber: 0,
-      testInfo: {
-        practiceDurationAvg: 0,
-        vipUserCount: 0,
-        practiceUserCount: 0
-      },
-      activeRow: null
-    });
-    const route = useRoute();
-    const router = useRouter();
-    const search = () => {
-      state.pagination.page = 1;
-      getInfo();
-      getList();
-      setCache({
-        current: { ...state.searchForm, timer: timer.value },
-        saveKey: 'classDetailTestRecord'
-      });
-    };
-    const timer = ref<[number, number]>([
-      getNowDateAndMonday(new Date().getTime()),
-      getNowDateAndSunday(new Date().getTime())
-    ]);
-    const onReset = () => {
-      timer.value = [
-        getNowDateAndMonday(new Date().getTime()),
-        getNowDateAndSunday(new Date().getTime())
-      ];
-      state.searchForm = {
-        keyword: '',
-        trainingStatus: null as any,
-        vipFlag: ''
-      };
-      search();
-      setCache({
-        current: { ...state.searchForm, timer: timer.value },
-        saveKey: 'classDetailTestRecord'
-      });
-    };
-
-    initCache({
-      current: { ...state.searchForm, timer: timer.value },
-      saveKey: 'classDetailTestRecord',
-      callBack: (active: any) => {
-        state.searchForm = active;
-        timer.value = active.timer;
-      }
-    });
-    const getList = async () => {
-      state.loading = true;
-      try {
-        const res = await getTestList({
-          classGroupId: route.query.id,
-          ...state.searchForm,
-          ...state.pagination,
-          ...getTimes(timer.value, ['startTime', 'endTime'], 'YYYY-MM-DD')
-        });
-
-        state.tableList = res.data.rows;
-
-        state.pagination.pageTotal = res.data.total;
-        state.loading = false;
-      } catch (e) {
-        state.loading = false;
-        console.log(e);
-      }
-    };
-
-    const getInfo = async () => {
-      try {
-        const res = await getTrainingStat({
-          classGroupId: route.query.id,
-          ...getTimes(timer.value, ['startTime', 'endTime'], 'YYYY-MM-DD')
-        });
-        state.testInfo.practiceDurationAvg = res.data.practiceDurationAvg;
-        state.testInfo.practiceUserCount = res.data.practiceUserCount;
-        state.testInfo.vipUserCount = res.data.vipUserCount;
-      } catch (e) {
-        console.log(e);
-      }
-    };
-    onMounted(() => {
-      getInfo();
-      getList();
-    });
-    const gotoStudentDetail = (row: any) => {
-      router.push({
-        path: '/classStudentRecode',
-        query: {
-          ...route.query,
-          studentId: row.studentId,
-          studentName: row.studentName
-        }
-      });
-    };
-    const columns = () => {
-      return [
-        {
-          title: '学生姓名',
-          key: 'studentName'
-        },
-        {
-          title: '手机号',
-          key: 'studentPhone'
-        },
-        {
-          title: '性别',
-          key: 'sex',
-          render(row: any) {
-            return (
-              <>
-                {row.gender + '' != 'null'
-                  ? row.gender == '0'
-                    ? '女'
-                    : '男'
-                  : '--'}
-              </>
-            );
-          }
-        },
-        {
-          title: '学生类型',
-          key: 'studentType',
-          render(row: any) {
-            return <>{row.vipFlag ? '会员' : '普通'}</>;
-          }
-        },
-        {
-          title: '练习天数',
-          key: 'practiceDays',
-          render(row: any) {
-            return <>{row.practiceDays ? row.practiceDays : 0}天</>;
-          }
-        },
-        {
-          title: '学练时长',
-          key: 'studentType',
-          render(row: any) {
-            return (
-              <>
-                {row.practiceDuration
-                  ? getMinutes(row.practiceDuration) > 0
-                    ? getMinutes(row.practiceDuration) +
-                      '分' +
-                      getSecend(row.practiceDuration) +
-                      '秒'
-                    : getSecend(row.practiceDuration) + '秒'
-                  : 0 + '秒'}
-              </>
-            );
-          }
-        },
-        {
-          title: '操作',
-          key: 'id',
-          render(row: any) {
-            return (
-              <NButton
-                text
-                type="primary"
-                onClick={() => {
-                  gotoStudentDetail(row);
-                }}>
-                详情
-              </NButton>
-            );
-          }
-        }
-      ];
-    };
-    return () => (
-      <div>
-        <div class={styles.searchList}>
-          <NForm label-placement="left" inline>
-            <NFormItem>
-              <SearchInput
-                {...{ placeholder: '请输入学生姓名' }}
-                class={styles.searchInput}
-                searchWord={state.searchForm.keyword}
-                onChangeValue={(val: string) =>
-                  (state.searchForm.keyword = val)
-                }></SearchInput>
-            </NFormItem>
-
-            <NFormItem>
-              <CSelect
-                {...({
-                  options: [
-                    {
-                      label: '全部类型',
-                      value: ''
-                    },
-                    {
-                      label: '会员',
-                      value: true
-                    },
-                    {
-                      label: '普通',
-                      value: false
-                    }
-                  ],
-                  placeholder: '学生类型',
-                  clearable: true,
-                  inline: true
-                } as any)}
-                v-model:value={state.searchForm.vipFlag}></CSelect>
-            </NFormItem>
-            <NFormItem>
-              <CDatePicker
-                v-model:value={timer.value}
-                separator={'至'}
-                type="daterange"
-                timerValue={timer.value}></CDatePicker>
-            </NFormItem>
-            <NFormItem>
-              <NSpace justify="end">
-                <NButton type="primary" class="searchBtn" onClick={search}>
-                  搜索
-                </NButton>
-                <NButton
-                  type="primary"
-                  ghost
-                  class="resetBtn"
-                  onClick={onReset}>
-                  重置
-                </NButton>
-              </NSpace>
-            </NFormItem>
-          </NForm>
-        </div>
-        <div class={['section-container']}>
-          <NGrid x-gap="12" cols={8}>
-            <NGi>
-              <div class={styles.TrainDataItem}>
-                <div>
-                  <p class={styles.TrainDataItemTitle}>
-                    <div>
-                      <span>
-                        <NNumberAnimation
-                          from={0}
-                          to={
-                            state.testInfo.practiceUserCount
-                          }></NNumberAnimation>
-                      </span>{' '}
-                      人
-                    </div>
-                  </p>
-                </div>
-                <p class={styles.TrainDataItemsubTitle}>练习人数</p>
-              </div>
-            </NGi>
-            <NGi>
-              <div class={styles.TrainDataItem}>
-                <p class={styles.TrainDataItemTitle}>
-                  <div>
-                    <span>
-                      <NNumberAnimation
-                        from={0}
-                        to={state.testInfo.vipUserCount}></NNumberAnimation>
-                    </span>{' '}
-                    人
-                  </div>
-                </p>
-                <p class={styles.TrainDataItemsubTitle}>会员人数</p>
-              </div>
-            </NGi>
-            <NGi>
-              <div class={styles.TrainDataItem}>
-                <p class={styles.TrainDataItemTitle}>
-                  {getMinutes(state.testInfo.practiceDurationAvg) > 0 ? (
-                    <div>
-                      <span>
-                        <NNumberAnimation
-                          from={0}
-                          to={getMinutes(
-                            state.testInfo.practiceDurationAvg
-                          )}></NNumberAnimation>
-                      </span>{' '}
-                      分
-                    </div>
-                  ) : null}
-                  <div>
-                    <span>
-                      <NNumberAnimation
-                        from={0}
-                        to={getSecend(
-                          state.testInfo.practiceDurationAvg
-                        )}></NNumberAnimation>
-                    </span>{' '}
-                    秒
-                  </div>
-                </p>
-                <p class={styles.TrainDataItemsubTitle}>平均每天练习时长</p>
-              </div>
-            </NGi>
-          </NGrid>
-        </div>
-        <div class={styles.tableWrap}>
-          <NDataTable
-            v-slots={{
-              empty: () => <TheEmpty></TheEmpty>
-            }}
-            class={styles.classTable}
-            loading={state.loading}
-            columns={columns()}
-            data={state.tableList}></NDataTable>
-          <Pagination
-            v-model:page={state.pagination.page}
-            v-model:pageSize={state.pagination.rows}
-            v-model:pageTotal={state.pagination.pageTotal}
-            onList={getList}
-            sync
-          />
-        </div>
-      </div>
-    );
-  }
-});
+import { defineComponent, nextTick, onMounted, reactive, ref } from 'vue';
+import styles from '../index.module.less';
+import {
+  NButton,
+  NDataTable,
+  NForm,
+  NFormItem,
+  NGi,
+  NGrid,
+  NImage,
+  NModal,
+  NNumberAnimation,
+  NSelect,
+  NSpace,
+  NTooltip
+} from 'naive-ui';
+import SearchInput from '@/components/searchInput';
+import CSelect from '@/components/CSelect';
+import Pagination from '@/components/pagination';
+import add from './images/add.png';
+import {
+  getNowDateAndMonday,
+  getNowDateAndSunday,
+  getTimes,
+  getMinutes,
+  getSecend
+} from '/src/utils/dateFormat';
+import { getTestList, getTrainingStat } from '../api';
+import CDatePicker from '/src/components/CDatePicker';
+import { useRoute, useRouter } from 'vue-router';
+import TheEmpty from '/src/components/TheEmpty';
+import { initCache, setCache } from '/src/hooks/use-async';
+import iconSortDefault from '@/common/images/icon-sort-default.png';
+import iconSortDesc from '@/common/images/icon-sort-desc.png';
+import iconSortAsc from '@/common/images/icon-sort-asc.png';
+
+export default defineComponent({
+  name: 'student-studentList',
+  setup(props, { emit }) {
+    const state = reactive({
+      searchForm: {
+        ase: 0,
+        sortType: 1,
+        keyword: '',
+        trainingStatus: null as any,
+        vipFlag: '' as any
+      },
+      searchWord: '',
+      orchestraType: null,
+      courseTypeCode: null,
+      subjectId: null,
+      classId: null,
+      studentType: null,
+      loading: false,
+      pagination: {
+        page: 1,
+        rows: 10,
+        pageTotal: 4
+      },
+      tableList: [] as any,
+      memberNumber: 0,
+      testInfo: {
+        practiceDurationAvg: 0,
+        vipUserCount: 0,
+        practiceUserCount: 0
+      },
+      activeRow: null
+    });
+    const route = useRoute();
+    const router = useRouter();
+    const search = () => {
+      state.pagination.page = 1;
+      getInfo();
+      getList();
+      setCache({
+        current: { ...state.searchForm, timer: timer.value },
+        saveKey: 'classDetailTestRecord'
+      });
+    };
+    const timer = ref<[number, number]>([
+      getNowDateAndMonday(new Date().getTime()),
+      getNowDateAndSunday(new Date().getTime())
+    ]);
+    const onReset = () => {
+      timer.value = [
+        getNowDateAndMonday(new Date().getTime()),
+        getNowDateAndSunday(new Date().getTime())
+      ];
+      state.searchForm = {
+        ase: 0,
+        sortType: 1,
+        keyword: '',
+        trainingStatus: null as any,
+        vipFlag: ''
+      };
+      search();
+      setCache({
+        current: { ...state.searchForm, timer: timer.value },
+        saveKey: 'classDetailTestRecord'
+      });
+    };
+
+    initCache({
+      current: { ...state.searchForm, timer: timer.value },
+      saveKey: 'classDetailTestRecord',
+      callBack: (active: any) => {
+        state.searchForm = active;
+        timer.value = active.timer;
+      }
+    });
+    const getList = async () => {
+      state.loading = true;
+      try {
+        const res = await getTestList({
+          classGroupId: route.query.id,
+          ...state.searchForm,
+          ...state.pagination,
+          ...getTimes(timer.value, ['startTime', 'endTime'], 'YYYY-MM-DD')
+        });
+
+        state.tableList = res.data.rows;
+
+        state.pagination.pageTotal = res.data.total;
+        state.loading = false;
+      } catch (e) {
+        state.loading = false;
+        console.log(e);
+      }
+    };
+
+    const getInfo = async () => {
+      try {
+        const res = await getTrainingStat({
+          classGroupId: route.query.id,
+          ...getTimes(timer.value, ['startTime', 'endTime'], 'YYYY-MM-DD')
+        });
+        state.testInfo.practiceDurationAvg = res.data.practiceDurationAvg;
+        state.testInfo.practiceUserCount = res.data.practiceUserCount;
+        state.testInfo.vipUserCount = res.data.vipUserCount;
+      } catch (e) {
+        console.log(e);
+      }
+    };
+    onMounted(() => {
+      getInfo();
+      getList();
+
+      // nextTick(() => {
+      //   // 把默认的排序删除
+      //   const dom = document.querySelectorAll('.n-data-table-sorter');
+      //   dom.forEach((item: any) => {
+      //     item.style.display = 'none';
+      //   });
+      // });
+    });
+    const gotoStudentDetail = (row: any) => {
+      router.push({
+        path: '/classStudentRecode',
+        query: {
+          ...route.query,
+          studentId: row.studentId,
+          studentName: row.studentName
+        }
+      });
+    };
+    const practiceDaysRef = reactive({
+      title() {
+        return (
+          <NTooltip showArrow={false} placement="top-start">
+            {{
+              trigger: () => (
+                <div class={styles.cell}>
+                  练习天数
+                  <img
+                    class={styles.sortIcon}
+                    src={
+                      practiceDaysRef.sortOrder === 'descend'
+                        ? iconSortDesc
+                        : practiceDaysRef.sortOrder === 'ascend'
+                        ? iconSortAsc
+                        : iconSortDefault
+                    }
+                  />
+                </div>
+              ),
+              default:
+                practiceDaysRef.sortOrder === 'descend'
+                  ? '点击升序'
+                  : practiceDaysRef.sortOrder === 'ascend'
+                  ? '取消排序'
+                  : '点击降序'
+            }}
+          </NTooltip>
+        );
+      },
+      key: 'practiceDays',
+      sorter: true,
+      sortOrder: false as any,
+      render(row: any) {
+        return <>{row.practiceDays ? row.practiceDays : 0}天</>;
+      }
+    });
+
+    const practiceDurationRef = reactive({
+      title() {
+        return (
+          <NTooltip showArrow={false} placement="top-start">
+            {{
+              trigger: () => (
+                <div class={styles.cell}>
+                  学练时长
+                  <img
+                    class={styles.sortIcon}
+                    src={
+                      practiceDurationRef.sortOrder === 'descend'
+                        ? iconSortDesc
+                        : practiceDurationRef.sortOrder === 'ascend'
+                        ? iconSortAsc
+                        : iconSortDefault
+                    }
+                  />
+                </div>
+              ),
+              default:
+                practiceDurationRef.sortOrder === 'descend'
+                  ? '点击升序'
+                  : practiceDurationRef.sortOrder === 'ascend'
+                  ? '取消排序'
+                  : '点击降序'
+            }}
+          </NTooltip>
+        );
+      },
+      key: 'practiceDuration',
+      sorter: true,
+      sortOrder: false as any,
+      render(row: any) {
+        return (
+          <>
+            {row.practiceDuration
+              ? getMinutes(row.practiceDuration) > 0
+                ? getMinutes(row.practiceDuration) +
+                  '分' +
+                  getSecend(row.practiceDuration) +
+                  '秒'
+                : getSecend(row.practiceDuration) + '秒'
+              : 0 + '秒'}
+          </>
+        );
+      }
+    });
+    const columns = () => {
+      return [
+        {
+          title: '学生姓名',
+          key: 'studentName'
+        },
+        {
+          title: '手机号',
+          key: 'studentPhone'
+        },
+        {
+          title: '性别',
+          key: 'sex',
+          render(row: any) {
+            return (
+              <>
+                {row.gender + '' != 'null'
+                  ? row.gender == '0'
+                    ? '女'
+                    : '男'
+                  : '--'}
+              </>
+            );
+          }
+        },
+        {
+          title: '学生类型',
+          key: 'studentType',
+          render(row: any) {
+            return <>{row.vipFlag ? '会员' : '普通'}</>;
+          }
+        },
+        practiceDaysRef,
+        practiceDurationRef,
+        // {
+        //   title: '练习天数',
+        //   key: 'practiceDays',
+        //   render(row: any) {
+        //     return <>{row.practiceDays ? row.practiceDays : 0}天</>;
+        //   }
+        // },
+        // {
+        //   title: '学练时长',
+        //   key: 'studentType',
+        //   render(row: any) {
+        //     return (
+        //       <>
+        //         {row.practiceDuration
+        //           ? getMinutes(row.practiceDuration) > 0
+        //             ? getMinutes(row.practiceDuration) +
+        //               '分' +
+        //               getSecend(row.practiceDuration) +
+        //               '秒'
+        //             : getSecend(row.practiceDuration) + '秒'
+        //           : 0 + '秒'}
+        //       </>
+        //     );
+        //   }
+        // },
+        {
+          title: '操作',
+          key: 'id',
+          render(row: any) {
+            return (
+              <NButton
+                text
+                type="primary"
+                onClick={() => {
+                  gotoStudentDetail(row);
+                }}>
+                详情
+              </NButton>
+            );
+          }
+        }
+      ];
+    };
+
+    const handleSorterChange = (sroter: any) => {
+      if (!sroter) {
+        state.searchForm.ase = 0;
+        state.searchForm.sortType = 1;
+        practiceDaysRef.sortOrder = false;
+        practiceDurationRef.sortOrder = false;
+      } else {
+        const list = {
+          practiceDuration: 1,
+          practiceDays: 2
+        };
+        state.searchForm.sortType =
+          list[sroter.columnKey as 'practiceDuration' | 'practiceDays'];
+        if (sroter.columnKey == 'practiceDuration') {
+          practiceDurationRef.sortOrder = sroter.order;
+          practiceDaysRef.sortOrder = false;
+        }
+        if (sroter.columnKey == 'practiceDays') {
+          practiceDaysRef.sortOrder = sroter.order;
+          practiceDurationRef.sortOrder = false;
+        }
+        state.searchForm.ase = sroter.order == 'ascend' ? 1 : 0;
+      }
+      getList();
+    };
+    return () => (
+      <div>
+        <div class={styles.searchList}>
+          <NForm label-placement="left" inline>
+            <NFormItem>
+              <SearchInput
+                {...{ placeholder: '请输入学生姓名' }}
+                class={styles.searchInput}
+                searchWord={state.searchForm.keyword}
+                onChangeValue={(val: string) =>
+                  (state.searchForm.keyword = val)
+                }></SearchInput>
+            </NFormItem>
+
+            <NFormItem>
+              <CSelect
+                {...({
+                  options: [
+                    {
+                      label: '全部类型',
+                      value: ''
+                    },
+                    {
+                      label: '会员',
+                      value: true
+                    },
+                    {
+                      label: '普通',
+                      value: false
+                    }
+                  ],
+                  placeholder: '学生类型',
+                  clearable: true,
+                  inline: true
+                } as any)}
+                v-model:value={state.searchForm.vipFlag}></CSelect>
+            </NFormItem>
+            <NFormItem>
+              <CDatePicker
+                v-model:value={timer.value}
+                separator={'至'}
+                type="daterange"
+                timerValue={timer.value}></CDatePicker>
+            </NFormItem>
+            <NFormItem>
+              <NSpace justify="end">
+                <NButton type="primary" class="searchBtn" onClick={search}>
+                  搜索
+                </NButton>
+                <NButton
+                  type="primary"
+                  ghost
+                  class="resetBtn"
+                  onClick={onReset}>
+                  重置
+                </NButton>
+              </NSpace>
+            </NFormItem>
+          </NForm>
+        </div>
+        <div class={['section-container']}>
+          <NGrid x-gap="12" cols={8}>
+            <NGi>
+              <div class={styles.TrainDataItem}>
+                <div>
+                  <p class={styles.TrainDataItemTitle}>
+                    <div>
+                      <span>
+                        <NNumberAnimation
+                          from={0}
+                          to={
+                            state.testInfo.practiceUserCount
+                          }></NNumberAnimation>
+                      </span>{' '}
+                      人
+                    </div>
+                  </p>
+                </div>
+                <p class={styles.TrainDataItemsubTitle}>练习人数</p>
+              </div>
+            </NGi>
+            <NGi>
+              <div class={styles.TrainDataItem}>
+                <p class={styles.TrainDataItemTitle}>
+                  <div>
+                    <span>
+                      <NNumberAnimation
+                        from={0}
+                        to={state.testInfo.vipUserCount}></NNumberAnimation>
+                    </span>{' '}
+                    人
+                  </div>
+                </p>
+                <p class={styles.TrainDataItemsubTitle}>会员人数</p>
+              </div>
+            </NGi>
+            <NGi>
+              <div class={styles.TrainDataItem}>
+                <p class={styles.TrainDataItemTitle}>
+                  {getMinutes(state.testInfo.practiceDurationAvg) > 0 ? (
+                    <div>
+                      <span>
+                        <NNumberAnimation
+                          from={0}
+                          to={getMinutes(
+                            state.testInfo.practiceDurationAvg
+                          )}></NNumberAnimation>
+                      </span>{' '}
+                      分
+                    </div>
+                  ) : null}
+                  <div>
+                    <span>
+                      <NNumberAnimation
+                        from={0}
+                        to={getSecend(
+                          state.testInfo.practiceDurationAvg
+                        )}></NNumberAnimation>
+                    </span>{' '}
+                    秒
+                  </div>
+                </p>
+                <p class={styles.TrainDataItemsubTitle}>平均每天练习时长</p>
+              </div>
+            </NGi>
+          </NGrid>
+        </div>
+        <div class={[styles.tableWrap, styles.noSort]}>
+          <NDataTable
+            v-slots={{
+              empty: () => <TheEmpty></TheEmpty>
+            }}
+            class={styles.classTable}
+            loading={state.loading}
+            columns={columns()}
+            data={state.tableList}
+            onUpdate:sorter={handleSorterChange}></NDataTable>
+          <Pagination
+            v-model:page={state.pagination.page}
+            v-model:pageSize={state.pagination.rows}
+            v-model:pageTotal={state.pagination.pageTotal}
+            onList={getList}
+            sync
+          />
+        </div>
+      </div>
+    );
+  }
+});

+ 19 - 0
src/views/classList/index.module.less

@@ -900,4 +900,23 @@
 
 .updateStudent {
   width: 480px;
+}
+
+.noSort {
+  :global {
+    .n-data-table-sorter {
+      display: none !important;
+    }
+  }
+}
+
+.cell {
+  display: flex;
+  align-items: center;
+
+  .sortIcon {
+    margin-left: 7px;
+    width: 13px;
+    height: 13px;
+  }
 }

+ 14 - 4
src/views/home/index.tsx

@@ -100,10 +100,20 @@ export default defineComponent({
             <div class={styles.homeUserInfo}>
               <i class={styles.homeTag}></i>
               <div class={styles.homeUsers}>
-                <NImage
-                  src={userStore.getUserInfo?.avatar || defultHeade}
-                  class={styles.userImg}
-                />
+                <div
+                  style={{ cursor: 'pointer' }}
+                  onClick={() => {
+                    router.push({
+                      path: '/setting',
+                      query: { activeTab: 'person' }
+                    });
+                  }}>
+                  <NImage
+                    src={userStore.getUserInfo?.avatar || defultHeade}
+                    class={styles.userImg}
+                    previewDisabled
+                  />
+                </div>
                 <p class={styles.userName}>
                   Hi,{userStore.getUserInfo?.nickname} {formatDateToDay()}~
                 </p>

+ 209 - 203
src/views/home/modals/class-modal/index.module.less

@@ -1,203 +1,209 @@
-.rightTeachingWrap {
-  overflow: hidden;
-  flex: 1;
-  background-color: #fff;
-  padding: 10px 0 30px;
-  border-radius: 20px;
-
-  .rightTeachingWrapTitle {
-    display: flex;
-    flex-direction: row;
-    // align-items: center;
-    justify-content: space-between;
-    flex-direction: column;
-
-    .lookMore {
-      cursor: pointer;
-      display: flex;
-      align-items: center;
-      min-width: 114px;
-      border-radius: 8px;
-      border: 1px solid #DEDEDE;
-      font-size: 15px;
-      color: #131415;
-      padding: 7px 12px;
-
-      svg {
-        margin-left: 8px;
-        width: 16px;
-        height: 16px;
-      }
-    }
-
-    .classSearchList {
-      display: flex;
-      gap: 12px;
-
-      :global {
-        .n-base-selection {
-          --n-height: 35px !important;
-          --n-font-size: 12Px !important;
-          --n-border: 1px solid #DEDEDE !important;
-          --n-border-radius: 8px !important;
-          max-width: 150px;
-        }
-      }
-    }
-  }
-}
-
-:global {
-  .n-base-select-menu .n-base-select-option.n-base-select-option--show-checkmark {
-    padding-right: var(--n-option-padding);
-  }
-
-  .n-empty {
-    --n-font-size: max(16px, 12Px) !important;
-  }
-}
-
-.teachListWrap {
-  position: relative;
-
-
-}
-
-.teachListWrapWall {
-  position: absolute;
-  bottom: 0;
-  height: 159px;
-  width: 100%;
-  background: linear-gradient(180deg,
-      rgba(255, 255, 255, 0) 0%,
-      #ffffff 100%);
-  border-radius: 0px 0px 20px 20px;
-
-  span {
-    position: absolute;
-    bottom: 17px;
-    left: 0;
-    width: 100%;
-    text-align: center;
-    color: #1677FF;
-    font-size: max(16px, 13Px);
-    cursor: pointer;
-
-    &::after {
-      content: ' ';
-      display: inline-block;
-      width: 12px;
-      height: 12px;
-      background: url('../../images/blueArrow.png') no-repeat center;
-      background-size: contain;
-    }
-  }
-}
-
-.teachGroup {
-  margin-top: 12px;
-
-  .teachGroupTitle {
-    position: relative;
-    left: -10px;
-    font-size: 14Px;
-    font-weight: 400;
-    color: #aaaaaa;
-    width: 60px;
-    text-align: center;
-    margin-bottom: 12px;
-  }
-
-  .teachGroupList {
-    padding-bottom: 12px;
-    margin-left: 20px;
-    border-left: 1px solid #d1e8ff;
-    min-height: 92px;
-    position: relative;
-
-    .teachGroupListDot {
-      width: 15px;
-      height: 15px;
-      background: #198cfe;
-      border: 4px solid #d1e8ff;
-      border-radius: 50%;
-      top: 28px;
-      left: -8px;
-      position: absolute;
-    }
-  }
-
-  .teachGroupItemWrap {
-    margin-left: 28px;
-    background: #f7f9ff;
-    border-radius: 12px;
-    display: flex;
-    flex-direction: row;
-    align-items: top;
-
-    &:nth-last-of-type(1) {
-      margin-bottom: 0;
-    }
-
-    margin-bottom: 12px;
-    padding: 10px;
-
-    .teachGroupItemLeft {
-      margin-right: 12px;
-      width: 50px;
-      height: 50px;
-      border-radius: 50%;
-      overflow: hidden;
-      border: 2px solid #198cfe;
-
-      .teachGroupItemHeader {
-        border: 2px solid #fff;
-        border-radius: 50%;
-        overflow: hidden;
-
-        img {
-          width: 44px;
-          height: 44px;
-        }
-      }
-    }
-
-    .teachGroupItemRight {
-      flex: 1;
-
-      .teachGroupItemName {
-        display: flex;
-        flex-direction: row;
-        align-items: center;
-        justify-content: space-between;
-        font-size: 16px;
-        margin-top: 2px;
-        font-weight: 600;
-        color: #131415;
-
-        span {
-          font-size: 13px;
-          font-weight: 400;
-          color: #1677ff;
-          line-height: 18px;
-        }
-      }
-
-      .teachGroupItemInfo {
-        font-size: 13px;
-        line-height: 26px;
-        color: rgba(0, 0, 0, 0.5);
-      }
-
-      .subjectName {
-        font-size: 14px;
-        font-weight: 400;
-        color: #FFFFFF;
-        background: #198CFE;
-        border-radius: 5px;
-        padding: 1px 8px;
-        margin-right: 4px;
-      }
-    }
-  }
-}
+.rightTeachingWrap {
+  overflow: hidden;
+  flex: 1;
+  background-color: #fff;
+  padding: 10px 0 20px;
+  border-radius: 20px;
+
+  .rightTeachingWrapTitle {
+    display: flex;
+    flex-direction: row;
+    // align-items: center;
+    justify-content: space-between;
+    flex-direction: column;
+
+    .lookMore {
+      cursor: pointer;
+      display: flex;
+      align-items: center;
+      min-width: 114px;
+      border-radius: 8px;
+      border: 1px solid #DEDEDE;
+      font-size: 15px;
+      color: #131415;
+      padding: 7px 12px;
+
+      svg {
+        margin-left: 8px;
+        width: 16px;
+        height: 16px;
+      }
+    }
+
+    .classSearchList {
+      display: flex;
+      gap: 12px;
+
+      :global {
+        .n-base-selection {
+          --n-height: 35px !important;
+          --n-font-size: 12Px !important;
+          --n-border: 1px solid #DEDEDE !important;
+          --n-border-radius: 8px !important;
+          max-width: 150px;
+        }
+      }
+    }
+  }
+
+  .emptySection {
+    min-height: 40vh;
+    display: flex;
+    align-items: center;
+  }
+}
+
+:global {
+  .n-base-select-menu .n-base-select-option.n-base-select-option--show-checkmark {
+    padding-right: var(--n-option-padding);
+  }
+
+  .n-empty {
+    --n-font-size: max(16px, 12Px) !important;
+  }
+}
+
+.teachListWrap {
+  position: relative;
+
+
+}
+
+.teachListWrapWall {
+  position: absolute;
+  bottom: 0;
+  height: 159px;
+  width: 100%;
+  background: linear-gradient(180deg,
+      rgba(255, 255, 255, 0) 0%,
+      #ffffff 100%);
+  border-radius: 0px 0px 20px 20px;
+
+  span {
+    position: absolute;
+    bottom: 17px;
+    left: 0;
+    width: 100%;
+    text-align: center;
+    color: #1677FF;
+    font-size: max(16px, 13Px);
+    cursor: pointer;
+
+    &::after {
+      content: ' ';
+      display: inline-block;
+      width: 12px;
+      height: 12px;
+      background: url('../../images/blueArrow.png') no-repeat center;
+      background-size: contain;
+    }
+  }
+}
+
+.teachGroup {
+  margin-top: 12px;
+
+  .teachGroupTitle {
+    position: relative;
+    left: -10px;
+    font-size: 14Px;
+    font-weight: 400;
+    color: #aaaaaa;
+    width: 60px;
+    text-align: center;
+    margin-bottom: 12px;
+  }
+
+  .teachGroupList {
+    padding-bottom: 12px;
+    margin-left: 20px;
+    border-left: 1px solid #d1e8ff;
+    min-height: 92px;
+    position: relative;
+
+    .teachGroupListDot {
+      width: 15px;
+      height: 15px;
+      background: #198cfe;
+      border: 4px solid #d1e8ff;
+      border-radius: 50%;
+      top: 28px;
+      left: -8px;
+      position: absolute;
+    }
+  }
+
+  .teachGroupItemWrap {
+    margin-left: 28px;
+    background: #f7f9ff;
+    border-radius: 12px;
+    display: flex;
+    flex-direction: row;
+    align-items: top;
+
+    &:nth-last-of-type(1) {
+      margin-bottom: 0;
+    }
+
+    margin-bottom: 12px;
+    padding: 10px;
+
+    .teachGroupItemLeft {
+      margin-right: 12px;
+      width: 50px;
+      height: 50px;
+      border-radius: 50%;
+      overflow: hidden;
+      border: 2px solid #198cfe;
+
+      .teachGroupItemHeader {
+        border: 2px solid #fff;
+        border-radius: 50%;
+        overflow: hidden;
+
+        img {
+          width: 44px;
+          height: 44px;
+        }
+      }
+    }
+
+    .teachGroupItemRight {
+      flex: 1;
+
+      .teachGroupItemName {
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+        justify-content: space-between;
+        font-size: 16px;
+        margin-top: 2px;
+        font-weight: 600;
+        color: #131415;
+
+        span {
+          font-size: 13px;
+          font-weight: 400;
+          color: #1677ff;
+          line-height: 18px;
+        }
+      }
+
+      .teachGroupItemInfo {
+        font-size: 13px;
+        line-height: 26px;
+        color: rgba(0, 0, 0, 0.5);
+      }
+
+      .subjectName {
+        font-size: 14px;
+        font-weight: 400;
+        color: #FFFFFF;
+        background: #198CFE;
+        border-radius: 5px;
+        padding: 1px 8px;
+        margin-right: 4px;
+      }
+    }
+  }
+}

+ 346 - 342
src/views/home/modals/class-modal/index.tsx

@@ -1,342 +1,346 @@
-import { defineComponent, onMounted, reactive, ref } from 'vue';
-import styles from './index.module.less';
-import { useUserStore } from '/src/store/modules/users';
-import { useRouter } from 'vue-router';
-import { NSelect, NSpin } from 'naive-ui';
-import {
-  classGroupList,
-  courseSchedulePage,
-  getGradeLevelList,
-  getGradeYearList
-} from '../../api';
-import dayjs from 'dayjs';
-import TeachGroup from '../teachGroup';
-import TheEmpty from '/src/components/TheEmpty';
-import { gradeToCN } from '/src/utils/contants';
-
-export default defineComponent({
-  name: 'class-modal',
-  emits: ['confirm'],
-  setup(props, { emit }) {
-    const router = useRouter();
-    const userStore = useUserStore();
-    const forms = reactive({
-      showAttendClass: false,
-      // useStatus: false,
-      studentList: [] as any,
-      bookVersionId: null,
-      classGroupId: null,
-      category: null,
-      subjectId: null,
-      musicTagList: [] as any,
-      loading: false,
-      list: [] as any,
-      unit: null,
-      unitList: [],
-      subjectList: [] as any,
-      gradeList: [] as any,
-      classLoading: false,
-      total: 0, // 上课数量
-      // 上次上课的数据
-      lastClassSelect: {
-        currentClass: null,
-        name: '',
-        upgradeFlag: false, // 是否为历史班
-        gradeYear: null as any,
-        gradeLevel: null as any
-      },
-      classSelect: {
-        currentGradeNum: null,
-        currentClass: null,
-        name: '',
-        upgradeFlag: false, // 是否为历史班
-        gradeLevel: null as any,
-        gradeYear: null
-      } as any,
-      popSelectOptions: [] as any,
-      popSelectYearList: [] as any,
-      popSelectLevelList: [] as any,
-      showGuide: false,
-      showPreview: false,
-      itemPreview: {} as any,
-      homeLeftHeight: 'auto'
-    });
-    const teachList = ref({} as any);
-
-    // 获取年级班级
-    const getClassList = async () => {
-      try {
-        const { data } = await classGroupList({
-          gradeLevel: forms.classSelect.gradeLevel,
-          gradeYear: forms.classSelect.gradeYear
-        });
-        const cList = data || [];
-        const gradeList: any = [];
-        const popSelectOptions: any = [];
-        // getLastClassRecode()
-        cList.forEach((item: any, index: number) => {
-          // 判断是否已经有班级了
-          if (index === 0) {
-            if (forms.lastClassSelect.currentClass) {
-              forms.classSelect.currentClass =
-                forms.lastClassSelect.currentClass;
-              forms.classSelect.name = forms.lastClassSelect.name;
-              forms.classSelect.upgradeFlag = forms.lastClassSelect.upgradeFlag;
-            } else {
-              const temp = item.classGroupList[0];
-              forms.classSelect.currentGradeNum = item.currentGradeNum;
-              forms.classSelect.currentClass = temp.id;
-              forms.classSelect.name = temp.name;
-            }
-          }
-
-          const classList: any = [];
-          item.classGroupList.forEach((i: any) => {
-            classList.push({
-              label: i.currentClass + '班',
-              value: i.id,
-              lastStudy: i.lastStudy
-            });
-
-            popSelectOptions.push({
-              label: i.name,
-              value: i.id,
-              currentGradeNum: item.currentGradeNum,
-              lastStudy: i.lastStudy
-            });
-          });
-
-          gradeList.push({
-            label: gradeToCN[item.currentGradeNum],
-            value: item.currentGradeNum,
-            childrens: classList
-          });
-        });
-        forms.popSelectOptions = popSelectOptions;
-        forms.gradeList = gradeList;
-      } catch {
-        //
-      }
-    };
-    const getLastClassRecode = async () => {
-      const { data } = await courseSchedulePage({
-        page: 1,
-        rows: 1,
-        teacherId: userStore.getUserInfo.id
-      });
-      if (data.rows.length > 0 && data.rows[0]) {
-        const tempRow = data.rows[0];
-        // forms.lastClassSelect.currentClass = tempRow.classGroupId;
-        // forms.lastClassSelect.name = tempRow.classGroupName;
-        forms.lastClassSelect = {
-          currentClass: tempRow.classGroupId,
-          name: tempRow.classGroupName,
-          upgradeFlag: tempRow.upgradeFlag,
-          gradeYear: tempRow.gradeYear + '',
-          gradeLevel: tempRow.gradeLevel + ''
-        };
-      }
-    };
-
-    // 获取学年
-    const getYearList = async () => {
-      try {
-        const { data } = await getGradeYearList();
-        const temp = data || [];
-        temp.forEach((i: any) => {
-          i.name = i.name + '学年';
-        });
-        forms.popSelectYearList = temp || [];
-        if (temp.length > 0) {
-          if (forms.lastClassSelect.gradeYear) {
-            forms.classSelect.gradeYear = forms.lastClassSelect.gradeYear;
-          } else {
-            forms.classSelect.gradeYear = temp[0].id;
-          }
-        }
-      } catch (e: any) {
-        //
-      }
-    };
-    // 获取学级
-    const getLevelList = async () => {
-      try {
-        const { data } = await getGradeLevelList();
-        const temp = data || [];
-        temp.forEach((i: any) => {
-          i.name = i.name + '级';
-        });
-        temp.unshift({
-          id: '',
-          name: '全部学级'
-        });
-        forms.popSelectLevelList = temp || [];
-        if (temp.length > 0) {
-          if (forms.lastClassSelect.gradeLevel) {
-            forms.classSelect.gradeLevel =
-              forms.lastClassSelect.gradeLevel + '';
-          } else {
-            forms.classSelect.gradeLevel = temp[0].id;
-          }
-        }
-      } catch {
-        //
-      }
-    };
-
-    const getCourseSchedulePage = async () => {
-      forms.classLoading = true;
-      try {
-        const { data } = await courseSchedulePage({
-          classGroupId: forms.classSelect.currentClass,
-          gradeLevel: forms.classSelect.gradeLevel,
-          gradeYear: forms.classSelect.gradeYear,
-          page: 1,
-          rows: 4,
-          teacherId: userStore.getUserInfo.id
-        });
-
-        const result = data.rows || [];
-        forms.total = data.total || 0;
-        const dateTime: any = {};
-        result.forEach((item: any) => {
-          const tempTime = dayjs(item.classDate).format('MM-DD');
-          if (!dateTime[tempTime]) {
-            dateTime[tempTime] = [];
-          }
-
-          const lessonCourseware = item.lessonCoursewareJson
-            ? JSON.parse(item.lessonCoursewareJson)
-            : {};
-          dateTime[tempTime].push({
-            classGroup: forms.classSelect.name,
-            teacherName: item.teacherName,
-            conent:
-              lessonCourseware.lessonCoursewareName +
-              ' | ' +
-              lessonCourseware.lessonCoursewareDetailName +
-              ' | ' +
-              lessonCourseware.lessonCoursewareKnowledgeDetailName +
-              ' | ' +
-              (lessonCourseware.useChapterLessonCoursewareName || ''),
-            image: item.teacherAvatar,
-            subjectName: item.instrumentName
-          });
-        });
-
-        teachList.value = dateTime;
-      } catch (e: any) {
-        //
-        console.log(e);
-      }
-
-      forms.classLoading = false;
-    };
-
-    onMounted(async () => {
-      forms.classLoading = true;
-      await getLastClassRecode();
-
-      await getYearList();
-      await getLevelList();
-      await getClassList();
-      // await catchStore.getSubjects();
-
-      await getCourseSchedulePage();
-      forms.classLoading = false;
-    });
-    return () => (
-      <div>
-        <div class={styles.rightTeachingWrap}>
-          <div class={styles.rightTeachingWrapTitle}>
-            <div class={styles.classSearchList}>
-              <NSelect
-                v-model:value={forms.classSelect.gradeYear}
-                class={styles.lookMoreSearch}
-                placeholder="全部学年"
-                options={forms.popSelectYearList}
-                labelField="name"
-                valueField="id"
-                onUpdate:value={async (val: any) => {
-                  forms.classSelect.gradeYear = val;
-                  forms.lastClassSelect.currentClass = null;
-                  forms.classSelect.currentClass = null;
-                  await getClassList();
-                  await getCourseSchedulePage();
-                }}></NSelect>
-              <NSelect
-                v-model:value={forms.classSelect.gradeLevel}
-                class={styles.lookMoreSearch}
-                placeholder="全部学级"
-                options={forms.popSelectLevelList}
-                labelField="name"
-                valueField="id"
-                onUpdate:value={async (val: any) => {
-                  forms.classSelect.gradeLevel = val;
-                  forms.lastClassSelect.currentClass = null;
-                  forms.classSelect.currentClass = null;
-                  await getClassList();
-                  await getCourseSchedulePage();
-                }}></NSelect>
-              <NSelect
-                v-model:value={forms.classSelect.currentClass}
-                class={styles.lookMoreSearch}
-                placeholder="选择班级"
-                options={forms.popSelectOptions}
-                onUpdate:value={(val: any) => {
-                  forms.popSelectOptions.forEach((item: any) => {
-                    if (item.value === val) {
-                      forms.classSelect.currentGradeNum = item.currentGradeNum;
-                      forms.classSelect.currentClass = item.value;
-                      forms.classSelect.name = item.label;
-                      forms.classSelect.upgradeFlag = item.upgradeFlag;
-                      getCourseSchedulePage();
-                    }
-                  });
-                }}></NSelect>
-            </div>
-          </div>
-          <NSpin show={forms.classLoading} style={{ minHeight: '40vh' }}>
-            {Object.keys(teachList.value).length > 0 && (
-              <div class={styles.teachListWrap}>
-                {Object.keys(teachList.value).map(key => (
-                  <TeachGroup
-                    list={teachList.value[key]}
-                    keys={key}></TeachGroup>
-                ))}
-              </div>
-            )}
-
-            {Object.keys(teachList.value).length <= 0 &&
-              !forms.classLoading && <TheEmpty />}
-          </NSpin>
-
-          {forms.total > 4 && (
-            <div class={styles.teachListWrapWall}>
-              <span
-                onClick={() => {
-                  // setTabsCaches('attendclass', 'tabName', {
-                  //   path: '/classDetail'
-                  // });
-                  emit('confirm');
-                  sessionStorage.setItem('classDetailTabs', 'attendclass');
-                  router.push({
-                    path: '/classDetail',
-                    query: {
-                      name: forms.classSelect.name,
-                      id: forms.classSelect.currentClass,
-                      gradeYear: forms.classSelect.gradeYear,
-                      upgradeFlag: forms.classSelect.upgradeFlag ? 1 : 0, // 是否为历史班
-                      v: +new Date()
-                    }
-                  });
-                }}>
-                查看全部
-              </span>
-            </div>
-          )}
-        </div>
-      </div>
-    );
-  }
-});
+import { defineComponent, onMounted, reactive, ref } from 'vue';
+import styles from './index.module.less';
+import { useUserStore } from '/src/store/modules/users';
+import { useRouter } from 'vue-router';
+import { NSelect, NSpin } from 'naive-ui';
+import {
+  classGroupList,
+  courseSchedulePage,
+  getGradeLevelList,
+  getGradeYearList
+} from '../../api';
+import dayjs from 'dayjs';
+import TeachGroup from '../teachGroup';
+import TheEmpty from '/src/components/TheEmpty';
+import { gradeToCN } from '/src/utils/contants';
+
+export default defineComponent({
+  name: 'class-modal',
+  emits: ['confirm'],
+  setup(props, { emit }) {
+    const router = useRouter();
+    const userStore = useUserStore();
+    const forms = reactive({
+      showAttendClass: false,
+      // useStatus: false,
+      studentList: [] as any,
+      bookVersionId: null,
+      classGroupId: null,
+      category: null,
+      subjectId: null,
+      musicTagList: [] as any,
+      loading: false,
+      list: [] as any,
+      unit: null,
+      unitList: [],
+      subjectList: [] as any,
+      gradeList: [] as any,
+      classLoading: false,
+      total: 0, // 上课数量
+      // 上次上课的数据
+      lastClassSelect: {
+        currentClass: null,
+        name: '',
+        upgradeFlag: false, // 是否为历史班
+        gradeYear: null as any,
+        gradeLevel: null as any
+      },
+      classSelect: {
+        currentGradeNum: null,
+        currentClass: null,
+        name: '',
+        upgradeFlag: false, // 是否为历史班
+        gradeLevel: null as any,
+        gradeYear: null
+      } as any,
+      popSelectOptions: [] as any,
+      popSelectYearList: [] as any,
+      popSelectLevelList: [] as any,
+      showGuide: false,
+      showPreview: false,
+      itemPreview: {} as any,
+      homeLeftHeight: 'auto'
+    });
+    const teachList = ref({} as any);
+
+    // 获取年级班级
+    const getClassList = async () => {
+      try {
+        const { data } = await classGroupList({
+          gradeLevel: forms.classSelect.gradeLevel,
+          gradeYear: forms.classSelect.gradeYear
+        });
+        const cList = data || [];
+        const gradeList: any = [];
+        const popSelectOptions: any = [];
+        // getLastClassRecode()
+        cList.forEach((item: any, index: number) => {
+          // 判断是否已经有班级了
+          if (index === 0) {
+            if (forms.lastClassSelect.currentClass) {
+              forms.classSelect.currentClass =
+                forms.lastClassSelect.currentClass;
+              forms.classSelect.name = forms.lastClassSelect.name;
+              forms.classSelect.upgradeFlag = forms.lastClassSelect.upgradeFlag;
+            } else {
+              const temp = item.classGroupList[0];
+              forms.classSelect.currentGradeNum = item.currentGradeNum;
+              forms.classSelect.currentClass = temp.id;
+              forms.classSelect.name = temp.name;
+            }
+          }
+
+          const classList: any = [];
+          item.classGroupList.forEach((i: any) => {
+            classList.push({
+              label: i.currentClass + '班',
+              value: i.id,
+              lastStudy: i.lastStudy
+            });
+
+            popSelectOptions.push({
+              label: i.name,
+              value: i.id,
+              currentGradeNum: item.currentGradeNum,
+              lastStudy: i.lastStudy
+            });
+          });
+
+          gradeList.push({
+            label: gradeToCN[item.currentGradeNum],
+            value: item.currentGradeNum,
+            childrens: classList
+          });
+        });
+        forms.popSelectOptions = popSelectOptions;
+        forms.gradeList = gradeList;
+      } catch {
+        //
+      }
+    };
+    const getLastClassRecode = async () => {
+      const { data } = await courseSchedulePage({
+        page: 1,
+        rows: 1,
+        teacherId: userStore.getUserInfo.id
+      });
+      if (data.rows.length > 0 && data.rows[0]) {
+        const tempRow = data.rows[0];
+        // forms.lastClassSelect.currentClass = tempRow.classGroupId;
+        // forms.lastClassSelect.name = tempRow.classGroupName;
+        forms.lastClassSelect = {
+          currentClass: tempRow.classGroupId,
+          name: tempRow.classGroupName,
+          upgradeFlag: tempRow.upgradeFlag,
+          gradeYear: tempRow.gradeYear + '',
+          gradeLevel: tempRow.gradeLevel + ''
+        };
+      }
+    };
+
+    // 获取学年
+    const getYearList = async () => {
+      try {
+        const { data } = await getGradeYearList();
+        const temp = data || [];
+        temp.forEach((i: any) => {
+          i.name = i.name + '学年';
+        });
+        forms.popSelectYearList = temp || [];
+        if (temp.length > 0) {
+          if (forms.lastClassSelect.gradeYear) {
+            forms.classSelect.gradeYear = forms.lastClassSelect.gradeYear;
+          } else {
+            forms.classSelect.gradeYear = temp[0].id;
+          }
+        }
+      } catch (e: any) {
+        //
+      }
+    };
+    // 获取学级
+    const getLevelList = async () => {
+      try {
+        const { data } = await getGradeLevelList();
+        const temp = data || [];
+        temp.forEach((i: any) => {
+          i.name = i.name + '级';
+        });
+        temp.unshift({
+          id: '',
+          name: '全部学级'
+        });
+        forms.popSelectLevelList = temp || [];
+        if (temp.length > 0) {
+          if (forms.lastClassSelect.gradeLevel) {
+            forms.classSelect.gradeLevel =
+              forms.lastClassSelect.gradeLevel + '';
+          } else {
+            forms.classSelect.gradeLevel = temp[0].id;
+          }
+        }
+      } catch {
+        //
+      }
+    };
+
+    const getCourseSchedulePage = async () => {
+      forms.classLoading = true;
+      try {
+        const { data } = await courseSchedulePage({
+          classGroupId: forms.classSelect.currentClass,
+          gradeLevel: forms.classSelect.gradeLevel,
+          gradeYear: forms.classSelect.gradeYear,
+          page: 1,
+          rows: 4,
+          teacherId: userStore.getUserInfo.id
+        });
+
+        const result = data.rows || [];
+        forms.total = data.total || 0;
+        const dateTime: any = {};
+        result.forEach((item: any) => {
+          const tempTime = dayjs(item.classDate).format('MM-DD');
+          if (!dateTime[tempTime]) {
+            dateTime[tempTime] = [];
+          }
+
+          const lessonCourseware = item.lessonCoursewareJson
+            ? JSON.parse(item.lessonCoursewareJson)
+            : {};
+          dateTime[tempTime].push({
+            classGroup: forms.classSelect.name,
+            teacherName: item.teacherName,
+            conent:
+              lessonCourseware.lessonCoursewareName +
+              ' | ' +
+              lessonCourseware.lessonCoursewareDetailName +
+              ' | ' +
+              lessonCourseware.lessonCoursewareKnowledgeDetailName +
+              ' | ' +
+              (lessonCourseware.useChapterLessonCoursewareName || ''),
+            image: item.teacherAvatar,
+            subjectName: item.instrumentName
+          });
+        });
+
+        teachList.value = dateTime;
+      } catch (e: any) {
+        //
+        console.log(e);
+      }
+
+      forms.classLoading = false;
+    };
+
+    onMounted(async () => {
+      forms.classLoading = true;
+      await getLastClassRecode();
+
+      await getYearList();
+      await getLevelList();
+      await getClassList();
+      // await catchStore.getSubjects();
+
+      await getCourseSchedulePage();
+      forms.classLoading = false;
+    });
+    return () => (
+      <div>
+        <div class={styles.rightTeachingWrap}>
+          <div class={styles.rightTeachingWrapTitle}>
+            <div class={styles.classSearchList}>
+              <NSelect
+                v-model:value={forms.classSelect.gradeYear}
+                class={styles.lookMoreSearch}
+                placeholder="全部学年"
+                options={forms.popSelectYearList}
+                labelField="name"
+                valueField="id"
+                onUpdate:value={async (val: any) => {
+                  forms.classSelect.gradeYear = val;
+                  forms.lastClassSelect.currentClass = null;
+                  forms.classSelect.currentClass = null;
+                  await getClassList();
+                  await getCourseSchedulePage();
+                }}></NSelect>
+              <NSelect
+                v-model:value={forms.classSelect.gradeLevel}
+                class={styles.lookMoreSearch}
+                placeholder="全部学级"
+                options={forms.popSelectLevelList}
+                labelField="name"
+                valueField="id"
+                onUpdate:value={async (val: any) => {
+                  forms.classSelect.gradeLevel = val;
+                  forms.lastClassSelect.currentClass = null;
+                  forms.classSelect.currentClass = null;
+                  await getClassList();
+                  await getCourseSchedulePage();
+                }}></NSelect>
+              <NSelect
+                v-model:value={forms.classSelect.currentClass}
+                class={styles.lookMoreSearch}
+                placeholder="选择班级"
+                options={forms.popSelectOptions}
+                onUpdate:value={(val: any) => {
+                  forms.popSelectOptions.forEach((item: any) => {
+                    if (item.value === val) {
+                      forms.classSelect.currentGradeNum = item.currentGradeNum;
+                      forms.classSelect.currentClass = item.value;
+                      forms.classSelect.name = item.label;
+                      forms.classSelect.upgradeFlag = item.upgradeFlag;
+                      getCourseSchedulePage();
+                    }
+                  });
+                }}></NSelect>
+            </div>
+          </div>
+          <NSpin show={forms.classLoading} style={{ minHeight: '40vh' }}>
+            {Object.keys(teachList.value).length > 0 && (
+              <div class={styles.teachListWrap}>
+                {Object.keys(teachList.value).map(key => (
+                  <TeachGroup
+                    list={teachList.value[key]}
+                    keys={key}></TeachGroup>
+                ))}
+              </div>
+            )}
+
+            {Object.keys(teachList.value).length <= 0 &&
+              !forms.classLoading && (
+                <div class={styles.emptySection}>
+                  <TheEmpty />
+                </div>
+              )}
+          </NSpin>
+
+          {forms.total > 4 && (
+            <div class={styles.teachListWrapWall}>
+              <span
+                onClick={() => {
+                  // setTabsCaches('attendclass', 'tabName', {
+                  //   path: '/classDetail'
+                  // });
+                  emit('confirm');
+                  sessionStorage.setItem('classDetailTabs', 'attendclass');
+                  router.push({
+                    path: '/classDetail',
+                    query: {
+                      name: forms.classSelect.name,
+                      id: forms.classSelect.currentClass,
+                      gradeYear: forms.classSelect.gradeYear,
+                      upgradeFlag: forms.classSelect.upgradeFlag ? 1 : 0, // 是否为历史班
+                      v: +new Date()
+                    }
+                  });
+                }}>
+                查看全部
+              </span>
+            </div>
+          )}
+        </div>
+      </div>
+    );
+  }
+});

+ 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>
+    );
+  }
+});

+ 7 - 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
       },
@@ -127,7 +128,7 @@ export default defineComponent({
     };
 
     onMounted(() => {
-      getList();
+      // getList();
     });
     return () => (
       <>
@@ -149,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)}
                   />

+ 46 - 25
src/views/natural-resources/components/my-collect/search-group-resources.tsx

@@ -37,6 +37,7 @@ export default defineComponent({
     const onSearch = () => {
       emit('search', {
         ...forms,
+        subjectId: forms.audioPlayTypes !== 'SING' ? forms.subjectId : null,
         audioPlayTypes: forms.audioPlayTypes
           ? forms.audioPlayTypes === 'PLAY_SING'
             ? ['PLAY', 'SING']
@@ -101,6 +102,20 @@ 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 => {
@@ -129,6 +144,8 @@ export default defineComponent({
       //   // 默认隐藏
       //   getLive();
       // }
+      formatFirstSubject();
+      onSearch();
     });
     return () => (
       <div class={styles.searchGroup}>
@@ -143,9 +160,8 @@ export default defineComponent({
                 focusable={false}
                 onClick={() => {
                   forms.type = item.value;
-                  forms.subjectId = null;
-                  state.tempSubjectId = null;
                   forms.audioPlayTypes = '';
+                  formatFirstSubject();
                   onSearch();
 
                   nextTick(() => {
@@ -218,33 +234,38 @@ export default defineComponent({
               </NFormItem>
             </div>
           )} */}
-          <NFormItem label="场景:">
-            <NSpace class={styles.spaceSection}>
-              {data.audioPlayTypeList.map((subject: any) => (
-                <span
-                  class={[
-                    styles.textBtn,
+          {forms.type === 'MUSIC' && (
+            <NFormItem label="场景:">
+              <NSpace class={styles.spaceSection}>
+                {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 === subject.value &&
-                      styles.textBtnActive
-                  ]}
-                  onClick={() => {
-                    forms.audioPlayTypes = subject.value;
-                    if (subject.value === 'SING') {
-                      state.tempSubjectId = null;
-                      forms.subjectId = null;
-                    }
-                    onSearch();
-                  }}>
-                  {subject.name}
-                </span>
-              ))}
-            </NSpace>
-          </NFormItem>
           {forms.audioPlayTypes !== 'SING' && (
             <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}

+ 8 - 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
       },
@@ -179,7 +180,7 @@ export default defineComponent({
     };
     const searchGroupResourcesRef = ref();
     onMounted(() => {
-      getList();
+      // getList();
     });
     return () => (
       <>
@@ -306,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)}
                       />

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

@@ -43,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);
-        // }
       });
 
       // 获取声部列表
@@ -62,6 +71,8 @@ export default defineComponent({
       if (forms.subjectId) {
         state.tempSubjectId = forms.subjectId;
       }
+
+      formatFirstSubject();
     });
 
     const selectChildObj = (item: any) => {
@@ -100,10 +111,11 @@ export default defineComponent({
                   }
                   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>
@@ -208,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}

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

@@ -26,6 +26,7 @@ export default defineComponent({
         type: 'MUSIC', //
         name: '',
         audioPlayTypes: [] as any,
+        musicalInstrumentId: null,
         bookVersionId: null,
         subjectId: null,
         sourceType: 2
@@ -124,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)}
                     />
@@ -135,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)}
                     />

+ 44 - 25
src/views/natural-resources/components/share-resources/search-group-resources.tsx

@@ -139,6 +139,7 @@ export default defineComponent({
     const onSearch = () => {
       emit('search', {
         ...forms,
+        subjectId: forms.audioPlayTypes !== 'SING' ? forms.subjectId : null,
         audioPlayTypes: forms.audioPlayTypes
           ? forms.audioPlayTypes === 'PLAY_SING'
             ? ['PLAY', 'SING']
@@ -244,6 +245,19 @@ 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 => {
@@ -263,6 +277,7 @@ export default defineComponent({
       // 获取声部列表
       await catchStore.getSubjects();
 
+      formatFirstSubject();
       if (forms.type === 'MUSIC') {
         orginHeight.value = collapseWrapRef.value?.offsetHeight;
         // hiddenHeight.value = collapseWrapRef.value.offsetHeight / line.value;
@@ -285,13 +300,13 @@ export default defineComponent({
                 focusable={false}
                 onClick={() => {
                   forms.type = item.value;
-                  forms.subjectId = null;
                   forms.audioPlayTypes = '';
-                  state.tempSubjectId = null;
                   data.tagActiveId = '';
                   data.childSelectId = null;
                   data.selectParents = {};
 
+                  formatFirstSubject();
+
                   onSearch();
 
                   nextTick(() => {
@@ -354,34 +369,38 @@ export default defineComponent({
             </>
           )}
 
-          <NFormItem label="场景:">
-            <NSpace class={styles.spaceSection}>
-              {data.audioPlayTypeList.map((subject: any) => (
-                <span
-                  class={[
-                    styles.textBtn,
+          {forms.type === 'MUSIC' && (
+            <NFormItem label="场景:">
+              <NSpace class={styles.spaceSection}>
+                {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;
-                    }
-                    onSearch();
-                  }}>
-                  {subject.name}
-                </span>
-              ))}
-            </NSpace>
-          </NFormItem>
+                      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.getSubjectInstruments.map((subject: any) =>
+                {catchStore.getSubjectInstrumentOnly.map((subject: any) =>
                   subject.instruments && subject.instruments.length > 1 ? (
                     <NPopselect
                       options={subject.instruments}

+ 40 - 9
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();
         }
       }
 
@@ -249,10 +283,7 @@ export default defineComponent({
                     <TheNoticeBar text={prepareStore.getBaseCourseware.name} />
                   </h2>
                   <div class={styles.subjects}>
-                    <TheNoticeBar
-                      text={formatInstrumentNames.value}
-                      time={formatInstrumentNames.value.length > 15 ? 10 : 5}
-                    />
+                    <TheNoticeBar text={formatInstrumentNames.value} />
                   </div>
                   <div
                     class={styles.changeDir}

+ 2 - 2
src/views/prepare-lessons/components/directory-main/select-lessonware/index.module.less

@@ -200,7 +200,7 @@
 
   .itemName {
     margin-top: 16px;
-    font-size: 16px;
+    font-size: max(16px, 13Px);
     font-weight: 600;
     color: #131415;
     text-align: center;
@@ -245,4 +245,4 @@
       }
     }
   }
-}
+}

+ 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}>

+ 30 - 1
src/views/prepare-lessons/components/lesson-main/courseware/addCourseware.module.less

@@ -345,6 +345,7 @@
   gap: 20px 0;
 
 
+
   .itemWrap {
     width: calc(100% / 4);
     padding-bottom: calc(100% / 4 * 0.73333);
@@ -388,6 +389,34 @@
   }
 
   :global {
+    .itemWrap {
+      width: calc(100% / 4);
+      padding-bottom: calc(100% / 4 * 0.73333);
+      position: relative;
+
+      .itemWrapBox {
+        position: absolute;
+        left: 0;
+        top: 0;
+        width: 100%;
+        height: 100%;
+        padding: 0 6px;
+      }
+
+      .itemOperation {
+        position: absolute;
+        top: 8px;
+        right: 14px;
+        z-index: 98;
+      }
+
+      .iconDelete {
+        width: 27px;
+        height: 27px;
+        cursor: pointer;
+      }
+    }
+
     .card-section-container {
       width: 100%;
       height: 100%;
@@ -489,4 +518,4 @@
 
 .addOtherSource {
   width: 726px;
-}
+}

+ 116 - 39
src/views/prepare-lessons/components/lesson-main/courseware/addCourseware.tsx

@@ -415,6 +415,48 @@ export default defineComponent({
       });
     };
 
+    // 拖拽添加数据
+    const addDragCoursewareItem = async (item: any, newIndex: number) => {
+      clearTimeout(timer);
+      const materialList: any[] = [];
+      try {
+        const { data } = await api_materialDetail(item.materialId);
+        if (Array.isArray(data.materialRefs)) {
+          data.materialRefs.forEach((item: any) => {
+            if (item.refType === 'STRONG') {
+              const relateMaterialInfo = item.relateMaterialInfo || {};
+              materialList.push({
+                content: relateMaterialInfo.content,
+                coverImg: relateMaterialInfo.coverImg,
+                isSelected:
+                  relateMaterialInfo.sourceFrom === 'PLATFORM' ? true : false,
+                materialId: relateMaterialInfo.id,
+                title: relateMaterialInfo.name,
+                type: relateMaterialInfo.type
+              });
+            }
+          });
+        }
+      } catch {
+        //
+      }
+
+      nextTick(() => {
+        const array: any = forms.coursewareList[item.index || 0].list || [];
+        array[newIndex] = item;
+        materialList.forEach((m: any) => {
+          array.splice(newIndex + 1, 0, m);
+        });
+        forms.coursewareList[item.index || 0].list = array;
+
+        console.log(forms.coursewareList, 'courseware add drag');
+        timer = setTimeout(() => {
+          // 内容有更新 - 相关资源会刷新
+          eventGlobal.emit('onCoursewareUpdate');
+        }, 100);
+      });
+    };
+
     // 提交
     const onSubmit = async () => {
       try {
@@ -693,44 +735,44 @@ export default defineComponent({
               {forms.coursewareList.map((item: any, index: number) => (
                 <div
                   class={[styles.listItems, 'row-group']}
-                  onDragenter={(e: any) => {
-                    e.preventDefault();
-                  }}
-                  onDragover={(e: any) => {
-                    e.preventDefault();
-                  }}
-                  onDrop={(e: any) => {
-                    let dropItem = e.dataTransfer.getData('text');
-                    dropItem =
-                      dropItem && e.dataTransfer.effectAllowed === 'all'
-                        ? JSON.parse(dropItem)
-                        : {};
-                    // 判断是否有数据
-                    if (dropItem.id) {
-                      // 获取拖拽的目标元素
-                      eventGlobal.emit(
-                        'onPrepareAddItem',
-                        {
-                          materialId: dropItem.id,
-                          coverImg: dropItem.coverImg,
-                          type: dropItem.type,
-                          title: dropItem.title,
-                          refFlag: dropItem.refFlag,
-                          isCollect: dropItem.isCollect,
-                          isSelected: dropItem.isSelected,
-                          audioPlayTypeArray: dropItem.audioPlayTypeArray,
-                          content: dropItem.content,
-                          removeFlag: false,
-                          index,
-                          addType: 'drag'
-                        },
-                        {
-                          x: e.clientX,
-                          y: e.clientY
-                        }
-                      );
-                    }
-                  }}>
+                  // onDragenter={(e: any) => {
+                  //   e.preventDefault();
+                  // }}
+                  // onDragover={(e: any) => {
+                  //   e.preventDefault();
+                  // }}
+                  // onDrop={(e: any) => {
+                  //   let dropItem = e.dataTransfer.getData('text');
+                  //   dropItem =
+                  //     dropItem && e.dataTransfer.effectAllowed === 'all'
+                  //       ? JSON.parse(dropItem)
+                  //       : {};
+                  //   // 判断是否有数据
+                  //   if (dropItem.id) {
+                  //     // 获取拖拽的目标元素
+                  //     eventGlobal.emit(
+                  //       'onPrepareAddItem',
+                  //       {
+                  //         materialId: dropItem.id,
+                  //         coverImg: dropItem.coverImg,
+                  //         type: dropItem.type,
+                  //         title: dropItem.title,
+                  //         refFlag: dropItem.refFlag,
+                  //         isCollect: dropItem.isCollect,
+                  //         isSelected: dropItem.isSelected,
+                  //         content: dropItem.content,
+                  //         removeFlag: false,
+                  //         index,
+                  //         addType: 'drag'
+                  //       },
+                  //       {
+                  //         x: e.clientX,
+                  //         y: e.clientY
+                  //       }
+                  //     );
+                  //   }
+                  // }}
+                >
                   <div class={styles.knowledgePoint}>
                     {/* <div class={styles.btnItem}>
                       <span class={styles.btnTitle}>
@@ -809,6 +851,41 @@ export default defineComponent({
                     // scrollSensitivity={120}
                     // forceAutoScrollFallback={true}
                     animation={200}
+                    // onChange={(evt: any) => {
+                    //   const added = evt.added;
+                    //   // 是否为添加
+                    //   if (!added || (added && !added.element)) {
+                    //     return;
+                    //   }
+
+                    //   if (added.element.sourceForm !== 'resource-item') {
+                    //     return;
+                    //   }
+                    //   // console.log(forms.coursewareList, 'courseware');
+                    // }}
+                    onAdd={(evt: any) => {
+                      // console.log(
+                      const list = forms.coursewareList[index].list;
+                      const dropItem = list[evt.newDraggableIndex];
+                      console.log(dropItem, 'dropItem');
+                      if (dropItem.sourceForm === 'resource-item') {
+                        addDragCoursewareItem(
+                          {
+                            materialId: dropItem.id,
+                            coverImg: dropItem.coverImg,
+                            type: dropItem.type,
+                            title: dropItem.title,
+                            refFlag: dropItem.refFlag,
+                            isCollect: dropItem.isCollect,
+                            isSelected: dropItem.isSelected,
+                            content: dropItem.content,
+                            removeFlag: false,
+                            index
+                          },
+                          evt.newDraggableIndex
+                        );
+                      }
+                    }}
                     onDrag={(event: any) => {
                       // 修复滚动超出范围
                       const container: any = document.querySelector(
@@ -821,7 +898,6 @@ export default defineComponent({
                         window.innerHeight - event.clientY <
                         sensitivity
                       ) {
-                        console.log('1111');
                         container.scrollTop += 8;
                       }
                     }}
@@ -855,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>
+    );
+  }
+});

+ 124 - 23
src/views/prepare-lessons/components/resource-main/components/resource-item/index.tsx

@@ -17,6 +17,7 @@ import { useDebounceFn, useThrottleFn, useThrottle } from '@vueuse/core';
 import { saveCourseware } from '/src/views/prepare-lessons/api';
 import CardPreview from '/src/components/card-preview';
 import { eventGlobal } from '/src/utils';
+import Draggable from 'vuedraggable';
 
 const formatType = (type: string) => {
   if (type === 'shareResources') {
@@ -39,7 +40,7 @@ export default defineComponent({
       default: 'relateResources'
     }
   },
-  setup(props) {
+  setup(props, { expose }) {
     const prepareStore = usePrepareStore();
     const message = useMessage();
     const dialog = useDialog();
@@ -96,10 +97,11 @@ export default defineComponent({
             refFlag: row.refFlag,
             isSelected: row.sourceFrom === 'PLATFORM' ? true : false,
             containAccompaniment: row.containAccompaniment,
+            content: row.content,
+            sourceForm: 'resource-item',
             audioPlayTypeArray: row.audioPlayTypes
               ? row.audioPlayTypes.split(',')
-              : [],
-            content: row.content
+              : []
             // exist: index !== -1 ? true : false // 是否存在
           });
         });
@@ -128,7 +130,7 @@ export default defineComponent({
       state.tableList = [];
       state.searchGroup = Object.assign(state.searchGroup, item);
       getList();
-    }, 500);
+    }, 300);
 
     // 声部变化时
     watch(
@@ -207,6 +209,15 @@ export default defineComponent({
     onUnmounted(() => {
       eventGlobal.off('onCoursewareUpdate', onUpdate);
     });
+
+    const getParams = () => {
+      return state.searchGroup;
+    };
+
+    expose({
+      getParams
+    });
+
     return () => (
       <div>
         <ResourceSearchGroup
@@ -248,25 +259,115 @@ export default defineComponent({
                   : ''
               ]}>
               {state.tableList.length > 0 && (
-                <div class={styles.list}>
-                  {state.tableList.map((item: any) => (
-                    <CardType
-                      isShowAdd
-                      item={item}
-                      isShowCollect={true}
-                      draggable
-                      disabledMouseHover={false}
-                      onClick={() => {
-                        if (item.type === 'IMG') return;
-                        state.show = true;
-                        state.item = item;
-                      }}
-                      onCollect={(item: any) => onCollect(item)}
-                      // isShowAddDisabled={!prepareStore.getIsEditResource}
-                      onAdd={(item: any) => onAdd(item)}
-                    />
-                  ))}
-                </div>
+                <Draggable
+                  v-model:modelValue={state.tableList}
+                  itemKey="id"
+                  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+                  // @ts-ignore
+                  // group="description"
+                  group={{ name: 'description', pull: 'clone', put: false }}
+                  animation={200}
+                  sort={false}
+                  onMove={(evt: any) => {
+                    // console.log(evt, 'evt', evt.from !== evt.to);
+                    return evt.from !== evt.to;
+                  }}
+                  componentData={{
+                    draggable: 'row-nav',
+                    itemKey: 'id',
+                    tag: 'div',
+                    pull: 'clone',
+                    put: false,
+                    animation: 200,
+                    group: 'description'
+                  }}
+                  class={styles.list}>
+                  {{
+                    item: (element: any) => {
+                      const item = element.element;
+                      return (
+                        <div
+                          data-id={item.id}
+                          class={['itemWrap', 'itemBlock', 'row-nav']}>
+                          <div class={'itemWrapBox'}>
+                            <CardType
+                              isShowAdd
+                              item={item}
+                              isShowCollect={true}
+                              draggable={false}
+                              disabledMouseHover={false}
+                              onClick={() => {
+                                if (item.type === 'IMG') return;
+                                state.show = true;
+                                state.item = {
+                                  instrumentId:
+                                    state.searchGroup.musicalInstrumentId ||
+                                    null,
+                                  ...item
+                                };
+                              }}
+                              onCollect={(item: any) => onCollect(item)}
+                              // isShowAddDisabled={!prepareStore.getIsEditResource}
+                              onAdd={(item: any) => onAdd(item)}
+                            />
+                          </div>
+                        </div>
+                        // <div
+                        //   data-id={item.id}
+                        //   class={[
+                        //     styles.itemWrap,
+                        //     styles.itemBlock,
+                        //     'row-nav'
+                        //   ]}>
+                        //   <div class={styles.itemWrapBox}>
+                        //     <CardType
+                        //       class={[styles.itemContent]}
+                        //       isShowCollect={false}
+                        //       offShelf={item.removeFlag ? true : false}
+                        //       // onOffShelf={() => onRemove(item)}
+                        //       item={item}
+                        //       disabledMouseHover={false}
+                        //       onClick={() => {
+                        //         if (item.type === 'IMG') return;
+                        //         forms.show = true;
+                        //         forms.item = item;
+                        //       }}
+                        //     />
+                        //     <div class={styles.itemOperation}>
+                        //       <img
+                        //         src={iconDelete}
+                        //         class={styles.iconDelete}
+                        //         onClick={(e: MouseEvent) => {
+                        //           e.stopPropagation();
+                        //           onDelete(element.index, index);
+                        //         }}
+                        //       />
+                        //     </div>
+                        //   </div>
+                        // </div>
+                      );
+                    }
+                  }}
+                </Draggable>
+                // <div class={styles.list}>
+                //   {state.tableList.map((item: any) => (
+                //     <CardType
+                //       isShowAdd
+                //       item={item}
+                //       isShowCollect={true}
+                //       draggable
+                //       disabledMouseHover={false}
+                //       onClick={() => {
+                //         if (item.type === 'IMG') return;
+                //         state.show = true;
+                //         state.item = item;
+                //       }}
+                //       onCollect={(item: any) => onCollect(item)}
+                //       // isShowAddDisabled={!prepareStore.getIsEditResource}
+                //       onAdd={(item: any) => onAdd(item)}
+                //     />
+                //   ))}
+                // </div>
               )}
               {!state.loading && state.tableList.length <= 0 && <TheEmpty />}
             </div>

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

@@ -146,6 +146,7 @@ export default defineComponent({
             )}
             <CCascader
               placeholder="全部声部"
+              childShowAllCheck={false}
               showPath
               showAudioPlayType={props.type === 'myResources' ? false : true}
               v-model:value={subjects.value}

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

@@ -305,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}

+ 32 - 6
src/views/prepare-lessons/components/resource-main/index.tsx

@@ -45,8 +45,14 @@ export default defineComponent({
       selectMusicStatus: false,
       selectResourceStatus: false,
       editStatus: false,
-      editItem: {} as any
+      editItem: {} as any,
+      searchGroup: {} as any
     });
+    const relateResourcesRef = ref();
+    const shareResourcesRef = ref();
+    const myResourcesRef = ref();
+    const myCollectRef = ref();
+
     const tabRef = ref();
     const workRef = ref();
 
@@ -156,6 +162,17 @@ export default defineComponent({
                 <div
                   class={styles.iconScreen}
                   onClick={() => {
+                    let searchGroup: any = {};
+                    if (forms.tabType === 'relateResources') {
+                      searchGroup = relateResourcesRef.value?.getParams();
+                    } else if (forms.tabType === 'shareResources') {
+                      searchGroup = shareResourcesRef.value?.getParams();
+                    } else if (forms.tabType === 'myResources') {
+                      searchGroup = myResourcesRef.value?.getParams();
+                    } else if (forms.tabType === 'myCollect') {
+                      searchGroup = myCollectRef.value?.getParams();
+                    }
+                    forms.searchGroup = searchGroup;
                     forms.selectResourceStatus = true;
                     prepareStore.setSelectResourceStatus(true);
                   }}>
@@ -171,21 +188,27 @@ export default defineComponent({
               default: () => (
                 <>
                   <NTabPane name="relateResources" tab="相关资源">
-                    <ResourceItem type="relateResources" />
+                    <ResourceItem
+                      type="relateResources"
+                      ref={relateResourcesRef}
+                    />
                   </NTabPane>
                   <NTabPane
                     name="shareResources"
                     tab="共享资源"
                     // displayDirective="show:lazy"
                   >
-                    <ResourceItem type="shareResources" />
+                    <ResourceItem
+                      type="shareResources"
+                      ref={shareResourcesRef}
+                    />
                   </NTabPane>
                   <NTabPane
                     name="myResources"
                     tab="我的资源"
                     // displayDirective="show:lazy"
                   >
-                    <ResourceItem type="myResources" />
+                    <ResourceItem type="myResources" ref={myResourcesRef} />
                   </NTabPane>
 
                   <NTabPane
@@ -193,7 +216,7 @@ export default defineComponent({
                     tab="我的收藏"
                     // displayDirective="show:lazy"
                   >
-                    <ResourceItem type="myCollect" />
+                    <ResourceItem type="myCollect" ref={myCollectRef} />
                   </NTabPane>
                 </>
               )
@@ -265,7 +288,10 @@ export default defineComponent({
           class={['modalTitle', styles.selectMusicModal]}
           preset="card"
           title={'选择资源'}>
-          <SelectResources type={forms.tabType} />
+          <SelectResources
+            type={forms.tabType}
+            searchGroup={forms.searchGroup}
+          />
         </NModal>
 
         <NModal

+ 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('');

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

@@ -134,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) => {
@@ -225,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}

+ 32 - 4
src/views/prepare-lessons/model/select-resources/index.tsx

@@ -12,10 +12,18 @@ export default defineComponent({
       type: String,
       default: 'myResources'
     },
+    searchGroup: {
+      type: Object,
+      default: () => ({})
+    },
     /** 从哪里使用 */
     from: {
       type: String,
       default: ''
+    },
+    instrumentId: {
+      type: String,
+      default: ''
     }
   },
   emits: ['select'],
@@ -57,22 +65,42 @@ export default defineComponent({
           }}>
           {props.from !== 'class' && (
             <NTabPane name="relateResources" tab={'相关资源'}>
-              <SelectItem type="relateResources" from={props.from} />
+              <SelectItem
+                type="relateResources"
+                searchGroup={props.searchGroup}
+                from={props.from}
+                instrumentId={props.instrumentId}
+              />
             </NTabPane>
           )}
           <NTabPane
             name="shareResources"
             tab={props.from === 'class' ? '共享曲目' : '共享资源'}>
-            <SelectItem type="shareResources" from={props.from} />
+            <SelectItem
+              type="shareResources"
+              from={props.from}
+              searchGroup={props.searchGroup}
+              instrumentId={props.instrumentId}
+            />
           </NTabPane>
           <NTabPane
             name="myResources"
             tab={props.from === 'class' ? '我的曲目' : '我的资源'}>
-            <SelectItem type="myResources" from={props.from} />
+            <SelectItem
+              type="myResources"
+              from={props.from}
+              searchGroup={props.searchGroup}
+              instrumentId={props.instrumentId}
+            />
           </NTabPane>
 
           <NTabPane name="myCollect" tab="我的收藏">
-            <SelectItem type="myCollect" from={props.from} />
+            <SelectItem
+              type="myCollect"
+              from={props.from}
+              searchGroup={props.searchGroup}
+              instrumentId={props.instrumentId}
+            />
           </NTabPane>
         </NTabs>
       </div>

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

@@ -57,15 +57,20 @@ export default defineComponent({
     const resourceType = ref([] as any);
     const audioPlayTypeList = ref([] as any);
 
-    const onSearch = () => {
-      emit('search', {
-        ...forms,
-        audioPlayTypes: forms.audioPlayTypes
-          ? forms.audioPlayTypes === 'PLAY_SING'
-            ? ['PLAY', 'SING']
-            : [forms.audioPlayTypes]
-          : []
-      });
+    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);
@@ -80,6 +85,19 @@ 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 => {
@@ -97,15 +115,25 @@ 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}>
@@ -128,9 +156,11 @@ export default defineComponent({
                     ]}
                     onClick={() => {
                       forms.audioPlayTypes = subject.value;
-                      if (subject.value === 'SING') {
-                        forms.subjectId = null;
-                      }
+                      // if (subject.value === 'SING') {
+                      //   forms.subjectId = null;
+                      // } else {
+                      //   formatFirstSubject();
+                      // }
                       onSearch();
                     }}>
                     {subject.name}
@@ -147,7 +177,7 @@ export default defineComponent({
                   styles.spaceSection2,
                   'spaceSectionBox'
                 ]}>
-                {catchStore.getSubjectInstruments.map((subject: any) =>
+                {catchStore.getSubjectInstrumentOnly.map((subject: any) =>
                   subject.instruments && subject.instruments.length > 1 ? (
                     <NPopselect
                       options={subject.instruments}

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

@@ -40,10 +40,18 @@ export default defineComponent({
       >,
       default: 'shareResources'
     },
+    searchGroup: {
+      type: Object,
+      default: () => ({})
+    },
     /** 从哪里使用 */
     from: {
       type: String,
       default: ''
+    },
+    instrumentId: {
+      type: String,
+      default: ''
     }
   },
   setup(props) {
@@ -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);
@@ -260,12 +268,21 @@ export default defineComponent({
               <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
                 type={props.type}
+                searchGroup={props.searchGroup}
                 onSearch={(item: any, type: any) => {
                   if (type) {
                     onSearch(item);
@@ -303,7 +320,11 @@ export default defineComponent({
                           onClick={() => {
                             if (item.type === 'IMG') return;
                             state.show = true;
-                            state.item = item;
+                            state.item = {
+                              instrumentId:
+                                state.searchGroup.musicalInstrumentId,
+                              ...item
+                            };
                           }}
                         />
                       </div>

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

@@ -46,9 +46,45 @@ const ChildNodeSearch = defineComponent({
       () => props.activeRow,
       () => {
         activeRow.value = props.activeRow;
-        selectItem.value = {};
+        initActiveRow();
       }
     );
+
+    const initActiveRow = () => {
+      if (activeRow.value.activeIndex) {
+        const childList = activeRow.value.children || [];
+        childList.forEach((subject: any) => {
+          if (subject.id === activeRow.value.activeIndex) {
+            let children: any;
+            let columnName = '';
+            if (subject.children) {
+              children = [
+                {
+                  columnName: subject.children[0].columnName,
+                  name: '全部',
+                  id: ''
+                },
+                ...subject.children
+              ];
+              columnName = subject.children[0].columnName;
+
+              selectItem.value = {
+                ...subject,
+                columnName,
+                activeIndex: subject.activeIndex,
+                children
+              };
+            }
+          }
+        });
+      } else {
+        selectItem.value = {};
+      }
+    };
+
+    onMounted(() => {
+      initActiveRow();
+    });
     return () => (
       <>
         {activeRow.value?.id && (
@@ -116,6 +152,10 @@ export default defineComponent({
       >,
       default: 'shareResources'
     },
+    searchGroup: {
+      type: Object,
+      default: () => ({})
+    },
     subjectId: {
       type: String,
       default: null
@@ -155,6 +195,7 @@ export default defineComponent({
         'search',
         {
           ...forms,
+          subjectId: forms.audioPlayTypes !== 'SING' ? forms.subjectId : null,
           audioPlayTypes: forms.audioPlayTypes
             ? forms.audioPlayTypes === 'PLAY_SING'
               ? ['PLAY', 'SING']
@@ -175,15 +216,15 @@ export default defineComponent({
     const line = ref(0);
     const isCollapse = ref(false);
     const loadingCollapse = ref(false); // 是否加载完成
-    const musicCateRef = (el: any) => {
-      if (el?.selfElRef) {
-        divDomList.value.push(el.selfElRef.parentNode);
-      }
-    };
-    const setCollapse = (flag: boolean) => {
-      isCollapse.value = flag;
-      getLive();
-    };
+    // const musicCateRef = (el: any) => {
+    //   if (el?.selfElRef) {
+    //     divDomList.value.push(el.selfElRef.parentNode);
+    //   }
+    // };
+    // const setCollapse = (flag: boolean) => {
+    //   isCollapse.value = flag;
+    //   getLive();
+    // };
     const getLive = () => {
       try {
         divDomList.value = [...new Set(divDomList.value)];
@@ -267,6 +308,75 @@ 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;
+        }
+      }
+    };
+
+    // const mapList: any = new Map();
+    const formatParentId = (id: any, list: any, ids = [] as any) => {
+      for (const item of list) {
+        if (item.children && item.children.length > 0) {
+          const cIds: any = formatParentId(id, item.children, [
+            ...ids,
+            item.id
+          ]);
+          if (cIds.includes(id)) {
+            return cIds;
+          }
+        }
+        if (item.id === id) {
+          return [...ids, id];
+        }
+        // mapList[item.id] = item.parentTagId;
+        // mapList.push()
+      }
+      return ids;
+    };
+
+    const formatParentCurrentValue = (ids: any, list: any) => {
+      for (const item of list) {
+        if (ids.includes(item.id)) {
+          if (item.children && item.children.length > 0) {
+            let lastId: any;
+            item.children.forEach((child: any) => {
+              if (ids.includes(child.id)) {
+                lastId = child.id;
+              }
+            });
+            item.activeIndex = lastId;
+          }
+        }
+        if (item.children && item.children.length > 0) {
+          formatParentCurrentValue(ids, item.children);
+        }
+      }
+    };
+
+    const formatParentresetValue = (list: any) => {
+      for (const item of list) {
+        if (item.children && item.children.length > 0) {
+          // item.children.forEach(() => {
+          //   item.activeIndex = '';
+          // });
+        }
+        item.activeIndex = '';
+
+        if (item.children && item.children.length > 0) {
+          formatParentresetValue(item.children);
+        }
+      }
+    };
+
     onMounted(async () => {
       // 场景
       const tempAudio = Object.keys(audioPlayType).map(key => {
@@ -298,9 +408,64 @@ export default defineComponent({
         getLive();
       }
 
-      if (props.type === 'shareResources') {
-        onSearch('timer');
+      formatFirstSubject();
+      console.log(props.searchGroup, 'searchGroup - parent');
+      if (props.searchGroup.type) {
+        const tempSearchGroup = props.searchGroup;
+        forms.audioPlayTypes = tempSearchGroup?.audioPlayTypes
+          ? tempSearchGroup.audioPlayTypes.join('_')
+          : '';
+
+        if (tempSearchGroup.musicalInstrumentId) {
+          forms.subjectId = tempSearchGroup.musicalInstrumentId;
+        }
+
+        if (tempSearchGroup.bookVersionId) {
+          // forms.bookVersionId = tempSearchGroup.bookVersionId || '';
+          data.childSelectId = tempSearchGroup.bookVersionId;
+          let ids = formatParentId(data.childSelectId, data.tags);
+          console.log(ids, 'ids');
+          data.tagActiveId = ids[0];
+          const index = ids.findIndex((id: any) => id === data.childSelectId);
+          // console.log(index, 'id');
+          ids = ids.slice(0, index + 1);
+          formatParentCurrentValue(ids, data.tags);
+          data.tags.forEach((item: any) => {
+            if (item.id === data.tagActiveId) {
+              let children: any;
+              let columnName = '';
+              if (item.children) {
+                children = [
+                  {
+                    columnName: item.children[0].columnName,
+                    name: '全部',
+                    id: ''
+                  },
+                  ...item.children
+                ];
+                columnName = item.children[0].columnName;
+
+                let id: any;
+                item.children.forEach((item: any) => {
+                  if (ids.includes(item.id)) {
+                    id = item.id;
+                  }
+                });
+
+                data.selectParents = {
+                  ...item,
+                  columnName,
+                  activeIndex: id || '',
+                  children
+                };
+              } else {
+                data.selectParents = {};
+              }
+            }
+          });
+        }
       }
+      onSearch('timer');
     });
     return () => (
       <div class={styles.searchGroup}>
@@ -316,12 +481,13 @@ export default defineComponent({
                 onClick={() => {
                   forms.type = item.value;
                   forms.subjectId = null;
-
                   data.tagActiveId = '';
                   data.childSelectId = null;
                   data.selectParents = {};
                   forms.audioPlayTypes =
                     props.type === 'myResources' ? 'PLAY' : '';
+
+                  formatFirstSubject();
                   onSearch();
 
                   try {
@@ -400,10 +566,12 @@ export default defineComponent({
                     ]}
                     onClick={() => {
                       forms.audioPlayTypes = subject.value;
-                      if (subject.value === 'SING') {
-                        state.tempSubjectId = null;
-                        forms.subjectId = null;
-                      }
+                      // if (subject.value === 'SING') {
+                      //   state.tempSubjectId = null;
+                      //   forms.subjectId = null;
+                      // } else {
+                      //   formatFirstSubject();
+                      // }
                       onSearch();
                     }}>
                     {subject.name}
@@ -416,21 +584,7 @@ export default defineComponent({
           {forms.audioPlayTypes !== 'SING' && (
             <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) =>
+                {catchStore.getSubjectInstrumentOnly.map((subject: any) =>
                   subject.instruments && subject.instruments.length > 1 ? (
                     <NPopselect
                       options={subject.instruments}

+ 1 - 1
src/views/prepare-lessons/model/source-rhythm/index.tsx

@@ -15,7 +15,7 @@ export default defineComponent({
       userStore.getToken
     }&platform=modal`;
     if (/(localhost|192)/.test(location.host)) {
-      src = `http://192.168.3.220:9002/#/tempo-practice?v=${Date.now()}&Authorization=${
+      src = `http://localhost:9002/#/tempo-practice?v=${Date.now()}&Authorization=${
         userStore.getToken
       }&platform=modal`;
     }

+ 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>
+    );
+  }
+});

+ 13 - 7
src/views/setting/components/personInfo.tsx

@@ -26,6 +26,7 @@ import UploadFile from '/src/components/upload-file';
 import ForgotPassword from '../modal/forgotPassword';
 import { api_sysAreaQueryAllProvince } from '../api';
 import { modalClickMask } from '/src/state';
+import { teacherJobType } from '/src/utils/contants';
 export default defineComponent({
   name: 'setting-personInfo',
   setup() {
@@ -99,22 +100,22 @@ export default defineComponent({
               src={teacherForm.avatar || defultHeade}></NImage>
             <div
               // style={{ display: data.disabled ? 'none' : '' }}
-              class={[
-                styles.defultHeade,
-                styles.changeHead,
-                data.disabled ? styles.disalbedNone : styles.hoverNone
-              ]}>
+              class={[styles.defultHeade, styles.changeHead, styles.hoverNone]}>
               修改头像
               {data.uploadShow && (
                 <UploadFile
                   class={[styles.uploadFile]}
                   cropper
-                  onUpdate:fileList={val => {
+                  onUpdate:fileList={async val => {
                     teacherForm.avatar = val;
                     data.uploadShow = false;
                     setTimeout(() => {
                       data.uploadShow = true;
                     }, 100);
+
+                    await api_teacherUpdate(teacherForm);
+                    console.log(teacherForm);
+                    userStore.getInfo();
                   }}
                 />
               )}
@@ -123,11 +124,16 @@ export default defineComponent({
           <div class={styles.headerInfo}>
             <p class={styles.headerTitle}>
               {userStore.info.nickname}
-              {userStore.info.gender !== null && (
+              {/* {userStore.info.gender !== null && (
                 <NImage
                   previewDisabled
                   class={styles.sexIcon}
                   src={userStore.info.gender ? maleIcon : femaleIcon}></NImage>
+              )} */}
+              {userStore.info.teacherJobType && (
+                <span class={styles.roleType}>
+                  {teacherJobType[userStore.info.teacherJobType]}
+                </span>
               )}
             </p>
             <p class={styles.headerSubTitle}>

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

@@ -150,21 +150,21 @@
 }
 
 .addTeacher {
-  padding: 0;
-  border-radius: 16px;
-  overflow: hidden;
-  min-width: 456px;
+  // padding: 0;
+  // border-radius: 16px;
+  // overflow: hidden;
+  width: 556px;
 
   :global {
-    .n-dialog__close {
-      transform: translate(0, 3px);
-    }
+    // .n-dialog__close {
+    //   transform: translate(0, 3px);
+    // }
 
-    .n-dialog__title {
-      min-height: 70px;
-      justify-content: center;
-      background: #F5F6FA;
-    }
+    // .n-dialog__title {
+    //   min-height: 70px;
+    //   justify-content: center;
+    //   background: #F5F6FA;
+    // }
 
     .n-form {
       padding: 20px 0;
@@ -231,7 +231,7 @@
 
       .n-alert-body .n-alert-body__content {
         color: #EA4132;
-        font-size: 14px;
+        font-size: calc(14px, 12Px);
       }
 
     }
@@ -488,4 +488,4 @@
       cursor: pointer;
     }
   }
-}
+}

+ 16 - 6
src/views/setting/components/schoolInfo/index.tsx

@@ -17,6 +17,7 @@ import styles from './index.module.less';
 import { useUserStore } from '/src/store/modules/users';
 import UploadFile from '/src/components/upload-file';
 import { Add } from '@vicons/ionicons5';
+import { teacherJobType } from '/src/utils/contants';
 import {
   api_schoolUpdate,
   api_sysAreaQueryAllProvince,
@@ -75,7 +76,7 @@ export default defineComponent({
         {
           title: '老师姓名',
           key: 'nickname',
-          width: '20%',
+          width: '15%',
           render: (row: any) => {
             return (
               <div
@@ -87,9 +88,17 @@ export default defineComponent({
           }
         },
         {
+          title: '角色',
+          key: 'jobType',
+          width: '15%',
+          render: (row: any) => {
+            return teacherJobType[row.jobType];
+          }
+        },
+        {
           title: '手机号码',
           key: 'phone',
-          width: '20%',
+          width: '15%',
           render: (row: any) => {
             return (
               <div
@@ -129,7 +138,7 @@ export default defineComponent({
         {
           title: '操作',
           key: 'titleImg',
-          width: '30%',
+          width: '25%',
           render: (row: any) => (
             <NSpace>
               <NButton
@@ -153,7 +162,7 @@ export default defineComponent({
                     onClick={() => handleChange(row)}>
                     冻结
                   </NButton>
-                  {row.jobType === 'TEACHER' && (
+                  {user.info.isSuperAdmin && !row.manageAdmin && (
                     <NButton
                       type="primary"
                       text
@@ -442,12 +451,13 @@ export default defineComponent({
           columns={columns()}
           data={data.dataList}></NDataTable>
 
+        {/* class={styles.addTeacher} */}
         <NModal
           maskClosable={modalClickMask}
-          class={styles.addTeacher}
+          class={['modalTitle background', styles.addTeacher]}
           v-model:show={data.modal}
           title="添加老师"
-          preset="dialog"
+          preset="card"
           showIcon={false}>
           <AddTeacher
             areaList={formOptions.areaList}

+ 309 - 296
src/views/setting/index.module.less

@@ -1,297 +1,310 @@
-@img: './images';
-
-.listWrap {
-  min-height: 805px;
-  padding: 32px;
-  background-color: #fff;
-  border-radius: 20px;
-
-  .customTabs {
-    :global {
-      .n-tabs-tab--active {
-        font-size: max(18px, 14Px) !important;
-
-        font-weight: 600 !important;
-        color: #131415 !important;
-      }
-
-      .n-tabs-tab {
-        font-size: max(18px, 14Px);
-        padding: 8px 0 !important;
-        font-weight: 400;
-        min-width: 50px;
-        color: #8b8d98;
-
-        &:hover {
-          color: #198cfe !important;
-        }
-      }
-
-      .n-tabs-bar {
-        // background-color: red !important;
-        width: 50px !important;
-        height: 5px !important;
-        background: url('@{img}/barIcon.png') no-repeat;
-        background-size: 50px 5px;
-      }
-    }
-  }
-}
-
-.infoWrap {
-  height: 100%;
-  padding-top: 100px;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-
-  .teacherInfoWrap {
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-
-    .teacherHeadWrap {
-      position: relative;
-      width: 236px;
-      height: 132px;
-
-      .headerD {
-        width: 100%;
-        height: 100%;
-      }
-
-      .defultHeade {
-        width: 116px;
-        height: 116px;
-        overflow: hidden;
-        border-radius: 50%;
-        position: absolute;
-        top: 8px;
-        left: 60px;
-      }
-
-      .changeHead {
-        background-color: rgba(0, 0, 0, 0.7);
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        font-size: 16px;
-        color: #fff;
-        font-weight: 600;
-        transition: opacity 0.3s;
-        cursor: pointer;
-      }
-
-      .disalbedNone {
-        display: none;
-      }
-
-      .hoverNone {
-        background: transparent;
-        color: transparent;
-        transition: all 0.3s;
-
-        &:hover {
-          background-color: rgba(0, 0, 0, 0.7);
-          color: #fff;
-          transition: all 0.3s;
-        }
-      }
-
-      .uploadFile {
-        position: absolute;
-        left: 0;
-        right: 0;
-        top: 0;
-        bottom: 0;
-        opacity: 0;
-      }
-    }
-
-    .headerInfo {
-      .headerTitle {
-        font-size: 22px;
-        font-weight: 600;
-        color: #131415;
-        line-height: 28px;
-        letter-spacing: 1px;
-        margin: 18px 0 8px;
-        text-align: center;
-        display: flex;
-        flex-direction: row;
-        justify-content: center;
-        align-items: center;
-
-        .sexIcon {
-          width: 12px;
-          height: 21px;
-          margin-left: 5px;
-        }
-      }
-
-      .headerSubTitle {
-        font-size: 16px;
-        font-weight: 400;
-        color: #707a92;
-        line-height: 20px;
-        text-align: center;
-      }
-    }
-  }
-
-  .setInfo {
-    margin-top: 64px;
-    width: 1172px;
-
-    :global {
-      .n-form-item {
-        min-width: 200px;
-      }
-
-      .n-form-item-label {
-        font-size: 15px;
-        color: rgba(0, 0, 0, 0.8);
-      }
-
-      .n-input {
-        border-radius: 8px;
-
-        .n-input__input-el {
-          height: 50px;
-          font-size: 16px;
-        }
-
-        &.n-input--disabled {
-          background-color: #f5f6fa;
-          color: rgba(149, 149, 152, 1);
-
-          .n-input__input-el {
-            background-color: #F5F6FA;
-            color: rgba(0, 0, 0, 0.4);
-          }
-        }
-      }
-
-      .n-base-selection {
-        height: 50px;
-        border-radius: 8px;
-
-        .n-base-selection-label {
-          height: 50px;
-          font-size: 16px;
-        }
-      }
-
-      .n-base-selection.n-base-selection--disabled .n-base-selection-label {
-        background-color: #F5F6FA;
-        color: rgba(0, 0, 0, 0.4) !important;
-      }
-
-      .n-base-selection.n-base-selection--disabled .n-base-selection-label .n-base-selection-input {
-        color: rgba(0, 0, 0, 0.4) !important;
-      }
-    }
-  }
-}
-
-.btnList {
-  width: 100%;
-  padding: 20px 0;
-  margin-top: 30px;
-
-  .btn {
-    width: 144px;
-    height: 45px;
-    border-radius: 8px;
-    font-size: 18px;
-    font-weight: 600 !important;
-    margin-right: 24px;
-  }
-}
-
-:global {
-  .option.n-base-select-option {
-    justify-content: center;
-  }
-
-  .option.n-base-select-option.n-base-select-option--pending::before {
-    background-color: #198cfe !important;
-  }
-
-  .option.n-base-select-option.n-base-select-option--pending .n-base-select-option__content {
-    color: #fff !important;
-    text-align: center;
-  }
-}
-
-.changePwdModal {
-  border-radius: 16px;
-
-  .wrap {
-    padding: 12px 0;
-
-    :global {
-      .n-input {
-        border-radius: 5px;
-      }
-
-      .n-input .n-input__input-el {
-        height: 50px;
-      }
-
-      .n-button.n-button--disabled {
-        background: #aaa;
-      }
-    }
-  }
-
-  .sendMsg {
-    min-width: 108px;
-    height: 50px;
-  }
-
-  .pwdIcon {
-    width: 24px;
-    height: 24px;
-    cursor: pointer;
-  }
-
-  .submitBtm {
-    width: 45%;
-    height: 46px;
-  }
-}
-
-.wrap {
-  padding: 12px 0;
-
-  :global {
-    .n-input {
-      border-radius: 8px;
-    }
-
-    .n-input .n-input__input-el {
-      height: 53px;
-    }
-
-    .n-button.n-button--disabled {
-      background: #aaa;
-    }
-  }
-}
-
-.sendMsg {
-  height: 53px;
-  min-width: 108px;
-}
-
-.pwdIcon {
-  width: 24px;
-  height: 24px;
-  cursor: pointer;
-}
-
-.submitBtm {
-  width: 45%;
-  height: 47px;
+@img: './images';
+
+.listWrap {
+  min-height: 805px;
+  padding: 32px;
+  background-color: #fff;
+  border-radius: 20px;
+
+  .customTabs {
+    :global {
+      .n-tabs-tab--active {
+        font-size: max(18px, 14Px) !important;
+
+        font-weight: 600 !important;
+        color: #131415 !important;
+      }
+
+      .n-tabs-tab {
+        font-size: max(18px, 14Px);
+        padding: 8px 0 !important;
+        font-weight: 400;
+        min-width: 50px;
+        color: #8b8d98;
+
+        &:hover {
+          color: #198cfe !important;
+        }
+      }
+
+      .n-tabs-bar {
+        // background-color: red !important;
+        width: 50px !important;
+        height: 5px !important;
+        background: url('@{img}/barIcon.png') no-repeat;
+        background-size: 50px 5px;
+      }
+    }
+  }
+}
+
+.infoWrap {
+  height: 100%;
+  padding-top: 100px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+
+  .teacherInfoWrap {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+
+    .teacherHeadWrap {
+      position: relative;
+      width: 236px;
+      height: 132px;
+
+      .headerD {
+        width: 100%;
+        height: 100%;
+      }
+
+      .defultHeade {
+        width: 116px;
+        height: 116px;
+        overflow: hidden;
+        border-radius: 50%;
+        position: absolute;
+        top: 8px;
+        left: 60px;
+      }
+
+      .changeHead {
+        background-color: rgba(0, 0, 0, 0.7);
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        font-size: 16px;
+        color: #fff;
+        font-weight: 600;
+        transition: opacity 0.3s;
+        cursor: pointer;
+      }
+
+      .disalbedNone {
+        display: none;
+      }
+
+      .hoverNone {
+        background: transparent;
+        color: transparent;
+        transition: all 0.3s;
+
+        &:hover {
+          background-color: rgba(0, 0, 0, 0.7);
+          color: #fff;
+          transition: all 0.3s;
+        }
+      }
+
+      .uploadFile {
+        position: absolute;
+        left: 0;
+        right: 0;
+        top: 0;
+        bottom: 0;
+        opacity: 0;
+      }
+    }
+
+    .headerInfo {
+      .headerTitle {
+        font-size: max(18px, 15Px);
+        font-weight: 600;
+        color: #131415;
+        line-height: 28px;
+        letter-spacing: 1px;
+        margin: 18px 0 8px;
+        text-align: center;
+        display: flex;
+        flex-direction: row;
+        justify-content: center;
+        align-items: center;
+
+        .sexIcon {
+          width: 12px;
+          height: 21px;
+          margin-left: 5px;
+        }
+      }
+
+
+      .roleType {
+        margin-left: 5px;
+        font-size: max(12px, 11Px);
+        color: #2089FF;
+        background: #E8F4FF;
+        border-radius: 3px;
+        border: 1px solid rgba(25, 140, 254, 0.5);
+        padding: 0 4px;
+        line-height: 1.3;
+      }
+
+
+      .headerSubTitle {
+        font-size: 16px;
+        font-weight: 400;
+        color: #707a92;
+        line-height: 20px;
+        text-align: center;
+      }
+    }
+  }
+
+  .setInfo {
+    margin-top: 64px;
+    width: 1172px;
+
+    :global {
+      .n-form-item {
+        min-width: 200px;
+      }
+
+      .n-form-item-label {
+        font-size: 15px;
+        color: rgba(0, 0, 0, 0.8);
+      }
+
+      .n-input {
+        border-radius: 8px;
+
+        .n-input__input-el {
+          height: 50px;
+          font-size: 16px;
+        }
+
+        &.n-input--disabled {
+          background-color: #f5f6fa;
+          color: rgba(149, 149, 152, 1);
+
+          .n-input__input-el {
+            background-color: #F5F6FA;
+            color: rgba(0, 0, 0, 0.4);
+          }
+        }
+      }
+
+      .n-base-selection {
+        height: 50px;
+        border-radius: 8px;
+
+        .n-base-selection-label {
+          height: 50px;
+          font-size: 16px;
+        }
+      }
+
+      .n-base-selection.n-base-selection--disabled .n-base-selection-label {
+        background-color: #F5F6FA;
+        color: rgba(0, 0, 0, 0.4) !important;
+      }
+
+      .n-base-selection.n-base-selection--disabled .n-base-selection-label .n-base-selection-input {
+        color: rgba(0, 0, 0, 0.4) !important;
+      }
+    }
+  }
+}
+
+.btnList {
+  width: 100%;
+  padding: 20px 0;
+  margin-top: 30px;
+
+  .btn {
+    width: 144px;
+    height: 45px;
+    border-radius: 8px;
+    font-size: 18px;
+    font-weight: 600 !important;
+    margin-right: 24px;
+  }
+}
+
+:global {
+  .option.n-base-select-option {
+    justify-content: center;
+  }
+
+  .option.n-base-select-option.n-base-select-option--pending::before {
+    background-color: #198cfe !important;
+  }
+
+  .option.n-base-select-option.n-base-select-option--pending .n-base-select-option__content {
+    color: #fff !important;
+    text-align: center;
+  }
+}
+
+.changePwdModal {
+  border-radius: 16px;
+
+  .wrap {
+    padding: 12px 0;
+
+    :global {
+      .n-input {
+        border-radius: 5px;
+      }
+
+      .n-input .n-input__input-el {
+        height: 50px;
+      }
+
+      .n-button.n-button--disabled {
+        background: #aaa;
+      }
+    }
+  }
+
+  .sendMsg {
+    min-width: 108px;
+    height: 50px;
+  }
+
+  .pwdIcon {
+    width: 24px;
+    height: 24px;
+    cursor: pointer;
+  }
+
+  .submitBtm {
+    width: 45%;
+    height: 46px;
+  }
+}
+
+.wrap {
+  padding: 12px 0;
+
+  :global {
+    .n-input {
+      border-radius: 8px;
+    }
+
+    .n-input .n-input__input-el {
+      height: 53px;
+    }
+
+    .n-button.n-button--disabled {
+      background: #aaa;
+    }
+  }
+}
+
+.sendMsg {
+  height: 53px;
+  min-width: 108px;
+}
+
+.pwdIcon {
+  width: 24px;
+  height: 24px;
+  cursor: pointer;
+}
+
+.submitBtm {
+  width: 45%;
+  height: 47px;
 }

+ 2 - 1
src/views/setting/index.tsx

@@ -44,7 +44,8 @@ export default defineComponent({
           <NTabPane name="person" tab="个人信息">
             <PersonInfo></PersonInfo>
           </NTabPane>
-          {user.info.isSuperAdmin && (
+          {(user.info.isSuperAdmin ||
+            user.info.teacherJobType === 'HEADMASTER') && (
             <NTabPane name="school" tab="学校设置">
               <SchoolInfo onChangeTab={onChangeTab} />
             </NTabPane>

+ 10 - 1
src/views/xiaoku-ai/index.module.less

@@ -49,6 +49,15 @@
     padding: 12px 0;
 
     :global {
+      .n-form-item-label {
+        height: 37px;
+        min-height: 37px;
+      }
+
+      .n-form-item-feedback-wrapper {
+        min-height: 0;
+      }
+
       .n-button {
         min-width: 102px;
         height: 37px;
@@ -247,4 +256,4 @@
       margin-top: 0;
     }
   }
-}
+}

+ 126 - 146
src/views/xiaoku-ai/index.tsx

@@ -1,7 +1,15 @@
 import { defineComponent, onMounted, reactive, ref, toRefs, watch } from 'vue';
 import styles from './index.module.less';
 import TheSearch from '@/components/TheSearch';
-import { NButton, NImage, NPopselect, NSpace, NSpin } from 'naive-ui';
+import {
+  NButton,
+  NForm,
+  NFormItem,
+  NImage,
+  NPopselect,
+  NSpace,
+  NSpin
+} from 'naive-ui';
 import { useRouter } from 'vue-router';
 import { api_musicSheetCategoriesPage, api_musicTagTree } from './api';
 import TheEmpty from '/src/components/TheEmpty';
@@ -75,12 +83,10 @@ const ChildNodeSearch = defineComponent({
       <>
         {activeRow.value?.id && (
           <>
-            <div class={styles.tags}>
+            <NFormItem
+              label={activeRow.value.columnName + ':'}
+              class={styles.tags}>
               <NSpace size={[12, 8]}>
-                <span class={styles.firstButton}>
-                  {activeRow.value.columnName}
-                </span>
-
                 {activeRow.value?.children.map((subject: any) => {
                   return (
                     <>
@@ -129,7 +135,7 @@ const ChildNodeSearch = defineComponent({
                   );
                 })}
               </NSpace>
-            </div>
+            </NFormItem>
 
             <ChildNodeSearch
               activeRow={selectItem.value}
@@ -401,160 +407,134 @@ export default defineComponent({
       <div class={styles.container}>
         <div class={styles.tools}>
           <div class={styles.tagWrap}>
-            <div class={styles.tags}>
-              <NSpace size={[12, 8]}>
-                <span class={styles.firstButton}>
-                  {data.tags?.[0]?.columnName}
-                </span>
-
-                {data.tags.map((item: any) => {
-                  return (
-                    <>
-                      <NButton
-                        round
-                        secondary={data.tagActiveId === item.id ? false : true}
-                        type={
-                          data.tagActiveId === item.id ? 'primary' : 'default'
-                        }
-                        onClick={() => changeTag(item)}>
-                        {item.name}
-                      </NButton>
-                    </>
+            <NForm labelAlign="left" labelPlacement="left">
+              <NFormItem
+                label={data.tags?.[0]?.columnName || '' + ':'}
+                class={styles.tags}>
+                <NSpace size={[12, 8]}>
+                  {data.tags.map((item: any) => {
+                    return (
+                      <>
+                        <NButton
+                          round
+                          secondary={
+                            data.tagActiveId === item.id ? false : true
+                          }
+                          type={
+                            data.tagActiveId === item.id ? 'primary' : 'default'
+                          }
+                          onClick={() => changeTag(item)}>
+                          {item.name}
+                        </NButton>
+                      </>
+                    );
+                  })}
+                </NSpace>
+              </NFormItem>
+              <ChildNodeSearch
+                activeRow={data.selectParents}
+                loading={data.loading}
+                onSelectChildTag={(val: any) => {
+                  data.childSelectId = val;
+                  localStorage.setItem(
+                    'xiaoku-ai-search',
+                    JSON.stringify({
+                      tagActiveId: data.tagActiveId,
+                      instrumentId: forms.instrumentId,
+                      childSelectId: data.childSelectId,
+                      musicTagIds: forms.musicTagIds
+                    })
                   );
-                })}
-              </NSpace>
-            </div>
+                  getList();
+                }}
+              />
+              <NFormItem label="乐器:" class={styles.tags}>
+                <NSpace size={[12, 8]}>
+                  {/* <span class={styles.firstButton}>乐器</span> */}
 
-            <ChildNodeSearch
-              activeRow={data.selectParents}
-              loading={data.loading}
-              onSelectChildTag={(val: any) => {
-                data.childSelectId = val;
-                localStorage.setItem(
-                  'xiaoku-ai-search',
-                  JSON.stringify({
-                    tagActiveId: data.tagActiveId,
-                    instrumentId: forms.instrumentId,
-                    childSelectId: data.childSelectId,
-                    musicTagIds: forms.musicTagIds
-                  })
-                );
-                getList();
-              }}
-            />
-            <div class={styles.tags}>
-              <NSpace size={[12, 8]}>
-                <span class={styles.firstButton}>乐器</span>
-
-                {catchStore.getSubjectInstruments.map((item: any) =>
-                  item.instruments && item.instruments.length > 1 ? (
-                    <NPopselect
-                      options={item.instruments}
-                      trigger="hover"
-                      v-model:value={data.tagIndex}
-                      scrollable
-                      onUpdate:value={() => {
-                        forms.instrumentId = data.tagIndex;
-                        localStorage.setItem(
-                          'xiaoku-ai-search',
-                          JSON.stringify({
-                            tagActiveId: data.tagActiveId,
-                            instrumentId: data.tagIndex,
-                            musicTagIds: forms.musicTagIds
-                          })
-                        );
-                        getList();
-                      }}
-                      key={item.value}
-                      class={[styles.popSelect1]}>
+                  {catchStore.getSubjectInstruments.map((item: any) =>
+                    item.instruments && item.instruments.length > 1 ? (
+                      <NPopselect
+                        options={item.instruments}
+                        trigger="hover"
+                        v-model:value={data.tagIndex}
+                        scrollable
+                        onUpdate:value={() => {
+                          forms.instrumentId = data.tagIndex;
+                          localStorage.setItem(
+                            'xiaoku-ai-search',
+                            JSON.stringify({
+                              tagActiveId: data.tagActiveId,
+                              instrumentId: data.tagIndex,
+                              musicTagIds: forms.musicTagIds
+                            })
+                          );
+                          getList();
+                        }}
+                        key={item.value}
+                        class={[styles.popSelect1]}>
+                        <NButton
+                          round
+                          textColor={
+                            selectChildObj(item.instruments).selected
+                              ? '#fff'
+                              : '#000'
+                          }
+                          color={
+                            selectChildObj(item.instruments).selected
+                              ? '#198CFE'
+                              : 'rgba(46, 51, 56, .05)'
+                          }
+                          type={
+                            selectChildObj(item.instruments).selected
+                              ? 'primary'
+                              : 'default'
+                          }
+                          class={[
+                            styles.textBtn,
+                            selectChildObj(item.instruments).selected &&
+                              styles.textBtnActive
+                          ]}>
+                          {selectChildObj(item.instruments).name || item.name}
+                          <i class={styles.iconArrow}></i>
+                        </NButton>
+                      </NPopselect>
+                    ) : (
                       <NButton
                         round
                         textColor={
-                          selectChildObj(item.instruments).selected
-                            ? '#fff'
-                            : '#000'
+                          data.tagIndex === (item.value || 0) ? '#fff' : '#000'
                         }
                         color={
-                          selectChildObj(item.instruments).selected
+                          data.tagIndex === (item.value || 0)
                             ? '#198CFE'
                             : 'rgba(46, 51, 56, .05)'
                         }
                         type={
-                          selectChildObj(item.instruments).selected
+                          data.tagIndex === (item.value || 0)
                             ? 'primary'
                             : 'default'
                         }
-                        class={[
-                          styles.textBtn,
-                          selectChildObj(item.instruments).selected &&
-                            styles.textBtnActive
-                        ]}>
-                        {selectChildObj(item.instruments).name || item.name}
-                        <i class={styles.iconArrow}></i>
+                        onClick={() => {
+                          data.tagIndex = item.value || 0;
+                          forms.instrumentId = item.value;
+                          localStorage.setItem(
+                            'xiaoku-ai-search',
+                            JSON.stringify({
+                              tagActiveId: data.tagActiveId,
+                              instrumentId: item.value,
+                              musicTagIds: forms.musicTagIds
+                            })
+                          );
+                          getList();
+                        }}>
+                        {item.name}
                       </NButton>
-                    </NPopselect>
-                  ) : (
-                    <NButton
-                      round
-                      textColor={
-                        data.tagIndex === (item.value || 0) ? '#fff' : '#000'
-                      }
-                      color={
-                        data.tagIndex === (item.value || 0)
-                          ? '#198CFE'
-                          : 'rgba(46, 51, 56, .05)'
-                      }
-                      type={
-                        data.tagIndex === (item.value || 0)
-                          ? 'primary'
-                          : 'default'
-                      }
-                      onClick={() => {
-                        data.tagIndex = item.value || 0;
-                        forms.instrumentId = item.value;
-                        localStorage.setItem(
-                          'xiaoku-ai-search',
-                          JSON.stringify({
-                            tagActiveId: data.tagActiveId,
-                            instrumentId: item.value,
-                            musicTagIds: forms.musicTagIds
-                          })
-                        );
-                        getList();
-                      }}>
-                      {item.name}
-                    </NButton>
-                  )
-                )}
-                {/* // {
-                //   return (
-                //     <>
-                //       <NButton
-                //         round
-                //         secondary={item.id === forms.instrumentId ? false : true}
-                //         type={
-                //           item.id === forms.instrumentId ? 'primary' : 'default'
-                //         }
-                //         onClick={() => {
-                //           forms.instrumentId = item.id;
-
-                //           localStorage.setItem(
-                //             'xiaoku-ai-search',
-                //             JSON.stringify({
-                //               tagActiveId: data.tagActiveId,
-                //               instrumentId: item.id,
-                //               musicTagIds: forms.musicTagIds
-                //             })
-                //           );
-                //           getList();
-                //         }}>
-                //         {item.name}
-                //       </NButton>
-                //     </>
-                //   );
-                // })} */}
-              </NSpace>
-            </div>
+                    )
+                  )}
+                </NSpace>
+              </NFormItem>
+            </NForm>
           </div>
           <TheSearch
             round

BIN
src/views/xiaoku-music/images/icon-collect-active.png


BIN
src/views/xiaoku-music/images/icon-collect-default.png


BIN
src/views/xiaoku-music/images/icon_trans_default.png


+ 63 - 14
src/views/xiaoku-music/index.module.less

@@ -203,7 +203,7 @@
 
     .nBaseCascaser {
       border-radius: 100px;
-      width: 201px;
+      width: 170px;
       background: #F5F6FA;
       margin-right: 16px;
 
@@ -304,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;
     }
   }
 
@@ -403,14 +433,23 @@
       height: 37px !important;
       background: #F5F6FA;
       --n-border: #F5F6FA !important;
-
-
     }
 
     .transBtn {
       width: 45px;
+      height: 45px;
       cursor: pointer;
       margin-right: 15px;
+      // background: url('./images/icon_trans_default.png');
+      // background-size: contain;
+
+      // &:hover {
+      //   background: url('./images/icon_trans.png');
+      //   background-size: contain;
+      // }
+      &:hover {
+        opacity: 0.7;
+      }
     }
   }
 
@@ -422,14 +461,18 @@
     transition: all .3s;
 
     &:hover {
-      transform: scale(1.1);
+      // transform: scale(1.1);
+
+      img {
+        opacity: 0.7;
+      }
     }
 
     &>img {
       display: block;
       width: 100%;
       height: 100%;
-      filter: drop-shadow(0 0 10px rgba(27, 35, 55, .1));
+      // filter: drop-shadow(0 0 10px rgba(27, 35, 55, .1));
     }
   }
 }
@@ -475,8 +518,8 @@
 
   .previewClose {
     position: absolute;
-    left: 40px;
-    top: 40px;
+    right: -80px;
+    top: 0px;
     width: 60px;
     height: 65px;
   }
@@ -549,18 +592,24 @@
     fill: #131415;
   }
 
+  &:hover {
+    opacity: 0.7;
+  }
+
   &:hover,
   &.textBtnActive {
-    background: #198CFE !important;
-    font-weight: 500 !important;
-    color: #fff !important;
+    background: #F5F6FA;
+    --n-border: #F5F6FA !important;
+    --n-border-hover: #F5F6FA !important;
+    font-weight: 600 !important;
+    color: #131415 !important;
 
     .iconArrow {
       transform: rotate(0deg);
-      background: url('./images/icon-arrow2.svg') no-repeat center center / contain;
-      color: #fff;
-      fill: #fff;
+      background: url('./images/icon-arrow.svg') no-repeat center center / contain;
+      color: #131415;
+      fill: #131415;
       margin-top: 0;
     }
   }
-}
+}

+ 106 - 31
src/views/xiaoku-music/index.tsx

@@ -31,11 +31,12 @@ 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_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';
+import icon_favitor from './images/icon-collect-default.png';
+import icon_favitorActive from './images/icon-collect-active.png';
 import icon_default from './images/icon_default.png';
 import icon_close from './images/icon-close.png';
-import icon_trans from './images/icon_trans.png';
+// import icon_trans from './images/icon_trans.png';
+import icon_trans_default from './images/icon_trans_default.png';
 import { useRoute, useRouter } from 'vue-router';
 import PlayItem from './component/play-item';
 import PlayLoading from './component/play-loading';
@@ -94,7 +95,7 @@ export default defineComponent({
       showMusicImg: 'staff' as 'staff' | 'first' | 'fixed', // 显示哪种曲谱
       trackList: [] as any, // 可筛选的分轨信息
       showTransBtn: true, // 是否显示转谱按钮
-      trackName: '切换声' as any // 分轨名字
+      trackName: '切换声' as any // 分轨名字
     });
     const subjects = ref('');
     const showGuide = ref(false);
@@ -167,8 +168,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;
       }
@@ -238,6 +252,8 @@ export default defineComponent({
       });
       obv.observe(spinRef.value);
       analyzeXml();
+
+      musicIframeLoad();
       window.addEventListener('message', iframeHandle);
     });
     onUnmounted(() => {
@@ -331,7 +347,7 @@ export default defineComponent({
       return temp;
     });
 
-    // 根据musicSheetType返回的值,判断是否显示切换声按钮
+    // 根据musicSheetType返回的值,判断是否显示切换声按钮
     const isEnsemble = computed(() => {
       // const details: any = data.list[data.listActive];
       // const musics: any = details?.musicalInstruments;
@@ -391,6 +407,8 @@ export default defineComponent({
       }&modelType=practise&modeType=json&Authorization=${token}&isPreView=true&part-index=${
         data.musicInstrumentIndex
       }&musicRenderType=${musicRenderType}`;
+
+      console.log(data.iframeSrc, 'iframeSrc');
     };
 
     /** 音频控制 */
@@ -546,6 +564,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;
@@ -592,25 +624,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 = [];
@@ -766,10 +798,12 @@ export default defineComponent({
                     <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;
@@ -786,6 +820,7 @@ export default defineComponent({
                     round
                     border={false}
                     onSearch={val => {
+                      if (data.loading) return;
                       forms.name = val;
                       data.reshing = true;
                       handleGetList();
@@ -801,8 +836,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}>
@@ -828,7 +872,25 @@ 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 ? (
                             <NButton
@@ -938,7 +1000,7 @@ export default defineComponent({
                     } else if (data.showMusicImg === 'staff') {
                       lineType = 'staff';
                     }
-                    let 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
@@ -946,8 +1008,8 @@ export default defineComponent({
                       data.musicInstrumentIndex
                     }`;
 
-                    if (data.tagIndex) {
-                      src += '&instrumentId=' + data.tagIndex;
+                    if (data.musicalInstrumentId) {
+                      src += '&instrumentId=' + data.musicalInstrumentId;
                     }
                     if (
                       window.matchMedia('(display-mode: standalone)').matches
@@ -966,7 +1028,7 @@ export default defineComponent({
                 <div
                   class={styles.rightBtns}
                   style={{ display: activeItem.value.id ? '' : 'none' }}>
-                  {isEnsemble.value && (
+                  {!isEnsemble.value && (
                     <NPopselect
                       options={data.trackList}
                       trigger="hover"
@@ -974,6 +1036,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]}>
@@ -992,10 +1061,14 @@ export default defineComponent({
                       onUpdate:value={async (val: any) => {
                         data.showMusicImg = val;
                         // musicIframeLoad();
+                        if (isEnsemble.value) {
+                          musicIframeLoad();
+                        }
                       }}
                       // key={item.id}
                       class={[styles.popTrans]}>
-                      <img class={[styles.transBtn]} src={icon_trans} />
+                      <img class={[styles.transBtn]} src={icon_trans_default} />
+                      {/* <i class={styles.transBtn}></i> */}
                     </NPopselect>
                   )}
                   <div class={styles.favitor} onClick={() => handleFavitor()}>
@@ -1020,7 +1093,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;
 }

+ 2 - 2
vite.config.ts

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