权限:菜单权限,按钮权限,数据权限
权限
什么是工作流?
部分或者整体业务实现的计算机环境下的自动化
工作流
审批流
// 获取用户对应的权限菜单
router.get("/getPermissionList", async (ctx) => {
let authorization = ctx.request.headers.authorization
let { data } = util.decoded(authorization)
let menuList = await getMenuList(data.role, data.roleList);
let actionList = getAction(JSON.parse(JSON.stringify(menuList)))
ctx.body = util.success({ menuList, actionList });
})
user.js
/**
* 用户管理模块
*/
const router = require('koa-router')()
const User = require('./../models/userSchema')
const Counter = require('./../models/counterSchema')
const Menu = require('./../models/menuSchema')
const Role = require('./../models/roleSchema')
const util = require('./../utils/util')
const jwt = require('jsonwebtoken')
const md5 = require('md5')
router.prefix('/users')
// 用户登录
router.post('/login', async (ctx) => {
try {
const { userName, userPwd } = ctx.request.body;
/**
* 返回数据库指定字段,有三种方式
* 1. 'userId userName userEmail state role deptId roleList'
* 2. {userId:1,_id:0}
* 3. select('userId')
*/
const res = await User.findOne({
userName,
userPwd: md5(userPwd)
}, 'userId userName userEmail state role deptId roleList')
if (res) {
const data = res._doc;
const token = jwt.sign({
data
}, 'imooc', { expiresIn: '1h' })
data.token = token;
ctx.body = util.success(data)
} else {
ctx.body = util.fail("账号或密码不正确")
}
} catch (error) {
ctx.body = util.fail(error.msg)
}
})
// 用户列表
router.get('/list', async (ctx) => {
const { userId, userName, state } = ctx.request.query;
const { page, skipIndex } = util.pager(ctx.request.query)
const {page,skipIndex}=util.pager(ctx.request.query)
let params = {}
if (userId) params.userId = userId;
if (userName) params.userName = userName;
if (state && state != '0') params.state = state;
try {
// 根据条件查询所有用户列表
const query = User.find(params, { _id: 0, userPwd: 0 })
const list = await query.skip(skipIndex).limit(page.pageSize)
const total = await User.countDocuments(params);
const total=await User.countDocuments(params);
const query=User.find(params,{_id:0,userPwd:0})
ctx.body = util.success({
page: {
...page,
total
},
list
})
} catch (error) {
ctx.body = util.fail(`查询异常:${error.stack}`)
}
})
// 获取全量用户列表
router.get('/all/list', async (ctx) => {
try {
const list = await User.find({}, "userId userName userEmail")
ctx.body = util.success(list)
} catch (error) {
ctx.body = util.fail(error.stack)
}
})
// 用户删除/批量删除
router.post('/delete', async (ctx) => {
// 待删除的用户Id数组
const { userIds } = ctx.request.body
// User.updateMany({ $or: [{ userId: 10001 }, { userId: 10002 }] })
const res = await User.updateMany({ userId: { $in: userIds } }, { state: 2 })
if (res.nModified) {
ctx.body = util.success(res, `共删除成功${res.nModified}条`)
return;
}
ctx.body = util.fail('删除失败');
})
router.popst('/delete',async(ctx)=>{
const {userIds}=ctx.request.body
})
// 用户新增/编辑
router.post('/operate', async (ctx) => {
const { userId, userName, userEmail, mobile, job, state, roleList, deptId, action } = ctx.request.body;
if (action == 'add') {
if (!userName || !userEmail || !deptId) {
ctx.body = util.fail('参数错误', util.CODE.PARAM_ERROR)
return;
}
const res = await User.findOne({ $or: [{ userName }, { userEmail }] }, '_id userName userEmail')
if (res) {
ctx.body = util.fail(`系统监测到有重复的用户,信息如下:${res.userName} - ${res.userEmail}`)
} else {
const doc = await Counter.findOneAndUpdate({ _id: 'userId' }, { $inc: { sequence_value: 1 } }, { new: true })
try {
const user = new User({
userId: doc.sequence_value,
userName,
userPwd: md5('123456'),
userEmail,
role: 1, //默认普通用户
roleList,
job,
state,
deptId,
mobile
})
user.save();
ctx.body = util.success('', '用户创建成功');
} catch (error) {
ctx.body = util.fail(error.stack, '用户创建失败');
}
}
} else {
if (!deptId) {
ctx.body = util.fail('部门不能为空', util.CODE.PARAM_ERROR)
return;
}
try {
const res = await User.findOneAndUpdate({ userId }, { mobile, job, state, roleList, deptId, })
ctx.body = util.success({}, '更新成功')
} catch (error) {
ctx.body = util.fail(error.stack, '更新失败')
}
}
})
// 获取用户对应的权限菜单
router.get("/getPermissionList", async (ctx) => {
let authorization = ctx.request.headers.authorization
let { data } = util.decoded(authorization)
let menuList = await getMenuList(data.role, data.roleList);
let actionList = getAction(JSON.parse(JSON.stringify(menuList)))
ctx.body = util.success({ menuList, actionList });
})
async function getMenuList(userRole, roleKeys) {
let rootList = []
if (userRole == 0) {
rootList = await Menu.find({}) || []
} else {
// 根据用户拥有的角色,获取权限列表
// 现查找用户对应的角色有哪些
let roleList = await Role.find({ _id: { $in: roleKeys } })
let permissionList = []
roleList.map(role => {
let { checkedKeys, halfCheckedKeys } = role.permissionList;
permissionList = permissionList.concat([...checkedKeys, ...halfCheckedKeys])
})
permissionList = [...new Set(permissionList)]
rootList = await Menu.find({ _id: { $in: permissionList } })
}
return util.getTreeMenu(rootList, null, [])
}
function getAction(list) {
let actionList = []
const deep = (arr) => {
while (arr.length) {
let item = arr.pop();
if (item.action) {
item.action.map(action => {
actionList.push(action.menuCode)
})
}
if (item.children && !item.action) {
deep(item.children)
}
}
}
deep(list)
return actionList;
}
module.exports = router
router.post('/operate',async(ctx)=>{
const {userId,userName}
})
// 获取用户对应的权限菜单
router.get("/getPermissionList", async (ctx) => {
let authorization = ctx.request.headers.authorization
let { data } = util.decoded(authorization)
let menuList = await getMenuList(data.role, data.roleList);
let actionList = getAction(JSON.parse(JSON.stringify(menuList)))
ctx.body = util.success({ menuList, actionList });
})
module.exports = {
/**
* 分页结构封装
* @param {number} pageNum
* @param {number} pageSize
*/
pager({ pageNum = 1, pageSize = 10 }) {
pageNum *= 1;
pageSize *= 1;
const skipIndex = (pageNum - 1) * pageSize;
return {
page: {
pageNum,
pageSize
},
skipIndex
}
},
success(data = '', msg = '', code = CODE.SUCCESS) {
log4js.debug(data);
return {
code, data, msg
}
},
fail(msg = '', code = CODE.BUSINESS_ERROR, data = '') {
log4js.debug(msg);
return {
code, data, msg
}
},
CODE,
decoded(authorization) {
if (authorization) {
let token = authorization.split(' ')[1]
return jwt.verify(token, 'imooc')
}
return '';
},
manager-fe/src/store/index.js
/**
* Vuex状态管理
*/
import { createStore } from 'vuex'
import mutations from './mutations'
import storage from './../utils/storage'
const state = {
userInfo: storage.getItem("userInfo") || {}, // 获取用户信息
menuList: storage.getItem("menuList"),
actionList: storage.getItem("actionList"),
noticeCount: 0
}
export default createStore({
state,
mutations
})
Mutations业务层数据提交
/**
* Mutations业务层数据提交
*/
import storage from './../utils/storage'
export default {
saveUserInfo(state, userInfo) {
state.userInfo = userInfo;
storage.setItem('userInfo', userInfo)
},
saveMenuList(state, menuList) {
state.menuList = menuList;
storage.setItem('menuList', menuList)
},
saveActionList(state, actionList) {
state.actionList = actionList;
storage.setItem('actionList', actionList)
},
saveNoticeCount(state, noticeCount) {
state.noticeCount = noticeCount;
storage.setItem('noticeCount', noticeCount)
}
}
main.js
app.directive('has', {
beforeMount: function (el, binding) {
let actionList = storage.getItem('actionList');
let value = binding.value;
let hasPermission = actionList.includes(value)
if (!hasPermission) {
el.style = 'display:none';
setTimeout(() => {
el.parentNode.removeChild(el);
}, 0)
}
}
})
404.vue
<template>
<div class="exception">
<img src="@/assets/images/404.jpeg" alt="" />
<el-button @click="goHome" class="btn-home">回首页</el-button>
</div>
</template>
<script>
export default {
name: "404",
methods: {
goHome() {
this.$router.push("/");
},
},
};
</script>
<style lang="scss">
.exception {
position: relative;
img {
width: 100%;
height: 100vh;
}
.btn-home {
position: fixed;
bottom: 100px;
left: 50%;
margin-left: -34px;
}
}
</style>
router/index.js
import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '@/components/Home.vue'
import storage from './../utils/storage'
import API from './../api'
import utils from './../utils/utils'
const routes = [
{
name: 'home',
path: '/',
meta: {
title: '首页'
},
component: Home,
redirect: '/welcome',
children: [
{
name: 'welcome',
path: '/welcome',
meta: {
title: '欢迎体验Vue3全栈课程'
},
component: () => import('@/views/Welcome.vue')
}
]
},
{
name: 'login',
path: '/login',
meta: {
title: '登录'
},
component: () => import('@/views/Login.vue')
},
{
name: '404',
path: '/404',
meta: {
title: '页面不存在'
},
component: () => import('@/views/404.vue')
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
async function loadAsyncRoutes() {
let userInfo = storage.getItem('userInfo') || {}
if (userInfo.token) {
try {
const { menuList } = await API.getPermissionList()
let routes = utils.generateRoute(menuList)
routes.map(route => {
let url = `./../views/${route.component}.vue`
route.component = () => import(url);
router.addRoute("home", route);
})
} catch (error) {
}
}
}
await loadAsyncRoutes();
// 判断当前地址是否可以访问
/*
function checkPermission(path) {
let hasPermission = router.getRoutes().filter(route => route.path == path).length;
if (hasPermission) {
return true;
} else {
return false;
}
}
*/
// 导航守卫
router.beforeEach((to, from, next) => {
if (router.hasRoute(to.name)) {
document.title = to.meta.title;
next()
} else {
next('/404')
}
})
export default router