فهرست منبع

Merge branch 'iteration-20240816-fire' into jenkins

lex 10 ماه پیش
والد
کامیت
a65baf2ba5
43فایلهای تغییر یافته به همراه2289 افزوده شده و 1618 حذف شده
  1. 1 1
      public/version.json
  2. BIN
      src/common/images/bg.png
  3. 1 1
      src/components/TheSearch/index.module.less
  4. 67 66
      src/components/card-preview/listen-modal/index.tsx
  5. 5 3
      src/components/card-preview/song-modal/index.module.less
  6. 2 0
      src/components/card-preview/song-modal/index.tsx
  7. 5 3
      src/components/card-preview/video-modal/index.module.less
  8. 3 1
      src/components/card-preview/video-modal/index.tsx
  9. 0 1
      src/components/card-type/index.tsx
  10. 26 5
      src/components/layout/index.module.less
  11. 20 9
      src/components/layout/layoutTop.tsx
  12. 9 0
      src/utils/contants.ts
  13. 3 0
      src/views/attend-class/component/audio-pay.tsx
  14. 47 27
      src/views/attend-class/index.tsx
  15. 2 2
      src/views/attend-class/model/train-type/index.module.less
  16. 503 372
      src/views/classList/components/testRecode.tsx
  17. 19 0
      src/views/classList/index.module.less
  18. 14 4
      src/views/home/index.tsx
  19. 209 203
      src/views/home/modals/class-modal/index.module.less
  20. 346 342
      src/views/home/modals/class-modal/index.tsx
  21. 1 4
      src/views/prepare-lessons/components/directory-main/index.tsx
  22. 2 2
      src/views/prepare-lessons/components/directory-main/select-lessonware/index.module.less
  23. 30 1
      src/views/prepare-lessons/components/lesson-main/courseware/addCourseware.module.less
  24. 115 39
      src/views/prepare-lessons/components/lesson-main/courseware/addCourseware.tsx
  25. 123 26
      src/views/prepare-lessons/components/resource-main/components/resource-item/index.tsx
  26. 32 6
      src/views/prepare-lessons/components/resource-main/index.tsx
  27. 8 0
      src/views/prepare-lessons/model/select-resources/index.tsx
  28. 5 0
      src/views/prepare-lessons/model/select-resources/select-item/index.tsx
  29. 161 10
      src/views/prepare-lessons/model/select-resources/select-item/resource-search-group/index.tsx
  30. 1 1
      src/views/prepare-lessons/model/source-rhythm/index.tsx
  31. 13 7
      src/views/setting/components/personInfo.tsx
  32. 14 14
      src/views/setting/components/schoolInfo/index.module.less
  33. 16 6
      src/views/setting/components/schoolInfo/index.tsx
  34. 309 296
      src/views/setting/index.module.less
  35. 2 1
      src/views/setting/index.tsx
  36. 10 1
      src/views/xiaoku-ai/index.module.less
  37. 126 146
      src/views/xiaoku-ai/index.tsx
  38. BIN
      src/views/xiaoku-music/images/icon-collect-active.png
  39. BIN
      src/views/xiaoku-music/images/icon-collect-default.png
  40. BIN
      src/views/xiaoku-music/images/icon_trans_default.png
  41. 30 11
      src/views/xiaoku-music/index.module.less
  42. 7 5
      src/views/xiaoku-music/index.tsx
  43. 2 2
      vite.config.ts

+ 1 - 1
public/version.json

@@ -1 +1 @@
-{"version":1724038552049}
+{ "version": 1724038552049 }

BIN
src/common/images/bg.png


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

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

+ 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={() => {

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

+ 47 - 27
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>

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

+ 1 - 4
src/views/prepare-lessons/components/directory-main/index.tsx

@@ -283,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 @@
       }
     }
   }
-}
+}

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

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

+ 123 - 26
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 // 是否存在
           });
         });
@@ -207,6 +209,15 @@ export default defineComponent({
     onUnmounted(() => {
       eventGlobal.off('onCoursewareUpdate', onUpdate);
     });
+
+    const getParams = () => {
+      return state.searchGroup;
+    };
+
+    expose({
+      getParams
+    });
+
     return () => (
       <div>
         <ResourceSearchGroup
@@ -248,29 +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 = {
-                          instrumentId:
-                            state.searchGroup.musicalInstrumentId || null,
-                          ...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>

+ 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();
 
@@ -166,6 +172,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);
                   }}>
@@ -181,21 +198,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
@@ -203,7 +226,7 @@ export default defineComponent({
                     tab="我的收藏"
                     // displayDirective="show:lazy"
                   >
-                    <ResourceItem type="myCollect" />
+                    <ResourceItem type="myCollect" ref={myCollectRef} />
                   </NTabPane>
                 </>
               )
@@ -275,7 +298,10 @@ export default defineComponent({
           class={['modalTitle', styles.selectMusicModal]}
           preset="card"
           title={'选择资源'}>
-          <SelectResources type={forms.tabType} />
+          <SelectResources
+            type={forms.tabType}
+            searchGroup={forms.searchGroup}
+          />
         </NModal>
 
         <NModal

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

@@ -12,6 +12,10 @@ export default defineComponent({
       type: String,
       default: 'myResources'
     },
+    searchGroup: {
+      type: Object,
+      default: () => ({})
+    },
     /** 从哪里使用 */
     from: {
       type: String,
@@ -63,6 +67,7 @@ export default defineComponent({
             <NTabPane name="relateResources" tab={'相关资源'}>
               <SelectItem
                 type="relateResources"
+                searchGroup={props.searchGroup}
                 from={props.from}
                 instrumentId={props.instrumentId}
               />
@@ -74,6 +79,7 @@ export default defineComponent({
             <SelectItem
               type="shareResources"
               from={props.from}
+              searchGroup={props.searchGroup}
               instrumentId={props.instrumentId}
             />
           </NTabPane>
@@ -83,6 +89,7 @@ export default defineComponent({
             <SelectItem
               type="myResources"
               from={props.from}
+              searchGroup={props.searchGroup}
               instrumentId={props.instrumentId}
             />
           </NTabPane>
@@ -91,6 +98,7 @@ export default defineComponent({
             <SelectItem
               type="myCollect"
               from={props.from}
+              searchGroup={props.searchGroup}
               instrumentId={props.instrumentId}
             />
           </NTabPane>

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

@@ -40,6 +40,10 @@ export default defineComponent({
       >,
       default: 'shareResources'
     },
+    searchGroup: {
+      type: Object,
+      default: () => ({})
+    },
     /** 从哪里使用 */
     from: {
       type: String,
@@ -278,6 +282,7 @@ export default defineComponent({
             ) : (
               <ResourceSearchGroup
                 type={props.type}
+                searchGroup={props.searchGroup}
                 onSearch={(item: any, type: any) => {
                   if (type) {
                     onSearch(item);

+ 161 - 10
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
@@ -176,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)];
@@ -282,6 +322,61 @@ export default defineComponent({
       }
     };
 
+    // 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 => {
@@ -314,6 +409,62 @@ export default defineComponent({
       }
 
       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 () => (

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

+ 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


+ 30 - 11
src/views/xiaoku-music/index.module.less

@@ -433,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;
+      }
     }
   }
 
@@ -452,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));
     }
   }
 }
@@ -579,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;
     }
   }
-}
+}

+ 7 - 5
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';
@@ -1027,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"
@@ -1066,7 +1067,8 @@ export default defineComponent({
                       }}
                       // 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()}>

+ 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://test.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(() => {