瀏覽代碼

ppt课件编辑

黄琪勇 5 月之前
父節點
當前提交
f0d1d252a4

+ 16 - 0
src/utils/urlUtils.ts

@@ -33,3 +33,19 @@ export function vaildMusicScoreUrl() {
   }
   return returnUrl;
 }
+
+export function vaildPPTUrl() {
+  const url: string = window.location.hostname;
+  let returnUrl = '';
+
+  if (/test/.test(url)) {
+    returnUrl = 'https://test.kt.colexiu.com';
+  } else if (/dev/.test(url)) {
+    returnUrl = 'https://dev.kt.colexiu.com';
+  } else if (/localhost/.test(url)) {
+    returnUrl = 'http://192.168.3.122:9527';
+  } else {
+    returnUrl = 'https://mec.colexiu.com';
+  }
+  return returnUrl;
+}

+ 15 - 6
src/views/prepare-lessons/api.ts

@@ -289,6 +289,18 @@ export const api_teacherChapterLessonCoursewareDetail = (id: string) => {
 };
 
 /**
+ * 平台课件转老师课件
+ */
+export const api_coursewareToTeacherCourseware = (id: string) => {
+  return request.post(
+    '/edu-app/teacherChapterLessonCourseware/coursewareToTeacherCourseware',
+    {
+      data: { id }
+    }
+  );
+};
+
+/**
  *  @description: 素材详情
  * @param params
  */
@@ -296,7 +308,6 @@ export const api_materialDetail = (id: string) => {
   return request.get('/edu-app/material/detail/' + id);
 };
 
-
 /**
  *  @description: 老师查询教材分类
  * @param params
@@ -305,17 +316,15 @@ export const api_lessonCoursewareTeacherCategory = () => {
   return request.get('/edu-app/lessonCourseware/teacherCategory');
 };
 
-
-
 /**
  *  @description: 备课页面检测声部
  * @param params
  */
 export const api_courseScheduleCheck = (params: {
-  classGroupId: string
-  chapterLessonCoursewareId: string
+  classGroupId: string;
+  chapterLessonCoursewareId: string;
 }) => {
   return request.post('/edu-app/courseSchedule/check', {
     data: params
   });
-};
+};

+ 85 - 1
src/views/prepare-lessons/components/lesson-main/courseware-presets/index.module.less

@@ -56,6 +56,28 @@
   .presetsLeft {
     flex: 1;
     transition: all .1s ease;
+    .popoverItem {
+      font-weight: 600;
+      font-size: max(16px, 12Px);
+      width: 120px;
+      height: 36px;
+      color: #484F59;
+      border-radius: 8px;
+      text-align: center;
+      line-height: 36px;
+      cursor: pointer;
+      &:hover {
+        background: #F5F6FA;
+      }
+    }
+
+    :global {
+      .n-popover {
+        box-shadow: 0px 2px 12px 0px rgba(0,0,0,0.1);
+        border-radius: 10px;
+        padding: 8px 6px !important;
+      }
+    }
   }
 
   .presetsRight {
@@ -441,4 +463,66 @@
       background: url('@/views/prepare-lessons/images/icon-arrow-2.png') no-repeat center center / contain;
     }
   }
-}
+}
+
+.pptCoursewareModal{
+  width: 486px;
+  :global{
+    .n-card-header{
+      background: #F5F6FA;
+    }
+    .n-card__content{
+      padding: 30px;
+      .n-form-item .n-form-item-label{
+        color: #666666;
+        .n-form-item-label__text{
+          font-size: max(18px, 13Px);
+        }
+      }
+    }
+  }
+  .updateBtnGroup {
+    padding: 0;
+    justify-content: center !important;
+    :global {
+      .n-button {
+        height: 48px !important;
+        min-width: 156px;
+      }
+    }
+  }
+  .btnItem {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    margin-bottom: 38px;
+
+    &.block {
+      flex-direction: column;
+      align-items: flex-start;
+
+      .btnTitle {
+        padding-bottom: 8px;
+      }
+    }
+
+    .btnTitle {
+      flex-shrink: 0;
+      font-size: max(18px, 13Px);
+      font-weight: 400;
+      display: flex;
+      align-items: center;
+      color: #666666;
+    }
+
+    .iconQuestion {
+      display: inline-block;
+      margin-left: 6px;
+      width: 13Px;
+      height: 14Px;
+      background: url('../../../images/icon-question.png') no-repeat center;
+      background-size: contain;
+      cursor: pointer;
+    }
+  }
+}

+ 365 - 56
src/views/prepare-lessons/components/lesson-main/courseware-presets/index.tsx

@@ -18,7 +18,14 @@ import {
   NTabPane,
   NTabs,
   useMessage,
-  NPopselect
+  NPopselect,
+  NPopover,
+  NForm,
+  NFormItem,
+  NInput,
+  NSpace,
+  NCascader,
+  NSwitch
 } from 'naive-ui';
 import { usePrepareStore } from '/src/store/modules/prepareLessons';
 import add from '@/views/studentList/images/add.png';
@@ -43,6 +50,15 @@ import PreviewWindow from '/src/views/preview-window';
 import Related from './related';
 import Train from '../train';
 import ResourceMain from '../../resource-main';
+import { useCatchStore } from '/src/store/modules/catchData';
+import deepClone from '/src/helpers/deep-clone';
+import {
+  api_teacherChapterLessonCoursewareAdd,
+  api_coursewareToTeacherCourseware,
+  api_updateCoursewareInfo
+} from '../../../api';
+import { vaildPPTUrl } from '/src/utils/urlUtils';
+import { useUserStore } from '/src/store/modules/users';
 
 export default defineComponent({
   name: 'courseware-presets',
@@ -103,7 +119,7 @@ export default defineComponent({
       workVisiable: false,
       wikiCategoryIdChild: null,
       instrumentErrorVisiable: false,
-      instrumentErrorContent: ""
+      instrumentErrorContent: ''
     });
 
     const getCoursewareList = async () => {
@@ -137,7 +153,11 @@ export default defineComponent({
             name: item.name,
             coverImg: firstItem && firstItem[0]?.bizInfo.coverImg,
             type: firstItem && firstItem[0]?.bizInfo.type,
-            isNotWork: item.lessonPreTrainingNum <= 0 ? true : false // 是否布置作业
+            isNotWork: item.lessonPreTrainingNum <= 0 ? true : false, // 是否布置作业
+            coursewareType: item.coursewareType,
+            instrumentIds: item.instrumentIds,
+            pptId: firstItem && firstItem[0]?.id,
+            teacherSaveFlag: item.teacherSaveFlag
           });
         });
         forms.tableList = tempList;
@@ -422,43 +442,37 @@ export default defineComponent({
     };
 
     /** 上课前检测声部 */
-    const onClassCheckInstrument = async (item: any,
+    const onClassCheckInstrument = async (
+      item: any,
       classGroupId: any,
-      instrumentId?: any) => {
-        
+      instrumentId?: any
+    ) => {
       try {
-        if(classGroupId) {
-          const {data} = await api_courseScheduleCheck({
+        if (classGroupId) {
+          const { data } = await api_courseScheduleCheck({
             classGroupId,
             chapterLessonCoursewareId: item.id
-          })
+          });
           forms.attendClassItem = item;
           forms.attendClassId = classGroupId;
-          if(!data.chapterLessonCoursewareFlag) {
+          if (!data.chapterLessonCoursewareFlag) {
             forms.instrumentErrorVisiable = true;
-            forms.instrumentErrorContent = '课件支持的乐器与班级不符,是否继续使用该课件上课?'
-          } else if(!data.materialFlag) {
+            forms.instrumentErrorContent =
+              '课件支持的乐器与班级不符,是否继续使用该课件上课?';
+          } else if (!data.materialFlag) {
             forms.instrumentErrorVisiable = true;
-            forms.instrumentErrorContent = '课件中含有不符合班级乐器的资源,是否继续使用该课件上课?'
+            forms.instrumentErrorContent =
+              '课件中含有不符合班级乐器的资源,是否继续使用该课件上课?';
           } else {
-            onStartClass(
-              item,
-              classGroupId,
-              instrumentId
-            );
+            onStartClass(item, classGroupId, instrumentId);
           }
         } else {
-          onStartClass(
-            item,
-            classGroupId,
-            instrumentId
-          );
+          onStartClass(item, classGroupId, instrumentId);
         }
-        
       } catch {
-        // 
+        //
       }
-    }
+    };
 
     const selectChildObj = (item: any) => {
       const obj: any = {};
@@ -487,6 +501,144 @@ export default defineComponent({
       });
       return instrumentId;
     });
+    /* ppt课件 */
+    const userStore = useUserStore();
+    const pptCourseware = reactive({
+      pptCoursewareShow: false,
+      id: '',
+      name: '',
+      subjects: [],
+      openFlagEnable: true,
+      openFlag: false
+    });
+    const pptFormsRef = ref();
+    const subjectList = ref<any[]>([]);
+    const updateSubjectList = (ids?: any[]) => {
+      // 获取适用乐器编号 ,修改的乐器编号,集合
+      ids = ids || [];
+      const courseIds: any = [];
+      prepareStore.getInstrumentList.forEach((item: any) => {
+        if (Array.isArray(item.instruments)) {
+          item.instruments.forEach((child: any) => {
+            courseIds.push(child.id);
+          });
+        }
+      });
+      const allIds = [...new Set([...courseIds, ...ids])];
+
+      const tempList: any = [];
+      useCatchStore().getSubjectList.forEach((item: any) => {
+        const temp = deepClone(item);
+        temp.enableFlag = false;
+        if (Array.isArray(temp.instruments)) {
+          temp.instruments.forEach((child: any) => {
+            child.enableFlag = false;
+            if (allIds.includes(child.id)) {
+              child.enableFlag = true;
+              temp.enableFlag = true;
+            }
+          });
+        }
+        tempList.push(temp);
+      });
+      const tempSubjects: any[] = [];
+      tempList.forEach((subject: any) => {
+        if (subject.enableFlag) {
+          const { instruments, ...r } = subject;
+
+          if (instruments && instruments.length > 0) {
+            const tempChild: any[] = [];
+            instruments?.forEach((instrument: any) => {
+              if (instrument.enableFlag) {
+                tempChild.push(instrument);
+              }
+            });
+
+            if (tempChild.length > 0)
+              tempSubjects.push({ ...r, instruments: tempChild });
+          }
+        }
+      });
+      subjectList.value = tempSubjects;
+    };
+    const chioseAll = (list: any) => {
+      // 全选
+      const ids = [] as any;
+      list.map((item: any) => {
+        if (Array.isArray(item.instruments)) {
+          item.instruments.forEach((c: any) => {
+            ids.push(c.value);
+          });
+        }
+      }) as any;
+      pptCourseware.subjects = ids;
+    };
+    function handlePptConfirm() {
+      pptFormsRef.value?.validate(async (err: any) => {
+        if (err) {
+          return;
+        }
+        const { id, name, subjects, openFlag, openFlagEnable } = pptCourseware;
+        if (id) {
+          const params = {
+            id,
+            name,
+            instrumentIds: subjects.join(','),
+            openFlag,
+            autoPlay: false,
+            openFlagEnable
+          };
+          api_updateCoursewareInfo(params).then(res => {
+            if (res.code === 200) {
+              pptCourseware.pptCoursewareShow = false;
+              getCoursewareList();
+              eventGlobal.emit('openCoursewareChanged');
+            }
+          });
+        } else {
+          const params = {
+            name,
+            instrumentIds: subjects.join(','),
+            openFlag,
+            autoPlay: false,
+            coursewareDetailKnowledgeId: prepareStore.getSelectKey,
+            coursewareType: 'PPT'
+          };
+          api_teacherChapterLessonCoursewareAdd(params).then(res => {
+            if (res.code === 200) {
+              pptCourseware.pptCoursewareShow = false;
+              getCoursewareList();
+              eventGlobal.emit('openCoursewareChanged');
+            }
+          });
+        }
+      });
+    }
+    function handlePptEdit(item: Record<string, any>) {
+      updateSubjectList();
+      pptCourseware.id = item.id;
+      pptCourseware.name = item.name;
+      pptCourseware.subjects = item.instrumentIds
+        ? item.instrumentIds.split(',')
+        : [];
+      pptCourseware.openFlag = item.openFlag;
+      pptCourseware.openFlagEnable = item.openFlagEnable;
+      pptCourseware.pptCoursewareShow = true;
+    }
+    async function handleRouterPPT(item: Record<string, any>) {
+      // 当teacherSaveFlag为false时候,需要把平台数据转为老师自己的课件
+      if (!item.teacherSaveFlag) {
+        await api_coursewareToTeacherCourseware(item.id);
+        item.teacherSaveFlag = true;
+      }
+      const href = `${vaildPPTUrl()}/#/pptEditor?id=${
+        item.pptId
+      }&Authorization=${userStore.getToken}`;
+      window.open(href);
+    }
+    onMounted(async () => {
+      await useCatchStore().getSubjects();
+    });
     return () => (
       <div
         class={[
@@ -527,23 +679,57 @@ export default defineComponent({
             }}
             v-slots={{
               suffix: () => (
-                <NButton
-                  class={styles.addBtn}
-                  type="primary"
-                  bordered={false}
-                  onClick={() => {
-                    eventGlobal.emit('teacher-slideshow', true);
-                    emit('change', {
-                      status: true,
-                      type: 'create'
-                    });
-                  }}>
-                  <NImage
-                    class={styles.addBtnIcon}
-                    previewDisabled
-                    src={add}></NImage>
-                  创建课件
-                </NButton>
+                <NPopover
+                  placement="bottom"
+                  trigger="hover"
+                  showArrow={false}
+                  to={false}
+                  duration={50}>
+                  {{
+                    trigger: () => (
+                      <NButton
+                        class={styles.addBtn}
+                        type="primary"
+                        bordered={false}>
+                        <NImage
+                          class={styles.addBtnIcon}
+                          previewDisabled
+                          src={add}></NImage>
+                        创建课件
+                      </NButton>
+                    ),
+                    default: () => (
+                      <div>
+                        <div
+                          class={styles.popoverItem}
+                          onClick={() => {
+                            eventGlobal.emit('teacher-slideshow', true);
+                            emit('change', {
+                              status: true,
+                              type: 'create'
+                            });
+                          }}>
+                          <span>传统课件</span>
+                        </div>
+                        <div
+                          class={styles.popoverItem}
+                          onClick={() => {
+                            updateSubjectList();
+                            Object.assign(pptCourseware, {
+                              pptCoursewareShow: true,
+                              id: '',
+                              name: '',
+                              subjects: [],
+                              openFlagEnable: true,
+                              openFlag: false
+                            });
+                          }}>
+                          <span>PPT</span>
+                        </div>
+                      </div>
+                    )
+                  }}
+                </NPopover>
               )
             }}>
             {[
@@ -617,14 +803,23 @@ export default defineComponent({
                           //   forms.editTitle = item.name;
                           //   forms.editTitleVisiable = true;
                           // }}
-                          onEdit={() => {
+                          onEdit={type => {
                             //
-                            eventGlobal.emit('teacher-slideshow', true);
-                            emit('change', {
-                              status: true,
-                              type: 'update',
-                              groupItem: { id: item.id }
-                            });
+                            if (item.coursewareType === 'PPT') {
+                              if (type === 'PPT') {
+                                // 进入 ppt 编辑页面
+                                handleRouterPPT(item);
+                              } else {
+                                handlePptEdit(item);
+                              }
+                            } else {
+                              eventGlobal.emit('teacher-slideshow', true);
+                              emit('change', {
+                                status: true,
+                                type: 'update',
+                                groupItem: { id: item.id }
+                              });
+                            }
                           }}
                           onStartClass={() =>
                             onClassCheckInstrument(item, forms.classGroupId)
@@ -798,14 +993,10 @@ export default defineComponent({
             contentDirection="left"
             onClose={() => {
               forms.instrumentErrorVisiable = false;
-              
             }}
             onConfirm={() => {
-              // 
-              onStartClass(
-                forms.attendClassItem,
-                forms.attendClassId
-              );
+              //
+              onStartClass(forms.attendClassItem, forms.attendClassId);
             }}
           />
         </NModal>
@@ -885,6 +1076,124 @@ export default defineComponent({
             </div>
           </div>
         </NModal>
+        {/* 新建ppt课件 */}
+        <NModal
+          maskClosable={modalClickMask}
+          v-model:show={pptCourseware.pptCoursewareShow}
+          preset="card"
+          class={['modalTitle', styles.pptCoursewareModal]}
+          title={'课件设置'}>
+          <NForm
+            ref={pptFormsRef}
+            model={pptCourseware}
+            labelAlign="right"
+            labelPlacement="left">
+            <NFormItem
+              label="课件名称"
+              path="name"
+              rule={[
+                {
+                  required: true,
+                  message: '请输入课件名称',
+                  trigger: ['blur', 'change']
+                }
+              ]}>
+              <NInput
+                placeholder="请输入课件名称"
+                v-model:value={pptCourseware.name}
+                maxlength={20}
+                clearable
+              />
+            </NFormItem>
+            <NFormItem
+              label="适用乐器"
+              path="subjects"
+              rule={[
+                {
+                  required: true,
+                  message: '请输入适用乐器',
+                  trigger: ['blur', 'change'],
+                  type: 'array'
+                }
+              ]}>
+              <NCascader
+                placeholder="请选择乐器(可多选)"
+                class={styles.btnSubjectList}
+                options={subjectList.value}
+                checkStrategy="child"
+                showPath={false}
+                childrenField="instruments"
+                expandTrigger="hover"
+                labelField="name"
+                valueField="id"
+                clearable
+                filterable
+                multiple
+                maxTagCount={1}
+                v-model:value={pptCourseware.subjects}
+                v-slots={{
+                  action: () => (
+                    <>
+                      <NButton
+                        text
+                        style=" --n-width: 100% "
+                        size="small"
+                        onClick={() => chioseAll(subjectList.value)}>
+                        全选
+                      </NButton>
+                    </>
+                  )
+                }}
+              />
+            </NFormItem>
+            <div class={styles.btnItem}>
+              <span class={styles.btnTitle}>
+                公开课件
+                <NTooltip style={{ maxWidth: '200px' }} showArrow={false}>
+                  {{
+                    trigger: () => <i class={styles.iconQuestion}></i>,
+                    default: () => '公开课件后,其它老师可以使用该课件上课'
+                  }}
+                </NTooltip>
+              </span>
+              {!pptCourseware.openFlagEnable ? (
+                <NTooltip style={{ maxWidth: '200px' }} showArrow={false}>
+                  {{
+                    trigger: () => (
+                      <NSwitch
+                        size="large"
+                        v-model:value={pptCourseware.openFlag}
+                        disabled={!pptCourseware.openFlagEnable}
+                      />
+                    ),
+                    default: () =>
+                      '为尊重课件原作者,在“相关课件”中添加的课件不支持公开'
+                  }}
+                </NTooltip>
+              ) : (
+                <NSwitch
+                  size="large"
+                  v-model:value={pptCourseware.openFlag}
+                  disabled={!pptCourseware.openFlagEnable}
+                />
+              )}
+            </div>
+            <NSpace class={styles.updateBtnGroup}>
+              <NButton
+                strong
+                type="default"
+                round
+                onClick={() => {
+                  pptCourseware.pptCoursewareShow = false;
+                }}>
+                取消
+              </NButton>
+              <NButton strong type="primary" round onClick={handlePptConfirm}>
+                确认
+              </NButton>
+            </NSpace>
+          </NForm>
+        </NModal>
       </div>
     );
   }

二進制
src/views/prepare-lessons/images/setup.png


+ 24 - 12
src/views/prepare-lessons/model/courseware-type/index.module.less

@@ -139,18 +139,24 @@
       background: url('../../images/icon-no-work.png') no-repeat center;
       background-size: contain;
     }
-
-    .status {
+    .statusCon{
       position: absolute;
-      top: 7px;
-      left: 7px;
-      background: linear-gradient(226deg, #13BFFF 0%, #1183FF 100%);
-      border-radius: 4px;
-      font-weight: 600;
-      font-size: max(12px, 11Px);
-      color: #FFFFFF;
-      padding: 3px 10px;
+      top: 6px;
+      left: 6px;
       z-index: 9;
+      display: flex;
+      align-items: center;
+      .status {
+        background: rgba(0, 0, 0, 0.5);
+        border-radius: 4px;
+        font-weight: 600;
+        font-size: max(12px, 11Px);
+        color: #FFFFFF;
+        padding: 2px 10px;
+        & + .status {
+          margin-left: 8px;
+        }
+      }
     }
 
     :global {
@@ -420,7 +426,8 @@
   //   // }
   // }
   .iconEdit,
-  .iconDelete {
+  .iconDelete,
+  .iconSetup {
     display: inline-block;
     width: 24px;
     height: 24px;
@@ -431,6 +438,11 @@
     background-size: contain;
   }
 
+  .iconSetup {
+    background: url('../../images/setup.png') no-repeat center;
+    background-size: contain;
+  }
+
   .iconDelete {
     background: url('../../images/icon-courseware-delete.png') no-repeat center;
     background-size: contain;
@@ -514,4 +526,4 @@
     }
   }
 
-}
+}

+ 30 - 8
src/views/prepare-lessons/model/courseware-type/index.tsx

@@ -74,8 +74,13 @@ export default defineComponent({
             props.isShowAdd && styles.isShowAdd
           ]}
           onClick={() => emit('click')}>
-          {props.item.openFlag && props.isShowOpenFlag && (
-            <span class={styles.status}>公开</span>
+          {props.isShowOpenFlag && (
+            <div class={styles.statusCon}>
+              <div class={styles.status}>
+                {props.item.coursewareType === 'PPT' ? 'PPT' : '传统课件'}
+              </div>
+              {props.item.openFlag && <div class={styles.status}>公开</div>}
+            </div>
           )}
           <NImage
             objectFit="cover"
@@ -158,12 +163,29 @@ export default defineComponent({
                     trigger: () => <div class={[styles.menu]}></div>,
                     default: () => (
                       <div class={styles.popoverList}>
-                        <div
-                          class={styles.popoverItem}
-                          onClick={() => emit('edit')}>
-                          <i class={styles.iconEdit}></i>
-                          <span>编辑课件</span>
-                        </div>
+                        {props.item.coursewareType === 'PPT' ? (
+                          <>
+                            <div
+                              class={styles.popoverItem}
+                              onClick={() => emit('edit', 'PPT')}>
+                              <i class={styles.iconEdit}></i>
+                              <span>编辑PPT</span>
+                            </div>
+                            <div
+                              class={styles.popoverItem}
+                              onClick={() => emit('edit')}>
+                              <i class={styles.iconSetup}></i>
+                              <span>课件设置</span>
+                            </div>
+                          </>
+                        ) : (
+                          <div
+                            class={styles.popoverItem}
+                            onClick={() => emit('edit')}>
+                            <i class={styles.iconEdit}></i>
+                            <span>编辑课件</span>
+                          </div>
+                        )}
                         <div
                           class={styles.popoverItem}
                           onClick={() => emit('delete')}>