Procházet zdrojové kódy

feat: 增加错误页以及ui优化

weijin před 4 roky
rodič
revize
f5372a453d

+ 0 - 60
src/components/HelloWorld.vue

@@ -1,60 +0,0 @@
-<template>
-  <div class="hello">
-    <h1>{{ msg }}</h1>
-    <p>
-      For a guide and recipes on how to configure / customize this project,<br>
-      check out the
-      <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
-    </p>
-    <h3>Installed CLI Plugins</h3>
-    <ul>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank" rel="noopener">router</a></li>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex" target="_blank" rel="noopener">vuex</a></li>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-unit-mocha" target="_blank" rel="noopener">unit-mocha</a></li>
-    </ul>
-    <h3>Essential Links</h3>
-    <ul>
-      <li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
-      <li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
-      <li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
-      <li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
-      <li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
-    </ul>
-    <h3>Ecosystem</h3>
-    <ul>
-      <li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
-      <li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
-      <li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
-      <li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
-      <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
-    </ul>
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'HelloWorld',
-  props: {
-    msg: String
-  }
-}
-</script>
-
-<!-- Add "scoped" attribute to limit CSS to this component only -->
-<style scoped>
-h3 {
-  margin: 40px 0 0;
-}
-ul {
-  list-style-type: none;
-  padding: 0;
-}
-li {
-  display: inline-block;
-  margin: 0 10px;
-}
-a {
-  color: #42b983;
-}
-</style>

+ 71 - 71
src/components/QuestionCard/PrimaryQuestionCard.vue

@@ -4,18 +4,17 @@
       <!--      <el-space>-->
       <el-space style="display: flex">
         <span><strong>S/N: </strong>{{ curNum + 1 }} / {{ totalNum }}</span>
-        <span><strong>题目类型: </strong>{{ questionVO.type }}</span>
-        <el-button type="text" circle @click="isAllShow=!isAllShow"><strong>{{ isAllShowText }}</strong></el-button>
+        <span style="margin-left: 20px"><strong>题目类型: </strong>{{ questionVO.type }}</span>
+        <span style="margin-left: 20px"><strong>知识点: </strong></span>
         <div>
           <!--知识点插槽,用于更新题目卡片中可能存在的知识点改变差异-->
           <slot name="knowledgeId">
-            <span><strong>KnowledgeId: </strong></span>
             <!--知识点显示内容-->
             <el-tooltip
-              v-if="questionVO.knowledgeId && questionVO.knowledgeId.length !== 0"
-              v-for="item in questionVO.knowledgeId"
-              effect="dark"
-              placement="bottom">
+                v-if="questionVO.knowledgeId && questionVO.knowledgeId.length !== 0"
+                v-for="item in questionVO.knowledgeId"
+                effect="dark"
+                placement="bottom">
               <template #content>
                 {{ map(item) }}
               </template>
@@ -24,13 +23,14 @@
             <span v-else>null</span>
           </slot>
         </div>
+        <el-button type="text" circle @click="isAllShow=!isAllShow"><strong>{{ isAllShowText }}</strong></el-button>
+        <slot name="button">
+          <!--按钮插槽,用于不同的卡片更换不同的按钮-->
+          <el-button type="primary" icon="el-icon-edit" circle @click="updateQuestion"/>
+          <el-button v-if="isDelete === false" type="danger" icon="el-icon-delete" circle @click="deleteQuestion"/>
+          <el-button v-else type="success" icon="el-icon-delete" circle @click="recoverQuestion"/>
+        </slot>
       </el-space>
-      <slot name="button">
-        <!--按钮插槽,用于不同的卡片更换不同的按钮-->
-        <el-button type="primary" icon="el-icon-edit" circle @click="updateQuestion"/>
-        <el-button v-if="isDelete === false" type="danger" icon="el-icon-delete" circle @click="deleteQuestion"/>
-        <el-button v-else type="success" icon="el-icon-delete" circle @click="recoverQuestion"/>
-      </slot>
       <!--      </el-space>-->
     </template>
     <!--题目内容部分-->
@@ -67,32 +67,32 @@
       <div class="analysis-block">
         <el-row>
           <slot name="keypoint">
-            <el-col :span="10">
-              <strong>KeyPoints: </strong>{{ questionVO.keyPoints }}
+            <el-col :span="6" style="text-align: left">
+              <strong>关键词: </strong>{{ questionVO.keyPoints ? questionVO.keyPoints : '无' }}
             </el-col>
           </slot>
           <slot name="difficulty">
-            <el-col :span="6">
+            <el-col :span="6" style="text-align: left">
               <strong>题目难度: </strong>{{ questionVO.weight }}/5
             </el-col>
           </slot>
           <slot name="tag">
-            <el-col :span="4">
-              <span><strong>Tags: </strong></span>
+            <el-col :span="12" style="text-align: left">
+              <span><strong>标签: </strong></span>
               <span v-if="questionVO.tags && questionVO.tags.length !== 0">
-              <el-tag v-for="(item, index) in questionVO.tags" effect="dark">
-                {{ item }}
-              </el-tag>
-            </span>
+                <el-tag v-for="(item, index) in questionVO.tags" effect="dark">
+                  {{ item }}
+                </el-tag>
+              </span>
               <span v-else>
-              <span>no tags</span>
+              <span><el-tag effect="dark">无</el-tag></span>
             </span>
             </el-col>
           </slot>
         </el-row>
       </div>
       <!--题目解析-正确答案-->
-      <div class="analysis-block">
+      <div class="analysis-block" style="text-align: left">
         <!--单选、多选、判断、简单-->
         <slot name="answer1"
               v-if="questionVO.type === 'choice' ||
@@ -104,7 +104,7 @@
         <!--todo: 简答-->
       </div>
       <!--题目解析-解析部分-->
-      <div class="analysis-block">
+      <div class="analysis-block" style="text-align: left">
         <!--单选、多选、判断-->
         <slot name="analysis1"
               v-if="questionVO.type === 'choice' ||
@@ -152,17 +152,17 @@
     </div>
   </el-card>
 
-<!--  <el-drawer-->
-<!--    title="更新题目"-->
-<!--    :before-close="handleClose"-->
-<!--    v-model="dialog"-->
-<!--    direction="rtl"-->
-<!--    custom-class="question-drawer"-->
-<!--    ref="drawer"-->
-<!--    size="35%"-->
-<!--  >-->
-<!--    <QuestionUpdater :question="questionVO" @closeDialog="closeDialog"/>-->
-<!--  </el-drawer>-->
+  <!--  <el-drawer-->
+  <!--    title="更新题目"-->
+  <!--    :before-close="handleClose"-->
+  <!--    v-model="dialog"-->
+  <!--    direction="rtl"-->
+  <!--    custom-class="question-drawer"-->
+  <!--    ref="drawer"-->
+  <!--    size="35%"-->
+  <!--  >-->
+  <!--    <QuestionUpdater :question="questionVO" @closeDialog="closeDialog"/>-->
+  <!--  </el-drawer>-->
 
 </template>
 
@@ -243,21 +243,21 @@ export default {
           operationType: "Delete",
         }
         this.$api.updateQuestion(this.questionVO)
-          .then(res => {
-            this.$message({
-              type: 'success',
-              message: '删除成功!'
-            });
-            this.isDelete = true;
-            record.questionId = res.data.result.id;
-            record.time = new Date();
-            this.$api.createRecord(record)
-              .then(res1 => {
-                console.log(res1);
-              }).catch(err1 => {
-              console.log(err1);
-            })
-          }).catch(error => {
+            .then(res => {
+              this.$message({
+                type: 'success',
+                message: '删除成功!'
+              });
+              this.isDelete = true;
+              record.questionId = res.data.result.id;
+              record.time = new Date();
+              this.$api.createRecord(record)
+                  .then(res1 => {
+                    console.log(res1);
+                  }).catch(err1 => {
+                console.log(err1);
+              })
+            }).catch(error => {
           console.log(error);
           this.$notify.error({
             title: '错误',
@@ -302,32 +302,32 @@ export default {
   mounted() {
     if (this.questionVO.checkedUserId) {
       this.$api.getUserById(this.questionVO.checkedUserId) // 异步函数1:根据用户ID获得用户名称
-        .then(res => {
-          if (res.data.result.name) {
-            this.checkedUserName = res.data.result.name;
-          }
-        }).catch(err => {
+          .then(res => {
+            if (res.data.result.name) {
+              this.checkedUserName = res.data.result.name;
+            }
+          }).catch(err => {
         console.log(err);
       })
     }
 
     this.$api.getRecordByQid(this.questionVO.id) // 异步函数2:根据题目id获得ope_record
-      .then(res1 => {
-        let tempList = res1.data.result.content;
-        this.recordList = tempList;
-        for (let record of tempList) { //这里换成this.recordList是没问题的
-          if (!this.recordNameDict[record.userId]) {
-            this.$api.getUserById(record.userId) //异步函数3:根据记录中的用户ID获得其name
-              .then(res2 => {
-                if (res2.data.result.name) {
-                  this.recordNameDict[record.userId] = res2.data.result.name;
-                }
-              }).catch(err2 => {
-              console.log(err2);
-            })
+        .then(res1 => {
+          let tempList = res1.data.result.content;
+          this.recordList = tempList;
+          for (let record of tempList) { //这里换成this.recordList是没问题的
+            if (!this.recordNameDict[record.userId]) {
+              this.$api.getUserById(record.userId) //异步函数3:根据记录中的用户ID获得其name
+                  .then(res2 => {
+                    if (res2.data.result.name) {
+                      this.recordNameDict[record.userId] = res2.data.result.name;
+                    }
+                  }).catch(err2 => {
+                console.log(err2);
+              })
+            }
           }
-        }
-      }).catch(err1 => {
+        }).catch(err1 => {
       console.log(err1);
     });
   },

+ 6 - 4
src/components/QuestionCreator/SingleQuestionCreator.vue

@@ -1,5 +1,5 @@
 <template>
-  <div>
+  <div style="text-align: left">
     <el-form ref="form" :model="form" label-width="120px">
       <el-form-item label="题干">
         <el-input v-model="form.stem" placeholder="请输入题干内容"></el-input>
@@ -69,8 +69,10 @@
         <el-input v-model="form.keyPoints" placeholder="请输入题目关键词"></el-input>
       </el-form-item>
     </el-form>
-    <el-button type="primary" @click="handleAckButtonClick">确定</el-button>
-    <el-button type="danger">取消</el-button>
+    <div style="text-align: center">
+      <el-button type="primary" @click="handleAckButtonClick">确定</el-button>
+      <el-button type="danger">取消</el-button>
+    </div>
   </div>
 </template>
 
@@ -423,4 +425,4 @@ export default {
 :deep(.el-cascader) {
   width: 100%;
 }
-</style>
+</style>

+ 31 - 18
src/router/index.js

@@ -1,23 +1,10 @@
 import {createRouter, createWebHistory} from 'vue-router'
-import Home from '../views/Home.vue'
 import store from '../store/index'
 import {jumpToLogin} from "../api/axios.config";
 import {getUserInfo} from "../api/user";
+import {ElMessageBox} from "element-plus";
 
 const routes = [
-  {
-    path: '/home',
-    name: 'Home',
-    component: Home
-  },
-  {
-    path: '/about',
-    name: 'About',
-    // route level code-splitting
-    // this generates a separate chunk (about.[hash].js) for this route
-    // which is lazy-loaded when the route is visited.
-    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
-  },
   {
     path: '/',
     name: 'BokFrontEnd',
@@ -79,6 +66,11 @@ const routes = [
         name: "Paper",
         component: ()=>import("@/views/Bok/Main/Paper")
       },
+      {
+        path: "error",
+        name: "Error",
+        component: ()=>import("@/views/NoPermission")
+      }
     ]
   },
 ]
@@ -89,20 +81,41 @@ const router = createRouter({
 })
 
 router.beforeEach((to, from , next) =>{
+  if(to.path === '/error'){
+    next()
+  }
   const {id_token} = to.query;
   if(id_token){
     store.commit('setToken', id_token);
     getUserInfo().then(({ data }) => {
       store.commit('setUser', data.result)
-      next(to.path)
+      if(to.path === '/check' && !store.getters.hasPermission){
+        next('/error')
+      }else{
+        next(to.path)
+      }
     }).catch(err => {
-      console.log(err);
+      console.log(err)
+      store.commit('setToken', null);
+      ElMessageBox.confirm('无权限','登录失败',{
+          confirmButtonText: '重新登陆',
+          cancelButtonText: '返回门户',
+          type: 'error',
+      }).then(()=>{
+        jumpToLogin();
+      }).catch(()=>{
+        window.location.href = 'https://p.seec.seecoder.cn'
+      })
     })
   }else{
     if(!store.getters.isLogin){
-      jumpToLogin();
+      jumpToLogin()
     }else{
-      next();
+      if(to.path === '/check' && !store.getters.hasPermission){
+        next('/error')
+      }else{
+        next()
+      }
     }
   }
 })

+ 3 - 1
src/store/index.js

@@ -56,7 +56,9 @@ export default createStore({
         return false;
       }
     },
-
+    hasPermission: state => {
+      return state.user.role === 'ADMIN' || state.user.role === 'SEEC' || state.user.role === 'SEECX';
+    }
   },
   modules: {
     bok

+ 0 - 5
src/views/About.vue

@@ -1,5 +0,0 @@
-<template>
-  <div class="about">
-    <h1>This is an about page</h1>
-  </div>
-</template>

+ 1 - 1
src/views/Bok/Main/Check.vue

@@ -1,6 +1,6 @@
 <template>
   <div>
-    <h1>题目审查</h1>
+    <h1>题目审核</h1>
     <el-tabs v-model="activeName" @tab-click="handleClick">
       <el-tab-pane label="全部审核" name="checkingAll">
         <el-pagination

+ 1 - 2
src/views/Bok/Main/Knowledge.vue

@@ -1,7 +1,6 @@
 <template>
   <el-space :fill="true" direction="vertical" class="knowledge-wrapper">
-    <h1>Knowledge</h1>
-
+    <h1>知识点</h1>
     <div class="tree_body">
       <el-input
               class="tree_input"

+ 2 - 4
src/views/Bok/Main/Operation.vue

@@ -1,8 +1,8 @@
 <template>
-  <h1>This is Operation Page!</h1>
+  <h1>新建题目</h1>
   <el-tabs v-model="activeName" @tab-click="handleClick" stretch>
     <el-tab-pane label="新建题目" name="create">
-      <div>新建题目</div>
+<!--      <div>新建题目</div>-->
       <single-question-creator id="single-question-creator"/>
     </el-tab-pane>
     <el-tab-pane label="批量新建题目" name="groupCreate">
@@ -35,8 +35,6 @@
 </template>
 
 <script>
-import {reactive} from "vue";
-import {useApi} from "@/api";
 import SingleQuestionCreator from "@/components/QuestionCreator/SingleQuestionCreator";
 
 export default {

+ 60 - 60
src/views/Bok/Main/QuestionRepository.vue

@@ -1,13 +1,13 @@
 <template>
-  <h1>Question Repository</h1>
+    <h1>题库</h1>
   <el-tabs v-model="tabActiveName" @tab-click="handleTabClick" stretch>
     <!--APPROVED-->
     <el-tab-pane label="APPROVED" name="APPROVED">
-      <div>
-        <el-button>新建题目</el-button>
-        <!--        <el-button @click="createQuestion">新建题目组</el-button>-->
-      </div>
-      <el-divider/>
+<!--      <div>-->
+<!--        <el-button>新建题目</el-button>-->
+<!--        <el-button @click="createQuestion">新建题目组</el-button>-->
+<!--      </div>-->
+<!--      <el-divider/>-->
       <div>
         <el-pagination @size-change="handleSizeChange"
                        @current-change="handleCurrentChange"
@@ -26,7 +26,7 @@
                                @update="handleQuestionUpdate(item)"/>
         <el-backtop :bottom="50">
           <div
-            style="height: 100%;width: 100%;background-color: #f2f5f6;box-shadow: 0 0 6px rgba(0,0,0, .12);line-height: 40px;">
+              style="height: 100%;width: 100%;background-color: #f2f5f6;box-shadow: 0 0 6px rgba(0,0,0, .12);line-height: 40px;">
             UP
           </div>
         </el-backtop>
@@ -52,7 +52,7 @@
                                @update="handleQuestionUpdate(item)"/>
         <el-backtop :bottom="50">
           <div
-            style="height: 100%;width: 100%;background-color: #f2f5f6;box-shadow: 0 0 6px rgba(0,0,0, .12);line-height: 40px;">
+              style="height: 100%;width: 100%;background-color: #f2f5f6;box-shadow: 0 0 6px rgba(0,0,0, .12);line-height: 40px;">
             UP
           </div>
         </el-backtop>
@@ -61,13 +61,13 @@
   </el-tabs>
   <!--修改框-->
   <el-drawer
-    title="更新题目"
-    :before-close="handleClose"
-    v-model="dialog"
-    direction="rtl"
-    custom-class="question-drawer"
-    ref="drawer"
-    size="35%">
+      title="更新题目"
+      :before-close="handleClose"
+      v-model="dialog"
+      direction="rtl"
+      custom-class="question-drawer"
+      ref="drawer"
+      size="35%">
     <single-question-creator ref="QuestionUpdater"
                              @acknowledge="handleQuestionCreatorAcknowledge"
                              :target="creatorTarget"/>
@@ -107,14 +107,14 @@ export default {
     // 挂载时获取第一页题目列表
     let states = 'APPROVED';
     this.$api.getStateQuestion(states, 0, this.pageSize)
-      .then(res => {
-        console.log(res);
-        this.questionList = res.data.result.content;
-        this.totalNum = res.data.result.totalElements;
-      })
-      .catch(error => {
-        console.log(error);
-      })
+        .then(res => {
+          console.log(res);
+          this.questionList = res.data.result.content;
+          this.totalNum = res.data.result.totalElements;
+        })
+        .catch(error => {
+          console.log(error);
+        })
   },
   computed: {},
   methods: {
@@ -124,11 +124,11 @@ export default {
 
     handleClose(done) {
       this.$confirm('确认关闭?')
-        .then(_ => {
-          done();
-        })
-        .catch(_ => {
-        });
+          .then(_ => {
+            done();
+          })
+          .catch(_ => {
+          });
     },
 
     closeDialog() {
@@ -144,26 +144,26 @@ export default {
       this.currentPage = val;
       let states = 'APPROVED';
       this.$api.getStateQuestion(states, val - 1, this.pageSize)
-        .then(res => {
-          console.log(res);
-          this.questionList = res.data.result.content;
-        })
-        .catch(error => {
-          console.log(error);
-        })
+          .then(res => {
+            console.log(res);
+            this.questionList = res.data.result.content;
+          })
+          .catch(error => {
+            console.log(error);
+          })
     },
 
     handleRefusedCurrentChange(val) { // 当点击新的页面时才请求新的数据
       this.currentPage = val;
       let states = 'REFUSED';
       this.$api.getStateQuestion(states, val - 1, this.pageSize)
-        .then(res => {
-          console.log(res);
-          this.questionList = res.data.result.content;
-        })
-        .catch(error => {
-          console.log(error);
-        })
+          .then(res => {
+            console.log(res);
+            this.questionList = res.data.result.content;
+          })
+          .catch(error => {
+            console.log(error);
+          })
     },
 
     handleTabClick(tabItem) {
@@ -171,27 +171,27 @@ export default {
       switch (state) {
         case "APPROVED":
           this.$api.getStateQuestion(state, 0, this.pageSize)
-            .then(res => {
-              console.log(res);
-              this.questionList = res.data.result.content;
-              this.totalNum = res.data.result.totalElements;
-              this.currentPage = 1;
-            })
-            .catch(error => {
-              console.log(error);
-            });
+              .then(res => {
+                console.log(res);
+                this.questionList = res.data.result.content;
+                this.totalNum = res.data.result.totalElements;
+                this.currentPage = 1;
+              })
+              .catch(error => {
+                console.log(error);
+              });
           break;
         case "REFUSED":
           this.$api.getStateQuestion(state, 0, this.pageSize)
-            .then(res => {
-              console.log(res);
-              this.refusedQuestionList = res.data.result.content;
-              this.refusedTotalNum = res.data.result.totalElements;
-              this.refusedCurrentPage = 1;
-            })
-            .catch(error => {
-              console.log(error);
-            })
+              .then(res => {
+                console.log(res);
+                this.refusedQuestionList = res.data.result.content;
+                this.refusedTotalNum = res.data.result.totalElements;
+                this.refusedCurrentPage = 1;
+              })
+              .catch(error => {
+                console.log(error);
+              })
           break;
         default:
           break;

+ 1 - 1
src/views/Bok/Main/Search/index.vue

@@ -1,6 +1,6 @@
 <template>
     <el-space :fill="true" direction="vertical" alignment="flex-start" :size="30" style="width: 90%;">
-        <h1>Question Search</h1>
+        <h1>题目搜索</h1>
         <el-input placeholder="请输入内容" v-model="searchContent" @keydown.enter="clickSearch">
             <template #append>
                 <el-button icon="el-icon-search" @click="clickSearch"></el-button>

+ 3 - 1
src/views/Bok/SideBar.vue

@@ -54,7 +54,9 @@ export default {
       return this.$route.path.split("/")[1]
     },
     role(){ //获得当前登录用户的角色;审查界面只给ADMIN用户显示。
-      return this.$store.state.user.role === 'ADMIN';
+      return this.$store.state.user.role === 'ADMIN'
+          ||this.$store.state.user.role === 'SEEC'||this.$store.state.user.role === 'SEECX';
+      // return true;
     }
   },
   methods: {

+ 0 - 18
src/views/Home.vue

@@ -1,18 +0,0 @@
-<template>
-  <div class="home">
-    <img alt="Vue logo" src="../assets/logo.png">
-    <HelloWorld msg="Welcome to Your Vue.js App"/>
-  </div>
-</template>
-
-<script>
-// @ is an alias to /src
-import HelloWorld from '@/components/HelloWorld.vue'
-
-export default {
-  name: 'Home',
-  components: {
-    HelloWorld
-  }
-}
-</script>

+ 26 - 0
src/views/NoPermission.vue

@@ -0,0 +1,26 @@
+<template>
+  <div>
+    <h1>权限不足</h1>
+    <a class="link" @click="back">返回上一页</a>
+    <a class="link" href="https://p.seec.seecoder.cn">返回门户</a>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "NoPermission",
+  methods: {
+    back() {
+      window.history.go(-1);
+    }
+  }
+}
+</script>
+
+<style scoped>
+.link{
+  color: blue;
+  text-decoration: underline;
+  margin: 20px;
+}
+</style>

+ 0 - 13
tests/unit/example.spec.js

@@ -1,13 +0,0 @@
-import { expect } from 'chai'
-import { shallowMount } from '@vue/test-utils'
-import HelloWorld from '@/components/HelloWorld.vue'
-
-describe('HelloWorld.vue', () => {
-  it('renders props.msg when passed', () => {
-    const msg = 'new message'
-    const wrapper = shallowMount(HelloWorld, {
-      props: { msg }
-    })
-    expect(wrapper.text()).to.include(msg)
-  })
-})