云e办前端笔记
办公系统前端开发
本系统采用vue框架进行搭建,主要ui是Elementui,主要功能实现了一个公司的员工资料、人事管理、薪资管理、统计管理、系统管理等功能。
1登陆页面设计
如图所示,使用Elementui进行简单搭建,验证码由后端提供,主要代码如下,
本代码主要运用了elemenui的Loading加载、form验证表单
以及附属的相关事件,样式由后期调整得。
事件的主要功能:将axios从后端请求得到的token数据存入window.
SessionStorage.setItem()中,为了使axios做下一次请求时获取token认证,
登陆即完成了
<template> <div> <el-form v-loading="loading" element-loading-text="正在登录..." element-loading-spinner="el-icon-loading" element-loading-background="rgba(0, 0, 0, 0.8)" :rules="rules" ref="loginForm" :model="loginForm" class="loginContainer"> <h3 class="loginTitle">系统登陆h3> <el-form-item prop="username"> <el-input type="text" v-model="loginForm.username" auto-complete="false" placeholder="请输入用户名">el-input> el-form-item> <el-form-item prop="password"> <el-input type="password" v-model="loginForm.password" auto-complete="false" placeholder="请输入密码">el-input> el-form-item> <el-form-item prop="code"> <el-input style="width:200px ; margin-right: 5px" type="text" v-model="loginForm.code" auto-complete="false" placeholder="点击更换图片"> el-input> <img :src="captchaUrl" @click="updateCaptcha" class="el-form-item__content"> el-form-item> <el-checkbox v-model="checked" class="loginRemember">记住我el-checkbox> <el-button type="primary" style="width: 100%" @click="submitLogin">登录el-button> el-form> div> template> <script> export default { name: "Login", data(){ return{ captchaUrl:'/captcha?time='+new Date(), loginForm:{ username:'admin', password:'123', code:'' }, checked:true, loading:false, rules:{ username: [{required:true,message:'请输入用户名',trigger:'blur'}], password: [{required:true,message: '请输入密码',trigger:'blur'}], code: [{required:true,message:'请输入验证码',trigger:'blur'}] } } }, methods: { updateCaptcha(){ this.captchaUrl='/captcha?time='+new Date(); }, submitLogin() { this.$refs.loginForm.validate((valid) =>{ if (valid) { this.loading=true; this.postRequest('/login',this.loginForm).then(resp=>{ if (resp){ this.loading=false; const tokenStr=resp.obj.tokenHead+resp.obj.token; //存进去 跳转页面后获取 window.sessionStorage.setItem('tokenStr',tokenStr); //跳转 /* this.$router.replace('/home');*/ /*此处解决自己输入属地址的行为*/ let path = this.$route.query.redirect; this.$router.replace((path=='/'||path==undefined)?'/home' : path); } this.loading=false; }); } else { this.$message.error('请填写完整!!!'); return false; } }); } } } script> <style> .el-form-item__content{ display: flex; align-items: center } .loginContainer{ border-radius: 15px; background-clip: padding-box;/*背景裁剪到内边框*/ margin: 180px auto; width: 350px; padding: 15px 35px 15px 35px;/*拉大间隔*/ background: #fff; border: 1px solid #eaeaea; } .loginTitle{ margin: 0px auto 40px auto; text-align: center; } .loginRemember{ text-align: left; margin: 0px 0px 15px 0px; } style>
2主页设计
如图所示,主要将上面所属的系统功能一一展示在左上角,主要运用的是
Elementui的container容器布局第四个,展示的数据菜单由路由模式从
后端获取,实现自动展示相应的菜单,代码如下。
<template> <div> <el-container> <el-header class="homeHeader"> <div class="title"> 云e办div> <el-dropdown class="userInfo" @command="commandHandler"> <span class="el-dropdown-link"> {{user.name}}<i><img :src="user.userFace"/>i> span> <el-dropdown-menu slot="dropdown"> <el-dropdown-item command="userinf">个人中心el-dropdown-item> <el-dropdown-item command="setting">设置el-dropdown-item> <el-dropdown-item command="logout">注销登录el-dropdown-item> el-dropdown-menu> el-dropdown> el-header> <el-container> <el-aside width="200px"> <el-menu router unique-opened> <el-submenu :index="index+''" v-for="(item,index) in routes" :key="index" v-if="!item.hidden"> <template slot="title"> <i :class="item.iconCls" style="color: darkcyan;margin-right: 5px">i> <span>{{item.name}}span> template> <el-menu-item v-for="(children,index) in item.children" :index="children.path"> {{children.name}} el-menu-item> el-submenu> el-menu> el-aside> <el-main> <el-breadcrumb v-if="this.$router.currentRoute.path !='/home'" separator-class="el-icon-arrow-right"> <el-breadcrumb-item :to="{ path: '/home' }">首页el-breadcrumb-item> <el-breadcrumb-item>{{this.$router.currentRoute.name}}el-breadcrumb-item> el-breadcrumb> <div class="homeWelcome" v-if="this.$router.currentRoute.path=='/home'"> 欢迎来到云e办系统 div> <router-view class="homeRouterView" /> el-main> el-container> el-container> div> template> <script> export default { name: "Home", computed:{ routes(){ return this.$store.state.routes; } }, data(){ return{ user:JSON.parse(window.sessionStorage.getItem('user')) } }, methods:{ commandHandler(command){ if (command=='logout'){ { this.$confirm('此操作将注销登录, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { this.postRequest('/logout'); window.sessionStorage.removeItem('tokenStr'); window.sessionStorage.removeItem('user'); //清空菜单 this.$store.commit('initRoutes',[]); this.$router.replace('/'); }).catch(() => { this.$message({ type: 'info', message: '已取消注销' }); }); } } } } } script> <style> .homeHeader{ background: #409eff; display: flex;/*文本生效*/ align-items: center; justify-content: space-between;/*将最后元素末尾对齐*/ padding: 0 15px; box-sizing: border-box; } .homeHeader .title{ font-size: 30px; font-family: 华文楷体; color: white; } .homeHeader .userInfo{ cursor:pointer; } .el-dropdown-link img{ width: 48px; height: 48px; border-radius: 24px; } .homeWelcome{ text-align: center; font-size: 30px; font-family: 华文楷体; color: #409eff; padding-top: 50px; } .homeRouterView{ margin-top: 10px; } style>
3Vuex及路由存储对象
安装vuex后,使用vuex构建存储对象,代码如下
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
export default new Vuex.Store({
state:{
routes:[]
},
//同步
mutations:{
initRoutes(state,data){
state.routes=data;
}
},
//异步
actions:{
}
})
4菜单初始化工具类
因为我们刚刚使用vuex构建了路由储存对象,需要使用菜单初始化工具将菜单存入routes[],
具体工具类代码如下
import {getRequest} from './api' export const initMenu = (router,store)=>{ if(store.state.routes.length>0){ return; } getRequest('/system/cfg/menu').then(data=>{ if (data){ let fmtRoutes = formatRoutes(data); router.addRoutes(fmtRoutes); store.commit('initRoutes',fmtRoutes);/*核心*/ } }) } export const formatRoutes = (routes)=>{ let fmtRoutes=[]; routes.forEach(router=>{ let{ path, component, name, iconCls, children, }= router; if (children&&children instanceof Array){ //递归 children=formatRoutes(children); } let fmRouter = { path:path, name, iconCls, children, component(resolve){ if (component.startsWith('Home')){ require(['../views/'+component+'.vue'],resolve); }else if (component.startsWith('Emp')){ require(['../views/emp/'+component+'.vue'],resolve); }else if(component.startsWith('Per')){ require(['../views/per/'+component+'.vue'],resolve); }else if(component.startsWith('Sal')){ require(['../views/sal/'+component+'.vue'],resolve); }else if(component.startsWith('Sta')){ require(['../views/sta/'+component+'.vue'],resolve); }else if(component.startsWith('Sys')){ require(['../views/sys/'+component+'.vue'],resolve); } } } fmtRoutes.push(fmRouter); }); return fmtRoutes; }
5请求响应处理工具类
此工具类主要是过滤非法请求以及处理响应时发生的错误,将他们的信息用弹窗显示出来如图所示,具体代码如下
import axios from 'axios' import {Message} from "element-ui"; //请求拦截器 axios.interceptors.request.use(config=>{ if (window.sessionStorage.getItem('tokenStr')){ //请求时自动带入token config.headers['Authorization'] = window.sessionStorage.getItem('tokenStr') } return config; },error => { console.log(error); }) axios.interceptors.response.use(success=>{ //业务逻辑错误 if (success.status||success.data.code==200){ if (success.data.code==500||success.data.code==401||success.data.code==403){ Message.error({message:success.data.message}); return; } if (success.data.message){ Message.success({message:success.data.message}) } } return success.data; },error=>{ //未能调取接口错误 if (error.response.data.code==504||error.response.data.code==404){ Message.error({message:'服务器被吃了'}) }else if(error.response.data.code==403){ Message.error({message:'权限不足'}) }else if(error.response.data.code==401){ Message.error({message:'尚未登陆'}) router.replace('/') } else { if (error.response.data.message) { Message.error({message: error.response.data.message}); } else { Message.error({message: '未知错误'}) } } return; }); let base=''; //传送json请求格式的post请求 export const postRequest=(url,params)=>{ return axios({ method:'post', url:`${base}${url}`, data:params }) } export const putRequest=(url,params)=>{ return axios({ method:'put', url:`${base}${url}`, data:params }) } export const getRequest=(url,params)=>{ return axios({ method:'get', url:`${base}${url}`, data:params }) } export const deleteRequest=(url,params)=>{ return axios({ method:'delete', url:`${base}${url}`, data:params }) }
6暴露路由
使用路由模式菜单,需要将路由包装暴露出来,以便公共使用
import Vue from 'vue' import VueRouter from 'vue-router' import Login from '../views/Login.vue' Vue.use(VueRouter) const routes = [ { path: '/', name: 'Login', component: Login, hidden:true }, ] const router = new VueRouter({ routes }) export default router
7创建菜单组件
我们需要将菜单组件分组创建好,然后通过工具类初始化存入路由数组,以便实现点击跳转,代码后面发布