Bläddra i källkod

Merge remote-tracking branch 'origin/develop' into hotfix/bay

# Conflicts:
#	vue.config.js
kunduin 7 år sedan
förälder
incheckning
a7f02c00c8

+ 1 - 0
mock/serializers/assignment/DocumentContentSerializer.js

@@ -12,6 +12,7 @@ module.exports = () => {
     id: makeId(),
     name: "购物车web项目",
     group: groupSerializer(),
+    result: "A",
     lastUpdateAt: dayjs("2018-10-21").unix(),
     content: makeLongMarkdown()
   };

+ 1 - 1
mock/serializers/assignment/DocumentResultSerializer.js

@@ -24,6 +24,6 @@ module.exports = () => {
     state: "互评中",
     result: "A",
     url: "https://github.com",
-    reviewGroup: [1, 2, 3]
+    reviewGroup: [groupSerializer(), groupSerializer(), groupSerializer()] //不显示,防止学生之间讨论
   };
 };

+ 0 - 18
src/api/assignment.js

@@ -98,15 +98,6 @@ export const getCodeAssignmentByStu = codeId => {
   return request(`${ASSIGNMENT_MODULE}/student/code/${codeId}`);
 };
 
-/**
- * 学生查看单个代码作业下的项目信息列表
- * @param codeId
- * @returns {Promise<{data:ProjectSerializerType}>}
- */
-export const getProjectListByCode = codeId => {
-  return request(`${ASSIGNMENT_MODULE}/student/code/${codeId}/project`);
-};
-
 /**
  * 学生查看单个代码作业下的成绩
  * @param codeId
@@ -138,15 +129,6 @@ export const getUnsubmittedCodeGroupsList = codeId => {
   );
 };
 
-/**
- * 老师查看单个代码作业的成绩列表(所有组的)
- * @param codeId
- * @returns {Promise<{data:CodeResultSerializerType}>}
- */
-export const getCodeResultListByCode = codeId => {
-  return request(`${ASSIGNMENT_MODULE}/teacher/code/${codeId}/result`);
-};
-
 /* 文档作业*/
 /**
  * 老师新建文档作业

+ 36 - 2
src/api/question.js

@@ -30,13 +30,47 @@ export const getQuestionByQuesType = ({ type, page, limit }) => {
     }&limit=${limit || 10}`
   );
 };
+
+/**
+ * 根据关键字及问题分类进行查找
+ * @param {string} keyword
+ * @param {string} type
+ * @returns {Promise<{data:QuestionSerializer[]}>}
+ */
+export const getTeacherKeywordQuestionsByType = (keyword = "", type = "") => {
+  return request(
+    `${QUESTION_MODULE}/teacher/keyword?keyword=${keyword}&type=${type}`
+  );
+};
+
+/**
+ * 根据关键字及问题分类进行查找
+ * @param {string} keyword
+ * @param {string} type
+ * @returns {Promise<{data:QuestionSerializer[]}>}
+ */
+export const getTeacherKeywordQuestionsByCode = (
+  keyword = "123",
+  type = "CODE"
+) => {
+  return request(
+    `${QUESTION_MODULE}/teacher/keyword?keyword=${keyword}&type=${type}`
+  );
+};
+
 /**
  * 根据关键字进行查找
  * @param {string} keyword
+ * @param {string} type
  * @returns {Promise<{data:QuestionSerializer[]}>}
  */
-export const getTeacherKeywordQuestions = (keyword = "123") => {
-  return request(`${QUESTION_MODULE}/teacher/keyword?keyword=${keyword}`);
+export const getTeacherKeywordQuestionsByDoc = (
+  keyword = "123",
+  type = "DOCUMENT"
+) => {
+  return request(
+    `${QUESTION_MODULE}/teacher/keyword?keyword=${keyword}&type=${type}`
+  );
 };
 
 /**

+ 77 - 52
src/components/AssignmentCRUD/CreateAssignment/index.vue

@@ -105,67 +105,73 @@
       <b-notification type="is-danger" :active.sync="isServerError">
         {{ errorMassage }}
       </b-notification>
-      <div class="card">
-        <div class="title">选择题目</div>
-        <div class="content">
-          <div class="question-list">
-            <b-table :data="questions" detailed detail-key="id">
-              <template slot-scope="props">
-                <b-table-column
-                  field="id"
-                  label="ID"
-                  width="40"
-                  numeric
-                  sortable
-                >
-                  {{ props.row.id }}
-                </b-table-column>
-                <b-table-column label="题目名称">
-                  <a @click="selectAndCreate(props.row)">{{
-                    props.row.name
-                  }}</a>
-                </b-table-column>
-                <b-table-column label="题目描述" width="100">
-                  <div class="description">{{ props.row.description }}</div>
-                </b-table-column>
-                <b-table-column
-                  field="difficulty"
-                  label="题目难度"
-                  sortable
-                  centered
-                >
-                  <span
-                    :class="[
-                      'tag',
-                      `${getDifficultyClass(props.row.difficulty)}`
-                    ]"
+      <div>
+        <div class="card" v-if="isAnyQuestion">
+          <div class="title">选择题目</div>
+          <div class="content">
+            <div class="question-list">
+              <b-table :data="questions" detailed detail-key="id">
+                <template slot-scope="props">
+                  <b-table-column
+                    field="id"
+                    label="ID"
+                    width="40"
+                    numeric
+                    sortable
                   >
-                    {{ getDifficultyType(props.row.difficulty) }}
-                  </span>
-                </b-table-column>
+                    {{ props.row.id }}
+                  </b-table-column>
+                  <b-table-column label="题目名称">
+                    <a @click="selectAndCreate(props.row)">{{
+                      props.row.name
+                    }}</a>
+                  </b-table-column>
+                  <b-table-column label="题目描述" width="100">
+                    <div class="description">{{ props.row.description }}</div>
+                  </b-table-column>
+                  <b-table-column
+                    field="difficulty"
+                    label="题目难度"
+                    sortable
+                    centered
+                  >
+                    <span
+                      :class="[
+                        'tag',
+                        `${getDifficultyClass(props.row.difficulty)}`
+                      ]"
+                    >
+                      {{ getDifficultyType(props.row.difficulty) }}
+                    </span>
+                  </b-table-column>
 
-                <b-table-column
-                  label="平均时长"
-                  field="expectTime"
-                  sortable
-                  centered
-                >
-                  {{ props.row.expectTime }}分钟
-                </b-table-column>
-              </template>
-              <template slot="detail" slot-scope="props">
-                <div>{{ props.row.description }}</div>
-              </template>
-            </b-table>
+                  <b-table-column
+                    label="平均时长"
+                    field="expectTime"
+                    sortable
+                    centered
+                  >
+                    {{ props.row.expectTime }}分钟
+                  </b-table-column>
+                </template>
+                <template slot="detail" slot-scope="props">
+                  <div>{{ props.row.description }}</div>
+                </template>
+              </b-table>
+            </div>
           </div>
         </div>
+        <div class="card" v-else>
+          没有查找到题目,请<a @click="reResearch()">重新查找</a>
+        </div>
       </div>
     </b-modal>
   </div>
 </template>
 
 <script>
-import { getTeacherKeywordQuestions } from "@/api/question";
+import { getTeacherKeywordQuestionsByCode } from "@/api/question";
+import { getTeacherKeywordQuestionsByDoc } from "@/api/question";
 import { postDocAssignment } from "@/api/assignment";
 import { postCodeAssignment } from "@/api/assignment";
 import timeMixins from "@/mixins/time";
@@ -206,6 +212,7 @@ export default {
       problemName: "",
       searchContent: "",
       questions: [],
+      isAnyQuestion: false,
 
       // 控制modal活动
       isCreateModalActive: false,
@@ -250,11 +257,20 @@ export default {
         this.loadingSearchQuestions = true;
         this.submitting = true;
         try {
-          getTeacherKeywordQuestions(content).then(res => {
+          let questionPromise = null;
+          if (this.assignType === 1) {
+            questionPromise = getTeacherKeywordQuestionsByDoc(content);
+          } else {
+            questionPromise = getTeacherKeywordQuestionsByCode(content);
+          }
+          questionPromise.then(res => {
             this.questions = res.data;
             this.isSearchModalActive = false;
             this.loadingSearchQuestions = false;
             this.isProblemListModalActive = true;
+            if (this.questions.length !== 0) {
+              this.isAnyQuestion = true;
+            }
           });
         } catch (e) {
           this.errorMassage = e.message;
@@ -270,6 +286,15 @@ export default {
       this.isProblemListModalActive = false;
       this.isCreateModalActive = true;
     },
+
+    /**
+     * 重新查找
+     */
+    reResearch() {
+      this.isProblemListModalActive = false;
+      this.isSearchModalActive = true;
+    },
+
     /**
      * 确认新建
      */

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

@@ -1,9 +1,5 @@
 <template>
-  <div>
-    <a style="color:#b34141" @click="confirmDelete(this)" disabled="true"
-      >删除</a
-    >
-  </div>
+  <div><a style="color:#827b7b">删除</a></div>
 </template>
 
 <script>
@@ -26,14 +22,7 @@ export default {
     };
   },
   methods: {
-    confirmDelete(obj) {
-      if (obj.disabled) {
-        return false;
-      } else {
-        this.doDelete();
-      }
-    },
-    doDelete() {
+    confirmDelete() {
       if (this.submitting) return;
       this.submitting = true;
       this.$dialog.confirm({

+ 3 - 18
src/components/AssignmentCRUD/UpdateAssignment/index.vue

@@ -27,26 +27,11 @@
               v-model="$v.params.description.$model"
             ></b-input>
           </b-field>
-          <!--<b-field-->
-          <!--label="开始时间"-->
-          <!--:type="$v.params.startAt.$error ? 'is-danger' : ''"-->
-          <!--:message="$v.params.startAt.$error ? '请填写作业开始时间' : ''"-->
-          <!--&gt;-->
-          <!--<flat-pickr-->
-          <!--placeholder="Click to select..."-->
-          <!--class="input"-->
-          <!--v-model="$v.params.startAt.$model"-->
-          <!--:config="startAtConfig"-->
-          <!--&gt;</flat-pickr>-->
-          <!--</b-field>          -->
           <b-field label="开始时间">
-            <button
-              class="button is-fullwidth"
+            <b-input
               disabled
-              style="text-align: left"
-            >
-              {{ displayUnixTime(params.startAt) }}
-            </button>
+              :value="displayUnixTime(params.startAt)"
+            ></b-input>
           </b-field>
           <b-field
             label="结束时间"

+ 29 - 2
src/router/routes.js

@@ -85,8 +85,35 @@ export default [
         component: () => import("@/views/teacher/Code/detail")
       },
       {
-        path: "code/:codeId/test/:testId",
-        component: () => import("@/views/teacher/Code/test")
+        path: "code/:homeworkId/:projectId",
+        component: () => import("@/views/teacher/Code/test"),
+        children: [
+          {
+            path: "",
+            component: () =>
+              import("@/views/student/Code/ProjectDetail/BuildDetail")
+          },
+          {
+            path: "deploy",
+            component: () =>
+              import("@/views/student/Code/ProjectDetail/DeployDetail")
+          },
+          {
+            path: "test",
+            component: () =>
+              import("@/views/student/Code/ProjectDetail/TestDetail")
+          }
+        ]
+      },
+      {
+        path: "code/:homeworkId/:projectId/test/unit/:unitTestId",
+        component: () =>
+          import("@/views/student/Code/ProjectDetail/Test/UnitTestDetail")
+      },
+      {
+        path: "code/:homeworkId/:projectId/test/functional/:functionalTestId",
+        component: () =>
+          import("@/views/student/Code/ProjectDetail/Test/FunctionalTestDetail")
       },
 
       {

+ 2 - 2
src/views/login/Login.vue

@@ -65,7 +65,7 @@ export default {
       username: "",
       password: "",
       submitting: false,
-      errorMassage: null,
+      errorMassage: "登录失败",
       isServerError: false
     };
   },
@@ -99,7 +99,7 @@ export default {
           this.$store.commit(SET_PROFILE, data);
           this.$router.push({ name: HOME });
         } catch (e) {
-          this.errorMassage = e.message;
+          this.errorMassage = e.message || "登录失败";
           this.isServerError = true;
           this.submitting = false;
         }

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

@@ -89,7 +89,7 @@
                 <b-table-column label="详情" centered>
                   <router-link
                     :to="{
-                      path: `${$route.path}/test/${props.row.id}`
+                      path: `${$route.path}/${props.row.id}`
                     }"
                     >查看详情</router-link
                   >

+ 3 - 3
src/views/teacher/Code/index.vue

@@ -29,9 +29,9 @@
           detail-key="id"
         >
           <template slot-scope="props">
-            <b-table-column field="id" label="ID" numeric sortable centered>
-              {{ props.row.id }}
-            </b-table-column>
+            <!--<b-table-column field="id" label="ID" numeric sortable centered>-->
+            <!--{{ props.row.id }}-->
+            <!--</b-table-column>-->
 
             <b-table-column label="作业名称" centered>
               <router-link

+ 45 - 15
src/views/teacher/Code/test.vue

@@ -6,22 +6,44 @@
         { name: '作业详情', path: `code/${$route.params.codeId}` },
         { name: '测试信息', path: `${$route.path}` }
       ]"
+      :tab-list="[
+        {
+          name: '构建',
+          path: `code/${$route.params.homeworkId}/${$route.params.projectId}`
+        },
+        {
+          name: '部署',
+          path: `code/${$route.params.homeworkId}/${
+            $route.params.projectId
+          }/deploy`
+        },
+        {
+          name: '测试',
+          path: `code/${$route.params.homeworkId}/${
+            $route.params.projectId
+          }/test`
+        }
+      ]"
     >
       <template slot="title">
-        测试信息
+        测试信息: {{ projectDetail.name }}
       </template>
       <template slot="content">
-        可查看最近五条测试数据
+        <strong>git 地址 : </strong>
+        <a :href="projectDetail.url">{{ projectDetail.url }}</a>
       </template>
     </page-header>
-
     <page-body>
-      <div class="data-table">和学生代码作业的测试信息的显示格式和接口相同</div>
+      <router-view
+        :project-detail="projectDetail"
+        :detail-loading="detailLoading"
+      />
     </page-body>
   </div>
 </template>
 
 <script>
+import { getProjectDetail } from "@/api/codehw";
 import PageHeader from "@/components/PageHeader";
 import PageBody from "@/components/PageBody/index";
 
@@ -30,22 +52,30 @@ export default {
     PageBody,
     PageHeader
   },
-  mounted() {
-    const { testId } = this.$route.params;
-    console.log(testId);
-  },
   data() {
-    return {};
+    return {
+      projectDetail: {},
+      detailLoading: false
+    };
+  },
+  async mounted() {
+    // console.log(
+    //   "code/" +
+    //     this.$route.params.homeworkId +
+    //     "/" +
+    //     this.$route.params.projectId
+    // );
+    const { projectId } = this.$route.params;
+    this.detailLoading = true;
+    const detail = await getProjectDetail(projectId);
+    this.projectDetail = detail.data;
+    this.detailLoading = false;
   }
 };
 </script>
 
 <style scoped>
-.breadcrumb a {
-  /*color: #7957d5;*/
-  font-weight: bold;
-}
-.collapseeeeeee {
-  margin-bottom: 10px;
+.top-nav-section {
+  padding: 0 40px;
 }
 </style>

+ 23 - 4
src/views/teacher/Document/detail.vue

@@ -14,7 +14,9 @@
         题目描述:{{ problem ? problem.description : "" }}
       </template>
       <template slot="extraContent">
-        题目进行阶段:{{ status }}
+        <b-tag type="is-info" style="margin-right: 5px" size="is-medium"
+          >阶段:{{ status }}</b-tag
+        >
       </template>
     </page-header>
 
@@ -45,13 +47,15 @@
                 </b-table-column>
 
                 <b-table-column label="互评负责组" centered>
-                  <span v-for="groupId in props.row.reviewGroup" :key="groupId"
-                    >{{ groupId }}&emsp;</span
+                  <span v-for="group in props.row.reviewGroup" :key="group.id"
+                    >{{ group.id }}&emsp;</span
                   >
                 </b-table-column>
 
                 <b-table-column label="分数" centered>
-                  {{ props.row.result }}
+                  {{
+                    props.row.result === null ? "暂无成绩" : props.row.result
+                  }}
                 </b-table-column>
                 <b-table-column field="difficulty" label="详情" centered
                   ><router-link
@@ -78,6 +82,21 @@
                         <br />
                         <strong>git地址:</strong
                         ><small>{{ props.row.url }}</small> <br />
+                        <strong>互评小组:</strong
+                        ><small>
+                          <li
+                            v-for="reviewGroupp of props.row.reviewGroup"
+                            :key="reviewGroupp.id"
+                          >
+                            ID : {{ reviewGroupp.id }} &emsp; 小组成员:
+                            <small
+                              v-for="member of reviewGroupp.members"
+                              :key="member.id"
+                            >
+                              {{ member.username }}&emsp;
+                            </small>
+                          </li>
+                        </small>
                       </p>
                     </div>
                   </div>

+ 12 - 1
src/views/teacher/Document/docContent.vue

@@ -24,7 +24,17 @@
         >
       </template>
       <template slot="extraContent">
-        上次修改时间:{{ displayUnixTime(contentResult.lastUpdateAt) }}
+        <b-tag type="is-light" style="margin-right: 5px"
+          >上次修改时间:{{
+            displayUnixTime(contentResult.lastUpdateAt)
+          }}</b-tag
+        >
+        <br />
+        <b-tag type="is-info" style="margin-right: 5px" size="is-medium"
+          >成绩:{{
+            contentResult.result === null ? "暂无" : contentResult.result
+          }}</b-tag
+        >
       </template>
     </page-header>
     <page-body>
@@ -60,6 +70,7 @@ export default {
       contentResult: {
         content: "",
         group: "",
+        result: null,
         lastUpdateAt: "",
         name: ""
       },

+ 3 - 3
src/views/teacher/Document/index.vue

@@ -25,9 +25,9 @@
         <div v-if="!loadingDocList" class="data-table">
           <b-table :data="docData" detailed detail-key="id">
             <template slot-scope="props">
-              <b-table-column field="id" label="ID" numeric sortable centered>
-                {{ props.row.id }}
-              </b-table-column>
+              <!--<b-table-column field="id" label="ID" numeric sortable centered>-->
+              <!--{{ props.row.id }}-->
+              <!--</b-table-column>-->
 
               <b-table-column label="作业名称" centered>
                 <router-link

+ 2 - 2
src/views/teacher/Question/index.vue

@@ -438,7 +438,7 @@ import { mapState } from "vuex";
 import {
   getQuestionsByAssignType,
   getTeacherQuestionType,
-  getTeacherKeywordQuestions,
+  getTeacherKeywordQuestionsByType,
   getQuestionByQuesType
 } from "@/api/question";
 import PageHeader from "@/components/PageHeader";
@@ -576,7 +576,7 @@ export default {
     },
     //根据关键字查找题目
     getQuestionsByKey() {
-      getTeacherKeywordQuestions(this.keyWord)
+      getTeacherKeywordQuestionsByType(this.keyWord, "")
         .then(value => {
           this.data = value.data;
         })

+ 67 - 30
src/views/teacher/Result/index.vue

@@ -28,7 +28,13 @@
         </div>
         <!--题目table-->
         <div class="question-list">
-          <b-table :data="data" paginated per-page="5" detailed detail-key="id">
+          <b-table
+            :data="data"
+            paginated
+            per-page="50"
+            detailed
+            detail-key="id"
+          >
             <template slot-scope="props">
               <b-table-column field="id" label="ID" width="40" numeric sortable>
                 {{ props.row.id }}
@@ -53,8 +59,8 @@
                 sortable
                 centered
               >
-                <span :class="['tag', type(getFinalResult(props.row))]">
-                  {{ getFinalResult(props.row) }}
+                <span :class="['tag', type(props.row.finalRes)]">
+                  {{ props.row.finalRes }}
                 </span>
               </b-table-column>
             </template>
@@ -233,28 +239,41 @@ export default {
       submitting: false,
       isServerError: false,
       errorMessage: "服务器错误,请稍后重试",
-      isResultLoading: true
+      isResultLoading: true,
+      finalResult: [],
+      homeworkNum: 0
     };
   },
   methods: {
+    //初始化成绩比例
+    initialResultPercent(studentResults) {
+      if (studentResults.length < 1) return;
+      let resultSample = studentResults[0];
+      let homeworkNum = 0;
+      homeworkNum =
+        resultSample.codes.length +
+        resultSample.documents.length +
+        resultSample.reviews.length;
+      this.homeworkNum = homeworkNum;
+    },
     //统计学生成绩分段
     studenResultStatistics(studentResults) {
       let resultStatisticsData = [];
       for (let i = 0; i < RESULT_PARTITION.length; i++) {
         let count = 0;
         if (i == 0) {
-          for (let result in studentResults) {
-            if (this.getFinalResult(result.row) == 0) count++;
+          for (let result of studentResults) {
+            if (result.finalRes == 0) count++;
           }
         } else if (i == RESULT_PARTITION.length - 1) {
-          for (let result in studentResults) {
-            if (this.getFinalResult(result.row) == 100) count++;
+          for (let result of studentResults) {
+            if (result.finalRes == 100) count++;
           }
         } else {
-          for (let result in studentResults) {
+          for (let result of studentResults) {
             if (
-              this.getFinalResult(result.row) > RESULT_PARTITION[i - 1] &&
-              this.getFinalResult(result.row) <= RESULT_PARTITION[i]
+              result.finalRes > RESULT_PARTITION[i - 1] &&
+              result.finalRes <= RESULT_PARTITION[i]
             )
               count++;
           }
@@ -285,25 +304,36 @@ export default {
       return res / resultList.length;
     },
     //计算总评
-    getFinalResult(result) {
-      let finalRes = 0;
-      let currentIndex = 0;
-      for (let docRes of result.documents) {
-        finalRes +=
-          docRes.score * (this.finalResultPercentage[currentIndex] / 100);
-        currentIndex++;
-      }
-      for (let codeRes of result.codes) {
-        finalRes +=
-          codeRes.score * (this.finalResultPercentage[currentIndex] / 100);
-        currentIndex++;
-      }
-      for (let reviewRes of result.reviews) {
-        finalRes +=
-          reviewRes.score * (this.finalResultPercentage[currentIndex] / 100);
-        currentIndex++;
+    getFinalResult(resultList) {
+      console.log(resultList);
+      let finalResultList = [];
+      for (let i = 0; i < resultList.length; i++) {
+        let finalRes = 0;
+        let result = resultList[i];
+        console.log(result);
+        //let currentIndex = 0;
+        for (let docRes of result.documents) {
+          finalRes += docRes.score;
+          // finalRes +=
+          //   docRes.score * (this.finalResultPercentage[currentIndex] / 100);
+          // currentIndex++;
+        }
+        for (let codeRes of result.codes) {
+          finalRes += codeRes.score;
+          // finalRes +=
+          //   codeRes.score * (this.finalResultPercentage[currentIndex] / 100);
+          // currentIndex++;
+        }
+        for (let reviewRes of result.reviews) {
+          finalRes += reviewRes.score;
+          // finalRes +=
+          //   reviewRes.score * (this.finalResultPercentage[currentIndex] / 100);
+          // currentIndex++;
+        }
+        result.finalRes = parseInt(finalRes / this.homeworkNum);
+        finalResultList.push(result);
       }
-      return parseInt(finalRes);
+      this.data = finalResultList;
     },
     confirmPercent() {
       this.submitting = true;
@@ -318,7 +348,14 @@ export default {
     const resultData = await getStudentFinaleResult(
       this.$route.params.courseId
     );
-    this.data = resultData;
+    this.isResultLoading = false;
+    this.data = resultData.data;
+    console.log(this.data);
+    //初始化默认成绩比例
+    this.initialResultPercent(this.data);
+    //统计学生总评
+    console.log(resultData.data);
+    this.getFinalResult(resultData.data);
     //统计学生分数
     let studentResultStatistics = this.studenResultStatistics(this.data);
     //绘制图表

+ 3 - 2
vue.config.js

@@ -2,10 +2,11 @@ module.exports = {
   devServer: {
     proxy: {
       "^/api": {
-        target: "http://localhost:4000/",
-        // target: "http://10.1.1.198:8080/",
+        // target: "http://localhost:4000/",
+        target: "http://10.1.1.198:8080/",
         // target: "http://192.168.0.101:8080",
         // target: "http://10.1.2.3:8080/",
+
         ws: true,
         changeOrigin: true
       }