소스 검색

feat: 管理员登录,教师用户审核界面初步

ChenYangfan 6 년 전
부모
커밋
8b9f6aa8cb
7개의 변경된 파일155개의 추가작업 그리고 19개의 파일을 삭제
  1. 3 2
      src/App.vue
  2. 6 0
      src/router/admin.js
  3. 3 1
      src/router/index.js
  4. 7 5
      src/server/admin.js
  5. 11 0
      src/server/enums/user-state.js
  6. 101 0
      src/views/admin/Admin.vue
  7. 24 11
      src/views/login/Login.vue

+ 3 - 2
src/App.vue

@@ -13,6 +13,7 @@
 import GlobalMessage from '@/components/Basic/GlobalMessage'
 import SlideUpTransition from '@/animations/SlideUpTransition'
 import { mapState } from 'vuex'
+import { userTypeNaming } from '@/server/enums/user-type'
 
 export default {
   components: { GlobalMessage, SlideUpTransition },
@@ -34,8 +35,8 @@ export default {
 
     this.$router.beforeEach((to, from, next) => {
       if (to.matched.some(record => (record.meta.roles && !record.meta.roles.some(role => role === this.userInfo.type.toLowerCase())))) {
-        this.$setInfoMessage('所前往的页面需要使用' + (this.userInfo.type === 'TEACHER' ? '学生' : '教师') + '身份登录')
-        next({ name: this.userInfo.type === 'TEACHER' ? 'teacher' : 'student' })
+        this.$setInfoMessage('所前往的页面需要使用' + userTypeNaming[this.userInfo.type] + '身份登录')
+        next({ name: this.userInfo.type.toLowerCase() })
       } else {
         next()
       }

+ 6 - 0
src/router/admin.js

@@ -0,0 +1,6 @@
+export default [{
+  meta: { roles: ['admin'] },
+  path: '/admin',
+  name: 'admin',
+  component: () => import(/* webpackChunkName: "main" */ '@/views/admin/Admin.vue')
+}]

+ 3 - 1
src/router/index.js

@@ -6,6 +6,7 @@ import student from '@/router/student'
 import main from '@/router/main'
 import quiz from '@/router/quiz'
 import pdf from '@/router/pdf'
+import admin from '@/router/admin'
 
 Vue.use(VueRouter)
 
@@ -19,7 +20,8 @@ const routes = [
   ...quiz,
   ...pdf,
   ...teacher,
-  ...student
+  ...student,
+  ...admin
 ]
 
 const router = new VueRouter({

+ 7 - 5
src/server/admin.js

@@ -1,18 +1,20 @@
 import axios from '@/plugins/axios'
 import { useAdminUrl } from '@/config/server-info'
 import generateSearchParams from '@/server/utils/generate-search-params'
+import userType from '@/server/enums/user-type'
+import { userState } from '@/server/enums/user-state'
 
 export function login ({ username, password }) {
-  return axios.post(useAdminUrl('/login'), null, {
-    params: {
+  return axios
+    .post(useAdminUrl('/login'), {
       username,
       password
-    }
-  })
+    })
+    .then(res => res.data)
 }
 
 // 获取注册教师列表
-export function getUsers ({ type, state, key = '', page = 1, size = 10, sort = '' }) {
+export function getUsers ({ type = userType.teacher, state = userState.checking, key = '', page = 1, size = 10, sort = '' }) {
   const params = generateSearchParams({ key, page, size, sort })
   params.append('type', type)
   params.append('state', state)

+ 11 - 0
src/server/enums/user-state.js

@@ -0,0 +1,11 @@
+export const userState = {
+  checking: 'CHECKING', // 审核中
+  normal: 'NORMAL', // 正常
+  locked: 'LOCKED' // 封禁中
+}
+
+export const userStateNaming = {
+  [userState.notStart]: '审核中',
+  [userState.normal]: '正常',
+  [userState.locked]: '封禁中'
+}

+ 101 - 0
src/views/admin/Admin.vue

@@ -0,0 +1,101 @@
+<template>
+  <div class="admin">
+    <div class="title">
+      <c-icon theme="red" :size="32" bold>lock_open</c-icon>
+      <div class="ml-8">管理面板</div>
+      <div class="spacer"></div>
+      <c-button class="exit" text @click="handleLogout" icon="exit_to_app">注销</c-button>
+    </div>
+    <div class="sub-title">教师用户审核</div>
+    <table class="checking-table">
+      <tr>
+        <td>邮箱</td>
+        <td>姓名</td>
+        <td>手机号</td>
+        <td>申请时间</td>
+        <td class="table-center">操作</td>
+      </tr>
+      <tr v-for="user of checkingUsers" :key="user.id">
+        <td>{{user.email}}</td>
+        <td>{{user.name}}</td>
+        <td>{{user.phone}}</td>
+        <td>{{momentFromNow(user.createAt)}}</td>
+        <td class="table-center">
+          <c-button text icon="check">审核通过</c-button>
+        </td>
+      </tr>
+    </table>
+  </div>
+</template>
+
+<script>
+import CIcon from '@/components/Basic/CIcon'
+import CButton from '@/components/Basic/CButton'
+import { logout } from '@/server/user'
+import { getUsers } from '@/server/admin'
+import { userState } from '@/server/enums/user-state'
+import userType from '@/server/enums/user-type'
+import momentFromNow from '@/utils/moment-from-now'
+
+export default {
+  components: { CButton, CIcon },
+  data () {
+    return {
+      checkingUsers: null,
+
+      userType,
+      userState
+    }
+  },
+  mounted () {
+    this.updateData()
+  },
+  methods: {
+    updateData () {
+      // 获取状态为正在审核中的用户
+      getUsers({ state: userState.checking, type: userType.teacher, size: 200 })
+        .then(res => { this.checkingUsers = res.data })
+        .catch(err => { this.$setErrorMessage(err.response.data.msg) })
+    },
+    handleLogout () {
+      logout()
+      this.$setSuccessMessage('您已退出登录')
+      this.$router.push({ name: 'login' })
+    },
+
+    momentFromNow
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import "~@/style/theme.scss";
+.admin {
+  margin: 64px auto;
+  max-width: 800px;
+  padding: 0 24px;
+}
+
+.spacer {
+  width: 1px;
+  flex: 1;
+}
+
+.checking-table {
+  width: 100%;
+  margin: 8px -8px;
+
+  .table-center {
+    text-align: center;
+  }
+
+  tr:first-child {
+    color: $theme-blue;
+    background-color: $card-background;
+  }
+
+  td {
+    padding: 4px 8px;
+  }
+}
+</style>

+ 24 - 11
src/views/login/Login.vue

@@ -24,6 +24,8 @@ import CInput from '@/components/Basic/CInput'
 import CButton from '@/components/Basic/CButton'
 import { getUserInfo, loginByEmail } from '@/server/user'
 import { SET_USER_INFO } from '@/store/types/main-types'
+import { login } from '@/server/admin'
+import userType from '@/server/enums/user-type'
 
 export default {
   components: { CButton, CInput },
@@ -52,17 +54,28 @@ export default {
         return
       }
 
-      loginByEmail({ email: this.email, password: this.password }).then(res => {
-        this.$setSuccessMessage('欢迎回来,' + res.name)
-        this.$store.commit(SET_USER_INFO, { userInfo: res })
-        if (res.type === 'TEACHER' || res.type === 'teacher') {
-          this.$router.push({ name: 'teacher' })
-        } else {
-          this.$router.push({ name: 'student' })
-        }
-      }).catch(err => {
-        this.$setErrorMessage(err.response.data.msg)
-      })
+      if (this.email.match(/.+@.+/)) {
+        loginByEmail({ email: this.email, password: this.password })
+          .then(res => {
+            this.$setSuccessMessage('欢迎回来,' + res.name)
+            this.$store.commit(SET_USER_INFO, { userInfo: res })
+            if (res.type === userType.teacher) {
+              this.$router.push({ name: 'teacher' })
+            } else if (res.type === userType.student) {
+              this.$router.push({ name: 'student' })
+            } else if (res.type === userType.admin) {
+              this.$router.push({ name: 'admin' })
+            }
+          })
+          .catch(err => { this.$setErrorMessage(err.response.data.msg) })
+      } else {
+        login({ username: this.email, password: this.password })
+          .then(res => {
+            this.$store.commit(SET_USER_INFO, { userInfo: { ...res, type: userType.admin } })
+            this.$router.push('/admin')
+          })
+          .catch(err => { this.$setErrorMessage(err.response.data.msg) })
+      }
     },
     handleToRegister () {
       this.$router.push({ name: 'register' })