lex před 1 rokem
rodič
revize
d269ca86e3
32 změnil soubory, kde provedl 762 přidání a 346 odebrání
  1. 1 1
      dev-dist/sw.js
  2. 1 1
      public/version.json
  3. binární
      src/common/images/icon-audio.png
  4. binární
      src/common/images/icon-image.png
  5. binární
      src/common/images/icon-music.png
  6. binární
      src/common/images/icon-other.png
  7. binární
      src/common/images/icon-ppt.png
  8. binární
      src/common/images/icon-video.png
  9. 3 2
      src/components/card-type/index.module.less
  10. 15 2
      src/components/card-type/index.tsx
  11. 6 0
      src/views/attend-class/index.module.less
  12. 124 86
      src/views/attend-class/index.tsx
  13. 1 1
      src/views/attend-class/model/chapter/index.tsx
  14. 28 0
      src/views/attend-class/model/select-class/index.module.less
  15. 90 0
      src/views/attend-class/model/select-class/index.tsx
  16. 1 11
      src/views/home/components/trainData.tsx
  17. 10 3
      src/views/prepare-lessons/api.ts
  18. 121 58
      src/views/prepare-lessons/components/lesson-main/courseware-presets/index.tsx
  19. 18 52
      src/views/prepare-lessons/components/lesson-main/courseware/addCourseware.module.less
  20. 179 82
      src/views/prepare-lessons/components/lesson-main/courseware/addCourseware.tsx
  21. 3 0
      src/views/prepare-lessons/components/lesson-main/index.tsx
  22. 11 0
      src/views/prepare-lessons/components/resource-main/index.module.less
  23. 1 0
      src/views/prepare-lessons/components/resource-main/index.tsx
  24. 26 0
      src/views/prepare-lessons/model/add-item-model/index.module.less
  25. 52 0
      src/views/prepare-lessons/model/add-item-model/index.tsx
  26. 35 1
      src/views/prepare-lessons/model/courseware-type/index.module.less
  27. 15 2
      src/views/prepare-lessons/model/courseware-type/index.tsx
  28. 5 4
      src/views/prepare-lessons/model/select-resources/index.tsx
  29. 3 1
      src/views/prepare-lessons/model/select-resources/select-item/class-search-group/index.tsx
  30. 9 38
      src/views/prepare-lessons/model/select-resources/select-item/index.tsx
  31. 3 1
      src/views/prepare-lessons/model/select-resources/select-item/resource-search-group/index.tsx
  32. 1 0
      src/views/preview-window/index.tsx

+ 1 - 1
dev-dist/sw.js

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

+ 1 - 1
public/version.json

@@ -1 +1 @@
-{"version":1709877240718}
+{"version":1709908537642}

binární
src/common/images/icon-audio.png


binární
src/common/images/icon-image.png


binární
src/common/images/icon-music.png


binární
src/common/images/icon-other.png


binární
src/common/images/icon-ppt.png


binární
src/common/images/icon-video.png


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

@@ -119,8 +119,9 @@
     align-items: center;
 
     .titleType {
-      width: max(36px, 28Px);
-      height: max(17px, 13Px);
+      width: 12Px;
+      height: 12Px;
+      margin-top: 1px;
     }
 
     .titleContent {

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

@@ -6,6 +6,7 @@ import iconVideo from '@common/images/icon-video.png';
 import iconAudio from '@common/images/icon-audio.png';
 import iconMusic from '@common/images/icon-music.png';
 import iconPPT from '@common/images/icon-ppt.png';
+import iconOther from '@common/images/icon-other.png';
 import iconCollectDefault from '@common/images/icon-collect-default.png';
 import iconCollectActive from '@common/images/icon-collect-active.png';
 import iconDownload from '@common/images/icon-download.png';
@@ -17,9 +18,21 @@ import { api_musicSheetDetail } from '/src/api/user';
 import JSZip, { file } from 'jszip';
 import { saveAs } from 'file-saver';
 
+// LISTEN:听音,RHYTHM:节奏,THEORY:乐理知识,MUSIC:曲目 INSTRUMENT:乐器 MUSICIAN:音乐家)
 type itemType = {
   id: string | number;
-  type: 'IMG' | 'VIDEO' | 'SONG' | 'MUSIC' | 'PPT';
+  type:
+    | 'IMG'
+    | 'VIDEO'
+    | 'SONG'
+    | 'MUSIC'
+    | 'PPT'
+    | 'LISTEN'
+    | 'RHYTHM'
+    | 'THEORY'
+    | 'MUSIC'
+    | 'INSTRUMENT'
+    | 'MUSICIAN';
   coverImg: string;
   content?: string;
   title: string;
@@ -98,7 +111,7 @@ export default defineComponent({
     const isAnimation = ref(false);
     const downloadStatus = ref(false);
     const formatType = (type: string) => {
-      let typeImg = iconImage;
+      let typeImg = iconOther;
       switch (type) {
         case 'IMG':
           typeImg = iconImage;

+ 6 - 0
src/views/attend-class/index.module.less

@@ -419,6 +419,8 @@
     }
   }
 
+
+
   .modelAttendContent {
     font-size: max(18px, 16px);
     color: #777777;
@@ -850,3 +852,7 @@
     }
   }
 }
+
+.selectClassModal {
+  width: 900px;
+}

+ 124 - 86
src/views/attend-class/index.tsx

@@ -31,10 +31,9 @@ import {
   NDrawerContent,
   NModal,
   NSpace,
-  NButton
-  // NTooltip,
-  // NPopover,
-  // NImage
+  NButton,
+  NCollapse,
+  NCollapseItem
 } from 'naive-ui';
 import CardType from '@/components/card-type';
 import Pen from './component/tools/pen';
@@ -42,37 +41,22 @@ import AudioPay from './component/audio-pay';
 import TrainSettings from './model/train-settings';
 import { useRoute } from 'vue-router';
 import {
+  api_teacherChapterLessonCoursewareDetail,
   courseScheduleUpdate,
   lessonCoursewareDetail,
   lessonPreTrainingPage,
   queryCourseware
 } from '../prepare-lessons/api';
-// import Attentguide from '@/custom-plugins/guide-page/attent-guide';
 import { vaildUrl } from '/src/utils/urlUtils';
 import TimerMeter from '/src/components/timerMeter';
-// import toneImage from '/src/components/layout/images/toneImage.png';
-// import toolbox from '/src/components/layout/images/toolbox.png';
-// import setTimeIcon from '/src/components/layout/images/setTimeIcon.png';
-// import beatIcon from '/src/components/layout/images/beatIcon.png';
-// import toneIcon from '/src/components/layout/images/toneIcon.png';
 import { px2vw } from '/src/utils';
 import PlaceholderTone from '/src/components/layout/modals/placeholderTone';
 import { state as globalState } from '/src/state';
 import Chapter from './model/chapter';
 import { useRouter } from 'vue-router';
 import { useUserStore } from '@/store/modules/users';
-
-// import iconBeatIcon from './new-image/icon-beatIcon.png';
-// import iconChange from './new-image/icon-change.png';
-// import iconDown from './new-image/icon-down.png';
-// import iconMenu from './new-image/icon-menu.png';
 import iconNote from './new-image/icon-note.png';
-// import iconOverClass from './new-image/icon-overclass.png';
-// import iconSetTime from './new-image/icon-setTime.png';
-// import iconToneIcon from './new-image/icon-toneIcon.png';
-// import iconUp from './new-image/icon-up.png';
 import iconWhite from './new-image/icon-white.png';
-// import iconWork from './new-image/icon-work.png';
 
 import rightIconEnd from './image/right_icon1.png';
 import rightIconArrange from './image/right_icon2.png';
@@ -93,6 +77,7 @@ import SelectResources from '../prepare-lessons/model/select-resources';
 import { getStudentAfterWork, getStudentList } from '../studentList/api';
 import TheNoticeBar from '/src/components/TheNoticeBar';
 import ClassWork from './model/class-work';
+import SelectClass from './model/select-class';
 
 export type ToolType = 'init' | 'pen' | 'whiteboard' | 'call';
 export type ToolItem = {
@@ -108,6 +93,10 @@ export default defineComponent({
       type: String,
       default: ''
     },
+    courseId: {
+      type: String,
+      default: ''
+    },
     subjectId: {
       type: [String, Number],
       default: ''
@@ -170,6 +159,7 @@ export default defineComponent({
     const drawerCardRef = ref(); // 资源列表对象
     const data = reactive({
       type: 'class' as '' | 'preview' | 'class', // 预览类型
+      courseId: '', // 课件编号
       subjectId: '' as any, // 声部编号
       lessonCourseId: '' as any, // 教材编号
       lessonCoursewareDetailId: '' as any, // 章节
@@ -188,6 +178,7 @@ export default defineComponent({
       modelAttendStatus: false, // 布置作业提示弹窗
       modalAttendMessage: '本节课未设置课后作业,是否继续?',
       modelTrainStatus: false, // 训练设置
+      selectClassStatus: false, // 选择课件
       homeworkStatus: true, // 布置作业完成时
       removeVisiable: false,
       removeTitle: '',
@@ -216,31 +207,39 @@ export default defineComponent({
 
     const getDetail = async () => {
       try {
-        const res = await queryCourseware({
-          coursewareDetailKnowledgeId: data.detailId,
-          subjectId: data.subjectId,
-          pag: 1,
-          rows: 99
-        });
-        const tempRows = res.data.rows || [];
+        const res = await api_teacherChapterLessonCoursewareDetail(
+          data.courseId
+        );
+
+        const tempRows = res.data.chapterKnowledgeList || [];
         const temp: any = [];
         tempRows.forEach((row: any) => {
-          if (!row.removeFlag) {
-            temp.push({
-              id: row.id,
-              materialId: row.materialId,
-              coverImg: row.coverImg,
-              type: row.materialType,
-              title: row.materialName,
-              isCollect: !!row.favoriteFlag,
-              isSelected: row.source === 'PLATFORM' ? true : false,
-              content: row.content
-            });
+          if (!Array.isArray(row.chapterKnowledgeMaterialList)) {
+            return;
           }
+          const childList: any[] = [];
+          row.chapterKnowledgeMaterialList.forEach((child: any) => {
+            if (!child.removeFlag) {
+              childList.push({
+                id: child.id,
+                materialId: child.bizId,
+                coverImg: child.bizInfo.coverImg,
+                type: child.type,
+                title: child.bizInfo.name,
+                isCollect: !!child.favoriteFlag,
+                isSelected: child.source === 'PLATFORM' ? true : false,
+                content: child.bizInfo.content
+              });
+            }
+          });
+          temp.push({
+            title: row.name,
+            list: childList
+          });
         });
 
         data.knowledgePointList = temp;
-        data.itemList = data.knowledgePointList.map((m: any) => {
+        data.itemList = data.knowledgePointList[0].list?.map((m: any) => {
           return {
             ...m,
             iframeRef: null,
@@ -254,8 +253,9 @@ export default defineComponent({
         setTimeout(() => {
           data.animationState = 'end';
         }, 500);
-      } catch {
+      } catch (e) {
         //
+        console.log(e);
       }
     };
 
@@ -317,6 +317,7 @@ export default defineComponent({
       // console.log(query, props.preStudentNum, '学生人数');
       // 先取参数,
       data.type = props.type || (query.type as any);
+      data.courseId = props.courseId || query.courseId;
       data.subjectId = props.subjectId || query.subjectId;
       data.detailId = props.detailId || query.detailId;
       data.lessonCourseId = props.lessonCourseId || query.lessonCourseId;
@@ -353,6 +354,7 @@ export default defineComponent({
       toolOpen: false, // 工具弹窗控制
       chapterOpen: false, // 切换章节
       chapterDetails: [] as any,
+      courseId: null, // 章节编号
       chapterLoading: false // 加载数据
     });
 
@@ -696,7 +698,7 @@ export default defineComponent({
           lessonIndex--;
 
           if (lessonIndex >= 0) {
-            if (detailItem[lessonIndex].containMaterial) {
+            if (detailItem[lessonIndex].coursewareNum > 0) {
               lessonStatus = true;
               lessonCoursewareDetailId =
                 detailItem[lessonIndex].lessonCoursewareDetailId;
@@ -731,7 +733,7 @@ export default defineComponent({
             popupData.chapterDetails[detailIndex]?.knowledgeList || [];
           let tempLessonLength = tempDetail.length;
           while (tempLessonLength > 0) {
-            if (tempDetail[tempLessonLength - 1].containMaterial) {
+            if (tempDetail[tempLessonLength - 1].coursewareNum > 0) {
               prevLessonStatus = true;
               lessonCoursewareDetailId =
                 tempDetail[tempLessonLength - 1].lessonCoursewareDetailId;
@@ -780,7 +782,7 @@ export default defineComponent({
         while (lessonIndex < detailItem.length - 1) {
           lessonIndex++;
           if (lessonIndex >= 0) {
-            if (detailItem[lessonIndex].containMaterial) {
+            if (detailItem[lessonIndex].coursewareNum > 0) {
               lessonStatus = true;
               lessonCoursewareDetailId =
                 detailItem[lessonIndex].lessonCoursewareDetailId;
@@ -814,7 +816,7 @@ export default defineComponent({
             popupData.chapterDetails[detailIndex]?.knowledgeList || [];
           let tempLessonLength = 0;
           while (tempLessonLength <= tempDetail.length - 1) {
-            if (tempDetail[tempLessonLength].containMaterial) {
+            if (tempDetail[tempLessonLength].coursewareNum > 0) {
               nextLessonStatus = true;
               lessonCoursewareDetailId =
                 tempDetail[tempLessonLength].lessonCoursewareDetailId;
@@ -1014,7 +1016,7 @@ export default defineComponent({
         lessonIndex--;
 
         if (lessonIndex >= 0) {
-          if (detailItem[lessonIndex].containMaterial) {
+          if (detailItem[lessonIndex].coursewareNum > 0) {
             lessonStatus = true;
           }
         }
@@ -1036,7 +1038,7 @@ export default defineComponent({
           popupData.chapterDetails[detailIndex]?.knowledgeList || [];
         let tempLessonLength = tempDetail.length;
         while (tempLessonLength > 0) {
-          if (tempDetail[tempLessonLength - 1].containMaterial) {
+          if (tempDetail[tempLessonLength - 1].coursewareNum > 0) {
             prevLessonStatus = true;
           }
           tempLessonLength--;
@@ -1078,7 +1080,7 @@ export default defineComponent({
       while (lessonIndex < detailItem.length - 1) {
         lessonIndex++;
         if (lessonIndex >= 0) {
-          if (detailItem[lessonIndex].containMaterial) {
+          if (detailItem[lessonIndex].coursewareNum > 0) {
             lessonStatus = true;
           }
         }
@@ -1100,7 +1102,7 @@ export default defineComponent({
           popupData.chapterDetails[detailIndex]?.knowledgeList || [];
         let tempLessonLength = 0;
         while (tempLessonLength <= tempDetail.length - 1) {
-          if (tempDetail[tempLessonLength].containMaterial) {
+          if (tempDetail[tempLessonLength].coursewareNum > 0) {
             nextLessonStatus = true;
           }
           tempLessonLength++;
@@ -1649,7 +1651,7 @@ export default defineComponent({
               ),
               default: () => (
                 <div ref={drawerCardRef} id="drawerCardRef">
-                  {data.knowledgePointList.map((item: any, index: number) => {
+                  {/* {data.knowledgePointList.map((item: any, index: number) => {
                     return (
                       <div class={[styles.cardContainer, 'drawerCardItemRef']}>
                         <CardType
@@ -1664,7 +1666,33 @@ export default defineComponent({
                         />
                       </div>
                     );
-                  })}
+                  })} */}
+                  <NCollapse displayDirective="show">
+                    {data.knowledgePointList.map((item: any, index: number) => {
+                      return (
+                        <NCollapseItem title={item.title}>
+                          {item.list.map((child: any) => (
+                            <div
+                              class={[
+                                styles.cardContainer,
+                                'drawerCardItemRef'
+                              ]}>
+                              <CardType
+                                item={child}
+                                isActive={popupData.activeIndex === index}
+                                isCollect={false}
+                                isShowCollect={false}
+                                onClick={() => {
+                                  popupData.open = false;
+                                  toggleMaterial(item.id);
+                                }}
+                              />
+                            </div>
+                          ))}
+                        </NCollapseItem>
+                      );
+                    })}
+                  </NCollapse>
                 </div>
               )
             }}
@@ -1677,32 +1705,17 @@ export default defineComponent({
           class={styles.drawerContainer}
           onAfterLeave={handleClosePopup}
           showMask={false}
-          displayDirective="show">
+          displayDirective="show"
+          maskClosable={data.selectClassStatus ? false : true}>
           <NDrawerContent title="切换章节" closable>
             <Chapter
               treeList={popupData.chapterDetails}
               itemActive={data.detailId as any}
               onHandleSelect={async (val: any) => {
-                popupData.chapterLoading = true;
-
-                try {
-                  data.detailId = val.itemActive;
-                  const ids = formatParentId(
-                    val.itemActive,
-                    popupData.chapterDetails
-                  );
-                  data.lessonCoursewareDetailId = ids[0];
-                  // 更新上课记录 上课的时候才更新
-                  if (data.type !== 'preview') {
-                    await classCourseScheduleUpdate();
-                  }
-                  await getDetail();
-                  popupData.activeIndex = 0;
-                  popupData.chapterOpen = false;
-                } catch {
-                  //
-                }
-                popupData.chapterLoading = false;
+                // itemActive: child.id,
+                // itemName: child.name
+                popupData.courseId = val.itemActive;
+                data.selectClassStatus = true;
               }}
             />
           </NDrawerContent>
@@ -1734,19 +1747,55 @@ export default defineComponent({
           />
         )}
 
+        {/* 训练设置 */}
+        <NModal
+          transformOrigin="center"
+          v-model:show={data.selectClassStatus}
+          preset="card"
+          class={[
+            'modalTitle background',
+            // styles.attendClassModal,
+            styles.selectClassModal
+          ]}
+          title={'选择课件'}>
+          <SelectClass
+            courseId={popupData.courseId}
+            subjectId={data.subjectId}
+            onConfirm={async (val: any) => {
+              popupData.chapterLoading = true;
+              try {
+                data.detailId = val.itemActive;
+                data.courseId = val.courseId;
+                const ids = formatParentId(
+                  val.itemActive,
+                  popupData.chapterDetails
+                );
+                data.lessonCoursewareDetailId = ids[0];
+                // 更新上课记录 上课的时候才更新
+                if (data.type !== 'preview') {
+                  await classCourseScheduleUpdate();
+                }
+                await getDetail();
+                popupData.activeIndex = 0;
+                popupData.chapterOpen = false;
+                data.selectClassStatus = false;
+              } catch {
+                //
+              }
+              popupData.chapterLoading = false;
+            }}
+          />
+        </NModal>
+
         {/* 布置作业 */}
         <NModal
           transformOrigin="center"
           v-model:show={data.modelAttendStatus}
           preset="card"
-          // class={styles.attendClassModal}
           title={'课后作业'}
           class={['modalTitle', styles.removeVisiable]}>
           <div class={styles.studentRemove}>
             <p>{data.modalAttendMessage}</p>
-            {/* <div class={styles.modelAttendContent}>
-              {data.modalAttendMessage}
-            </div> */}
             <NSpace class={styles.btnGroupModal} justify="center">
               <NButton
                 type="default"
@@ -1777,17 +1826,6 @@ export default defineComponent({
           preset="card"
           class={[styles.attendClassModal, styles.trainClassModal]}
           title={'作业设置'}>
-          {/* <TrainSettings
-            detailId={data.detailId}
-            subjectId={data.subjectId}
-            courseScheduleId={data.classId}
-            classGroupId={data.classGroupId}
-            onClose={() => (data.modelTrainStatus = false)}
-            onConfirm={() => {
-              // 布置完作业之后直接关闭
-              data.modelTrainStatus = false;
-            }}
-          /> */}
           <ClassWork
             detailId={data.detailId}
             subjectId={data.subjectId}

+ 1 - 1
src/views/attend-class/model/chapter/index.tsx

@@ -115,7 +115,7 @@ export default defineComponent({
                       if (itemActive.value == child.id) {
                         return;
                       }
-                      if (!child.containMaterial) {
+                      if (child.coursewareNum <= 0) {
                         message.error('该章节暂无课件');
                         return;
                       }

+ 28 - 0
src/views/attend-class/model/select-class/index.module.less

@@ -0,0 +1,28 @@
+.selectClass {
+  padding: 27px 0;
+}
+
+.selectClassScroll {
+  min-height: 60vh;
+  max-height: 60vh;
+  padding: 0 33px
+}
+
+.list {
+  display: flex;
+  flex-flow: row wrap;
+  justify-content: flex-start;
+  padding: 0 0 12px;
+  gap: 20px 0;
+  margin: 0 -10px 0;
+  min-height: 300px;
+
+
+  .itemWrap {
+    width: calc(100% / 3);
+
+    .itemWrapBox {
+      padding: 0 10px;
+    }
+  }
+}

+ 90 - 0
src/views/attend-class/model/select-class/index.tsx

@@ -0,0 +1,90 @@
+import { PropType, defineComponent, onMounted, reactive } from 'vue';
+import styles from './index.module.less';
+import { teacherChapterLessonCoursewareList } from '/src/views/prepare-lessons/api';
+import { NScrollbar, NSpin } from 'naive-ui';
+import CoursewareType from '/src/views/prepare-lessons/model/courseware-type';
+import TheEmpty from '/src/components/TheEmpty';
+
+export default defineComponent({
+  name: 'select-class',
+  props: {
+    courseId: {
+      type: String as PropType<'' | null>,
+      default: ''
+    },
+    subjectId: {
+      type: String,
+      default: ''
+    }
+  },
+  emits: ['confirm', 'close'],
+  setup(props, { emit }) {
+    const forms = reactive({
+      loading: false,
+      tableList: [] as any
+    });
+    const getDetail = async () => {
+      forms.loading = true;
+      try {
+        const { data } = await teacherChapterLessonCoursewareList({
+          coursewareDetailKnowledgeId: props.courseId
+          // subjectId: props.subjectId
+        });
+
+        if (!Array.isArray(data)) {
+          return;
+        }
+        const tempList: any = [];
+        data.forEach((item: any) => {
+          const firstItem: any =
+            item.chapterKnowledgeList[0]?.chapterKnowledgeMaterialList[0];
+          tempList.push({
+            id: item.id,
+            openFlag: item.openFlag,
+            openFlagEnable: item.openFlagEnable,
+            subjectNames: item.subjectNames,
+            fromChapterLessonCoursewareId: item.fromChapterLessonCoursewareId,
+            name: item.name,
+            coverImg: firstItem?.bizInfo.coverImg,
+            type: firstItem?.bizInfo.type
+          });
+        });
+        forms.tableList = tempList;
+      } catch {
+        //
+      }
+      forms.loading = false;
+    };
+
+    onMounted(() => {
+      getDetail();
+    });
+    return () => (
+      <div class={styles.selectClass}>
+        <NSpin show={forms.loading}>
+          <NScrollbar class={styles.selectClassScroll}>
+            <div class={styles.list}>
+              {forms.tableList.map((item: any) => (
+                <div class={[styles.itemWrap, styles.itemBlock, 'row-nav']}>
+                  <div class={styles.itemWrapBox}>
+                    <CoursewareType
+                      isShowPreviewBtn
+                      item={item}
+                      onClick={() => {
+                        emit('confirm', {
+                          itemActive: props.courseId,
+                          chapterId: item.id
+                        });
+                      }}
+                    />
+                  </div>
+                </div>
+              ))}
+              {!forms.loading && forms.tableList.length <= 0 && <TheEmpty />}
+            </div>
+          </NScrollbar>
+        </NSpin>
+      </div>
+    );
+  }
+});

+ 1 - 11
src/views/home/components/trainData.tsx

@@ -1,22 +1,12 @@
-import {
-  Ref,
-  computed,
-  defineComponent,
-  onMounted,
-  reactive,
-  ref,
-  watch
-} from 'vue';
+import { Ref, computed, defineComponent, onMounted, reactive, ref } from 'vue';
 import styles from '../index2.module.less';
 import { NButton, NDataTable, NNumberAnimation, NSpace } from 'naive-ui';
-import numeral from 'numeral';
 import { useECharts } from '@/hooks/web/useECharts';
 import Pagination from '/src/components/pagination';
 import { getTimes } from '/src/utils/dateFormat';
 import { getTrainingStat } from '../../data-module/api';
 import { useRoute, useRouter } from 'vue-router';
 import { getTrainingList } from '../../classList/api';
-import dayjs from 'dayjs';
 import TheEmpty from '/src/components/TheEmpty';
 
 export default defineComponent({

+ 10 - 3
src/views/prepare-lessons/api.ts

@@ -254,7 +254,7 @@ export const api_addByOpenCourseware = (params: any) => {
 /**
  * 课件 新增课件
  */
-export const api_add = (params: any) => {
+export const api_teacherChapterLessonCoursewareAdd = (params: any) => {
   return request.post('/edu-app//teacherChapterLessonCourseware/add', {
     data: params
   });
@@ -263,7 +263,7 @@ export const api_add = (params: any) => {
 /**
  * 课件 删除我的课件
  */
-export const api_eacherChapterLessonCoursewareRemove = (params: any) => {
+export const api_teacherChapterLessonCoursewareRemove = (params: any) => {
   return request.post(
     '/edu-app/teacherChapterLessonCourseware/remove?id=' + params.id,
     {
@@ -275,8 +275,15 @@ export const api_eacherChapterLessonCoursewareRemove = (params: any) => {
 /**
  * 课件 修改我的课件
  */
-export const api_eacherChapterLessonCoursewareUpdate = (params: any) => {
+export const api_teacherChapterLessonCoursewareUpdate = (params: any) => {
   return request.post('/edu-app/teacherChapterLessonCourseware/update', {
     data: params
   });
 };
+
+/**
+ * 课件 课件详情
+ */
+export const api_teacherChapterLessonCoursewareDetail = (id: string) => {
+  return request.get('/edu-app/teacherChapterLessonCourseware/detail/' + id);
+};

+ 121 - 58
src/views/prepare-lessons/components/lesson-main/courseware-presets/index.tsx

@@ -19,17 +19,19 @@ import iconSlideRight from '../../../images/icon-slide-right.png';
 import CoursewareType from '../../../model/courseware-type';
 import TheEmpty from '/src/components/TheEmpty';
 import RelatedClass from '../../../model/related-class';
+import { state } from '/src/state';
 import { useResizeObserver } from '@vueuse/core';
 import {
   api_addByOpenCourseware,
-  api_eacherChapterLessonCoursewareRemove,
+  api_teacherChapterLessonCoursewareRemove,
   api_queryOpenCoursewareByPage,
   api_updateCoursewareInfo,
   teacherChapterLessonCoursewareList
 } from '../../../api';
-import { useRoute } from 'vue-router';
+import { useRoute, useRouter } from 'vue-router';
 import TheMessageDialog from '/src/components/TheMessageDialog';
-import { eventGlobal } from '/src/utils';
+import { eventGlobal, fscreen } from '/src/utils';
+import PreviewWindow from '/src/views/preview-window';
 
 export default defineComponent({
   name: 'courseware-presets',
@@ -38,6 +40,7 @@ export default defineComponent({
     const prepareStore = usePrepareStore();
     const message = useMessage();
     const route = useRoute();
+    const router = useRouter();
     const localStorageSubjectId = localStorage.getItem(
       'prepareLessonSubjectId'
     );
@@ -61,7 +64,14 @@ export default defineComponent({
       editTitle: null,
       editBtnLoading: false,
       preRemoveVisiable: false,
-      carouselIndex: 0
+      carouselIndex: 0,
+      previewModal: false,
+      previewParams: {
+        type: '',
+        courseId: '',
+        subjectId: '',
+        detailId: ''
+      } as any
     });
 
     const getCoursewareList = async () => {
@@ -255,7 +265,7 @@ export default defineComponent({
     const onRemove = async () => {
       forms.messageLoading = true;
       try {
-        await api_eacherChapterLessonCoursewareRemove({
+        await api_teacherChapterLessonCoursewareRemove({
           id: forms.selectItem.id
         });
         message.success('删除成功');
@@ -284,6 +294,37 @@ export default defineComponent({
         forms.messageLoading = false;
       }, 100);
     };
+
+    // 预览上课
+    const onPreviewAttend = (id: string) => {
+      // 判断是否在应用里面
+      if (window.matchMedia('(display-mode: standalone)').matches) {
+        state.application = window.matchMedia(
+          '(display-mode: standalone)'
+        ).matches;
+        forms.previewModal = true;
+        fscreen();
+        forms.previewParams = {
+          type: 'preview',
+          courseId: id,
+          subjectId: prepareStore.getSubjectId,
+          detailId: prepareStore.getSelectKey,
+          lessonCourseId: prepareStore.getBaseCourseware.id
+        };
+      } else {
+        const { href } = router.resolve({
+          path: '/attend-class',
+          query: {
+            type: 'preview',
+            courseId: id,
+            subjectId: prepareStore.getSubjectId,
+            detailId: prepareStore.getSelectKey,
+            lessonCourseId: prepareStore.getBaseCourseware.id
+          }
+        });
+        window.open(href, +new Date() + '');
+      }
+    };
     return () => (
       <div class={styles.coursewarePresetsContainer}>
         <NScrollbar class={styles.coursewarePresets}>
@@ -334,11 +375,20 @@ export default defineComponent({
                         operate
                         isEditName
                         item={item}
+                        onClick={() => onPreviewAttend(item.id)}
                         onEditName={() => {
                           forms.selectItem = item;
                           forms.editTitle = item.name;
                           forms.editTitleVisiable = true;
                         }}
+                        onEdit={() => {
+                          //
+                          eventGlobal.emit('teacher-slideshow', true);
+                          emit('change', {
+                            status: true,
+                            groupItem: { id: item.id }
+                          });
+                        }}
                         onDelete={() => {
                           forms.selectItem = item;
                           forms.preRemoveVisiable = true;
@@ -352,61 +402,67 @@ export default defineComponent({
             </NSpin>
           </div>
 
-          <div class={[styles.title, styles.line]}>
-            <div class={styles.titleLeft}>
-              <i class={[styles.icon, styles.iconCourseware]}></i>
-              相关课件
-              {forms.openTableList.length > 4 && (
-                <span
-                  class={styles.more}
-                  onClick={() => (forms.showRelatedClass = true)}>
-                  查看更多
-                  <NIcon>
-                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
-                      <path
-                        d="M8.59 16.59L13.17 12L8.59 7.41L10 6l6 6l-6 6l-1.41-1.41z"
-                        fill="currentColor"></path>
-                    </svg>
-                  </NIcon>
-                </span>
-              )}
-            </div>
-
-            {forms.openTableList.length > 4 && (
-              <NSpace class={styles.swipeControll}>
-                <div>
-                  <NImage
-                    previewDisabled
-                    class={[styles.leftIcon]}
-                    src={iconSlideRight}
-                  />
-                </div>
-                <div>
-                  <NImage previewDisabled src={iconSlideRight} />
+          {forms.openTableList.length > 0 && (
+            <>
+              <div class={[styles.title, styles.line]}>
+                <div class={styles.titleLeft}>
+                  <i class={[styles.icon, styles.iconCourseware]}></i>
+                  相关课件
+                  {forms.openTableList.length > 4 && (
+                    <span
+                      class={styles.more}
+                      onClick={() => (forms.showRelatedClass = true)}>
+                      查看更多
+                      <NIcon>
+                        <svg
+                          xmlns="http://www.w3.org/2000/svg"
+                          viewBox="0 0 24 24">
+                          <path
+                            d="M8.59 16.59L13.17 12L8.59 7.41L10 6l6 6l-6 6l-1.41-1.41z"
+                            fill="currentColor"></path>
+                        </svg>
+                      </NIcon>
+                    </span>
+                  )}
                 </div>
-              </NSpace>
-            )}
-          </div>
 
-          <NSpin show={forms.openLoading} class={styles.openLoading}>
-            <NCarousel
-              slidesPerView={4}
-              loop={false}
-              style={{ width: forms.bodyWidth }}
-              v-model:currentIndex={forms.carouselIndex}>
-              {forms.openTableList.map((item: any) => (
-                <div class={[styles.itemWrap, styles.itemBlock, 'row-nav']}>
-                  <div class={styles.itemWrapBox}>
-                    <CoursewareType
-                      isShowAdd
-                      item={item}
-                      onAdd={() => onAddCourseware(item)}
-                    />
-                  </div>
-                </div>
-              ))}
-            </NCarousel>
-          </NSpin>
+                {forms.openTableList.length > 4 && (
+                  <NSpace class={styles.swipeControll}>
+                    <div>
+                      <NImage
+                        previewDisabled
+                        class={[styles.leftIcon]}
+                        src={iconSlideRight}
+                      />
+                    </div>
+                    <div>
+                      <NImage previewDisabled src={iconSlideRight} />
+                    </div>
+                  </NSpace>
+                )}
+              </div>
+
+              <NSpin show={forms.openLoading} class={styles.openLoading}>
+                <NCarousel
+                  slidesPerView={4}
+                  loop={false}
+                  style={{ width: forms.bodyWidth }}
+                  v-model:currentIndex={forms.carouselIndex}>
+                  {forms.openTableList.map((item: any) => (
+                    <div class={[styles.itemWrap, styles.itemBlock, 'row-nav']}>
+                      <div class={styles.itemWrapBox}>
+                        <CoursewareType
+                          isShowAdd
+                          item={item}
+                          onAdd={() => onAddCourseware(item)}
+                        />
+                      </div>
+                    </div>
+                  ))}
+                </NCarousel>
+              </NSpin>
+            </>
+          )}
         </NScrollbar>
 
         <NModal
@@ -472,6 +528,13 @@ export default defineComponent({
             onConfirm={() => onRemove()}
           />
         </NModal>
+
+        {/* 应用内预览或上课 */}
+        <PreviewWindow
+          v-model:show={forms.previewModal}
+          type="attend"
+          params={forms.previewParams}
+        />
       </div>
     );
   }

+ 18 - 52
src/views/prepare-lessons/components/lesson-main/courseware/addCourseware.module.less

@@ -322,6 +322,22 @@
       height: 100%;
       padding: 0 6px;
     }
+
+    .itemOperation {
+      position: absolute;
+      top: 0;
+      right: 10px;
+      z-index: 98;
+      cursor: move;
+    }
+
+    .iconDelete {
+      width: 27px;
+      height: 27px;
+      margin-top: 8px;
+      margin-right: 8px;
+      cursor: pointer;
+    }
   }
 
   :global {
@@ -338,65 +354,15 @@
   overflow: hidden;
 }
 
-.itemBlock {
-  position: relative;
-
-  .itemOperation {
-    position: absolute;
-    top: 0;
-    left: 10px;
 
-    width: calc(100% - 20px);
-    height: 100%;
-    text-align: right;
-    z-index: 98;
-    cursor: move;
-  }
-
-  .iconDelete {
-    width: 27px;
-    height: 27px;
-    margin-top: 8px;
-    margin-right: 8px;
-    cursor: pointer;
-  }
-}
-
-.removeVisiable {
-  width: 432px;
+.addCourseware {
+  width: 532px;
 
   :global {
     .n-card-header {
       font-size: max(22px, 16Px);
     }
   }
-
-
-  .studentRemove {
-    padding: 20px 40px 0;
-
-    p {
-      font-size: max(18px, 14Px);
-      color: #777777;
-      line-height: 30px;
-      text-align: center;
-
-      span {
-        color: #EA4132;
-      }
-    }
-  }
-
-  .btnGroupModal {
-    padding: 32px 0;
-
-    :global {
-      .n-button {
-        height: 47px;
-        min-width: 156px;
-      }
-    }
-  }
 }
 
 .removeVisiable1 {

+ 179 - 82
src/views/prepare-lessons/components/lesson-main/courseware/addCourseware.tsx

@@ -28,11 +28,12 @@ import { usePrepareStore } from '/src/store/modules/prepareLessons';
 import { useCatchStore } from '/src/store/modules/catchData';
 import TheEmpty from '/src/components/TheEmpty';
 import {
-  api_add,
+  api_teacherChapterLessonCoursewareAdd,
+  api_teacherChapterLessonCoursewareUpdate,
+  api_teacherChapterLessonCoursewareDetail,
   courseScheduleStart,
   queryCourseware,
-  saveCourseware,
-  teacherKnowledgeMaterialDelete
+  saveCourseware
 } from '../../../api';
 import Draggable from 'vuedraggable';
 import iconDelete from '../../../images/icon-delete.png';
@@ -46,8 +47,15 @@ import SubjectSync from '../../../model/subject-sync';
 import { eventGlobal } from '/src/utils';
 import iconTips from '../../../images/icon-tips.png';
 import TheMessageDialog from '/src/components/TheMessageDialog';
+import AddItemModel from '../../../model/add-item-model';
 export default defineComponent({
   name: 'courseware-modal',
+  props: {
+    groupItem: {
+      type: Object,
+      default: () => ({})
+    }
+  },
   emits: ['change'],
   setup(props, { emit }) {
     const catchStore = useCatchStore();
@@ -59,11 +67,13 @@ export default defineComponent({
 
     const forms = reactive({
       subjects: [] as any,
+      openFlagEnable: false, // 是否支持修改公开状态
       name: '',
       openFlag: false,
       coursewareList: [
         {
           name: '',
+          id: null,
           list: [] as any
         }
       ] as any,
@@ -72,10 +82,11 @@ export default defineComponent({
       attendClassType: 'change', //
       removeIds: [] as any, // 临时删除的编号
       editSubjectIds: '', // 声部编号
-      removeVisiable: false,
+      addCoursewareVisiable: false,
       addCoursewareItem: {} as any,
       messageOperation: {
         visiable: false,
+        loading: false, // 是否显示加载
         type: 'delete' as 'delete' | 'addItem' | 'save',
         contentDirection: 'center' as 'left' | 'center' | 'right',
         title: '删除知识点',
@@ -99,49 +110,61 @@ export default defineComponent({
     const getList = async () => {
       forms.loadingStatus = true;
       try {
-        // const { data } = await queryCourseware({
-        //   coursewareDetailKnowledgeId: prepareStore.getSelectKey,
-        //   subjectId: prepareStore.getSubjectId,
-        //   page: 1,
-        //   rows: 99
-        // });
-        // const tempRows = data.rows || [];
-        // const temp: any = [];
-        // tempRows.forEach((row: any) => {
-        //   temp.push({
-        //     id: row.id,
-        //     materialId: row.materialId,
-        //     coverImg: row.coverImg,
-        //     type: row.materialType,
-        //     title: row.materialName,
-        //     isCollect: !!row.favoriteFlag,
-        //     isSelected: row.source === 'PLATFORM' ? true : false,
-        //     content: row.content,
-        //     removeFlag: row.removeFlag
-        //   });
-        // });
-        // prepareStore.setCoursewareList(temp || []);
-        // const tempCourse: any = [];
-        // temp.forEach((item: any) => {
-        //   if (!forms.removeIds.includes(item.id)) {
-        //     tempCourse.push(item);
-        //   }
-        // });
-        // forms.coursewareList = tempCourse;
-      } catch {
+        if (!props.groupItem.id) return (forms.loadingStatus = false);
+
+        const { data } = await api_teacherChapterLessonCoursewareDetail(
+          props.groupItem.id
+        );
+        const tempRows = data.chapterKnowledgeList || [];
+        forms.name = data.name;
+        forms.subjects = data.subjectIds
+          ? data.subjectIds.split(',').map((s: any) => {
+              return Number(s);
+            })
+          : [];
+        forms.openFlag = data.openFlag;
+        forms.openFlagEnable = data.openFlagEnable;
+        const temp: any = [];
+        tempRows.forEach((row: any) => {
+          const child: any = row.chapterKnowledgeMaterialList;
+          const childList: any[] = [];
+          if (Array.isArray(child) && child.length > 0) {
+            child.forEach((sub: any) => {
+              childList.push({
+                id: sub.id,
+                materialId: sub.bizId,
+                coverImg: sub.bizInfo.coverImg,
+                type: sub.type,
+                title: sub.bizInfo.name,
+                // isCollect: !!sub.favoriteFlag,
+                isSelected: sub.source === 'PLATFORM' ? true : false,
+                content: sub.bizInfo.content,
+                removeFlag: sub.removeFlag
+              });
+            });
+          }
+          temp.push({
+            name: row.name,
+            id: row.id,
+            list: [...childList]
+          });
+        });
+        forms.coursewareList = temp;
+      } catch (e) {
         //
+        console.log(e);
       }
       forms.loadingStatus = false;
     };
 
     // 删除
-    const onDelete = (item: any) => {
-      //
-      forms.removeIds.push(item.id);
-      const index = forms.coursewareList.findIndex(
-        (c: any) => c.id === item.id
+    const onDelete = (item: any, index: number) => {
+      const coursewareItem = forms.coursewareList[index];
+      if (!coursewareItem) return;
+      const childIndex = coursewareItem.list.findIndex(
+        (c: any) => c.id === coursewareItem.list.id
       );
-      forms.coursewareList.splice(index, 1);
+      coursewareItem.list.splice(childIndex, 1);
     };
 
     // 完成编辑
@@ -169,7 +192,7 @@ export default defineComponent({
         });
 
         message.success('编辑成功');
-        forms.removeVisiable = false;
+        // forms.removeVisiable = false;
         prepareStore.setIsEditResource(false);
         // 重置临时删除编号
         forms.removeIds = [];
@@ -194,15 +217,24 @@ export default defineComponent({
     // 操作
     const onChangePoint = (type: string, index: number) => {
       if (type === 'up') {
-        //
+        // 向上移动
+        if (index === 0) return;
+        const temp = forms.coursewareList[index - 1];
+        forms.coursewareList[index - 1] = forms.coursewareList[index];
+        forms.coursewareList[index] = temp;
       } else if (type === 'down') {
-        //
+        // 向下移动
+        if (index >= forms.coursewareList.length - 1) return;
+        const temp = forms.coursewareList[index + 1];
+        forms.coursewareList[index + 1] = forms.coursewareList[index];
+        forms.coursewareList[index] = temp;
       } else if (type === 'remove') {
         forms.messageOperation = {
           visiable: true,
           type: 'delete',
           contentDirection: 'left',
           title: '删除知识点',
+          loading: false,
           content:
             '请确认是否删除该知识点,删除知识点后将同步删除知识点下的资源',
           cancelButtonText: '取消',
@@ -221,7 +253,10 @@ export default defineComponent({
         forms.coursewareList.push({ name: '', list: [] });
         addCoursewareItem(forms.addCoursewareItem);
       } else if (type === 'save') {
+        if (forms.messageOperation.loading) return;
+        forms.messageOperation.loading = true;
         await onSaveCourseWare();
+        forms.messageOperation.loading = false;
       }
       forms.messageOperation.visiable = false;
     };
@@ -234,7 +269,8 @@ export default defineComponent({
           dom.forEach((child: any, index: number) => {
             const status = isPointInsideElement(child, point.x, point.y);
             if (status) {
-              const array: any = forms.coursewareList;
+              const array: any =
+                forms.coursewareList[item.index || 0].list || [];
               const left = isPointOnLeft(child, point.x);
               if (!left) {
                 array.splice(index + 1, 0, item);
@@ -243,17 +279,14 @@ export default defineComponent({
               }
               isAdd = true;
               forms.coursewareList[item.index || 0].list = array;
-              prepareStore.setCoursewareList(forms.coursewareList);
             }
           });
           if (!isAdd) {
             forms.coursewareList[item.index || 0].list.push(item);
-            prepareStore.setCoursewareList(forms.coursewareList);
           }
         } else {
-          forms.coursewareList[0].list.push(item);
-          console.log(forms.coursewareList);
-          prepareStore.setCoursewareList(forms.coursewareList);
+          forms.coursewareList[item.index || 0].list.push(item);
+          message.success('添加成功');
         }
       });
     };
@@ -288,6 +321,7 @@ export default defineComponent({
         forms.messageOperation = {
           visiable: true,
           type: 'save',
+          loading: false,
           contentDirection: 'center',
           title: '保存课件',
           content: '当前课件暂未保存,是否保存?',
@@ -299,11 +333,8 @@ export default defineComponent({
         //
       }
     };
-    let isLock = false;
     const onSaveCourseWare = async () => {
       try {
-        if (isLock) return;
-        isLock = true;
         const params = {
           name: forms.name,
           subjectIds: forms.subjects.join(','),
@@ -328,13 +359,19 @@ export default defineComponent({
             chapterKnowledgeMaterialList: tempItem
           });
         });
-        await api_add(params);
-        message.success('添加成功');
+        if (props.groupItem?.id) {
+          await api_teacherChapterLessonCoursewareUpdate({
+            id: props.groupItem.id,
+            ...params
+          });
+          message.success('修改成功');
+        } else {
+          await api_teacherChapterLessonCoursewareAdd(params);
+          message.success('添加成功');
+        }
+
         emit('change', { status: false });
         eventGlobal.emit('teacher-slideshow', false);
-        setTimeout(() => {
-          isLock = false;
-        }, 100);
       } catch {
         //
       }
@@ -349,18 +386,21 @@ export default defineComponent({
           type: 'addItem',
           contentDirection: 'center',
           title: '添加到知识点',
+          loading: false,
           content: '当前课件暂无知识点,请添加知识点后操作',
           cancelButtonText: '取消',
           confirmButtonText: '添加知识点',
           index: 0
         };
+      } else if (forms.coursewareList.length > 1 && item.addType !== 'drag') {
+        forms.addCoursewareVisiable = true;
+        forms.addCoursewareItem = item;
       } else {
         addCoursewareItem(item, point);
       }
     };
     onMounted(async () => {
       await getList();
-
       // 动态添加数据
       eventGlobal.on('onPrepareAddItem', addItem);
     });
@@ -369,6 +409,16 @@ export default defineComponent({
       eventGlobal.off('onPrepareAddItem', addItem);
     });
 
+    // 当列表数据更新时同步缓存数据
+    watch(
+      () => forms.coursewareList,
+      () => {
+        prepareStore.setCoursewareList = forms.coursewareList;
+      },
+      {
+        deep: true
+      }
+    );
     return () => (
       <div class={styles.coursewareModal}>
         <div class={styles.btnGroup}>
@@ -377,7 +427,12 @@ export default defineComponent({
               <span class={styles.btnTitle}>
                 <span>*</span>标题:
               </span>
-              <NInput placeholder="请输入课件标题" v-model:value={forms.name} />
+              <NInput
+                placeholder="请输入课件标题"
+                v-model:value={forms.name}
+                maxlength={15}
+                clearable
+              />
             </div>
             <div class={styles.btnItem}>
               <span class={styles.btnTitle}>
@@ -393,11 +448,30 @@ export default defineComponent({
                 maxTagCount={1}
                 size="small"
                 v-model:value={forms.subjects}
+                clearable
               />
             </div>
             <div class={styles.btnItem}>
               <span class={styles.btnTitle}>公开:</span>
-              <NSwitch v-model:value={forms.openFlag} />
+              {forms.openFlagEnable ? (
+                <NTooltip style={{ maxWidth: '200px' }} showArrow={false}>
+                  {{
+                    trigger: () => (
+                      <NSwitch
+                        v-model:value={forms.openFlag}
+                        disabled={forms.openFlagEnable}
+                      />
+                    ),
+                    default: () =>
+                      '为尊重课件原作者,在“相关课件”中添加的课件不支持公开'
+                  }}
+                </NTooltip>
+              ) : (
+                <NSwitch
+                  v-model:value={forms.openFlag}
+                  disabled={forms.openFlagEnable}
+                />
+              )}
             </div>
           </NSpace>
 
@@ -431,7 +505,10 @@ export default defineComponent({
                   }}
                   onDrop={(e: any) => {
                     let dropItem = e.dataTransfer.getData('text');
-                    dropItem = dropItem ? JSON.parse(dropItem) : {};
+                    dropItem =
+                      dropItem && e.dataTransfer.effectAllowed === 'all'
+                        ? JSON.parse(dropItem)
+                        : {};
                     // 判断是否有数据
                     if (dropItem.id) {
                       // 获取拖拽的目标元素
@@ -441,12 +518,13 @@ export default defineComponent({
                           materialId: dropItem.id,
                           coverImg: dropItem.coverImg,
                           type: dropItem.type,
-                          title: dropItem.name,
+                          title: dropItem.title,
                           isCollect: dropItem.isCollect,
                           isSelected: dropItem.isSelected,
                           content: dropItem.content,
                           removeFlag: false,
-                          index
+                          index,
+                          addType: 'drag'
                         },
                         {
                           x: e.clientX,
@@ -463,6 +541,8 @@ export default defineComponent({
                       <NInput
                         placeholder="未命名知识点"
                         v-model:value={item.name}
+                        maxlength={15}
+                        clearable
                       />
                     </div>
                   </div>
@@ -476,7 +556,7 @@ export default defineComponent({
                               class={styles.iconCUp}
                               onClick={() => onChangePoint('up', index)}></i>
                           ),
-                          default: '上移知识点'
+                          default: () => '上移知识点'
                         }}
                       </NTooltip>
                     )}
@@ -488,7 +568,7 @@ export default defineComponent({
                               class={styles.iconCDown}
                               onClick={() => onChangePoint('down', index)}></i>
                           ),
-                          default: '下移知识点'
+                          default: () => '下移知识点'
                         }}
                       </NTooltip>
                     )}
@@ -499,7 +579,7 @@ export default defineComponent({
                             class={styles.iconCRemove}
                             onClick={() => onChangePoint('remove', index)}></i>
                         ),
-                        default: '删除知识点'
+                        default: () => '删除知识点'
                       }}
                     </NTooltip>
                   </NSpace>
@@ -534,6 +614,12 @@ export default defineComponent({
                                   offShelf={item.removeFlag ? true : false}
                                   // onOffShelf={() => onRemove(item)}
                                   item={item}
+                                  disabledMouseHover={false}
+                                  onClick={() => {
+                                    if (item.type === 'IMG') return;
+                                    forms.show = true;
+                                    forms.item = item;
+                                  }}
                                 />
                                 <div class={styles.itemOperation}>
                                   <img
@@ -541,7 +627,7 @@ export default defineComponent({
                                     class={styles.iconDelete}
                                     onClick={(e: MouseEvent) => {
                                       e.stopPropagation();
-                                      onDelete(item);
+                                      onDelete(item, index);
                                     }}
                                   />
                                 </div>
@@ -627,22 +713,26 @@ export default defineComponent({
         <CardPreview v-model:show={forms.show} item={forms.item} />
 
         <NModal
-          v-model:show={forms.removeVisiable}
+          v-model:show={forms.addCoursewareVisiable}
           preset="card"
-          class={['modalTitle', styles.removeVisiable]}
-          title={'提示'}>
-          <div class={styles.studentRemove}>
-            <p>是否完成编辑?</p>
+          class={['modalTitle', styles.addCourseware]}
+          title={'添加知识点'}>
+          <AddItemModel
+            coursewareList={forms.coursewareList}
+            onClose={() => (forms.addCoursewareVisiable = false)}
+            onConfirm={(selects: number[]) => {
+              if (Array.isArray(selects) && selects.length > 0) {
+                selects.forEach(select => {
+                  addCoursewareItem({
+                    ...forms.addCoursewareItem,
+                    index: select
+                  });
+                });
 
-            <NSpace class={styles.btnGroupModal} justify="center">
-              <NButton round type="primary" onClick={onOverEdit}>
-                确定
-              </NButton>
-              <NButton round onClick={() => (forms.removeVisiable = false)}>
-                取消
-              </NButton>
-            </NSpace>
-          </div>
+                forms.addCoursewareVisiable = false;
+              }
+            }}
+          />
         </NModal>
 
         <NModal
@@ -655,7 +745,14 @@ export default defineComponent({
             contentDirection={forms.messageOperation.contentDirection}
             cancelButtonText={forms.messageOperation.cancelButtonText}
             confirmButtonText={forms.messageOperation.confirmButtonText}
-            onClose={() => (forms.messageOperation.visiable = false)}
+            loading={forms.messageOperation.loading}
+            onClose={() => {
+              forms.messageOperation.visiable = false;
+              if (forms.messageOperation.type === 'save') {
+                emit('change', { status: false });
+                eventGlobal.emit('teacher-slideshow', false);
+              }
+            }}
             onConfirm={() => onMessageConfirm()}
           />
         </NModal>

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

@@ -14,6 +14,7 @@ export default defineComponent({
     const prepareStore = usePrepareStore();
     const state = reactive({
       editCoursewareShow: false, // 是否编辑课件
+      editCourseware: {} as any, //
       editWorkShow: false, // 是否编辑预设
       editWork: {} as any // 预设模板编号
     });
@@ -55,6 +56,7 @@ export default defineComponent({
               displayDirective="if">
               {state.editCoursewareShow ? (
                 <Courseware
+                  groupItem={state.editCourseware}
                   onChange={(val: any) => {
                     state.editCoursewareShow = val.status;
 
@@ -67,6 +69,7 @@ export default defineComponent({
                 <CoursewarePresets
                   onChange={(val: any) => {
                     state.editCoursewareShow = val.status;
+                    state.editCourseware = val.groupItem;
                   }}
                 />
               )}

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

@@ -56,6 +56,17 @@
     cursor: pointer;
   }
 
+  .homerowkTabs {
+    :global {
+      .n-tabs-tab-pad {
+        width: 13px !important;
+      }
+
+      .v-x-scroll {
+        padding-right: 40px;
+      }
+    }
+  }
 
 }
 

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

@@ -96,6 +96,7 @@ export default defineComponent({
           <NTabs
             ref={tabRef}
             animated
+            class={styles.homerowkTabs}
             value={forms.tabType}
             paneClass={styles.paneTitle}
             paneWrapperClass={styles.paneWrapperContainer}

+ 26 - 0
src/views/prepare-lessons/model/add-item-model/index.module.less

@@ -0,0 +1,26 @@
+.addCoursewareItem {
+  padding: 20px 40px 0;
+
+
+  :global {
+    .n-checkbox__label {
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      width: 200px;
+      padding-left: 10px;
+      color: #777777;
+    }
+  }
+}
+
+.btnGroupModal {
+  padding: 32px 0;
+
+  :global {
+    .n-button {
+      height: 47px;
+      min-width: 156px;
+    }
+  }
+}

+ 52 - 0
src/views/prepare-lessons/model/add-item-model/index.tsx

@@ -0,0 +1,52 @@
+import { defineComponent, ref } from 'vue';
+import styles from './index.module.less';
+import {
+  NButton,
+  NCheckbox,
+  NCheckboxGroup,
+  NGi,
+  NGrid,
+  NSpace
+} from 'naive-ui';
+
+export default defineComponent({
+  name: 'add-courseware-item',
+  props: {
+    coursewareList: {
+      type: Array,
+      default: () => []
+    }
+  },
+  emits: ['close', 'confirm'],
+  setup(props, { emit }) {
+    const selects = ref<number[]>([]);
+    return () => (
+      <div class={styles.addCoursewareItem}>
+        <NCheckboxGroup v-model:value={selects.value}>
+          <NGrid yGap={12} cols={2}>
+            {props.coursewareList.map((courseware: any, index: number) => (
+              <NGi>
+                <NCheckbox value={index}>{courseware.name}</NCheckbox>
+              </NGi>
+            ))}
+          </NGrid>
+        </NCheckboxGroup>
+
+        <NSpace class={styles.btnGroupModal} justify="center">
+          <NButton round onClick={() => emit('close')}>
+            取消
+          </NButton>
+          <NButton
+            round
+            type="primary"
+            onClick={() => {
+              console.log(selects.value, '1221');
+              emit('confirm', selects.value);
+            }}>
+            确定
+          </NButton>
+        </NSpace>
+      </div>
+    );
+  }
+});

+ 35 - 1
src/views/prepare-lessons/model/courseware-type/index.module.less

@@ -54,6 +54,7 @@
     border-radius: 10px;
     overflow: hidden;
     background-color: #fff;
+    transition: all .2s ease;
 
     .status {
       position: absolute;
@@ -77,6 +78,37 @@
     img {
       width: 100%;
     }
+
+    &:hover .preview {
+      opacity: 1;
+      visibility: visible;
+      transition: all .2s ease;
+    }
+  }
+
+
+  .preview {
+    position: absolute;
+    opacity: 0;
+    visibility: hidden;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background-color: rgba(0, 0, 0, 0.4);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+    cursor: pointer;
+
+    .previewBtn {
+      background: #3D9EFF;
+      height: max(40px, 32Px);
+      padding: 0 30px;
+      border-radius: 12px;
+      color: #fff;
+    }
   }
 
   .coursewareText {
@@ -90,6 +122,7 @@
       align-items: center;
 
       span {
+        list-style: 16Px;
         max-width: 100%;
         display: inline-block;
         overflow: hidden;
@@ -137,9 +170,10 @@
     }
 
     .subjectName {
-      padding-top: 10px;
+      padding-top: 8px;
       font-size: 11Px;
       color: #777777;
+      line-height: 16Px;
     }
   }
 }

+ 15 - 2
src/views/prepare-lessons/model/courseware-type/index.tsx

@@ -31,10 +31,15 @@ export default defineComponent({
     operate: {
       type: Boolean,
       default: false
+    },
+    /** 是否显示预览按钮 */
+    isShowPreviewBtn: {
+      type: Boolean,
+      default: false
     }
   },
   /** add */
-  emits: ['add', 'editName', 'edit', 'delete', 'startClass'],
+  emits: ['add', 'editName', 'edit', 'delete', 'startClass', 'click'],
   setup(props, { emit }) {
     return () => (
       <div
@@ -57,9 +62,17 @@ export default defineComponent({
             {props.item.isAdd ? '已添加' : '添加'}
           </NButton>
         )}
-        <div class={styles.cover}>
+        <div class={styles.cover} onClick={() => emit('click')}>
           {props.item.openFlag && <span class={styles.status}>公开</span>}
           <NImage objectFit="cover" previewDisabled src={props.item.coverImg} />
+
+          {props.isShowPreviewBtn && (
+            <div class={styles.preview}>
+              <NButton strong secondary class={styles.previewBtn}>
+                使用课件
+              </NButton>
+            </div>
+          )}
         </div>
         <div class={styles.coursewareText}>
           <div class={[styles.name, props.isEditName && styles.editName]}>

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

@@ -23,10 +23,6 @@ export default defineComponent({
     const tabType = ref(type.value);
 
     onMounted(() => {
-      // console.log(
-      //   document.querySelector('.select-resource .n-tabs-nav--top'),
-      //   ''
-      // );
       useResizeObserver(
         document.querySelector(
           '.select-resource .n-tabs-nav--top'
@@ -53,6 +49,11 @@ export default defineComponent({
           onUpdate:value={(val: string) => {
             tabType.value = val;
           }}>
+          {props.from !== 'class' && (
+            <NTabPane name="relateResources" tab={'相关资源'}>
+              <SelectItem type="relateResources" />
+            </NTabPane>
+          )}
           <NTabPane
             name="myResources"
             tab={props.from === 'class' ? '我的曲目' : '我的资源'}>

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

@@ -26,7 +26,9 @@ export default defineComponent({
   name: 'resource-search-group',
   props: {
     type: {
-      type: String as PropType<'shareResources' | 'myResources' | 'myCollect'>,
+      type: String as PropType<
+        'relateResources' | 'shareResources' | 'myResources' | 'myCollect'
+      >,
       default: 'shareResources'
     },
     subjectId: {

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

@@ -1,13 +1,6 @@
-import {
-  PropType,
-  defineComponent,
-  onMounted,
-  reactive,
-  toRefs,
-  watch
-} from 'vue';
+import { PropType, defineComponent, onMounted, reactive, toRefs } from 'vue';
 import ResourceSearchGroup from './resource-search-group';
-import { NScrollbar, NSpin } from 'naive-ui';
+import { NScrollbar, NSpin, useMessage } from 'naive-ui';
 import styles from './index.module.less';
 import CardType from '/src/components/card-type';
 import { favorite, materialQueryPage } from '/src/views/natural-resources/api';
@@ -26,6 +19,8 @@ const formatType = (type: string) => {
     return 3;
   } else if (type === 'myCollect') {
     return 4;
+  } else if (type === 'relateResources') {
+    return 5;
   }
 };
 
@@ -33,7 +28,9 @@ export default defineComponent({
   name: 'share-resources',
   props: {
     type: {
-      type: String as PropType<'shareResources' | 'myResources' | 'myCollect'>,
+      type: String as PropType<
+        'relateResources' | 'shareResources' | 'myResources' | 'myCollect'
+      >,
       default: 'shareResources'
     },
     /** 从哪里使用 */
@@ -45,6 +42,7 @@ export default defineComponent({
   setup(props) {
     const prepareStore = usePrepareStore();
     const catchStore = useCatchStore();
+    const message = useMessage();
     const { type } = toRefs(props);
     const className = 'resourceSearchGroup' + +new Date();
     const state = reactive({
@@ -83,9 +81,6 @@ export default defineComponent({
         const tempRows = data.rows || [];
         const temp: any = [];
         tempRows.forEach((row: any) => {
-          const index = prepareStore.getCoursewareList.findIndex(
-            (course: any) => course.materialId === row.id
-          );
           temp.push({
             id: row.id,
             coverImg: row.coverImg,
@@ -93,8 +88,7 @@ export default defineComponent({
             title: row.name,
             isCollect: !!row.favoriteFlag,
             isSelected: row.sourceFrom === 'PLATFORM' ? true : false,
-            content: row.content,
-            exist: index !== -1 ? true : false // 是否存在
+            content: row.content
           });
         });
         state.tableList.push(...temp);
@@ -142,22 +136,6 @@ export default defineComponent({
       }
     };
 
-    watch(
-      () => prepareStore.coursewareList,
-      () => {
-        state.tableList.forEach((item: any) => {
-          const index = prepareStore.getCoursewareList.findIndex(
-            (course: any) => course.materialId === item.id
-          );
-          item.exist = index !== -1 ? true : false; // 是否存在
-        });
-      },
-      {
-        deep: true,
-        immediate: true
-      }
-    );
-
     // 收藏
     const onCollect = async (item: any) => {
       try {
@@ -175,13 +153,6 @@ export default defineComponent({
     onMounted(async () => {
       // 获取声部
       await catchStore.getSubjects();
-      // catchStore.getSubjectInstruments.forEach((item: any) => {
-      //   if (item.id == prepareStore.getSubjectId) {
-      //     if (item.instruments && item.instruments.length > 0) {
-      //       state.searchGroup.musicalInstrumentId = item.instruments[0].value;
-      //     }
-      //   }
-      // });
 
       getList();
 

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

@@ -26,7 +26,9 @@ export default defineComponent({
   name: 'resource-search-group',
   props: {
     type: {
-      type: String as PropType<'shareResources' | 'myResources' | 'myCollect'>,
+      type: String as PropType<
+        'relateResources' | 'shareResources' | 'myResources' | 'myCollect'
+      >,
       default: 'shareResources'
     },
     subjectId: {

+ 1 - 0
src/views/preview-window/index.tsx

@@ -79,6 +79,7 @@ export default defineComponent({
                 <AttendClass
                   type={params.value.type || ''}
                   subjectId={params.value.subjectId || ''}
+                  courseId={params.value.courseId || ''}
                   detailId={params.value.detailId || ''}
                   classGroupId={params.value.classGroupId || ''}
                   lessonCourseId={params.value.lessonCourseId || ''}