学生管理系统-02项目案例(2)

news2025/1/10 17:42:07

一、表单的验证

完成表单验证的步骤

  • el-form表单元素上添加一个rules属性,rules中配置相关的验证规则

  • el-form表单元素上添加:model将data中验证的响应式数据关联起来

  • el-form-item中添加prop属性,该属性一定和rules中的key值对应来

 <el-form :rules="userFormRules" :model="userForm">
      <el-form-item prop="username">
           <el-input  prefix-icon="el-icon-user-solid" v-model="userForm.username"></el-input>
      </el-form-item>
  </el-form>
export default {
    data(){
        return{
            userForm:{
                username:'',
                password:''
            },
            userFormRules:{
                username:[
                    {required:true,message:'用户名不能为空',trigger:'blur'}
                ]
            }
        }
    }
}

登录功能实现

  • 给登录按钮绑定单击事件

 <el-button type="primary" class="loginbtn" @click="login()">登录</el-button>
  • 在methods选项定义login方法,完成登录业务

methods:{
        login(){
            this.$refs.loginForm.validate(async args=>{
               if(args){
                 const {code,message,token}=await this.$api.users.login(this.userForm)
                 if(code){
                    //this.$message.success(message)
                    this.$message({
                        message,
                        type:'success'
                    })
                    //保存token
                    setStore(TOKEN_KEY,token)
                    this.$router.replace('/')
                 }else{
                    this.$message.warning(message)
                 }
               }
            })
​
        }
    }
  • 这里将保存token的方法写成了一个工具

在utils下创建h5store.js文件,编写代码如下

export const setStore=(key,value)=>localStorage.setItem(key,value)
export const getStore=key=>localStorage.getItem(key)
export const removeStore=key=>localStorage.removeItem(key)

在utils下创建constants.js,专门存放常量,便于后续的管理

export const TOKEN_KEY="token"

二、后台首页布局

1、静态页面布局

用于布局的容器组件,方便快速搭建页面的基本结构:

<el-container>:外层容器。当子元素中包含 <el-header><el-footer> 时,全部子元素会垂直上下排列,否则会水平左右排列。

<el-header>:顶栏容器。

<el-aside>:侧边栏容器。

<el-main>:主要区域容器。

<el-footer>:底栏容器。

<template>
   <el-container>
      <!-- 侧边栏 -->
      <el-aside width="220px">asider</el-aside>
      <el-container>
          <el-header>header</el-header>
          <el-main>main</el-main>
      </el-container>
   </el-container>
</template>

2、左侧菜单栏

<template>
    <el-container class="container">
        <el-aside>
           <div class="logo">蜗牛BOSS系统</div>
           <el-menu
            background-color="#112243"
            text-color="#fff"
            active-text-color="#ff0"
            :unique-opened="true">
                <el-submenu index="1">
                    <template slot="title">
                        <i class="el-icon-s-management"></i>
                        <span>控制面板</span>
                    </template>
                    <el-menu-item index="11">
                        <i class="el-icon-tickets"></i>
                        <span>工作台</span>
                    </el-menu-item>
                     <el-menu-item index="12">
                        <i class="el-icon-tickets"></i>
                        <span>报表分析</span>
                    </el-menu-item>
                </el-submenu>
                <el-submenu index="2">
                    <template slot="title">
                        <i class="el-icon-s-management"></i>
                        <span>业务管理</span>
                    </template>
                    <el-menu-item index="21">
                        <i class="el-icon-tickets"></i>
                        <span>学生管理</span>
                    </el-menu-item>
                     <el-menu-item index="22">
                        <i class="el-icon-tickets"></i>
                        <span>教师管理</span>
                    </el-menu-item>
                </el-submenu>
           </el-menu>
        </el-aside>
        <el-container class="main-container">
            <el-header></el-header>
            <el-main></el-main>
        </el-container>
    </el-container>
</template>

3、动态菜单

  • 在请求拦截器中设置Authorization

在request.js文件中进行设置

instance.interceptors.request.use(config=>{
    //可以设置携带token信息
    config.headers.Authorization=getStore(TOKEN_KEY)
    return config
},err=>{
    return Promise.reject(err)
})
  • 在api中添加获取权限的api方法

//导入封装后的axios
import {instance} from '@/util/request'
export default{
   getAuthMenus:()=>instance.get('/menus/getAuthMenus')
}
  • 在Home组件中在created方法中调用获取权限的方法

export default {
    data(){
        return{
            menus:[]
        }
    },
    methods:{
        async getAuthMenus(){
            const result=await this.$api.users.getAuthMenus()
            console.log('result',result);
            this.menus=result.data
        }
    },
    created(){
        this.getAuthMenus()
    }
}
  • 在菜单栏中完成动态渲染

<el-menu
    background-color="#112243"
    text-color="#fff"
    active-text-color="#ff0"
    :unique-opened="true">
    <el-submenu :index="item._id" v-for="item in menus" :key="item._id">
           <template slot="title">
                <i :class="item.icon"></i>
                <span>{{item.title}}</span>
           </template>
           <el-menu-item :index="subitem._id" v-for="subitem in item.children" :key="subitem._id">
                <i class="el-icon-tickets"></i>
                <span>{{subitem.title}}</span>
           </el-menu-item>      
     </el-submenu>    
</el-menu>

4、静态路由的配置

实现步骤

  • 在views的目录下按照模块创建相应的页面

    按照老师指定的要求去定义路由页面

  • 在config.js文件中进行二级的配置,这里配置二级路由路径的时候,请参照上图数据库表中的path字段来进行定义

//通过ES6的导入语法将组件导入进来
import Login from '@/views/Login'
import Home from '@/views/Home'
import NotFound from '@/views/NotFound'

export default[
    {
        path:'/login',
        component:Login
    },
    {
        path:'/',
        redirect:'/home'
    },
    {
        path:'/home',
        component:Home,
        children:[
            {
                path:'workplace',
                component:()=>import('@/views/dashboard/workplace.vue')
            },
            {
                path:'analysis',
                component:()=>import('@/views/dashboard/analysis.vue')
            }
        ]
    },
    {
        path:'*',
        component:NotFound
    },
]
  • 如果要让elementui的menu菜单启用vu-router路由模式,需要在el-menu标签中设置:router="true"

<el-menu
	:router="true">        
  • 设置完如上的属性后,就需要在el-menu-item标签中将:index的属性值,由之前的subItem._id改成subItem.path

  • 在Home的el-main区域内容配置二级路由出口

<el-main>
     <!-- 配置二级路由出口 -->
     <router-view></router-view>
</el-main>

5、菜单折叠

  • 在Home.vue文件中定义数据isCollpase

export default {
  data(){
    return{
      isCollapse:false,
      logotitle:'蜗牛BOSS系统'
    }
  }
}
  • <el-header>区域添加折叠和展开按钮,并根据isCollapse的值控制这两个按钮的显示或隐藏

<el-header>
     <i v-if="!isCollapse" class="el-icon-s-fold"></i>
     <i v-else class="el-icon-s-unfold"></i>
    <!--...其余代码省略-->   
</el-header>
  • 为展开和折叠按钮添加绑定单击事件

<el-aside>
     <i v-if="!isCollapse" class="el-icon-s-fold" @click="toggleCollpase" style="margin-left:190px"></i>
     <i v-else class="el-icon-s-unfold" @click="toggleCollpase" style="margin-left:40px"></i>
    <!--...其余代码省略-->   
</el-aside>
methods: {
    toggleCollpase(){
      this.isCollapse=!this.isCollapse;
	  if(this.isCollapse){
               this.logotitle="蜗牛"
        }else{
               this.logotitle="蜗牛BOSS系统"
        }
    }
}
  • <el-menu>标签中添加collpase属性来控制菜单的折叠或展开

<el-menu :collapse="isCollapse">
  • <el-aside>中动态设置菜单栏的宽度,同时删除掉之前style="width: 200px"

<el-aside :width="isCollapse?'68px':'220px'">
  • 取消切换动画

<el-menu :collapse-transition="false">
  • 去掉菜单栏边框

 .el-menu{
       border: none;
  }

三、路由守卫

在单页面应用SPA,组件之间的切换(页面的跳转)实际上是通过路由跳转来完成,路由守卫的主要作用就是在进入目标路由的时候(可以在之前,也可以在后)先进入到这些函数里边,这些函数可以用来完成逻辑判断,适合要求的进入目标路由,不符合要求的会被拦截到其他地方去

我们把这种函数称为路由守卫函数

路由守卫函数分类

  • 全局前置守卫:所有的路由都要进入的守卫函数,而且时机在前

  • 全局后置守卫:所有的路由都要进入的守卫函数,时机在后

  • 路由独享守卫:指定只进入指定路由的时候触发的函数

  • 组件内守卫:进入组件触发,离开组件触发

1、全局前置守卫

  • 在router/index.js文件中添加路由守卫

//设置路由全局前置守卫
router.beforeEach(async(to,from,next)=>{
  console.log('*********路由全局前置守卫*************');
  console.log('to',to);
  if(to.path=="/login"){
    next()//进入目标路由
  }else{
    console.log('*********您等等*************');
    //获取token信息
    if(getStore(TOKEN_KEY)){
      try{
        await Vue.prototype.$api.users.getUserInfo()
      }catch(err){
         next('/login')
      }
      console.log('result',result);
      next()//进入到目标地
    }else{
      Vue.prototype.$message.warning("您还没有登录请先登录")
      next("/login")
    }
  }
})
  • 修改request.js中响应拦截器

instance.interceptors.response.use(response=>{
    return response.data
},err=>{
    if(err.response){
        switch(err.response.status){
            case 401:
                Vue.prototype.$message.warning('Token已经过期,请重新登录')
                break;
        }
    }
    return Promise.reject(err)
})

2、动态设置路由规则

前提:由于项目中路由配置都是静态,除了这种方式之外还另外一种方式,是通过代码方法进行动态路由设置

router.beforeEach(async(to,from,next)=>{
  if(to.path=="/login"){
    next()
  }else{
    if(getStore(TOKEN_KEY)){
        try{
          const result=await Vue.prototype.$api.users.getUserInfo()
          //定义一个变量用来接收后端的所有路由规则
          let permissionList=result.data.permissionList
          //将查出来的数据赋值到menus
          menus=permissionList
          //使用for循环进行遍历
          for(let i=0;i<permissionList.length;i++){
            let routeObj=permissionList[i]
            //addRoute(参数1,参数2):用来动态添加一条新的路由规则,参数1:父路由的name,参数2:路由对象
            router.addRoute("homeName",{
              path:routeObj.path,
              component:()=>import(`@/views${routeObj.permission}.vue`)
            })
          }
          //查看所有路由
          console.log('routes',router.getRoutes());
         
        }catch(err){
           next('/login')
        }
      next()//进入到目标地
    }else{
      Vue.prototype.$message.warning("您还没有登录请先登录")
      next("/login")
    }
  }
})

如上错误的解决办法有三种

  • 降低版本

  • 在路由跳转中使用catch来处理

this.$router.replace('/').catch(()=>{})
  • 统一重写replace或者push方法

const originalPush = VueRouter.prototype.push;
const originalReplace = VueRouter.prototype.replace;
//push
VueRouter.prototype.push = function push(location, onResolve, onReject) {
  if (onResolve || onReject)
    return originalPush.call(this, location, onResolve, onReject);
  return originalPush.call(this, location).catch(err => err);
};
//replace
VueRouter.prototype.replace = function push(location, onResolve, onReject) {
    if (onResolve || onReject)
        return originalReplace.call(this, location, onResolve, onReject);
    return originalReplace.call(this, location).catch(err => err);
};

如上问题解决完毕后,下面来打印一下添加好的路由规则

如上效果,就表示添加成功,路由添加成功后,我们需要让跳转的目标路由上,这里我们通过next({path\:to.path})方式让其进入,会发现网络发送多请求,造成严重影响,如下图所示

解决的办法设置menus变量,然后判断只有menus为空的时候,采取发送网路请求

//定义一个变量
let menus=null
//设置路由全局前置守卫:当进入目标路由之前会调用该函数
router.beforeEach(async(to,from,next)=>{
  if(to.path=="/login"){
    next()
  }else{
    if(getStore(TOKEN_KEY)){
      if(!menus){
        try{
          const result=await Vue.prototype.$api.users.getUserInfo()
          //定义一个变量用来接收后端的所有路由规则
          let permissionList=result.data.permissionList
          //将查出来的数据赋值到menus
          menus=permissionList
          //使用for循环进行遍历
          for(let i=0;i<permissionList.length;i++){
            let routeObj=permissionList[i]
            //addRoute(参数1,参数2):用来动态添加一条新的路由规则,参数1:父路由的name,参数2:路由对象
            router.addRoute("homeName",{
              path:routeObj.path,
              component:()=>import(`@/views${routeObj.permission}.vue`)
            })
          }
          //查看所有路由
          console.log('routes',router.getRoutes());
          next({path:to.path})
        }catch(err){
           next('/login')
        }
      }
      next()//进入到目标地
    }else{
      Vue.prototype.$message.warning("您还没有登录请先登录")
      next("/login")
    }
  }
})

3、路由进度条

使用nprogress插件来完成路由进度操作

  • 下载依赖包

npm i nprogress 
  • 配置

//导入nprogress依赖包
import NProgress from 'nprogress'
//将nprogress的css导入
import 'nprogress/nprogress.css'
NProgress.configure({
   easing: "ease-in-out",
   speed: 300,
   trickeSpeed: 300,
})
  • 在路由全局前置守卫上启动动画

router.beforeEach(async(to,from,next)=>{
      NProgress.start()
})
  • 在路由全局后置守卫上结束动画

router.afterEach((to,from)=>{
  NProgress.done()
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/787411.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

区块链实验室(12) - 网络拓扑对PBFT共识流量的影响

区块链实验室(10) - 实例说明PBFT的共识过程说明了1个简单又极端的网络&#xff0c;在这个网络中完成1个交易的共识&#xff0c;需要26次通信&#xff0c;见下图所示。 换1个网络&#xff0c;这个网络是强连通图&#xff0c;见下图。 在这个网络中完成1次交易&#xff0c;流量见…

vue3 +ts 报错 index.vue 不是模块

那是因为index.vue中创建了一个空的script标签&#xff0c;而且语法使用的是ts语法。vue-cli会用ts语法解析和校验 如果是无状态组件&#xff0c;删掉 如果是有状态组件&#xff0c;导出该组件的实例 去掉null的script后&#xff1a;

如何防止word转pdf乱码?这几个方法你试过了吗?

在工作中&#xff0c;我们常常需要处理各种类型的文件&#xff0c;并且会根据不同需求进行PDF文件与其他格式文件的相互转换&#xff0c;然而有时候在将Word文件转换成PDF时&#xff0c;可能会遇到乱码等问题&#xff0c;让人感到困扰。今天我将介绍两种方法&#xff0c;让您在…

除了Midjourney,这5个绘画网站同样好用

如今随着科技的发展&#xff0c;AI绘画网站走进了人们的视线。今天本文会为大家介绍5个同Midjourney一样好用的AI绘画王章&#xff0c;带大家体验AI绘画带来的乐趣&#xff0c;也帮助设计师更快地实现绘画创作&#xff0c;一起来看看吧&#xff01; 1、即时灵感 即时灵感是一…

世界头号黑客,渗透成功率100%,他为什么这么厉害?

这个世界有一些人&#xff0c;他们特别擅长计算机编程&#xff0c;比如Linux之父Linus&#xff0c;id software创始人John Carmack、QEMU, FFMPEG作者Fabrice Bellard。 这个世界也有一些人&#xff0c;他们特别擅长和人打交道&#xff0c;三言两语之间就能让你敞开心扉&#…

抖斗音直播间评论引流助手,支持直播间喊话+视频评论区喊话=到指定直播间引流精准粉丝【永久脚本+详细教程】

如果你觉得直播间发言手动太麻烦了&#xff0c;或许这个自动工具能帮到你&#xff01; 1.开始运行前&#xff0c;需要手动去打开打开直播间或者视频评论区&#xff0c;再运行脚本。 2.脚本就是模拟人工操作&#xff0c;在相应的APP里进行评论&#xff0c;无突破APP限制功能。…

【【51单片机的DS18B20温度传感器】】

学习温度传感器&#xff0c;探索单片机的奥秘 DS18B20是一种常见的数字温度传感器 测温范围-55度 ~125度 通信接口 1-wire 其他特征 可形成总线结构 内置温度报警功能 可寄生供电 其中的64位bit ROM 作为器件地址&#xff0c;用于总线通信的寻址 SCRATCHPAD暂存器 用于总线…

科技资讯|苹果计划本月推出Vision Pro头显开发套件,电池有重大更新

根据消息源 aaronp613 分享的信息&#xff0c;苹果计划本月底面向开发者&#xff0c;发布 Vision Pro 头显开发套件。消息源还指出苹果更新了 Vision Pro 头显电池组的代号&#xff0c;共有 A2781&#xff0c;A2988 和 A2697 三种不同的型号&#xff0c;目前尚不清楚三者之间的…

从零构建深度学习推理框架-1 简介和Tensor

源代码作者&#xff1a;https://github.com/zjhellofss 本文仅作为个人学习心得领悟 &#xff0c;将原作品提炼&#xff0c;更加适合新手 什么是推理框架&#xff1f; 深度学习推理框架用于对已训练完成的神经网络进行预测&#xff0c;也就是说&#xff0c;能够将深度训练框…

openGauss学习笔记-19 openGauss 简单数据管理-ORDER BY子句

文章目录 openGauss学习笔记-19 openGauss 简单数据管理-ORDER BY子句19.1 语法格式19.2 参数说明19.3 示例 openGauss学习笔记-19 openGauss 简单数据管理-ORDER BY子句 ORDER BY对SELECT语句检索得到的一列或者多列数据进行升序&#xff08;ASC&#xff09;或者降序&#xf…

Linux 两种GPIO控制方式

1、采用sysfs的方式控制&#xff0c;这是内核标准的sysfs接口 如&#xff1a; echo 25 > /sys/class/gpio/export echo "out" > /sys/class/gpio/gpio25/direction echo 1 > /sys/class/gpio/gpio25/value 2、采用libgpiod 控制内核生成的节点来控制/d…

Qt:强大API、简化框架、多语言支持,构建全面应用程序“

强大的API&#xff1a;Qt提供了丰富的API&#xff0c;包括250多个C类&#xff0c;基于模板的集合、序列化、文件操作、IO设备、目录管理、日期/时间等功能。还包括正则表达式处理和支持2D/3D图形渲染&#xff0c;以及OpenGL和XML支持。此外&#xff0c;Qt还允许导入第三方图形设…

Spring Boot 框架中的配置文件

一、配置文件作用 整个项目中所有重要的数据都是在配置文件中配置的&#xff0c;比如&#xff1a; 数据库的连接信息&#xff08;包含用户名和密码的设置&#xff09;&#xff1b; 项目的启动端口&#xff1b; 第三方系统的调用秘钥等信息&#xff1b; 用于发现和定位问题的普…

小红书如何引流推广,小红书app评论图片脚本实操教学分享

大家好&#xff0c;我是小刘互联网思维。最近小红书越来越火&#xff0c;所以很多人或者小团队也都盯上了这个新兴市场。有人选择手动引流&#xff0c;就一定有人想软件引流&#xff0c;有些朋友就私信问我这个软件引流要怎么操作&#xff0c;接下来我就为大家简单讲解小红书脚…

多线程下的OOM问题

多线程下的OOM问题 前言问题排查日志查看代码查看集群查看问题解决 多线程OOM时候的回收测试代码启动参数设置控制台打印 前言 最近的一台服务器出现了OOM的情况&#xff0c;出于好奇就进行了一些探查&#xff0c;这里做一些简单的记录 问题排查 日志查看 登陆服务器查看当…

24考研数据结构-线性表3

目录 2.4 线性表的链式表示2.4.0 引入的原因2.4.1 单链表的定义 2.4.2 单链表的两种实现形式2.4.2.1 不带头结点的单链表2.4.2.2 带头结点的单链表2.4.2.3知识回顾与重要考点2.4.3.1 带头结点的单链表按位序插入节点2.4.3.2 单链表的插入节点的时间复杂度2.4.3.3 不带头结点的单…

Ceph网络模型

Ceph网络模型 Ceph 生产环境中一般分为两个网段公有网络: 用于用户的数据通信集群网络: 用于集群内部的管理通信

mac m1 触控栏TouchBar功能栏异常

电脑可能在高温下运行时间过长&#xff0c;导致TouchBar之前正常显示的调整屏幕亮度与调整声音等功能的按钮均丢失&#xff0c;然后看了一眼键盘设置&#xff0c;设置也是正常的&#xff0c;已勾选显示功能栏 下面请看 如何在MacBook Pro&#xff08;macOS Monterey&#xff0…

2023年深圳杯数学建模赛题浅析

由于今明两日由于一些不可避免的事情&#xff0c;这里仅仅先给大家简单写一个赛题浅析&#xff0c;详细过程步骤思路以及讲解视频预计后天发布 A题 影响城市居民身体健康的因素分析 A题以慢性病为命题背景&#xff0c;给出数据以及题目初步来看来看为一个数据处理数据分析的综…

elasticsearch查询操作(DSL语句方式)

说明&#xff1a;本文介绍在kibana&#xff0c;es的可视化界面上对文档的查询操作&#xff1b; 添加数据 先使用API&#xff0c;创建索引库&#xff0c;并且把数据从MySQL中查出来&#xff0c;传到ES上&#xff0c;参考&#xff08;http://t.csdn.cn/NaTHg&#xff09; 索引库…