Browse Source

修改上课

lex 1 year ago
parent
commit
34d68bcd12

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

@@ -401,4 +401,13 @@
       background: #f5f6fa;
     }
   }
+}
+
+.workContainer {
+  padding: 20px 40px 40px;
+
+  h2 {
+    font-size: 26px;
+    text-align: center;
+  }
 }

+ 31 - 4
src/views/attend-class/index.tsx

@@ -72,9 +72,10 @@ export default defineComponent({
     });
 
     const data = reactive({
-      type: '' as any, // 预览类型
+      type: '' as '' | 'preview' | 'class', // 预览类型
       subjectId: '' as any, // 声部编号
       detailId: '' as any, // 编号 - 章节编号
+      classGroupId: '' as any, // 上课时需要 班级编号
       // detail: null,
       knowledgePointList: [] as any,
       itemList: [] as any,
@@ -84,7 +85,8 @@ export default defineComponent({
       videoRefs: {} as any[],
       audioRefs: {} as any[],
       modelAttendStatus: false, // 布置作业提示弹窗
-      modelTrainStatus: false // 训练设置
+      modelTrainStatus: false, // 训练设置
+      homeworkStatus: true // 布置作业完成时
     });
     const activeData = reactive({
       // isAutoPlay: false, // 是否自动播放
@@ -147,9 +149,10 @@ export default defineComponent({
 
     onMounted(() => {
       const query = route.query;
-      data.type = query.type;
+      data.type = query.type as any;
       data.subjectId = query.subjectId;
       data.detailId = query.detailId;
+      data.classGroupId = query.classGroupId;
       window.addEventListener('message', iframeHandle);
       getDetail();
     });
@@ -788,8 +791,32 @@ export default defineComponent({
           preset="card"
           class={[styles.attendClassModal, styles.trainClassModal]}
           title={'训练设置'}>
-          <TrainSettings onClose={() => (data.modelTrainStatus = false)} />
+          <TrainSettings
+            detailId={data.detailId}
+            subjectId={data.subjectId}
+            classGroupId={data.classGroupId}
+            onClose={() => (data.modelTrainStatus = false)}
+            onConfirm={() => {
+              // 布置完作业之后直接关闭
+              setTimeout(() => {
+                window.close();
+              }, 1000);
+            }}
+          />
         </NModal>
+
+        {/* <NModal
+          v-model:show={data.homeworkStatus}
+          preset="card"
+          class={[styles.attendClassModal]}
+          closable={false}
+          maskClosable={false}
+          title={' '}>
+          <div class={styles.workContainer}>
+            <h2>作业布置成功</h2>
+            <p>倒</p>
+          </div>
+        </NModal> */}
       </div>
     );
   }

+ 20 - 0
src/views/attend-class/model/train-settings/index.module.less

@@ -60,12 +60,32 @@
     max-height: 50vh;
     padding: 0 40px;
 
+    .listSection {
+      min-height: 50vh;
+    }
+
+    .emptySection {
+      display: flex;
+      align-items: center;
+    }
+
     :global {
       .n-scrollbar-content {
         display: flex;
         gap: 24px;
         flex-wrap: wrap;
       }
+
+      .n-spin-container {
+        width: 100%;
+      }
+    }
+
+    .list {
+      display: flex;
+      flex-flow: row wrap;
+      justify-content: flex-start;
+      gap: 20px;
     }
   }
 }

+ 247 - 37
src/views/attend-class/model/train-settings/index.tsx

@@ -1,45 +1,183 @@
-import { defineComponent, reactive } from 'vue';
+import { defineComponent, onMounted, reactive } from 'vue';
 import styles from './index.module.less';
 import {
   NButton,
   NDatePicker,
-  NEmpty,
   NModal,
   NScrollbar,
-  NSpace
+  NSpace,
+  NSpin,
+  useMessage
 } from 'naive-ui';
 import TrainType from '@/views/attend-class/model/train-type';
 import TrainUpdate from '../train-update';
 import SelectMusic from '@/views/prepare-lessons/model/select-music';
+import {
+  lessonPreTrainingPage,
+  lessonTrainingAdd
+} from '/src/views/prepare-lessons/api';
+import { evaluateDifficult } from '/src/utils/contants';
+import dayjs from 'dayjs';
+import TheEmpty from '/src/components/TheEmpty';
+import requestOrigin from 'umi-request';
 
 export default defineComponent({
   name: 'train-settings',
-  emits: ['close'],
+  props: {
+    /** 章节编号 */
+    detailId: {
+      type: String,
+      default: ''
+    },
+    /** 声部编号 */
+    subjectId: {
+      type: String,
+      default: ''
+    },
+    /** 班级编号 */
+    classGroupId: {
+      type: String,
+      default: ''
+    }
+  },
+  emits: ['close', 'confirm'],
   setup(props, { emit }) {
+    const message = useMessage();
     const trainForms = reactive({
+      type: 'add' as 'add' | 'update',
+      btnLoading: false,
+      loadingStatus: false,
       editStatus: false,
-      selectMusicStatus: false
+      editItem: {} as any,
+      selectMusicStatus: false,
+      trainList: [] as any,
+      currentTime: dayjs(dayjs().format('YYYY-MM-DD')).valueOf(),
+      expireDate: dayjs().add(7, 'day').format('YYYY-MM-DD') as any // 默认7天
     });
-    const list = [
-      {
-        id: 22078,
-        src: 'https://cloud-coach.ks3-cn-beijing.ksyuncs.com/music-sheet-fixed/1675770786664-1.png',
-        type: 'practice',
-        name: '彩虹岛',
-        typeList: ['1-12小节', '速度90', '20分钟']
-      },
-      {
-        id: 22048,
-        src: 'https://cloud-coach.ks3-cn-beijing.ksyuncs.com/music-sheet-fixed/1675839970286-1.png',
-        type: 'evaluation',
-        name: '彩云追月',
-        typeList: ['入门级', '全部小节', '速度90', '20分钟']
+    const getList = async () => {
+      trainForms.loadingStatus = true;
+      try {
+        // 判断是否有选择对应的课件
+        const { data } = await lessonPreTrainingPage({
+          coursewareKnowledgeDetailId: props.detailId,
+          subjectId: props.subjectId,
+          pag: 1,
+          rows: 99
+        });
+        const tempRows = data.rows || [];
+        const temp: any = [];
+
+        tempRows.forEach((row: any) => {
+          const tList = typeFormat(row.trainingType, row.trainingConfigJson);
+          temp.push({
+            typeList: tList || [],
+            ...row
+          });
+        });
+        trainForms.trainList = temp || [];
+      } catch {
+        //
+      }
+      trainForms.loadingStatus = false;
+    };
+
+    const typeFormat = (trainingType: string, configJson: any) => {
+      let tList: string[] = [];
+
+      if (trainingType === 'EVALUATION') {
+        tList = [
+          `${evaluateDifficult[configJson.evaluateDifficult]}`,
+          '全部小节',
+          `速度${configJson.evaluateSpeed}`,
+          `${configJson.trainingTimes}分钟`
+        ];
+      } else {
+        tList = [
+          `${configJson.practiceChapterBegin}-${configJson.practiceChapterEnd}小节`,
+          `速度${configJson.practiceSpeed}`,
+          `${configJson.trainingTimes}分钟`
+        ];
+      }
+      return tList;
+    };
+
+    const onAdd = async (item: any) => {
+      let xmlStatus = 'init';
+      // 第一个声部小节
+      let firstMeasures: any = null;
+      try {
+        // 获取文件
+        const res = await requestOrigin.get(item.xmlFileUrl, {
+          mode: 'cors'
+        });
+        const xmlParse = new DOMParser().parseFromString(res, 'text/xml');
+        const parts = xmlParse.getElementsByTagName('part');
+        firstMeasures = parts[0]?.getElementsByTagName('measure');
+        xmlStatus = 'success';
+      } catch (error) {
+        xmlStatus = 'error';
       }
-    ];
+
+      // 判断读取小节数
+      if (xmlStatus == 'success') {
+        item.practiceChapterMax = firstMeasures.length;
+      } else {
+        item.practiceChapterMax = 0;
+      }
+      item.coursewareKnowledgeDetailId = props.detailId;
+      item.subjectId = props.subjectId;
+
+      trainForms.editItem = item;
+      trainForms.editStatus = true;
+    };
+
+    const onSubmit = async () => {
+      // 训练内容不能为空
+      if (trainForms.trainList.length <= 0) {
+        message.error('训练内容不能为空');
+        return;
+      }
+      trainForms.btnLoading = true;
+      try {
+        const trainList = trainForms.trainList || [];
+        const details: any[] = [];
+        trainList.forEach((item: any) => {
+          details.push({
+            trainingType: item.trainingType,
+            musicId: item.musicId,
+            trainingConfigJsonObject: item.trainingConfigJson
+          });
+        });
+        const params = {
+          lessonTrainingDetails: details,
+          expireDate: trainForms.expireDate + ' 23:59:59',
+          classGroupId: props.classGroupId
+        };
+        await lessonTrainingAdd(params);
+        message.success('布置成功');
+
+        emit('close');
+        emit('confirm');
+      } catch {
+        //
+      }
+      trainForms.btnLoading = false;
+    };
+
+    onMounted(() => {
+      // 判断是否有数据
+      if (props.detailId && props.subjectId) {
+        getList();
+      }
+    });
     return () => (
       <div class={styles.trainSettings}>
         <div class={styles.searchGroup}>
-          <NButton onClick={() => (trainForms.selectMusicStatus = true)}>
+          <NButton
+            onClick={() => {
+              trainForms.selectMusicStatus = true;
+              trainForms.type = 'add';
+            }}>
             添加训练
           </NButton>
 
@@ -47,30 +185,74 @@ export default defineComponent({
             <label>截止时间:</label>
             <NDatePicker
               style={{ width: '200px' }}
-              value-format="yyyy-MM-dd"
+              placeholder="请选择截止日期"
+              v-model:formatted-value={trainForms.expireDate}
               type="date"
               clearable
-              placeholder="请选择截止日期"
+              valueFormat="yyyy-MM-dd"
+              isDateDisabled={(ts: number) => {
+                return ts < trainForms.currentTime;
+              }}
             />
           </div>
         </div>
         <NScrollbar class={styles.trainList}>
-          {/* <NEmpty description="暂无训练" /> */}
-          {list.map((item: any) => (
-            <TrainType
-              item={item}
-              onEdit={() => {
-                console.log('edit');
-                trainForms.editStatus = true;
-              }}
-            />
-          ))}
+          <NSpin show={trainForms.loadingStatus}>
+            <div
+              class={[
+                styles.listSection,
+                !trainForms.loadingStatus && trainForms.trainList.length <= 0
+                  ? styles.emptySection
+                  : ''
+              ]}>
+              {trainForms.trainList.length > 0 && (
+                <div class={styles.list}>
+                  {trainForms.trainList.map((item: any) => (
+                    <TrainType
+                      item={item}
+                      type="homework"
+                      onEdit={(child: any) => {
+                        const { trainingConfigJson, id, musicId, ...res } =
+                          child;
+                        trainForms.editItem = {
+                          ...res,
+                          id: musicId,
+                          trainId: id,
+                          ...trainingConfigJson
+                        };
+                        console.log(trainForms.editItem);
+                        trainForms.type = 'update';
+                        trainForms.editStatus = true;
+                      }}
+                      onDelete={() => {
+                        // 删除
+                        const index = trainForms.trainList.findIndex(
+                          (c: any) => c.id === item.id
+                        );
+                        trainForms.trainList.splice(index, 1);
+                      }}
+                    />
+                  ))}
+                </div>
+              )}
+
+              {!trainForms.loadingStatus &&
+                trainForms.trainList.length <= 0 && (
+                  <TheEmpty description="暂无训练" />
+                )}
+            </div>
+          </NSpin>
         </NScrollbar>
         <NSpace class={styles.trainBtnGroup}>
           <NButton strong type="default" round onClick={() => emit('close')}>
             取消布置
           </NButton>
-          <NButton strong type="primary" round>
+          <NButton
+            strong
+            type="primary"
+            round
+            disabled={trainForms.trainList.length <= 0 ? true : false}
+            onClick={onSubmit}>
             立即布置
           </NButton>
         </NSpace>
@@ -80,7 +262,35 @@ export default defineComponent({
           class={['modalTitle background', styles.trainEditModal]}
           preset="card"
           title="训练设置">
-          <TrainUpdate onClose={() => (trainForms.editStatus = false)} />
+          <TrainUpdate
+            item={trainForms.editItem}
+            type="homework"
+            onClose={() => (trainForms.editStatus = false)}
+            onConfirm={(item: any) => {
+              const tList = typeFormat(
+                item.trainingType,
+                item.trainingConfigJson
+              );
+              // 更新
+              if (trainForms.type === 'update') {
+                trainForms.trainList.forEach((train: any) => {
+                  if (train.id === item.id) {
+                    train.trainingType = item.trainingType;
+                    train.typeList = tList;
+                  }
+                });
+              } else {
+                //
+                trainForms.trainList.push({
+                  ...item,
+                  id: +new Date(),
+                  musicName: trainForms.editItem.title,
+                  typeList: tList
+                });
+              }
+              trainForms.editItem = {};
+            }}
+          />
         </NModal>
 
         <NModal
@@ -89,9 +299,9 @@ export default defineComponent({
           preset="card"
           title={'选择曲目'}>
           <SelectMusic
-            onSelect={() => {
+            onAdd={(item: any) => {
               trainForms.selectMusicStatus = false;
-              trainForms.editStatus = true;
+              onAdd(item);
             }}
           />
         </NModal>

+ 64 - 15
src/views/attend-class/model/train-update/index.tsx

@@ -1,10 +1,9 @@
-import { defineComponent, nextTick, onMounted, reactive, ref } from 'vue';
+import { PropType, defineComponent, onMounted, reactive, ref } from 'vue';
 import styles from './index.module.less';
 import {
   NButton,
   NForm,
   NFormItem,
-  NInput,
   NInputGroup,
   NInputGroupLabel,
   NInputNumber,
@@ -23,6 +22,11 @@ export default defineComponent({
     item: {
       type: Object,
       default: () => ({})
+    },
+    /** 操作类型 */
+    type: {
+      type: String as PropType<'train' | 'homework'>,
+      default: 'train'
     }
   },
   emits: ['close', 'confirm'],
@@ -77,16 +81,18 @@ export default defineComponent({
           }
           configJson.practiceChapterMax = forms.baseMaxScore;
           params.trainingConfigJson = configJson;
-          if (forms.id) {
-            await lessonPreTrainingUpdate(params);
-            message.success('修改成功');
-          } else {
-            await lessonPreTrainingAdd(params);
-            message.success('添加成功');
+          if (props.type === 'train') {
+            if (forms.id) {
+              await lessonPreTrainingUpdate(params);
+              message.success('修改成功');
+            } else {
+              await lessonPreTrainingAdd(params);
+              message.success('添加成功');
+            }
           }
 
           emit('close');
-          emit('confirm');
+          emit('confirm', params);
         } catch {
           //
         }
@@ -101,6 +107,7 @@ export default defineComponent({
         forms.minScore = item.practiceChapterBegin;
         forms.maxScore = item.practiceChapterEnd;
         forms.practiceSpeed = item.practiceSpeed;
+        forms.type = item.trainingType;
         if (item.trainingType === 'PRACTICE') {
           forms.practiceTimes = item.trainingTimes;
         } else {
@@ -156,7 +163,14 @@ export default defineComponent({
                 <NFormItem
                   label="练习小节"
                   path="minScore"
-                  rule={[{ required: true, message: '请输入最小练习小节' }]}>
+                  rule={[
+                    {
+                      required: true,
+                      message: '请输入最小练习小节',
+                      trigger: ['blur', 'change'],
+                      type: 'number'
+                    }
+                  ]}>
                   <NInputNumber
                     v-model:value={forms.minScore}
                     showButton={false}
@@ -181,7 +195,14 @@ export default defineComponent({
                 </div>
                 <NFormItem
                   path="maxScore"
-                  rule={[{ required: true, message: '请输入最大练习小节' }]}>
+                  rule={[
+                    {
+                      required: true,
+                      message: '请输入最大练习小节',
+                      trigger: ['blur', 'change'],
+                      type: 'number'
+                    }
+                  ]}>
                   <NInputNumber
                     v-model:value={forms.maxScore}
                     showButton={false}
@@ -195,7 +216,14 @@ export default defineComponent({
               <NFormItem
                 label="练习速度"
                 path="practiceSpeed"
-                rule={[{ required: true, message: '请输入练习速度' }]}>
+                rule={[
+                  {
+                    required: true,
+                    message: '请输入练习速度',
+                    trigger: ['blur', 'change'],
+                    type: 'number'
+                  }
+                ]}>
                 <NInputNumber
                   min={60}
                   max={270}
@@ -209,7 +237,14 @@ export default defineComponent({
               <NFormItem
                 label="练习时长"
                 path="practiceTimes"
-                rule={[{ required: true, message: '请输入练习时长' }]}>
+                rule={[
+                  {
+                    required: true,
+                    message: '请输入练习时长',
+                    trigger: ['blur', 'change'],
+                    type: 'number'
+                  }
+                ]}>
                 <NInputGroup>
                   <NInputNumber
                     min={0}
@@ -264,7 +299,14 @@ export default defineComponent({
               <NFormItem
                 label="评测速度"
                 path="evaluationSpeed"
-                rule={[{ required: true, message: '请输入评测速度' }]}>
+                rule={[
+                  {
+                    required: true,
+                    message: '请输入评测速度',
+                    trigger: ['blur', 'change'],
+                    type: 'number'
+                  }
+                ]}>
                 <NInputNumber
                   min={60}
                   max={270}
@@ -278,7 +320,14 @@ export default defineComponent({
               <NFormItem
                 label="合格分数"
                 path="evaluationScore"
-                rule={[{ required: true, message: '请输入合格分数' }]}>
+                rule={[
+                  {
+                    required: true,
+                    message: '请输入合格分数',
+                    trigger: ['blur', 'change'],
+                    type: 'number'
+                  }
+                ]}>
                 <NInputGroup>
                   <NInputNumber
                     min={0}

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

@@ -114,3 +114,11 @@ export const lessonTrainingAdd = (params: any) => {
     data: params
   });
 };
+/**
+ * 备课 - 开始上课
+ */
+export const courseScheduleStart = (params: any) => {
+  return request.post('/edu-app/courseSchedule/start', {
+    data: params
+  });
+};

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

@@ -1,6 +1,6 @@
 import { defineComponent, onMounted, reactive, watch } from 'vue';
 import ResourceSearchGroup from './resource-search-group';
-import { NModal, NScrollbar, NSpin, useDialog, useMessage } from 'naive-ui';
+import { NModal, NScrollbar, NSpin } from 'naive-ui';
 import styles from './index.module.less';
 import CardType from '/src/components/card-type';
 import TheEmpty from '/src/components/TheEmpty';
@@ -13,8 +13,6 @@ export default defineComponent({
   name: 'share-resources',
   setup() {
     const prepareStore = usePrepareStore();
-    const dialog = useDialog();
-    const message = useMessage();
     const state = reactive({
       loading: false,
       finshed: false, // 是否加载完

+ 25 - 8
src/views/prepare-lessons/model/attend-class/index.tsx

@@ -3,9 +3,10 @@ import styles from './index.module.less';
 import { NInput, NScrollbar, NSelect, NSpin, NThing } from 'naive-ui';
 import { useRouter } from 'vue-router';
 import { BOOK_DATA } from '/src/views/natural-resources/model/add-teaching';
-import { classGroupPage } from '../../api';
+import { classGroupPage, courseScheduleStart } from '../../api';
 import { useThrottleFn } from '@vueuse/core';
 import TheEmpty from '/src/components/TheEmpty';
+import { usePrepareStore } from '/src/store/modules/prepareLessons';
 
 const classList: any = [];
 for (let i = 1; i <= 40; i++) {
@@ -16,6 +17,7 @@ export default defineComponent({
   name: 'attend-class',
   emits: ['close'],
   setup(props, { emit }) {
+    const prepareStore = usePrepareStore();
     const router = useRouter();
     const forms = reactive({
       keyword: null,
@@ -24,13 +26,29 @@ export default defineComponent({
     });
     const list = ref([] as any);
     const loading = ref(false);
-    const onAttendClass = (i: any) => {
-      emit('close');
+    // 开始上课
+    const onAttendClass = async (item: any) => {
+      try {
+        await courseScheduleStart({
+          lessonCoursewareKnowledgeDetailId: prepareStore.selectKey,
+          classGroupId: item.id
+        });
+        emit('close');
 
-      const { href } = router.resolve({
-        path: '/attend-class'
-      });
-      window.open(href, +new Date() + '');
+        const { href } = router.resolve({
+          path: '/attend-class',
+          query: {
+            type: 'class',
+            classGroupId: item.id,
+            subjectId: prepareStore.getSubjectId,
+            detailId: prepareStore.getSelectKey,
+            classGroupId: item.id
+          }
+        });
+        window.open(href, +new Date() + '');
+      } catch {
+        //
+      }
     };
 
     const getList = async () => {
@@ -41,7 +59,6 @@ export default defineComponent({
           rows: 99,
           ...forms
         });
-        console.log(data, 'data');
         list.value = data.rows || [];
       } catch {
         //

+ 2 - 2
src/views/prepare-lessons/model/select-music/index.tsx

@@ -1,5 +1,5 @@
 import { NScrollbar, NSpin, NTabPane, NTabs } from 'naive-ui';
-import { defineComponent, onMounted, reactive } from 'vue';
+import { PropType, defineComponent, onMounted, reactive } from 'vue';
 import styles from './index.module.less';
 import CardType from '@/components/card-type';
 import SearchGroup from './search-group';
@@ -10,7 +10,7 @@ import { musicSheetPage } from '../../api';
 
 export default defineComponent({
   name: 'select-music',
-  emits: ['select', 'add'],
+  emits: ['add'],
   setup(props, { emit }) {
     const prepareStore = usePrepareStore();
     const state = reactive({