19 Commits f5e0f6abfa ... 3829437db0

Tác giả SHA1 Thông báo Ngày
  Johnson 3829437db0 与后端张怡接口调试通过 7 năm trước cách đây
  WuXinyu 1e2826e6d2 Merge branch 'feature/assignment-zhangyasen' of SEEC-II-FrontEnd-Team/SEEC-II-FrontEnd into develop 7 năm trước cách đây
  Kunduin 78c8cc6891 Merge remote-tracking branch 'origin/feature/result-zhouweilu' into develop 7 năm trước cách đây
  soleil 8666baf8cf [修改]老师学生课程、题目、题目详情、成绩页面loading 7 năm trước cách đây
  soleil c9962ab3fb [修改]成绩页button loading效果 7 năm trước cách đây
  WuXinyu 39ba9fdc3c Merge branch 'style/loading-bay' of SEEC-II-FrontEnd-Team/SEEC-II-FrontEnd into develop 7 năm trước cách đây
  Kunduin 8ca8b602c5 [更新] 添加老师部分loading 7 năm trước cách đây
  soleil dbe4a66417 [修改]老师、学生课程部分表单提交 7 năm trước cách đây
  soleil 487d532a46 [merge]合并 7 năm trước cách đây
  WuXinyu 6347ccd3df Merge branch 'mock/codeHW' of SEEC-II-FrontEnd-Team/SEEC-II-FrontEnd into develop 7 năm trước cách đây
  Kunduin 9d42228375 [更新] 初步完成build界面 7 năm trước cách đây
  Unknown 5215d1920d 修改了一下路由 7 năm trước cách đây
  Unknown c42122b11a Merge remote-tracking branch 'origin/develop' into feature/codeHW 7 năm trước cách đây
  soleil 45326095da [修改]获取题目分类、获取题目列表、获取文档作列表业接口 7 năm trước cách đây
  soleil d0346f4efd Merge branch 'develop' into feature/result-zhouweilu 7 năm trước cách đây
  soleil f6fab75aa9 [新增]老师、学生课程页交互 7 năm trước cách đây
  soleil fc69121aae Merge branch 'develop' into feature/result-zhouweilu 7 năm trước cách đây
  soleil d7b72b6928 [修改]学生课程页面 7 năm trước cách đây
  Unknown 7a6fa68ada Merge remote-tracking branch 'origin/develop' into feature/codeHW 7 năm trước cách đây
34 tập tin đã thay đổi với 799 bổ sung269 xóa
  1. 23 1
      mock/modules/question/index.js
  2. 1 1
      mock/serializers/user/UserSerializer.js
  3. 13 0
      package-lock.json
  4. 4 2
      src/api/assignment.js
  5. 1 0
      src/api/course.js
  6. 16 4
      src/api/question.js
  7. 6 4
      src/components/AssignmentCRUD/CreateAssignment/index.vue
  8. 3 13
      src/components/AssignmentCRUD/DeleteAssignment/index.vue
  9. 2 0
      src/components/AssignmentCRUD/UpdateAssignment/index.vue
  10. 1 1
      src/layouts/HomeLayout/HomeHeader/index.vue
  11. 2 1
      src/layouts/courseLayouts/LayoutStructure.vue
  12. 1 1
      src/router/routes.js
  13. 5 4
      src/views/login/Login.vue
  14. 5 4
      src/views/login/Register.vue
  15. 50 3
      src/views/student/Code/ProjectDetail/BuildDetail.vue
  16. 25 0
      src/views/student/Code/ProjectDetail/components/BuildTag.vue
  17. 7 7
      src/views/student/Code/ProjectDetail/index.vue
  18. 15 7
      src/views/student/Code/ProjectList/index.vue
  19. 19 9
      src/views/student/Code/index.vue
  20. 6 3
      src/views/student/Document/detail.vue
  21. 165 5
      src/views/student/Home/index.vue
  22. 51 24
      src/views/teacher/Code/detail.vue
  23. 1 1
      src/views/teacher/Document/detail.vue
  24. 4 4
      src/views/teacher/Document/docContent.vue
  25. 64 10
      src/views/teacher/Home/index.vue
  26. 100 45
      src/views/teacher/Question/index.vue
  27. 38 26
      src/views/teacher/Question/questionDetail.vue
  28. 36 25
      src/views/teacher/Result/index.vue
  29. 72 54
      src/views/teacher/Review/ReviewDetail/Detail/index.vue
  30. 19 5
      src/views/teacher/Review/ReviewDetail/GroupDocDetail/index.vue
  31. 8 0
      src/views/teacher/Review/ReviewDetail/Groups/index.vue
  32. 21 3
      src/views/teacher/Review/ReviewDetail/index.vue
  33. 14 2
      src/views/teacher/Review/index.vue
  34. 1 0
      vue.config.js

+ 23 - 1
mock/modules/question/index.js

@@ -10,8 +10,30 @@ router.route("/teacher/questionType").get((req, res) => {
   });
 });
 
+//按题目分类获得题目(分页)
+router.route("/teacher/questions/type").get((req, res) => {
+  res.send({
+    data: [
+      QuestionSerializer(),
+      QuestionSerializer(),
+      QuestionSerializer(),
+      QuestionSerializer(),
+      QuestionSerializer(),
+      QuestionSerializer(),
+      QuestionSerializer(),
+      QuestionSerializer(),
+      QuestionSerializer(),
+      QuestionSerializer(),
+      QuestionSerializer(),
+      QuestionSerializer(),
+      QuestionSerializer()
+    ],
+    pageNum: 1
+  });
+});
+
 //按题目分类获得题目(分页) || 根据作业分类获得题目
-router.route("/teacher/questions").get((req, res) => {
+router.route("/teacher/questions/assignmentType").get((req, res) => {
   res.send({
     data: [
       QuestionSerializer(),

+ 1 - 1
mock/serializers/user/UserSerializer.js

@@ -14,7 +14,7 @@ const makeId = require("../../util/makeId");
  * @param role
  * @returns {UserSerializerType}
  */
-module.exports = (role = "STUDENT") => {
+module.exports = (role = "TEACHER") => {
   return {
     id: makeId(),
     role: role,

+ 13 - 0
package-lock.json

@@ -6233,6 +6233,11 @@
         "write": "^0.2.1"
       }
     },
+    "flatpickr": {
+      "version": "4.5.2",
+      "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.5.2.tgz",
+      "integrity": "sha512-jDy4QYGpmiy7+Qk8QvKJ4spjDdxcx9cxMydmq1x427HkKWBw0qizLYeYM2F6tMcvvqGjU5VpJS55j4LnsaBblA=="
+    },
     "flush-write-stream": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz",
@@ -15825,6 +15830,14 @@
         }
       }
     },
+    "vue-flatpickr-component": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/vue-flatpickr-component/-/vue-flatpickr-component-8.1.1.tgz",
+      "integrity": "sha512-WkZVZbsv/gK3pEMlWA0/Azh21R7neLbDEGb2Yx39+IYbtTpNFRlxQltUVMif0W+TTuuLF5BQOgoe77P5my6cLA==",
+      "requires": {
+        "flatpickr": "^4.5.1"
+      }
+    },
     "vue-hot-reload-api": {
       "version": "2.3.1",
       "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.1.tgz",

+ 4 - 2
src/api/assignment.js

@@ -264,6 +264,8 @@ export const getUnsubmittedDocGroupsByDocId = documentId => {
  * @param documentId
  * @return {Promise<data:DocumentContentSerializerType>}
  */
-export const getDocContentByDocId = documentId => {
-  return request(`${ASSIGNMENT_MODULE}/teacher/document/${documentId}/content`);
+export const getDocContentByDocId = documentResultId => {
+  return request(
+    `${ASSIGNMENT_MODULE}/teacher/document/result/${documentResultId}/content`
+  );
 };

+ 1 - 0
src/api/course.js

@@ -25,6 +25,7 @@ export const getStudentCourses = () => {
  * @throws {StatusException} "课程名重复" | "课程选课码重复"
  */
 export const postTeacherCourse = ({ name, code }) => {
+  console.log(`name${name} code ${code}`);
   return request(`${COURSE_MODULE}/teacher`, {
     method: "POST",
     body: {

+ 16 - 4
src/api/question.js

@@ -13,10 +13,22 @@ export const getTeacherQuestionType = () => {
  * 按题目分类 || 作业分类获得题目
  * @returns {Promise<{data:QuestionSerializer[]}>}
  */
-export const getTeacherQuestions = () => {
-  return request(`${QUESTION_MODULE}/teacher/questions`);
+export const getQuestionsByAssignType = ({ type, page, limit }) => {
+  return request(
+    `${QUESTION_MODULE}/teacher/questions/assignmentType?type=${type ||
+      ""}&page=${page || 0}&limit=${limit || 20}`
+  );
+};
+/**
+ * 按题目分类 || 题目分类获得题目
+ * @returns {Promise<{data:QuestionSerializer[]}>}
+ */
+export const getQuestionByQuesType = ({ type, page, limit }) => {
+  return request(
+    `${QUESTION_MODULE}/teacher/questions/type?type=${type || ""}&page=${page ||
+      1}&limit=${limit || 10}`
+  );
 };
-
 /**
  * 根据关键字进行查找
  * @param {string} keyword
@@ -31,6 +43,6 @@ export const getTeacherKeywordQuestions = (keyword = "123") => {
  * @param {number | string} questionId
  * @returns {Promise<{data:QuestionSerializer}>}
  */
-export const getQuestionDetail = (questionId = 123) => {
+export const getQuestionDetail = questionId => {
   return request(`${QUESTION_MODULE}/question/${questionId}`);
 };

+ 6 - 4
src/components/AssignmentCRUD/CreateAssignment/index.vue

@@ -82,6 +82,7 @@
               placeholder="输入关键字模糊查找"
               type="search"
               v-model="$v.searchContent.$model"
+              @keyup.enter.native="search(searchContent)"
               expanded
             >
             </b-input>
@@ -221,6 +222,7 @@ export default {
       errorMassage: null,
       isServerError: false,
       submitting: false,
+      // 转圈圈
       loadingSearchQuestions: false,
       loadingCreateAssignment: false
     };
@@ -289,16 +291,16 @@ export default {
           );
         }
         this.myPromise.then(res => {
+          //创建成功
+          this.isCreateModalActive = false;
           if (res.code === 0) {
-            //创建成功
-            this.$emit("sendCreatedAssignment", res.data);
-            this.isCreateModalActive = false;
-            this.loadingCreateAssignment = false;
             if (this.assignType === 1) {
               this.$router.push({
                 path: `${this.prefix}/review?documentHwId=${res.data.id}`
               });
             }
+            this.$emit("sendCreatedAssignment", res.data);
+            this.loadingCreateAssignment = false;
           } else {
             //创建失败
             this.isCreateModalActive = false;

+ 3 - 13
src/components/AssignmentCRUD/DeleteAssignment/index.vue

@@ -1,12 +1,5 @@
 <template>
-  <div>
-    <a
-      style="color:#b34141"
-      :class="{ 'is-loading': loadingDelAssignment }"
-      @click="confirmDelete()"
-      >删除</a
-    >
-  </div>
+  <div><a style="color:#b34141" @click="confirmDelete()">删除</a></div>
 </template>
 
 <script>
@@ -25,17 +18,15 @@ export default {
   data() {
     return {
       myPromise: null,
-      submitting: false,
-      loadingDelAssignment: false
+      submitting: false
     };
   },
   methods: {
     confirmDelete() {
       if (this.submitting) return;
-      this.loadingDelAssignment = true;
       this.submitting = true;
       this.$dialog.confirm({
-        message: "确认删除?",
+        message: `确认删除?`,
         confirmText: "删除",
         type: "is-danger",
         onConfirm: () => {
@@ -56,7 +47,6 @@ export default {
                 hasIcon: true
               });
             }
-            this.loadingDelAssignment = false;
           });
         }
       });

+ 2 - 0
src/components/AssignmentCRUD/UpdateAssignment/index.vue

@@ -119,6 +119,8 @@ export default {
       this.isUpdateModalActive = true;
       this.params.name = this.updateItem.name;
       this.params.description = this.updateItem.description;
+      this.params.startAt = this.updateItem.startAt;
+      this.params.endAt = this.updateItem.endAt;
     },
     /**
      * 确认修改

+ 1 - 1
src/layouts/HomeLayout/HomeHeader/index.vue

@@ -2,7 +2,7 @@
   <default-header>
     <div class="container">
       <div class="navbar-brand">
-        <a class="navbar-item header-logo"> SEEC </a>
+        <router-link to="/" class="navbar-item header-logo"> SEEC </router-link>
         <a class="navbar-item"><b-icon pack="fab" icon="github"></b-icon></a>
         <a class="navbar-item"><b-icon pack="fab" icon="twitter"></b-icon></a>
       </div>

+ 2 - 1
src/layouts/courseLayouts/LayoutStructure.vue

@@ -3,7 +3,7 @@
     <div class="course-layout">
       <div class="menu-section">
         <div class="menu-sticky">
-          <div class="header-logo">SEEC</div>
+          <router-link tag="div" to="/" class="header-logo">SEEC</router-link>
           <div class="course-detail">
             {{ course.name }}
             <b-loading
@@ -127,6 +127,7 @@ $top-section-height: 4.25rem;
       border-bottom: 2px solid rgba(255, 255, 255, 0.16);
       /*background-image: linear-gradient(to left, #4f62e9 0%, #161aa7 100%);*/
       padding-left: 24px;
+      cursor: pointer;
       a {
         color: #3d70b2;
       }

+ 1 - 1
src/router/routes.js

@@ -156,7 +156,7 @@ export default [
         component: () => import("@/views/student/Code/ProjectDetail/index"),
         children: [
           {
-            path: "build",
+            path: "",
             component: () =>
               import("@/views/student/Code/ProjectDetail/BuildDetail")
           },

+ 5 - 4
src/views/login/Login.vue

@@ -33,7 +33,7 @@
     <div style="padding-top: 40px;">
       <button
         :class="{ 'is-loading': submitting }"
-        class="login"
+        class="button login"
         @click="loginAction"
       >
         登 陆
@@ -43,7 +43,7 @@
       <router-link
         :to="{ name: 'REGISTER' }"
         :class="{ 'is-text': true }"
-        class="register"
+        class="button register"
         type="submit"
         >没有账户,注册
       </router-link>
@@ -125,16 +125,17 @@ export default {
 .register {
   color: #7396fd;
   margin-top: 20px;
-  padding: 10px 0px 10px 0px;
+  /*padding: 10px 0px 10px 0px;*/
   font-size: 1rem;
   width: 100%;
   display: flex;
   justify-content: center;
   border: 1px solid #82b1ed;
+  text-decoration: none;
 }
 .login {
   color: #ffffff;
-  padding: 10px 0px 10px 0px;
+  /*padding: 10px 0px 10px 0px;*/
   display: flex;
   justify-content: center;
   font-size: 1rem;

+ 5 - 4
src/views/login/Register.vue

@@ -70,7 +70,7 @@
     <div style="padding-top: 20px;">
       <button
         :class="{ 'is-loading': submitting }"
-        class="register"
+        class="button register"
         @click="registerAction"
       >
         注 册
@@ -80,7 +80,7 @@
     <router-link
       :to="{ name: 'LOGIN' }"
       :class="{ 'is-text': true }"
-      class="login"
+      class="button login"
       type="submit"
       >已有账户,登陆
     </router-link>
@@ -175,7 +175,7 @@ export default {
 }
 .register {
   color: #ffffff;
-  padding: 10px 0 10px 0;
+  /*padding: 10px 0 10px 0;*/
   display: flex;
   justify-content: center;
   font-size: 1rem;
@@ -187,11 +187,12 @@ export default {
 .login {
   color: #7396fd;
   margin-top: 20px;
-  padding: 10px 0 10px 0;
+  /*padding: 10px 0 10px 0;*/
   font-size: 1rem;
   width: 100%;
   display: flex;
   justify-content: center;
   border: 1px solid #82b1ed;
+  text-decoration: none;
 }
 </style>

+ 50 - 3
src/views/student/Code/ProjectDetail/BuildDetail.vue

@@ -1,17 +1,64 @@
 <template>
-  <div><project-build-card v-bind:buildState="1"></project-build-card></div>
+  <div>
+    <div v-if="detailLoading"><page-section-loading show /></div>
+    <div v-else>
+      <div
+        v-for="item in projectDetail.buildList"
+        :key="item.id"
+        class="gap-section"
+      >
+        <div class="page-section">
+          <div class="level">
+            <div class="level-left">
+              <build-tag :build-state="item.buildState" />
+              <strong style="padding-left: 10px">
+                {{ item.commitMessage }} · #{{ item.branchId }}
+              </strong>
+            </div>
+            <div v-if="item.buildState === 1" class="level-right">
+              <strong>mirror : {{ item.mirrorId }}</strong>
+            </div>
+          </div>
+          <div class="code-section">{{ item.buildMessage }}</div>
+        </div>
+      </div>
+    </div>
+  </div>
 </template>
 
 <script>
-import ProjectBuildCard from "@/components/ProjectBuildCard/index";
+import PageSectionLoading from "@/components/PageBody/PageSectionLoading/index";
+import BuildTag from "@/views/student/Code/ProjectDetail/components/BuildTag";
 export default {
   name: "BuildDetail",
-  components: { ProjectBuildCard },
+  components: { BuildTag, PageSectionLoading },
   props: {
     projectDetail: {
       type: Object,
       default: () => {}
+    },
+    detailLoading: {
+      type: Boolean,
+      default: false
     }
   }
 };
 </script>
+
+<style lang="scss" scoped>
+@import "../../../../assets/scss/app";
+.gap-section {
+  padding-bottom: $default-margin-between;
+}
+
+.gap-section:last-child {
+  padding-bottom: 0;
+}
+
+.code-section {
+  margin: $default-margin-between -#{$default-margin-between} -#{$default-margin-between};
+  padding: $default-margin-between;
+  background-color: #2d3044;
+  color: #cacff1;
+}
+</style>

+ 25 - 0
src/views/student/Code/ProjectDetail/components/BuildTag.vue

@@ -0,0 +1,25 @@
+<template>
+  <div style="display: inline-block">
+    <div v-if="buildState === 1" class="tag is-success" style="width: 55px;">
+      <strong style="color: white;">构建成功</strong>
+    </div>
+    <div v-if="buildState === -1" class="tag is-danger" style="width: 55px;">
+      <strong style="color: white;">构建失败</strong>
+    </div>
+    <div v-if="buildState === 0" class="tag" style="width: 55px;">
+      <strong>正在构建</strong>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "BuildTag",
+  props: {
+    buildState: {
+      type: Number,
+      default: 0
+    }
+  }
+};
+</script>

+ 7 - 7
src/views/student/Code/ProjectDetail/index.vue

@@ -1,6 +1,7 @@
 <template>
   <div>
     <page-header
+      :loading="detailLoading"
       :routes="[
         { name: '代码作业', path: 'code' },
         { name: '项目列表', path: `code/${$route.params.homeworkId}` },
@@ -9,9 +10,7 @@
       :tab-list="[
         {
           name: '构建',
-          path: `code/${$route.params.homeworkId}/${
-            $route.params.projectId
-          }/build`
+          path: `code/${$route.params.homeworkId}/${$route.params.projectId}`
         },
         {
           name: '部署',
@@ -27,11 +26,12 @@
         }
       ]"
     >
-      <template slot="title"
-        >项目名称</template
-      >
+      <template slot="title">
+        {{ projectDetail.name }}
+      </template>
       <template slot="content">
-        <div>项目详情</div>
+        <strong>git 地址 : </strong>
+        <a :href="projectDetail.url">{{ projectDetail.url }}</a>
       </template>
     </page-header>
     <page-body>

+ 15 - 7
src/views/student/Code/ProjectList/index.vue

@@ -1,18 +1,23 @@
 <template>
   <div>
     <page-header
+      :loading="projectListLoading"
       :routes="[{ name: '代码作业', path: 'code' }, { name: '项目列表' }]"
     >
-      <template slot="title"
-        >项目列表</template
-      >
-      <template slot="content"
-        >共有 {{ projectList.length }} 个项目</template
-      >
+      <template slot="title">
+        项目列表
+      </template>
+      <template slot="content">
+        共有 {{ projectList.length }} 个项目
+      </template>
     </page-header>
     <page-body>
       <div class="columns is-multiline is-desktop">
+        <div v-if="projectListLoading" class="column is-4-desktop">
+          <card loading />
+        </div>
         <div
+          v-else
           :key="item.projectId"
           v-for="item in projectList"
           class="column is-4"
@@ -45,12 +50,15 @@ export default {
   },
   data() {
     return {
-      projectList: []
+      projectList: [],
+      projectListLoading: false
     };
   },
   async mounted() {
+    this.projectListLoading = true;
     const list = await getProjectList(this.course.id);
     this.projectList = list.data;
+    this.projectListLoading = false;
   }
 };
 </script>

+ 19 - 9
src/views/student/Code/index.vue

@@ -1,19 +1,26 @@
 <template>
   <div>
-    <page-header :routes="[{ name: '代码作业', path: 'code' }]">
-      <template slot="title"
-        >代码作业</template
-      >
-      <template slot="content"
-        >您仍剩余 {{ codeHomeworkList.length }} 份代码作业待完成</template
-      >
+    <page-header
+      :loading="codeHomeworkListLoading"
+      :routes="[{ name: '代码作业', path: 'code' }]"
+    >
+      <template slot="title">
+        代码作业
+      </template>
+      <template slot="content">
+        您仍剩余 {{ codeHomeworkList.length }} 份代码作业待完成
+      </template>
     </page-header>
     <page-body>
       <div class="columns is-multiline is-desktop">
+        <div v-if="codeHomeworkListLoading" class="column is-4-desktop">
+          <card loading />
+        </div>
         <div
+          v-else
           :key="item.homeworkId"
           v-for="item in codeHomeworkList"
-          class="column is-4"
+          class="column is-4-desktop"
         >
           <router-link :to="`${$route.path}/${item.homeworkId}`">
             <card hoverable>{{ item.description }}</card>
@@ -43,12 +50,15 @@ export default {
   },
   data() {
     return {
-      codeHomeworkList: []
+      codeHomeworkList: [],
+      codeHomeworkListLoading: false
     };
   },
   async mounted() {
+    this.codeHomeworkListLoading = true;
     const list = await getCodeHomeworkList(this.course.id);
     this.codeHomeworkList = list.data;
+    this.codeHomeworkListLoading = false;
   }
 };
 </script>

+ 6 - 3
src/views/student/Document/detail.vue

@@ -28,7 +28,9 @@
               <div class="subtitle is-6" v-if="isAvailable">
                 {{ detail.problem ? detail.problem.name : "" }}
               </div>
-              <div class="subtitle is-6" v-else>题目开始进行才可查看</div>
+              <div class="subtitle is-6" v-else>
+                <s>题目开始进行才可查看</s>
+              </div>
             </div>
             <div class="column">
               <h5 class="title is-5">状态:</h5>
@@ -110,8 +112,9 @@ export default {
     getDocResultById(this.assignmentInfo.id).then(res => {
       this.docResult = res.data;
       // 有成绩
-      if (parseInt(this.docResult.result) !== -1) {
-        this.loadingDocResult = true;
+      // 修改为String
+      if (this.docResult.result !== null) {
+        this.loadingDocResult = true; //不显示
       }
     });
   },

+ 165 - 5
src/views/student/Home/index.vue

@@ -2,38 +2,198 @@
   <div>
     <section class="hero">
       <div class="hero-body">
-        <div class="container">
+        <div class="container hint">
           <h1 class="title">我的课程</h1>
           <h2 class="subtitle">展示我加入的全部课程</h2>
+          <img
+            class="newSubject"
+            src="../../../assets/white.png"
+            @click="joinCouseActive = true"
+          />
         </div>
       </div>
     </section>
     <div class="container">
       <div class="columns is-multiline is-desktop">
-        <div :key="item.id" v-for="item in courses" class="column is-4-desktop">
+        <div v-if="isStudentCourseLoading" class="column is-4-desktop">
+          <card loading />
+        </div>
+        <div
+          v-else
+          :key="item.id"
+          v-for="item in courses"
+          class="column is-4-desktop"
+        >
           <router-link :to="`/course-student/${item.id}/dashboard`">
             <card hoverable>{{ item.name }}</card>
           </router-link>
         </div>
       </div>
     </div>
+    <!-- 新建课程模态框 -->
+    <b-modal :active.sync="joinCouseActive" :width="320" scroll="keep">
+      <div class="card">
+        <div class="title">加入课程</div>
+        <div class="content">
+          <b-notification
+            class="notification-self"
+            type="is-danger"
+            :active.sync="isServerError"
+          >
+            {{ errorMassage }}
+          </b-notification>
+          <b-field
+            label="选课码"
+            :type="$v.coursenum.$error ? 'is-danger' : ''"
+            :message="
+              $v.coursenum.$error
+                ? [
+                    !$v.coursenum.minLength ? '选课码不少于4个字符' : undefined,
+                    !$v.coursenum.maxLength
+                      ? '选课码不多于10个字符'
+                      : undefined,
+                    !$v.coursenum.required ? '请填写选课码' : undefined,
+                    !$v.coursenum.alphaNum ? '选课码应为字母或数字' : undefined
+                  ]
+                : ''
+            "
+          >
+            <b-input
+              v-model="$v.coursenum.$model"
+              placeholder="请输入选课码"
+            ></b-input>
+          </b-field>
+          <a
+            :class="['button', 'is-link', { 'is-loading': submitting }]"
+            @click="joinSubject"
+            >加入课程</a
+          >
+        </div>
+      </div>
+    </b-modal>
   </div>
 </template>
 
 <script>
 import Card from "@/components/Card";
-import { getStudentCourses } from "@/api/course";
+import { getStudentCourses, postStudentCourse } from "@/api/course";
+import {
+  required,
+  minLength,
+  maxLength,
+  alphaNum
+} from "vuelidate/lib/validators";
+
 export default {
   components: {
     Card
   },
+  validations: {
+    coursenum: {
+      required,
+      minLength: minLength(4),
+      maxLength: maxLength(10),
+      alphaNum
+    }
+  },
   data() {
     return {
-      courses: []
+      courses: [],
+      joinCouseActive: false,
+      coursenum: "",
+      submitting: false,
+      isServerError: false,
+      errorMassage: "服务器错误,请稍后重试",
+      isStudentCourseLoading: true
     };
   },
   mounted() {
-    getStudentCourses().then(value => (this.courses = value.data));
+    this.getCourses();
+  },
+  methods: {
+    getCourses() {
+      getStudentCourses().then(value => {
+        this.courses = value.data;
+        this.isStudentCourseLoading = false;
+      });
+    },
+    //加入课程
+    joinSubject() {
+      if (this.submitting) return false;
+      this.$v.$touch();
+      if (!this.$v.$invalid) {
+        this.submitting = true;
+        this.isServerError = false;
+        postStudentCourse(this.coursenum)
+          .then(res => {
+            this.submitting = false;
+            this.joinCouseActive = false;
+            this.$toast.open({
+              message: `${res.data.name} 选课成功`,
+              type: "is-success"
+            });
+            this.getCourses();
+          })
+          .catch(e => {
+            this.submitting = false;
+            this.isServerError = true;
+            this.errorMassage = e.message;
+          });
+      }
+    }
   }
 };
 </script>
+<style lang="scss" scoped>
+@import "../../../assets/scss/app";
+.container.hint {
+  padding: 30px 20px 20px 30px;
+  /*background-image: linear-gradient(to right, #6a11cb 0%, #2575fc 100%);*/
+  /*TODO: 寻找质量更高的图片以防止对比度过低 */
+  background-image: url("../../../assets/login_background.png");
+  /*background-size: cover;*/
+  box-shadow: $default-shadow;
+  border-radius: $default-radius;
+  .title {
+    color: #ffffff;
+  }
+  .subtitle {
+    margin-top: -0.8em;
+    font-size: 1rem;
+    font-weight: bold;
+    color: #ffffff;
+  }
+}
+.card {
+  padding: 30px;
+  .title {
+    font-size: 1.25rem;
+    small {
+      color: gray;
+      font-size: 1rem;
+    }
+  }
+  .content {
+    a {
+      margin-top: 30px;
+      width: 100%;
+    }
+  }
+}
+.newSubject {
+  height: 80px;
+  width: 80px;
+  position: absolute;
+  bottom: -40px;
+  left: 20px;
+  transition-property: all;
+  transition-duration: 0.2s;
+
+  &:hover {
+    height: 90px;
+    width: 90px;
+    bottom: -45px;
+    left: 15px;
+  }
+}
+</style>

+ 51 - 24
src/views/teacher/Code/detail.vue

@@ -38,39 +38,55 @@
                   {{ props.row.group.id }}
                 </b-table-column>
                 <b-table-column label="构建" centered>
-                  <span :class="geneTitleAndTag(props.row.buildStatus.key).tag">
-                    {{ geneTitleAndTag(props.row.buildStatus.key).title }}
+                  <span :class="geneTag(props.row.buildStatus.key)">
+                    {{
+                      props.row.buildStatus.key === 0
+                        ? "未构建"
+                        : props.row.buildStatus.key === -1
+                        ? "失败"
+                        : "成功"
+                    }}
                   </span>
                 </b-table-column>
 
                 <b-table-column label="部署" centered>
-                  <span
-                    :class="geneTitleAndTag(props.row.deployStatus.key).tag"
-                  >
-                    {{ geneTitleAndTag(props.row.deployStatus.key).title }}
+                  <span :class="geneTag(props.row.deployStatus.key)">
+                    {{
+                      props.row.deployStatus.key === 0
+                        ? "未部署"
+                        : props.row.deployStatus.key === -1
+                        ? "失败"
+                        : "成功"
+                    }}
                   </span>
                 </b-table-column>
-                <b-table-column label="单元测试">
-                  <span
-                    :class="geneTitleAndTag(props.row.unitTestStatus.key).tag"
-                  >
-                    {{ props.row.unitTestStatus.passCount }}/{{
-                      props.row.unitTestStatus.testCount
+                <b-table-column label="单元测试" centered>
+                  <span :class="geneTag(props.row.unitTestStatus.key)">
+                    {{
+                      props.row.unitTestStatus.key === 0
+                        ? "未测试"
+                        : props.row.unitTestStatus.key === -1
+                        ? "构建失败"
+                        : props.row.unitTestStatus.passCount +
+                          "/" +
+                          props.row.unitTestStatus.testCount
                     }}
                   </span>
                 </b-table-column>
-                <b-table-column label="功能测试">
-                  <span
-                    :class="
-                      geneTitleAndTag(props.row.functionTestStatus.key).tag
-                    "
-                  >
-                    {{ props.row.functionTestStatus.passCount }}/{{
-                      props.row.functionTestStatus.testCount
+                <b-table-column label="功能测试" centered>
+                  <span :class="geneTag(props.row.functionTestStatus.key)">
+                    {{
+                      props.row.functionTestStatus.key === 0
+                        ? "未测试"
+                        : props.row.functionTestStatus.key === -1
+                        ? "未知状态"
+                        : props.row.functionTestStatus.passCount +
+                          "/" +
+                          props.row.functionTestStatus.testCount
                     }}
                   </span>
                 </b-table-column>
-                <b-table-column label="详情">
+                <b-table-column label="详情" centered>
                   <router-link
                     :to="{
                       path: `/course-teacher/:courseId/code/detail/test`,
@@ -117,7 +133,7 @@
                 <b-table-column label="小组名称" centered>
                   {{ props.row.name }}
                 </b-table-column>
-                <b-table-column label="小组成员" centered>
+                <b-table-column label="小组a成员" centered>
                   <span v-for="member in props.row.members" :key="member.id"
                     >{{ member.username }}&emsp;</span
                   >
@@ -168,12 +184,12 @@ export default {
     this.loadingUncommittedGroups = true;
     this.loadingCommittedGroups = true;
     this.assignmentInfo = this.$route.query.assignmentInfo;
-    getCodeProcedureListByCodeId(123).then(res => {
+    getCodeProcedureListByCodeId(this.$route.params.codeId).then(res => {
       this.codeProcedureList = res.data;
       this.submitInfo.yes = "已提交:" + this.codeProcedureList.length;
       this.loadingCommittedGroups = false;
     });
-    getUnsubmittedCodeGroupsList(123).then(res => {
+    getUnsubmittedCodeGroupsList(this.$route.params.codeId).then(res => {
       this.unsubmitedGroups = res.data;
       this.submitInfo.no = "未提交:" + this.unsubmitedGroups.length;
       this.loadingUncommittedGroups = false;
@@ -196,6 +212,17 @@ export default {
     };
   },
   methods: {
+    geneTag(state) {
+      let showTag = "";
+      if (state === -1) {
+        showTag = tag.failed;
+      } else if (state === 0) {
+        showTag = tag.uncommitted;
+      } else {
+        showTag = tag.success;
+      }
+      return showTag;
+    },
     geneTitleAndTag(state) {
       let data = {
         title: "",

+ 1 - 1
src/views/teacher/Document/detail.vue

@@ -57,7 +57,7 @@
                   ><router-link
                     :to="{
                       path: `${$route.path}/content`,
-                      query: { assignId: docId }
+                      query: { groupWorkId: props.row.id }
                     }"
                     >查看详情</router-link
                   >

+ 4 - 4
src/views/teacher/Document/docContent.vue

@@ -6,7 +6,7 @@
         { name: '文档作业', path: 'document' },
         {
           name: `作业详情`,
-          path: `document/${docId}`
+          path: `document/${groupWorkId}`
         },
         { name: `文档内容`, path: `${$route.path}` }
       ]"
@@ -57,7 +57,7 @@ export default {
   },
   data() {
     return {
-      docId: null,
+      groupWorkId: null,
       contentResult: {
         content: "",
         group: "",
@@ -68,11 +68,11 @@ export default {
     };
   },
   created() {
-    this.docId = this.$route.query.assignId;
+    this.groupWorkId = this.$route.query.groupWorkId;
   },
   mounted() {
     this.loadingDocContent = true;
-    getDocContentByDocId(this.docId).then(res => {
+    getDocContentByDocId(this.groupWorkId).then(res => {
       this.contentResult = res.data;
       this.loadingDocContent = false;
     });

+ 64 - 10
src/views/teacher/Home/index.vue

@@ -8,25 +8,35 @@
           <img
             class="newSubject"
             src="../../../assets/white.png"
-            @click="isCardModalActive = true"
+            @click="newSubjectActive = true"
           />
         </div>
       </div>
     </section>
     <div class="container">
       <div class="columns is-multiline is-desktop">
-        <div :key="item.id" v-for="item in courses" class="column is-4">
+        <div v-if="isTeacherCourseLoading" class="column is-4-desktop">
+          <card loading />
+        </div>
+        <div v-else :key="item.id" v-for="item in courses" class="column is-4">
           <router-link :to="`/course-teacher/${item.id}/dashboard`">
             <card hoverable>{{ item.name }}</card>
           </router-link>
         </div>
       </div>
     </div>
-    <!-- 成绩比例调控模态框 -->
-    <b-modal :active.sync="isCardModalActive" :width="320" scroll="keep">
+    <!-- 新建课程模态框 -->
+    <b-modal :active.sync="newSubjectActive" :width="320" scroll="keep">
       <div class="card">
         <div class="title">新建课程</div>
         <div class="content">
+          <b-notification
+            class="notification-self"
+            type="is-danger"
+            :active.sync="isServerError"
+          >
+            {{ errorMassage }}
+          </b-notification>
           <b-field
             label="课程名"
             :type="$v.coursename.$error ? 'is-danger' : ''"
@@ -70,7 +80,11 @@
               placeholder="请输入选课码"
             ></b-input>
           </b-field>
-          <a class="button is-link" @click="isCardModalActive = false">新建</a>
+          <a
+            :class="['button', 'is-link', { 'is-loading': submitting }]"
+            @click="newSubject"
+            >新建</a
+          >
         </div>
       </div>
     </b-modal>
@@ -79,7 +93,7 @@
 
 <script>
 import Card from "@/components/Card";
-import { getTeacherCourses } from "@/api/course";
+import { getTeacherCourses, postTeacherCourse } from "@/api/course";
 import {
   required,
   minLength,
@@ -107,14 +121,55 @@ export default {
   data() {
     return {
       courses: [],
-      isCardModalActive: false,
+      newSubjectActive: false,
       username: "",
       coursename: "",
-      coursenum: ""
+      coursenum: "",
+      submitting: false,
+      isServerError: false,
+      errorMassage: "服务器错误,请稍后再试",
+      isTeacherCourseLoading: true
     };
   },
   mounted() {
-    getTeacherCourses().then(value => (this.courses = value.data));
+    this.getCourses();
+  },
+  methods: {
+    getCourses() {
+      getTeacherCourses().then(value => {
+        this.courses = value.data;
+        this.isTeacherCourseLoading = false;
+      });
+    },
+    //新建课程
+    newSubject() {
+      if (this.submitting) return;
+      this.$v.$touch();
+      if (!this.$v.$invalid) {
+        this.isServerError = false;
+        let subjectInfo = {
+          name: this.coursename,
+          code: this.coursenum
+        };
+        this.submitting = true;
+        postTeacherCourse(subjectInfo)
+          .then(res => {
+            this.submitting = false;
+            this.$toast.open({
+              message: `${res.data.name}创建成功`,
+              type: "is-success"
+            });
+            this.newSubjectActive = false;
+            this.getCourses();
+          })
+          .catch(e => {
+            if (this.errorMassage) {
+              this.errorMassage = e.message;
+            }
+            this.isServerError = true;
+          });
+      }
+    }
   }
 };
 </script>
@@ -122,7 +177,6 @@ export default {
 @import "../../../assets/scss/app";
 .container.hint {
   padding: 30px 20px 20px 30px;
-
   /*background-image: linear-gradient(to right, #6a11cb 0%, #2575fc 100%);*/
   /*TODO: 寻找质量更高的图片以防止对比度过低 */
   background-image: url("../../../assets/login_background.png");

+ 100 - 45
src/views/teacher/Question/index.vue

@@ -1,24 +1,28 @@
 <template>
   <div>
-    <page-header :routes="[{ name: `查看题目`, path: 'question/' }]">
+    <page-header
+      :loading="loadingQuestionList"
+      :routes="[{ name: `查看题目`, path: 'question/' }]"
+    >
       <template slot="title">
         查看题目
       </template>
     </page-header>
     <page-body>
+      <page-section-loading :show="loadingQuestionList" />
       <!-- container面板-->
-      <div class="data-table">
+      <div v-if="!loadingQuestionList" class="data-table">
         <!--下拉框&搜索框-->
         <div class="form-group">
           <!--下拉框-->
           <b-field>
             <b-select placeholder="选择题目类型">
               <option
-                v-for="option in questionType"
-                :value="option.title"
-                :key="option.id"
+                v-for="(option, index) in questionType"
+                :value="option"
+                :key="index"
               >
-                {{ option.title }}
+                {{ option }}
               </option>
             </b-select>
           </b-field>
@@ -29,19 +33,15 @@
               placeholder="输入关键字查找题目"
               type="search"
               icon="magnify"
+              v-model="keyWord"
             >
             </b-input>
-            <p class="control"><button class="button is-link">查找</button></p>
+            <p class="control">
+              <button class="button is-link" @click="getQuestionsByKey()">
+                查找
+              </button>
+            </p>
           </b-field>
-
-          <!--<b-field>-->
-          <!--<b-input-->
-          <!--placeholder="输入关键字查找题目"-->
-          <!--type="search"-->
-          <!--icon="magnify"-->
-          <!--&gt;-->
-          <!--</b-input>-->
-          <!--</b-field>-->
         </div>
         <!--题目table-->
         <div class="question-list">
@@ -55,7 +55,10 @@
                 <router-link
                   :to="{
                     path: `${props.row.id}`,
-                    query: { questionName: props.row.name }
+                    query: {
+                      questionName: props.row.name,
+                      questionId: props.row.id
+                    }
                   }"
                   >{{ props.row.name }}</router-link
                 >
@@ -80,11 +83,11 @@
 
               <b-table-column
                 label="平均时长"
-                field="expectTime"
+                field="expect_time"
                 sortable
                 centered
               >
-                {{ props.row.expectTime }}分钟
+                {{ props.row.expect_time }}分钟
               </b-table-column>
             </template>
 
@@ -94,22 +97,27 @@
                   <div class="content">
                     <p class="detail-content">
                       <strong>{{ props.row.name }}</strong>
-                      <small
-                        ><b-tag type="is-info"
-                          >{{ props.row.expectTime }}分钟</b-tag
-                        ></small
-                      >
-                      <small
-                        ><b-tag
+                      <small v-show="props.row.expect_time">
+                        <b-tag type="is-info"
+                          >{{ props.row.expect_time }}分钟</b-tag
+                        >
+                      </small>
+                      <small v-show="props.row.difficulty">
+                        <b-tag
                           :type="`${difficultyClass(props.row.difficulty)}`"
                           >{{ difficultyType(props.row.difficulty) }}</b-tag
-                        ></small
-                      >
-                      <small
-                        ><b-tag type="is-link">{{
-                          props.row.assignmentType.value
-                        }}</b-tag></small
-                      >
+                        >
+                      </small>
+                      <small v-show="props.row.assignmentType">
+                        <b-tag type="is-link">{{
+                          props.row.assignmentType
+                        }}</b-tag>
+                      </small>
+                      <small v-show="props.row.questionType">
+                        <b-tag type="is-primary">{{
+                          props.row.questionType
+                        }}</b-tag>
+                      </small>
                       <br /><br />
                       {{ props.row.description }}
                     </p>
@@ -125,15 +133,20 @@
 </template>
 <script>
 import { mapState } from "vuex";
-import { getStudentCourseReviewList } from "@/api/review";
-import { getTeacherQuestions } from "@/api/question";
+import {
+  getQuestionsByAssignType,
+  getTeacherQuestionType,
+  getTeacherKeywordQuestions
+} from "@/api/question";
 import PageHeader from "@/components/PageHeader";
 import PageBody from "@/components/PageBody/index";
+import PageSectionLoading from "@/components/PageBody/PageSectionLoading/index";
 
 export default {
   components: {
     PageHeader,
-    PageBody
+    PageBody,
+    PageSectionLoading
   },
   computed: {
     ...mapState({
@@ -144,20 +157,62 @@ export default {
     return {
       courses: [],
       review: [],
-      questionType: [
-        { id: 1, title: "文档作业题目" },
-        { id: 2, title: "代码作业题目" }
-      ],
-      data: []
+      questionType: [],
+      data: [],
+      keyWord: "",
+      errorMessage: "服务器错误,请稍后再试",
+      loadingQuestionList: true
     };
   },
   mounted() {
-    getStudentCourseReviewList(this.courses.id).then(
-      value => (this.review = value.data)
-    );
-    getTeacherQuestions().then(value => (this.data = value.data));
+    //获取全部题目分类
+    this.getQuestionType();
+    //获取全部题目
+    this.getQuestions();
+
+    this.loadingQuestionList = false;
   },
   methods: {
+    //获取全部题目分类
+    getQuestionType() {
+      getTeacherQuestionType()
+        .then(value => {
+          this.questionType = value.data;
+        })
+        .catch(e => {
+          this.$toast.open({
+            message: e.message,
+            type: "is-link"
+          });
+        });
+    },
+    //获取全部题目
+    getQuestions() {
+      getQuestionsByAssignType({ type: "DOCUMENT", page: 0, limit: 10 })
+        .then(value => {
+          // this.data = value.res.content;
+          this.data = value.data;
+        })
+        .catch(e => {
+          this.$toast.open({
+            message: e.message,
+            type: "is-danger"
+          });
+        });
+    },
+    //根据关键字查找题目
+    getQuestionsByKey() {
+      getTeacherKeywordQuestions(this.keyWord)
+        .then(value => {
+          this.data = value.data;
+        })
+        .catch(e => {
+          this.$toast.open({
+            message: e.message || this.errorMessage,
+            type: "is-danger"
+          });
+        });
+    },
     difficultyType: level => {
       switch (level) {
         case 1:

+ 38 - 26
src/views/teacher/Question/questionDetail.vue

@@ -1,6 +1,7 @@
 <template>
   <div>
     <page-header
+      :loading="isQuestionDetailLoading"
       :routes="[
         { name: '查看题目', path: 'question/' },
         { name: `${questionName}`, path: `question/123` }
@@ -19,30 +20,35 @@
       </template>
     </page-header>
     <page-body>
-      <div class="data-table">
-        <div class="question-description">
-          <div class="subtitle">题目描述</div>
-          <div class="question-content">{{ questionInfo.description }}</div>
-        </div>
-        <div class="question-description">
-          <div class="subtitle">预计完成时间</div>
-          <div class="question-content">{{ questionInfo.expectTime }}分钟</div>
-        </div>
-        <div class="question-description">
-          <div class="subtitle">题目难度</div>
-          <div class="question-content">
-            {{ difficultyType(questionInfo.difficulty) }}
+      <page-section-loading :show="isQuestionDetailLoading" />
+      <div v-if="!isQuestionDetailLoading" class="data-table">
+        <div>
+          <div class="question-description">
+            <div class="subtitle">题目描述</div>
+            <div class="question-content">{{ questionInfo.description }}</div>
           </div>
-        </div>
-        <div class="question-description">
-          <div class="subtitle">文件信息</div>
-          <div class="question-content">
-            <div
-              class="file-info"
-              v-for="(item, index) in questionInfo.file"
-              :key="index"
-            >
-              <a>{{ item.filename }}</a>
+          <div class="question-description">
+            <div class="subtitle">预计完成时间</div>
+            <div class="question-content">
+              {{ questionInfo.expectTime }}分钟
+            </div>
+          </div>
+          <div class="question-description">
+            <div class="subtitle">题目难度</div>
+            <div class="question-content">
+              {{ difficultyType(questionInfo.difficulty) }}
+            </div>
+          </div>
+          <div class="question-description">
+            <div class="subtitle">文件信息</div>
+            <div class="question-content">
+              <div
+                class="file-info"
+                v-for="(item, index) in questionInfo.file"
+                :key="index"
+              >
+                <a>{{ item.filename }}</a>
+              </div>
             </div>
           </div>
         </div>
@@ -54,23 +60,29 @@
 import PageHeader from "@/components/PageHeader";
 import PageBody from "@/components/PageBody/index";
 import { getQuestionDetail } from "@/api/question";
+import PageSectionLoading from "@/components/PageBody/PageSectionLoading/index";
 
 export default {
   components: {
     PageBody,
-    PageHeader
+    PageHeader,
+    PageSectionLoading
   },
   mounted() {
     this.questionName = this.$route.query.questionName;
-    getQuestionDetail(234).then(res => {
+    this.questionId = this.$route.query.questionId;
+    getQuestionDetail(this.questionId).then(res => {
       console.log(res.data);
       this.questionInfo = res.data;
+      this.isQuestionDetailLoading = false;
     });
   },
   data() {
     return {
       questionName: "",
-      questionInfo: {}
+      questionInfo: {},
+      questionId: "",
+      isQuestionDetailLoading: true
     };
   },
   methods: {

+ 36 - 25
src/views/teacher/Result/index.vue

@@ -1,13 +1,17 @@
 <template>
   <div>
-    <page-header :routes="[{ name: '成绩管理', path: 'result/' }]">
+    <page-header
+      :loading="isResultLoading"
+      :routes="[{ name: '成绩管理', path: 'result/' }]"
+    >
       <template slot="title">
         全部作业成绩
       </template>
     </page-header>
     <page-body>
+      <page-section-loading :show="isResultLoading" />
       <!-- container面板-->
-      <div class="data-table">
+      <div v-show="!isResultLoading" class="data-table">
         <!--下拉框&搜索框-->
         <div class="form-group">
           <!--下拉框-->
@@ -166,7 +170,9 @@
             </div>
           </div>
         </div>
-        <a class="button is-link" @click="isCardModalActive = false"
+        <a
+          :class="['button', 'is-link', { 'is-loading': submitting }]"
+          @click="confirmPercent"
           >确认调整</a
         >
       </div>
@@ -175,19 +181,20 @@
 </template>
 <script>
 import { mapState } from "vuex";
-// import { getStudentCourseReviewList } from "@/api/review";
 import PageHeader from "@/components/PageHeader";
 import PageBody from "@/components/PageBody/index";
 import Chart from "chart.js";
 import BInput from "buefy/src/components/input/Input";
 import { required, numeric, between } from "vuelidate/lib/validators";
 import { getStudentFinaleResult } from "@/api/resultstatistics";
+import PageSectionLoading from "@/components/PageBody/PageSectionLoading/index";
 
 export default {
   components: {
     BInput,
     PageHeader,
-    PageBody
+    PageBody,
+    PageSectionLoading
   },
   validations: {
     percent: {
@@ -206,15 +213,15 @@ export default {
       name: "",
       courses: [],
       review: [],
-      questionType: [
-        { id: 1, title: "文档作业题目" },
-        { id: 2, title: "代码作业题目" }
-      ],
       data: [],
       isCardModalActive: false,
       myChart2: {},
       percent: "",
-      finalResultPercentage: [20, 20, 20, 10, 10, 10, 10]
+      finalResultPercentage: [20, 20, 20, 10, 10, 10, 10],
+      submitting: false,
+      isServerError: false,
+      errorMessage: "服务器错误,请稍后重试",
+      isResultLoading: true
     };
   },
   methods: {
@@ -256,6 +263,13 @@ export default {
         currentIndex++;
       }
       return parseInt(finalRes);
+    },
+    confirmPercent() {
+      this.submitting = true;
+      this.$toast.open({
+        message: "成绩比例调整成功",
+        type: "is-success"
+      });
     }
   },
   mounted() {
@@ -263,19 +277,22 @@ export default {
     getStudentFinaleResult(this.courses.id).then(res => {
       console.log(res.data);
       this.data = res.data;
+      this.isResultLoading = false;
     });
     //绘制图表
-    var resultChart = document.getElementById("result-chart");
-    var myChart2 = new Chart(resultChart, {
+    let resultChart = document.getElementById("result-chart");
+    let myChart2 = new Chart(resultChart, {
       type: "bar",
       data: {
         labels: [
-          "0-30分段",
-          "30-60分段",
-          "60-70分段",
-          "70-80分段",
-          "80-90分段",
-          "90-100分段"
+          "0分",
+          "1-29分",
+          "30-59分段",
+          "60-69分段",
+          "70-79分段",
+          "80-89分段",
+          "90-99分段",
+          "100分"
         ],
         datasets: [
           {
@@ -285,7 +302,7 @@ export default {
             borderWidth: 1,
             pointStrokeColor: "#fff",
             pointStyle: "crossRot",
-            data: [6, 10, 34, 50, 80, 30],
+            data: [2, 6, 10, 34, 50, 80, 30, 2],
             cubicInterpolationMode: "monotone",
             spanGaps: "false",
             fill: "false"
@@ -303,12 +320,6 @@ export default {
   /*color: #7957d5;*/
   font-weight: bold;
 }
-/*.data-table {*/
-/*width: 100%;*/
-/*padding: 30px;*/
-/*!*min-height: 80vh;*!*/
-/*background-color: #ffffff;*/
-/*}*/
 .chart {
   margin-top: 1.5rem;
 }

+ 72 - 54
src/views/teacher/Review/ReviewDetail/Detail/index.vue

@@ -1,67 +1,80 @@
 <template>
   <div>
-    <div class="page-section">
-      <div class="columns is-desktop">
-        <div class="column">
-          <h5 class="title is-5">id:</h5>
-          <div class="subtitle is-6">{{ detail.reviewId }}</div>
-        </div>
-        <div class="column">
-          <h5 class="title is-5">名称:</h5>
-          <div class="subtitle is-6">{{ detail.name }}</div>
-        </div>
-        <div class="column">
-          <h5 class="title is-5">状态:</h5>
-          <div class="subtitle is-6">
-            <review-state-tag :state="detail.state" />
-          </div>
+    <div v-if="detailLoading">
+      <page-section-loading show />
+      <div class="space">
+        <div class="columns is-desktop">
+          <div class="column"><page-section-loading show /></div>
+          <div class="column"><page-section-loading show /></div>
         </div>
       </div>
-      <div class="columns is-desktop">
-        <div class="column">
-          <h5 class="title is-5">互评结束时间:</h5>
-          <div class="subtitle is-6">
-            {{ displayUnixTime(detail.reviewDdl) }}
+    </div>
+    <div v-else>
+      <div class="page-section">
+        <div class="columns is-desktop">
+          <div class="column">
+            <h5 class="title is-5">id:</h5>
+            <div class="subtitle is-6">{{ detail.reviewId }}</div>
           </div>
-        </div>
-        <div class="column">
-          <h5 class="title is-5">重申申请结束时间:</h5>
-          <div class="subtitle is-6">
-            {{ displayUnixTime(detail.argueDdl) }}
+          <div class="column">
+            <h5 class="title is-5">名称:</h5>
+            <div class="subtitle is-6">{{ detail.name }}</div>
+          </div>
+          <div class="column">
+            <h5 class="title is-5">状态:</h5>
+            <div class="subtitle is-6">
+              <review-state-tag :state="detail.state" />
+            </div>
           </div>
         </div>
-        <div class="column">
-          <h5 class="title is-5">重申结束时间:</h5>
-          <div class="subtitle is-6">{{ displayUnixTime(detail.endDdl) }}</div>
+        <div class="columns is-desktop">
+          <div class="column">
+            <h5 class="title is-5">互评结束时间:</h5>
+            <div class="subtitle is-6">
+              {{ displayUnixTime(detail.reviewDdl) }}
+            </div>
+          </div>
+          <div class="column">
+            <h5 class="title is-5">重申申请结束时间:</h5>
+            <div class="subtitle is-6">
+              {{ displayUnixTime(detail.argueDdl) }}
+            </div>
+          </div>
+          <div class="column">
+            <h5 class="title is-5">重申结束时间:</h5>
+            <div class="subtitle is-6">
+              {{ displayUnixTime(detail.endDdl) }}
+            </div>
+          </div>
         </div>
       </div>
-    </div>
-    <div class="space">
-      <div class="columns is-desktop">
-        <div class="column">
-          <div class="page-section">
-            <h5 class="title is-5">完成率: {{ sum.completeRate }}%</h5>
-            <progress
-              class="progress is-success"
-              :value="sum.completeRate"
-              max="100"
-              >{sum.completeRate}%</progress
-            >
+      <div class="space">
+        <div class="columns is-desktop">
+          <div class="column">
+            <div class="page-section">
+              <h5 class="title is-5">完成率: {{ sum.completeRate }}%</h5>
+              <progress
+                class="progress is-success"
+                :value="sum.completeRate"
+                max="100"
+                >{sum.completeRate}%</progress
+              >
+            </div>
           </div>
-        </div>
-        <div class="column">
-          <div class="page-section">
-            <h5 class="title is-5">checkList 通过情况:</h5>
-            <div
-              class="checklist-item"
-              :key="item.id"
-              v-for="item in sum.checklistItems"
-            >
-              <div>id: {{ item.id }}</div>
-              <b-tag type="is-success" style="margin-right: 5px"
-                >通过 : {{ item.passedNum }}</b-tag
+          <div class="column">
+            <div class="page-section">
+              <h5 class="title is-5">checkList 通过情况:</h5>
+              <div
+                class="checklist-item"
+                :key="item.id"
+                v-for="item in sum.checklistItems"
               >
-              <span>{{ item.content }}</span>
+                <div>id: {{ item.id }}</div>
+                <b-tag type="is-success" style="margin-right: 5px"
+                  >通过 : {{ item.passedNum }}</b-tag
+                >
+                <span>{{ item.content }}</span>
+              </div>
             </div>
           </div>
         </div>
@@ -74,13 +87,18 @@
 import ReviewStateTag from "@/components/ReviewStateTag/index";
 import timeMixins from "@/mixins/time";
 import { getTeacherReviewResult } from "@/api/review";
+import PageSectionLoading from "@/components/PageBody/PageSectionLoading/index";
 export default {
-  components: { ReviewStateTag },
+  components: { PageSectionLoading, ReviewStateTag },
   mixins: [timeMixins],
   props: {
     detail: {
       type: Object,
       default: () => ({ completeRate: 0 })
+    },
+    detailLoading: {
+      type: Boolean,
+      default: false
     }
   },
   data() {

+ 19 - 5
src/views/teacher/Review/ReviewDetail/GroupDocDetail/index.vue

@@ -1,6 +1,7 @@
 <template>
   <div>
     <page-header
+      :loading="groupDetailLoading"
       :routes="[
         { name: '互评作业', path: 'review' },
         { name: '文档详情', path: `review/${$route.params.reviewId}` },
@@ -24,7 +25,8 @@
     <page-body>
       <div class="columns">
         <div class="column is-8">
-          <div class="page-section">
+          <div v-if="detailLoading"><page-section-loading show /></div>
+          <div v-else class="page-section">
             <div v-if="detail.docContent" class="content">
               <vue-markdown>{{ detail.docContent }}</vue-markdown>
             </div>
@@ -32,7 +34,9 @@
         </div>
         <div class="column is-4">
           <div class="right-part">
+            <div v-if="detailLoading"><page-section-loading show /></div>
             <result-check-list-item
+              v-else
               v-for="item in detail.checkListResult"
               :key="item.id"
               :check-result-item="item"
@@ -51,8 +55,10 @@ import ResultCheckListItem from "@/components/CheckList/ResultCheckListItem";
 import PageHeader from "@/components/PageHeader";
 import PageBody from "@/components/PageBody/index";
 import { getGroupDetail } from "@/api/group";
+import PageSectionLoading from "@/components/PageBody/PageSectionLoading/index";
 export default {
   components: {
+    PageSectionLoading,
     PageBody,
     PageHeader,
     ResultCheckListItem,
@@ -64,17 +70,25 @@ export default {
         review: {},
         checkListResult: []
       },
+      detailLoading: false,
       groupDetail: {},
+      groupDetailLoading: false,
       submitLoading: false
     };
   },
   mixins: [timeMixins],
   mounted() {
     const { reviewId, groupId } = this.$route.params;
-    getGroupDetail(groupId).then(value => (this.groupDetail = value.data));
-    getTeacherReviewGroupDetail(reviewId, groupId).then(
-      resp => (this.detail = resp.data)
-    );
+    this.detailLoading = true;
+    this.groupDetailLoading = true;
+    getGroupDetail(groupId).then(value => {
+      this.groupDetail = value.data;
+      this.groupDetailLoading = false;
+    });
+    getTeacherReviewGroupDetail(reviewId, groupId).then(resp => {
+      this.detail = resp.data;
+      this.detailLoading = false;
+    });
   }
 };
 </script>

+ 8 - 0
src/views/teacher/Review/ReviewDetail/Groups/index.vue

@@ -5,7 +5,11 @@
       </b-input>
     </div>
     <div class="columns is-multiline is-desktop">
+      <div v-if="groupsLoading" class="column is-4-desktop">
+        <card loading />
+      </div>
       <div
+        v-else
         :key="item.id"
         v-for="item in availableGroups"
         class="column is-4-desktop"
@@ -28,6 +32,10 @@ export default {
     groups: {
       type: Array,
       default: () => []
+    },
+    groupsLoading: {
+      type: Boolean,
+      default: false
     }
   },
   data() {

+ 21 - 3
src/views/teacher/Review/ReviewDetail/index.vue

@@ -1,6 +1,7 @@
 <template>
   <div>
     <page-header
+      :loading="detailLoading"
       :routes="[{ name: '互评作业', path: 'review' }, { name: '文档详情' }]"
       :tab-list="[
         { name: '作业详情', path: `review/${$route.params.reviewId}` },
@@ -30,7 +31,14 @@
         </div>
       </template>
     </page-header>
-    <page-body> <router-view :detail="detail" :groups="groups" /> </page-body>
+    <page-body>
+      <router-view
+        :detail="detail"
+        :groups="groups"
+        :detail-loading="detailLoading"
+        :groups-loading="groupsLoading"
+      />
+    </page-body>
     <b-modal :active.sync="showModal" :width="400">
       <div class="card">
         <div class="title">每个等级通过数字</div>
@@ -80,7 +88,9 @@ export default {
   data() {
     return {
       detail: {},
+      detailLoading: false,
       groups: [],
+      groupsLoading: false,
       showModal: false,
       grade: {
         A: 0,
@@ -96,8 +106,16 @@ export default {
   mixins: [timeMixins],
   mounted() {
     const { reviewId } = this.$route.params;
-    getTeacherReviewDetail(reviewId).then(resp => (this.detail = resp.data));
-    getTeacherReviewAllGroups(reviewId).then(resp => (this.groups = resp.data));
+    this.detailLoading = true;
+    this.groupsLoading = true;
+    getTeacherReviewDetail(reviewId).then(resp => {
+      this.detail = resp.data;
+      this.detailLoading = false;
+    });
+    getTeacherReviewAllGroups(reviewId).then(resp => {
+      this.groups = resp.data;
+      this.groupsLoading = false;
+    });
   },
   methods: {
     async submit() {

+ 14 - 2
src/views/teacher/Review/index.vue

@@ -1,6 +1,9 @@
 <template>
   <div>
-    <page-header :routes="[{ name: '互评作业', path: 'review' }]">
+    <page-header
+      :loading="reviewListLoading"
+      :routes="[{ name: '互评作业', path: 'review' }]"
+    >
       <template slot="title">
         互评作业
       </template>
@@ -15,7 +18,15 @@
     </page-header>
     <page-body>
       <div class="columns is-multiline is-desktop">
-        <div :key="item.id" v-for="item in review" class="column is-4-desktop">
+        <div v-if="reviewListLoading" class="column is-4-desktop">
+          <card loading />
+        </div>
+        <div
+          v-else
+          :key="item.id"
+          v-for="item in review"
+          class="column is-4-desktop"
+        >
           <router-link :to="`${$route.path}/${item.reviewId}`">
             <card hoverable>
               {{ item.name }}
@@ -144,6 +155,7 @@ export default {
     return {
       courses: [],
       review: [],
+      reviewListLoading: false,
       showModal: false,
       submitting: false,
       docHomework: [],

+ 1 - 0
vue.config.js

@@ -3,6 +3,7 @@ module.exports = {
     proxy: {
       "^/api": {
         target: "http://localhost:4000/",
+        // target: "http://10.1.2.2:8080/",
         ws: true,
         changeOrigin: true
       }