Browse Source

fix: 尝试实现预览pdf课件

chillqi 3 years ago
parent
commit
f04844b2f1

File diff suppressed because it is too large
+ 1 - 19264
package-lock.json


+ 15 - 0
src/App.vue

@@ -41,3 +41,18 @@ export default {
   //margin-bottom: 250px;
 }
 </style>
+
+<style>
+html{
+  height: 100%;
+}
+
+body{
+  height: 100%;
+}
+
+#app{
+  min-height: calc(100% - 220px);
+  position: relative;
+}
+</style>

+ 2 - 1
src/api/analysis/const.js

@@ -2,7 +2,8 @@
 export const REQUEST_BASE_URL_PROD = "https://smart-server.seec.seecoder.cn/";
 // 开发url (mock的地址
 // export const REQUEST_BASE_URL_DEV = "http://localhost:8080/api";
-export const REQUEST_BASE_URL_DEV = "/api";
+// export const REQUEST_BASE_URL_DEV = "/api";
+export const REQUEST_BASE_URL_DEV = "https://smart-server.seec.seecoder.cn/";
 export const ROLE = {
   STUDENT: "STUDENT", //学生身份
   TEACHER: "TEACHER", //教师身份

+ 13 - 6
src/api/course/course.js

@@ -86,14 +86,20 @@ function uploadCourseImage(name, image) {
   });
 }
 
-function uploadCarouselChart(input){
-  return axios.post(`${prefix}/uploadCarouseChart`,input);
+function uploadCarouselChart(input) {
+  return axios.post(`${prefix}/uploadCarouseChart`, input);
 }
 
-function queryCarouselChart(){
-  return axios.get(`${prefix}/queryCarouselChart`,{
-    params:{
+function queryCarouselChart() {
+  return axios.get(`${prefix}/queryCarouselChart`, {
+    params: {}
+  });
+}
 
+function findCourseByName(data) {
+  return axios.get(`${prefix}/findCourseByName`, {
+    params: {
+      name: data,
     }
   });
 }
@@ -115,7 +121,8 @@ const courseAPIs = {
   getCourseByEvalId,
   uploadCourseImage,
   uploadCarouselChart,
-  queryCarouselChart
+  queryCarouselChart,
+  findCourseByName,
 };
 
 export default courseAPIs;

+ 6 - 1
src/api/eval.js

@@ -107,6 +107,10 @@ function joinExamByInviteCode(inviteCode,examId){
   return axios.put(`${prefix}/exam/invite/withCode?inviteCode=${inviteCode}&examId=${examId}`);
 }
 
+function getExamListByCurrentStudent(){
+  return axios.get(`${prefix}/exam/student/examList`);
+}
+
 const evalAPIs = {
   getTeacherEvalExams,
   getTeacherEvalExamsGroupByCourse,
@@ -128,7 +132,8 @@ const evalAPIs = {
   getExamJoinedUsers,
   getAllReportByExamId,
   joinPublicExam,
-  joinExamByInviteCode
+  joinExamByInviteCode,
+  getExamListByCurrentStudent
 };
 
 export default evalAPIs;

+ 5 - 0
src/api/project.js

@@ -59,6 +59,10 @@ function forkProject(projectId, name = null) {
   });
 }
 
+function findAllPublicProjectsGroupByCourse() {
+  return axios.get(`${prefix}/findAllPublicGroupByCourse`);
+}
+
 const projectAPIs = {
   findAllProjects,
   findCourseProjects,
@@ -69,6 +73,7 @@ const projectAPIs = {
   createProject,
   updateCourseProjectState,
   forkProject,
+  findAllPublicProjectsGroupByCourse,
 };
 
 export default projectAPIs;

+ 423 - 362
src/components/Analysis/AnalysisGroupCard.vue

@@ -1,15 +1,15 @@
 <template xmlns:v-slot="http://www.w3.org/1999/XSL/Transform">
     <div class="main">
-<!--        小组信息-->
+        <!--        小组信息-->
         <el-card class="box-card">
             <template v-slot:header class="clearfix">
                 <span>小组信息</span>
             </template>
             <el-descriptions :column="2">
-                <el-descriptions-item label="小组总得分">{{
+                <el-descriptions-item label="小组总得分:">{{
                     totalScore
                     }}</el-descriptions-item>
-                <el-descriptions-item label="额外得分bonus">{{
+                <el-descriptions-item label="额外得分bonus:">{{
                     bonus
                     }}</el-descriptions-item>
             </el-descriptions>
@@ -47,13 +47,36 @@
                 </el-descriptions>
             </el-card>
         </el-card>
-<!--        commit信息-->
+        <!--        图表-->
+        <el-card class="box-card" style="margin-top: 20px">
+            <el-row :gutter="20">
+                <el-col :span="6">
+                    <p class="table_font">commit贡献占比</p>
+                    <div id="main1" class="pie"
+                    /></el-col>
+                <el-col :span="6">
+                    <p class="table_font">流水线部署贡献占比</p>
+                    <div id="main2" class="pie"
+                    />
+                </el-col>
+                <el-col :span="6">
+                    <p class="table_font">缺陷贡献占比</p>
+                    <div id="main3" class="pie"
+                    /></el-col>
+                <el-col :span="6">
+                    <p class="table_font">需求树贡献占比</p>
+                    <div id="main4" class="pie"
+                    />
+                </el-col>
+            </el-row>
+        </el-card>
+        <!--        commit信息-->
         <el-card class="box-card" style="margin-top: 20px">
             <template v-slot:header class="clearfix">
                 <span>commit信息</span>
             </template>
             <el-descriptions :column="1">
-                <el-descriptions-item label="commit得分">{{
+                <el-descriptions-item label="commit得分:">{{
                     commitScore
                     }}</el-descriptions-item>
             </el-descriptions>
@@ -62,16 +85,16 @@
                     <span>commit统计信息</span>
                 </template>
                 <el-descriptions :column="2">
-                    <el-descriptions-item label="commit总次数">{{
+                    <el-descriptions-item label="commit总次数:">{{
                         commitMessage.commit_times
                         }}</el-descriptions-item>
-                    <el-descriptions-item label="有效commit次数">{{
+                    <el-descriptions-item label="有效commit次数:">{{
                         commitMessage.valid_commit_times
                         }}</el-descriptions-item>
-                    <el-descriptions-item label="bugList_commit次数">{{
+                    <el-descriptions-item label="bugList_commit次数:">{{
                         commitMessage.buglist_commit
                         }}</el-descriptions-item>
-                    <el-descriptions-item label="feature_commit次数">{{
+                    <el-descriptions-item label="feature_commit次数:">{{
                         commitMessage.feature_commit
                         }}</el-descriptions-item>
                 </el-descriptions>
@@ -89,13 +112,13 @@
                 </el-descriptions>
             </el-card>
         </el-card>
-<!--        bug信息-->
+        <!--        bug信息-->
         <el-card class="box-card" style="margin-top: 20px">
             <template v-slot:header class="clearfix">
                 <span>缺陷信息</span>
             </template>
             <el-descriptions :column="1">
-                <el-descriptions-item label="缺陷得分">{{
+                <el-descriptions-item label="缺陷得分:">{{
                     bugScore
                     }}</el-descriptions-item>
             </el-descriptions>
@@ -104,25 +127,25 @@
                     <span>缺陷统计信息</span>
                 </template>
                 <el-descriptions :column="2">
-                    <el-descriptions-item label="缺陷数目">{{
+                    <el-descriptions-item label="缺陷数目:">{{
                         bugList.bug_times
                         }}</el-descriptions-item>
-                    <el-descriptions-item label="高优先级缺陷数目">{{
+                    <el-descriptions-item label="高优先级缺陷数目:">{{
                         bugList.high_times
                         }}</el-descriptions-item>
-                    <el-descriptions-item label="已经修复的缺陷数目">{{
+                    <el-descriptions-item label="已经修复的缺陷数目:">{{
                         bugList.finished_times
                         }}</el-descriptions-item>
                 </el-descriptions>
             </el-card>
         </el-card>
-<!--        treeNode信息-->
+        <!--        treeNode信息-->
         <el-card class="box-card" style="margin-top: 20px">
             <template v-slot:header class="clearfix">
                 <span>需求树信息</span>
             </template>
             <el-descriptions :column="1">
-                <el-descriptions-item label="需求得分">{{
+                <el-descriptions-item label="需求得分:">{{
                     nodeScore
                     }}</el-descriptions-item>
             </el-descriptions>
@@ -131,25 +154,25 @@
                     <span>需求统计信息</span>
                 </template>
                 <el-descriptions :column="2">
-                    <el-descriptions-item label="需求节点数目">{{
+                    <el-descriptions-item label="需求节点数目:">{{
                         treeNode.treeNode_times
                         }}</el-descriptions-item>
-                    <el-descriptions-item label="高优先级需求数目">{{
+                    <el-descriptions-item label="高优先级需求数目:">{{
                         treeNode.high_treeNode_times
                         }}</el-descriptions-item>
-                    <el-descriptions-item label="已经完成的需求数目">{{
+                    <el-descriptions-item label="已经完成的需求数目:">{{
                         treeNode.finished_treeNode_times
                         }}</el-descriptions-item>
                 </el-descriptions>
             </el-card>
         </el-card>
-<!--        部署信息-->
+        <!--        部署信息-->
         <el-card class="box-card" style="margin-top: 20px">
             <template v-slot:header class="clearfix">
                 <span>流水线部署信息</span>
             </template>
             <el-descriptions :column="1">
-                <el-descriptions-item label="部署得分">{{
+                <el-descriptions-item label="部署得分:">{{
                     pipelineScore
                     }}</el-descriptions-item>
             </el-descriptions>
@@ -158,378 +181,416 @@
                     <span>部署统计信息</span>
                 </template>
                 <el-descriptions :column="2">
-                    <el-descriptions-item label="流水线部署次数">{{
+                    <el-descriptions-item label="流水线部署次数:">{{
                         arrange.pipeline_deploy
                         }}</el-descriptions-item>
-                    <el-descriptions-item label="流水线部署成功次数">{{
+                    <el-descriptions-item label="流水线部署成功次数:">{{
                         arrange.pipeline_pass
                         }}</el-descriptions-item>
-                    <el-descriptions-item label="流水线部署失败次数">{{
+                    <el-descriptions-item label="流水线部署失败次数:">{{
                         arrange.pipline_failure
                         }}</el-descriptions-item>
                 </el-descriptions>
             </el-card>
         </el-card>
-<!--        图表-->
-        <el-card class="box-card" style="margin-top: 20px">
-            <el-row :gutter="20">
-                <el-col :span="6">
-                    <p class="table_font">commit贡献占比</p>
-                    <div id="main1" class="pie"
-                    /></el-col>
-                <el-col :span="6">
-                    <p class="table_font">流水线部署贡献占比</p>
-                    <div id="main2" class="pie"
-                    />
-                </el-col>
-                <el-col :span="6">
-                    <p class="table_font">缺陷贡献占比</p>
-                    <div id="main3" class="pie"
-                    /></el-col>
-                <el-col :span="6">
-                    <p class="table_font">需求树贡献占比</p>
-                    <div id="main4" class="pie"
-                    />
-                </el-col>
-            </el-row>
-        </el-card>
+
     </div>
 </template>
 
 <script>
-import * as echarts from "echarts";
-import {getGroupAnalysis,getGroupScore} from "@/api/analysis/devcloud.js";
+    import * as echarts from "echarts";
+    import {getGroupAnalysis,getGroupScore} from "@/api/analysis/devcloud.js";
 
-export default {
-  name: "AnalysisGroupCard",
-  props:{
-    "num": {type:Number,default:1},
-  },
-  data() {
-    return {
-      userId: this.num,
+    export default {
+        name: "AnalysisGroupCard",
+        props:{
+            "num": {type:Number,default:1},
+        },
+        data() {
+            return {
+                userId: this.num,
 
-      commitContribution: [
-        { name: "zqq", times: 0, proportion: 0 },
-        { name: "ty", times: 2, proportion: 0.4 },
-        { name: "kcy", times: 1, proportion: 0.2 },
-        { name: "pyy", times: 2, proportion: 0.4 },
-      ],
-      interfaceContribution: [
-        // { name: "zqq", times: 4, proportion: 0.8 },
-        // { name: "ty", times: 0, proportion: 0 },
-        // { name: "kcy", times: 0, proportion: 0 },
-        // { name: "pyy", times: 1, proportion: 0.2 },
-      ],
-      pipelineContribution: [
-        // { name: "zqq", times: 1, proportion: 0.1 },
-        // { name: "ty", times: 1, proportion: 0.1 },
-        // { name: "kcy", times: 2, proportion: 0.2 },
-        // { name: "pyy", times: 6, proportion: 0.6 },
-      ],
-      bugContribution: [],
-      treeContribution: [],
+                commitContribution: [
+                    // { name: "zqq", times: 0, proportion: 0 },
+                    // { name: "ty", times: 2, proportion: 0.4 },
+                    // { name: "kcy", times: 1, proportion: 0.2 },
+                    // { name: "pyy", times: 2, proportion: 0.4 },
+                ],
+                interfaceContribution: [
+                    // { name: "zqq", times: 4, proportion: 0.8 },
+                    // { name: "ty", times: 0, proportion: 0 },
+                    // { name: "kcy", times: 0, proportion: 0 },
+                    // { name: "pyy", times: 1, proportion: 0.2 },
+                ],
+                pipelineContribution: [
+                    // { name: "zqq", times: 1, proportion: 0.1 },
+                    // { name: "ty", times: 1, proportion: 0.1 },
+                    // { name: "kcy", times: 2, proportion: 0.2 },
+                    // { name: "pyy", times: 6, proportion: 0.6 },
+                ],
+                bugContribution: [],
+                treeContribution: [],
 
-      commitPie: [],
-      testPie: [],
-      deployPie: [],
-      bugListPie: [],
-      treePie: [],
+                commitPie: [],
+                testPie: [],
+                deployPie: [],
+                bugListPie: [],
+                treePie: [],
 
-      arrange: {
-        pipeline_deploy: 10,
-        pipeline_pass: 20,
-        pipline_failure: 20,
-      },
-      test: {
-        // total: 20,
-        // execute: 200,
-        // pass: 10,
-        // fail: 20,
-      },
-      commitMessage: {
-        commit_times: 5,
-        valid_commit_times: 3,
-        buglist_commit: 4,
-        feature_commit: 3,
-        commit_msg_overview: [
-          "- fix: 修改错误",
-          "- feat: 增加评论区功能",
-          "- feat: 增加头像上传",
-          "- fix: 修复登录页面的错误",
-        ],
-      },
-      bugList: {
-        bug_times: 10,
-        high_times: 5,
-        finished_times: 9,
-      },
-      treeNode: {
-        treeNode_times: 10,
-        high_treeNode_times: 5,
-        finished_treeNode_times: 9,
-      },
+                arrange: {
+                    pipeline_deploy: 10,
+                    pipeline_pass: 20,
+                    pipline_failure: 20,
+                },
+                test: {
+                    // total: 20,
+                    // execute: 200,
+                    // pass: 10,
+                    // fail: 20,
+                },
+                commitMessage: {
+                    // commit_times: 5,
+                    // valid_commit_times: 3,
+                    // buglist_commit: 4,
+                    // feature_commit: 3,
+                    // commit_msg_overview: [
+                    //   "- fix: 修改错误",
+                    //   "- feat: 增加评论区功能",
+                    //   "- feat: 增加头像上传",
+                    //   "- fix: 修复登录页面的错误",
+                    // ],
+                },
+                bugList: {
+                    // bug_times: 10,
+                    // high_times: 5,
+                    // finished_times: 9,
+                },
+                treeNode: {
+                    // treeNode_times: 10,
+                    // high_treeNode_times: 5,
+                    // finished_treeNode_times: 9,
+                },
 
-      userList: [
-        { userId: 11, name: "测试", email: "2222" },
-        { userId: 12, name: "测试2", email: "2222" },
-        { userId: 13, name: "测试3", email: "2222" },
-      ],
-      productList: [
-        { projectId: 1, projectName: "fun_frontEnd" },
-        { projectId: 2, projectName: "fun_backEnd" },
-      ],
+                userList: [
+                    // { userId: 11, name: "测试", email: "2222" },
+                    // { userId: 12, name: "测试2", email: "2222" },
+                    // { userId: 13, name: "测试3", email: "2222" },
+                ],
+                productList: [
+                    // { projectId: 1, projectName: "fun_frontEnd" },
+                    // { projectId: 2, projectName: "fun_backEnd" },
+                ],
 
-      totalScore: 0.0,
-      commitScore: 0.0,
-      bugScore: 0.0,
-      nodeScore: 0.0,
-      pipelineScore: 0.0,
-      bonus: 0.0,
-    };
-  },
+                totalScore: 0.0,
+                commitScore: 0.0,
+                bugScore: 0.0,
+                nodeScore: 0.0,
+                pipelineScore: 0.0,
+                bonus: 0.0,
+            };
+        },
 
-  async mounted() {
-    await this.getData();
-    await this.getAnalysis();
-    this.getCommitPie();
-    // this.getTestPie();
-    this.getDeployPie();
-    this.getBugPie();
-    this.getTreePie();
-  },
+        async mounted() {
+            await this.getData();
+            await this.getAnalysis();
+            this.getCommitPie();
+            // this.getTestPie();
+            this.getDeployPie();
+            this.getBugPie();
+            this.getTreePie();
+        },
 
-  methods: {
-    async getData(){
-      try{
-        let res = await getGroupAnalysis({
-          params: {
-            // user_id: this.$route.params.id,
-            // user_id: 1575,
-            user_id: this.userId,
-          },
-        });
-        // console.log(res);
-        // console.log("here");
-        // console.log(res.content.commit["commit_contribution"]);
-        if(res.success){
-          this.userList = res.content.students;
-          this.productList = res.content.projects;
-          this.commitMessage = res.content.commit;
-          this.commitContribution = res.content.commit.commit_contribution;
-          this.test = res.content.test;
-          this.interfaceContribution = res.content.test.test_contribution;
-          this.arrange = res.content.pipeline;
-          this.pipelineContribution = res.content.pipeline.pipeline_contribution;
-          this.bugList = res.content.buglist;
-          this.bugContribution = res.content.buglist.bug_contribution;
-          this.treeNode = res.content.treeNode;
-          this.treeContribution = res.content.treeNode.treeNode_contribution;
-        }
-        // console.log("done");
-        // console.log(this.commitContribution);
-      } catch(e) {
-        this.$message.error(e.message);
-      }
-      try{
-        let res1 = await getGroupScore({
-          params: {
-            // user_id: this.$route.params.id,
-            // user_id: 1575,
-            user_id: this.userId,
-          }
-        });
-        // console.log(res1);
-        if(res1.success){
-          this.totalScore = res1.content.totalScore;
-          this.commitScore = res1.content.commitScore;
-          this.bugScore = res1.content.bugScore;
-          this.nodeScore = res1.content.nodeScore;
-          this.pipelineScore = res1.content.pipelineScore;
-          this.bonus = res1.content.bonus;
-        }
-      } catch (e) {
-        this.$message.error(e.message);
-      }
-    },
+        methods: {
+            async getData(){
+                try{
+                    let res = await getGroupAnalysis({
+                        params: {
+                            // user_id: this.$route.params.id,
+                            // user_id: 1575,
+                            user_id: this.userId,
+                        },
+                    });
+                    // console.log(res);
+                    // console.log("here");
+                    // console.log(res.content.commit["commit_contribution"]);
+                    if(res.success){
+                        this.userList = res.content.students;
+                        this.productList = res.content.projects;
+                        this.commitMessage = res.content.commit;
+                        this.commitContribution = res.content.commit.commit_contribution;
+                        this.test = res.content.test;
+                        this.interfaceContribution = res.content.test.test_contribution;
+                        this.arrange = res.content.pipeline;
+                        this.pipelineContribution = res.content.pipeline.pipeline_contribution;
+                        this.bugList = res.content.buglist;
+                        this.bugContribution = res.content.buglist.bug_contribution;
+                        this.treeNode = res.content.treeNode;
+                        this.treeContribution = res.content.treeNode.treeNode_contribution;
+                    }
+                    // console.log("done");
+                    // console.log(this.commitContribution);
+                } catch(e) {
+                    // this.$message.error("暂未查找到相关数据");
+                    alert("暂未查找到相关数据");
+                }
+                try{
+                    let res1 = await getGroupScore({
+                        params: {
+                            // user_id: this.$route.params.id,
+                            // user_id: 1575,
+                            user_id: this.userId,
+                        }
+                    });
+                    // console.log(res1);
+                    if(res1.success){
+                        this.totalScore = res1.content.totalScore;
+                        this.commitScore = res1.content.commitScore;
+                        this.bugScore = res1.content.bugScore;
+                        this.nodeScore = res1.content.nodeScore;
+                        this.pipelineScore = res1.content.pipelineScore;
+                        this.bonus = res1.content.bonus;
+                    }
+                } catch (e) {
+                    // this.$message.error(e.message);
+                }
+            },
 
-    async getAnalysis() {
-      console.log("analysis:");
-      console.log(this.commitContribution);
-      for (let i = 0; i < this.commitContribution.length; i++) {
-        this.commitPie.push({
-          value: this.commitContribution[i].times,
-          name: this.commitContribution[i].name,
-        });
-      }
-      for (let i = 0; i < this.interfaceContribution.length; i++) {
-        this.testPie.push({
-          value: this.interfaceContribution[i].times,
-          name: this.interfaceContribution[i].name,
-        });
-      }
-      for (let i = 0; i < this.pipelineContribution.length; i++) {
-        this.deployPie.push({
-          value: this.pipelineContribution[i].times,
-          name: this.pipelineContribution[i].name,
-        });
-      }
-      for(let i = 0; i < this.bugContribution.length; i++) {
-        this.bugListPie.push({
-          value : this.bugContribution[i].times,
-          name: this.bugContribution[i].name,
-        });
-      }
-      // console.log(this.bugListPie);
-      for(let i = 0; i < this.treeContribution.length; i++) {
-        this.treePie.push({
-          value: this.treeContribution[i].times,
-          name: this.treeContribution[i].name,
-        });
-      }
-    },
+            async getAnalysis() {
+                console.log("analysis:");
+                console.log(this.commitContribution);
+                for (let i = 0; i < this.commitContribution.length; i++) {
+                    this.commitPie.push({
+                        value: this.commitContribution[i].times,
+                        name: this.commitContribution[i].name,
+                    });
+                }
+                for (let i = 0; i < this.interfaceContribution.length; i++) {
+                    this.testPie.push({
+                        value: this.interfaceContribution[i].times,
+                        name: this.interfaceContribution[i].name,
+                    });
+                }
+                for (let i = 0; i < this.pipelineContribution.length; i++) {
+                    this.deployPie.push({
+                        value: this.pipelineContribution[i].times,
+                        name: this.pipelineContribution[i].name,
+                    });
+                }
+                for(let i = 0; i < this.bugContribution.length; i++) {
+                    this.bugListPie.push({
+                        value : this.bugContribution[i].times,
+                        name: this.bugContribution[i].name,
+                    });
+                }
+                // console.log(this.bugListPie);
+                for(let i = 0; i < this.treeContribution.length; i++) {
+                    this.treePie.push({
+                        value: this.treeContribution[i].times,
+                        name: this.treeContribution[i].name,
+                    });
+                }
+            },
 
-    getCommitPie() {
-      // 绘制图表
-      var myChart1 = echarts.init(document.getElementById("main1"));
-      // 指定图表的配置项和数据
-      var option = {
-        title: {
-          // text: 'commit占比信息',
-        },
-        grid: {
-          top: 90,
-        },
-        tooltip: {
-          trigger: "item",
-        },
-        series: [
-          {
-            name: "commit次数",
-            center: ["50%", "40%"],
-            type: "pie", // 设置图表类型为饼图
-            radius: "55%", // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
-            data: this.commitPie,
-          },
-        ],
-      };
-      // 使用刚指定的配置项和数据显示图表。
-      myChart1.setOption(option);
-    },
+            getCommitPie() {
+                // 绘制图表
+                var myChart1 = echarts.init(document.getElementById("main1"));
+                // 指定图表的配置项和数据
+                var option = {
+                    title: {
+                        // text: 'commit占比信息',
+                    },
+                    grid: {
+                        top: 90,
+                    },
+                    tooltip: {
+                        trigger: "item",
+                    },
+                    series: [
+                        {
+                            name: "commit次数",
+                            center: ["50%", "40%"],
+                            type: "pie", // 设置图表类型为饼图
+                            radius: "55%", // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
+                            data: this.commitPie,
+                        },
+                    ],
+                };
+                // 使用刚指定的配置项和数据显示图表。
+                myChart1.setOption(option);
+            },
 
-    // getTestPie() {
-    //   var myChart2 = echarts.init(document.getElementById("main2"));
-    //   // 指定图表的配置项和数据
-    //   var option = {
-    //     title: {
-    //       // text: 'commit占比信息',
-    //     },
-    //     grid: {
-    //       top: 90,
-    //     },
-    //     tooltip: {
-    //       trigger: "item",
-    //     },
-    //     series: [
-    //       {
-    //         name: "测试次数",
-    //         center: ["50%", "40%"],
-    //         type: "pie", // 设置图表类型为饼图
-    //         radius: "55%", // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
-    //         data: this.testPie,
-    //       },
-    //     ],
-    //   };
-    //   // 使用刚指定的配置项和数据显示图表。
-    //   myChart2.setOption(option);
-    // },
+            // getTestPie() {
+            //   var myChart2 = echarts.init(document.getElementById("main2"));
+            //   // 指定图表的配置项和数据
+            //   var option = {
+            //     title: {
+            //       // text: 'commit占比信息',
+            //     },
+            //     grid: {
+            //       top: 90,
+            //     },
+            //     tooltip: {
+            //       trigger: "item",
+            //     },
+            //     series: [
+            //       {
+            //         name: "测试次数",
+            //         center: ["50%", "40%"],
+            //         type: "pie", // 设置图表类型为饼图
+            //         radius: "55%", // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
+            //         data: this.testPie,
+            //       },
+            //     ],
+            //   };
+            //   // 使用刚指定的配置项和数据显示图表。
+            //   myChart2.setOption(option);
+            // },
 
-    getDeployPie() {
-      var myChart3 = echarts.init(document.getElementById("main2"));
-      // 指定图表的配置项和数据
-      var option = {
-        title: {
-          // text: 'commit占比信息',
-        },
-        grid: {
-          top: 90,
-        },
-        tooltip: {
-          trigger: "item",
-        },
-        series: [
-          {
-            name: "部署次数",
-            center: ["50%", "40 %"],
-            type: "pie", // 设置图表类型为饼图
-            radius: "55%", // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
-            data: this.deployPie,
-          },
-        ],
-      };
-      // 使用刚指定的配置项和数据显示图表。
-      myChart3.setOption(option);
-    },
+            getDeployPie() {
+                var myChart3 = echarts.init(document.getElementById("main2"));
+                // 指定图表的配置项和数据
+                var option = {
+                    title: {
+                        // text: 'commit占比信息',
+                    },
+                    grid: {
+                        top: 90,
+                    },
+                    tooltip: {
+                        trigger: "item",
+                    },
+                    series: [
+                        {
+                            name: "部署次数",
+                            center: ["50%", "40 %"],
+                            type: "pie", // 设置图表类型为饼图
+                            radius: "55%", // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
+                            data: this.deployPie,
+                        },
+                    ],
+                };
+                // 使用刚指定的配置项和数据显示图表。
+                myChart3.setOption(option);
+            },
 
-    getBugPie() {
-      var myChart4 = echarts.init(document.getElementById("main3"));
-      // 指定图表的配置项和数据
-      var option = {
-        title: {
-          // text: 'commit占比信息',
-        },
-        grid: {
-          top: 90,
-        },
-        tooltip: {
-          trigger: "item",
-        },
-        series: [
-          {
-            name: "提交缺陷次数",
-            center: ["50%", "40 %"],
-            type: "pie", // 设置图表类型为饼图
-            radius: "55%", // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
-            data: this.bugListPie,
-          },
-        ],
-      };
-      // 使用刚指定的配置项和数据显示图表。
-      myChart4.setOption(option);
-    },
+            getBugPie() {
+                var myChart4 = echarts.init(document.getElementById("main3"));
+                // 指定图表的配置项和数据
+                var option = {
+                    title: {
+                        // text: 'commit占比信息',
+                    },
+                    grid: {
+                        top: 90,
+                    },
+                    tooltip: {
+                        trigger: "item",
+                    },
+                    series: [
+                        {
+                            name: "提交缺陷次数",
+                            center: ["50%", "40 %"],
+                            type: "pie", // 设置图表类型为饼图
+                            radius: "55%", // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
+                            data: this.bugListPie,
+                        },
+                    ],
+                };
+                // 使用刚指定的配置项和数据显示图表。
+                myChart4.setOption(option);
+            },
 
-    getTreePie() {
-      var myChart5 = echarts.init(document.getElementById("main4"));
-      // 指定图表的配置项和数据
-      var option = {
-        title: {
-          // text: 'commit占比信息',
-        },
-        grid: {
-          top: 90,
+            getTreePie() {
+                var myChart5 = echarts.init(document.getElementById("main4"));
+                // 指定图表的配置项和数据
+                var option = {
+                    title: {
+                        // text: 'commit占比信息',
+                    },
+                    grid: {
+                        top: 90,
+                    },
+                    tooltip: {
+                        trigger: "item",
+                    },
+                    series: [
+                        {
+                            name: "提交需求次数",
+                            center: ["50%", "40 %"],
+                            type: "pie", // 设置图表类型为饼图
+                            radius: "55%", // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
+                            data: this.treePie,
+                        },
+                    ],
+                };
+                // 使用刚指定的配置项和数据显示图表。
+                myChart5.setOption(option);
+            },
         },
-        tooltip: {
-          trigger: "item",
-        },
-        series: [
-          {
-            name: "提交需求次数",
-            center: ["50%", "40 %"],
-            type: "pie", // 设置图表类型为饼图
-            radius: "55%", // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
-            data: this.treePie,
-          },
-        ],
-      };
-      // 使用刚指定的配置项和数据显示图表。
-      myChart5.setOption(option);
-    },
-  },
 
-};
+    };
 
 </script>
 
 <style scoped>
+    .score-box {
+        width: 20px;
+        height: 10px;
+        background-color: #98e7ff;
+    }
+    .nui-scroll {
+        margin-top: 5px;
+        width: 99%;
+        height: 300px;
+        overflow: auto;
+    }
+
+    .nui-scroll::-webkit-scrollbar {
+        width: 8px;
+        height: 8px;
+    }
+    /*正常情况下滑块的样式*/
+
+    .nui-scroll::-webkit-scrollbar-thumb {
+        background-color: rgba(0, 0, 0, .05);
+        border-radius: 10px;
+        -webkit-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .1);
+    }
+    /*鼠标悬浮在该类指向的控件上时滑块的样式*/
+
+    .nui-scroll:hover::-webkit-scrollbar-thumb {
+        background-color: rgba(0, 0, 0, .2);
+        border-radius: 10px;
+        -webkit-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .1);
+    }
+    /*鼠标悬浮在滑块上时滑块的样式*/
+
+    .nui-scroll::-webkit-scrollbar-thumb:hover {
+        background-color: rgba(0, 0, 0, .4);
+        -webkit-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .1);
+    }
+    /*正常时候的主干部分*/
+
+    .nui-scroll::-webkit-scrollbar-track {
+        border-radius: 10px;
+        -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0);
+        background-color: white;
+    }
+    /*鼠标悬浮在滚动条上的主干部分*/
+
+    .nui-scroll::-webkit-scrollbar-track:hover {
+        -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .4);
+        background-color: rgba(0, 0, 0, .01);
+    }
 
-</style>
+    .box-innercard {
+        /*background-color: #1f00f5;*/
+    }
+    .pie {
+        width: 200px;
+        height: 150px;
+    }
+    /* .main{
+      display: flex;
+    } */
+</style>

+ 331 - 330
src/components/Analysis/AnalysisStudentCard.vue

@@ -6,10 +6,10 @@
                 <span>个人信息</span>
             </template>
             <el-descriptions :column="2">
-                <el-descriptions-item label="个人总得分">{{
+                <el-descriptions-item label="个人总得分:">{{
                     totalScore
                     }}</el-descriptions-item>
-                <el-descriptions-item label="额外得分bonus">{{
+                <el-descriptions-item label="额外得分bonus:">{{
                     bonus
                     }}</el-descriptions-item>
             </el-descriptions>
@@ -18,13 +18,13 @@
                     <span>基本信息</span>
                 </template>
                 <el-descriptions :column="2">
-                    <el-descriptions-item label="姓名">{{
+                    <el-descriptions-item label="姓名:">{{
                         user.name
                         }}</el-descriptions-item>
-                    <el-descriptions-item label="用户id">{{
+                    <el-descriptions-item label="用户id:">{{
                         user.userId
                         }}</el-descriptions-item>
-                    <el-descriptions-item label="电子邮箱">{{
+                    <el-descriptions-item label="电子邮箱:">{{
                         user.email
                         }}</el-descriptions-item>
                 </el-descriptions>
@@ -35,10 +35,10 @@
                 </template>
                 <el-descriptions :column="2" style="margin-top: 20px">
                     <div v-for="item in productList" v-bind:key="item">
-                        <el-descriptions-item label="项目id" :key="item.projectId">{{
+                        <el-descriptions-item label="项目id:" :key="item.projectId">{{
                             item.projectId
                             }}</el-descriptions-item>
-                        <el-descriptions-item label="项目名称" :key="item.projectName">{{
+                        <el-descriptions-item label="项目名称:" :key="item.projectName">{{
                             item.projectName
                             }}</el-descriptions-item>
                     </div>
@@ -51,7 +51,7 @@
                 <span>commit信息</span>
             </template>
             <el-descriptions :column="1">
-                <el-descriptions-item label="commit得分">{{
+                <el-descriptions-item label="commit得分:">{{
                     commitScore
                     }}</el-descriptions-item>
             </el-descriptions>
@@ -60,16 +60,16 @@
                     <span>commit统计信息</span>
                 </template>
                 <el-descriptions :column="2">
-                    <el-descriptions-item label="commit总次数">{{
+                    <el-descriptions-item label="commit总次数:">{{
                         commitMessage.commit_times
                         }}</el-descriptions-item>
-                    <el-descriptions-item label="有效commit次数">{{
+                    <el-descriptions-item label="有效commit次数:">{{
                         commitMessage.valid_commit_times
                         }}</el-descriptions-item>
-                    <el-descriptions-item label="bugList_commit次数">{{
+                    <el-descriptions-item label="bugList_commit次数:">{{
                         commitMessage.buglist_commit
                         }}</el-descriptions-item>
-                    <el-descriptions-item label="feature_commit次数">{{
+                    <el-descriptions-item label="feature_commit次数:">{{
                         commitMessage.feature_commit
                         }}</el-descriptions-item>
                 </el-descriptions>
@@ -94,7 +94,7 @@
                 <span>缺陷信息</span>
             </template>
             <el-descriptions :column="1">
-                <el-descriptions-item label="缺陷得分">{{
+                <el-descriptions-item label="缺陷得分:">{{
                     bugScore
                     }}</el-descriptions-item>
             </el-descriptions>
@@ -103,13 +103,13 @@
                     <span>缺陷统计信息</span>
                 </template>
                 <el-descriptions :column="2">
-                    <el-descriptions-item label="缺陷数目">{{
+                    <el-descriptions-item label="缺陷数目:">{{
                         bugList.bug_times
                         }}</el-descriptions-item>
-                    <el-descriptions-item label="高优先级缺陷数目">{{
+                    <el-descriptions-item label="高优先级缺陷数目:">{{
                         bugList.high_times
                         }}</el-descriptions-item>
-                    <el-descriptions-item label="已经修复的缺陷数目">{{
+                    <el-descriptions-item label="已经修复的缺陷数目:">{{
                         bugList.finished_times
                         }}</el-descriptions-item>
                 </el-descriptions>
@@ -122,7 +122,7 @@
                 <span>需求树信息</span>
             </template>
             <el-descriptions :column="1">
-                <el-descriptions-item label="需求得分">{{
+                <el-descriptions-item label="需求得分:">{{
                     nodeScore
                     }}</el-descriptions-item>
             </el-descriptions>
@@ -131,13 +131,13 @@
                     <span>需求统计信息</span>
                 </template>
                 <el-descriptions :column="2">
-                    <el-descriptions-item label="需求节点数目">{{
+                    <el-descriptions-item label="需求节点数目:">{{
                         treeNode.treeNode_times
                         }}</el-descriptions-item>
-                    <el-descriptions-item label="高优先级需求数目">{{
+                    <el-descriptions-item label="高优先级需求数目:">{{
                         treeNode.high_treeNode_times
                         }}</el-descriptions-item>
-                    <el-descriptions-item label="已经完成的需求数目">{{
+                    <el-descriptions-item label="已经完成的需求数目:">{{
                         treeNode.finished_treeNode_times
                         }}</el-descriptions-item>
                 </el-descriptions>
@@ -150,7 +150,7 @@
                 <span>流水线部署信息</span>
             </template>
             <el-descriptions :column="1">
-                <el-descriptions-item label="部署得分">{{
+                <el-descriptions-item label="部署得分:">{{
                     pipelineScore
                     }}</el-descriptions-item>
             </el-descriptions>
@@ -159,13 +159,13 @@
                     <span>部署统计信息</span>
                 </template>
                 <el-descriptions :column="2">
-                    <el-descriptions-item label="流水线部署次数">{{
+                    <el-descriptions-item label="流水线部署次数:">{{
                         pipeline.pipeline_deploy
                         }}</el-descriptions-item>
-                    <el-descriptions-item label="流水线部署成功次数">{{
+                    <el-descriptions-item label="流水线部署成功次数:">{{
                         pipeline.pipeline_pass
                         }}</el-descriptions-item>
-                    <el-descriptions-item label="流水线部署失败次数">{{
+                    <el-descriptions-item label="流水线部署失败次数:">{{
                         pipeline.pipline_failure
                         }}</el-descriptions-item>
                 </el-descriptions>
@@ -231,320 +231,321 @@
 </template>
 
 <script>
-import * as echarts from "echarts";
-import { getStudentAnalysis,getStudentScore } from "@/api/analysis/devcloud.js";
+    import * as echarts from "echarts";
+    import { getStudentAnalysis,getStudentScore } from "@/api/analysis/devcloud.js";
 
-export default {
-  name: "AnalysisStudentCard",
-  props:{
-    "num": {type:Number,default:1},
-  },
-  data() {
-    return {
-      userId: this.num,
+    export default {
+        name: "AnalysisStudentCard",
+        props:{
+            "num": {type:Number,default:1},
+        },
+        data() {
+            return {
+                userId: this.num,
 
-      visible1: false,
-      commitAnalysis: [],
-      visible2: false,
-      testAnalysis: [],
-      visible3: false,
-      deployAnalysis: [],
-      pipeline: {},
-      user: {},
-      test: {},
-      commitMessage: {},
-      visible4: false,
-      bugAnalysis: [],
-      bugList:{},
-      visible5: false,
-      treeAnalysis:[],
-      treeNode:{},
-      //项目列表
-      productList: [],
+                visible1: false,
+                commitAnalysis: [],
+                visible2: false,
+                testAnalysis: [],
+                visible3: false,
+                deployAnalysis: [],
+                pipeline: {},
+                user: {},
+                test: {},
+                commitMessage: {},
+                visible4: false,
+                bugAnalysis: [],
+                bugList:{},
+                visible5: false,
+                treeAnalysis:[],
+                treeNode:{},
+                //项目列表
+                productList: [],
 
-      totalScore:0.0,
-      commitScore:0.0,
-      bugScore:0.0,
-      nodeScore:0.0,
-      pipelineScore:0.0,
-      bonus:0.0,
-    };
-  },
-  async mounted() {
-    await this.getData();
-    this.getAnaylysis();
-  },
-  methods: {
-    async getData() {
-      try {
-        let res = await getStudentAnalysis({
-          params: {
-            // user_id: this.$route.params.id,
-            // user_id: 1575,
-            user_id: this.userId,
-          },
-        });
-        // console.log(res);
-        if (res.success) {
-          this.user = res.content;
-          this.productList = res.content.projects;
-          this.commitMessage = res.content.commit;
-          this.test = res.content.test;
-          this.bugList = res.content.buglist;
-          this.pipeline = res.content.pipeline;
-          this.treeNode = res.content.treeNode;
-        }
-      } catch (e) {
-        this.$message.error(e.message);
-      }
-      try{
-        let res1 = await getStudentScore({
-          params: {
-            // user_id: this.$route.params.id,
-            // user_id: 1575,
-            user_id: this.userId,
-          }
-        });
-        // console.log(res1);
-        if(res1.success){
-          this.totalScore = res1.content.totalScore;
-          this.commitScore = res1.content.commitScore;
-          this.bugScore = res1.content.bugScore;
-          this.nodeScore = res1.content.nodeScore;
-          this.pipelineScore = res1.content.pipelineScore;
-          this.bonus = res1.content.bonus;
-        }
-      } catch (e) {
-        this.$message.error(e.message);
-      }
-    },
-    getAnaylysis() {
-      //部署信息图表
-      this.deployAnalysis.push({
-        value: this.pipeline.pipeline_deploy,
-        name: "部署成功次数",
-      });
-      this.deployAnalysis.push({
-        value: this.pipeline.pipline_failure,
-        name: "部署失败次数",
-      });
-      //commit信息图表
-      this.commitAnalysis.push({
-        value: this.commitMessage.feature_commit,
-        name: "feature_commit次数",
-      });
-      this.commitAnalysis.push({
-        value: this.commitMessage.buglist_commit,
-        name: "buglist_commit次数",
-      });
-      //test信息图表
-      this.testAnalysis.push({
-        value: this.test.test_concurrency_failure,
-        name: "接口测试失败次数",
-      });
-      this.testAnalysis.push({
-        value: this.test.test_concurrency_success,
-        name: "接口测试通过次数",
-      });
-      //bug信息图表
-      this.bugAnalysis.push({
-        value: this.bugList.finished_times,
-        name: "已完成的缺陷数目",
-      });
-      this.bugAnalysis.push({
-        value: (this.bugList.bug_times - this.bugList.finished_times),
-        name: "未完成的缺陷数目",
-      });
-      //需求信息图表
-      this.treeAnalysis.push({
-        value: this.treeNode.finished_treeNode_times,
-        name: "已完成的需求数目",
-      });
-      this.treeAnalysis.push({
-        value: (this.treeNode.treeNode_times - this.treeNode.finished_treeNode_times),
-        name: "未完成的需求数目",
-      });
-    },
-    initBarChart1() {
-      let newPromise = new Promise((resolve) => {
-        resolve();
-      });
-      newPromise.then(() => {
-        let myChart1 = echarts.init(this.$refs.charts1);
-        myChart1.setOption({
-          title: {
-            text: "commit占比信息",
-          },
-          grid: {
-            top: 90,
-          },
-          tooltip: {
-            trigger: "item",
-          },
-          series: [
-            {
-              name: "commit次数",
-              type: "pie", // 设置图表类型为饼图
-              radius: "55%", // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
-              data: this.commitAnalysis,
+                totalScore:0.0,
+                commitScore:0.0,
+                bugScore:0.0,
+                nodeScore:0.0,
+                pipelineScore:0.0,
+                bonus:0.0,
+            };
+        },
+        async mounted() {
+            await this.getData();
+            this.getAnaylysis();
+        },
+        methods: {
+            async getData() {
+                try {
+                    let res = await getStudentAnalysis({
+                        params: {
+                            // user_id: this.$route.params.id,
+                            // user_id: 1575,
+                            user_id: this.userId,
+                        },
+                    });
+                    // console.log(res);
+                    if (res.success) {
+                        this.user = res.content;
+                        this.productList = res.content.projects;
+                        this.commitMessage = res.content.commit;
+                        this.test = res.content.test;
+                        this.bugList = res.content.buglist;
+                        this.pipeline = res.content.pipeline;
+                        this.treeNode = res.content.treeNode;
+                    }
+                } catch (e) {
+                    // this.$message.error(e.message);
+                    alert("暂未查找到相关数据");
+                }
+                try{
+                    let res1 = await getStudentScore({
+                        params: {
+                            // user_id: this.$route.params.id,
+                            // user_id: 1575,
+                            user_id: this.userId,
+                        }
+                    });
+                    // console.log(res1);
+                    if(res1.success){
+                        this.totalScore = res1.content.totalScore;
+                        this.commitScore = res1.content.commitScore;
+                        this.bugScore = res1.content.bugScore;
+                        this.nodeScore = res1.content.nodeScore;
+                        this.pipelineScore = res1.content.pipelineScore;
+                        this.bonus = res1.content.bonus;
+                    }
+                } catch (e) {
+                    // this.$message.error(e.message);
+                }
+            },
+            getAnaylysis() {
+                //部署信息图表
+                this.deployAnalysis.push({
+                    value: this.pipeline.pipeline_deploy,
+                    name: "部署成功次数",
+                });
+                this.deployAnalysis.push({
+                    value: this.pipeline.pipline_failure,
+                    name: "部署失败次数",
+                });
+                //commit信息图表
+                this.commitAnalysis.push({
+                    value: this.commitMessage.feature_commit,
+                    name: "feature_commit次数",
+                });
+                this.commitAnalysis.push({
+                    value: this.commitMessage.buglist_commit,
+                    name: "buglist_commit次数",
+                });
+                //test信息图表
+                this.testAnalysis.push({
+                    value: this.test.test_concurrency_failure,
+                    name: "接口测试失败次数",
+                });
+                this.testAnalysis.push({
+                    value: this.test.test_concurrency_success,
+                    name: "接口测试通过次数",
+                });
+                //bug信息图表
+                this.bugAnalysis.push({
+                    value: this.bugList.finished_times,
+                    name: "已完成的缺陷数目",
+                });
+                this.bugAnalysis.push({
+                    value: (this.bugList.bug_times - this.bugList.finished_times),
+                    name: "未完成的缺陷数目",
+                });
+                //需求信息图表
+                this.treeAnalysis.push({
+                    value: this.treeNode.finished_treeNode_times,
+                    name: "已完成的需求数目",
+                });
+                this.treeAnalysis.push({
+                    value: (this.treeNode.treeNode_times - this.treeNode.finished_treeNode_times),
+                    name: "未完成的需求数目",
+                });
             },
-          ],
-        });
-      });
-    },
-    initBarChart2() {
-      let newPromise = new Promise((resolve) => {
-        resolve();
-      });
-      newPromise.then(() => {
-        let myChart2 = echarts.init(this.$refs.charts2);
-        myChart2.setOption({
-          title: {
-            text: "接口测试通过率",
-          },
-          grid: {
-            top: 90,
-          },
-          tooltip: {
-            trigger: "item",
-          },
-          series: [
-            {
-              name: "测试次数",
-              type: "pie", // 设置图表类型为饼图
-              radius: "55%", // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
-              data: this.testAnalysis,
+            initBarChart1() {
+                let newPromise = new Promise((resolve) => {
+                    resolve();
+                });
+                newPromise.then(() => {
+                    let myChart1 = echarts.init(this.$refs.charts1);
+                    myChart1.setOption({
+                        title: {
+                            text: "commit占比信息",
+                        },
+                        grid: {
+                            top: 90,
+                        },
+                        tooltip: {
+                            trigger: "item",
+                        },
+                        series: [
+                            {
+                                name: "commit次数",
+                                type: "pie", // 设置图表类型为饼图
+                                radius: "55%", // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
+                                data: this.commitAnalysis,
+                            },
+                        ],
+                    });
+                });
             },
-          ],
-        });
-      });
-    },
-    initBarChart3() {
-      let newPromise = new Promise((resolve) => {
-        resolve();
-      });
-      newPromise.then(() => {
-        let myChart3 = echarts.init(this.$refs.charts3);
-        myChart3.setOption({
-          title: {
-            text: "部署通过率",
-          },
-          grid: {
-            top: 90,
-          },
-          tooltip: {
-            trigger: "item",
-          },
-          series: [
-            {
-              name: "部署次数",
-              type: "pie", // 设置图表类型为饼图
-              radius: "55%", // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
-              data: this.deployAnalysis,
+            initBarChart2() {
+                let newPromise = new Promise((resolve) => {
+                    resolve();
+                });
+                newPromise.then(() => {
+                    let myChart2 = echarts.init(this.$refs.charts2);
+                    myChart2.setOption({
+                        title: {
+                            text: "接口测试通过率",
+                        },
+                        grid: {
+                            top: 90,
+                        },
+                        tooltip: {
+                            trigger: "item",
+                        },
+                        series: [
+                            {
+                                name: "测试次数",
+                                type: "pie", // 设置图表类型为饼图
+                                radius: "55%", // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
+                                data: this.testAnalysis,
+                            },
+                        ],
+                    });
+                });
             },
-          ],
-        });
-      });
-    },
-    initBarChart4() {
-      let newPromise = new Promise((resolve) => {
-        resolve();
-      });
-      newPromise.then(() => {
-        let myChart4 = echarts.init(this.$refs.charts4);
-        myChart4.setOption({
-          title: {
-            text: "缺陷修复率",
-          },
-          grid: {
-            top: 90,
-          },
-          tooltip: {
-            trigger: "item",
-          },
-          series: [
-            {
-              name: "缺陷数目",
-              type: "pie", // 设置图表类型为饼图
-              radius: "55%", // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
-              data: this.bugAnalysis,
+            initBarChart3() {
+                let newPromise = new Promise((resolve) => {
+                    resolve();
+                });
+                newPromise.then(() => {
+                    let myChart3 = echarts.init(this.$refs.charts3);
+                    myChart3.setOption({
+                        title: {
+                            text: "部署通过率",
+                        },
+                        grid: {
+                            top: 90,
+                        },
+                        tooltip: {
+                            trigger: "item",
+                        },
+                        series: [
+                            {
+                                name: "部署次数",
+                                type: "pie", // 设置图表类型为饼图
+                                radius: "55%", // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
+                                data: this.deployAnalysis,
+                            },
+                        ],
+                    });
+                });
+            },
+            initBarChart4() {
+                let newPromise = new Promise((resolve) => {
+                    resolve();
+                });
+                newPromise.then(() => {
+                    let myChart4 = echarts.init(this.$refs.charts4);
+                    myChart4.setOption({
+                        title: {
+                            text: "缺陷修复率",
+                        },
+                        grid: {
+                            top: 90,
+                        },
+                        tooltip: {
+                            trigger: "item",
+                        },
+                        series: [
+                            {
+                                name: "缺陷数目",
+                                type: "pie", // 设置图表类型为饼图
+                                radius: "55%", // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
+                                data: this.bugAnalysis,
+                            },
+                        ],
+                    });
+                });
             },
-          ],
-        });
-      });
-    },
 
-    initBarChart5() {
-      let newPromise = new Promise((resolve) => {
-        resolve();
-      });
-      newPromise.then(() => {
-        let myChart5 = echarts.init(this.$refs.charts5);
-        myChart5.setOption({
-          title: {
-            text: "需求完成率",
-          },
-          grid: {
-            top: 90,
-          },
-          tooltip: {
-            trigger: "item",
-          },
-          series: [
-            {
-              name: "需求数目",
-              type: "pie", // 设置图表类型为饼图
-              radius: "55%", // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
-              data: this.treeAnalysis,
+            initBarChart5() {
+                let newPromise = new Promise((resolve) => {
+                    resolve();
+                });
+                newPromise.then(() => {
+                    let myChart5 = echarts.init(this.$refs.charts5);
+                    myChart5.setOption({
+                        title: {
+                            text: "需求完成率",
+                        },
+                        grid: {
+                            top: 90,
+                        },
+                        tooltip: {
+                            trigger: "item",
+                        },
+                        series: [
+                            {
+                                name: "需求数目",
+                                type: "pie", // 设置图表类型为饼图
+                                radius: "55%", // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
+                                data: this.treeAnalysis,
+                            },
+                        ],
+                    });
+                });
+            },
+            showModel1() {
+                this.visible1 = true;
+            },
+            showModel2() {
+                this.visible2 = true;
+            },
+            showModel3() {
+                this.visible3 = true;
+            },
+            showModel4() {
+                this.visible4 = true;
             },
-          ],
-        });
-      });
-    },
-    showModel1() {
-      this.visible1 = true;
-    },
-    showModel2() {
-      this.visible2 = true;
-    },
-    showModel3() {
-      this.visible3 = true;
-    },
-    showModel4() {
-      this.visible4 = true;
-    },
-    showModel5() {
-      this.visible5 = true;
-    },
-  },
-  watch: {
-    visible1: function (val) {
-      if (val) {
-        this.initBarChart1();
-      }
-    },
-    visible2: function (val) {
-      if (val) {
-        this.initBarChart2();
-      }
-    },
-    visible3: function (val) {
-      if (val) {
-        this.initBarChart3();
-      }
-    },
-    visible4: function (val) {
-      if (val) {
-        this.initBarChart4();
-      }
-    },
-    visible5: function (val) {
-      if (val) {
-        this.initBarChart5();
-      }
-    },
-  },
-};
+            showModel5() {
+                this.visible5 = true;
+            },
+        },
+        watch: {
+            visible1: function (val) {
+                if (val) {
+                    this.initBarChart1();
+                }
+            },
+            visible2: function (val) {
+                if (val) {
+                    this.initBarChart2();
+                }
+            },
+            visible3: function (val) {
+                if (val) {
+                    this.initBarChart3();
+                }
+            },
+            visible4: function (val) {
+                if (val) {
+                    this.initBarChart4();
+                }
+            },
+            visible5: function (val) {
+                if (val) {
+                    this.initBarChart5();
+                }
+            },
+        },
+    };
 </script>
 
 <style scoped>
@@ -592,4 +593,4 @@ export default {
         -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .4);
         background-color: rgba(0, 0, 0, .01);
     }
-</style>
+</style>

+ 3 - 3
src/components/GlobalFooter.vue

@@ -66,9 +66,9 @@ export default {
 <style scoped>
 /*Zhurui修改,footer固定在视口的最下方*/
 .global-footer-wrapper {
-  /*position: fixed;*/
-  /*bottom: 0;*/
-  /*width: 100%;*/
+  position: absolute;
+  bottom: -220px;
+  width: 100%;
 }
 
 #global-footer-body {

+ 193 - 193
src/components/GlobalHeader.vue

@@ -6,9 +6,9 @@
       <el-menu-item index="1">
         首页
       </el-menu-item>
-      <el-menu-item v-if="isStudent" index="2">
-        任务
-      </el-menu-item>
+      <!--      <el-menu-item v-if="isStudent" index="2">-->
+      <!--        任务-->
+      <!--      </el-menu-item>-->
       <el-menu-item index="3">
         课程
       </el-menu-item>
@@ -16,14 +16,14 @@
         项目
       </el-menu-item>
       <el-menu-item index="5">
-        测试
-      </el-menu-item>
-      <el-menu-item index="6">
-        个人中心
+        任务
       </el-menu-item>
       <el-menu-item v-if="isTeacher" index="7">
         管理
       </el-menu-item>
+      <el-menu-item index="6">
+        个人中心
+      </el-menu-item>
     </el-menu>
     <div id="global-header-icon">
       <el-tooltip content="前往通知页" placement="bottom" effect="light" :show-after="1000">
@@ -33,230 +33,230 @@
           </sup>
           <svg height="32" viewBox="0 0 1024 1024" width="32" xmlns="http://www.w3.org/2000/svg">
             <path
-              d="M849.6 713.4c8.4-0.4 16.7 1.8 23.8 6.4-28.9-18.5-46.4-50.4-46.3-84.8V436c0-145.9-105.7-267.6-246.9-297.5v-7.2c0-37.1-30.1-67.1-67.2-67.1h-0.1c-37.1 0-67.3 30.1-67.3 67.2v7C304.3 168.4 198.7 290 198.7 436v199.1c0 35.7-18.6 66.9-46.4 84.8 7-4.6 15.4-6.9 23.8-6.4-24.7-0.9-45.5 18.4-46.4 43.1-0.9 24.7 18.4 45.5 43.1 46.4h676.6c24.7 0.1 44.8-20 44.9-44.7 0.1-24.8-19.9-44.9-44.7-44.9zM513 959.8c62 0 112.2-50.2 112.2-111.9H400.7c0 61.7 50.2 111.9 112.3 111.9z"
-              fill="#E8AA5B"></path>
+                    d="M849.6 713.4c8.4-0.4 16.7 1.8 23.8 6.4-28.9-18.5-46.4-50.4-46.3-84.8V436c0-145.9-105.7-267.6-246.9-297.5v-7.2c0-37.1-30.1-67.1-67.2-67.1h-0.1c-37.1 0-67.3 30.1-67.3 67.2v7C304.3 168.4 198.7 290 198.7 436v199.1c0 35.7-18.6 66.9-46.4 84.8 7-4.6 15.4-6.9 23.8-6.4-24.7-0.9-45.5 18.4-46.4 43.1-0.9 24.7 18.4 45.5 43.1 46.4h676.6c24.7 0.1 44.8-20 44.9-44.7 0.1-24.8-19.9-44.9-44.7-44.9zM513 959.8c62 0 112.2-50.2 112.2-111.9H400.7c0 61.7 50.2 111.9 112.3 111.9z"
+                    fill="#E8AA5B"></path>
           </svg>
         </div>
       </el-tooltip>
       <el-tooltip content="前往个人中心页" placement="right" effect="light" :show-after="1000">
         <div class="global-header-icon-content" @click="toHome">
-        <ElPopover trigger="hover">
-          <template #reference>
-            <div v-if="isLogin" id="info-circle">
+          <ElPopover trigger="hover">
+            <template #reference>
+              <div v-if="isLogin" id="info-circle">
               <span>
                 {{ singleName }}
               </span>
-            </div>
-            <div v-else>
-              <svg height="32" viewBox="0 0 1025 1024" width="32" xmlns="http://www.w3.org/2000/svg">
-                <path
-                  d="M511.999723 331.913794m-117.748854 0a117.748854 117.748854 0 1 0 235.497708 0 117.748854 117.748854 0 1 0-235.497708 0Z"
-                  fill="#82BAD8"></path>
-                <path
-                  d="M511.999723 0.000554A511.999723 511.999723 0 1 0 1025.10767 512.000277 512.276779 512.276779 0 0 0 511.999723 0.000554zM792.380524 779.636496a24.935051 24.935051 0 0 1-24.935052-24.935052
+              </div>
+              <div v-else>
+                <svg height="32" viewBox="0 0 1025 1024" width="32" xmlns="http://www.w3.org/2000/svg">
+                  <path
+                          d="M511.999723 331.913794m-117.748854 0a117.748854 117.748854 0 1 0 235.497708 0 117.748854 117.748854 0 1 0-235.497708 0Z"
+                          fill="#82BAD8"></path>
+                  <path
+                          d="M511.999723 0.000554A511.999723 511.999723 0 1 0 1025.10767 512.000277 512.276779 512.276779 0 0 0 511.999723 0.000554zM792.380524 779.636496a24.935051 24.935051 0 0 1-24.935052-24.935052
                   255.445749 255.445749 0 0 0-510.614442 0 24.935051 24.935051 0 0 1-49.870103 0 304.76174 304.76174 0 0 1 205.29859-288.138372 167.896013 167.896013 0 1 1 199.480412 0 304.76174 304.76174 0 0 1 205.575646 288.138372 24.935051 24.935051 0 0 1-24.935051 24.935052z"
-                  fill="#82BAD8"></path>
-              </svg>
-            </div>
-          </template>
-          <InfoCard/>
-        </ElPopover>
-      </div>
+                          fill="#82BAD8"></path>
+                </svg>
+              </div>
+            </template>
+            <InfoCard/>
+          </ElPopover>
+        </div>
       </el-tooltip>
     </div>
   </div>
 </template>
 
 <script>
-import InfoCard from "@/components/InfoCard";
+  import InfoCard from "@/components/InfoCard";
 
-export default {
-  name: "GlobalHeader",
-  components: { InfoCard },
-  data() {
-    return {
-      menuIndex: [
-        ["1", "Portal"],
-        ["2", "Task"],
-        ["3", "Course"],
-        ["4", "Project"],
-        ["5", "Test"],
-        ["6", "Home"],
-        ["7", "Manage"],
-        ["8", "Problem"],
-        ["9", "CourseDetail"],
-        
-      ]
-    };
-  },
-  computed: {
-    isLogin() {
-      return this.$store.getters.isLogin;
-    },
-    name() {
-      return this.$store.state.user.name || "无名氏";
-    },
-    singleName() {
-      return this.name.substring(0, 1);
-    },
-    isTeacher() {
-      return this.$store.getters.isTeacher;
-    },
-    isStudent() {
-      return this.$store.getters.isStudent;
-    },
-    activeMenu() {
-      let out = "1";
-      this.menuIndex.forEach(i => {
-        if (i[1] === this.$route.name) {
-          out = i[0];
-        }
-      });
-      return out;
-    },
-    unReadMessages() {
-      return this.$store.getters.unReadMessages;
-    },
-    unReadAnnouncements() {
-      return this.$store.getters.unReadAnnouncements;
-    },
-    unReadInvitations(){
-      return this.$store.getters.unReadInvitations;
+  export default {
+    name: "GlobalHeader",
+    components: { InfoCard },
+    data() {
+      return {
+        menuIndex: [
+          ["1", "Portal"],
+          ["2", "Task"],
+          ["3", "Course"],
+          ["4", "Project"],
+          ["5", "Test"],
+          ["6", "Home"],
+          ["7", "Manage"],
+          ["8", "Problem"],
+          ["9", "CourseDetail"],
+
+        ]
+      };
     },
-    unreadNum() {
-      const x = this.unReadAnnouncements === undefined ? 0 : this.unReadAnnouncements.length;
-      const y = this.unReadMessages === undefined ? 0 : this.unReadMessages.length;
-      const z = this.unReadInvitations === undefined ? 0 : this.unReadInvitations.length;
-      return x + y + z> 99 ? "99+" : x + y + z + "";
+    computed: {
+      isLogin() {
+        return this.$store.getters.isLogin;
+      },
+      name() {
+        return this.$store.state.user.name || "无名氏";
+      },
+      singleName() {
+        return this.name.substring(0, 1);
+      },
+      isTeacher() {
+        return this.$store.getters.isTeacher;
+      },
+      isStudent() {
+        return this.$store.getters.isStudent;
+      },
+      activeMenu() {
+        let out = "1";
+        this.menuIndex.forEach(i => {
+          if (i[1] === this.$route.name) {
+            out = i[0];
+          }
+        });
+        return out;
+      },
+      unReadMessages() {
+        return this.$store.getters.unReadMessages;
+      },
+      unReadAnnouncements() {
+        return this.$store.getters.unReadAnnouncements;
+      },
+      unReadInvitations(){
+        return this.$store.getters.unReadInvitations;
+      },
+      unreadNum() {
+        const x = this.unReadAnnouncements === undefined ? 0 : this.unReadAnnouncements.length;
+        const y = this.unReadMessages === undefined ? 0 : this.unReadMessages.length;
+        const z = this.unReadInvitations === undefined ? 0 : this.unReadInvitations.length;
+        return x + y + z> 99 ? "99+" : x + y + z + "";
+      },
     },
-  },
 
-  watch: {
-    isLogin(newData) {
-      if (newData) {
-        this.$store.dispatch("fetchMessages", this);
+    watch: {
+      isLogin(newData) {
+        if (newData) {
+          this.$store.dispatch("fetchMessages", this);
+        }
+      },
+      $route() {
+        if (this.isLogin) {
+          this.$store.dispatch("fetchMessages", this);
+        }
       }
     },
-    $route() {
+
+    created() {
       if (this.isLogin) {
         this.$store.dispatch("fetchMessages", this);
       }
-    }
-  },
-
-  created() {
-    if (this.isLogin) {
-      this.$store.dispatch("fetchMessages", this);
-    }
-  },
-
-  methods: {
-    toPortal() {
-      this.$router.push("/portal");
-    },
-    toHome() {
-      this.$router.push("/home");
     },
-    toMessage() {
-      this.$router.push("/message");
-    },
-    handleMenuSelect(key) {
-      let target = "/portal";
-      this.menuIndex.forEach(i => {
-        if (i[0] === key) {
-          target = i[1];
-        }
-      });
-      this.$router.push({ name: target });
+
+    methods: {
+      toPortal() {
+        this.$router.push("/portal");
+      },
+      toHome() {
+        this.$router.push("/home");
+      },
+      toMessage() {
+        this.$router.push("/message");
+      },
+      handleMenuSelect(key) {
+        let target = "/portal";
+        this.menuIndex.forEach(i => {
+          if (i[0] === key) {
+            target = i[1];
+          }
+        });
+        this.$router.push({ name: target });
+      },
     },
-  },
-};
+  };
 </script>
 
 <style scoped>
-#global-header-body {
-  width: calc(100% - 2px);
-  height: 48px;
-  position: sticky;
-  top: 0;
-  z-index: 999;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  background: white;
-  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
-  border: 1px solid #e4e7ed;
-}
+  #global-header-body {
+    width: calc(100% - 2px);
+    height: 48px;
+    position: sticky;
+    top: 0;
+    z-index: 999;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    background: white;
+    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+    border: 1px solid #e4e7ed;
+  }
 
-#global-header-logo {
-  height: 32px;
-  margin-left: 150px;
-  cursor: pointer;
-}
+  #global-header-logo {
+    height: 32px;
+    margin-left: 150px;
+    cursor: pointer;
+  }
 
-:deep(.el-menu--horizontal) {
-  height: 48px;
-}
+  :deep(.el-menu--horizontal) {
+    height: 48px;
+  }
 
-:deep(.el-menu--horizontal>.el-submenu .el-submenu__title) {
-  height: 48px;
-  position: relative;
-  bottom: 5px;
-}
+  :deep(.el-menu--horizontal>.el-submenu .el-submenu__title) {
+    height: 48px;
+    position: relative;
+    bottom: 5px;
+  }
 
-:deep(.el-menu--horizontal>.el-menu-item) {
-  height: 48px;
-  position: relative;
-  bottom: 5px;
-}
+  :deep(.el-menu--horizontal>.el-menu-item) {
+    height: 48px;
+    position: relative;
+    bottom: 5px;
+  }
 
-#menu li{
-  color: black;
-  border-bottom: none;
-}
+  #menu li{
+    color: black;
+    border-bottom: none;
+  }
 
 
-#global-header-icon {
-  width: 120px;
-  margin-right: 150px;
-  display: flex;
-  justify-content: space-around;
-}
+  #global-header-icon {
+    width: 120px;
+    margin-right: 150px;
+    display: flex;
+    justify-content: space-around;
+  }
 
-.global-header-icon-content {
-  cursor: pointer;
-}
+  .global-header-icon-content {
+    cursor: pointer;
+  }
 
-#info-circle {
-  height: 32px;
-  width: 32px;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  border-radius: 50%;
-  background: #619dc9;
-}
+  #info-circle {
+    height: 32px;
+    width: 32px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    border-radius: 50%;
+    background: #619dc9;
+  }
 
-#info-circle span {
-  color: white;
-  font-weight: bold;
-}
+  #info-circle span {
+    color: white;
+    font-weight: bold;
+  }
 
-.reminder {
-  position: absolute;
-  top: 0;
-  right: 0;
-  transform: translateY(-25%) translateX(35%);
-  background-color: #f56c6c;
-  border-radius: 10px;
-  color: #fff;
-  display: inline-block;
-  font-size: 12px;
-  height: 18px;
-  line-height: 18px;
-  padding: 0 6px;
-  text-align: center;
-  white-space: nowrap;
-  border: 1px solid #fff;
-}
+  .reminder {
+    position: absolute;
+    top: 0;
+    right: 0;
+    transform: translateY(-25%) translateX(35%);
+    background-color: #f56c6c;
+    border-radius: 10px;
+    color: #fff;
+    display: inline-block;
+    font-size: 12px;
+    height: 18px;
+    line-height: 18px;
+    padding: 0 6px;
+    text-align: center;
+    white-space: nowrap;
+    border: 1px solid #fff;
+  }
 </style>

+ 6 - 1
src/components/ProjectCard.vue

@@ -34,6 +34,7 @@ export default {
   props: {
     projectVO: Object,
     type: String,
+    isPublic: undefined,
   },
   data() {
     return {
@@ -69,6 +70,9 @@ export default {
           duration: 1000,
         });
         await this.$router.push({name: "Auth", params: {login_to: "/portal"}});
+      } else if (this.isPublic) {
+        const courseId = (await this.$apis.findCourseByName(this.isPublic)).data.data.id;
+        await this.$router.push(`/course/${courseId}`);
       } else {
         if (this.projectVO.name) {
           window.open("https://devcloud.seec.seecoder.cn/project/" + this.projectVO.id + "/schedule?id_token=" + this.$store.state.user.token);
@@ -95,7 +99,7 @@ export default {
 
 .project:hover {
   cursor: pointer;
-  border: 1px solid #aaaaaa;
+  border: 1px solid #999999;
 }
 
 .projectId {
@@ -109,6 +113,7 @@ export default {
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
+  font-weight: bold;
 }
 
 .project-description {

+ 66 - 78
src/components/TestCard.vue

@@ -47,7 +47,7 @@
 </template>
 
 <script>
-import {ElMessage, ElMessageBox} from "element-plus";
+import {ElMessage} from "element-plus";
 import store from "@/store";
 import timeUtil from "@/utils/time";
 
@@ -70,11 +70,18 @@ export default {
       return store.state.user.token;
     },
     isCreator() {
-      if (this.testVO.examId) {
-        return Number(this.testVO.course.teacherId) === Number(this.$store.state.user.id);
-      } else {
-        return this.testVO.creator.username === this.$store.state.user.username;
+      let result = null;
+      switch (this.type) {
+        case "eval":
+          result = Number(this.testVO.course.teacherId) === Number(this.$store.state.user.id);
+          break;
+        case "coder":
+          result = this.testVO.creator.username === this.$store.state.user.username;
+          break;
+        default:
+          break;
       }
+      return result;
     },
     isTeacher() {
       return this.$store.getters.isTeacher;
@@ -174,8 +181,9 @@ export default {
     }
   },
   methods: {
-    // TODO 分情况处理跳转
     async toTestInfo() {
+      const _this = this;
+      // 未登录
       if (!this.isLogin) {
         ElMessage({
           showClose: true,
@@ -186,90 +194,70 @@ export default {
         await this.$router.push({name: "Auth", params: {login_to: "/portal"}});
         return;
       }
-
-      console.log(this.testVO);
-
+      // 已登录
+      // 教师(拥有者)
       if (this.isCreator) {
         if (this.type === "eval") {
-          this.$router.push(`/exam/${this.testVO.examId}`);
-          // window.open("https://eval.seec.seecoder.cn/teacher/exam/" + this.testVO.examId + "/details?id_token" + this.$store.state.user.token);
+          this.toEvalExamPage(this.testVO.examId);
         } else {
-          this.$router.push(`/exam/${this.testVO.id}`); //跳转到考试详情页
-          // window.open("https://coder.seec.seecoder.cn/exam/" + this.testVO.id + "?id_token=" + this.$store.state.user.token);
+          this.toCoderExamPage(this.testVO.id);
         }
-      } else if (this.isTeacher) {
+      }
+      // 其他教师
+      else if (this.isTeacher) {
         this.$message.error("无权访问其他教师创建的课程");
-      } else {
-        let messageBoxContent = "";
-        let messageBoxTitle = "";
-        let confirmButtonText = "";
-        let cancelButtonText = "让我想想";
-        let nextURL = "";
-        if (this.type === "eval") {
-          messageBoxTitle = "Eval";
-          if (this.testVO.isJoined) {
-            nextURL = "https://eval.seec.seecoder.cn/exam/" + this.testVO.id + "/before-exam/?id_token=" + this.$store.state.user.token;
-            window.open(nextURL);
-            return;
-          } else {
-            const courseId = (await this.$apis.getCourseByEvalId(this.testVO.course.id)).data.data;
-            if (courseId) {
-              const isCourseSelected = (await this.$apis.checkCourseSelection(courseId, this.$store.state.user.id)).data.data;
-              if (isCourseSelected) {
-                messageBoxContent = "是否立即查看测试详情";
-                confirmButtonText = "立即查看";
-                nextURL = "https://eval.seec.seecoder.cn/student/home/?id_token=" + this.$store.state.user.token;
-              } else {
-                messageBoxContent = "尚未参加课程,是否立即参加?";
-                confirmButtonText = "立即选课";
-                nextURL = "/course/" + courseId;
-              }
-            } else {
-              messageBoxContent = "是否立即查看测试详情";
-              confirmButtonText = "立即查看";
-              nextURL = "https://eval.seec.seecoder.cn/student/home/?id_token=" + this.$store.state.user.token;
-            }
+      }
+      // 学生
+      else {
+        if (this.testVO.isJoined || this.testVO.joined) {
+          switch (_this.type) {
+            case "coder":
+              _this.toCoderExamPage(_this.testVO.id);
+              break;
+            case "eval":
+              _this.toEvalExamPage(_this.testVO.examId, "student");
+              break;
+            default:
+              break;
           }
         } else {
-          messageBoxTitle = "Coder";
-          if (this.testVO.joined) {
-            nextURL = "https://coder.seec.seecoder.cn/exam/" + this.testVO.id + "?id_token=" + this.$store.state.user.token;
-            window.open(nextURL);
-            return;
-          } else {
-            const courseId = (await this.$apis.getCourseByCoderId(this.testVO.courseId)).data.data;
-            if (courseId) {
-              const isCourseSelected = (await this.$apis.checkCourseSelection(courseId, this.$store.state.user.id)).data.data;
-              if (isCourseSelected) {
-                messageBoxContent = "是否立即查看测试详情";
-                confirmButtonText = "立即查看";
-                this.$router.push("/exam/" + this.testVO.id);
-                // nextURL = "https://coder.seec.seecoder.cn/exam?id_token=" + this.$store.state.user.token;
-              } else {
-                messageBoxContent = "尚未选择课程,是否立即参加?";
-                confirmButtonText = "立即选课";
-                nextURL = "/course/" + courseId;
-              }
-            } else {
-              messageBoxContent = "是否立即查看测试详情";
-              confirmButtonText = "立即查看";
-              nextURL = "https://coder.seec.seecoder.cn/exam?id_token=" + this.$store.state.user.token;
-            }
+          let courseId;
+          switch (this.type) {
+            case "coder":
+              courseId = (await this.$apis.getCourseByCoderId(this.testVO.courseId)).data.data.id;
+              break;
+            case "eval":
+              courseId = (await this.$apis.getCourseByEvalId(this.testVO.course.id)).data.data.id;
+              break;
+            default:
+              break;
           }
-        }
-        ElMessageBox.confirm(messageBoxContent, messageBoxTitle, {
-          distinguishCancelAndClose: true,
-          confirmButtonText,
-          cancelButtonText,
-        }).then(() => {
-          if (nextURL.startsWith("http")) {
-            window.open(nextURL);
+          const isSelected = (await this.$apis.checkCourseSelection(courseId, this.$store.state.user.id));
+          if (isSelected) {
+            switch (_this.type) {
+              case "coder":
+                _this.toCoderExamPage(_this.testVO.id);
+                break;
+              case "eval":
+                _this.toEvalExamPage(_this.testVO.examId, "student");
+                break;
+              default:
+                break;
+            }
           } else {
-            this.$router.push(nextURL);
+            this.$router.push(`/course/${courseId}`);
           }
-        });
+        }
       }
     },
+
+    toEvalExamPage(examId, role="teacher") {
+      this.$router.push(`/evalExam/${examId}/${role}/details`);
+    },
+
+    toCoderExamPage(examId) {
+      this.$router.push(`/exam/${examId}`);
+    }
   }
 };
 </script>

+ 1 - 1
src/router/index.js

@@ -127,7 +127,7 @@ const routes = [
     component: () =>import("../views/ExamPage/evalExamPage/teacherExamDetails")
   },
   {
-    path: "/evalExam/:examId/student/details",
+    path: "/evalExam/student/details",
     name: "student-examDetails",
     component: () =>import("../views/ExamPage/evalExamPage/studentExamDetails")
   },

+ 36 - 37
src/views/CoursePage/tabs/TaskTab.vue

@@ -499,42 +499,42 @@ export default {
     toTask(task) {
       const _this = this;
       const type = task["examId"] ? "eval" : "coder";
-      let evalUrl;
-      let evalExamUrl;
-      let coderUrl;
-      let url;
-      if (_this.isStudent) {
-        evalUrl = "https://eval.seec.seecoder.cn/student/home/";
-        evalExamUrl = "https://eval.seec.seecoder.cn/exam/";
-        coderUrl = "https://coder.seec.seecoder.cn/exam/";
-        switch (this.state(task)) {
-          case "NOT_STARTED":
-            url = type === "eval" ? evalUrl : coderUrl;
-            break;
-          case "CLOSED":
-            url = type === "eval" ? evalUrl : coderUrl;
-            break;
-          case "FINISHED":
-            url = type === "eval" ? evalUrl : coderUrl;
-            break;
-          case "RUNNING":
-            if (task["isJoined"] || task["joined"]) {
-              url = type === "eval" ? evalExamUrl + task["examId"] + "/before-exam" : coderUrl + task.id;
-            } else {
-              url = type === "eval" ? evalUrl : coderUrl;
-            }
-            break;
-        }
-      } else {
-        evalUrl = "https://eval.seec.seecoder.cn/teacher/exam/";
-        coderUrl = "https://coder.seec.seecoder.cn/exam/";
-        url = type === "eval" ? evalUrl + task["examId"] + "/details" : coderUrl + task.id;
-      }
+      // let evalUrl;
+      // let evalExamUrl;
+      // let coderUrl;
+      // let url;
+      // if (_this.isStudent) {
+      //   evalUrl = "https://eval.seec.seecoder.cn/student/home/";
+      //   evalExamUrl = "https://eval.seec.seecoder.cn/exam/";
+      //   coderUrl = "https://coder.seec.seecoder.cn/exam/";
+      //   switch (this.state(task)) {
+      //     case "NOT_STARTED":
+      //       url = type === "eval" ? evalUrl : coderUrl;
+      //       break;
+      //     case "CLOSED":
+      //       url = type === "eval" ? evalUrl : coderUrl;
+      //       break;
+      //     case "FINISHED":
+      //       url = type === "eval" ? evalUrl : coderUrl;
+      //       break;
+      //     case "RUNNING":
+      //       if (task["isJoined"] || task["joined"]) {
+      //         url = type === "eval" ? evalExamUrl + task["examId"] + "/before-exam" : coderUrl + task.id;
+      //       } else {
+      //         url = type === "eval" ? evalUrl : coderUrl;
+      //       }
+      //       break;
+      //   }
+      // } else {
+      //   evalUrl = "https://eval.seec.seecoder.cn/teacher/exam/";
+      //   coderUrl = "https://coder.seec.seecoder.cn/exam/";
+      //   url = type === "eval" ? evalUrl + task["examId"] + "/details" : coderUrl + task.id;
+      // }
       if (type === "coder") {
         _this.$router.push(`/exam/${task.id}`);
 
       } else { //只有eval直接跳转
-        if (_this.isTeacher()) {
+        if (_this.isTeacher) {
           _this.$router.push({
             name: "teacher-examDetails",
             params: {
@@ -544,12 +544,12 @@ export default {
         } else {
           _this.$router.push({
             name: "student-examDetails",
-            params: {
+            query: {
               examId: task["examId"],
+              isJoined: task["isJoined"]
             }
           });
         }
-        // window.open(url + "?id_token=" + this.$store.state.user.token);
       }
     },
     // 创建Coder考试的Dialog
@@ -694,7 +694,7 @@ export default {
         antiCheating: this.evalExamForm.antiCheating,
         isPublic: !this.evalExamForm.isPrivate,
         isHidden: false,
-        courseId: this.courseId,
+        courseId: this.evalId,
         courseName: this.courseName
       };
       console.log("创建eval测试", obj);
@@ -702,7 +702,7 @@ export default {
           _res => {
             ElMessage.success("创建Eval评测成功");
             this.init();
-            console.log(_res.data.data.result);
+            console.log(_res);
             this.evalExamDialog = false;
             this.isEvalExamCreated = !!_res.data;
             console.log(this.isEvalExamCreated);
@@ -717,7 +717,6 @@ export default {
       ).catch(_err => {
         ElMessage.error("创建Eval评测失败");
       });
-
     }
   },
 };

+ 0 - 1
src/views/ExamPage/ExamDetail.vue

@@ -362,7 +362,6 @@ export default {
       this.$apis.getCoderExamByExamId(examId)
           .then(_res => {
             this.exam = _res.data.res;
-            console.log(this.exam);
             if (!this.isAdmin && this.exam.joined) {
               this.fetchResult();
             }

+ 4 - 3
src/views/ExamPage/evalExamPage/EditExam.vue

@@ -1,6 +1,6 @@
 <template>
   <el-row v-if="!showQuestionList" :gutter="20" type="flex" justify="space-between">
-    <el-col :span="24" class="box">
+    <el-col :span="20" class="box">
       <el-card class="box-card" v-if="examInfo">
         <template #header>
           <div class="card-header" v-if="paperQuestionsSet" style="font-size: 20px">
@@ -31,7 +31,7 @@
         </el-row>
       </el-card>
     </el-col>
-    <el-col v-if="!paperQuestionsSet" :span="24" class="box">
+    <el-col v-if="!paperQuestionsSet" :span="20" class="box">
       <el-card class="box-card">
         <span style="font-size: 20px">样卷选择</span>
         <el-divider></el-divider>
@@ -63,7 +63,7 @@
         </el-tabs>
       </el-card>
     </el-col>
-    <el-col v-else :span="24" class="box">
+    <el-col v-else :span="20" class="box">
       <el-card class="box-card">
         <template #header>
           <div class="card-header">
@@ -291,6 +291,7 @@ export default {
   /*overflow-y: auto;*/
   display: flex;
   flex-direction: column;
+  margin-left: 150px;
 }
 
 .el-card {

+ 3 - 2
src/views/ExamPage/evalExamPage/QuestionList.vue

@@ -1,6 +1,6 @@
 <template>
   <el-row :gutter="20" type="flex" justify="space-between">
-    <el-col :span="24" class="box">
+    <el-col :span="20" class="box">
       <el-card class="box-card">
         <span style="font-size: 20px">已选题目</span>
         <el-divider></el-divider>
@@ -35,7 +35,7 @@
         </el-row>
       </el-card>
     </el-col>
-    <el-col :span="24" class="box">
+    <el-col :span="20" class="box">
       <el-card class="box-card">
         <span style="font-size: 20px">试题列表</span>
         <el-divider></el-divider>
@@ -240,6 +240,7 @@ export default {
   /*overflow-y: auto;*/
   display: flex;
   flex-direction: column;
+  margin-left: 150px;
 }
 
 .el-card {

+ 51 - 44
src/views/ExamPage/evalExamPage/studentExamDetails.vue

@@ -1,6 +1,6 @@
 <template>
   <el-row>
-    <el-col :span="24" class="box">
+    <el-col :span="20" class="box">
       <el-card class="box-card" v-if="this.examInfo">
         <span>评测详情</span>
         <el-divider></el-divider>
@@ -21,31 +21,31 @@
             <el-tag class="ml-2" :type="statusToType(state)">{{ state }}</el-tag>
             <el-tag v-if="this.examInfo.isFinished" class="ml-2" type="info">已完成</el-tag>
             <el-button
-                v-if="!this.examInfo.isJoined && (state === '未开始' || state === '进行中')"
-                :disabled="this.examInfo.isJoined"
-                type="primary"
-                style="float: right"
-                @click="onJoinExam">
+              v-if="!isJoined && (state === '未开始' || state === '进行中')"
+              :disabled="this.isJoined"
+              type="primary"
+              style="float: right"
+              @click="onJoinExam">
               报名参加
             </el-button>
             <el-button
-                v-if="this.examInfo.isJoined && state === '未开始'"
-                :disabled="this.examInfo.isJoined"
-                type="primary"
-                style="float: right">
+              v-if="this.isJoined && state === '未开始'"
+              :disabled="this.isJoined"
+              type="primary"
+              style="float: right">
               等待加入
             </el-button>
             <el-button
-                v-if="this.examInfo.isJoined && state === '进行中' && !this.examInfo.isFinished"
-                type="success"
-                style="float: right"
-                @click="onStartExam">
+              v-if="this.isJoined && state === '进行中' && !this.examInfo.isFinished"
+              type="success"
+              style="float: right"
+              @click="onStartExam">
               开始评测
             </el-button>
             <el-button
-                v-if="this.examInfo.isJoined && (state === '已结束' || this.examInfo.isFinished)"
-                style="float: right"
-                @click="onOpenResult">
+              v-if="this.isJoined && (state === '已结束' || this.examInfo.isFinished)"
+              style="float: right"
+              @click="onOpenResult">
               结果报告
             </el-button>
           </div>
@@ -56,7 +56,7 @@
             所属课程: {{ this.courseInfo.name }}
           </el-col>
           <el-col :span="12">
-            监考:{{ this.examInfo.antiCheating ? '是' : '否' }}
+            监考:{{ this.examInfo.antiCheating ? "是" : "否" }}
           </el-col>
         </el-row>
         <el-row>
@@ -110,29 +110,30 @@ export default {
       examInfo: [],
       courseInfo: [],
       examId: 0,
+      isJoined: false,
       state: "",
       inputInviteCode: false,
       examQuestionsNum: 0,
       examCodeQuestionsNum: 0,
       inviteCode: "",
+      examList: [],
+      totalNum: 0
     };
   },
   created() {
-    this.examId=this.$route.params.examId;
-    // this.examId = 84;
+    this.examId = this.$route.query.examId;
+    this.isJoined = this.$route.query.isJoined === "true";
     this.$apis.getExamById(this.examId).then(_res => {
       this.examInfo = _res.data.data.result;
       this.examInfo.skills = this.examInfo.skills.toString();
       this.courseInfo = this.examInfo.course;
       this.state = this.computeExamStateText(
-          this.examInfo.startTime,
-          this.examInfo.endTime
+        this.examInfo.startTime,
+        this.examInfo.endTime
       );
-      this.$apis.getExamSubmitRecordsByUserId(this.examId).then(({ data }) => {
-        console.log(data.data.result);
+      this.$apis.getExamSubmitRecordsByUserId(this.examId).then(({data}) => {
         this.examInfo.isFinished = !!data.data.result.find((val) => !val.message);
       });
-      console.log(this.examInfo);
     });
   },
 
@@ -141,10 +142,10 @@ export default {
 
   updated() {
     this.state = this.computeExamStateText(
-        this.examInfo.startTime,
-        this.examInfo.endTime
+      this.examInfo.startTime,
+      this.examInfo.endTime
     );
-    this.$apis.getExamSubmitRecordsByUserId(this.examId).then(({ data }) => {
+    this.$apis.getExamSubmitRecordsByUserId(this.examId).then(({data}) => {
       console.log(data.data.result);
       this.examInfo.isFinished = !!data.data.result.find((val) => !val.message);
     });
@@ -181,12 +182,12 @@ export default {
       if (this.examInfo.isPublic) {
         const examId = this.examInfo.examId ?? 0;
         this.$apis.joinPublicExam(examId).then(() => {
+          this.isJoined = true;
+          console.log(this.examInfo);
           ElMessage({
             message: "加入考试成功",
             type: "success",
           });
-          this.examInfo.isJoined = true;
-          console.log(this.examInfo);
         });
       } else {
         this.inputInviteCode = true;
@@ -198,20 +199,20 @@ export default {
       const examId = this.examInfo.examId ?? 0;
       const inviteCode = this.inviteCode;
       this.$apis.joinExamByInviteCode(inviteCode, examId)
-          .then(() => {
-            this.inputInviteCode = false;
-            ElMessage({
-              message: "加入考试成功",
-              type: "success",
-            });
-            this.examInfo.isJoined = true;
-            console.log(this.examInfo);
-          })
-          .catch(() => {
-          })
-          .finally(() => {
-            this.inviteCode = "";
+        .then(() => {
+          this.inputInviteCode = false;
+          this.isJoined = true;
+          console.log(this.examInfo);
+          ElMessage({
+            message: "加入考试成功",
+            type: "success",
           });
+        })
+        .catch(() => {
+        })
+        .finally(() => {
+          this.inviteCode = "";
+        });
     },
 
     onStartExam() {
@@ -230,5 +231,11 @@ export default {
 </script>
 
 <style scoped>
-
+.box {
+  height: 80%;
+  /*overflow-y: auto;*/
+  display: flex;
+  flex-direction: column;
+  margin-left: 150px;
+}
 </style>

+ 4 - 3
src/views/ExamPage/evalExamPage/teacherExamDetails.vue

@@ -1,6 +1,6 @@
 <template>
   <el-row v-if="!showQuestionList" :gutter="20" type="flex" justify="space-between">
-    <el-col :span="24" class="box">
+    <el-col :span="20" class="box">
       <el-card class="box-card" v-if="this.examInfo">
         <template #header>
           <div class="card-header" style="font-size: 20px">
@@ -40,7 +40,7 @@
         </el-row>
       </el-card>
     </el-col>
-    <el-col :span="24" class="box">
+    <el-col :span="20" class="box">
       <el-card class="box-card">
         <template #header>
           <div class="card-header">
@@ -85,7 +85,7 @@
         <div v-else v-loading="loading"></div>
       </el-card>
     </el-col>
-    <el-col :span="24" class="box">
+    <el-col :span="20" class="box">
       <el-card class="box-card">
         <span style="font-size: 20px">评测名单</span>
         <el-table :data="joinedUsers" style="width: 100%">
@@ -230,6 +230,7 @@ export default {
   /*overflow-y: auto;*/
   display: flex;
   flex-direction: column;
+  margin-left: 150px;
 }
 
 .el-card {

+ 1 - 1
src/views/HomePage/HomePage.vue

@@ -25,7 +25,7 @@
             <el-icon>
               <Files/>
             </el-icon>
-            <span style="padding-left: 20px">gitlab</span>
+            <span style="padding-left: 20px">Gitlab</span>
           </el-menu-item>
         </el-menu>
       </el-card>

+ 1 - 1
src/views/ManagePage/ManagePage.vue

@@ -30,7 +30,7 @@
         </el-menu>
       </el-card>
     </el-col>
-    <el-col :span="1"/>
+    <el-col :span="2"/>
     <el-col :span="18">
       <el-card id="all-test-card">
         <template #header>

+ 9 - 42
src/views/PortalPage/components/MyTestCard.vue

@@ -41,8 +41,6 @@
 </template>
 
 <script>
-import { ElMessageBox } from "element-plus";
-
 export default {
   name: "MyTestCard",
   props: {
@@ -134,47 +132,16 @@ export default {
       return Y + M + D + h + m;
     },
     toTestInfo() {
-      let messageBoxContent = "";
-      let messageBoxTitle = "";
-      let confirmButtonText = "";
-      let cancelButtonText = "让我想想";
-      let nextURL = "";
-
-      if (this.type === "eval") {
-        messageBoxTitle = "Eval";
-        if (this.testVO.isJoined) {
-          nextURL = "https://eval.seec.seecoder.cn/exam/" + this.testVO.examId + "/before-exam/?id_token=" + this.$store.state.user.token;
-          window.open(nextURL);
-          return;
-        } else {
-          messageBoxContent = "尚未参加该测试,是否立即参加?";
-          confirmButtonText = "立即参加";
-          nextURL = "https://eval.seec.seecoder.cn/student/home/?id_token=" + this.$store.state.user.token;
-        }
-      } else {
-        messageBoxTitle = "Coder";
-        if (this.testVO.joined) {
-          nextURL = "https://coder.seec.seecoder.cn/exam/" + this.testVO.id + "?id_token=" + this.$store.state.user.token;
-          window.open(nextURL);
-          return;
-        } else {
-          messageBoxContent = "尚未参加该测试,是否立即参加?";
-          confirmButtonText = "立即参加";
-          nextURL = "https://coder.seec.seecoder.cn/exam?id_token=" + this.$store.state.user.token;
-        }
+      switch (this.type) {
+        case "coder":
+          this.$router.push(`/exam/${this.testVO.id}`);
+          break;
+        case "eval":
+          this.$router.push(`/evalExam/${this.testVO.examId}/student/details`);
+          break;
+        default:
+          break;
       }
-
-      ElMessageBox.confirm(messageBoxContent, messageBoxTitle, {
-        distinguishCancelAndClose: true,
-        confirmButtonText,
-        cancelButtonText,
-      }).then(() => {
-        if (nextURL.startsWith("http")) {
-          window.open(nextURL);
-        } else {
-          this.$router.push(nextURL);
-        }
-      });
     },
   }
 };

+ 43 - 21
src/views/ProjectPage/ProjectPage.vue

@@ -1,6 +1,6 @@
 <template>
   <el-row id="project-page-body">
-    <el-col :span="3">
+    <el-col :span="4">
       <el-card style="position: fixed;">
         <el-menu default-active="1" @select="handleSelect">
           <el-menu-item index="0">
@@ -26,14 +26,14 @@
             <el-icon>
               <Document/>
             </el-icon>
-            <span style="padding-left: 20px">个人项目分析</span>
+            <span style="padding-left: 20px">个人分析</span>
           </el-menu-item>
 
           <el-menu-item index="4">
             <el-icon>
               <Document/>
             </el-icon>
-            <span style="padding-left: 20px">小组项目分析</span>
+            <span style="padding-left: 20px">小组分析</span>
           </el-menu-item>
 
         </el-menu>
@@ -49,12 +49,26 @@
           </span>
         </template>
         <div v-if="this.activeIndex === '1'">
+          <div v-for="(item, key) in courseProjectList" :key="key">
+            <div v-if="item.length !== 0">
+              <div>
+                <el-divider style="margin: 10px 0 20px 0" content-position="left">{{ key }}</el-divider>
+              </div>
+              <div class="project-page-main">
+                <ProjectCard v-for="project in item"
+                             :is-public="key"
+                             :key="project.id"
+                             :projectVO="project"
+                             type="courseProject"/>
+              </div>
+            </div>
+          </div>
         </div>
 
         <div v-if="this.activeIndex === '2' && isStudent">
           <el-tabs v-model="activeProjectPaneName" style="width: 100%">
             <el-tab-pane label="课程下项目" name="courseProject">
-              <div v-for="(item, key) in courseProjectList" :key="key">
+              <div v-for="(item, key) in myCourseProjects" :key="key">
                 <div v-if="item.length !== 0">
                   <div>
                     <el-divider style="margin: 10px 0 20px 0" content-position="left">{{ key }}</el-divider>
@@ -67,7 +81,7 @@
             </el-tab-pane>
             <el-tab-pane label="非课程项目" name="commonProject">
               <div class="project-page-main">
-                <ProjectCard v-for="(item,key) in commonProjectList" :key="key" :projectVO="item" type="commonProject"></ProjectCard>
+                <ProjectCard v-for="(item,key) in myNonCourseProjects" :key="key" :projectVO="item" type="commonProject"></ProjectCard>
               </div>
             </el-tab-pane>
           </el-tabs>
@@ -86,12 +100,24 @@
                 @click="$router.push('/login')">登录</span>
         </div>
 
-        <div v-if="this.activeIndex === '3'">
-            <AnalysisStudentCard :num="1757"/>
+          <div v-if="this.activeIndex === '3' && !isLogin">
+              请先
+              <span style="cursor: pointer;color: #409eff"
+                    @click="$router.push('/login')">登录</span>
+          </div>
+
+          <div v-if="this.activeIndex === '4' && !isLogin">
+              请先
+              <span style="cursor: pointer;color: #409eff"
+                    @click="$router.push('/login')">登录</span>
+          </div>
+
+        <div v-if="this.activeIndex === '3' && isStudent">
+            <AnalysisStudentCard :num="$store.state.user.id"/>
         </div>
 
-        <div v-if="this.activeIndex === '4'">
-          <AnalysisGroupCard :num="1626"/>
+        <div v-if="this.activeIndex === '4' && isStudent">
+          <AnalysisGroupCard :num="$store.state.user.id"/>
         </div>
 
       </el-card>
@@ -111,12 +137,12 @@ export default {
   data() {
     return {
       activeIndex: "1",
-      courseProjectList: [],
-      commonProjectList: [],
-      ProjectList_my: [],
+      courseProjectList: null,
+      myNonCourseProjects: null,
+      myCourseProjects: null,
       activeProjectPaneName: "courseProject",
       activeProjectPaneName_my: "courseProject_my",
-      userId:1575,//传递给分析系统
+      userId:this.$store.state.user.id,//传递给分析系统
     };
   },
   computed: {
@@ -144,19 +170,15 @@ export default {
   },
   mounted() {
     this.$apis.findCourseProjects().then(res =>{
-        this.courseProjectList = res.data.data;
-        console.log(this.courseProjectList);
+        this.myCourseProjects = res.data.data;
         });
 
     this.$apis.findNonCourseProjects().then(res =>{
-      this.commonProjectList = res.data.data;
-      console.log(this.commonProjectList);
+      this.myNonCourseProjects = res.data.data;
     });
 
-    this.$apis.findProjectById(this.$store.state.user.id).then(res =>{
-      this.ProjectList_my = res.data.data;
-      this.userId = this.$store.state.user.id;
-      console.log(this.ProjectList_my);
+    this.$apis.findAllPublicProjectsGroupByCourse().then(res =>{
+      this.courseProjectList = res.data.data;
     });
 
   },

+ 281 - 280
src/views/TaskPage/TaskPage.vue

@@ -1,290 +1,291 @@
-<template>
-  <div id="task-page-body">
+//此页面转移至TestPage
+<!--<template>-->
+<!--  <div id="task-page-body">-->
 
-    <el-card>
-      <template #header>
-          <span style="font-weight: bold; font-size: larger">
-            即将到期
-          </span>
-      </template>
-      <div id="task-page-expiring-main">
-        <TestCard v-for="item in expiringTaskList_show" :key="item.id" :testVO="item"/>
-      </div>
-      <el-pagination
-        :page-size="4"
-        :total="expiringTaskList.length"
-        @current-change="handleCurrentChange"
-        layout="total, prev, pager, next"
-        style="width: 200px; margin: 10px auto 0 auto"/>
-    </el-card>
+<!--    <el-card>-->
+<!--      <template #header>-->
+<!--          <span style="font-weight: bold; font-size: larger">-->
+<!--            即将到期-->
+<!--          </span>-->
+<!--      </template>-->
+<!--      <div id="task-page-expiring-main">-->
+<!--        <TestCard v-for="item in expiringTaskList_show" :key="item.id" :testVO="item"/>-->
+<!--      </div>-->
+<!--      <el-pagination-->
+<!--        :page-size="4"-->
+<!--        :total="expiringTaskList.length"-->
+<!--        @current-change="handleCurrentChange"-->
+<!--        layout="total, prev, pager, next"-->
+<!--        style="width: 200px; margin: 10px auto 0 auto"/>-->
+<!--    </el-card>-->
 
-    <el-card>
-      <template #header>
-        <div style="display: flex; justify-content: space-between; align-content: center">
-          <span style="font-weight: bold; font-size: larger;padding-top: 6px">
-            我的任务
-          </span>
-          <el-select placeholder="Select" v-model="selector" filterable clearable>
-            <el-option-group
-              v-for="group in options"
-              :key="group.label"
-              :label="group.label"
-            >
-              <el-option
-                v-for="item in group.options"
-                :key="item.value"
-                :label="item.label"
-                :value="item.value"
-              />
-            </el-option-group>
-          </el-select>
-        </div>
-      </template>
-      <div id="task-page-all-task-main">
-        <div class="task-content">
-          <TestCard v-for="item in myTaskList" :key="item.id" :testVO="item"/>
-        </div>
-        <!--        <el-tabs v-model="activeTaskPaneName">-->
-        <!--          <el-tab-pane label="评测" name="eval">-->
-        <!--            <div class="task-content">-->
-        <!--              <TestCard v-for="item in myEvalExamList" :key="item.id" :testVO="item"/>-->
-        <!--            </div>-->
-        <!--          </el-tab-pane>-->
-        <!--          <el-tab-pane label="代码" name="coder">-->
-        <!--            <div class="task-content">-->
-        <!--              <TestCard v-for="item in myCoderExamList" :key="item.id" :testVO="item"/>-->
-        <!--            </div>-->
-        <!--          </el-tab-pane>-->
-        <!--        </el-tabs>-->
-      </div>
-    </el-card>
+<!--    <el-card>-->
+<!--      <template #header>-->
+<!--        <div style="display: flex; justify-content: space-between; align-content: center">-->
+<!--          <span style="font-weight: bold; font-size: larger;padding-top: 6px">-->
+<!--            我的任务-->
+<!--          </span>-->
+<!--          <el-select placeholder="Select" v-model="selector" filterable clearable>-->
+<!--            <el-option-group-->
+<!--              v-for="group in options"-->
+<!--              :key="group.label"-->
+<!--              :label="group.label"-->
+<!--            >-->
+<!--              <el-option-->
+<!--                v-for="item in group.options"-->
+<!--                :key="item.value"-->
+<!--                :label="item.label"-->
+<!--                :value="item.value"-->
+<!--              />-->
+<!--            </el-option-group>-->
+<!--          </el-select>-->
+<!--        </div>-->
+<!--      </template>-->
+<!--      <div id="task-page-all-task-main">-->
+<!--        <div class="task-content">-->
+<!--          <TestCard v-for="item in myTaskList" :key="item.id" :testVO="item"/>-->
+<!--        </div>-->
+<!--        &lt;!&ndash;        <el-tabs v-model="activeTaskPaneName">&ndash;&gt;-->
+<!--        &lt;!&ndash;          <el-tab-pane label="评测" name="eval">&ndash;&gt;-->
+<!--        &lt;!&ndash;            <div class="task-content">&ndash;&gt;-->
+<!--        &lt;!&ndash;              <TestCard v-for="item in myEvalExamList" :key="item.id" :testVO="item"/>&ndash;&gt;-->
+<!--        &lt;!&ndash;            </div>&ndash;&gt;-->
+<!--        &lt;!&ndash;          </el-tab-pane>&ndash;&gt;-->
+<!--        &lt;!&ndash;          <el-tab-pane label="代码" name="coder">&ndash;&gt;-->
+<!--        &lt;!&ndash;            <div class="task-content">&ndash;&gt;-->
+<!--        &lt;!&ndash;              <TestCard v-for="item in myCoderExamList" :key="item.id" :testVO="item"/>&ndash;&gt;-->
+<!--        &lt;!&ndash;            </div>&ndash;&gt;-->
+<!--        &lt;!&ndash;          </el-tab-pane>&ndash;&gt;-->
+<!--        &lt;!&ndash;        </el-tabs>&ndash;&gt;-->
+<!--      </div>-->
+<!--    </el-card>-->
 
-  </div>
-</template>
+<!--  </div>-->
+<!--</template>-->
 
-<script>
-import TestCard from "@/components/TestCard";
+<!--<script>-->
+<!--import TestCard from "@/components/TestCard";-->
 
-const options = [
-  {
-    label: "全部测试",
-    options: [
-      {
-        value: "ALL",
-        label: "全部测试题",
-      },
-      {
-        value: "ALL_NOT_STARTED",
-        label: "全部未开始",
-      },
-      {
-        value: "ALL_RUNNING_IN",
-        label: "全部已参加",
-      },
-      {
-        value: "ALL_RUNNING_NOT",
-        label: "全部未参加",
-      },
-      {
-        value: "ALL_FINISHED",
-        label: "全部已结束",
-      },
-    ]
-  },
-  {
-    label: "评测题",
-    options: [
-      {
-        value: "EVAL_ALL",
-        label: "全部评测题",
-      },
-      {
-        value: "EVAL_NOT_STARTED",
-        label: "未开始评测题",
-      },
-      {
-        value: "EVAL_RUNNING_IN",
-        label: "已参加评测题",
-      },
-      {
-        value: "EVAL_RUNNING_NOT",
-        label: "未参加评测题",
-      },
-      {
-        value: "EVAL_FINISHED",
-        label: "已结束评测题",
-      },
-    ],
-  },
-  {
-    label: "代码题",
-    options: [
-      {
-        value: "CODER_ALL",
-        label: "全部代码题",
-      },
-      {
-        value: "CODER_NOT_STARTED",
-        label: "未开始代码题",
-      },
-      {
-        value: "CODER_RUNNING_IN",
-        label: "已参加代码题",
-      },
-      {
-        value: "CODER_RUNNING_NOT",
-        label: "未参加代码题",
-      },
-      {
-        value: "CODER_FINISHED",
-        label: "已结束代码题",
-      },
-    ],
-  },
-];
-export default {
-  name: "TaskPage",
-  components: {TestCard},
-  data() {
-    return {
-      myEvalExamList: [],
-      myCoderExamList: [],
-      expiringTask_currentPage: 1,
-      activeTaskPaneName: "eval",
-      options: options,
-      selector: "ALL",
-    };
-  },
-  computed: {
-    expiringTaskList_show() {
-      return this.expiringTaskList.slice((this.expiringTask_currentPage - 1) * 4, this.expiringTask_currentPage * 4);
-    },
-    expiringTaskList() {
-      return []
-        .concat(this.myEvalExamList)
-        .concat(this.myCoderExamList)
-        .sort((a, b) => {
-          let a_time = a["endAt"] * 1000 || new Date(a.endTime).getTime();
-          let b_time = b["endAt"] * 1000 || new Date(b.endTime).getTime();
-          return a_time - b_time;
-        })
-        .filter(i => (this.state(i) === "RUNNING_IN" || this.state(i) === "RUNNING_NOT"));
-    },
-    myTaskList() {
-      let out = []
-        .concat(this.myEvalExamList)
-        .concat(this.myCoderExamList)
-        .sort((a, b) => {
-          return this.state(b).charCodeAt(0) - this.state(a).charCodeAt(0);
-        });
-      switch (this.selector) {
-        case "ALL":
-          break;
-        case "ALL_NOT_STARTED":
-          out = out.filter(i => this.state(i) === "NOT_STARTED");
-          break;
-        case "ALL_RUNNING_IN":
-          out = out.filter(i => this.state(i) === "RUNNING_IN");
-          break;
-        case "ALL_RUNNING_NOT":
-          out = out.filter(i => this.state(i) === "RUNNING_NOT");
-          break;
-        case "ALL_FINISHED":
-          out = out.filter(i => this.state(i) === "FINISHED" || this.state(i) === "CLOSED");
-          break;
-        case "EVAL_ALL":
-          out = out.filter(i => i.examId !== undefined);
-          break;
-        case "EVAL_NOT_STARTED":
-          out = out.filter(i => (i.examId !== undefined && this.state(i) === "NOT_STARTED"));
-          break;
-        case "EVAL_RUNNING_IN":
-          out = out.filter(i => (i.examId !== undefined && this.state(i) === "RUNNING_IN"));
-          break;
-        case "EVAL_RUNNING_NOT":
-          out = out.filter(i => (i.examId !== undefined && this.state(i) === "RUNNING_NOT"));
-          break;
-        case "EVAL_FINISHED":
-          out = out.filter(i => (i.examId !== undefined && this.state(i) === "FINISHED"));
-          break;
-        case "CODER_ALL":
-          out = out.filter(i => i.examId === undefined);
-          break;
-        case "CODER_NOT_STARTED":
-          out = out.filter(i => (i.examId === undefined && this.state(i) === "NOT_STARTED"));
-          break;
-        case "CODER_RUNNING_IN":
-          out = out.filter(i => (i.examId === undefined && this.state(i) === "RUNNING_IN"));
-          break;
-        case "CODER_RUNNING_NOT":
-          out = out.filter(i => (i.examId === undefined && this.state(i) === "RUNNING_NOT"));
-          break;
-        case "CODER_FINISHED":
-          out = out.filter(i => (i.examId === undefined && (this.state(i) === "FINISHED" || this.state(i) === "CLOSED")));
-          break;
-      }
-      return out;
-    },
-  },
+<!--const options = [-->
+<!--  {-->
+<!--    label: "全部测试",-->
+<!--    options: [-->
+<!--      {-->
+<!--        value: "ALL",-->
+<!--        label: "全部测试题",-->
+<!--      },-->
+<!--      {-->
+<!--        value: "ALL_NOT_STARTED",-->
+<!--        label: "全部未开始",-->
+<!--      },-->
+<!--      {-->
+<!--        value: "ALL_RUNNING_IN",-->
+<!--        label: "全部已参加",-->
+<!--      },-->
+<!--      {-->
+<!--        value: "ALL_RUNNING_NOT",-->
+<!--        label: "全部未参加",-->
+<!--      },-->
+<!--      {-->
+<!--        value: "ALL_FINISHED",-->
+<!--        label: "全部已结束",-->
+<!--      },-->
+<!--    ]-->
+<!--  },-->
+<!--  {-->
+<!--    label: "评测题",-->
+<!--    options: [-->
+<!--      {-->
+<!--        value: "EVAL_ALL",-->
+<!--        label: "全部评测题",-->
+<!--      },-->
+<!--      {-->
+<!--        value: "EVAL_NOT_STARTED",-->
+<!--        label: "未开始评测题",-->
+<!--      },-->
+<!--      {-->
+<!--        value: "EVAL_RUNNING_IN",-->
+<!--        label: "已参加评测题",-->
+<!--      },-->
+<!--      {-->
+<!--        value: "EVAL_RUNNING_NOT",-->
+<!--        label: "未参加评测题",-->
+<!--      },-->
+<!--      {-->
+<!--        value: "EVAL_FINISHED",-->
+<!--        label: "已结束评测题",-->
+<!--      },-->
+<!--    ],-->
+<!--  },-->
+<!--  {-->
+<!--    label: "代码题",-->
+<!--    options: [-->
+<!--      {-->
+<!--        value: "CODER_ALL",-->
+<!--        label: "全部代码题",-->
+<!--      },-->
+<!--      {-->
+<!--        value: "CODER_NOT_STARTED",-->
+<!--        label: "未开始代码题",-->
+<!--      },-->
+<!--      {-->
+<!--        value: "CODER_RUNNING_IN",-->
+<!--        label: "已参加代码题",-->
+<!--      },-->
+<!--      {-->
+<!--        value: "CODER_RUNNING_NOT",-->
+<!--        label: "未参加代码题",-->
+<!--      },-->
+<!--      {-->
+<!--        value: "CODER_FINISHED",-->
+<!--        label: "已结束代码题",-->
+<!--      },-->
+<!--    ],-->
+<!--  },-->
+<!--];-->
+<!--export default {-->
+<!--  name: "TaskPage",-->
+<!--  components: {TestCard},-->
+<!--  data() {-->
+<!--    return {-->
+<!--      myEvalExamList: [],-->
+<!--      myCoderExamList: [],-->
+<!--      expiringTask_currentPage: 1,-->
+<!--      activeTaskPaneName: "eval",-->
+<!--      options: options,-->
+<!--      selector: "ALL",-->
+<!--    };-->
+<!--  },-->
+<!--  computed: {-->
+<!--    expiringTaskList_show() {-->
+<!--      return this.expiringTaskList.slice((this.expiringTask_currentPage - 1) * 4, this.expiringTask_currentPage * 4);-->
+<!--    },-->
+<!--    expiringTaskList() {-->
+<!--      return []-->
+<!--        .concat(this.myEvalExamList)-->
+<!--        .concat(this.myCoderExamList)-->
+<!--        .sort((a, b) => {-->
+<!--          let a_time = a["endAt"] * 1000 || new Date(a.endTime).getTime();-->
+<!--          let b_time = b["endAt"] * 1000 || new Date(b.endTime).getTime();-->
+<!--          return a_time - b_time;-->
+<!--        })-->
+<!--        .filter(i => (this.state(i) === "RUNNING_IN" || this.state(i) === "RUNNING_NOT"));-->
+<!--    },-->
+<!--    myTaskList() {-->
+<!--      let out = []-->
+<!--        .concat(this.myEvalExamList)-->
+<!--        .concat(this.myCoderExamList)-->
+<!--        .sort((a, b) => {-->
+<!--          return this.state(b).charCodeAt(0) - this.state(a).charCodeAt(0);-->
+<!--        });-->
+<!--      switch (this.selector) {-->
+<!--        case "ALL":-->
+<!--          break;-->
+<!--        case "ALL_NOT_STARTED":-->
+<!--          out = out.filter(i => this.state(i) === "NOT_STARTED");-->
+<!--          break;-->
+<!--        case "ALL_RUNNING_IN":-->
+<!--          out = out.filter(i => this.state(i) === "RUNNING_IN");-->
+<!--          break;-->
+<!--        case "ALL_RUNNING_NOT":-->
+<!--          out = out.filter(i => this.state(i) === "RUNNING_NOT");-->
+<!--          break;-->
+<!--        case "ALL_FINISHED":-->
+<!--          out = out.filter(i => this.state(i) === "FINISHED" || this.state(i) === "CLOSED");-->
+<!--          break;-->
+<!--        case "EVAL_ALL":-->
+<!--          out = out.filter(i => i.examId !== undefined);-->
+<!--          break;-->
+<!--        case "EVAL_NOT_STARTED":-->
+<!--          out = out.filter(i => (i.examId !== undefined && this.state(i) === "NOT_STARTED"));-->
+<!--          break;-->
+<!--        case "EVAL_RUNNING_IN":-->
+<!--          out = out.filter(i => (i.examId !== undefined && this.state(i) === "RUNNING_IN"));-->
+<!--          break;-->
+<!--        case "EVAL_RUNNING_NOT":-->
+<!--          out = out.filter(i => (i.examId !== undefined && this.state(i) === "RUNNING_NOT"));-->
+<!--          break;-->
+<!--        case "EVAL_FINISHED":-->
+<!--          out = out.filter(i => (i.examId !== undefined && this.state(i) === "FINISHED"));-->
+<!--          break;-->
+<!--        case "CODER_ALL":-->
+<!--          out = out.filter(i => i.examId === undefined);-->
+<!--          break;-->
+<!--        case "CODER_NOT_STARTED":-->
+<!--          out = out.filter(i => (i.examId === undefined && this.state(i) === "NOT_STARTED"));-->
+<!--          break;-->
+<!--        case "CODER_RUNNING_IN":-->
+<!--          out = out.filter(i => (i.examId === undefined && this.state(i) === "RUNNING_IN"));-->
+<!--          break;-->
+<!--        case "CODER_RUNNING_NOT":-->
+<!--          out = out.filter(i => (i.examId === undefined && this.state(i) === "RUNNING_NOT"));-->
+<!--          break;-->
+<!--        case "CODER_FINISHED":-->
+<!--          out = out.filter(i => (i.examId === undefined && (this.state(i) === "FINISHED" || this.state(i) === "CLOSED")));-->
+<!--          break;-->
+<!--      }-->
+<!--      return out;-->
+<!--    },-->
+<!--  },-->
 
-  async created() {
-    this.myEvalExamList = (await this.$apis.getStudentEvalExams()).data.data;
-    this.myCoderExamList = (await this.$apis.getStudentCoderExams({})).data.data["res"];
-  },
+<!--  async created() {-->
+<!--    this.myEvalExamList = (await this.$apis.getStudentEvalExams()).data.data;-->
+<!--    this.myCoderExamList = (await this.$apis.getStudentCoderExams({})).data.data["res"];-->
+<!--  },-->
 
-  methods: {
-    handleCurrentChange(index) {
-      this.expiringTask_currentPage = index;
-    },
-    state(testVO) {
-      const now = new Date();
-      if (testVO.examId !== undefined) {
-        if (new Date(testVO.endTime) < now) {
-          return "FINISHED";
-        } else if (new Date(testVO.startTime) > now) {
-          return "NOT_STARTED";
-        } else if (testVO.isJoined) {
-          return "RUNNING_IN";
-        } else {
-          return "RUNNING_NOT";
-        }
-      } else {
-        if (testVO.status === "CLOSED") {
-          return "CLOSED";
-        } else if (testVO.startAt * 1000 > now) {
-          return "NOT_STARTED";
-        } else if (testVO.endAt * 1000 < now) {
-          return "FINISHED";
-        } else if (testVO.joined) {
-          return "RUNNING_IN";
-        } else {
-          return "RUNNING_NOT";
-        }
-      }
-    },
-  },
-};
-</script>
+<!--  methods: {-->
+<!--    handleCurrentChange(index) {-->
+<!--      this.expiringTask_currentPage = index;-->
+<!--    },-->
+<!--    state(testVO) {-->
+<!--      const now = new Date();-->
+<!--      if (testVO.examId !== undefined) {-->
+<!--        if (new Date(testVO.endTime) < now) {-->
+<!--          return "FINISHED";-->
+<!--        } else if (new Date(testVO.startTime) > now) {-->
+<!--          return "NOT_STARTED";-->
+<!--        } else if (testVO.isJoined) {-->
+<!--          return "RUNNING_IN";-->
+<!--        } else {-->
+<!--          return "RUNNING_NOT";-->
+<!--        }-->
+<!--      } else {-->
+<!--        if (testVO.status === "CLOSED") {-->
+<!--          return "CLOSED";-->
+<!--        } else if (testVO.startAt * 1000 > now) {-->
+<!--          return "NOT_STARTED";-->
+<!--        } else if (testVO.endAt * 1000 < now) {-->
+<!--          return "FINISHED";-->
+<!--        } else if (testVO.joined) {-->
+<!--          return "RUNNING_IN";-->
+<!--        } else {-->
+<!--          return "RUNNING_NOT";-->
+<!--        }-->
+<!--      }-->
+<!--    },-->
+<!--  },-->
+<!--};-->
+<!--</script>-->
 
-<style scoped>
-#task-page-body {
-  display: grid;
-  grid-template-columns: 1fr;
-  grid-template-rows: auto auto;
-  grid-gap: 20px;
-  margin: 40px 15vw 80px 15vw;
-}
+<!--<style scoped>-->
+<!--#task-page-body {-->
+<!--  display: grid;-->
+<!--  grid-template-columns: 1fr;-->
+<!--  grid-template-rows: auto auto;-->
+<!--  grid-gap: 20px;-->
+<!--  margin: 40px 15vw 80px 15vw;-->
+<!--}-->
 
-#task-page-expiring-main {
-  display: grid;
-  grid-template-rows: 1fr;
-  grid-template-columns: 1fr 1fr 1fr 1fr;
-  grid-gap: 10px;
-}
+<!--#task-page-expiring-main {-->
+<!--  display: grid;-->
+<!--  grid-template-rows: 1fr;-->
+<!--  grid-template-columns: 1fr 1fr 1fr 1fr;-->
+<!--  grid-gap: 10px;-->
+<!--}-->
 
-.task-content {
-  display: grid;
-  grid-template-columns: 1fr 1fr 1fr 1fr;
-  grid-gap: 10px;
-}
-</style>
+<!--.task-content {-->
+<!--  display: grid;-->
+<!--  grid-template-columns: 1fr 1fr 1fr 1fr;-->
+<!--  grid-gap: 10px;-->
+<!--}-->
+<!--</style>-->

+ 334 - 60
src/views/TestPage/TestPage.vue

@@ -21,84 +21,153 @@
             </el-icon>
             <span style="padding-left: 20px">我的测试</span>
           </el-menu-item>
+          <el-menu-item index="3">
+            <el-icon>
+              <DocumentChecked/>
+            </el-icon>
+            <span style="padding-left: 20px">我的任务</span>
+          </el-menu-item>
         </el-menu>
       </el-card>
     </el-col>
     <el-col :span="2"/>
     <el-col :span="18">
-      <el-card>
-        <template #header>
-          <span style="font-weight: bold; font-size: larger">
-            {{ activeName }}
-          </span>
-        </template>
-        <div v-if="this.activeIndex === '1'">
-          <el-tabs v-model="activeTestPaneName" style="width: 100%">
-            <el-tab-pane label="eval测试" name="eval">
-              <div v-for="(item, key) in evalExamList" :key="key">
-                <div v-if="item.length !== 0">
+      <div v-if="this.activeIndex !== '3'">
+        <el-card>
+          <template #header>
+            <span style="font-weight: bold; font-size: larger">
+             {{ activeName }}
+            </span>
+          </template>
+          <div v-if="this.activeIndex === '1'">
+            <el-tabs v-model="activeTestPaneName" style="width: 100%">
+              <el-tab-pane label="eval测试" name="eval">
+                <div v-for="(item, key) in evalExamList" :key="key">
+                  <div v-if="item.length !== 0">
+                    <div>
+                      <el-divider style="margin: 10px 0 20px 0" content-position="left">{{ key }}</el-divider>
+                    </div>
+                    <div class="test-page-main">
+                      <TestCard v-for="exam in item" :key="exam.id" :testVO="exam" :isPublicTest="true"/>
+                    </div>
+                  </div>
+                </div>
+              </el-tab-pane>
+              <el-tab-pane label="coder测试" name="coder">
+                <div v-for="(item, key) in coderExamList" :key="key">
+                  <div v-if="item.length !== 0">
+                    <div>
+                      <el-divider style="margin: 10px 0 20px 0;" content-position="left">{{ key }}</el-divider>
+                    </div>
+                    <div class="test-page-main">
+                      <TestCard v-for="exam in item" :key="exam.id" :testVO="exam"/>
+                    </div>
+                  </div>
+                </div>
+              </el-tab-pane>
+            </el-tabs>
+          </div>
+
+          <div v-if="this.activeIndex === '2' && isStudent">
+            <el-tabs v-model="activeTestPaneName_my" style="width: 100%">
+              <el-tab-pane label="eval测试" name="eval">
+                <div v-for="(item, key) in evalExamList_my" :key="key">
                   <div>
                     <el-divider style="margin: 10px 0 20px 0" content-position="left">{{ key }}</el-divider>
                   </div>
                   <div class="test-page-main">
-                    <TestCard v-for="exam in item" :key="exam.id" :testVO="exam" :isPublicTest="true"/>
+                    <TestCard v-for="exam in item" :key="exam.id" :testVO="exam"/>
                   </div>
                 </div>
-              </div>
-            </el-tab-pane>
-            <el-tab-pane label="coder测试" name="coder">
-              <div v-for="(item, key) in coderExamList" :key="key">
-                <div v-if="item.length !== 0">
+              </el-tab-pane>
+              <el-tab-pane label="coder测试" name="coder">
+                <div v-for="(item, key) in coderExamList_my" :key="key">
                   <div>
-                    <el-divider style="margin: 10px 0 20px 0;" content-position="left">{{ key }}</el-divider>
+                    <el-divider style="margin: 10px 0 20px 0" content-position="left">{{ key }}</el-divider>
                   </div>
                   <div class="test-page-main">
                     <TestCard v-for="exam in item" :key="exam.id" :testVO="exam"/>
                   </div>
                 </div>
-              </div>
-            </el-tab-pane>
-          </el-tabs>
-        </div>
+              </el-tab-pane>
+            </el-tabs>
+          </div>
 
-        <div v-if="this.activeIndex === '2' && isStudent">
-          <el-tabs v-model="activeTestPaneName_my" style="width: 100%">
-            <el-tab-pane label="eval测试" name="eval">
-              <div v-for="(item, key) in evalExamList_my" :key="key">
-                <div>
-                  <el-divider style="margin: 10px 0 20px 0" content-position="left">{{ key }}</el-divider>
-                </div>
-                <div class="test-page-main">
-                  <TestCard v-for="exam in item" :key="exam.id" :testVO="exam"/>
-                </div>
-              </div>
-            </el-tab-pane>
-            <el-tab-pane label="coder测试" name="coder">
-              <div v-for="(item, key) in coderExamList_my" :key="key">
-                <div>
-                  <el-divider style="margin: 10px 0 20px 0" content-position="left">{{ key }}</el-divider>
-                </div>
-                <div class="test-page-main">
-                  <TestCard v-for="exam in item" :key="exam.id" :testVO="exam"/>
-                </div>
-              </div>
-            </el-tab-pane>
-          </el-tabs>
-        </div>
-
-        <div v-if="this.activeIndex === '2' && isTeacher">
-          教师请前往
-          <span style="cursor: pointer;color: #409eff"
+          <div v-if="this.activeIndex === '2' && isTeacher">
+            教师请前往
+            <span style="cursor: pointer;color: #409eff"
                 @click="$router.push('/manage')">管理页面</span>
-          查看相关测试。
-        </div>
+            查看相关测试。
+          </div>
 
-        <div v-if="this.activeIndex === '2' && !isLogin">
-          请先
-          <span style="cursor: pointer;color: #409eff"
+          <div v-if="this.activeIndex === '2' && !isLogin">
+            请先
+            <span style="cursor: pointer;color: #409eff"
                 @click="$router.push('/login')">登录</span>
-        </div>
-      </el-card>
+          </div>
+        </el-card>
+      </div>
+
+      <div v-if="this.activeIndex === '3'">
+        <el-card>
+          <template #header>
+            <span style="font-weight: bold; font-size: larger">
+              即将到期
+            </span>
+          </template>
+          <div id="task-page-expiring-main">
+            <TestCard v-for="item in expiringTaskList_show" :key="item.id" :testVO="item"/>
+          </div>
+          <el-pagination
+              :page-size="4"
+              :total="expiringTaskList.length"
+              @current-change="handleCurrentChange"
+              layout="total, prev, pager, next"
+              style="width: 200px; margin: 10px auto 0 auto"/>
+        </el-card>
+
+        <el-card>
+          <template #header>
+            <div style="display: flex; justify-content: space-between; align-content: center">
+              <span style="font-weight: bold; font-size: larger;padding-top: 6px">
+                我的任务
+              </span>
+              <el-select placeholder="Select" v-model="selector" filterable clearable>
+                <el-option-group
+                    v-for="group in options"
+                    :key="group.label"
+                    :label="group.label"
+                >
+                  <el-option
+                      v-for="item in group.options"
+                      :key="item.value"
+                      :label="item.label"
+                      :value="item.value"
+                  />
+                </el-option-group>
+              </el-select>
+            </div>
+          </template>
+
+          <div id="task-page-all-task-main">
+            <div class="task-content">
+              <TestCard v-for="item in myTaskList" :key="item.id" :testVO="item"/>
+            </div>
+              <!--        <el-tabs v-model="activeTaskPaneName">-->
+              <!--          <el-tab-pane label="评测" name="eval">-->
+              <!--            <div class="task-content">-->
+              <!--              <TestCard v-for="item in myEvalExamList" :key="item.id" :testVO="item"/>-->
+              <!--            </div>-->
+              <!--          </el-tab-pane>-->
+              <!--          <el-tab-pane label="代码" name="coder">-->
+              <!--            <div class="task-content">-->
+              <!--              <TestCard v-for="item in myCoderExamList" :key="item.id" :testVO="item"/>-->
+              <!--            </div>-->
+              <!--          </el-tab-pane>-->
+              <!--        </el-tabs>-->
+          </div>
+        </el-card>
+      </div>
     </el-col>
   </el-row>
 </template>
@@ -106,7 +175,83 @@
 <script>
 import {Back, Document, DocumentChecked} from "@element-plus/icons-vue";
 import TestCard from "@/components/TestCard";
-
+const options = [
+  {
+    label: "全部测试",
+    options: [
+      {
+        value: "ALL",
+        label: "全部测试题",
+      },
+      {
+        value: "ALL_NOT_STARTED",
+        label: "全部未开始",
+      },
+      {
+        value: "ALL_RUNNING_IN",
+        label: "全部已参加",
+      },
+      {
+        value: "ALL_RUNNING_NOT",
+        label: "全部未参加",
+      },
+      {
+        value: "ALL_FINISHED",
+        label: "全部已结束",
+      },
+    ]
+  },
+  {
+    label: "评测题",
+    options: [
+      {
+        value: "EVAL_ALL",
+        label: "全部评测题",
+      },
+      {
+        value: "EVAL_NOT_STARTED",
+        label: "未开始评测题",
+      },
+      {
+        value: "EVAL_RUNNING_IN",
+        label: "已参加评测题",
+      },
+      {
+        value: "EVAL_RUNNING_NOT",
+        label: "未参加评测题",
+      },
+      {
+        value: "EVAL_FINISHED",
+        label: "已结束评测题",
+      },
+    ],
+  },
+  {
+    label: "代码题",
+    options: [
+      {
+        value: "CODER_ALL",
+        label: "全部代码题",
+      },
+      {
+        value: "CODER_NOT_STARTED",
+        label: "未开始代码题",
+      },
+      {
+        value: "CODER_RUNNING_IN",
+        label: "已参加代码题",
+      },
+      {
+        value: "CODER_RUNNING_NOT",
+        label: "未参加代码题",
+      },
+      {
+        value: "CODER_FINISHED",
+        label: "已结束代码题",
+      },
+    ],
+  },
+];
 export default {
   name: "TestPage",
   components: {TestCard, Back, Document, DocumentChecked,},
@@ -119,14 +264,22 @@ export default {
       coderExamList_my: [],
       activeTestPaneName: "eval",
       activeTestPaneName_my: "eval",
+      myEvalExamList: [],
+      myCoderExamList: [],
+      expiringTask_currentPage: 1,
+      activeTaskPaneName: "eval",
+      options: options,
+      selector: "ALL",
     };
   },
   computed: {
     activeName() {
       if (this.activeIndex === "1") {
         return "公开测试";
-      } else {
+      } else if (this.activeIndex === "2"){
         return "我的测试";
+      }else{
+        return "我的任务";
       }
     },
     isTeacher() {
@@ -138,8 +291,77 @@ export default {
     isLogin() {
       return this.$store.getters.isLogin;
     },
+    expiringTaskList_show() {
+      return this.expiringTaskList.slice((this.expiringTask_currentPage - 1) * 4, this.expiringTask_currentPage * 4);
+    },
+    expiringTaskList() {
+      return []
+          .concat(this.myEvalExamList)
+          .concat(this.myCoderExamList)
+          .sort((a, b) => {
+            let a_time = a["endAt"] * 1000 || new Date(a.endTime).getTime();
+            let b_time = b["endAt"] * 1000 || new Date(b.endTime).getTime();
+            return a_time - b_time;
+          })
+          .filter(i => (this.state(i) === "RUNNING_IN" || this.state(i) === "RUNNING_NOT"));
+    },
+    myTaskList() {
+      let out = []
+          .concat(this.myEvalExamList)
+          .concat(this.myCoderExamList)
+          .sort((a, b) => {
+            return this.state(b).charCodeAt(0) - this.state(a).charCodeAt(0);
+          });
+      switch (this.selector) {
+        case "ALL":
+          break;
+        case "ALL_NOT_STARTED":
+          out = out.filter(i => this.state(i) === "NOT_STARTED");
+          break;
+        case "ALL_RUNNING_IN":
+          out = out.filter(i => this.state(i) === "RUNNING_IN");
+          break;
+        case "ALL_RUNNING_NOT":
+          out = out.filter(i => this.state(i) === "RUNNING_NOT");
+          break;
+        case "ALL_FINISHED":
+          out = out.filter(i => this.state(i) === "FINISHED" || this.state(i) === "CLOSED");
+          break;
+        case "EVAL_ALL":
+          out = out.filter(i => i.examId !== undefined);
+          break;
+        case "EVAL_NOT_STARTED":
+          out = out.filter(i => (i.examId !== undefined && this.state(i) === "NOT_STARTED"));
+          break;
+        case "EVAL_RUNNING_IN":
+          out = out.filter(i => (i.examId !== undefined && this.state(i) === "RUNNING_IN"));
+          break;
+        case "EVAL_RUNNING_NOT":
+          out = out.filter(i => (i.examId !== undefined && this.state(i) === "RUNNING_NOT"));
+          break;
+        case "EVAL_FINISHED":
+          out = out.filter(i => (i.examId !== undefined && this.state(i) === "FINISHED"));
+          break;
+        case "CODER_ALL":
+          out = out.filter(i => i.examId === undefined);
+          break;
+        case "CODER_NOT_STARTED":
+          out = out.filter(i => (i.examId === undefined && this.state(i) === "NOT_STARTED"));
+          break;
+        case "CODER_RUNNING_IN":
+          out = out.filter(i => (i.examId === undefined && this.state(i) === "RUNNING_IN"));
+          break;
+        case "CODER_RUNNING_NOT":
+          out = out.filter(i => (i.examId === undefined && this.state(i) === "RUNNING_NOT"));
+          break;
+        case "CODER_FINISHED":
+          out = out.filter(i => (i.examId === undefined && (this.state(i) === "FINISHED" || this.state(i) === "CLOSED")));
+          break;
+      }
+      return out;
+    },
   },
-  mounted() {
+  async mounted() {
     this.$apis.getRecommendEvalExamsGroupByCourse().then(res => {
       this.evalExamList = res.data.data;
     });
@@ -156,6 +378,8 @@ export default {
           this.coderExamList_my = res.data.data;
         });
     }
+    this.myEvalExamList = (await this.$apis.getStudentEvalExams()).data.data;
+    this.myCoderExamList = (await this.$apis.getStudentCoderExams({})).data.data["res"];
   },
   methods: {
     handleSelect(index) {
@@ -164,6 +388,35 @@ export default {
       }
       this.activeIndex = index;
     },
+    handleCurrentChange(index) {
+      this.expiringTask_currentPage = index;
+    },
+    state(testVO) {
+      const now = new Date();
+      if (testVO.examId !== undefined) {
+        if (new Date(testVO.endTime) < now) {
+          return "FINISHED";
+        } else if (new Date(testVO.startTime) > now) {
+          return "NOT_STARTED";
+        } else if (testVO.isJoined) {
+          return "RUNNING_IN";
+        } else {
+          return "RUNNING_NOT";
+        }
+      } else {
+        if (testVO.status === "CLOSED") {
+          return "CLOSED";
+        } else if (testVO.startAt * 1000 > now) {
+          return "NOT_STARTED";
+        } else if (testVO.endAt * 1000 < now) {
+          return "FINISHED";
+        } else if (testVO.joined) {
+          return "RUNNING_IN";
+        } else {
+          return "RUNNING_NOT";
+        }
+      }
+    },
   },
 };
 </script>
@@ -184,4 +437,25 @@ export default {
 :deep(.el-divider) {
   margin: 0;
 }
+
+#task-page-body {
+  display: grid;
+  grid-template-columns: 1fr;
+  grid-template-rows: auto auto;
+  grid-gap: 20px;
+  margin: 40px 15vw 80px 15vw;
+}
+
+#task-page-expiring-main {
+  display: grid;
+  grid-template-rows: 1fr;
+  grid-template-columns: 1fr 1fr 1fr 1fr;
+  grid-gap: 10px;
+}
+
+.task-content {
+  display: grid;
+  grid-template-columns: 1fr 1fr 1fr 1fr;
+  grid-gap: 10px;
+}
 </style>

File diff suppressed because it is too large
+ 301 - 301
yarn.lock


Some files were not shown because too many files changed in this diff