学习源码可以看我的个人前端学习笔记 (github.com):qdxzw/humanResourceIntelligentManagementProject
觉得有帮助的同学,可以点心心支持一下哈
主页权限验证(permission.js)
import router from '@/router'
import nprogress from 'nprogress' // 进度条
import 'nprogress/nprogress.css' // 进度条样式
import store from '@/store'
/*** 前置守卫**/
// 白名单
const whiteList = ['/login', '/404']
router.beforeEach((to, from, next) => {nprogress.start() // 开启进度条if (store.getters.token) {// 存在tokenif (to.path === '/login') {// 跳转到主页next('/') // 中转到主页// next有地址的话并没有执行后置守卫nprogress.done()} else {next() // 放过}} else {// 没有tokenif (whiteList.includes(to.path)) {next() // 放过} else {next('/login') // 中转到登录页nprogress.done()}}
})/*** 后置守卫**/
router.afterEach(() => {console.log(123)nprogress.done() // 关闭进度条
})
获取用户资料在Vuex中共享
获取资料action的调用位置
1.封装API请求
export function getUserInfo () {// request执行之后会得到promise对象(再通过使用async和await可以获取结果)return request({url: '/sys/profile',method: 'GET'})
}
2.Vuex应用
// 存放数据
const state = {token: getToken(), // 从缓存中读取初始值userInfo: {} // 存储用户基本资料状态
}setUserInfo (state, userInfo) {state.userInfo = userInfo}// 获取用户的基本资料async getUserInfo (context) {const result = await getUserInfo()context.commit('setUserInfo', result)}
3.getters声明userId
userId: state => state.user.userInfo.userId, // 取用户id,用于判断页面是否获取过资料
4.权限拦截处调用action
// 如果不是则放过// 判断是否获取过资料if (!store.getters.userId) {// 如果没有则获取资料await store.dispatch('user/getUserInfo')}next()
显示用户头像和用户名
1.Vuex使用getters暴露属性
avatar: state => state.user.userInfo.staffPhoto, // 用户头像
name: state => state.user.userInfo.username // 用户姓名
2.Navbar组件引入
// 辅助函数,自动引入getters中的属性// 引入用户头像和名称...mapGetters(['sidebar', 'avatar', 'name'])},
3.Navbar设置
<!-- 用户头像 --><img :src="avatar" class="user-avatar" /><!-- 用户名称 --><span class="name">{{ name }}</span><!-- 图标 --><i class="el-icon-setting" />
4.设置样式
.avatar-wrapper {margin-top: 5px;position: relative;display: flex;align-items: center;.name {// 用户名称距离右侧的距离margin-right: 10px;font-size: 16px;}.user-avatar {cursor: pointer;width: 30px;height: 30px;border-radius: 50%;}.el-icon-setting {font-size: 20px;}
处理用户头像为空的场景
实例代码
<!-- 用户头像 -->
<img v-if="avatar" :src="avatar" class="user-avatar" />
<span v-else class="username">{{ name?.charAt(0) }}</span>.username {width: 30px;height: 30px;line-height: 30px;text-align: center;background-color: #04c9be;color: #fff;border-radius: 50%;margin-right: 4px;}npm i vue@2.7.0 vue-template-compiler@2.7.0
处理token失效
实例代码
// 判断token值是否等于401if (error.response.status === 401) {Message({ type: 'warning', message: '登录超时了' })// token超时了await store.dispatch('user/logout') // 退出登录actionrouter.push('/login') // 跳到登录页return Promise.reject(error)}// 退出登录logout (context) {// 1.删除tokencontext.commit('removeToken')// 2.删除用户信息context.commit('setUserInfo', {})}
调整下拉菜单,实现退出登录
<!-- native事件修饰符 --><!-- 注册组件的根元素的原生事件 --><el-dropdown-item @click.native="logout"><span style="display: block">退出登录</span></el-dropdown-item>async logout () {// 调用退出登录的actionawait this.$store.dispatch('user/logout')this.$router.push('/login')}
修改密码功能实现
修改密码-弹出层
<!-- prevent阻止默认事件 --><a target="_blank" @click.prevent="updatePassword"><el-dropdown-item>修改密码</el-dropdown-item></a><!-- 放置dialog --><!-- sync可以接收子组件传过来的事件和值 --><el-dialog width="500px" title="修改密码" :visible.sync="showDialog"><!-- 放置表单 --></el-dialog>showDialog: true // 控制弹层的显示和隐藏updatePassword () {this.showDialog = true // 显示弹层}
修改密码-表单结构
<!-- 放置表单 --><el-form label-width="120px"><el-form-item label="旧密码"><el-input type="password" size="small" /></el-form-item><el-form-item label="新密码"><el-input type="password" size="small" /></el-form-item><el-form-item label="重复密码"><el-input type="password" size="small" /></el-form-item><el-form-item><el-button size="mini" type="primary">确认密码</el-button><el-button size="mini">取消</el-button></el-form-item></el-form>
修改密码-表单校验
rules: {// 旧密码oldPassword: [{ required: true, message: '旧密码不能为空', trigger: 'blur' }], // 新密码newPassword: [{ required: true, message: '新密码不能为空', trigger: 'blur' },{trigger: 'blur',min: 6,max: 16,message: '新密码的长度6-16位之间'}], // 确认密码字段confirmPassword: [{ required: true, message: '重复密码不能为空', trigger: 'blur' },{trigger: 'blur',validator: (rule, value, callback) => {if (this.passForm.newPassword === value) {callback()} else {callback(new Error('重复密码和新密码输入不一致'))}}}]}
修改密码-确定和取消
btnOk () {this.$refs.passForm.validate(async isOk => {if (isOk) {// 调用接口await updatePassword(this.passForm)this.$message.success('修改密码成功')this.btnCancel()}})},btnCancel () {// 成功之后重置表单this.$refs.passForm.resetFields()// 关闭弹层this.showDialog = false}@close="btnCancel"/*** 更新密码*/
export function updatePassword (data) {return request({url: '/sys/user/updatePass',method: 'PUT',data})
}
清理组件和路由并创建项目所需组件和路由
删除多余的组件和路由
业务模块
实例代码(department)
<template><div class="container"><div class="app-container">组织架构</div></div>
</template>
<script>
export default {name: 'Department'
}
</script>import layout from '@/layout'
export default {// 路由信息path: '/department',component: layout, // 一级路由children: [{path: '', // 二级路由地址为空时 表示 /department 显示一级路由 + 二级路由component: () => import('@/views/department'),name: 'department', // 可以用来跳转 也可以标记路由meta: {// 路由元信息 存储数据的icon: 'tree', // 图标title: '组织' // 标题}}]
}import Layout from '@/layout'
import department from './modules/department'
import approval from './modules/approval'
import attendance from './modules/attendance'
import employee from './modules/employee'
import permission from './modules/permission'
import role from './modules/role'
import salary from './modules/salary'
import social from './modules/social'{path: '/',component: Layout,redirect: '/dashboard',children: [{path: 'dashboard',name: 'Dashboard',component: () => import('@/views/dashboard/index'),meta: { title: '首页', icon: 'dashboard' }}]},department,role,employee,permission,attendance,approval,salary,social,
解析左侧菜单
显示项目logo
<router-link key="collapse" class="sidebar-logo-link" to="/"><img src="@/assets/common/logo.png" class="sidebar-logo" /></router-link>& .sidebar-logo {width: 140px;vertical-align: middle;margin-right: 12px;}&.collapse {.sidebar-logo {margin-right: 0px;width: 32px;height: 32px;}}\src\settings.js
sidebarLogo: true