mjh 4 лет назад
Родитель
Сommit
f20cf0ba5e
4 измененных файлов с 204 добавлено и 148 удалено
  1. 9 0
      src/api/project.js
  2. 5 0
      src/api/user.js
  3. 1 1
      src/components/project/ProjectLongCard.vue
  4. 189 147
      src/views/CoursePage/CourseDetail.vue

+ 9 - 0
src/api/project.js

@@ -50,6 +50,14 @@ function updateCourseProjectState(id) {
   });
 }
 
+function forkProject(projectId) {
+  return axios.post(`${prefix}/fork`, null, {
+    params: {
+      projectId,
+    }
+  });
+}
+
 const projectAPIs = {
   findAllProjects,
   findCourseProjects,
@@ -59,6 +67,7 @@ const projectAPIs = {
   findProjectsByCourse,
   createProject,
   updateCourseProjectState,
+  forkProject,
 };
 
 export default projectAPIs;

+ 5 - 0
src/api/user.js

@@ -46,6 +46,10 @@ function saveSignatureAPI(data) {
   return axios.post(`${prefix}/saveSignature`, data);
 }
 
+function findUserIdByPhone(phone){
+  return axios.get(`${prefix}/findIdByPhone/${phone}`);
+}
+
 const userAPIs = {
   loginAPI,
   registerAPI,
@@ -56,6 +60,7 @@ const userAPIs = {
   saveEmailAPI,
   saveSignatureAPI,
   getNameByUsernameAPI,
+  findUserIdByPhone
 };
 
 export default userAPIs;

+ 1 - 1
src/components/project/ProjectLongCard.vue

@@ -47,7 +47,7 @@ export default {
       default: false,
     }
   },
-  emits: ["switch"],
+  emits: ["switch","fork"],
   data() {
     return {
       members: [],

+ 189 - 147
src/views/CoursePage/CourseDetail.vue

@@ -44,7 +44,7 @@
       <el-divider v-if="isCreator || isCourseSelected"/>
       <!--tab页-->
       <el-card v-if="isCreator || isCourseSelected">
-        <!--tab标签-->
+        <!--tab标签&&tab按钮-->
         <div v-if="isCreator || isCourseSelected" class="course-tabs">
           <el-radio-group v-model="tabName" size="large">
             <el-radio-button label="task" @click="switchTab('task')">任务</el-radio-button>
@@ -123,14 +123,14 @@
           <!--学生视角-->
           <div v-if="isCourseSelected">
             <div v-if="tabName==='group'">
-            <el-button v-if="isGroupExisted===false" :disabled="isRuleExisted"
-                       plain type="primary" @click="createGroupDialog=true">
-              创建队伍
-            </el-button>
-            <el-button v-if="isGroupExisted===true"
-                       plain type="primary" @click="addMemberDialog=true">
-              邀请成员
-            </el-button>
+              <el-button v-if="isGroupExisted===false" :disabled="!isRuleExisted"
+                         plain type="primary" @click="createGroupDialog=true">
+                创建队伍
+              </el-button>
+              <el-button v-if="isGroupExisted===true"
+                         plain type="primary" @click="addMemberDialog=true">
+                邀请成员
+              </el-button>
             </div>
           </div>
         </div>
@@ -282,7 +282,8 @@
                   <div v-else>
                     <project-long-card v-for="item in projects.public" :key="'project'+item.id"
                                        :project="item" is-public :is-teacher="isCreator"
-                                       @switch="handleProjectSwitch(item.id)"/>
+                                       @fork="handleForkProject(item.id)"
+                                       @switch="handleSwitchProject(item.id)"/>
                   </div>
                 </div>
               </el-tab-pane>
@@ -294,27 +295,28 @@
                   <div v-else>
                     <project-long-card v-for="item in projects.private" :key="'project'+item.id"
                                        :project="item" :is-teacher="isCreator"
-                                       @switch="handleProjectSwitch(item.id)"/>
+                                       @switch="handleSwitchProject(item.id)"/>
                   </div>
                 </div>
               </el-tab-pane>
             </el-tabs>
           </div>
           <div v-else-if="tabName==='group'">
-            <el-table v-if="groupData!=null" :data="groupTableData" style="width: 100%">
+            <el-table :data="groupTableData" style="width: 100%">
               <el-table-column label="组名">
                 <template #default="scope">
-                  <span :style="scope.row.groupVO.name===groupData.groupVO.name?'color:#67C23A':''">
-                    {{ scope.row.groupVO.name }}
+                  <span :style="isGroupExisted && scope.row['groupVO'].id===groupData['groupVO'].id ? 'color: #67C23A':''">
+                    {{ scope.row['groupVO'].name }}
                   </span>
                 </template>
               </el-table-column>
               <el-table-column label="组员">
                 <template #default="scope">
-                  <span :style="scope.row.groupVO.name===groupData.groupVO.name?'color:#67C23A':''"
-                        v-for="item of scope.row.members" :key="'member'+item.id">
-                    {{ item.username }}
-                  </span>
+                  <div v-for="item of scope.row.members" :key="'member'+item.id">
+                    <span :style="isGroupExisted && scope.row['groupVO'].id===groupData['groupVO'].id ? 'color: #67C23A':''">
+                      {{ item.username }}
+                    </span>
+                  </div>
                 </template>
               </el-table-column>
             </el-table>
@@ -397,8 +399,8 @@
     <!-- 添加组员-->
     <el-dialog v-model="addMemberDialog" :before-close="beforeGroupMemberFormClose" :title="addMemberForm.dialogTitle">
       <el-form ref="addMemberFormRef" :model="addMemberForm" label-position="right">
-        <el-form-item label="组员手机号" prop="phoneNumber">
-          <el-input v-model="addMemberForm.phoneNumber" placeholder="输入组员手机号" maxlength="11"></el-input>
+        <el-form-item label="组员手机号" prop="phone">
+          <el-input v-model="addMemberForm.phone" placeholder="输入组员手机号" maxlength="11"></el-input>
         </el-form-item>
       </el-form>
       <div style="margin: auto;width: fit-content">
@@ -536,14 +538,10 @@ export default {
 
       // group member
       addMemberDialog: false,
-      groupTableData: [{
-        name: "组1",
-        groupLeader: "组长1",
-        groupMembers: "组员1、组员2、组员3"
-      }],
+      groupTableData: [],
       addMemberForm: {
         dialogTitle: "组员信息",
-        phoneNumber: null,
+        phone: null,
       },
     };
   },
@@ -617,7 +615,118 @@ export default {
       });
   },
   methods: {
-    //
+    // course
+
+    handleSelectCourse() {
+      ElMessageBox.prompt("请输入选课码", "选课:" + this.courseInfo.name, {
+        confirmButtonText: "立即选课",
+        cancelButtonText: "我再想想",
+      })
+        .then(({value}) => {
+          if (value !== this.courseInfo.invitationCode) {
+            ElMessage.error("选课码错误");
+          } else {
+            this.$apis.confirmCourseSelection(
+              {
+                courseId: this.courseInfo.id,
+                userId: this.$store.state.user.id,
+              })
+              .then((res) => {
+                if (res.data.code === -1) {
+                  ElMessage.error("选课失败");
+                } else {
+                  ElMessage.success("选课成功");
+                  setTimeout(function () {
+                    location.reload();
+                  }, 500);
+                }
+              });
+          }
+        });
+    },
+
+    handleDropCourse() {
+      ElMessageBox.confirm("是否确认退课?", "退课:" + this.courseInfo.name, {
+        confirmButtonText: "立即退课",
+        cancelButtonText: "我再想想",
+      })
+        .then(() => {
+          this.$apis.cancelCourseSelection(
+            {
+              courseId: this.courseInfo.id,
+              userId: this.$store.state.user.id,
+            }
+          )
+            .then(() => {
+              ElMessage.success("退课成功");
+              setTimeout(function () {
+                location.reload();
+              }, 500);
+            })
+            .catch(err => {
+              ElMessage.error("handleCancelCourse: " + err);
+            });
+        });
+    },
+
+    // tab
+
+    async switchTab(tabName) {
+      const _this = this;
+      switch (tabName) {
+        case "task":
+          if (this.isTeacher) {
+            if (this.courseInfo.evalId !== null) {
+              this.evalExamList = (await this.$apis.getTeacherEvalExamsByCourseId(this.courseInfo.evalId)).data.data || [];
+            }
+            if (this.courseInfo.coderId !== null) {
+              this.coderExamList = (await this.$apis.getTeacherCoderExamsByCourseId(this.courseInfo.coderId)).data.data;
+            }
+          } else if (this.isStudent) {
+            if (this.courseInfo.evalId !== null) {
+              this.evalExamList = (await this.$apis.getStudentEvalExamsByCourseId(this.courseInfo.evalId)).data.data || [];
+            }
+            if (this.courseInfo.coderId !== null) {
+              this.coderExamList = (await this.$apis.getStudentCoderExamsByCourseId(this.courseInfo.coderId)).data.data;
+            }
+          }
+          break;
+        case "notice":
+          this.announcementList = (await this.$apis.getAnnouncementsByCourseId(this.$route.params.id)).data.data;
+          break;
+        case "courseware":
+          break;
+        case "comment":
+          this.commentTree = (await this.$apis.getCommentsByCourseId(this.$route.params.id)).data.data;
+          break;
+        case "project":
+          const projectRes = (await _this.$apis.findProjectsByCourse(_this.courseInfo.id)).data;
+          if (projectRes.code) {
+            ElMessage.error(projectRes.message);
+          } else {
+            _this.projects = projectRes.data;
+          }
+          break;
+        case "group":
+          const ruleRes = (await _this.$apis.findGroupRule(this.courseInfo.id)).data;
+          _this.isRuleExisted = !ruleRes.code;
+          if (_this.isRuleExisted) {
+            const groupsRes = (await _this.$apis.findAllGroupsByCourse(this.courseInfo.id)).data;
+            if (!groupsRes.code) {
+              _this.groupTableData = groupsRes.data;
+            }
+            const groupRes = (await _this.$apis.findGroup(_this.courseInfo.id)).data;
+            _this.isGroupExisted = !groupRes.code;
+            if (_this.isGroupExisted) {
+              _this.groupData = groupRes.data;
+            }
+          }
+          break;
+      }
+    },
+
+    // time
+
     timestampToTime(timestamp) {
       const date = new Date(timestamp);
       const Y = date.getFullYear() + "-";
@@ -627,7 +736,9 @@ export default {
       const m = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
       return Y + M + D + h + m;
     },
-    // 任务
+
+    // task
+
     courseTaskStatusColor(VO) {
       if (this.state(VO) === "FINISHED" || this.state(VO) === "NOT_STARTED" || this.state(VO) === "CLOSED") {
         return "grey";
@@ -637,6 +748,7 @@ export default {
         return this.themeColor.blue;
       }
     },
+
     state(VO) {
       if (VO["examId"]) {
         if (new Date(VO.endTime) < new Date()) {
@@ -658,6 +770,7 @@ export default {
         }
       }
     },
+
     addTest(type) {
       switch (type) {
         case "eval":
@@ -674,6 +787,7 @@ export default {
           break;
       }
     },
+
     toTask(task) {
       const type = task["examId"] ? "eval" : "coder";
       let evalUrl;
@@ -709,11 +823,14 @@ export default {
       }
       window.open(url + "?id_token=" + this.$store.state.user.token);
     },
-    // 公告相关
+
+    // announcement
+
     selAndInitAnnouncement(type) {
       this.announcementForm.type = type;
       this.announcementFormDialog = true;
     },
+
     beforeFormClose() {
       ElMessageBox.confirm("是否确认退出?退出后将不保存表格信息。", "提示", {
         confirmButtonText: "确认退出",
@@ -726,7 +843,7 @@ export default {
           this.$refs.announceFormRef.resetFields();
         });
     },
-    // announcement
+
     handlePublishAnnouncement() {
       const _this = this;
       if (this.announcementForm.content === "") {
@@ -790,6 +907,7 @@ export default {
           });
       }
     },
+
     beforeUpdateAnnouncement(item) {
       this.announcementForm.dialogTitle = "修改公告";
       this.announcementForm.id = item.id;
@@ -798,6 +916,7 @@ export default {
       this.announcementForm.content = item.content;
       this.announcementFormDialog = true;
     },
+
     deleteAnnouncement(item, index) {
       ElMessageBox.confirm("是否确认删除公告  \"" + item.title + "\"  ?", "提示", {
         confirmButtonText: "确认删除",
@@ -812,6 +931,7 @@ export default {
             });
         });
     },
+
     announcementContent(item) {
       if (item.content === "") {
         return "当前公告暂无具体内容。";
@@ -819,6 +939,7 @@ export default {
         return item.content;
       }
     },
+
     readAnnouncement(item) {
       if (!item.read) {
         this.$apis.readAnnouncement(item.id)
@@ -828,120 +949,20 @@ export default {
           });
       }
     },
-    //
+
+    // courseware
+
     handleFileUploading() {
     },
+
     handleFileUploadSuccess() {
     },
+
     handleDownloadFileIconClick(url) {
     },
-    // 选课、退课
-    handleSelectCourse() {
-      ElMessageBox.prompt("请输入选课码", "选课:" + this.courseInfo.name, {
-        confirmButtonText: "立即选课",
-        cancelButtonText: "我再想想",
-      })
-        .then(({value}) => {
-          if (value !== this.courseInfo.invitationCode) {
-            ElMessage.error("选课码错误");
-          } else {
-            this.$apis.confirmCourseSelection(
-              {
-                courseId: this.courseInfo.id,
-                userId: this.$store.state.user.id,
-              })
-              .then((res) => {
-                if (res.data.code === -1) {
-                  ElMessage.error("选课失败");
-                } else {
-                  ElMessage.success("选课成功");
-                  setTimeout(function () {
-                    location.reload();
-                  }, 500);
-                }
-              });
-          }
-        });
-    },
-    handleDropCourse() {
-      ElMessageBox.confirm("是否确认退课?", "退课:" + this.courseInfo.name, {
-        confirmButtonText: "立即退课",
-        cancelButtonText: "我再想想",
-      })
-        .then(() => {
-          this.$apis.cancelCourseSelection(
-            {
-              courseId: this.courseInfo.id,
-              userId: this.$store.state.user.id,
-            }
-          )
-            .then(() => {
-              ElMessage.success("退课成功");
-              setTimeout(function () {
-                location.reload();
-              }, 500);
-            })
-            .catch(err => {
-              ElMessage.error("handleCancelCourse: " + err);
-            });
-        });
-    },
-    // tab页相关
-    async switchTab(tabName) {
-      const _this = this;
-      switch (tabName) {
-        case "task":
-          if (this.isTeacher) {
-            if (this.courseInfo.evalId !== null) {
-              this.evalExamList = (await this.$apis.getTeacherEvalExamsByCourseId(this.courseInfo.evalId)).data.data || [];
-            }
-            if (this.courseInfo.coderId !== null) {
-              this.coderExamList = (await this.$apis.getTeacherCoderExamsByCourseId(this.courseInfo.coderId)).data.data;
-            }
-          } else if (this.isStudent) {
-            if (this.courseInfo.evalId !== null) {
-              this.evalExamList = (await this.$apis.getStudentEvalExamsByCourseId(this.courseInfo.evalId)).data.data || [];
-            }
-            if (this.courseInfo.coderId !== null) {
-              this.coderExamList = (await this.$apis.getStudentCoderExamsByCourseId(this.courseInfo.coderId)).data.data;
-            }
-          }
-          break;
-        case "notice":
-          this.announcementList = (await this.$apis.getAnnouncementsByCourseId(this.$route.params.id)).data.data;
-          break;
-        case "courseware":
-          break;
-        case "comment":
-          this.commentTree = (await this.$apis.getCommentsByCourseId(this.$route.params.id)).data.data;
-          break;
-        case "project":
-          const projectRes = (await _this.$apis.findProjectsByCourse(_this.courseInfo.id)).data;
-          if (projectRes.code) {
-            ElMessage.error(projectRes.message);
-          } else {
-            _this.projects = projectRes.data;
-          }
-          break;
-        case "group":
-          const ruleRes = (await _this.$apis.findGroupRule(this.courseInfo.id)).data;
-          _this.isRuleExisted = !ruleRes.code;
-          if (_this.isRuleExisted) {
-            const groupsRes = (await _this.$apis.findAllGroupsByCourse(this.courseInfo.id)).data;
-            if (!groupsRes.code) {
-              _this.groupTableData = groupsRes.data;
-            }
-            const groupRes = (await _this.$apis.findGroup(_this.courseInfo.id)).data;
-            _this.isGroupExisted = !groupRes.code;
-            if (_this.isGroupExisted) {
-              _this.groupData = groupRes.data;
-              console.log(_this.groupData);
-            }
-          }
-          break;
-      }
-    },
-    // comment相关
+
+    // comment
+
     createComment() {
       if (this.commentContent === "") {
         ElMessage.error("无法发表空评论");
@@ -966,6 +987,7 @@ export default {
           });
       }
     },
+
     async deleteComment(commentId) {
       const res = (await this.$apis.deleteMessage(commentId)).data.data || null;
       if (res == null) {
@@ -975,6 +997,7 @@ export default {
       this.$message.success(res);
       this.commentTree = (await this.$apis.getCommentsByCourseId(this.$route.params.id)).data.data;
     },
+
     handleReplyClick(target, index) {
       ElMessageBox.prompt("请输入评论内容", "回复", {
         confirmButtonText: "发送",
@@ -1010,6 +1033,7 @@ export default {
     },
 
     // project
+
     handleProjectFormClose() {
       const _this = this;
       _this.projectDialogVisible = false;
@@ -1035,7 +1059,7 @@ export default {
       }
     },
 
-    async handleProjectSwitch(id) {
+    async handleSwitchProject(id) {
       const _this = this;
       const res = (await _this.$apis.updateCourseProjectState(id)).data;
       if (!res.code) {
@@ -1057,6 +1081,12 @@ export default {
       }
     },
 
+    async handleForkProject(id) {
+      const _this = this;
+      const res = (await _this.$apis.forkProject(id)).data;
+      ElMessage.success(JSON.stringify(res));
+    },
+
     // group rule
 
     beforeRuleFormClose() {
@@ -1080,7 +1110,6 @@ export default {
             maxSize: this.ruleForm.maxSize,
             maxNameLen: this.ruleForm.maxNameLen,
           };
-          console.log(RuleVO);
           this.$apis.createGroupRule(RuleVO)
             .then(res => {
               if (res.data.code) {
@@ -1133,19 +1162,32 @@ export default {
     },
 
     handleAddMemberConfirm() {
-      this.$refs.addMemberFormRef.validate((valid) => {
+      const _this = this;
+      this.$refs.addMemberFormRef.validate(async (valid) => {
         if (valid) {
-          let GroupMemberVO = {
-            courseId: this.courseInfo.id,
-            phoneNumber: this.addMemberForm.phoneNumber,
+          const userIdRes = (await _this.$apis.findUserIdByPhone(_this.addMemberForm.phone)).data;
+          if (userIdRes.code) {
+            ElMessage.error(userIdRes.message);
+            return;
+          }
+          let groupMemberVO = {
+            userId: userIdRes.data,
+            groupId: _this.groupData.groupVO.id,
+            courseId: _this.courseInfo.id,
           };
-          this.$apis.addGroupMember(GroupMemberVO)
+          this.$apis.addGroupMember(groupMemberVO)
             .then(res => {
               if (res.data.code) {
                 ElMessage.error(res.data.message);
               } else {
-                this.addMemberDialog = false;
-                this.$refs.addMemberFormRef.resetFields();
+                const groupDTO = res.data.data;
+                for (const row of _this.groupTableData) {
+                  if (groupDTO.groupVO.id === row.groupVO.id) {
+                    row.members = groupDTO.members;
+                  }
+                }
+                _this.addMemberDialog = false;
+                _this.$refs.addMemberFormRef.resetFields();
                 ElMessage.success("添加组员成功");
               }
             });