user.vue
<template>
<div class="user-manage">
<div class="query-form">
<el-form ref="form" :inline="true" :model="user">
<el-form-item label="用户ID" prop="userId">
<el-input v-model="user.userId" placeholder="请输入用户ID" />
</el-form-item>
<el-form-item label="用户名称" prop="userName">
<el-input v-model="user.userName" placeholder="请输入用户名称" />
</el-form-item>
<el-form-item label="状态" prop="state">
<el-select v-model="user.state">
<el-option :value="0" label="所有"></el-option>
<el-option :value="1" label="在职"></el-option>
<el-option :value="2" label="离职"></el-option>
<el-option :value="3" label="试用期"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery">查询</el-button>
<el-button @click="handleReset('form')">重置</el-button>
</el-form-item>
</el-form>
</div>
<div class="base-table">
<div class="action">
<el-button type="primary" @click="handleCreate" v-has="'user-create'"
>新增</el-button
>
<el-button
type="danger"
@click="handlePatchDel"
v-has="'user-patch-delete'"
>批量删除</el-button
>
</div>
<el-table :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column
v-for="item in columns"
:key="item.prop"
:prop="item.prop"
:label="item.label"
:width="item.width"
:formatter="item.formatter"
>
</el-table-column>
<el-table-column label="操作" width="150">
<template #default="scope">
<el-button
@click="handleEdit(scope.row)"
size="mini"
v-has="'user-edit'"
>编辑</el-button
>
<el-button
type="danger"
size="mini"
@click="handleDel(scope.row)"
v-has="'user-delete'"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<el-pagination
class="pagination"
background
layout="prev, pager, next"
:total="pager.total"
:page-size="pager.pageSize"
@current-change="handleCurrentChange"
/>
</div>
<el-dialog title="用户新增" v-model="showModal">
<el-form
ref="dialogForm"
:model="userForm"
label-width="100px"
:rules="rules"
>
<el-form-item label="用户名" prop="userName">
<el-input
v-model="userForm.userName"
:disabled="action == 'edit'"
placeholder="请输入用户名称"
/>
</el-form-item>
<el-form-item label="邮箱" prop="userEmail">
<el-input
v-model="userForm.userEmail"
:disabled="action == 'edit'"
placeholder="请输入用户邮箱"
>
<template #append>@imooc.com</template>
</el-input>
</el-form-item>
<el-form-item label="手机号" prop="mobile">
<el-input v-model="userForm.mobile" placeholder="请输入手机号" />
</el-form-item>
<el-form-item label="岗位" prop="job">
<el-input v-model="userForm.job" placeholder="请输入岗位" />
</el-form-item>
<el-form-item label="状态" prop="state">
<el-select v-model="userForm.state">
<el-option :value="1" label="在职"></el-option>
<el-option :value="2" label="离职"></el-option>
<el-option :value="3" label="试用期"></el-option>
</el-select>
</el-form-item>
<el-form-item label="系统角色" prop="roleList">
<el-select
v-model="userForm.roleList"
placeholder="请选择用户系统角色"
multiple
style="width: 100%"
>
<el-option
v-for="role in roleList"
:key="role._id"
:label="role.roleName"
:value="role._id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="部门" prop="deptId">
<el-cascader
v-model="userForm.deptId"
placeholder="请选择所属部门"
:options="deptList"
:props="{ checkStrictly: true, value: '_id', label: 'deptName' }"
clearable
style="width: 100%"
></el-cascader>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="handleSubmit">确 定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script>
import { getCurrentInstance, onMounted, reactive, ref, toRaw } from "vue";
import utils from "./../utils/utils";
export default {
name: "user",
setup() {
// 获取Composition API 上下文对象
const { ctx } = getCurrentInstance();
// 初始化用户表单对象
const user = reactive({
state: 1,
});
// 初始化用户列表数据
const userList = ref([]);
// 初始化分页对象
const pager = reactive({
pageNum: 1,
pageSize: 10,
});
// 选中用户列表对象
const checkedUserIds = ref([]);
// 弹框显示对象
const showModal = ref(false);
// 新增用户Form对象
const userForm = reactive({
state: 3,
});
// 所有角色列表
const roleList = ref([]);
// 所有部门列表
const deptList = ref([]);
// 定义用户操作行为
const action = ref("add");
// 定义表单校验规则
const rules = reactive({
userName: [
{
required: true,
message: "请输入用户名称",
trigger: "blur",
},
],
userEmail: [
{ required: true, message: "请输入用户邮箱", trigger: "blur" },
],
mobile: [
{
pattern: /1[3-9]\d{9}/,
message: "请输入正确的手机号格式",
trigger: "blur",
},
],
deptId: [
{
required: true,
message: "请输入用户邮箱",
trigger: "blur",
},
],
});
// 定义动态表格-格式
const columns = reactive([
{
label: "用户ID",
prop: "userId",
},
{
label: "用户名",
prop: "userName",
},
{
label: "用户邮箱",
prop: "userEmail",
},
{
label: "用户角色",
prop: "role",
formatter(row, column, value) {
return {
0: "管理员",
1: "普通用户",
}[value];
},
},
{
label: "用户状态",
prop: "state",
formatter(row, column, value) {
return {
1: "在职",
2: "离职",
3: "试用期",
}[value];
},
},
{
label: "注册时间",
prop: "createTime",
width: 180,
formatter: (row, column, value) => {
return utils.formateDate(new Date(value));
},
},
{
label: "最后登录时间",
prop: "lastLoginTime",
width: 180,
formatter: (row, column, value) => {
return utils.formateDate(new Date(value));
},
},
]);
// 初始化接口调用
onMounted(() => {
getUserList();
getDeptList();
getRoleAllList();
});
// 获取用户列表
const getUserList = async () => {
let params = { ...user, ...pager };
try {
const { list, page } = await ctx.$api.getUserList(params);
userList.value = list;
pager.total = page.total;
} catch (error) {}
};
// 查询事件,获取用户列表
const handleQuery = () => {
getUserList();
};
// 重置查询表单
const handleReset = (form) => {
ctx.$refs[form].resetFields();
};
// 分页事件处理
const handleCurrentChange = (current) => {
pager.pageNum = current;
getUserList();
};
// 用户单个删除
const handleDel = async (row) => {
await ctx.$api.userDel({
userIds: [row.userId], //可单个删除,也可批量删除
});
ctx.$message.success("删除成功");
getUserList();
};
// 批量删除
const handlePatchDel = async () => {
if (checkedUserIds.value.length == 0) {
ctx.$message.error("请选择要删除的用户");
return;
}
const res = await ctx.$api.userDel({
userIds: checkedUserIds.value, //可单个删除,也可批量删除
});
if (res.nModified > 0) {
ctx.$message.success("删除成功");
getUserList();
} else {
ctx.$message.success("修改失败");
}
};
// 表格多选
const handleSelectionChange = (list) => {
let arr = [];
list.map((item) => {
arr.push(item.userId);
});
checkedUserIds.value = arr;
};
// 用户新增
const handleCreate = () => {
action.value = "add";
showModal.value = true;
};
const getDeptList = async () => {
let list = await ctx.$api.getDeptList();
deptList.value = list;
};
// 角色列表查询
const getRoleAllList = async () => {
let list = await ctx.$api.getRoleAllList();
roleList.value = list;
};
// 用户弹窗关闭
const handleClose = () => {
showModal.value = false;
handleReset("dialogForm");
};
// 用户提交
const handleSubmit = () => {
ctx.$refs.dialogForm.validate(async (valid) => {
if (valid) {
let params = toRaw(userForm);
params.userEmail += "@imooc.com";
params.action = action.value;
let res = await ctx.$api.userSubmit(params);
showModal.value = false;
ctx.$message.success("用户创建成功");
handleReset("dialogForm");
getUserList();
}
});
};
// 用户编辑
const handleEdit = (row) => {
action.value = "edit";
showModal.value = true;
ctx.$nextTick(() => {
Object.assign(userForm, row);
});
};
return {
user,
userList,
columns,
pager,
checkedUserIds,
showModal,
userForm,
rules,
roleList,
deptList,
action,
getUserList,
handleQuery,
handleReset,
handleCurrentChange,
handleDel,
handlePatchDel,
handleSelectionChange,
handleCreate,
getRoleAllList,
getDeptList,
handleClose,
handleSubmit,
handleEdit,
};
},
};
</script>
<style lang="scss">
</style>
users.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)
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);
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.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
utils.js
/**
* 工具函数封装
*/
export default {
formateDate(date, rule) {
let fmt = rule || 'yyyy-MM-dd hh:mm:ss'
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, date.getFullYear())
}
const o = {
// 'y+': date.getFullYear(),
'M+': date.getMonth() + 1,
'd+': date.getDate(),
'h+': date.getHours(),
'm+': date.getMinutes(),
's+': date.getSeconds()
}
for (let k in o) {
if (new RegExp(`(${k})`).test(fmt)) {
const val = o[k] + '';
fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? val : ('00' + val).substr(val.length));
}
}
return fmt;
},
generateRoute(menuList) {
let routes = []
const deepList = (list) => {
while (list.length) {
let item = list.pop()
if (item.action) {
routes.push({
name: item.component,
path: item.path,
meta: {
title: item.menuName
},
component: item.component
})
}
if (item.children && !item.action) {
deepList(item.children)
}
}
}
deepList(menuList)
return routes;
}
}