Forráskód Böngészése

教师点评和教师回复消息

dusenyao 2 éve
szülő
commit
cff248aea9

+ 14 - 14
package-lock.json

@@ -13,7 +13,7 @@
         "awe-dnd": "^0.3.4",
         "axios": "^0.27.2",
         "book-ui": "file:../book-ui-0.3.19.tgz",
-        "core-js": "^3.27.0",
+        "core-js": "^3.27.1",
         "dayjs": "^1.11.7",
         "element-ui": "^2.15.12",
         "gcls-book-question-ui": "file:../gcls-book-question-ui-0.1.0.tgz",
@@ -58,7 +58,7 @@
         "sass": "^1.57.1",
         "sass-loader": "^10.4.1",
         "script-ext-html-webpack-plugin": "^2.1.5",
-        "stylelint": "^14.16.0",
+        "stylelint": "^14.16.1",
         "stylelint-config-prettier": "^9.0.4",
         "stylelint-config-recess-order": "^3.1.0",
         "stylelint-config-recommended-vue": "^1.4.0",
@@ -6956,9 +6956,9 @@
       }
     },
     "node_modules/core-js": {
-      "version": "3.27.0",
-      "resolved": "https://registry.npmmirror.com/core-js/-/core-js-3.27.0.tgz",
-      "integrity": "sha512-wY6cKosevs430KRkHUIsvepDXHGjlXOZO3hYXNyqpD6JvB0X28aXyv0t1Y1vZMwE7SoKmtfa6IASHCPN52FwBQ==",
+      "version": "3.27.1",
+      "resolved": "https://registry.npmmirror.com/core-js/-/core-js-3.27.1.tgz",
+      "integrity": "sha512-GutwJLBChfGCpwwhbYoqfv03LAfmiz7e7D/BNxzeMxwQf10GRSzqiOjx7AmtEk+heiD/JWmBuyBPgFtx0Sg1ww==",
       "hasInstallScript": true
     },
     "node_modules/core-js-compat": {
@@ -20091,9 +20091,9 @@
       }
     },
     "node_modules/stylelint": {
-      "version": "14.16.0",
-      "resolved": "https://registry.npmmirror.com/stylelint/-/stylelint-14.16.0.tgz",
-      "integrity": "sha512-X6uTi9DcxjzLV8ZUAjit1vsRtSwcls0nl07c9rqOPzvpA8IvTX/xWEkBRowS0ffevRrqkHa/ThDEu86u73FQDg==",
+      "version": "14.16.1",
+      "resolved": "https://registry.npmmirror.com/stylelint/-/stylelint-14.16.1.tgz",
+      "integrity": "sha512-ErlzR/T3hhbV+a925/gbfc3f3Fep9/bnspMiJPorfGEmcBbXdS+oo6LrVtoUZ/w9fqD6o6k7PtUlCOsCRdjX/A==",
       "dev": true,
       "dependencies": {
         "@csstools/selector-specificity": "^2.0.2",
@@ -28494,9 +28494,9 @@
       }
     },
     "core-js": {
-      "version": "3.27.0",
-      "resolved": "https://registry.npmmirror.com/core-js/-/core-js-3.27.0.tgz",
-      "integrity": "sha512-wY6cKosevs430KRkHUIsvepDXHGjlXOZO3hYXNyqpD6JvB0X28aXyv0t1Y1vZMwE7SoKmtfa6IASHCPN52FwBQ=="
+      "version": "3.27.1",
+      "resolved": "https://registry.npmmirror.com/core-js/-/core-js-3.27.1.tgz",
+      "integrity": "sha512-GutwJLBChfGCpwwhbYoqfv03LAfmiz7e7D/BNxzeMxwQf10GRSzqiOjx7AmtEk+heiD/JWmBuyBPgFtx0Sg1ww=="
     },
     "core-js-compat": {
       "version": "3.24.0",
@@ -37651,9 +37651,9 @@
       }
     },
     "stylelint": {
-      "version": "14.16.0",
-      "resolved": "https://registry.npmmirror.com/stylelint/-/stylelint-14.16.0.tgz",
-      "integrity": "sha512-X6uTi9DcxjzLV8ZUAjit1vsRtSwcls0nl07c9rqOPzvpA8IvTX/xWEkBRowS0ffevRrqkHa/ThDEu86u73FQDg==",
+      "version": "14.16.1",
+      "resolved": "https://registry.npmmirror.com/stylelint/-/stylelint-14.16.1.tgz",
+      "integrity": "sha512-ErlzR/T3hhbV+a925/gbfc3f3Fep9/bnspMiJPorfGEmcBbXdS+oo6LrVtoUZ/w9fqD6o6k7PtUlCOsCRdjX/A==",
       "dev": true,
       "requires": {
         "@csstools/selector-specificity": "^2.0.2",

+ 2 - 2
package.json

@@ -18,7 +18,7 @@
     "awe-dnd": "^0.3.4",
     "axios": "^0.27.2",
     "book-ui": "file:../book-ui-0.3.19.tgz",
-    "core-js": "^3.27.0",
+    "core-js": "^3.27.1",
     "dayjs": "^1.11.7",
     "element-ui": "^2.15.12",
     "gcls-book-question-ui": "file:../gcls-book-question-ui-0.1.0.tgz",
@@ -63,7 +63,7 @@
     "sass": "^1.57.1",
     "sass-loader": "^10.4.1",
     "script-ext-html-webpack-plugin": "^2.1.5",
-    "stylelint": "^14.16.0",
+    "stylelint": "^14.16.1",
     "stylelint-config-prettier": "^9.0.4",
     "stylelint-config-recess-order": "^3.1.0",
     "stylelint-config-recommended-vue": "^1.4.0",

+ 13 - 0
src/api/course.js

@@ -732,3 +732,16 @@ export function DeleteTask_MessageReply(data) {
     data
   });
 }
+
+/**
+ * 提交任务消息回复(教师回复学员)
+ * @param {Object} data
+ */
+export function SubmitTask_MessageReply_TeacherReplyStudent(data) {
+  return request({
+    method: 'post',
+    url: process.env.VUE_APP_LearnWebSI,
+    params: getRequestParams('teaching-task_manager-SubmitTask_MessageReply_TeacherReplyStudent'),
+    data
+  });
+}

+ 5 - 3
src/views/new_task_view/components/common/FileView.vue

@@ -53,12 +53,14 @@
           class="file-item"
         >
           <div class="file-item-image">
-            <div class="file-operation student">
+            <div :class="['file-operation', { student: !isTeacher }]">
               <svg-icon icon-class="course-preview" @click="showFileVisible(file_name, file_id)" />
               <span class="vertical-bar"></span>
               <svg-icon icon-class="course-download" @click="downloadFileUrl(file_id, file_name)" />
-              <span class="vertical-bar"></span>
-              <svg-icon icon-class="delete-current" @click="deleteHomework(file_id)" />
+              <template v-if="!isTeacher">
+                <span class="vertical-bar"></span>
+                <svg-icon icon-class="delete-current" @click="deleteHomework(file_id)" />
+              </template>
             </div>
             <img :src="getFileImage(getFileType(file_name))" />
           </div>

+ 6 - 3
src/views/new_task_view/components/common/MessageView.vue

@@ -5,7 +5,7 @@
       <template v-else>
         <ul class="message-list">
           <li
-            v-for="({ message_type, text, file_id, is_student_reply }, i) in messageList"
+            v-for="({ message_type, text, file_id, is_reply, is_student_reply }, i) in messageList"
             :key="i"
             :class="[
               'message-list-item',
@@ -40,7 +40,8 @@
             </template>
             <svg-icon
               v-if="
-                (is_student_reply === 'true' && !isTeacher) || (is_student_reply === 'false' && isTeacher)
+                is_reply === 'true' &&
+                ((is_student_reply === 'true' && !isTeacher) || (is_student_reply === 'false' && isTeacher))
                   ? true
                   : false
               "
@@ -122,6 +123,7 @@ function sendMessage() {
   props.addMessageItem(
     Object.assign({}, messageItem[0], {
       text: textMsg.value,
+      is_reply: 'true',
       is_student_reply: isTeacher ? 'false' : 'true'
     })
   );
@@ -141,6 +143,7 @@ watch(blob, (newVal) => {
       props.addMessageItem(
         Object.assign({}, messageItem[1], {
           file_id: file_info_list[0].file_id,
+          is_reply: 'true',
           is_student_reply: isTeacher ? 'false' : 'true'
         })
       );
@@ -152,7 +155,7 @@ watch(blob, (newVal) => {
 const { changVisible_video } = inject('visible_video');
 
 function getVideoData(data) {
-  props.addMessageItem({ ...data, is_student_reply: isTeacher ? 'false' : 'true' });
+  props.addMessageItem({ ...data, is_student_reply: isTeacher ? 'false' : 'true', is_reply: 'true' });
 }
 </script>
 

+ 0 - 16
src/views/new_task_view/components/student/homework.js

@@ -1,16 +0,0 @@
-import { inject } from 'vue';
-
-export function useHomework() {
-  /**
-   * 任务添加到作业列表
-   * @param {Array} homeworkList
-   * @param {Array} file
-   */
-  function addHomework(homeworkList, file) {
-    homeworkList.push(file);
-  }
-
-  return {
-    addHomework
-  };
-}

+ 36 - 8
src/views/new_task_view/components/student/index.vue

@@ -12,7 +12,8 @@
           accessory_list,
           homework_list,
           message_list,
-          child_task_list
+          child_task_list,
+          message_list_task_remark
         },
         taskIndex
       ) in taskList"
@@ -50,8 +51,8 @@
           <MessageView
             v-if="[taskClassify[3].teaching_type].includes(teaching_type)"
             :message-list="message_list"
-            :add-message-item="curry(addMessageItem)(taskIndex)"
-            :delete-message-item="curry(deleteMessageItem)(taskIndex)"
+            :add-message-item="curry(addMessageItem)(taskIndex)(false)"
+            :delete-message-item="curry(deleteMessageItem)(taskIndex)(false)"
           />
         </div>
         <!-- 子任务 -->
@@ -71,6 +72,17 @@
           />
         </template>
       </div>
+      <!-- 任务点评 -->
+      <template v-if="message_list_task_remark.length > 0">
+        <div class="task-remark">
+          <div class="task-remark-title">教师点评</div>
+          <MessageView
+            :message-list="message_list_task_remark"
+            :add-message-item="curry(addMessageItem)(taskIndex)(true)"
+            :delete-message-item="curry(deleteMessageItem)(taskIndex)(true)"
+          />
+        </div>
+      </template>
     </div>
     <ShowFile :visible="visible" :file-name="curFileName" :file-id="curFileId" @close="dialogShowFileClose" />
   </div>
@@ -243,19 +255,20 @@ function addSubtaskAnswer(index, subIndex, infoIndex, courseIndex, exam_answer)
 /**
  * 添加消息列表项
  * @param {Number} index 任务索引
+ * @param {Number} is_task_remark 是否是任务点评
  * @param {Object} data 消息数据
  */
-function addMessageItem(index, data) {
+function addMessageItem(index, is_task_remark, data) {
   SubmitTask_MessageReply_Student({
     task_id: taskList.value[index].id,
-    is_task_remark: false,
+    is_task_remark,
     info_block_id: '',
     text: data.text,
     file_id: data.file_id,
     message_type: data.message_type
   }).then(({ status, id }) => {
     if (status === 1) {
-      taskList.value[index].message_list.push({ id, ...data });
+      taskList.value[index][is_task_remark ? 'message_list_task_remark' : 'message_list'].push({ id, ...data });
     }
   });
 }
@@ -286,15 +299,16 @@ function addSubtaskMessageItem(index, subIndex, infoIndex, data) {
 /**
  * 删除消息列表项
  * @param {Number} index 任务索引
+ * @param {Boolean} is_task_remark 是否是任务点评
  * @param {Number} i 消息索引
  */
-function deleteMessageItem(index, i) {
+function deleteMessageItem(index, is_task_remark, i) {
   MessageBox.confirm('您确定要删除该消息吗?', '提示', {
     confirmButtonText: '确定',
     cancelButtonText: '取消',
     type: 'warning'
   }).then(() => {
-    const messageList = taskList.value[index].message_list;
+    const messageList = taskList.value[index][is_task_remark ? 'message_list_task_remark' : 'message_list'];
     DeleteTask_MessageReply({
       task_id: taskList.value[index].id,
       message_id: messageList[i].id
@@ -395,5 +409,19 @@ function deleteSubtaskMessageItem(index, subIndex, infoIndex, i) {
       font-weight: bold;
     }
   }
+
+  .task-remark {
+    padding: 24px;
+    margin-top: 24px;
+    background-color: #fff;
+    border: 1px solid rgba(0, 0, 0, 8%);
+    border-radius: 8px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 8%);
+
+    &-title {
+      margin-bottom: 8px;
+      font-weight: bold;
+    }
+  }
 }
 </style>

+ 183 - 2
src/views/new_task_view/components/teacher/index.vue

@@ -12,7 +12,9 @@
           accessory_list,
           homework_list,
           message_list,
-          child_task_list
+          child_task_list,
+          message_list_task_remark,
+          isRemark
         },
         taskIndex
       ) in taskList"
@@ -37,7 +39,12 @@
             :accessory-list="accessory_list"
             :homework-list="homework_list"
           />
-          <MessageView v-if="[taskClassify[3].teaching_type].includes(teaching_type)" :message-list="message_list" />
+          <MessageView
+            v-if="[taskClassify[3].teaching_type].includes(teaching_type)"
+            :message-list="message_list"
+            :add-message-item="curry(submitTaskMessageReplayTeacher)(taskIndex)(false)"
+            :delete-message-item="curry(deleteMessageItem)(taskIndex)(false)"
+          />
         </div>
         <!-- 子任务 -->
         <template v-if="child_task_list.length > 0">
@@ -48,9 +55,30 @@
             :key="`subtask-${i}`"
             :class="[`${taskType}-${taskIndex}-${i}`]"
             :subtask-data="data"
+            :add-message-item="curry(submitSubtaskMessageReplayTeacher)(taskIndex)(i)"
+            :delete-message-item="curry(deleteSubtaskMessageItem)(taskIndex)(i)"
           />
         </template>
       </div>
+      <!-- 任务点评 -->
+      <template v-if="isRemark || message_list_task_remark.length > 0">
+        <div class="task-remark">
+          <div class="task-remark-title">教师点评</div>
+          <MessageView
+            :message-list="message_list_task_remark"
+            :add-message-item="curry(submitTaskMessageReplayTeacher)(taskIndex)(true)"
+            :delete-message-item="curry(deleteMessageItem)(taskIndex)(true)"
+          />
+        </div>
+      </template>
+      <template v-else>
+        <div class="add-remark">
+          <div class="add-remark-button" @click="addRemark(taskIndex)">
+            <svg-icon icon-class="plus" class-name="plus" />
+            <span>进行点评</span>
+          </div>
+        </div>
+      </template>
     </div>
     <ShowFile :visible="visible" :file-name="curFileName" :file-id="curFileId" @close="dialogShowFileClose" />
   </div>
@@ -67,6 +95,9 @@ import { inject } from 'vue';
 import { useShowFile } from '@/common/show_file/index';
 import { previewDateTransform } from '@/utils/course';
 import { taskClassify } from '@/views/teacher/create_course/step_three/components/data/constant';
+import { curry } from '@/utils/common';
+import { SubmitTask_MessageReply_TeacherReplyStudent, DeleteTask_MessageReply } from '@/api/course';
+import { MessageBox } from 'element-ui';
 
 import ShowFile from '@/common/show_file/index.vue';
 import FileView from '../common/FileView.vue';
@@ -74,10 +105,124 @@ import CoursewareView from '@/components/course/CoursewareView.vue';
 import MessageView from '../common/MessageView.vue';
 import SubtaskItem from '../common/SubtaskItem.vue';
 
+const props = defineProps({
+  curStudentId: {
+    type: String,
+    required: true
+  }
+});
+
 let { visible, curFileId, curFileName, dialogShowFileClose } = useShowFile();
 
 let taskList = inject('taskList');
 let taskType = inject('taskType');
+
+/**
+ * 提交任务消息回复(教师回复学员)
+ * @param {Number} index 任务索引
+ * @param {Boolean} is_task_remark 是否是任务点评
+ * @param {Object} data 回复数据
+ */
+function submitTaskMessageReplayTeacher(index, is_task_remark, data) {
+  SubmitTask_MessageReply_TeacherReplyStudent({
+    student_id: props.curStudentId,
+    task_id: taskList.value[index].id,
+    is_task_remark,
+    info_block_id: '',
+    text: data.text,
+    file_id: data.file_id,
+    message_type: data.message_type
+  }).then(({ status, id }) => {
+    if (status === 1) {
+      taskList.value[index][is_task_remark ? 'message_list_task_remark' : 'message_list'].push({ id, ...data });
+    }
+  });
+}
+
+/**
+ * 提交子任务消息回复(教师回复学员)
+ * @param {Number} index
+ * @param {Number} subIndex
+ * @param {Number} infoIndex
+ * @param {Object} data
+ */
+function submitSubtaskMessageReplayTeacher(index, subIndex, infoIndex, data) {
+  const infoBlockItem = taskList.value[index].child_task_list[subIndex].info_block_list[infoIndex];
+  SubmitTask_MessageReply_TeacherReplyStudent({
+    student_id: props.curStudentId,
+    task_id: taskList.value[index].id,
+    is_task_remark: false,
+    info_block_id: infoBlockItem.id,
+    text: data.text,
+    file_id: data.file_id,
+    message_type: data.message_type
+  }).then(({ status, id }) => {
+    if (status === 1) {
+      infoBlockItem.message_list.push({ id, ...data });
+    }
+  });
+}
+
+/**
+ * 删除消息列表项
+ * @param {Number} index 任务索引
+ * @param {Boolean} is_task_remark 是否是任务点评
+ * @param {Number} i 消息索引
+ */
+function deleteMessageItem(index, is_task_remark, i) {
+  MessageBox.confirm('您确定要删除该消息吗?', '提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning'
+  }).then(() => {
+    const messageList = taskList.value[index][is_task_remark ? 'message_list_task_remark' : 'message_list'];
+    DeleteTask_MessageReply({
+      task_id: taskList.value[index].id,
+      message_id: messageList[i].id,
+      is_teacher_reply_student: true,
+      student_id: props.curStudentId
+    }).then(({ status }) => {
+      if (status === 1) {
+        messageList.splice(i, 1);
+      }
+    });
+  });
+}
+
+/**
+ * 删除子任务消息列表项
+ * @param {Number} index 任务索引
+ * @param {Number} subIndex 子任务索引
+ * @param {Number} infoIndex 信息块索引
+ * @param {Number} i 消息索引
+ */
+function deleteSubtaskMessageItem(index, subIndex, infoIndex, i) {
+  MessageBox.confirm('您确定要删除该消息吗?', '提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning'
+  }).then(() => {
+    const subtaskMessageList = taskList.value[index].child_task_list[subIndex].info_block_list[infoIndex].message_list;
+    DeleteTask_MessageReply({
+      task_id: taskList.value[index].id,
+      message_id: subtaskMessageList[i].id,
+      is_teacher_reply_student: true,
+      student_id: props.curStudentId
+    }).then(({ status }) => {
+      if (status === 1) {
+        subtaskMessageList.splice(i, 1);
+      }
+    });
+  });
+}
+
+/**
+ * 添加点评
+ * @param {Number} taskIndex
+ */
+function addRemark(taskIndex) {
+  taskList.value[taskIndex].isRemark = true;
+}
 </script>
 
 <style lang="scss" scoped>
@@ -143,5 +288,41 @@ let taskType = inject('taskType');
       font-weight: bold;
     }
   }
+
+  .task-remark {
+    padding: 24px;
+    margin-top: 24px;
+    background-color: #fff;
+    border: 1px solid rgba(0, 0, 0, 8%);
+    border-radius: 8px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 8%);
+
+    &-title {
+      margin-bottom: 8px;
+      font-weight: bold;
+    }
+  }
+
+  .add-remark {
+    display: flex;
+    justify-content: center;
+    margin-top: 24px;
+
+    &-button {
+      padding: 4px;
+      font-size: 14px;
+      color: #fff;
+      cursor: pointer;
+      background-color: #5498ff;
+      border-radius: 4px;
+
+      .plus {
+        width: 24px;
+        height: 24px;
+        margin-right: 4px;
+        vertical-align: -7px;
+      }
+    }
+  }
 }
 </style>

+ 3 - 0
src/views/new_task_view/index.js

@@ -13,6 +13,9 @@ function convertDataFormatTaskList(list) {
   list.forEach((item) => {
     // 学生列表转换为学生id列表
     item.custom_student_id_list = item.custom_student_list.map(({ student_id }) => student_id);
+
+    // 是否显示任务点评
+    item.isRemark = false;
   });
   return list;
 }

+ 4 - 1
src/views/new_task_view/index.vue

@@ -28,7 +28,7 @@
         </span>
         <div class="task-view-main-container" :style="{ transform: `scale(${scale})` }">
           <TaskExplain v-if="curTaskType === TASK_EXPLAIN" />
-          <TeacherView v-else-if="isTeacher" />
+          <TeacherView v-else-if="isTeacher" :cur-student-id="curStudentId" />
           <StudentView v-else />
         </div>
       </main>
@@ -62,6 +62,7 @@ import { SubmitTaskHomework_Student } from '@/api/course';
 import { videoRecording } from '@/components/course/common/recording.js';
 import { useOtherPausePlay } from '@/components/course/common/play';
 import { Message } from 'element-ui';
+import { useRouter } from 'vue-router/composables';
 
 import StudentView from './components/student/index.vue';
 import TeacherView from './components/teacher/index.vue';
@@ -85,7 +86,9 @@ const { changeScale } = useScale();
 const { visible_video, sendVideo } = videoRecording();
 useOtherPausePlay();
 
+const router = useRouter();
 function saveCSItem() {
+  router.push('/main');
   // isTeacher ? teacherSubmit() : studentSubmit();
 }