Bläddra i källkod

Merge branch 'iteration-login'

lex 1 år sedan
förälder
incheckning
e4e497d9d3
51 ändrade filer med 2061 tillägg och 702 borttagningar
  1. 8 1
      src/api/user.ts
  2. 1 0
      src/components/card-type/index.module.less
  3. 2 2
      src/components/layout/layoutSilder.tsx
  4. 70 0
      src/store/modules/prepareLessons.ts
  5. 1 0
      src/styles/index.less
  6. 7 0
      src/views/natural-resources/api.ts
  7. 1 0
      src/views/natural-resources/components/my-collect/index.module.less
  8. 1 1
      src/views/natural-resources/components/my-collect/index.tsx
  9. 7 1
      src/views/natural-resources/components/my-resources/index.module.less
  10. 1 1
      src/views/natural-resources/components/my-resources/index.tsx
  11. 1 0
      src/views/natural-resources/components/my-resources/upload-modal/index.module.less
  12. 1 25
      src/views/natural-resources/components/my-resources/upload-modal/index.tsx
  13. 25 23
      src/views/natural-resources/components/my-resources/upload-modal/upload-file.tsx
  14. 1 0
      src/views/natural-resources/components/share-resources/index.module.less
  15. 2 1
      src/views/natural-resources/components/share-resources/index.tsx
  16. 2 0
      src/views/natural-resources/index.module.less
  17. 1 1
      src/views/natural-resources/index.tsx
  18. 53 3
      src/views/natural-resources/model/add-teaching/index.tsx
  19. 35 0
      src/views/prepare-lessons/api.ts
  20. 39 0
      src/views/prepare-lessons/components/directory-main/images/icon-custom.svg
  21. 30 0
      src/views/prepare-lessons/components/directory-main/images/icon-upload-bg.svg
  22. 40 0
      src/views/prepare-lessons/components/directory-main/images/icon_default.svg
  23. 7 2
      src/views/prepare-lessons/components/directory-main/index.module.less
  24. 124 286
      src/views/prepare-lessons/components/directory-main/index.tsx
  25. 193 0
      src/views/prepare-lessons/components/directory-main/select-lessonware/index.module.less
  26. 215 0
      src/views/prepare-lessons/components/directory-main/select-lessonware/index.tsx
  27. 50 0
      src/views/prepare-lessons/components/lesson-main/courseware/index.module.less
  28. 104 0
      src/views/prepare-lessons/components/lesson-main/courseware/index.tsx
  29. 0 79
      src/views/prepare-lessons/components/lesson-main/index.module.less
  30. 5 85
      src/views/prepare-lessons/components/lesson-main/index.tsx
  31. 44 0
      src/views/prepare-lessons/components/lesson-main/train/index.module.less
  32. 36 0
      src/views/prepare-lessons/components/lesson-main/train/index.tsx
  33. 17 0
      src/views/prepare-lessons/components/resource-main/components/my-collect/index.module.less
  34. 106 0
      src/views/prepare-lessons/components/resource-main/components/my-collect/index.tsx
  35. 3 0
      src/views/prepare-lessons/components/resource-main/components/my-collect/resource-search-group/index.module.less
  36. 112 0
      src/views/prepare-lessons/components/resource-main/components/my-collect/resource-search-group/index.tsx
  37. 17 0
      src/views/prepare-lessons/components/resource-main/components/my-resources/index.module.less
  38. 106 0
      src/views/prepare-lessons/components/resource-main/components/my-resources/index.tsx
  39. 59 0
      src/views/prepare-lessons/components/resource-main/components/my-resources/resource-search-group/index.module.less
  40. 112 0
      src/views/prepare-lessons/components/resource-main/components/my-resources/resource-search-group/index.tsx
  41. 18 0
      src/views/prepare-lessons/components/resource-main/components/share-resources/index.module.less
  42. 105 0
      src/views/prepare-lessons/components/resource-main/components/share-resources/index.tsx
  43. 59 0
      src/views/prepare-lessons/components/resource-main/components/share-resources/resource-search-group/index.module.less
  44. 104 0
      src/views/prepare-lessons/components/resource-main/components/share-resources/resource-search-group/index.tsx
  45. 0 18
      src/views/prepare-lessons/components/resource-main/index.module.less
  46. 20 72
      src/views/prepare-lessons/components/resource-main/index.tsx
  47. 0 52
      src/views/prepare-lessons/model/resource-search-group/index.tsx
  48. 97 27
      src/views/setting/components/personInfo.tsx
  49. 18 17
      src/views/setting/index.module.less
  50. 1 1
      src/views/setting/index.tsx
  51. 0 4
      vite.config.ts

+ 8 - 1
src/api/user.ts

@@ -5,7 +5,7 @@ import request from '@/utils/request';
  * @param prams 登录参数
  */
 export const userLogin = (params: any) => {
-  return request.post('/edu-oauth/userlogin', {
+  return request.post('/edu-app/userlogin', {
     requestType: 'form',
     data: params
   });
@@ -20,6 +20,13 @@ export const getUserInfo = () => {
 };
 
 /**
+ * 老师端修改用户信息
+ */
+export const api_teacherUpdate = (body: any) => {
+  return request.post('/edu-app/teacher/update', { data: body });
+};
+
+/**
  * 获取声部列表
  * returns subjects
  */

+ 1 - 0
src/components/card-type/index.module.less

@@ -120,6 +120,7 @@
     position: absolute;
     top: 0px;
     left: 0px;
+    z-index: 9;
     width: 58px;
     height: 29px;
     border-top-left-radius: 13px;

+ 2 - 2
src/components/layout/layoutSilder.tsx

@@ -63,7 +63,7 @@ export default defineComponent({
         normalIcon: kuNormal,
         isActive: false,
         id: 5,
-        lightList:[ '/xiaoku-music'],//小酷AI的灯光列表
+        lightList: ['/xiaoku-music'], //小酷AI的灯光列表
         path: '/xiaoku-ai'
       },
       {
@@ -88,7 +88,7 @@ export default defineComponent({
         now.isActive = false;
         if (now.id == item.id) {
           now.isActive = true;
-          console.log(item.path);
+          // console.log(item.path);
           item.path && router.push(item.path);
         }
       });

+ 70 - 0
src/store/modules/prepareLessons.ts

@@ -0,0 +1,70 @@
+import { defineStore } from 'pinia';
+import { store } from '@/store';
+
+export const usePrepareStore = defineStore('prepare-lessons-store', {
+  state: () => ({
+    baseCourseware: {} as any, // 基础教学课件
+    selectKey: '', // 选的哪一节课
+    lessonCoursewareId: '', // 哪个教材分类
+    lessonCoursewareDetailId: '', // 哪个教材详情
+    treeList: [] as any[], // 左边教学课件列表
+    coursewareList: [] as any[] // 课件信息
+  }),
+  getters: {
+    /** 获取基础教学课件 */
+    getBaseCourseware(): any {
+      return this.baseCourseware;
+    },
+    /** 获取选择课的编号 */
+    getSelectKey(): string {
+      return this.selectKey;
+    },
+    /** 获取教材编号 */
+    getLessonCoursewareId(): string {
+      return this.lessonCoursewareId;
+    },
+    /** 获取分类编号 */
+    getLessonCoursewareDetailId(): string {
+      return this.lessonCoursewareDetailId;
+    },
+    /** 获取树形控件 */
+    getTreeList(): any[] {
+      return this.treeList;
+    },
+    /** 获取课件列表 */
+    getCoursewareList(): any[] {
+      return this.coursewareList;
+    }
+  },
+  actions: {
+    /** 设置基础教学课件 */
+    setBaseCourseware(baseCourseware: any) {
+      this.baseCourseware = baseCourseware;
+    },
+    /** 设置课的编号 */
+    setSelectKey(key: string) {
+      this.selectKey = key;
+    },
+    /** 设置教材的编号 */
+    setLessonCoursewareId(id: string) {
+      this.lessonCoursewareId = id;
+    },
+    /** 设置分类的编号 */
+    setLessonCoursewareDetailId(id: string) {
+      this.lessonCoursewareDetailId = id;
+    },
+    /** 设置课的编号 */
+    setTreeList(list: any[]) {
+      this.treeList = list;
+    },
+    /** 设置课件列表 */
+    setCoursewareList(list: any[]) {
+      this.coursewareList = list;
+    }
+  }
+});
+
+// Need to be used outside the setup
+export function usePrepareLessonsStoreWidthOut() {
+  return usePrepareStore(store);
+}

+ 1 - 0
src/styles/index.less

@@ -1,3 +1,4 @@
+
 * {
   padding: 0;
   margin: 0;

+ 7 - 0
src/views/natural-resources/api.ts

@@ -25,6 +25,13 @@ export const api_lessonCoursewareSave = (params: any): Promise<any> => {
   });
 };
 
+/** 音乐教材-修改 */
+export const api_lessonCoursewareUpdate = (params: any): Promise<any> => {
+  return request.post('/edu-app/lessonCourseware/update', {
+    data: params
+  });
+};
+
 /** 资源-新增 */
 export const materialSave = (params: any[]): Promise<any> => {
   return request.post('/edu-app/material/save', {

+ 1 - 0
src/views/natural-resources/components/my-collect/index.module.less

@@ -67,6 +67,7 @@
     width: 360px;
     height: 42px;
     font-size: 16px;
+    --n-height: 42px !important;
 
     img {
       width: 18px;

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

@@ -73,7 +73,7 @@ export default defineComponent({
       <>
         <SearchGroupResources onSearch={(item: any) => onSearch(item)} />
 
-        <NSpin v-model:show={state.loading}>
+        <NSpin v-model:show={state.loading} style={{ 'min-height': '50vh' }}>
           <div class={styles.list}>
             {state.tableList.map((item: any) => {
               const tmpItem = {

+ 7 - 1
src/views/natural-resources/components/my-resources/index.module.less

@@ -4,7 +4,6 @@
   flex-flow: row wrap;
   justify-content: flex-start;
   gap: 22px;
-  min-height: 220px;
 }
 
 .searchGroup {
@@ -67,6 +66,7 @@
     width: 360px;
     height: 42px;
     font-size: 16px;
+    --n-height: 42px !important;
 
     img {
       width: 18px;
@@ -179,4 +179,10 @@
 
 .attendClassModal {
   width: 1100px;
+
+  :global {
+    .n-select-menu {
+      --n-height: calc(var(--n-option-height) * 5.6) !important;
+    }
+  }
 }

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

@@ -162,7 +162,7 @@ export default defineComponent({
           onDelete={onDelete}
         />
 
-        <NSpin v-model:show={state.loading}>
+        <NSpin v-model:show={state.loading} style={{ 'min-height': '50vh' }}>
           <div class={styles.list}>
             {state.tableList.map((item: any) => (
               <div class={styles.itemSection}>

+ 1 - 0
src/views/natural-resources/components/my-resources/upload-modal/index.module.less

@@ -85,6 +85,7 @@
     width: 320px;
 
     :global {
+
       .n-input {
         margin-bottom: 12px;
       }

+ 1 - 25
src/views/natural-resources/components/my-resources/upload-modal/index.tsx

@@ -126,29 +126,6 @@ export default defineComponent({
       uploadForms.list.splice(index, 1);
     };
 
-    // const getImgBase64 = (url: any) => {
-    //   return new Promise(function (resolve) {
-    //     let dataURL = '';
-    //     const video = document.createElement('video');
-    //     video.currentTime = 1; //指定帧数
-    //     video.setAttribute('crossOrigin', 'anonymous'); //处理跨域
-    //     video.setAttribute('src', url);
-    //     video.setAttribute('width', '100');
-    //     video.setAttribute('height', '100');
-
-    //     video.addEventListener('loadeddata', function () {
-    //       const canvas: any = document.createElement('canvas'),
-    //         width = video.width, //canvas的尺寸和图片一样
-    //         height = video.height;
-    //       canvas.width = width;
-    //       canvas.height = height;
-    //       canvas.getContext('2d').drawImage(video, 0, 0, width, height); //绘制canvas
-    //       dataURL = canvas.toDataURL('image/jpeg'); //转换为base64
-    //       resolve(dataURL);
-    //     });
-    //   });
-    // };
-
     const isUpdate = computed(() => (props.list.length > 0 ? true : false));
 
     onMounted(async () => {
@@ -189,7 +166,7 @@ export default defineComponent({
                   <div class={styles.previewModal}>
                     <NImage
                       class={[styles.titleType]}
-                      src={formatType('MUSIC')}
+                      src={formatType(item.type)}
                       previewDisabled
                       objectFit="cover"
                     />
@@ -271,7 +248,6 @@ export default defineComponent({
                       fixedBox: true
                     }}
                     onFinished={(val: any) => {
-                      console.log(val, 'val');
                       uploadForms.list.push({
                         subjectIds: uploadForms.subjectIds || [],
                         openFlag: true,

+ 25 - 23
src/views/natural-resources/components/my-resources/upload-modal/upload-file.tsx

@@ -1,4 +1,4 @@
-import { NModal, NUpload, UploadFileInfo, useMessage } from 'naive-ui';
+import { NModal, NSpin, NUpload, UploadFileInfo, useMessage } from 'naive-ui';
 import { defineComponent, watch, PropType, reactive, ref } from 'vue';
 import { policy } from '@/components/upload-file/api';
 import Copper from '@/components/upload-file/copper';
@@ -386,28 +386,30 @@ export default defineComponent({
 
     return () => (
       <div class={styles.uploadFile}>
-        <NUpload
-          ref={uploadRef}
-          action={ossUploadUrl}
-          data={state}
-          v-model:fileList={fileListRef.value}
-          accept={props.accept}
-          multiple={props.multiple}
-          max={props.max}
-          disabled={props.disabled}
-          showFileList={props.showFileList}
-          showPreviewButton
-          onBeforeUpload={(options: any) => onBeforeUpload(options)}
-          onFinish={(options: any) => onFinish(options)}
-          onRemove={() => onRemove()}>
-          {props.showType === 'default' && (
-            <div class={styles.uploadBtn}>
-              <img src={iconUploadAdd} class={styles.iconUploadAdd} />
-              <p>上传</p>
-            </div>
-          )}
-          {props.showType === 'custom' && slots.custom && slots.custom()}
-        </NUpload>
+        <NSpin show={btnLoading.value} description="上传中...">
+          <NUpload
+            ref={uploadRef}
+            action={ossUploadUrl}
+            data={state}
+            v-model:fileList={fileListRef.value}
+            accept={props.accept}
+            multiple={props.multiple}
+            max={props.max}
+            disabled={props.disabled}
+            showFileList={props.showFileList}
+            showPreviewButton
+            onBeforeUpload={(options: any) => onBeforeUpload(options)}
+            onFinish={(options: any) => onFinish(options)}
+            onRemove={() => onRemove()}>
+            {props.showType === 'default' && (
+              <div class={styles.uploadBtn}>
+                <img src={iconUploadAdd} class={styles.iconUploadAdd} />
+                <p>上传</p>
+              </div>
+            )}
+            {props.showType === 'custom' && slots.custom && slots.custom()}
+          </NUpload>
+        </NSpin>
 
         <NModal
           v-model:show={visiable.value}

+ 1 - 0
src/views/natural-resources/components/share-resources/index.module.less

@@ -67,6 +67,7 @@
     width: 360px;
     height: 42px;
     font-size: 16px;
+    --n-height: 42px !important;
 
     img {
       width: 18px;

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

@@ -90,11 +90,12 @@ export default defineComponent({
           onAdd={() => (state.teachingStatus = true)}
         />
 
-        <NSpin v-model:show={state.loading}>
+        <NSpin v-model:show={state.loading} style={{ 'min-height': '50vh' }}>
           <div class={styles.list}>
             {state.tableList.map((item: any) => (
               <CardType
                 item={item}
+                disabledMouseHover={false}
                 onClick={(val: any) => {
                   if (val.type === 'IMG') return;
                   state.show = true;

+ 2 - 0
src/views/natural-resources/index.module.less

@@ -2,6 +2,7 @@
   padding: 32px 20px;
   background-color: #fff;
   border-radius: 20px;
+  // min-height: calc(100% - 104px);
 
   :global {
     .n-tabs-tab-pad {
@@ -115,6 +116,7 @@
     width: 360px;
     height: 42px;
     font-size: 16px;
+
     :global {
       .n-input-wrapper {
         padding-left: 12px;

+ 1 - 1
src/views/natural-resources/index.tsx

@@ -10,7 +10,7 @@ export default defineComponent({
     return () => (
       <div class={styles.listWrap}>
         <NTabs
-          defaultValue="myResources"
+          defaultValue="shareResources"
           paneClass={styles.paneTitle}
           justifyContent="center"
           animated

+ 53 - 3
src/views/natural-resources/model/add-teaching/index.tsx

@@ -8,7 +8,13 @@ import {
   NSpace,
   useMessage
 } from 'naive-ui';
-import { TransitionGroup, defineComponent, reactive, ref } from 'vue';
+import {
+  TransitionGroup,
+  defineComponent,
+  onMounted,
+  reactive,
+  ref
+} from 'vue';
 import styles from './index.module.less';
 import UploadFile from '@/components/upload-file';
 import { nextTick } from 'vue';
@@ -22,6 +28,7 @@ import btnDelete from '../../images/btn-delete.svg';
 import btnUp from '../../images/btn-up.svg';
 import btnDown from '../../images/btn-down.svg';
 import btnRemove from '../../images/btn-remove.svg';
+import { lessonCoursewareDetail } from '/src/views/prepare-lessons/api';
 export const BOOK_DATA = {
   grades: [
     { label: '一年级', value: 1 },
@@ -67,7 +74,13 @@ const initState = () => ({
 
 export default defineComponent({
   name: 'addNatural',
-  emits: ['close'],
+  props: {
+    item: {
+      type: Object,
+      default: () => ({})
+    }
+  },
+  emits: ['close', 'confirm'],
   setup(props, { emit }) {
     const message = useMessage();
     const data = reactive({
@@ -91,14 +104,51 @@ export default defineComponent({
         Object.assign(form, initState());
         message.success('添加成功');
         emit('close', true);
+        emit('confirm');
       } catch {
         //
       }
       data.uploading = false;
     };
+
+    onMounted(async () => {
+      if (props.item.id) {
+        const { data } = await lessonCoursewareDetail({ id: props.item.id });
+        form.id = data.id;
+        form.name = data.name;
+        form.currentGradeNum = data.currentGradeNum;
+        form.bookType = data.bookType;
+        form.coverImg = data.coverImg;
+        form.lessonList = [];
+        const lessonList = data.lessonList || [];
+        const tempLesson: any[] = [];
+        lessonList.forEach((item: any) => {
+          const tmpItem: any = {
+            id: item.id,
+            key: 'item' + Date.now() + '-' + Math.random() * 100,
+            name: item.name,
+            lessonTargetDesc: item.lessonTargetDesc,
+            knowledgeList: [] as any
+          };
+
+          if (item.knowledgeList && item.knowledgeList.length) {
+            item.knowledgeList.forEach((knowledge: any) => {
+              tmpItem.knowledgeList.push({
+                id: knowledge.id,
+                key: Date.now() + '-' + Math.random() * 100,
+                name: knowledge.name
+              });
+            });
+          }
+          tempLesson.push(tmpItem);
+        });
+
+        form.lessonList = tempLesson;
+      }
+    });
     return () => (
       <div class={styles.container}>
-        <NScrollbar style={{ 'max-height': '55vh' }}>
+        <NScrollbar style={{ 'max-height': '65vh' }}>
           <NForm
             ref={formRef}
             labelPlacement="left"

+ 35 - 0
src/views/prepare-lessons/api.ts

@@ -0,0 +1,35 @@
+import request from '@/utils/request';
+
+/**
+ * 备课 - 教学课件
+ */
+export const lessonCoursewarePage = (params: any) => {
+  return request.post('/edu-app/lessonCourseware/page', {
+    data: params
+  });
+};
+
+/**
+ * 备课 - 教学课件详情
+ */
+export const lessonCoursewareDetail = (params: any) => {
+  return request.get('/edu-app/lessonCourseware/detail/' + params.id, {});
+};
+
+/**
+ * 备课 - 教学课件删除
+ */
+export const lessonCoursewareRemove = (params: any) => {
+  return request.post('/edu-app/lessonCourseware/remove', {
+    data: params
+  });
+};
+
+/**
+ * 备课 - 课件列表
+ */
+export const queryCourseware = (params: any) => {
+  return request.post('/edu-app/teacherKnowledgeMaterial/queryCourseware', {
+    data: params
+  });
+};

+ 39 - 0
src/views/prepare-lessons/components/directory-main/images/icon-custom.svg

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="80px" height="82px" viewBox="0 0 80 82" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>编组 6</title>
+    <defs>
+        <linearGradient x1="16.0585307%" y1="48.1812553%" x2="88.7815146%" y2="51.655599%" id="linearGradient-1">
+            <stop stop-color="#308AFF" offset="0%"></stop>
+            <stop stop-color="#60A9FF" offset="100%"></stop>
+        </linearGradient>
+        <path d="M26.1421356,-9.86533591e-13 L77.8578644,-9.86533591e-13 C80.5100293,-9.92349856e-13 83.0535684,1.0535684 84.9289322,2.92893219 L104,22 L104,22 L-8.56952355e-13,22 L19.0710678,2.92893219 C20.9464316,1.0535684 23.4899707,-9.86046396e-13 26.1421356,-9.86533591e-13 Z" id="path-2"></path>
+        <linearGradient x1="50%" y1="13.692199%" x2="50%" y2="69.4941756%" id="linearGradient-4">
+            <stop stop-color="#FFFFFF" stop-opacity="0.404392483" offset="0%"></stop>
+            <stop stop-color="#FFFFFF" stop-opacity="0" offset="100%"></stop>
+        </linearGradient>
+    </defs>
+    <g id="所有页面" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="46、选择教材" transform="translate(-1010.000000, -322.000000)">
+            <g id="编组-4" transform="translate(385.000000, 127.000000)">
+                <g id="编组-2备份-2" transform="translate(605.000000, 179.703907)">
+                    <g id="编组-6" transform="translate(3.703907, 0.000000)">
+                        <g id="编组-5" transform="translate(48.777762, 48.777762) rotate(-45.000000) translate(-48.777762, -48.777762) translate(-4.075266, 32.648617)">
+                            <path d="M0.577507392,31.6130682 L-1.44486575e-13,24.5356078 L-1.44486575e-13,24.5356078 C0.150435792,23.0883 1.1854755,22.0762681 3.10511912,21.4995122 C5.02476274,20.9227562 7.59556321,20.1716791 10.8175205,19.2462809 L11.1122213,21.7991185 L1.08841361,31.8010336 C0.971128318,31.9180628 0.781178938,31.9178551 0.664149799,31.8005698 C0.613985136,31.7502954 0.583283393,31.6838541 0.577507392,31.6130682 Z" id="路径-33" fill="#1E3DCC"></path>
+                            <path d="M95.1713422,31.6130682 L94.5938348,24.5356078 L94.5938348,24.5356078 C94.7442706,23.0883 95.7793103,22.0762681 97.698954,21.4995122 C99.6185976,20.9227562 102.189398,20.1716791 105.411355,19.2462809 L105.706056,21.7991185 L95.6822485,31.8010336 C95.5649632,31.9180628 95.3750138,31.9178551 95.2579846,31.8005698 C95.20782,31.7502954 95.1771182,31.6838541 95.1713422,31.6130682 Z" id="路径-33备份" fill="#1E3DCC" transform="translate(100.149945, 25.752285) scale(-1, 1) translate(-100.149945, -25.752285) "></path>
+                            <g id="矩形" transform="translate(0.845434, 0.711632)">
+                                <mask id="mask-3" fill="white">
+                                    <use xlink:href="#path-2"></use>
+                                </mask>
+                                <use id="蒙版" fill="url(#linearGradient-1)" transform="translate(52.000000, 11.000000) rotate(-360.000000) translate(-52.000000, -11.000000) " xlink:href="#path-2"></use>
+                                <rect fill="url(#linearGradient-4)" mask="url(#mask-3)" transform="translate(30.713441, 12.039373) rotate(-315.000000) translate(-30.713441, -12.039373) " x="24.713441" y="-13.960627" width="12" height="52"></rect>
+                            </g>
+                            <text id="自定义" transform="translate(52.499475, 11.000000) rotate(-360.000000) translate(-52.499475, -11.000000) " font-family="PingFangSC-Semibold, PingFang SC" font-size="16" font-weight="500" letter-spacing="1" fill="#FFFFFF">
+                                <tspan x="26.9994747" y="17">自定义</tspan>
+                            </text>
+                        </g>
+                    </g>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

+ 30 - 0
src/views/prepare-lessons/components/directory-main/images/icon-upload-bg.svg

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="158px" height="224px" viewBox="0 0 158 224" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>编组 7</title>
+    <defs>
+        <rect id="path-1" x="0" y="0" width="158" height="224"></rect>
+    </defs>
+    <g id="所有页面" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="46、选择教材" transform="translate(-470.000000, -330.000000)">
+            <g id="编组-4" transform="translate(385.000000, 127.000000)">
+                <g id="编组-2" transform="translate(57.000000, 203.000000)">
+                    <g id="编组-7" transform="translate(28.000000, 0.000000)">
+                        <mask id="mask-2" fill="white">
+                            <use xlink:href="#path-1"></use>
+                        </mask>
+                        <use id="蒙版" fill="#F8F9FB" xlink:href="#path-1"></use>
+                        <g id="编组" mask="url(#mask-2)" fill="#859BD4">
+                            <g transform="translate(54.000000, 65.000000)" id="矩形">
+                                <rect x="0" y="21" width="50" height="8" rx="4"></rect>
+                                <rect transform="translate(25.000000, 25.000000) rotate(-270.000000) translate(-25.000000, -25.000000) " x="-5.45696821e-12" y="21" width="50" height="8" rx="4"></rect>
+                            </g>
+                        </g>
+                        <text id="添加自定义教材" mask="url(#mask-2)" font-family="PingFangSC-Regular, PingFang SC" font-size="18" font-weight="normal" fill="#859BD4">
+                            <tspan x="16" y="154">添加自定义教材</tspan>
+                        </text>
+                    </g>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

+ 40 - 0
src/views/prepare-lessons/components/directory-main/images/icon_default.svg

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="51px" height="49px" viewBox="0 0 51 49" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>编组@2x</title>
+    <defs>
+        <linearGradient x1="60.3790157%" y1="14.1179897%" x2="60.3790157%" y2="99.1367692%" id="linearGradient-1">
+            <stop stop-color="#D8D9DB" offset="0%"></stop>
+            <stop stop-color="#D3D4D6" offset="100%"></stop>
+        </linearGradient>
+        <linearGradient x1="47.928727%" y1="88.2137009%" x2="47.928727%" y2="-1.32949207e-12%" id="linearGradient-2">
+            <stop stop-color="#D0D1D3" offset="0%"></stop>
+            <stop stop-color="#CACBCD" offset="100%"></stop>
+        </linearGradient>
+        <linearGradient x1="57.5601934%" y1="1.66592618%" x2="56.4312509%" y2="99.1367692%" id="linearGradient-3">
+            <stop stop-color="#D8D9DB" offset="0%"></stop>
+            <stop stop-color="#D1D2D4" offset="100%"></stop>
+        </linearGradient>
+        <linearGradient x1="47.928727%" y1="88.2137009%" x2="47.928727%" y2="-1.32949207e-12%" id="linearGradient-4">
+            <stop stop-color="#D0D1D3" offset="0%"></stop>
+            <stop stop-color="#C8C9CB" offset="100%"></stop>
+        </linearGradient>
+        <linearGradient x1="47.928727%" y1="88.2137009%" x2="47.928727%" y2="-1.32949207e-12%" id="linearGradient-5">
+            <stop stop-color="#CFD0D2" offset="0%"></stop>
+            <stop stop-color="#CBCCCE" offset="100%"></stop>
+        </linearGradient>
+    </defs>
+    <g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="67、小酷AI" transform="translate(-1720.000000, -737.000000)" fill-rule="nonzero">
+            <g id="编组" transform="translate(1720.000000, 737.000000)">
+                <g id="编组-6" transform="translate(0.600000, 0.666667)">
+                    <path d="M0.755328486,15.0252525 C-0.830540243,19.9313215 0.11107891,25.262202 3.29524979,29.4047571 C6.47942068,33.5473122 11.5319763,36.0147566 16.9240016,36.0606061 C24.4286025,36.09296 31.0759035,31.4573623 33.3061224,24.6361115 L0.755328486,15.0252525 Z" id="路径" fill="url(#linearGradient-1)"></path>
+                    <path d="M17.7262393,31.0568351 C8.4521233,30.9803529 0.940551474,23.8601879 0.813375057,15.0252525 L0.754723889,15.0252525 C-0.829875444,19.9313026 0.110989998,25.2621626 3.29261214,29.4047017 C6.47423428,33.5472408 11.5227456,36.0146758 16.9104549,36.060355 C24.4276023,36.0999738 31.0862959,31.4479077 33.3061224,24.6055962 L31.7758601,24.1535015 C28.5683718,28.5148198 23.3157927,31.0956941 17.7262393,31.0568351 L17.7262393,31.0568351 Z" id="路径" fill="url(#linearGradient-2)"></path>
+                    <path d="M14.7677422,5.37825957 C14.7677422,5.37825957 18.3328036,4.44948812 20.0004184,7.54187485 C15.9970737,11.1250329 13.586515,16.8823604 15.6870684,21.3679043 C16.5048411,23.1304592 18.0548677,24.5341705 18.6962581,26.4392074 C20.6791709,32.3335664 18.6004257,38.818554 13.5437557,42.5132859 L13.4849616,42.5555028 C13.4849616,42.5555028 12.9504696,42.951286 12.1113173,43.5370453 C14.650154,45.1782267 18.4236672,47.1360346 21.8711403,47.7956734 C30.2359393,49.4051921 38.8305699,44.0067081 42.0642462,36.4921028 C42.3367119,35.8608728 42.5652914,35.2120441 42.7483959,34.5501262 C43.5795078,31.4293042 43.8097647,28.1821626 43.4272007,24.9774478 C43.202714,23.0407483 42.6147729,19.4681445 45.3674064,19.0354214 C46.4363903,18.8665539 47.4626149,19.4048192 48.2803876,20.0539038 C48.4033207,20.1488917 49.5364437,21.067109 49.4562699,21.2518078 C51.2735425,16.9351315 48.2964223,5.51018733 38.3869416,1.64734247 C31.0376772,-1.32367072 20.3692179,-0.389622168 14.7677422,5.37825957 Z" id="路径" fill="url(#linearGradient-3)"></path>
+                    <path d="M26.6124657,47.6072826 C21.4912819,46.636432 18.7337213,44.7527707 16.9716508,43.1698621 C17.8393774,42.600015 18.3557545,42.2148405 18.3557545,42.2148405 L18.4143128,42.1726296 C23.5265567,38.5761859 25.72439,32.1283454 23.8602286,26.1958052 C23.2533524,24.2752094 21.7308383,22.8505916 20.9589343,21.077734 C18.9626308,16.5558917 21.459341,10.8415915 25.5105062,7.33281071 C23.9134634,4.20920435 20.3414111,5.07452773 20.3414111,5.07452773 C23.237382,2.18835767 27.421634,0.584343589 31.7922078,0.114747363 C25.5850348,-0.47092883 18.8188969,1.17001978 14.7570848,5.39110946 C14.7570848,5.39110946 18.3078432,4.46774609 19.9687677,7.55441792 C15.9814843,11.1370678 13.5805966,16.8988552 15.6727227,21.383763 C16.4872145,23.1407916 18.0310225,24.5495802 18.6698396,26.4490706 C20.6447971,32.3425937 18.5743917,38.8266616 13.5380088,42.5208695 L13.4794506,42.5630804 C13.4794506,42.5630804 12.947103,42.9640839 12.1113173,43.5444838 C14.6399683,45.1907088 18.3983423,47.1429627 21.8319843,47.8077844 C23.7881287,48.171816 25.7955452,48.171816 27.7516896,47.8077844 C27.3524289,47.744468 26.9797855,47.6811517 26.6124657,47.6072826 Z" id="路径" fill="url(#linearGradient-4)"></path>
+                    <path d="M45.0423476,14.0093804 C46.200789,13.854566 48.445269,13.5716291 48.445269,13.5716291 C46.707607,9.89878877 42.4247158,7.65130943 39.7402509,6.83452952 C39.7068343,6.83452952 38.3200464,6.42347036 38.3311852,6.43948565 C33.2852822,5.3717995 29.0190992,6.29000959 25.799969,9.25283865 C22.37477,12.4025128 21.6340358,17.9598192 24.3964728,21.7340897 C25.154529,22.6993831 26.100114,23.5151123 27.1811875,24.1363836 C25.0592349,38.8384218 37.0335082,40.6855189 37.1560356,40.562735 C39.1777385,38.2405176 41.2105802,35.939654 41.2105802,28.0601302 C41.2105802,25.9247579 40.2916244,22.4120704 40.1579581,21.5045372 C39.5230431,17.1750699 40.8652756,14.5966078 45.0423476,14.0093804 Z" id="路径" fill="#F4F5F7"></path>
+                    <ellipse id="椭圆形" fill="url(#linearGradient-5)" cx="35.5769944" cy="14.2739899" rx="2.27087199" ry="2.25378788"></ellipse>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

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

@@ -1,6 +1,6 @@
 .directoryList {
   height: 100%;
-  padding: 24px 20px;
+  padding: 24px 0;
 
   :global {
     .n-scrollbar-container {
@@ -10,6 +10,7 @@
 
   .scrollBar {
     margin-top: 12px;
+    padding: 0 20px;
     max-height: calc(100% - 49px - 12px);
   }
 }
@@ -20,7 +21,7 @@
   background: #E8F4FF;
   border-radius: 10px;
   padding: 0 16px;
-  margin-bottom: 12px;
+  margin: 0 20px 12px;
   font-size: 18px;
   font-weight: 600;
   color: #131415;
@@ -103,4 +104,8 @@
       font-weight: bold;
     }
   }
+}
+
+.coursewareModal {
+  width: 1150px;
 }

+ 124 - 286
src/views/prepare-lessons/components/directory-main/index.tsx

@@ -1,312 +1,124 @@
-import { defineComponent, reactive, ref } from 'vue';
+import { defineComponent, onMounted, reactive, ref } from 'vue';
 import styles from './index.module.less';
-import { NIcon, NSpin, NScrollbar } from 'naive-ui';
+import { NIcon, NSpin, NScrollbar, NModal } from 'naive-ui';
+import { lessonCoursewareDetail, lessonCoursewarePage } from '../../api';
+import SelectLessonware from './select-lessonware';
+import TheEmpty from '/src/components/TheEmpty';
+import { usePrepareStore } from '/src/store/modules/prepareLessons';
 
 export default defineComponent({
   name: 'directory-main',
   setup() {
+    const prepareStore = usePrepareStore();
     const show = ref(true);
     const forms = reactive({
-      expandedKey: null, // 展开
-      selectKey: 16 // 选的
+      coursewareStatus: false
     });
-    const treeList = ref([
-      {
-        key: 1,
-        label: '第1课 好朋友',
-        selected: false,
-        children: [
-          {
-            key: 10,
-            label: '玩具兵进行曲'
-          },
-          {
-            key: 11,
-            label: '口哨与小狗'
-          },
-          {
-            key: 12,
-            label: '你的名字叫什么?'
-          },
-          {
-            key: 13,
-            label: '拉勾勾'
-          },
-          {
-            key: 14,
-            label: '唱歌姿势'
-          }
-        ]
-      },
-      {
-        key: 2,
-        label: '第2课 快乐的一天',
-        selected: true,
-        children: [
-          {
-            key: 15,
-            label: '快乐的一天'
-          },
-          {
-            key: 16,
-            label: '其多列'
-          },
-          {
-            key: 17,
-            label: '跳绳'
-          }
-        ]
-      },
-      {
-        key: 3,
-        label: '第3课 祖国您好',
-        selected: false,
-        children: [
-          {
-            key: 18,
-            label: '中华人民共和国国歌'
-          },
-          {
-            key: 19,
-            label: '颂祖国'
-          },
-          {
-            key: 20,
-            label: '国旗国旗真美丽'
-          },
-          {
-            key: 21,
-            label: '同唱一首歌'
-          },
-          {
-            key: 22,
-            label: '音的强弱'
-          }
-        ]
-      },
-      {
-        key: 4,
-        label: '第4课 可爱的动物',
-        selected: false,
-        children: [
-          {
-            key: 23,
-            label: '快乐的小熊猫'
-          },
-          {
-            key: 24,
-            label: '袋鼠'
-          },
-          {
-            key: 25,
-            label: '动物说话'
-          },
-          {
-            key: 26,
-            label: '咏鹅'
-          },
-          {
-            key: 27,
-            label: '木鱼 碰钟'
-          }
-        ]
-      },
-      {
-        key: 5,
-        label: '第5课 爱劳动',
-        selected: false,
-        children: [
-          {
-            key: 28,
-            label: '劳动最光荣'
-          },
-          {
-            key: 29,
-            label: '三个和尚'
-          },
-          {
-            key: 30,
-            label: '洗手绢'
-          },
-          {
-            key: 31,
-            label: '大家来劳动'
-          }
-        ]
-      },
-      {
-        key: 6,
-        label: '第6课 小精灵',
-        selected: false,
-        children: [
-          {
-            key: 32,
-            label: '小青蛙'
-          },
-          {
-            key: 33,
-            label: '野蜂飞舞'
-          },
-          {
-            key: 34,
-            label: '小青蛙找家'
-          },
-          {
-            key: 35,
-            label: '小蜻蜓'
-          },
-          {
-            key: 36,
-            label: '响板'
-          }
-        ]
-      },
-      {
-        key: 7,
-        label: '游戏宫',
-        selected: false,
-        children: [
-          {
-            key: 37,
-            label: '欢乐的游乐园'
-          }
-        ]
-      },
-      {
-        key: 8,
-        label: '第7课 小小音乐家',
-        selected: false,
-        children: [
-          {
-            key: 38,
-            label: '号手与鼓手'
-          },
-          {
-            key: 39,
-            label: '会跳舞的洋娃娃'
-          },
-          {
-            key: 40,
-            label: '星光圆舞曲'
-          },
-          {
-            key: 41,
-            label: '法国号'
-          },
-          {
-            key: 42,
-            label: '快乐的小笛子'
-          },
-          {
-            key: 43,
-            label: '音的长短'
-          }
-        ]
-      },
-      {
-        key: 9,
-        label: '第8课 过新年',
-        selected: false,
-        children: [
-          {
-            key: 44,
-            label: '小拜年'
-          },
-          {
-            key: 45,
-            label: '平安夜'
-          },
-          {
-            key: 46,
-            label: '龙咚锵'
-          },
-          {
-            key: 47,
-            label: '新年好'
-          },
-          {
-            key: 48,
-            label: '锣 鼓 镲'
-          }
-        ]
-      },
-      {
-        key: -1,
-        label: '欢乐谷',
-        selected: false,
-        children: [
-          {
-            key: 49,
-            label: '小鼓响咚咚'
-          },
-          {
-            key: 50,
-            label: '我有一只小羊羔'
-          },
-          {
-            key: 51,
-            label: '大月亮'
-          },
-          {
-            key: 52,
-            label: '我的音乐表现'
+
+    const getLessonCourseware = async () => {
+      try {
+        const { data } = await lessonCoursewarePage({
+          page: 1,
+          rows: 1,
+          type: 'COURSEWARE',
+          enableFlag: 1
+        });
+
+        if (data.rows.length > 0) {
+          prepareStore.setBaseCourseware(data.rows[0]);
+        }
+      } catch {
+        //
+      }
+    };
+
+    const getLessonCoursewareDetail = async () => {
+      try {
+        const baseCourseware: any = prepareStore.getBaseCourseware;
+        if (!baseCourseware.id) return;
+        const { data } = await lessonCoursewareDetail({
+          id: baseCourseware.id
+        });
+        const tempList: any = data.lessonList || [];
+        tempList.forEach((item: any, index: number) => {
+          item.selected = false;
+          if (index === 0) {
+            item.selected = true;
+            const temp = item['knowledgeList'][0];
+            prepareStore.setSelectKey(temp?.id);
+            prepareStore.setLessonCoursewareId(temp?.lessonCoursewareId);
+            prepareStore.setLessonCoursewareDetailId(
+              temp?.lessonCoursewareDetailId
+            );
           }
-        ]
+        });
+        prepareStore.setTreeList(tempList);
+      } catch {
+        //
       }
-    ]);
+    };
 
-    setTimeout(() => {
+    onMounted(async () => {
+      show.value = true;
+      await getLessonCourseware();
+      await getLessonCoursewareDetail();
       show.value = false;
-    }, 100);
+    });
     return () => (
       <div class={styles.directoryList}>
-        <div class={styles['select-directory']}>
-          <span class={['cr-ellipsis']} title="人教版二年级上册(2013)">
-            人教版二年级上册(2013)
-          </span>
-          <NIcon class={styles.iconArrow}>
-            <svg
-              width="11px"
-              height="15px"
-              viewBox="0 0 11 15"
-              version="1.1"
-              xmlns="http://www.w3.org/2000/svg">
-              <g
-                stroke="none"
-                stroke-width="1"
-                fill="none"
-                fill-rule="evenodd"
-                opacity="0.699999988">
+        {prepareStore.getBaseCourseware.id && (
+          <div
+            class={styles['select-directory']}
+            onClick={() => (forms.coursewareStatus = true)}>
+            <span
+              class={['cr-ellipsis']}
+              title={prepareStore.getBaseCourseware.name}>
+              {prepareStore.getBaseCourseware.name}
+            </span>
+            <NIcon class={styles.iconArrow}>
+              <svg
+                width="11px"
+                height="15px"
+                viewBox="0 0 11 15"
+                version="1.1"
+                xmlns="http://www.w3.org/2000/svg">
                 <g
-                  transform="translate(-445.000000, -137.000000)"
-                  fill="#131415">
-                  <g transform="translate(152.000000, 120.000000)">
-                    <path
-                      d="M299.326227,20.2118001 L304.934089,28.4366632 C305.245211,28.8929759 305.127511,29.515105 304.671198,29.8262273 C304.505147,29.9394437 304.308836,30 304.107861,30 L292.892139,30 C292.339854,30 291.892139,29.5522847 291.892139,29 C291.892139,28.7990254 291.952695,28.6027139 292.065911,28.4366632 L297.673773,20.2118001 C297.984895,19.7554873 298.607024,19.6377872 299.063337,19.9489096 C299.16663,20.0193364 299.255801,20.1085074 299.326227,20.2118001 Z"
-                      id="三角形"
-                      transform="translate(298.500000, 24.500000) rotate(-270.000000) translate(-298.500000, -24.500000) "></path>
+                  stroke="none"
+                  stroke-width="1"
+                  fill="none"
+                  fill-rule="evenodd"
+                  opacity="0.699999988">
+                  <g
+                    transform="translate(-445.000000, -137.000000)"
+                    fill="#131415">
+                    <g transform="translate(152.000000, 120.000000)">
+                      <path
+                        d="M299.326227,20.2118001 L304.934089,28.4366632 C305.245211,28.8929759 305.127511,29.515105 304.671198,29.8262273 C304.505147,29.9394437 304.308836,30 304.107861,30 L292.892139,30 C292.339854,30 291.892139,29.5522847 291.892139,29 C291.892139,28.7990254 291.952695,28.6027139 292.065911,28.4366632 L297.673773,20.2118001 C297.984895,19.7554873 298.607024,19.6377872 299.063337,19.9489096 C299.16663,20.0193364 299.255801,20.1085074 299.326227,20.2118001 Z"
+                        id="三角形"
+                        transform="translate(298.500000, 24.500000) rotate(-270.000000) translate(-298.500000, -24.500000) "></path>
+                    </g>
                   </g>
                 </g>
-              </g>
-            </svg>
-          </NIcon>
-        </div>
+              </svg>
+            </NIcon>
+          </div>
+        )}
 
         <NScrollbar class={styles.scrollBar}>
           <NSpin show={show.value}>
-            {treeList.value.map((item: any, index: number) => (
+            {prepareStore.getTreeList.map((item: any, index: number) => (
               <div class={styles.treeParent} key={'parent' + index}>
                 <div
                   class={[styles.treeItem, styles.parentItem]}
                   onClick={() => {
-                    treeList.value.forEach((child: any) => {
-                      if (item.key !== child.key) {
+                    prepareStore.getTreeList.forEach((child: any) => {
+                      if (item.id !== child.id) {
                         child.selected = false;
                       }
                     });
                     item.selected = item.selected ? false : true;
                   }}>
-                  {item.children && item.children.length > 0 && (
+                  {item.knowledgeList && item.knowledgeList.length > 0 && (
                     <span
                       class={[
                         styles.arrow,
@@ -318,32 +130,58 @@ export default defineComponent({
                       styles.title,
                       item.selected ? styles.titleSelect : ''
                     ]}>
-                    {item.label}
+                    {item.name}
                   </p>
                 </div>
 
                 {item.selected &&
-                  item.children &&
-                  item.children.map((child: any, j: number) => (
+                  item.knowledgeList &&
+                  item.knowledgeList.map((child: any, j: number) => (
                     <div
                       key={'child' + j}
                       class={[
                         styles.treeItem,
                         styles.childItem,
                         styles.animation,
-                        forms.selectKey === child.key ? styles.childSelect : ''
+                        prepareStore.getSelectKey === child.id
+                          ? styles.childSelect
+                          : ''
                       ]}
                       onClick={() => {
-                        forms.selectKey = child.key;
+                        prepareStore.setSelectKey(child.id);
+                        prepareStore.setLessonCoursewareId(
+                          child.lessonCoursewareId
+                        );
+                        prepareStore.setLessonCoursewareDetailId(
+                          child.lessonCoursewareDetailId
+                        );
                       }}>
                       <span class={styles.childArrow}></span>
-                      <p class={styles.title}>{child.label}</p>
+                      <p class={styles.title}>{child.name}</p>
                     </div>
                   ))}
               </div>
             ))}
           </NSpin>
+          {!show.value && prepareStore.getTreeList.length <= 0 && <TheEmpty />}
         </NScrollbar>
+
+        {/* 选择教材 */}
+        <NModal
+          v-model:show={forms.coursewareStatus}
+          preset="card"
+          showIcon={false}
+          class={['modalTitle background', styles.coursewareModal]}
+          title={'选择教材'}
+          blockScroll={false}>
+          <SelectLessonware
+            onClose={() => (forms.coursewareStatus = false)}
+            onConfirm={(item: any) => {
+              prepareStore.setBaseCourseware(item);
+              getLessonCoursewareDetail();
+            }}
+          />
+        </NModal>
       </div>
     );
   }

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

@@ -0,0 +1,193 @@
+.attendClassSearch {
+  width: 100%;
+  display: flex;
+  align-items: center;
+  gap: 0 24px;
+  margin-bottom: 6px;
+  padding: 32px 40px 0;
+
+  :global {
+
+    .n-base-selection,
+    .n-input {
+      height: 52px;
+      min-height: 52px;
+      --n-height: 52px !important;
+      font-size: 18px;
+      border-radius: 8px !important;
+    }
+  }
+
+  .iconSearch {
+    width: 16px;
+    height: 17px;
+  }
+}
+
+.classList {
+  min-height: 50vh;
+  max-height: 60vh;
+
+  .content {
+    padding: 32px 40px;
+  }
+}
+
+.item {
+  position: relative;
+  width: 214px;
+  cursor: pointer;
+  transition: all .3s;
+
+  .cover {
+    position: relative;
+    overflow: hidden;
+
+    &::before {
+      content: '';
+      position: absolute;
+      top: 107px;
+      left: 0;
+      width: 214px;
+      height: 214px;
+      background: #DDF2FF;
+      border-radius: 50%;
+    }
+  }
+
+  .iconCustom {
+    position: absolute;
+    top: -8px;
+    left: -7px;
+    width: 80px;
+    height: 81px;
+    background: url('../images/icon-custom.svg') no-repeat center;
+    background-size: contain;
+    z-index: 9;
+  }
+
+  .editContainer {
+    opacity: 0;
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(0, 0, 0, 0.7);
+    z-index: 8;
+    display: none;
+    align-items: flex-end;
+    justify-content: center;
+
+    .editBtnGroup {
+      padding-bottom: 7px;
+    }
+
+    .delBtn,
+    .editBtn {
+      height: 30px;
+      font-size: 16px;
+      font-weight: 600;
+      border: none;
+      border-radius: 4px;
+    }
+
+    .delBtn {
+      color: #fff;
+      background: #EA4132;
+      border: 1px solid #EA4132;
+      margin-right: 9px;
+    }
+
+    .editBtn {
+      color: #131415;
+    }
+  }
+
+  &:hover {
+    transform: scale(1.05);
+
+    .editContainer {
+      display: flex;
+      opacity: 1;
+    }
+  }
+
+  .itemImg {
+    position: relative;
+    width: 158px;
+    height: 223px;
+    margin: auto;
+    background-color: #EDEFF2;
+    background-image: url('../images/icon_default.svg');
+    background-repeat: no-repeat;
+    background-position: center center;
+
+    &::before {
+      content: '';
+      position: absolute;
+      top: 4px;
+      right: -4px;
+      width: 4px;
+      height: calc(100% - 8px);
+      background-color: #C5C5C5;
+      z-index: 1;
+    }
+
+    &::after {
+      content: '';
+      position: absolute;
+      top: 2px;
+      right: -2px;
+      width: 4px;
+      height: calc(100% - 4px);
+      background-color: #E7E7E7;
+      z-index: 2;
+    }
+
+    .itemBg {
+      position: absolute;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      z-index: 4;
+      background-repeat: no-repeat;
+      background-image: linear-gradient(to right, rgba(0, 0, 0, 0.2) 0, rgba(255, 255, 255, 0.08) 0%, transparent 0.5%), linear-gradient(to right, rgba(0, 0, 0, 0.1) 0.3%, rgba(255, 255, 255, 0.09) 1.1%, transparent 1.3%);
+      background-size: 50% 100%, 50% 100%;
+      background-position: 0% top, 9% top;
+    }
+
+    :global {
+      .n-image {
+        position: relative;
+        width: 100%;
+        height: 100%;
+        z-index: 3;
+      }
+    }
+
+    img {
+      transition: opacity .3s;
+      opacity: 0;
+    }
+
+    img[data-loaded="true"] {
+      opacity: 1;
+    }
+
+
+  }
+
+  .itemName {
+    margin-top: 16px;
+    font-size: 16px;
+    font-weight: 600;
+    color: #131415;
+    text-align: center;
+  }
+}
+
+.teachingModal {
+  width: 1100px;
+}

+ 215 - 0
src/views/prepare-lessons/components/directory-main/select-lessonware/index.tsx

@@ -0,0 +1,215 @@
+import { defineComponent, onMounted, reactive } from 'vue';
+import styles from './index.module.less';
+import {
+  NButton,
+  NImage,
+  NInput,
+  NModal,
+  NScrollbar,
+  NSelect,
+  NSpace,
+  useDialog,
+  useMessage
+} from 'naive-ui';
+import AddTeaching, {
+  BOOK_DATA
+} from '/src/views/natural-resources/model/add-teaching';
+import { lessonCoursewarePage, lessonCoursewareRemove } from '../../../api';
+import iconUploadBg from '../images/icon-upload-bg.svg';
+
+export default defineComponent({
+  name: 'select-lessonware',
+  emits: ['close', 'confirm'],
+  setup(props, { emit }) {
+    const dialog = useDialog();
+    const message = useMessage();
+    const forms = reactive({
+      currentGradeNum: null,
+      bookType: null,
+      list: [] as any[],
+      teachingStatus: false,
+      selectItem: {} as any
+    });
+
+    const getLessonCourseware = async () => {
+      try {
+        const { data } = await lessonCoursewarePage({
+          page: 1,
+          rows: 99,
+          type: 'COURSEWARE',
+          enableFlag: 1
+        });
+
+        console.log(data.rows, 'data');
+        forms.list = data.rows;
+      } catch {
+        //
+      }
+    };
+
+    // 删除教材
+    const onDelete = async (item: any) => {
+      dialog.warning({
+        title: '提示',
+        content: '是否删除该教材?',
+        positiveText: '确定',
+        negativeText: '取消',
+        onPositiveClick: async () => {
+          try {
+            await lessonCoursewareRemove({ id: item.id });
+            message.success('删除成功');
+          } catch {
+            //
+          }
+        }
+      });
+    };
+
+    const onDetail = (item: any) => {
+      emit('confirm', item);
+      emit('close');
+    };
+
+    onMounted(() => {
+      getLessonCourseware();
+    });
+    return () => (
+      <div class={styles.selectLessonware}>
+        <div class={styles.attendClassSearch}>
+          <NInput placeholder="请输入班级名称" clearable>
+            {{
+              prefix: () => <span class="icon-search-input"></span>
+            }}
+          </NInput>
+          <NSelect
+            placeholder="版本"
+            clearable
+            options={[
+              {
+                label: '一年级',
+                value: '1'
+              },
+              {
+                label: '二年级',
+                value: '2'
+              }
+            ]}
+          />
+          <NSelect
+            placeholder="请选择年级"
+            options={BOOK_DATA.grades}
+            v-model:value={forms.currentGradeNum}
+            clearable
+            filterable
+          />
+          <NSelect
+            placeholder="请选择册别"
+            options={BOOK_DATA.bookTypes}
+            v-model:value={forms.bookType}
+            clearable
+          />
+        </div>
+        <NScrollbar class={styles.classList}>
+          <div class={styles.content}>
+            <NSpace size={[50, 40]}>
+              <div
+                class={styles.item}
+                key={`item--1`}
+                onClick={() => {
+                  forms.selectItem = {};
+                  forms.teachingStatus = true;
+                }}>
+                <div class={styles.cover}>
+                  <div class={styles.itemImg}>
+                    <div class={styles.itemBg}></div>
+                    <NImage
+                      objectFit="cover"
+                      src={iconUploadBg}
+                      lazy
+                      previewDisabled={true}
+                      onLoad={e => {
+                        (e.target as any).dataset.loaded = 'true';
+                      }}
+                    />
+                  </div>
+                </div>
+              </div>
+              {forms.list.map((item: any, index: number) => {
+                return (
+                  <div
+                    class={styles.item}
+                    key={`item-${index}`}
+                    onClick={() => onDetail(item)}>
+                    <div class={styles.cover}>
+                      <div class={styles.itemImg}>
+                        <div class={styles.itemBg}></div>
+                        <NImage
+                          objectFit="cover"
+                          src={item.coverImg}
+                          lazy
+                          previewDisabled={true}
+                          onLoad={e => {
+                            (e.target as any).dataset.loaded = 'true';
+                          }}
+                        />
+                        {item.customFlag && (
+                          <>
+                            <div class={styles.iconCustom}></div>
+                            <div class={styles.editContainer}>
+                              <div class={styles.editBtnGroup}>
+                                <NButton
+                                  size="small"
+                                  class={styles.delBtn}
+                                  color="#EA4132"
+                                  onClick={(e: MouseEvent) => {
+                                    e.stopPropagation();
+                                    onDelete(item);
+                                  }}>
+                                  删除
+                                </NButton>
+                                <NButton
+                                  size="small"
+                                  class={styles.editBtn}
+                                  color="#FFFFFF"
+                                  onClick={(e: MouseEvent) => {
+                                    e.stopPropagation();
+                                    forms.selectItem = item;
+                                    forms.teachingStatus = true;
+                                  }}>
+                                  编辑
+                                </NButton>
+                              </div>
+                            </div>
+                          </>
+                        )}
+                      </div>
+                    </div>
+                    <div class={styles.itemName}>{item.name}</div>
+                  </div>
+                );
+              })}
+            </NSpace>
+          </div>
+        </NScrollbar>
+
+        {/* 添加自定义教材 */}
+        <NModal
+          v-model:show={forms.teachingStatus}
+          preset="card"
+          showIcon={false}
+          class={['modalTitle background', styles.teachingModal]}
+          title={'自定义教材'}
+          blockScroll={false}>
+          <AddTeaching
+            item={forms.selectItem}
+            onClose={() => (forms.teachingStatus = false)}
+            onConfirm={() => {
+              getLessonCourseware();
+              forms.selectItem = {};
+            }}
+          />
+        </NModal>
+      </div>
+    );
+  }
+});

+ 50 - 0
src/views/prepare-lessons/components/lesson-main/courseware/index.module.less

@@ -0,0 +1,50 @@
+.btnGroup {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding-left: 22px !important;
+  padding-right: 22px !important;
+
+  :global {
+    .n-button {
+      border-radius: 8px;
+      height: 38px;
+      font-size: 17px;
+      font-weight: 600 !important;
+      padding: 0 27px;
+    }
+
+    .n-button--default-type {
+      background: #E8F4FF;
+      color: #0378EC;
+
+      &:not(.n-button--disabled):hover {
+        background: #E8F4FF;
+      }
+
+      .n-button__border {
+        border: 1px solid #198CFE;
+      }
+    }
+  }
+}
+
+.listContainer {
+  margin-top: 12px;
+  // // 52 + 28 + 38
+  max-height: calc(var(--window-page-lesson-height) - 148px);
+}
+
+.list {
+  padding: 12px 22px 12px;
+  display: flex;
+  flex-flow: row wrap;
+  justify-content: flex-start;
+  gap: 20px;
+}
+
+.attendClassModal {
+  width: 800px;
+  border-radius: 16px;
+  overflow: hidden;
+}

+ 104 - 0
src/views/prepare-lessons/components/lesson-main/courseware/index.tsx

@@ -0,0 +1,104 @@
+import { defineComponent, onMounted, reactive, watch } from 'vue';
+import styles from './index.module.less';
+import { NButton, NModal, NScrollbar, NSpace, NSpin } from 'naive-ui';
+import CardType from '/src/components/card-type';
+import AttendClass from '/src/views/prepare-lessons/model/attend-class';
+import { usePrepareStore } from '/src/store/modules/prepareLessons';
+import TheEmpty from '/src/components/TheEmpty';
+import { queryCourseware } from '../../../api';
+
+export default defineComponent({
+  name: 'courseware-modal',
+  setup() {
+    const prepareStore = usePrepareStore();
+    const forms = reactive({
+      loadingStatus: false,
+      showAttendClass: false
+    });
+
+    const getList = async () => {
+      forms.loadingStatus = true;
+      try {
+        // 判断是否有选择对应的课件
+        if (!prepareStore.getSelectKey) return;
+        const { data } = await queryCourseware({
+          coursewareDetailKnowledgeId: prepareStore.getSelectKey,
+          lessonCoursewareId: prepareStore.getLessonCoursewareId,
+          lessonCoursewareDetailId: prepareStore.getLessonCoursewareDetailId,
+          pag: 1,
+          rows: 99
+        });
+        const tempRows = data.rows || [];
+        const temp: any = [];
+        tempRows.forEach((row: any) => {
+          temp.push({
+            id: row.id,
+            coverImg: row.coverImg,
+            type: row.materialType,
+            title: row.materialName,
+            isCollect: !!row.favoriteFlag,
+            isSelected: row.source === 'PLATFORM' ? true : false,
+            content: row.content
+          });
+        });
+
+        prepareStore.setCoursewareList(temp || []);
+      } catch {
+        //
+      }
+      forms.loadingStatus = false;
+    };
+
+    // 监听选择的key
+    watch(
+      () => prepareStore.getSelectKey,
+      () => {
+        getList();
+      }
+    );
+
+    onMounted(() => {
+      getList();
+    });
+    return () => (
+      <div class={styles.coursewareModal}>
+        <div class={styles.btnGroup}>
+          <NSpace>
+            <NButton type="default">编辑</NButton>
+          </NSpace>
+
+          <NSpace>
+            <NButton type="default">预览</NButton>
+            <NButton
+              type="primary"
+              onClick={() => (forms.showAttendClass = true)}>
+              开始上课
+            </NButton>
+          </NSpace>
+        </div>
+
+        <NScrollbar class={styles.listContainer}>
+          <NSpin show={forms.loadingStatus}>
+            <div class={styles.list}>
+              {prepareStore.getCoursewareList.map((item: any) => (
+                <CardType isShowCollect={false} item={item} />
+              ))}
+            </div>
+            {!forms.loadingStatus &&
+              prepareStore.getCoursewareList.length <= 0 && <TheEmpty />}
+          </NSpin>
+        </NScrollbar>
+
+        <NModal
+          v-model:show={forms.showAttendClass}
+          preset="card"
+          showIcon={false}
+          class={['modalTitle background', styles.attendClassModal]}
+          title={'选择班级'}
+          blockScroll={false}>
+          <AttendClass onClose={() => (forms.showAttendClass = false)} />
+        </NModal>
+      </div>
+    );
+  }
+});

+ 0 - 79
src/views/prepare-lessons/components/lesson-main/index.module.less

@@ -34,85 +34,6 @@
 
     .n-tab-pane {
       padding-top: 4px !important;
-      // padding-left: 22px !important;
-      // padding-right: 22px !important;
-    }
-  }
-}
-
-.btnGroup {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  padding-left: 22px !important;
-  padding-right: 22px !important;
-
-  :global {
-    .n-button {
-      border-radius: 8px;
-      height: 38px;
-      font-size: 17px;
-      font-weight: 600 !important;
-      padding: 0 27px;
-    }
-
-    .n-button--default-type {
-      background: #E8F4FF;
-      color: #0378EC;
-
-      &:not(.n-button--disabled):hover {
-        background: #E8F4FF;
-      }
-
-      .n-button__border {
-        border: 1px solid #198CFE;
-      }
-    }
-  }
-}
-
-.listContainer {
-  margin-top: 12px;
-  // // 52 + 28 + 38
-  max-height: calc(var(--window-page-lesson-height) - 148px);
-}
-
-.list {
-  padding: 12px 22px 12px;
-  display: flex;
-  flex-flow: row wrap;
-  justify-content: flex-start;
-  gap: 20px;
-}
-
-.attendClassModal {
-  width: 800px;
-  border-radius: 16px;
-  overflow: hidden;
-
-  :global {
-    .n-card-header {
-      position: relative;
-      padding: 20px 18px;
-      text-align: center;
-      background: #F5F6FA;
-      font-size: 22px;
-      font-weight: 600;
-      color: #131415;
-      line-height: 30px;
-    }
-
-    .n-card-header__close {
-      position: absolute;
-      right: 18px;
-    }
-
-    .n-card__content {
-      padding: 0;
-    }
-
-    .n-base-select-menu .n-base-select-option {
-      font-size: 18px !important;
     }
   }
 }

+ 5 - 85
src/views/prepare-lessons/components/lesson-main/index.tsx

@@ -1,52 +1,12 @@
 import { defineComponent, reactive } from 'vue';
 import styles from './index.module.less';
-import { NButton, NModal, NScrollbar, NSpace, NTabPane, NTabs } from 'naive-ui';
-import CardType from '@/components/card-type';
-import AttendClass from '../../model/attend-class';
+import { NTabPane, NTabs } from 'naive-ui';
+import Courseware from './courseware';
+import Train from './train';
 
 export default defineComponent({
   name: 'lesson-main',
   setup() {
-    const forms = reactive({
-      list: [
-        {
-          id: '1',
-          name: '其多列',
-          title: '其多列',
-          type: 'VIDEO',
-          content:
-            'https://gyt.ks3-cn-beijing.ksyuncs.com/courseware/1687844560120.mp4',
-          url: 'https://gyt.ks3-cn-beijing.ksyuncs.com/courseware/1687844640957.png'
-        },
-        {
-          id: '5',
-          name: '歌曲表演 大鹿',
-          title: '歌曲表演 大鹿',
-          type: 'SONG',
-          content:
-            'https://cloud-coach.ks3-cn-beijing.ksyuncs.com/1686819360752.mp3',
-          url: 'https://gyt.ks3-cn-beijing.ksyuncs.com/courseware/1687916228530.png'
-        },
-        {
-          id: '2',
-          name: '其多列',
-          title: '其多列',
-          type: 'IMG',
-          content:
-            'https://gyt.ks3-cn-beijing.ksyuncs.com/courseware/1688007481564.jpg',
-          url: 'https://gyt.ks3-cn-beijing.ksyuncs.com/courseware/1688007481564.jpg'
-        },
-        {
-          id: '4',
-          name: '歌曲 其多列',
-          title: '其多列',
-          type: 'MUSIC',
-          content: '43541',
-          url: 'https://cloud-coach.ks3-cn-beijing.ksyuncs.com/music-sheet-first/1687847690372-1.png'
-        }
-      ],
-      showAttendClass: false // 开始上课
-    });
     return () => (
       <div class={styles['lesson-main']}>
         <NTabs
@@ -56,52 +16,12 @@ export default defineComponent({
           justifyContent="center"
           paneWrapperClass={styles.paneWrapperContainer}>
           <NTabPane name="courseware" tab="课件">
-            <div class={styles.btnGroup}>
-              <NSpace>
-                <NButton type="default">编辑</NButton>
-              </NSpace>
-
-              <NSpace>
-                <NButton type="default">预览</NButton>
-                <NButton
-                  type="primary"
-                  onClick={() => (forms.showAttendClass = true)}>
-                  开始上课
-                </NButton>
-              </NSpace>
-            </div>
-
-            <NScrollbar class={styles.listContainer}>
-              <div class={styles.list}>
-                {forms.list.map((item: any) => (
-                  <CardType isShowCollect={false} item={item} />
-                ))}
-              </div>
-            </NScrollbar>
+            <Courseware />
           </NTabPane>
           <NTabPane name="train" tab="训练">
-            <div class={styles.btnGroup}>
-              <NSpace>
-                <NButton type="default">添加训练</NButton>
-                <NButton type="default">编辑</NButton>
-              </NSpace>
-
-              <NSpace>
-                <NButton type="primary">布置训练</NButton>
-              </NSpace>
-            </div>
+            <Train />
           </NTabPane>
         </NTabs>
-
-        <NModal
-          v-model:show={forms.showAttendClass}
-          preset="card"
-          showIcon={false}
-          class={styles.attendClassModal}
-          title={'选择班级'}
-          blockScroll={false}>
-          <AttendClass onClose={() => (forms.showAttendClass = false)} />
-        </NModal>
       </div>
     );
   }

+ 44 - 0
src/views/prepare-lessons/components/lesson-main/train/index.module.less

@@ -0,0 +1,44 @@
+.btnGroup {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding-left: 22px !important;
+  padding-right: 22px !important;
+
+  :global {
+    .n-button {
+      border-radius: 8px;
+      height: 38px;
+      font-size: 17px;
+      font-weight: 600 !important;
+      padding: 0 27px;
+    }
+
+    .n-button--default-type {
+      background: #E8F4FF;
+      color: #0378EC;
+
+      &:not(.n-button--disabled):hover {
+        background: #E8F4FF;
+      }
+
+      .n-button__border {
+        border: 1px solid #198CFE;
+      }
+    }
+  }
+}
+
+.listContainer {
+  margin-top: 12px;
+  // // 52 + 28 + 38
+  max-height: calc(var(--window-page-lesson-height) - 148px);
+}
+
+.list {
+  padding: 12px 22px 12px;
+  display: flex;
+  flex-flow: row wrap;
+  justify-content: flex-start;
+  gap: 20px;
+}

+ 36 - 0
src/views/prepare-lessons/components/lesson-main/train/index.tsx

@@ -0,0 +1,36 @@
+import { defineComponent, reactive } from 'vue';
+import styles from './index.module.less';
+import { NButton, NScrollbar, NSpace } from 'naive-ui';
+import CardType from '/src/components/card-type';
+
+export default defineComponent({
+  name: 'courseware-modal',
+  setup() {
+    const forms = reactive({
+      showAttendClass: false,
+      list: [] as any
+    });
+    return () => (
+      <div class={styles.coursewareModal}>
+        <div class={styles.btnGroup}>
+          <NSpace>
+            <NButton type="default">添加训练</NButton>
+            <NButton type="default">编辑</NButton>
+          </NSpace>
+
+          <NSpace>
+            <NButton type="primary">布置训练</NButton>
+          </NSpace>
+        </div>
+
+        <NScrollbar class={styles.listContainer}>
+          <div class={styles.list}>
+            {forms.list.map((item: any) => (
+              <CardType isShowCollect={false} item={item} />
+            ))}
+          </div>
+        </NScrollbar>
+      </div>
+    );
+  }
+});

+ 17 - 0
src/views/prepare-lessons/components/resource-main/components/my-collect/index.module.less

@@ -0,0 +1,17 @@
+.listContainer {
+  margin: 10px 0;
+  max-height: calc(var(--window-page-lesson-height) - 224px - 20px);
+
+  .list {
+    padding: 10px 0;
+    text-align: center;
+
+    &>div {
+      margin-bottom: 20px;
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+    }
+  }
+}

+ 106 - 0
src/views/prepare-lessons/components/resource-main/components/my-collect/index.tsx

@@ -0,0 +1,106 @@
+import { defineComponent, onMounted, reactive, ref } from 'vue';
+import ResourceSearchGroup from './resource-search-group';
+import { NScrollbar, NSpin } from 'naive-ui';
+import styles from './index.module.less';
+import CardType from '/src/components/card-type';
+import { materialQueryPage } from '/src/views/natural-resources/api';
+import TheEmpty from '/src/components/TheEmpty';
+export default defineComponent({
+  name: 'share-resources',
+  setup() {
+    const scrollContentRef = ref();
+    const state = reactive({
+      searchWord: '',
+      loading: false,
+      pageTotal: 0,
+      finshed: false, // 是否加载完
+      pagination: {
+        page: 1,
+        rows: 20
+      },
+      searchGroup: {
+        type: '', //
+        keyword: '',
+        bookVersionId: null,
+        subjectId: null,
+        sourceType: 4
+      },
+      tableList: [] as any,
+      teachingStatus: false,
+      show: false,
+      item: {} as any
+    });
+    const getList = async () => {
+      try {
+        state.loading = true;
+        const { data } = await materialQueryPage({
+          ...state.searchGroup,
+          ...state.pagination
+        });
+        state.loading = false;
+        const tempRows = data.rows || [];
+        const temp: any = [];
+        tempRows.forEach((row: any) => {
+          temp.push({
+            id: row.id,
+            coverImg: row.coverImg,
+            type: row.type,
+            title: row.name,
+            isCollect: !!row.favoriteFlag,
+            isSelected: row.sourceFrom === 'PLATFORM' ? true : false,
+            content: row.content
+          });
+        });
+        state.tableList.push(...temp);
+
+        state.finshed = data.pages <= data.current ? true : false;
+      } catch {
+        state.loading = false;
+      }
+    };
+
+    const onSearch = async (item: any) => {
+      state.pagination.page = 1;
+      state.tableList = [];
+      state.searchGroup = Object.assign(state.searchGroup, item);
+      getList();
+    };
+
+    onMounted(() => {
+      getList();
+    });
+    return () => (
+      <div>
+        <ResourceSearchGroup onSearch={(item: any) => onSearch(item)} />
+        <NScrollbar
+          class={styles.listContainer}
+          onScroll={(e: any) => {
+            const clientHeight = e.target?.clientHeight;
+            const scrollTop = e.target?.scrollTop;
+            const scrollHeight = e.target?.scrollHeight;
+            // 是否到底,是否加载完
+            if (
+              clientHeight + scrollTop + 20 >= scrollHeight &&
+              !state.finshed
+            ) {
+              state.pagination.page = state.pagination.page + 1;
+              getList();
+            }
+          }}>
+          <div class={styles.list} ref={scrollContentRef}>
+            {state.tableList.map((item: any) => (
+              <CardType isShowAdd item={item} />
+            ))}
+          </div>
+
+          <NSpin
+            show={state.loading}
+            style={{ display: 'flex' }}
+            size={'small'}></NSpin>
+
+          {!state.loading && state.tableList.length <= 0 && <TheEmpty />}
+        </NScrollbar>
+      </div>
+    );
+  }
+});

+ 3 - 0
src/views/prepare-lessons/model/resource-search-group/index.module.less → src/views/prepare-lessons/components/resource-main/components/my-collect/resource-search-group/index.module.less

@@ -9,6 +9,9 @@
   }
 
   :global {
+    .n-select {
+      max-width: 152px;
+    }
 
     .n-base-selection,
     .n-input {

+ 112 - 0
src/views/prepare-lessons/components/resource-main/components/my-collect/resource-search-group/index.tsx

@@ -0,0 +1,112 @@
+import { defineComponent, onMounted, reactive, ref } from 'vue';
+import styles from './index.module.less';
+import { NButton, NInput, NSelect, NSpace } from 'naive-ui';
+import { resourceTypeArray } from '/src/utils/searchArray';
+import { useCatchStore } from '/src/store/modules/catchData';
+import { useDebounceFn } from '@vueuse/core';
+
+export default defineComponent({
+  name: 'resource-search-group',
+  emits: ['search'],
+  setup(props, { emit }) {
+    const catchStore = useCatchStore();
+    const forms = reactive({
+      type: '', //
+      keyword: '',
+      bookVersionId: null,
+      subjectId: null
+    });
+    const resourceList = ref([] as any);
+
+    const onSearch = () => {
+      emit('search', forms);
+    };
+
+    const debouncedRequest = useDebounceFn(() => onSearch(), 500);
+
+    onMounted(async () => {
+      resourceList.value = [
+        {
+          label: '全部',
+          value: ''
+        },
+        ...resourceTypeArray
+      ];
+      // 获取教材分类列表
+      await catchStore.getMusicSheetCategory();
+      // 获取声部列表
+      await catchStore.getSubjects();
+    });
+    return () => (
+      <>
+        <div class={styles.searchGroup}>
+          <NSpace size="small" class={styles.btnType}>
+            {resourceList.value.map((item: any) => (
+              <NButton
+                type={forms.type === item.value ? 'primary' : 'default'}
+                secondary={forms.type === item.value ? false : true}
+                round
+                size="small"
+                focusable={false}
+                onClick={() => {
+                  forms.type = item.value;
+                  debouncedRequest();
+                }}>
+                {item.label}
+              </NButton>
+            ))}
+          </NSpace>
+
+          <div class={styles.searchSelect}>
+            <NSelect
+              placeholder="教材"
+              options={catchStore.getMusicCategories}
+              clearable
+              labelField="name"
+              valueField="id"
+              v-model:value={forms.bookVersionId}
+              onUpdate:value={() => {
+                onSearch();
+              }}
+            />
+            <NSelect
+              placeholder="乐器"
+              options={catchStore.getSubjectList}
+              clearable
+              labelField="name"
+              valueField="id"
+              v-model:value={forms.subjectId}
+              onUpdate:value={() => {
+                onSearch();
+              }}
+            />
+          </div>
+
+          <NInput
+            type="text"
+            placeholder="请输入搜索关键词"
+            clearable
+            v-model:value={forms.keyword}
+            class={styles.inputSearch}
+            onKeyup={(e: KeyboardEvent) => {
+              if (e.code === 'Enter') {
+                debouncedRequest();
+              }
+            }}
+            onClear={() => {
+              forms.keyword = '';
+              debouncedRequest();
+            }}>
+            {{
+              prefix: () => (
+                <span
+                  class={'icon-search-input'}
+                  onClick={() => debouncedRequest()}></span>
+              )
+            }}
+          </NInput>
+        </div>
+      </>
+    );
+  }
+});

+ 17 - 0
src/views/prepare-lessons/components/resource-main/components/my-resources/index.module.less

@@ -0,0 +1,17 @@
+.listContainer {
+  margin: 10px 0;
+  max-height: calc(var(--window-page-lesson-height) - 224px - 20px);
+
+  .list {
+    padding: 10px 0;
+    text-align: center;
+
+    &>div {
+      margin-bottom: 20px;
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+    }
+  }
+}

+ 106 - 0
src/views/prepare-lessons/components/resource-main/components/my-resources/index.tsx

@@ -0,0 +1,106 @@
+import { defineComponent, onMounted, reactive, ref } from 'vue';
+import ResourceSearchGroup from './resource-search-group';
+import { NScrollbar, NSpin } from 'naive-ui';
+import styles from './index.module.less';
+import CardType from '/src/components/card-type';
+import { materialQueryPage } from '/src/views/natural-resources/api';
+import TheEmpty from '/src/components/TheEmpty';
+export default defineComponent({
+  name: 'share-resources',
+  setup() {
+    const scrollContentRef = ref();
+    const state = reactive({
+      searchWord: '',
+      loading: false,
+      pageTotal: 0,
+      finshed: false, // 是否加载完
+      pagination: {
+        page: 1,
+        rows: 20
+      },
+      searchGroup: {
+        type: '', //
+        keyword: '',
+        bookVersionId: null,
+        subjectId: null,
+        sourceType: 3
+      },
+      tableList: [] as any,
+      teachingStatus: false,
+      show: false,
+      item: {} as any
+    });
+    const getList = async () => {
+      try {
+        state.loading = true;
+        const { data } = await materialQueryPage({
+          ...state.searchGroup,
+          ...state.pagination
+        });
+        state.loading = false;
+        const tempRows = data.rows || [];
+        const temp: any = [];
+        tempRows.forEach((row: any) => {
+          temp.push({
+            id: row.id,
+            coverImg: row.coverImg,
+            type: row.type,
+            title: row.name,
+            isCollect: !!row.favoriteFlag,
+            isSelected: row.sourceFrom === 'PLATFORM' ? true : false,
+            content: row.content
+          });
+        });
+        state.tableList.push(...temp);
+
+        state.finshed = data.pages <= data.current ? true : false;
+      } catch {
+        state.loading = false;
+      }
+    };
+
+    const onSearch = async (item: any) => {
+      state.pagination.page = 1;
+      state.tableList = [];
+      state.searchGroup = Object.assign(state.searchGroup, item);
+      getList();
+    };
+
+    onMounted(() => {
+      getList();
+    });
+    return () => (
+      <div>
+        <ResourceSearchGroup onSearch={(item: any) => onSearch(item)} />
+        <NScrollbar
+          class={styles.listContainer}
+          onScroll={(e: any) => {
+            const clientHeight = e.target?.clientHeight;
+            const scrollTop = e.target?.scrollTop;
+            const scrollHeight = e.target?.scrollHeight;
+            // 是否到底,是否加载完
+            if (
+              clientHeight + scrollTop + 20 >= scrollHeight &&
+              !state.finshed
+            ) {
+              state.pagination.page = state.pagination.page + 1;
+              getList();
+            }
+          }}>
+          <div class={styles.list} ref={scrollContentRef}>
+            {state.tableList.map((item: any) => (
+              <CardType isShowAdd item={item} />
+            ))}
+          </div>
+
+          <NSpin
+            show={state.loading}
+            style={{ display: 'flex' }}
+            size={'small'}></NSpin>
+
+          {!state.loading && state.tableList.length <= 0 && <TheEmpty />}
+        </NScrollbar>
+      </div>
+    );
+  }
+});

+ 59 - 0
src/views/prepare-lessons/components/resource-main/components/my-resources/resource-search-group/index.module.less

@@ -0,0 +1,59 @@
+.searchGroup {
+  padding: 0 20px;
+
+  .searchSelect {
+    padding: 20px 0;
+    display: flex;
+    justify-content: flex-start;
+    gap: 0px 16px;
+  }
+
+  :global {
+    .n-select {
+      max-width: 152px;
+    }
+
+    .n-base-selection,
+    .n-input {
+      border-radius: 8px;
+      min-height: 40px;
+      height: 40px;
+      font-size: 15px;
+      --n-height: 40px !important;
+    }
+  }
+}
+
+.inputSearch {
+  :global {
+    .n-input-wrapper {
+      padding-left: 12px;
+      padding-right: 4px;
+    }
+  }
+
+  .searchBtn {
+    height: 34px;
+    border-radius: 8px;
+    font-size: 15px;
+    font-weight: 500;
+  }
+}
+
+.btnType {
+  gap: 0px 6px !important;
+
+  :global {
+    .n-button {
+      height: 28px;
+      padding: 0 13px;
+      font-size: 15px;
+      color: rgba(0, 0, 0, .6);
+
+      &.n-button--primary-type {
+        font-weight: bold;
+        color: #fff;
+      }
+    }
+  }
+}

+ 112 - 0
src/views/prepare-lessons/components/resource-main/components/my-resources/resource-search-group/index.tsx

@@ -0,0 +1,112 @@
+import { defineComponent, onMounted, reactive, ref } from 'vue';
+import styles from './index.module.less';
+import { NButton, NInput, NSelect, NSpace } from 'naive-ui';
+import { resourceTypeArray } from '/src/utils/searchArray';
+import { useCatchStore } from '/src/store/modules/catchData';
+import { useDebounceFn } from '@vueuse/core';
+
+export default defineComponent({
+  name: 'resource-search-group',
+  emits: ['search'],
+  setup(props, { emit }) {
+    const catchStore = useCatchStore();
+    const forms = reactive({
+      type: '', //
+      keyword: '',
+      bookVersionId: null,
+      subjectId: null
+    });
+    const resourceList = ref([] as any);
+
+    const onSearch = () => {
+      emit('search', forms);
+    };
+
+    const debouncedRequest = useDebounceFn(() => onSearch(), 500);
+
+    onMounted(async () => {
+      resourceList.value = [
+        {
+          label: '全部',
+          value: ''
+        },
+        ...resourceTypeArray
+      ];
+      // 获取教材分类列表
+      await catchStore.getMusicSheetCategory();
+      // 获取声部列表
+      await catchStore.getSubjects();
+    });
+    return () => (
+      <>
+        <div class={styles.searchGroup}>
+          <NSpace size="small" class={styles.btnType}>
+            {resourceList.value.map((item: any) => (
+              <NButton
+                type={forms.type === item.value ? 'primary' : 'default'}
+                secondary={forms.type === item.value ? false : true}
+                round
+                size="small"
+                focusable={false}
+                onClick={() => {
+                  forms.type = item.value;
+                  debouncedRequest();
+                }}>
+                {item.label}
+              </NButton>
+            ))}
+          </NSpace>
+
+          <div class={styles.searchSelect}>
+            <NSelect
+              placeholder="教材"
+              options={catchStore.getMusicCategories}
+              clearable
+              labelField="name"
+              valueField="id"
+              v-model:value={forms.bookVersionId}
+              onUpdate:value={() => {
+                onSearch();
+              }}
+            />
+            <NSelect
+              placeholder="乐器"
+              options={catchStore.getSubjectList}
+              clearable
+              labelField="name"
+              valueField="id"
+              v-model:value={forms.subjectId}
+              onUpdate:value={() => {
+                onSearch();
+              }}
+            />
+          </div>
+
+          <NInput
+            type="text"
+            placeholder="请输入搜索关键词"
+            clearable
+            v-model:value={forms.keyword}
+            class={styles.inputSearch}
+            onKeyup={(e: KeyboardEvent) => {
+              if (e.code === 'Enter') {
+                debouncedRequest();
+              }
+            }}
+            onClear={() => {
+              forms.keyword = '';
+              debouncedRequest();
+            }}>
+            {{
+              prefix: () => (
+                <span
+                  class={'icon-search-input'}
+                  onClick={() => debouncedRequest()}></span>
+              )
+            }}
+          </NInput>
+        </div>
+      </>
+    );
+  }
+});

+ 18 - 0
src/views/prepare-lessons/components/resource-main/components/share-resources/index.module.less

@@ -0,0 +1,18 @@
+.listContainer {
+  margin: 10px 0;
+  max-height: calc(var(--window-page-lesson-height) - 224px - 20px);
+  // overflow-x: auto;
+
+  .list {
+    padding: 10px 0;
+    text-align: center;
+
+    &>div {
+      margin-bottom: 20px;
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+    }
+  }
+}

+ 105 - 0
src/views/prepare-lessons/components/resource-main/components/share-resources/index.tsx

@@ -0,0 +1,105 @@
+import { defineComponent, onMounted, reactive, ref } from 'vue';
+import ResourceSearchGroup from './resource-search-group';
+import { NScrollbar, NSpin } from 'naive-ui';
+import styles from './index.module.less';
+import CardType from '/src/components/card-type';
+import { materialQueryPage } from '/src/views/natural-resources/api';
+import TheEmpty from '/src/components/TheEmpty';
+export default defineComponent({
+  name: 'share-resources',
+  setup() {
+    const scrollContentRef = ref();
+    const state = reactive({
+      searchWord: '',
+      loading: false,
+      pageTotal: 0,
+      finshed: false, // 是否加载完
+      pagination: {
+        page: 1,
+        rows: 20
+      },
+      searchGroup: {
+        type: 'MUSIC', //
+        keyword: '',
+        bookVersionId: null,
+        subjectId: null,
+        sourceType: 2
+      },
+      tableList: [] as any,
+      teachingStatus: false,
+      show: false,
+      item: {} as any
+    });
+    const getList = async () => {
+      try {
+        state.loading = true;
+        const { data } = await materialQueryPage({
+          ...state.searchGroup,
+          ...state.pagination
+        });
+        state.loading = false;
+        const tempRows = data.rows || [];
+        const temp: any = [];
+        tempRows.forEach((row: any) => {
+          temp.push({
+            id: row.id,
+            coverImg: row.coverImg,
+            type: row.type,
+            title: row.name,
+            isCollect: !!row.favoriteFlag,
+            isSelected: row.sourceFrom === 'PLATFORM' ? true : false,
+            content: row.content
+          });
+        });
+        state.tableList.push(...temp);
+
+        state.finshed = data.pages <= data.current ? true : false;
+      } catch {
+        state.loading = false;
+      }
+    };
+
+    const onSearch = async (item: any) => {
+      state.pagination.page = 1;
+      state.tableList = [];
+      state.searchGroup = Object.assign(state.searchGroup, item);
+      getList();
+    };
+
+    onMounted(() => {
+      getList();
+    });
+    return () => (
+      <div>
+        <ResourceSearchGroup onSearch={(item: any) => onSearch(item)} />
+        <NScrollbar
+          class={styles.listContainer}
+          onScroll={(e: any) => {
+            const clientHeight = e.target?.clientHeight;
+            const scrollTop = e.target?.scrollTop;
+            const scrollHeight = e.target?.scrollHeight;
+            // 是否到底,是否加载完
+            if (
+              clientHeight + scrollTop + 20 >= scrollHeight &&
+              !state.finshed
+            ) {
+              state.pagination.page = state.pagination.page + 1;
+              getList();
+            }
+          }}>
+          <div class={styles.list} ref={scrollContentRef}>
+            {state.tableList.map((item: any) => (
+              <CardType isShowAdd item={item} />
+            ))}
+          </div>
+          <NSpin
+            show={state.loading}
+            style={{ display: 'flex' }}
+            size={'small'}></NSpin>
+
+          {!state.loading && state.tableList.length <= 0 && <TheEmpty />}
+        </NScrollbar>
+      </div>
+    );
+  }
+});

+ 59 - 0
src/views/prepare-lessons/components/resource-main/components/share-resources/resource-search-group/index.module.less

@@ -0,0 +1,59 @@
+.searchGroup {
+  padding: 0 20px;
+
+  .searchSelect {
+    padding: 20px 0;
+    display: flex;
+    justify-content: flex-start;
+    gap: 0px 16px;
+  }
+
+  :global {
+    .n-select {
+      max-width: 152px;
+    }
+
+    .n-base-selection,
+    .n-input {
+      border-radius: 8px;
+      min-height: 40px;
+      height: 40px;
+      font-size: 15px;
+      --n-height: 40px !important;
+    }
+  }
+}
+
+.inputSearch {
+  :global {
+    .n-input-wrapper {
+      padding-left: 12px;
+      padding-right: 4px;
+    }
+  }
+
+  .searchBtn {
+    height: 34px;
+    border-radius: 8px;
+    font-size: 15px;
+    font-weight: 500;
+  }
+}
+
+.btnType {
+  gap: 0px 6px !important;
+
+  :global {
+    .n-button {
+      height: 28px;
+      padding: 0 13px;
+      font-size: 15px;
+      color: rgba(0, 0, 0, .6);
+
+      &.n-button--primary-type {
+        font-weight: bold;
+        color: #fff;
+      }
+    }
+  }
+}

+ 104 - 0
src/views/prepare-lessons/components/resource-main/components/share-resources/resource-search-group/index.tsx

@@ -0,0 +1,104 @@
+import { defineComponent, onMounted, reactive } from 'vue';
+import styles from './index.module.less';
+import { NButton, NInput, NSelect, NSpace } from 'naive-ui';
+import { resourceTypeArray } from '/src/utils/searchArray';
+import { useCatchStore } from '/src/store/modules/catchData';
+import { useDebounceFn } from '@vueuse/core';
+
+export default defineComponent({
+  name: 'resource-search-group',
+  emits: ['search'],
+  setup(props, { emit }) {
+    const catchStore = useCatchStore();
+    const forms = reactive({
+      type: 'MUSIC', //
+      keyword: '',
+      bookVersionId: null,
+      subjectId: null
+    });
+
+    const onSearch = () => {
+      emit('search', forms);
+    };
+
+    const debouncedRequest = useDebounceFn(() => onSearch(), 500);
+
+    onMounted(async () => {
+      // 获取教材分类列表
+      await catchStore.getMusicSheetCategory();
+      // 获取声部列表
+      await catchStore.getSubjects();
+    });
+    return () => (
+      <>
+        <div class={styles.searchGroup}>
+          <NSpace size="small" class={styles.btnType}>
+            {resourceTypeArray.map((item: any) => (
+              <NButton
+                type={forms.type === item.value ? 'primary' : 'default'}
+                secondary={forms.type === item.value ? false : true}
+                round
+                size="small"
+                focusable={false}
+                onClick={() => {
+                  forms.type = item.value;
+                  debouncedRequest();
+                }}>
+                {item.label}
+              </NButton>
+            ))}
+          </NSpace>
+
+          <div class={styles.searchSelect}>
+            <NSelect
+              placeholder="教材"
+              options={catchStore.getMusicCategories}
+              clearable
+              labelField="name"
+              valueField="id"
+              v-model:value={forms.bookVersionId}
+              onUpdate:value={() => {
+                onSearch();
+              }}
+            />
+            <NSelect
+              placeholder="乐器"
+              options={catchStore.getSubjectList}
+              clearable
+              labelField="name"
+              valueField="id"
+              v-model:value={forms.subjectId}
+              onUpdate:value={() => {
+                onSearch();
+              }}
+            />
+          </div>
+
+          <NInput
+            type="text"
+            placeholder="请输入搜索关键词"
+            clearable
+            v-model:value={forms.keyword}
+            class={styles.inputSearch}
+            onKeyup={(e: KeyboardEvent) => {
+              if (e.code === 'Enter') {
+                debouncedRequest();
+              }
+            }}
+            onClear={() => {
+              forms.keyword = '';
+              debouncedRequest();
+            }}>
+            {{
+              prefix: () => (
+                <span
+                  class={'icon-search-input'}
+                  onClick={() => debouncedRequest()}></span>
+              )
+            }}
+          </NInput>
+        </div>
+      </>
+    );
+  }
+});

+ 0 - 18
src/views/prepare-lessons/components/resource-main/index.module.less

@@ -47,22 +47,4 @@
     height: 18px;
     cursor: pointer;
   }
-}
-
-.listContainer {
-  margin: 10px 0;
-  max-height: calc(var(--window-page-lesson-height) - 224px - 20px);
-
-  .list {
-    padding: 10px 0;
-    text-align: center;
-
-    &>div {
-      margin-bottom: 20px;
-
-      &:last-child {
-        margin-bottom: 0;
-      }
-    }
-  }
 }

+ 20 - 72
src/views/prepare-lessons/components/resource-main/index.tsx

@@ -1,10 +1,9 @@
-import { defineComponent, reactive } from 'vue';
+import { defineComponent } from 'vue';
 import styles from './index.module.less';
-import { NTabs, NTabPane, NScrollbar } from 'naive-ui';
-import ResourceSearchGroup from '../../model/resource-search-group';
-import CardType from '@/components/card-type';
-// import { useElementSize } from '@vueuse/core';
-// import { useRect } from '@vant/use';
+import { NTabs, NTabPane } from 'naive-ui';
+import ShareResources from './components/share-resources';
+import MyResources from './components/my-resources';
+import MyCollect from './components/my-collect';
 
 export default defineComponent({
   name: 'resource-main',
@@ -15,45 +14,6 @@ export default defineComponent({
     }
   },
   setup() {
-    const forms = reactive({
-      list: [
-        {
-          id: '5',
-          name: '其多列',
-          title: '其多列',
-          type: 'VIDEO',
-          content:
-            'https://gyt.ks3-cn-beijing.ksyuncs.com/courseware/1687844560120.mp4',
-          url: 'https://gyt.ks3-cn-beijing.ksyuncs.com/courseware/1687844640957.png'
-        },
-        {
-          id: '2',
-          name: '其多列',
-          title: '其多列',
-          type: 'IMG',
-          content: 'https://daya.ks3-cn-beijing.ksyun.com/202306/TiLlteU.png',
-          url: 'https://daya.ks3-cn-beijing.ksyun.com/202306/TiLlteU.png'
-        },
-        {
-          id: '3',
-          name: '其多列',
-          title: '其多列',
-          type: 'IMG',
-          content: 'https://daya.ks3-cn-beijing.ksyun.com/202306/TiLlxJ0.png',
-          url: 'https://daya.ks3-cn-beijing.ksyun.com/202306/TiLlxJ0.png'
-        },
-        {
-          id: '4',
-          name: '彩虹岛',
-          title: '彩虹岛',
-          type: 'MUSIC',
-          content: '22078',
-          url: 'https://cloud-coach.ks3-cn-beijing.ksyuncs.com/music-sheet-fixed/1675770786664-1.png'
-        }
-      ],
-      height: '100%' as any
-    });
-
     return () => (
       <div class={styles['resource-main']}>
         <NTabs
@@ -75,35 +35,23 @@ export default defineComponent({
             ),
             default: () => (
               <>
-                <NTabPane name="shareResources" tab="共享资源">
-                  <ResourceSearchGroup />
-                  <NScrollbar class={styles.listContainer}>
-                    <div class={styles.list}>
-                      {forms.list.map((item: any) => (
-                        <CardType isShowAdd item={item} />
-                      ))}
-                    </div>
-                  </NScrollbar>
+                <NTabPane
+                  name="shareResources"
+                  tab="共享资源"
+                  displayDirective="show:lazy">
+                  <ShareResources />
                 </NTabPane>
-                <NTabPane name="myResources" tab="我的资源">
-                  <ResourceSearchGroup />
-                  <NScrollbar class={styles.listContainer}>
-                    <div class={styles.list}>
-                      {forms.list.map((item: any) => (
-                        <CardType isShowAdd item={item} />
-                      ))}
-                    </div>
-                  </NScrollbar>
+                <NTabPane
+                  name="myResources"
+                  tab="我的资源"
+                  displayDirective="show:lazy">
+                  <MyResources />
                 </NTabPane>
-                <NTabPane name="myCollect" tab="我的收藏">
-                  <ResourceSearchGroup />
-                  <NScrollbar class={styles.listContainer}>
-                    <div class={styles.list}>
-                      {forms.list.map((item: any) => (
-                        <CardType isShowAdd item={item} />
-                      ))}
-                    </div>
-                  </NScrollbar>
+                <NTabPane
+                  name="myCollect"
+                  tab="我的收藏"
+                  displayDirective="show:lazy">
+                  <MyCollect />
                 </NTabPane>
               </>
             )

+ 0 - 52
src/views/prepare-lessons/model/resource-search-group/index.tsx

@@ -1,52 +0,0 @@
-import { defineComponent, reactive } from 'vue';
-import styles from './index.module.less';
-import { NButton, NInput, NSelect, NSpace } from 'naive-ui';
-import { instrumentArray, teachingArray } from '@/utils/searchArray';
-
-export default defineComponent({
-  name: 'resource-search-group',
-  setup() {
-    const forms = reactive({
-      search: null
-    });
-    return () => (
-      <>
-        <div class={styles.searchGroup}>
-          <NSpace size="small" class={styles.btnType}>
-            <NButton type="primary" round size="small">
-              全部
-            </NButton>
-            <NButton secondary round size="small">
-              乐谱
-            </NButton>
-            <NButton secondary round size="small">
-              图片
-            </NButton>
-            <NButton secondary round size="small">
-              音频
-            </NButton>
-            <NButton secondary round size="small">
-              视频
-            </NButton>
-          </NSpace>
-
-          <div class={styles.searchSelect}>
-            <NSelect placeholder="教材" options={teachingArray} clearable />
-            <NSelect placeholder="乐器" options={instrumentArray} clearable />
-          </div>
-
-          <NInput
-            type="text"
-            placeholder="请输入搜索关键词"
-            clearable
-            v-model:value={forms.search}
-            class={styles.inputSearch}>
-            {{
-              prefix: () => <span class={'icon-search-input'}></span>
-            }}
-          </NInput>
-        </div>
-      </>
-    );
-  }
-});

+ 97 - 27
src/views/setting/components/personInfo.tsx

@@ -7,20 +7,55 @@ import {
   NInput,
   NGrid,
   NGi,
-  NButton
+  NButton,
+  NSelect,
+  NSpace,
+  SelectOption,
+  useMessage
 } from 'naive-ui';
 import headerD from '@/views/home/images/headerD.png';
 import defultHeade from '@/components/layout/images/teacherIcon.png';
 import femaleIcon from '../images/femaleIcon.png';
 import maleIcon from '../images/maleIcon.png';
+import { state } from '/src/state';
+import { useUserStore } from '/src/store/modules/users';
+import { api_teacherUpdate } from '/src/api/user';
 export default defineComponent({
   name: 'setting-personInfo',
   setup(props, { emit, attrs }) {
+    const message = useMessage();
+    const userStore = useUserStore();
+    const formOptions = reactive({
+      sexs: [
+        { label: '男', value: 1, class: 'option' },
+        { label: '女', value: 0, class: 'option' }
+      ] as SelectOption[]
+    });
+    const formRef = ref();
     const teacherForm = reactive({
-      name: '张晚意',
-      phone: '18971685555',
-      sex: '男'
+      nickname: userStore.info.nickname,
+      phone: userStore.info.phone,
+      gender: userStore.info.gender,
+      schoolId: userStore.info.schoolInfos?.[0]?.id,
+      tenantId: userStore.info.schoolInfos?.[0]?.tenantId,
+      id: userStore.info.id
+    });
+    const data = reactive({
+      disabled: true
     });
+
+    const handleSave = () => {
+      formRef.value.validate(async (err: any) => {
+        if (err) {
+          return;
+        }
+        await api_teacherUpdate(teacherForm);
+        console.log(teacherForm);
+        userStore.getInfo();
+        data.disabled = true;
+        message.success('修改成功');
+      });
+    };
     return () => (
       <div class={styles.infoWrap}>
         <div class={styles.teacherInfoWrap}>
@@ -46,46 +81,81 @@ export default defineComponent({
           </div>
         </div>
         <div class={styles.setInfo}>
-          <NForm inline model={teacherForm}>
-            <NGrid cols={3} x-gap="160">
+          <NForm ref={formRef} model={teacherForm} disabled={data.disabled}>
+            <NGrid cols={3} x-gap="100">
               <NGi>
-                {' '}
-                <NFormItem label="姓名" path="name">
+                <NFormItem
+                  label="姓名"
+                  path="nickname"
+                  rule={{
+                    required: true,
+                    message: '请填写老师姓名',
+                    trigger: 'blur'
+                  }}>
                   <NInput
-                    disabled
-                    placeholder="请输入老师姓名"
-                    v-model:value={teacherForm.name}></NInput>
+                    placeholder="请填写老师姓名"
+                    v-model:value={teacherForm.nickname}></NInput>
                 </NFormItem>
               </NGi>
               <NGi>
-                {' '}
-                <NFormItem label="手机号" path="phone">
+                <NFormItem
+                  label="手机号"
+                  path="phone"
+                  rule={[
+                    {
+                      required: true,
+                      message: '请填写老师手机号',
+                      trigger: 'blur'
+                    },
+                    {
+                      pattern: /^1[3456789]\d{9}$/,
+                      message: '手机号格式不正确',
+                      trigger: 'blur'
+                    }
+                  ]}>
                   <NInput
-                    disabled
-                    placeholder="请输入老师姓名"
+                    placeholder="请填写老师手机号"
                     v-model:value={teacherForm.phone}></NInput>
                 </NFormItem>
               </NGi>
               <NGi>
-                {' '}
                 <NFormItem label="性别" path="sex">
-                  <NInput
-                    disabled
+                  <NSelect
+                    showArrow={!data.disabled}
                     placeholder="请选择性别"
-                    v-model:value={teacherForm.sex}></NInput>
+                    options={formOptions.sexs}
+                    v-model:value={teacherForm.gender}
+                  />
                 </NFormItem>
               </NGi>
             </NGrid>
           </NForm>
         </div>
-        <div class={styles.btnList}>
-          <NButton class={styles.resetpwd} type="primary">
-            修改密码
-          </NButton>
-          <NButton class={styles.resetInfo} type="error">
-            修改信息
-          </NButton>
-        </div>
+        {data.disabled ? (
+          <NSpace class={styles.btnList} align="center" justify="end">
+            <NButton class={styles.btn} color="#198cfe">
+              修改密码
+            </NButton>
+            <NButton
+              class={styles.btn}
+              color="#f24433"
+              onClick={() => (data.disabled = false)}>
+              修改信息
+            </NButton>
+          </NSpace>
+        ) : (
+          <NSpace class={styles.btnList} align="center" justify="end">
+            <NButton class={styles.btn} onClick={() => (data.disabled = true)}>
+              取消
+            </NButton>
+            <NButton
+              class={styles.btn}
+              type="primary"
+              onClick={() => handleSave()}>
+              完成
+            </NButton>
+          </NSpace>
+        )}
       </div>
     );
   }

+ 18 - 17
src/views/setting/index.module.less

@@ -127,30 +127,31 @@
     }
   }
 }
+
 .btnList {
   width: 100%;
-  display: flex;
-  flex-direction: row;
-  justify-content: flex-end;
-  margin-top: 100px;
-  .resetpwd {
+  padding: 20px 0;
+  margin-top: 30px;
+
+  .btn {
     width: 144px;
     height: 45px;
-    background: #198cfe;
     border-radius: 8px;
     font-size: 18px;
     font-weight: 600 !important;
-    color: #ffffff;
     margin-right: 24px;
   }
-  .resetInfo {
-    width: 144px;
-    height: 45px;
-    background: #f24433;
-    border-radius: 8px;
-    font-size: 18px;
-    font-weight: 600 !important;
-    color: #ffffff;
-    margin-right: 100px;
-  }
 }
+
+: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;
+  }
+}

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

@@ -18,7 +18,7 @@ export default defineComponent({
           <NTabPane name="person" tab="个人信息">
             <PersonInfo></PersonInfo>
           </NTabPane>
-          <NTabPane disabled name="school" tab="学校设置"></NTabPane>
+          <NTabPane name="school" tab="学校设置"></NTabPane>
         </NTabs>
       </div>
     );

+ 0 - 4
vite.config.ts

@@ -70,10 +70,6 @@ export default defineConfig({
     cors: true,
     https: false,
     proxy: {
-      '/edu-oauth': {
-        target: proxyUrl,
-        changeOrigin: true
-      },
       '/edu-app': {
         target: proxyUrl,
         changeOrigin: true