Explorar el Código

Code Inspect: GlobalHeader InfoCard AuthPage;
Other feats: CourseDetail layout;
Refactoring, caution for unexpected errors

Damon hace 4 años
padre
commit
f04efa4f7b

+ 4 - 2
src/App.vue

@@ -1,13 +1,15 @@
 <template>
-  <GlobalHeader/>
+  <GlobalHeader v-if="this.$route.path!=='/auth'"/>
   <router-view/>
+  <GlobalFooter v-if="this.$route.path!=='/auth'"/>
 </template>
 
 <script>
 
 import GlobalHeader from "@/components/GlobalHeader";
+import GlobalFooter from "@/components/GlobalFooter";
 export default {
-  components: { GlobalHeader },
+  components: { GlobalFooter, GlobalHeader },
   created() {
     const that = this;
     if (sessionStorage.token) {

+ 17 - 40
src/components/GlobalHeader.vue

@@ -1,40 +1,29 @@
 <template>
-  <div v-show="this.$route.path!=='/auth'" id="global-header-body">
+  <div id="global-header-body">
     <el-backtop/>
-    <div @click="toPortal">
-      <img id="global-header-logo" alt="err" src="@/assets/seec-logo--full.png">
-    </div>
-    <el-menu :default-active="activeMenu" class="el-menu-demo" mode="horizontal" @select="handleMenuSelect">
-      <el-menu-item index="1">
-        首页
-      </el-menu-item>
-      <el-menu-item index="2">
-        任务
-      </el-menu-item>
+    <img id="global-header-logo" alt="err" src="@/assets/seec-logo--full.png" @click="this.$router.push('/portal')">
+    <el-menu :default-active="activeMenu" mode="horizontal" @select="handleMenuSelect">
+      <el-menu-item index="1">首页</el-menu-item>
+      <el-menu-item index="2">任务</el-menu-item>
       <el-submenu index="3">
         <template #title>{{ quickAccessTitle }}</template>
         <el-menu-item index="3-1">全部课程</el-menu-item>
         <el-menu-item index="3-2">全部测试</el-menu-item>
       </el-submenu>
-      <el-menu-item index="4">
-        个人中心
-      </el-menu-item>
-      <el-menu-item v-show="accessToManage" index="5">
-        教师[临]
-      </el-menu-item>
-      <el-menu-item index="6">
-        问题[?]
-      </el-menu-item>
+      <el-menu-item index="4">个人中心</el-menu-item>
+      <el-menu-item v-if="accessToManage" index="5">教师[临]</el-menu-item>
+      <!--      todo @DQJ 导航栏可能还有变动-->
+      <el-menu-item index="6">问题[?]</el-menu-item>
     </el-menu>
     <div id="global-header-icon">
-      <div class="global-header-icon-content" @click="toMessage">
+      <div class="global-header-icon-content" @click="this.$router.push('/message')">
         <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>
         </svg>
       </div>
-      <div class="global-header-icon-content" @click="toHome">
+      <div class="global-header-icon-content" @click="this.$router.push('/home')">
         <ElPopover trigger="hover">
           <template #reference>
             <div v-if="isLogin" id="info-circle">
@@ -46,7 +35,8 @@
                   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"
+                  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>
@@ -80,19 +70,16 @@ export default {
     };
   },
   computed: {
-    currentPage: function () {
-      return this.$route.name;
-    },
     isLogin() {
       return this.$store.state.user.token !== undefined;
     },
     name() {
       return this.$store.state.user.name;
     },
-    accessToManage(){
-      if(!this.$store.state.user.token){
+    accessToManage() {
+      if (!this.$store.state.user.token) {
         return false;
-      }else{
+      } else {
         return ["SEEC", "TEACHER", "ADMIN"].indexOf(store.state.user.role) !== -1;
       }
     },
@@ -108,15 +95,6 @@ export default {
   },
 
   methods: {
-    toPortal() {
-      this.$router.push("/portal");
-    },
-    toMessage() {
-      this.$router.push("/message");
-    },
-    toHome() {
-      this.$router.push("/home");
-    },
     handleMenuSelect(key) {
       let target = "/portal";
       this.menuIndex.forEach(i => {
@@ -125,7 +103,6 @@ export default {
         }
       });
       this.$router.push(target);
-
       if (key === "3-1") {
         this.quickAccessTitle = "全部课程";
       } else if (key === "3-2") {
@@ -182,7 +159,7 @@ export default {
   justify-content: space-around;
 }
 
-.global-header-icon-content:hover {
+.global-header-icon-content {
   cursor: pointer;
 }
 

+ 8 - 52
src/components/InfoCard.vue

@@ -1,12 +1,11 @@
 <template>
-  <!--  <el-card>-->
   <div id="info-card-body">
-    <div>SEECODER</div>
+    <div style="font-weight: bold">SEECODER</div>
     <div v-if="isLogin" id="info-card-circle">
       <span>{{ name.substring(0, 1) }}</span>
     </div>
     <div v-else>
-      <svg height="50" viewBox="0 0 1025 1024" width="50" xmlns="http://www.w3.org/2000/svg">
+      <svg height="50" viewBox="0 0 1024 1024" width="50" 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>
@@ -19,22 +18,16 @@
       <div>{{ name }}</div>
       <div style="font-size: x-small">{{ email }}</div>
     </div>
-    <div v-if="isLogin" id="info-card-button-in" @click="logout">
-      <span>登出</span>
-    </div>
-    <div v-else id="info-card-button-not" @click="toAuth">
-      <span>登录/注册</span>
-    </div>
+    <el-button class="info-card-button" v-if="isLogin" plain round size="small" type="primary" @click="signOut">登出</el-button>
+    <el-button class="info-card-button" v-else plain round size="small" type="primary" @click="this.$router.push('/auth')">登录/注册</el-button>
   </div>
-  <!--  </el-card>-->
 </template>
 
 <script>
 export default {
   name: "InfoCard",
-
   computed: {
-    isLogin: function () {
+    isLogin() {
       return this.$store.state.user.token !== undefined;
     },
     name() {
@@ -46,10 +39,7 @@ export default {
   },
 
   methods: {
-    toAuth() {
-      this.$router.push("/auth");
-    },
-    logout() {
+    signOut() {
       this.$store.commit("state_reset_user");
       this.$store.commit("storage_delete_user");
       this.$router.push("/portal");
@@ -64,7 +54,7 @@ export default {
 <style scoped>
 #info-card-body {
   min-height: 180px;
-  margin: 0 auto 0 auto;
+  margin: 0 auto;
   display: flex;
   flex-direction: column;
   justify-content: space-around;
@@ -92,41 +82,7 @@ export default {
   text-align: center;
 }
 
-#info-card-button-in {
+.info-card-button {
   width: 120px;
-  height: 30px;
-  border-radius: 15px;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  /*background: #FFF1DE;*/
-  background: #E6F1FC;
-}
-
-#info-card-button-in:hover {
-  cursor: pointer;
-}
-
-#info-card-button-in span {
-  /*color: #E6A23C;*/
-  color: #1989FA;
-}
-
-#info-card-button-not {
-  width: 120px;
-  height: 30px;
-  border-radius: 15px;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  background: #E6F1FC;
-}
-
-#info-card-button-not:hover {
-  cursor: pointer;
-}
-
-#info-card-button-not span {
-  color: #1989FA;
 }
 </style>

+ 0 - 1
src/global/register-element.js

@@ -77,7 +77,6 @@ const components = [
   ElMenu,
   ElMenuItem,
   ElSubmenu,
-  ElPagination,
 ];
 
 export default function (app) {

+ 6 - 29
src/views/AuthPage/AuthPage.vue

@@ -1,11 +1,7 @@
 <template>
-  <div id="auth-body">
-    <div id="auth-img">
-      <img alt="err" src="@/assets/seec-logo--horizontal.png" style="width: 352px; height: 300px">
-    </div>
-    <div id="auth-card">
-      <AuthCard/>
-    </div>
+  <img id="auth-img" alt="err" src="@/assets/seec-logo--horizontal.png" @click="this.$router.push('/portal')">
+  <div id="auth-card">
+    <AuthCard/>
   </div>
 </template>
 
@@ -21,8 +17,10 @@ export default {
 <style scoped>
 #auth-img {
   position: fixed;
-  top: 30vh;
+  top: 28vh;
   left: 15vw;
+  width: 352px;
+  height: 300px;
 }
 
 #auth-card {
@@ -32,25 +30,4 @@ export default {
   right: 15vw;
   padding-bottom: 50px;
 }
-
-@media screen and (max-width: 1260px) {
-  #auth-body {
-    display: flex;
-    flex-direction: column;
-    justify-content: center;
-    align-items: center;
-  }
-
-  #auth-card {
-    position: static;
-    margin-top: 15vh;
-    padding: 0;
-  }
-
-  #auth-img {
-    position: static;
-    transform: scale(0.6);
-    order: 2;
-  }
-}
 </style>

+ 2 - 2
src/views/AuthPage/components/AuthCard.vue

@@ -44,7 +44,7 @@
       </el-form-item>
 
       <el-form-item class="auth-card-form-item" prop="password">
-        <el-input v-model="cardForm.password" :placeholder="passwordPlaceHolder" clearable type="password">
+        <el-input v-model="cardForm.password" :placeholder="passwordPlaceHolder" clearable type="password" autocomplete="new-password">
           <template #prefix>
             <el-icon class="el-input__icon">
               <lock/>
@@ -108,7 +108,7 @@
 </template>
 
 <script>
-import { Avatar, Cherry, Key, Lock, Message, Phone } from "@element-plus/icons";
+import { Avatar, Cherry, Key, Lock, Message, Phone } from "@element-plus/icons-vue";
 import SlideVerifier from "@/views/AuthPage/components/SlideVerifier";
 
 export default {

+ 42 - 35
src/views/CoursePage/CourseDetail.vue

@@ -1,15 +1,19 @@
 <template>
-  <div class="course-detail-page">
-    <div class="course-detail-container" v-if="courseInfo!==null">
+  <el-card class="course-detail-page">
+    <div v-if="courseInfo!==null" class="course-detail-container">
       <div class="header">
         <div class="course-img">
-          <img alt="" :src="imgUrl">
+          <img :src="imgUrl" alt="">
         </div>
         <div class="course-info">
-          <el-row>课程名称:{{ courseInfo.name }}</el-row>
-          <el-row>教师:{{ courseInfo.teacher.name }}</el-row>
-          <el-row>学期:{{ courseInfo.semester }}</el-row>
-          <el-row>时间:{{ timestampToTime(courseInfo.startTime) }} 至 {{ timestampToTime(courseInfo.endTime) }}</el-row>
+          <el-row style="font-size: xx-large; font-weight: bold">
+            {{ courseInfo.name === undefined ? "空白课程" : courseInfo.name }}
+          </el-row>
+          <div class="course-info-main">
+            <el-row>教师:{{ courseInfo.teacher.name }}</el-row>
+            <el-row>学期:{{ courseInfo.semester }}</el-row>
+            <el-row>时间:{{ timestampToTime(courseInfo.startTime) }} 至 {{ timestampToTime(courseInfo.endTime) }}</el-row>
+          </div>
           <el-row class="mooc-link">
             MOOC链接:
             <el-link v-if="courseInfo.moocUrl!==null" :href="courseInfo.moocUrl" target="_blank">点击此处<i
@@ -17,8 +21,8 @@
             <span v-else>无</span>
           </el-row>
           <el-row v-if="isStudent">
-            <el-button size="mini" :disabled="isCourseSelected" @click="handleSelectCourse">
-              {{ isCourseSelected ? "已选课" : "立即选课" }}
+            <el-button :disabled="isCourseSelected" size="mini" @click="handleSelectCourse">
+              {{ isCourseSelected ? "已选课" : "确认选课" }}
             </el-button>
             <el-button v-if="isCourseSelected" size="mini" type="danger" @click="handleDropCourse">
               退课
@@ -36,15 +40,15 @@
         </div>
       </div>
 
-      <el-divider></el-divider>
+      <el-divider v-if="isCourseSelected"/>
 
-      <div class="course-tabs">
+      <div v-if="isCourseSelected" class="course-tabs">
         <el-radio-group v-model="tabName" size="large">
           <el-radio-button label="tasks">任务时间轴</el-radio-button>
           <el-radio-button label="notice">通知栏</el-radio-button>
           <el-radio-button label="courseware">课件列表</el-radio-button>
         </el-radio-group>
-        <div v-if="true">
+        <div>
           <el-popover v-if="isTeacher && tabName==='notice'"
                       v-model:visible="noticePopover"
                       :width="160"
@@ -54,7 +58,7 @@
                 公告
               </div>
               <div class="notice-type-txt">
-                <el-link type="success" href="javascript:void(0);" @click="selAndInitAnnouncement('announcement')">发布公告
+                <el-link href="javascript:void(0);" type="success" @click="selAndInitAnnouncement('announcement')">发布公告
                 </el-link>
               </div>
             </el-row>
@@ -63,7 +67,7 @@
                 作业
               </div>
               <div class="notice-type-txt">
-                <el-link type="warning" href="javascript:void(0);" @click="selAndInitAnnouncement('homework')">发布作业
+                <el-link href="javascript:void(0);" type="warning" @click="selAndInitAnnouncement('homework')">发布作业
                 </el-link>
               </div>
             </el-row>
@@ -72,7 +76,7 @@
                 考试
               </div>
               <div class="notice-type-txt">
-                <el-link type="danger" href="javascript:void(0);" @click="selAndInitAnnouncement('exam')">发布考试</el-link>
+                <el-link href="javascript:void(0);" type="danger" @click="selAndInitAnnouncement('exam')">发布考试</el-link>
               </div>
             </el-row>
             <template #reference>
@@ -80,8 +84,8 @@
               </el-button>
             </template>
           </el-popover>
-          <el-upload v-if="isTeacher && tabName==='courseware'" action="" :http-request="handleFileUploading"
-                     :on-success="handleFileUploadSuccess" :show-file-list="false">
+          <el-upload v-if="isTeacher && tabName==='courseware'" :http-request="handleFileUploading" :on-success="handleFileUploadSuccess"
+                     :show-file-list="false" action="">
             <el-button plain type="primary">上传课件</el-button>
           </el-upload>
         </div>
@@ -118,9 +122,9 @@
       </div>
     </div>
 
-    <el-dialog v-model="announcementFormDialog" :title="'添加发布'" :before-close="beforeFormClose">
-      <el-form label-position="right" :model="announcementForm" :rules="announcementFormRule" label-width="60px"
-               ref="announceFormRef">
+    <el-dialog v-model="announcementFormDialog" :before-close="beforeFormClose" :title="'添加发布'">
+      <el-form ref="announceFormRef" :model="announcementForm" :rules="announcementFormRule" label-position="right"
+               label-width="60px">
         <el-form-item label="类别" prop="type">
           <el-select v-model="announcementForm.type">
             <el-option label="公告" value="announcement"></el-option>
@@ -132,26 +136,29 @@
           <el-input v-model="announcementForm.title"></el-input>
         </el-form-item>
         <el-form-item label="内容">
-          <el-input v-model="announcementForm.content" type="textarea" :rows="3"></el-input>
+          <el-input v-model="announcementForm.content" :rows="3" type="textarea"></el-input>
         </el-form-item>
       </el-form>
       <div style="margin: auto;width: fit-content">
-        <el-button type="primary" plain @click="handlePublishAnnouncement">确认发布</el-button>
-        <el-button type="danger" plain @click="beforeFormClose">我再想想</el-button>
+        <el-button plain type="primary" @click="handlePublishAnnouncement">确认发布</el-button>
+        <el-button plain type="danger" @click="beforeFormClose">我再想想</el-button>
       </div>
     </el-dialog>
-  </div>
+  </el-card>
+  <GlobalFooter/>
 </template>
 
 <script>
 import NoticeItem from "./components/NoticeItem";
 import FileEntry from "./components/FileEntry";
-import {ElMessageBox, ElMessage} from "element-plus";
+import { ElMessageBox, ElMessage } from "element-plus";
 import variables from "@/utils/variables";
+import GlobalFooter from "@/components/GlobalFooter";
 
 export default {
   name: "CourseDetail",
   components: {
+    GlobalFooter,
     // eslint-disable-next-line vue/no-unused-components
     NoticeItem,
     // eslint-disable-next-line vue/no-unused-components
@@ -194,11 +201,11 @@ export default {
         color: "",
       },
       noticeTypeMap: {
-        announce: {type: "公告", title: "发布公告", color: themeColor.orange},
-        homework: {type: "作业", title: "发布作业", color: themeColor.blue},
-        exam: {type: "考试", title: "发布考试", color: themeColor.red},
+        announce: { type: "公告", title: "发布公告", color: themeColor.orange },
+        homework: { type: "作业", title: "发布作业", color: themeColor.blue },
+        exam: { type: "考试", title: "发布考试", color: themeColor.red },
       },
-      newNoticeInfo: {noticeDescription: "", priority: "1", fileList: []},
+      newNoticeInfo: { noticeDescription: "", priority: "1", fileList: [] },
       postNoticeInfo: {},
       fileEntryList: [{
         id: 1,
@@ -247,7 +254,7 @@ export default {
     },
     imgUrl() {
       return this.courseInfo.imageUrl === null ? this.noImgUrl : this.courseInfo.imageUrl;
-        // + "?t=" + Date.now().valueOf();
+      // + "?t=" + Date.now().valueOf();
     },
   },
   mounted() {
@@ -258,9 +265,9 @@ export default {
           .then(res => {
             this.isCourseSelected = res.data.data;
             this.$apis.getAnnouncementsByCourseId(this.$route.params.id)
-            .then(res => {
-              this.announcementList = res.data.data;
-            });
+              .then(res => {
+                this.announcementList = res.data.data;
+              });
           });
       });
   },
@@ -295,7 +302,7 @@ export default {
     },
     handlePublishAnnouncement() {
       let announcementVO = {
-        sender: {id: this.$store.state.user.id,},
+        sender: { id: this.$store.state.user.id, },
         courseId: this.courseInfo.id,
         title: this.announcementForm.title,
         content: this.announcementForm.content,
@@ -323,7 +330,7 @@ export default {
         confirmButtonText: "立即选课",
         cancelButtonText: "我再想想",
       })
-        .then(({value}) => {
+        .then(({ value }) => {
           if (value !== this.courseInfo.invitationCode) {
             ElMessage.error("选课码错误");
           } else {

+ 11 - 5
src/views/CoursePage/style/CourseDetail.css

@@ -1,8 +1,6 @@
 .course-detail-page {
-    /*min-height: 100vh;*/
-    display: flex;
-    flex-direction: column;
-    align-items: center;
+    margin: 40px 10vw 80px 10vw;
+    min-height: calc(100vh - 100px);
 }
 
 .course-detail-container {
@@ -54,8 +52,16 @@
     margin-left: 32px;
 }
 
+.course-info-main {
+    background-color: #f6f6f6;
+    color: #777777;
+    margin-top: 10px;
+    border-radius: 8px;
+    padding: 20px;
+}
+
 .course-info > div {
-    margin-bottom: 16.5px;
+    margin-bottom: 16px;
 }
 
 .course-info > div:last-child {

+ 2 - 5
src/views/PortalPage/PortalPage.vue

@@ -144,18 +144,16 @@
     </div>
 
   </div>
-  <GlobalFooter/>
 </template>
 
 <script>
 import CarouselCard from "@/views/PortalPage/components/CarouselCard";
 import CourseCard from "@/components/CourseCard";
-import GlobalFooter from "@/components/GlobalFooter";
 import EvalCard from "@/components/EvalCard";
 import CoderCard from "@/components/CoderCard";
 import MyCourseCard from "@/views/PortalPage/components/MyCourseCard";
 import MyTestCard from "@/views/PortalPage/components/MyTestCard";
-import {Lock, SetUp, ShoppingCart} from "@element-plus/icons-vue";
+import { Lock, SetUp, ShoppingCart } from "@element-plus/icons-vue";
 
 export default {
   //数据
@@ -166,7 +164,6 @@ export default {
     Lock,
     MyTestCard,
     CoderCard,
-    GlobalFooter,
     CourseCard,
     CarouselCard,
     EvalCard,
@@ -238,7 +235,7 @@ export default {
         this.myCourseList = res.data.data;
         that.handleResize();
       });
-      this.$apis.getStudentEvalExams({state: 0}).then(res => {
+      this.$apis.getStudentEvalExams({ state: 0 }).then(res => {
         this.myEvalExamList = res.data.data.examVOList;
         that.handleResize();
       });

+ 2 - 2
src/views/PortalPage/components/MyTestCard.vue

@@ -12,7 +12,7 @@
     </div>
 
     <el-row>
-      <el-col :span="16">
+      <el-col :span="20">
         <el-col v-if="type==='eval'" class="title">
           {{ testVO.examName }}
         </el-col>
@@ -20,7 +20,7 @@
           {{ testVO.name }}
         </el-col>
       </el-col>
-      <el-col :span="8" style="text-align: center;">
+      <el-col :span="4" style="text-align: center;">
         <el-tag v-if="state==='NOT_STARTED'" size="small" type="info">未开始</el-tag>
         <el-tag v-else-if="state==='RUNNING'" size="small">进行中</el-tag>
         <el-tag v-else-if="state==='FINISHED'" size="small" type="danger">已结束</el-tag>

+ 125 - 114
src/views/ProblemPage/ProblemDetail.vue

@@ -1,36 +1,39 @@
 <template>
-  <div>
-    <page-header>
-      <template #actions>
-        <el-button @click="download">
-          下载
-        </el-button>
-        <el-button
-          variant="danger"
-          @click="this.$store.commit('removeProblem', problem)"
-        >移出试题清单
-        </el-button
-        >
-        <el-button
-          variant="primary"
-          @click="this.$store.commit('addProblem', problem)"
-        >加入试题清单
-        </el-button
-        >
-        <el-button
-          variant="danger-secondary"
-          @click="dialog.delete = true"
-        >
-          删除题目
-        </el-button>
+  <div id="problem-detail-body">
+    <el-card>
+      <template #header>
+        <page-header>
+          <template #actions>
+            <el-button @click="download">
+              下载
+            </el-button>
+            <el-button
+              variant="danger"
+              @click="this.$store.commit('removeProblem', problem)"
+            >移出试题清单
+            </el-button
+            >
+            <el-button
+              variant="primary"
+              @click="this.$store.commit('addProblem', problem)"
+            >加入试题清单
+            </el-button
+            >
+            <el-button
+              variant="danger-secondary"
+              @click="dialog.delete = true"
+            >
+              删除题目
+            </el-button>
+          </template>
+          {{ problem.name }}
+        </page-header>
       </template>
-      {{ problem.name }}
-    </page-header>
-    <el-dialog v-model="dialog.delete" title="确认删除题目">
-      <b>确认删除题目吗?</b>
-      <p>题目ID:{{ problem.id }}</p>
-      <p>题目名称:{{ problem.name }}</p>
-      <template #footer>
+      <el-dialog v-model="dialog.delete" title="确认删除题目">
+        <b>确认删除题目吗?</b>
+        <p>题目ID:{{ problem.id }}</p>
+        <p>题目名称:{{ problem.name }}</p>
+        <template #footer>
         <span class="dialog-footer">
         <el-button @click="dialog.delete = false">取消</el-button>
         <el-button
@@ -40,30 +43,30 @@
         >确定</el-button
         >
       </span>
-      </template>
-    </el-dialog>
-    <el-dialog v-model="dialog.update" title="更新题目文件">
-      <el-form label-width="40px">
-        <el-form-item label="路径" prop="name">
-          <div>{{ selectedFile }}</div>
-        </el-form-item>
-        <el-form-item label="文件" prop="file">
-          <el-upload
-            ref="file"
-            :auto-upload="false"
-            :limit="1"
-            :on-change="onFileChange"
-            :on-remove="onFileChange"
-            action=""
-          >
-            <el-button size="small" type="primary"
-            >选取
-            </el-button
+        </template>
+      </el-dialog>
+      <el-dialog v-model="dialog.update" title="更新题目文件">
+        <el-form label-width="40px">
+          <el-form-item label="路径" prop="name">
+            <div>{{ selectedFile }}</div>
+          </el-form-item>
+          <el-form-item label="文件" prop="file">
+            <el-upload
+              ref="file"
+              :auto-upload="false"
+              :limit="1"
+              :on-change="onFileChange"
+              :on-remove="onFileChange"
+              action=""
             >
-          </el-upload>
-        </el-form-item>
-      </el-form>
-      <template #footer>
+              <el-button size="small" type="primary"
+              >选取
+              </el-button
+              >
+            </el-upload>
+          </el-form-item>
+        </el-form>
+        <template #footer>
           <span class="dialog-footer">
           <el-button @click="cancelUpdate">取消</el-button>
           <el-button
@@ -74,67 +77,68 @@
           >确定</el-button
           >
         </span>
-      </template>
+        </template>
 
-    </el-dialog>
-    <paper shadow="sm" style="margin-bottom: 20px">
-      <el-descriptions>
-        <el-descriptions-item label="题目名称">
-          {{ problem.name }}
-        </el-descriptions-item>
-        <el-descriptions-item label="题目类型">
-          {{ typeTagContent }}
-        </el-descriptions-item>
-        <el-descriptions-item label="上传者">
-          {{ problem.creator ? problem.creator.username : "系统" }}
-        </el-descriptions-item>
-        <el-descriptions-item label="上传时间">
-          {{ format(problem.createdAt) }}
-        </el-descriptions-item>
-        <el-descriptions-item :span="3" label="题目描述">
-          {{ problem.description }}
-        </el-descriptions-item>
-      </el-descriptions>
-    </paper>
-    <div class="fill-card top-divide">
-      <el-table :data="files">
-        <el-table-column label="文件列表">
-          <template v-slot="scope">
-            <span>{{ scope.row.path }}</span>
-          </template>
-        </el-table-column>
-        <el-table-column label="类型" width="120">
-          <template v-slot="scope">
-            <span>{{ scope.row.type }}</span>
-          </template>
-        </el-table-column>
-        <el-table-column label="操作" width="220">
-          <template v-slot="scope">
-            <el-button
-              size="small"
-              type="text"
-              @click="onGetDetail(scope.row.path)"
-            >
-              查看详情
-            </el-button>
-            <el-button
-              size="small"
-              type="text"
-              @click="onDialogUpdate(scope.row.path)"
-            >
-              更新文件
-            </el-button>
-          </template>
-        </el-table-column>
-      </el-table>
-    </div>
-    <el-dialog
-      v-model="fileDetailDialogShow"
-      :title="fileDetailName"
-      width="80%"
-    >
-      <pre>{{ fileDetail }}</pre>
-    </el-dialog>
+      </el-dialog>
+      <paper shadow="sm" style="margin-bottom: 20px">
+        <el-descriptions>
+          <el-descriptions-item label="题目名称">
+            {{ problem.name }}
+          </el-descriptions-item>
+          <el-descriptions-item label="题目类型">
+            {{ typeTagContent }}
+          </el-descriptions-item>
+          <el-descriptions-item label="上传者">
+            {{ problem.creator ? problem.creator.username : "系统" }}
+          </el-descriptions-item>
+          <el-descriptions-item label="上传时间">
+            {{ format(problem.createdAt) }}
+          </el-descriptions-item>
+          <el-descriptions-item :span="3" label="题目描述">
+            {{ problem.description }}
+          </el-descriptions-item>
+        </el-descriptions>
+      </paper>
+      <div class="fill-card top-divide">
+        <el-table :data="files">
+          <el-table-column label="文件列表">
+            <template v-slot="scope">
+              <span>{{ scope.row.path }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="类型" width="120">
+            <template v-slot="scope">
+              <span>{{ scope.row.type }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作" width="220">
+            <template v-slot="scope">
+              <el-button
+                size="small"
+                type="text"
+                @click="onGetDetail(scope.row.path)"
+              >
+                查看详情
+              </el-button>
+              <el-button
+                size="small"
+                type="text"
+                @click="onDialogUpdate(scope.row.path)"
+              >
+                更新文件
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+      <el-dialog
+        v-model="fileDetailDialogShow"
+        :title="fileDetailName"
+        width="80%"
+      >
+        <pre>{{ fileDetail }}</pre>
+      </el-dialog>
+    </el-card>
   </div>
 </template>
 
@@ -301,3 +305,10 @@ export default {
   }
 };
 </script>
+
+<style>
+#problem-detail-body {
+  margin: 40px 10vw 80px 10vw;
+  min-height: calc(100vh - 100px);
+}
+</style>

+ 62 - 49
src/views/ProblemPage/ProblemPage.vue

@@ -1,48 +1,53 @@
 <template>
-  <div>
-    <page-header>
-      <template #actions>
-        <el-input
-            v-model="nameInput"
-            style="width: 200px;"
-            placeholder="搜索"
-            :debounce-events="['input']"
-        />
-        <el-select
-            v-model="typeInput"
-            style="width: 200px"
-            @change="fetchData(1)"
-        >
-          <el-option
-              v-for="item in typeOptions"
-              :key="item.value"
-              :value="item.value"
-          >
-            {{ item.label }}
-          </el-option>
-        </el-select>
-        <router-link
-            :to="{name:'ProblemUpload'}"
-        >
-          <el-button type="primary">
-            上传题目
-          </el-button>
-        </router-link>
+  <div id="problem-page-body">
+    <el-card>
+      <template #header>
+        <page-header>
+          <template #actions>
+            <el-input
+              v-model="nameInput"
+              :debounce-events="['input']"
+              placeholder="搜索"
+              style="width: 200px;"
+            />
+            <el-select
+              v-model="typeInput"
+              style="width: 200px"
+              @change="fetchData(1)"
+            >
+              <el-option
+                v-for="item in typeOptions"
+                :key="item.value"
+                :value="item.value"
+              >
+                {{ item.label }}
+              </el-option>
+            </el-select>
+            <router-link
+              :to="{name:'ProblemUpload'}"
+            >
+              <el-button type="primary">
+                上传题目
+              </el-button>
+            </router-link>
+          </template>
+          题目列表
+        </page-header>
       </template>
-      题目列表
-    </page-header>
-    <problem-list
-        :problem-list="problemList"
+      <problem-list
         :page-info="pageInfo"
+        :problem-list="problemList"
         @current-change="fetchData"
-    />
+      />
+    </el-card>
   </div>
 </template>
 
 <script>
 import ProblemList from "@/views/ProblemPage/components/ProblemList";
-import {errorMessage, problemTypeOptions} from "@/utils/coder-utils";
+import { problemTypeOptions } from "@/utils/coder-utils";
 import PageHeader from "@/views/ProblemPage/components/PageHeader";
+
 export default {
   components: {
     PageHeader,
@@ -57,28 +62,36 @@ export default {
     };
   },
   computed: {
-    typeOptions(){
+    typeOptions() {
       return problemTypeOptions(true);
     }
   },
   mounted() {
-    // this.fetchData(1);
+    this.fetchData(1);
   },
   methods: {
     fetchData(page = 1) {
-      this.$apis.getCoderProblem({ limit: 30, page, type: this.typeInput, name: this.nameInput })
-          .then((res) => {
-            const data=res.data;
-            this.pageInfo = data.page ?? {};
-            this.problemList = data.res ?? [];
-          })
-          .catch((err) => {
-            this.$message.error({
-              message: errorMessage(err),
-              center: true
-            });
-          });
+      // todo @Arsekl 失效的api
+      // this.$apis.getCoderProblem({ limit: 30, page, type: this.typeInput, name: this.nameInput })
+      //     .then((res) => {
+      //       const data=res.data;
+      //       this.pageInfo = data.page ?? {};
+      //       this.problemList = data.res ?? [];
+      //     })
+      //     .catch((err) => {
+      //       this.$message.error({
+      //         message: errorMessage(err),
+      //         center: true
+      //       });
+      //     });
     }
   }
 };
 </script>
+
+<style>
+#problem-page-body {
+  margin: 40px 10vw 80px 10vw;
+  min-height: calc(100vh - 100px);
+}
+</style>

+ 64 - 51
src/views/ProblemPage/ProblemUpload.vue

@@ -1,58 +1,64 @@
 <template>
-  <div>
-    <el-form
+  <div id="problem-upload-body">
+    <el-card>
+      <template #header>
+
+      </template>
+      <el-form
         ref="form"
         :model="form"
-        label-width="80px"
         :rules="rules"
         class="fill-card"
-    >
-      <el-form-item label="题目名称" prop="name">
-        <el-input v-model="form.name"></el-input>
-      </el-form-item>
-      <el-form-item label="题目类型" prop="type">
-        <el-select v-model="form.type" placeholder="请选择" value="">
-          <el-option
+        label-width="80px"
+      >
+        <el-form-item label="题目名称" prop="name">
+          <el-input v-model="form.name"></el-input>
+        </el-form-item>
+        <el-form-item label="题目类型" prop="type">
+          <el-select v-model="form.type" placeholder="请选择" value="">
+            <el-option
               v-for="item in typeOptions"
               :key="item.value"
               :label="item.label"
               :value="item.value"
-          ></el-option>
-        </el-select>
-      </el-form-item>
-      <el-form-item label="题目描述" prop="description">
-        <el-input
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="题目描述" prop="description">
+          <el-input
             v-model="form.description"
-            type="textarea"
             :rows="3"
-        ></el-input>
-      </el-form-item>
-      <el-form-item label="题目文件" prop="file">
-        <el-upload
+            type="textarea"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="题目文件" prop="file">
+          <el-upload
             ref="file"
-            action=""
             :auto-upload="false"
             :limit="1"
-            accept=".zip"
             :on-change="onFileChange"
             :on-remove="onFileChange"
-        >
-          <el-button size="small" type="primary">选取</el-button>
-        </el-upload>
-      </el-form-item>
-      <el-form-item>
-        <div class="form-button">
-          <el-button type="danger" plain @click="resetForm">重置</el-button>
-          <el-button
-              type="primary"
-              :loading="loading"
+            accept=".zip"
+            action=""
+          >
+            <el-button size="small" type="primary">选取</el-button>
+          </el-upload>
+        </el-form-item>
+        <el-form-item>
+          <div class="form-button">
+            <el-button plain type="danger" @click="resetForm">重置</el-button>
+            <el-button
               :disabled="!files.length"
+              :loading="loading"
+              type="primary"
               @click="onSubmit"
-          >上传</el-button
-          >
-        </div>
-      </el-form-item>
-    </el-form>
+            >上传
+            </el-button
+            >
+          </div>
+        </el-form-item>
+      </el-form>
+    </el-card>
   </div>
 </template>
 <script>
@@ -60,11 +66,10 @@ const { problemTypeOptions } = require("@/utils/coder-utils.js");
 const { errorMessage } = require("@/utils/coder-utils.js");
 export default {
   name: "ProblemUpload",
-  components: {
-  },
+  components: {},
   data() {
     return {
-      form: {} ,
+      form: {},
       rules: {
         name: [{ required: true, message: "请输入题目名称", trigger: "blur" }],
         type: [{ required: true, message: "请选择题目类型", trigger: "blur" }],
@@ -83,8 +88,8 @@ export default {
   },
   methods: {
     onFileChange(
-        _,
-        fileList
+      _,
+      fileList
     ) {
       this.files = fileList;
     },
@@ -114,17 +119,25 @@ export default {
       body.append("meta", meta);
       body.append("data", this.files[0].raw);
       this.$apis.createCoderProblem(body)
-          .then((data) => {
-            this.$router.push("/problem/" + data.res?.id);
-          })
-          .catch((err) => {
-            this.$message.error({
-              message: errorMessage(err),
-              center: true
-            });
-            this.loading = false;
+        .then((data) => {
+          this.$router.push("/problem/" + data.res?.id);
+        })
+        .catch((err) => {
+          this.$message.error({
+            message: errorMessage(err),
+            center: true
           });
+          this.loading = false;
+        });
     }
   }
 };
 </script>
+
+
+<style>
+#problem-upload-body {
+  margin: 40px 10vw 80px 10vw;
+  min-height: calc(100vh - 100px);
+}
+</style>

+ 27 - 19
src/views/TaskPage/TaskPage.vue

@@ -7,11 +7,11 @@
             即将到期
           </span>
       </template>
-      <div id="task-page-expiring-main" class="aaa">
+      <div id="task-page-expiring-main" ref="expiringTask">
         <EvalCard v-for="item in myEvalExamList" :key="item.id" :examVO="item" style="height: 150px; margin: 0 10px 10px 10px"/>
         <CoderCard v-for="item in myCoderExamList" :key="item.id" :coderVO="item" style="height: 150px; margin: 0 10px 10px 10px"/>
       </div>
-      <el-pagination layout="prev, pager, next" :total="50" style="margin: 0 auto 0 40%" />
+      <el-pagination :total="50" layout="prev, pager, next" style="margin: 0 auto 0 40%"/>
     </el-card>
 
     <el-card>
@@ -20,10 +20,9 @@
             我的任务
           </span>
       </template>
-      <div id="task-page-all-task-main" class="aaa">
+      <div id="task-page-all-task-main">
+        {{ allTaskList }}
       </div>
-        <EvalCard v-for="item in myEvalExamList" :key="item.id" :examVO="item"/>
-        <CoderCard v-for="item in myCoderExamList" :key="item.id" :coderVO="item"/>
     </el-card>
 
   </div>
@@ -34,22 +33,41 @@
 import GlobalFooter from "@/components/GlobalFooter";
 import EvalCard from "@/components/EvalCard";
 import CoderCard from "@/components/CoderCard";
+
 export default {
   name: "TaskPage",
-  components: { CoderCard, EvalCard, GlobalFooter  },
+  // eslint-disable-next-line vue/no-unused-components
+  components: { CoderCard, EvalCard, GlobalFooter },
   data() {
     return {
-      expiring: [],
-      allTask: [],
       myEvalExamList: [],
       myCoderExamList: [],
     };
   },
+  computed: {
+    expiringTaskList() {
+      if (!this.myEvalExamList.length || !this.myCoderExamList) {
+        return [];
+      } else {
+        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;
+        }).slice(0,6);
+      }
+    },
+    allTaskList() {
+      if (!this.myEvalExamList.length || !this.myCoderExamList) {
+        return [];
+      } else {
+        return [].concat(this.myEvalExamList).concat(this.myCoderExamList);
+      }
+    }
+  },
 
   async mounted() {
     this.myEvalExamList = (await this.$apis.getAllEvalExams()).data.data["examVOList"];
     this.myCoderExamList = (await this.$apis.getAllCoderExams()).data.data["res"];
-    this.expiring = this.allTask = [].concat(this.myEvalExamList).concat(this.myCoderExamList);
   }
 };
 </script>
@@ -62,14 +80,4 @@ export default {
   grid-gap: 20px;
   margin: 40px 15vw 80px 15vw;
 }
-
-.aaa {
-  display: flex;
-  overflow: scroll;
-}
-
-:deep(.aaa .el-card) {
-  flex-shrink: 0;
-  width: 200px;
-}
 </style>