瀏覽代碼

添加 任务可以单独发布给学员

dusenyao 3 年之前
父節點
當前提交
ee32de0534

+ 21 - 21
package-lock.json

@@ -12,7 +12,7 @@
         "awe-dnd": "^0.3.4",
         "axios": "^0.24.0",
         "book-ui": "file:../book-ui-0.2.4.tgz",
-        "core-js": "^3.19.2",
+        "core-js": "^3.19.3",
         "dayjs": "^1.10.7",
         "element-ui": "^2.15.6",
         "gcls-book-question-ui": "file:../gcls-book-question-ui-0.1.0.tgz",
@@ -45,11 +45,11 @@
         "compression-webpack-plugin": "^6.1.1",
         "eslint": "^7.32.0",
         "eslint-plugin-prettier": "^4.0.0",
-        "eslint-plugin-vue": "^8.1.1",
+        "eslint-plugin-vue": "^8.2.0",
         "html-webpack-plugin": "^5.3.1",
         "postcss": "^8.4.4",
         "postcss-html": "^1.3.0",
-        "prettier": "2.5.0",
+        "prettier": "2.5.1",
         "sass": "^1.44.0",
         "sass-loader": "^10.2.0",
         "script-ext-html-webpack-plugin": "^2.1.5",
@@ -7789,9 +7789,9 @@
       }
     },
     "node_modules/core-js": {
-      "version": "3.19.2",
-      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.19.2.tgz",
-      "integrity": "sha512-ciYCResnLIATSsXuXnIOH4CbdfgV+H1Ltg16hJFN7/v6OxqnFr/IFGeLacaZ+fHLAm0TBbXwNK9/DNBzBUrO/g==",
+      "version": "3.19.3",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.19.3.tgz",
+      "integrity": "sha512-LeLBMgEGSsG7giquSzvgBrTS7V5UL6ks3eQlUSbN8dJStlLFiRzUm5iqsRyzUB8carhfKjkJ2vzKqE6z1Vga9g==",
       "hasInstallScript": true,
       "funding": {
         "type": "opencollective",
@@ -9616,9 +9616,9 @@
       }
     },
     "node_modules/eslint-plugin-vue": {
-      "version": "8.1.1",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.1.1.tgz",
-      "integrity": "sha512-rx64IrlhdfPya6u2V5ukOGiLCTgaCBdMSpczLVqyo8A0l+Vbo+lzvIfEUfAQ2auj+MF6y0TwxLorzdCIzHunnw==",
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.2.0.tgz",
+      "integrity": "sha512-cLIdTuOAMXyHeQ4drYKcZfoyzdwdBpH279X8/N0DgmotEI9yFKb5O/cAgoie/CkQZCH/MOmh0xw/KEfS90zY2A==",
       "dev": true,
       "dependencies": {
         "eslint-utils": "^3.0.0",
@@ -18673,9 +18673,9 @@
       }
     },
     "node_modules/prettier": {
-      "version": "2.5.0",
-      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.0.tgz",
-      "integrity": "sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg==",
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
+      "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
       "dev": true,
       "bin": {
         "prettier": "bin-prettier.js"
@@ -31229,9 +31229,9 @@
       }
     },
     "core-js": {
-      "version": "3.19.2",
-      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.19.2.tgz",
-      "integrity": "sha512-ciYCResnLIATSsXuXnIOH4CbdfgV+H1Ltg16hJFN7/v6OxqnFr/IFGeLacaZ+fHLAm0TBbXwNK9/DNBzBUrO/g=="
+      "version": "3.19.3",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.19.3.tgz",
+      "integrity": "sha512-LeLBMgEGSsG7giquSzvgBrTS7V5UL6ks3eQlUSbN8dJStlLFiRzUm5iqsRyzUB8carhfKjkJ2vzKqE6z1Vga9g=="
     },
     "core-js-compat": {
       "version": "3.19.1",
@@ -32944,9 +32944,9 @@
       }
     },
     "eslint-plugin-vue": {
-      "version": "8.1.1",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.1.1.tgz",
-      "integrity": "sha512-rx64IrlhdfPya6u2V5ukOGiLCTgaCBdMSpczLVqyo8A0l+Vbo+lzvIfEUfAQ2auj+MF6y0TwxLorzdCIzHunnw==",
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.2.0.tgz",
+      "integrity": "sha512-cLIdTuOAMXyHeQ4drYKcZfoyzdwdBpH279X8/N0DgmotEI9yFKb5O/cAgoie/CkQZCH/MOmh0xw/KEfS90zY2A==",
       "dev": true,
       "requires": {
         "eslint-utils": "^3.0.0",
@@ -39833,9 +39833,9 @@
       "dev": true
     },
     "prettier": {
-      "version": "2.5.0",
-      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.0.tgz",
-      "integrity": "sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg==",
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
+      "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
       "dev": true
     },
     "prettier-linter-helpers": {

+ 2 - 2
package.json

@@ -17,7 +17,7 @@
     "awe-dnd": "^0.3.4",
     "axios": "^0.24.0",
     "book-ui": "file:../book-ui-0.2.4.tgz",
-    "core-js": "^3.19.2",
+    "core-js": "^3.19.3",
     "dayjs": "^1.10.7",
     "element-ui": "^2.15.6",
     "gcls-book-question-ui": "file:../gcls-book-question-ui-0.1.0.tgz",
@@ -50,7 +50,7 @@
     "compression-webpack-plugin": "^6.1.1",
     "eslint": "^7.32.0",
     "eslint-plugin-prettier": "^4.0.0",
-    "eslint-plugin-vue": "^8.1.1",
+    "eslint-plugin-vue": "^8.2.0",
     "html-webpack-plugin": "^5.3.1",
     "postcss": "^8.4.4",
     "postcss-html": "^1.3.0",

+ 15 - 0
src/api/select.js

@@ -95,3 +95,18 @@ export function GetMyJoinCourseTeacherList_Student() {
     params
   });
 }
+
+/**
+ * 得到课程学员列表
+ * @param {Object} data
+ */
+export function GetCourseStudentList(data) {
+  let params = getRequestParams('teaching-course_manager-GetCourseStudentList');
+
+  return request({
+    method: 'post',
+    url: process.env.VUE_APP_LearnWebSI,
+    params,
+    data
+  });
+}

+ 1 - 0
src/icons/svg/check-mark-currentColor.svg

@@ -0,0 +1 @@
+<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M24 0H0v24h24V0Z" fill="#fff" fill-opacity=".01"/><path d="m21.5 5.5-13.063 13L2.5 12.59" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>

+ 5 - 0
src/icons/svg/closed.svg

@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M8.00065 14.6663C11.6826 14.6663 14.6673 11.6816 14.6673 7.99967C14.6673 4.31777 11.6826 1.33301 8.00065 1.33301C4.31875 1.33301 1.33398 4.31777 1.33398 7.99967C1.33398 11.6816 4.31875 14.6663 8.00065 14.6663Z" fill="#C4C4C4"/>
+<path d="M9.88549 6.11426L6.11426 9.88549" stroke="white" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M6.11426 6.11426L9.88549 9.88549" stroke="white" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

+ 1 - 0
src/icons/svg/plus.svg

@@ -0,0 +1 @@
+<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M24 0H0v24h24V0Z" fill="#fff" fill-opacity=".01"/><path d="m12.03 5-.018 14M5 12h14" stroke="#fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>

+ 1 - 1
src/icons/svg/send-message.svg

@@ -1 +1 @@
-<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M24 0H0v24h24V0Z" fill="#fff" fill-opacity=".01"/><path d="M16.5 19H11v-4h7v-4h4v8h-2.5L18 20.5 16.5 19Z" stroke="#333" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M2 3h16v12H8.5l-2 2-2-2H2V3Z" stroke="#333" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M9.5 9h.5M13 9h.5M6 9h.5" stroke="#333" stroke-width="1.5" stroke-linecap="round"/></svg>
+<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M24 0H0v24h24V0Z" fill="#fff" fill-opacity=".01"/><path d="M16.5 19H11v-4h7v-4h4v8h-2.5L18 20.5 16.5 19Z" stroke="#333" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M2 3h16v12H8.5l-2 2-2-2H2V3Z" stroke="#333" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M9.5 9h.5m3 0h.5M6 9h.5" stroke="#333" stroke-width="1.5" stroke-linecap="round"/></svg>

+ 33 - 12
src/views/main/TaskList.vue

@@ -15,12 +15,16 @@
         <!-- 通知列表 -->
         <div class="notice-container">
           <ul>
-            <li v-for="{ id, is_read, content, send_time, source_entity_id } in message_list" :key="id">
+            <li v-for="{ id, is_read, content, send_time, source_entity_id, message_type } in message_list" :key="id">
               <span class="is-read" v-text="is_read === 'false' ? 'new' : ''" />
               <span
                 class="notice-content"
-                :style="{ color: is_read === 'true' ? '#8c8c8c' : '#000' }"
-                @click="readMyMessage(id, source_entity_id)"
+                :style="{
+                  color: is_read === 'true' ? '#8c8c8c' : '#000',
+                  cursor: message_type === 201 ? 'text' : 'pointer'
+                }"
+                :title="content"
+                @click="readMyMessage(id, source_entity_id, message_type)"
               >
                 {{ content }}
               </span>
@@ -59,22 +63,24 @@
             {{ date_stamp }}
           </li>
           <li
-            v-for="({ id, cs_item_name, time_type, course_name, teaching_type, time_space_view_txt }, j) in task_list"
+            v-for="(
+              { id, cs_item_name, time_type, course_name, teaching_type, time_space_view_txt, name }, j
+            ) in task_list"
             :key="id"
             class="task-item"
             :style="{
-              'background-color': colorMatching[i % 6].background,
-              color: colorMatching[i % 6].main,
-              border: `1px solid ${colorMatching[i % 6].border}`
+              'background-color': colorMatching[i % 7].background,
+              color: colorMatching[i % 7].main,
+              border: `1px solid ${colorMatching[i % 7].border}`
             }"
             @click="taskLink_outside(id)"
           >
             <div class="task-item-top">
-              <svg-icon icon-class="arrival" :style="{ color: colorMatching[i % 6].main }" />
-              <span class="cs-item-name">{{ cs_item_name }}</span>
+              <svg-icon icon-class="arrival" :style="{ color: colorMatching[i % 7].main }" />
+              <span class="cs-item-name">{{ cs_item_name }} - {{ name }}</span>
               <span
                 class="task-button"
-                :style="{ 'background-color': buttonColorList[j % 2] }"
+                :style="{ 'background-color': buttonColorList[j % 3] }"
                 @click.stop="taskLink(teaching_type, id)"
               >
                 {{ getTimeTypeName(time_type) }}任务
@@ -221,7 +227,8 @@ export default {
       );
     },
 
-    readMyMessage(id, source_entity_id) {
+    readMyMessage(id, source_entity_id, message_type) {
+      if (message_type === 201) return;
       ReadMyMessage({ id }).then(() => {
         this.taskLink_outside(source_entity_id);
       });
@@ -291,9 +298,23 @@ export default {
             }
 
             .notice-content {
+              position: relative;
               width: 230px;
+              max-height: 3.45em;
               margin-right: 16px;
-              cursor: pointer;
+              overflow: hidden;
+              word-break: break-all;
+
+              // 多行文本隐藏
+              &::after {
+                position: absolute;
+                top: 2em;
+                right: 0;
+                padding-left: 40px;
+                font-size: 18px;
+                content: '...';
+                background: linear-gradient(to right, transparent, #fff 55%);
+              }
             }
 
             .send-time {

+ 0 - 1
src/views/main/index.vue

@@ -13,7 +13,6 @@ import CurriculaListStudent from './curricula_list/student.vue';
 import CurriculaListTeacher from './curricula_list/teacher.vue';
 
 export default {
-  name: 'Main',
   components: {
     TaskList,
     TemplateList,

+ 5 - 3
src/views/task_details/teacher/index.vue

@@ -185,7 +185,9 @@ export default {
           cs_item_learning_material_list,
           task_mode,
           time_space_view_txt,
-          student_list
+          student_list,
+          is_custom_student,
+          custom_student_list
         }) => {
           this.itemInfo = {
             time_space_view_txt,
@@ -201,8 +203,8 @@ export default {
           this.accessory_list = accessory_list;
           this.task_mode = task_mode;
           this.time_space_view_txt = time_space_view_txt;
-          this.student_list = student_list;
-          if (student_list.length > 0) this.getTaskStudentExecuteInfo(student_list[0].student_id);
+          this.student_list = is_custom_student === 'true' ? custom_student_list : student_list;
+          if (this.student_list.length > 0) this.getTaskStudentExecuteInfo(this.student_list[0].student_id);
         }
       )
       .finally(() => {

+ 162 - 32
src/views/teacher/create_course/step_table/NewTask.vue

@@ -26,6 +26,40 @@
             />
           </el-select>
         </el-form-item>
+        <el-form-item v-if="!is_template" label="选择学生">
+          <div class="tag-list">
+            <el-popover trigger="click" placement="bottom-start">
+              <div class="student-list create-task">
+                <ul>
+                  <li
+                    v-for="({ student_id, student_name, student_image_url }, i) in student_list"
+                    :key="student_id"
+                    :class="{ selected: custom_student_list.some(item => item.student_id === student_id) }"
+                    @click="selectStudent(i)"
+                  >
+                    <el-avatar icon="el-icon-user" :src="student_image_url" class="student_image" />
+                    <span class="student_name nowrap-ellipsis">{{ student_name }}</span>
+                    <svg-icon icon-class="check-mark-currentColor" class="svg-normal" />
+                  </li>
+                </ul>
+              </div>
+
+              <span slot="reference" class="add-button">
+                <svg-icon icon-class="plus" />
+              </span>
+            </el-popover>
+
+            <span
+              v-for="{ student_id, student_name, student_image_url } in custom_student_list"
+              :key="`tag-${student_id}`"
+              class="student-tag"
+            >
+              <el-avatar :src="student_image_url" :size="32" />
+              <span class="tag-name">{{ student_name }}</span>
+              <svg-icon icon-class="closed" @click="deleteStudentItem(student_id)" />
+            </span>
+          </div>
+        </el-form-item>
 
         <el-form-item label="时间">
           <el-date-picker v-model="form.begin_date" type="date" value-format="yyyy-MM-dd" />&nbsp;
@@ -211,7 +245,7 @@
 
 <script>
 import SelectCourse from '@/components/select/SelectCourse.vue';
-import { GetTaskTeachingTypeList, GetTaskModeList, GetTeacherListByCourseID } from '@/api/select';
+import { GetTaskTeachingTypeList, GetTaskModeList, GetTeacherListByCourseID, GetCourseStudentList } from '@/api/select';
 import { AddTaskToCSItem, GetTreeNodeInfo_BookChapterStruct, GetTaskInfo, UpdateTask, GetCSItem } from '@/api/course';
 import { fileUpload } from '@/api/app';
 
@@ -239,6 +273,8 @@ export default {
       type_list: [],
       teacher_list: [],
       mode_list: [],
+      student_list: [],
+      custom_student_list: [],
       form: {
         name: '',
         teacher_id: '',
@@ -305,6 +341,11 @@ export default {
         this.cs_item_begin_time = begin_time;
         this.cs_item_end_time = end_time;
       });
+      if (!this.is_template) {
+        GetCourseStudentList({ course_id: this.id, audit_status_list: [1], pay_status: 1 }).then(({ student_list }) => {
+          this.student_list = student_list;
+        });
+      }
     },
 
     addTaskToCSItem() {
@@ -312,7 +353,6 @@ export default {
         if (!valid) {
           return false;
         }
-
         let teaching_type = this.form.teaching_type;
         let data = {
           cs_item_id: this.cs_item_id,
@@ -328,40 +368,25 @@ export default {
               ? `${this.form.end_date} ${this.form.end_date_hour}:${this.form.end_date_minute}`
               : this.cs_item_end_time,
           teacher_id: this.form.teacher_id,
-          content: this.form.content
+          content: this.form.content,
+          custom_student_id_list: this.custom_student_list.map(({ student_id }) => student_id)
         };
 
         if (teaching_type === 10) {
-          let courseware_id_list = [];
-          this.liveForm.coursewareInfo.forEach(item => {
-            courseware_id_list.push(item.courseware_id);
-          });
-          data['courseware_id_list'] = courseware_id_list;
-          let file_info_list = [];
-          this.liveForm.file_info_list.forEach(item => {
-            file_info_list.push(item.file_id);
-          });
-          data['file_id_list'] = file_info_list;
+          data['courseware_id_list'] = this.liveForm.coursewareInfo.map(({ courseware_id }) => courseware_id);
+          data['file_id_list'] = this.liveForm.file_info_list.map(({ file_id }) => file_id);
           data['courseware_visible_mode'] = this.liveForm.courseware_visible_mode;
           data['zhibo_record_mode'] = this.liveForm.zhibo_record_mode;
         }
 
         if (teaching_type === 11) {
-          let courseware_id_list = [];
-          this.courseForm.coursewareInfo.forEach(item => {
-            courseware_id_list.push(item.courseware_id);
-          });
-          data['courseware_id_list'] = courseware_id_list;
+          data['courseware_id_list'] = this.courseForm.coursewareInfo.map(({ courseware_id }) => courseware_id);
           data['task_mode'] = this.courseForm.task_mode;
           data['is_enable_message'] = this.courseForm.is_enable_message;
         }
 
         if (teaching_type === 12) {
-          let file_info_list = [];
-          this.basicForm.file_info_list.forEach(item => {
-            file_info_list.push(item.file_id);
-          });
-          data['file_id_list'] = file_info_list;
+          data['file_id_list'] = this.basicForm.file_info_list.map(({ file_id }) => file_id);
           data['is_enable_homework'] = this.basicForm.is_enable_homework;
           data['is_enable_message'] = this.basicForm.is_enable_message;
         }
@@ -379,6 +404,20 @@ export default {
       });
     },
 
+    selectStudent(i) {
+      const id = this.student_list[i].student_id;
+      let list = this.custom_student_list;
+      let index = list.findIndex(({ student_id }) => student_id === id);
+      index === -1 ? list.push(this.student_list[i]) : list.splice(index, 1);
+    },
+
+    deleteStudentItem(id) {
+      this.custom_student_list.splice(
+        this.custom_student_list.findIndex(({ student_id }) => student_id === id),
+        1
+      );
+    },
+
     goBack() {
       this.$router.push({
         path: `/create_course_step_table/create_task/${this.id}?is_template=${this.is_template}`
@@ -458,7 +497,9 @@ export default {
           courseware_visible_mode,
           zhibo_record_mode,
           cs_item_begin_time,
-          cs_item_end_time
+          cs_item_end_time,
+          is_custom_student,
+          custom_student_list
         }) => {
           if (begin_time.length > 0) {
             let begin = begin_time.split(' ');
@@ -499,6 +540,8 @@ export default {
             this.basicForm.is_enable_homework = is_enable_homework === 'true';
             this.basicForm.is_enable_message = is_enable_message === 'true';
           }
+
+          if (is_custom_student === 'true') this.custom_student_list = custom_student_list;
         }
       );
     }
@@ -555,6 +598,48 @@ export default {
         width: 140px;
       }
 
+      .tag-list {
+        display: flex;
+        flex-wrap: wrap;
+
+        .add-button {
+          display: inline-block;
+          width: 40px;
+          height: 40px;
+          text-align: center;
+          cursor: pointer;
+          background-color: $basic-color;
+          border-radius: 50%;
+
+          .svg-icon {
+            position: relative;
+            top: -1px;
+            width: 24px;
+            height: 24px;
+            vertical-align: middle;
+          }
+        }
+
+        .student-tag {
+          display: flex;
+          align-items: center;
+          height: 40px;
+          padding: 4px 12px 4px 4px;
+          margin-left: 16px;
+          border: 1px solid $border-color;
+          border-radius: 20px;
+
+          .tag-name {
+            margin: 0 16px 0 8px;
+
+            + .svg-icon {
+              cursor: pointer;
+            }
+          }
+        }
+      }
+
+      // 任务模板
       .task-template {
         padding: 24px 32px;
         background-color: #fbfbfb;
@@ -564,22 +649,67 @@ export default {
         .el-form-item:not(:first-child, :last-child) {
           margin: 20px 0;
         }
+
+        .el-tag {
+          margin-right: 16px;
+
+          > span {
+            display: inline-block;
+            max-width: 200px;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+            vertical-align: bottom;
+          }
+        }
       }
 
       .el-button.done {
         width: 120px;
       }
+    }
+  }
+}
+</style>
 
-      .el-tag {
-        margin-right: 16px;
+<style lang="scss">
+.el-popover {
+  padding: 8px 0;
+
+  .student-list.create-task {
+    width: 330px;
+    height: 25vh;
+    min-height: 240px;
+    overflow: auto;
+
+    ul {
+      li {
+        padding: 8px 24px;
+        cursor: pointer;
+
+        .student_image {
+          margin-right: 16px;
+          vertical-align: middle;
+        }
 
-        > span {
+        .student_name {
           display: inline-block;
-          max-width: 200px;
-          overflow: hidden;
-          text-overflow: ellipsis;
-          white-space: nowrap;
-          vertical-align: bottom;
+          width: 70%;
+          vertical-align: middle;
+        }
+
+        .svg-icon {
+          vertical-align: middle;
+          visibility: hidden;
+        }
+
+        &.selected {
+          background-color: #dbdbdb;
+
+          .svg-icon {
+            color: #333;
+            visibility: visible;
+          }
         }
       }
     }