11.用户管理
1.CRUD后台
com.atguigu.auth.controller.SysUserController
@Api(tags = "用户管理接口")
@RestController
@RequestMapping("/admin/system/sysUser")
public class SysUserController {
@Autowired
private SysUserService sysUserService;
/**
* 添加用户
*
* @param sysUser
* @return
*/
@ApiOperation("添加用户")
@PostMapping("/save")
public Result save(@RequestBody SysUser sysUser) {
// 密码要进行加密处理, MD5加密
String pwdMD5 = MD5.encrypt(sysUser.getPassword());
sysUser.setPassword(pwdMD5);
if (sysUserService.save(sysUser)) {
return Result.ok();
} else {
return Result.fail();
}
}
/**
* 删除用户
*
* @param id
* @return
*/
@ApiOperation("删除用户")
@DeleteMapping("/remove/{id}")
public Result remove(@PathVariable long id) {
if (sysUserService.removeById(id)) {
return Result.ok();
} else {
return Result.fail();
}
}
/**
* 批量删除用户
*
* @param ids
* @return
*/
@ApiOperation("批量删除用户")
@DeleteMapping("/removeBatch/{ids}")
public Result removeBatch(@PathVariable List<Long> ids) {
if (sysUserService.removeByIds(ids)) {
return Result.ok();
} else {
return Result.fail();
}
}
/**
* 更新用户
*
* @param sysUser
* @return
*/
@ApiOperation("更新用户")
@PostMapping("/update")
public Result update(@RequestBody SysUser sysUser) {
if (sysUserService.updateById(sysUser)) {
return Result.ok();
} else {
return Result.fail();
}
}
/**
* 用户状态更新(1:正常 0:停用)
*
* @param id
* @param status
* @return
*/
@ApiOperation("用户状态更新")
@GetMapping("/updateStatus/{id}/{status}")
public Result updateStatus(@PathVariable Long id, @PathVariable Integer status) {
if (sysUserService.updateStatus(id, status)) {
return Result.ok();
} else {
return Result.fail();
}
}
/**
* 获取用户
*
* @param id
* @return
*/
@ApiOperation("获取用户")
@GetMapping("/get/{id}")
public Result get(@PathVariable long id) {
return Result.ok(sysUserService.getById(id));
}
/**
* 用户条件分页查询
*
* @param pageNum 当前页码
* @param pageSize 页记录数
* @param sysUserQueryVo
* @return
*/
@ApiOperation("用户条件分页查询")
@GetMapping("/{pageNum}/{pageSize}")
public Result page(@PathVariable Integer pageNum, @PathVariable Integer pageSize, SysUserQueryVo sysUserQueryVo) {
Page<SysUser> sysUserPage = new Page<>(pageNum, pageSize);
LambdaQueryWrapper<SysUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//获取条件
String username = sysUserQueryVo.getKeyword();
String createTimeBegin = sysUserQueryVo.getCreateTimeBegin();
String createTimeEnd = sysUserQueryVo.getCreateTimeEnd();
//模糊查询用户名
if (StringUtils.isNoneBlank(username)) {
lambdaQueryWrapper.and(
wrapper ->
wrapper.like(SysUser::getUsername, keyword).or().like(SysUser::getName, keyword)
);
}
//模糊查询创建开始时间
if (StringUtils.isNoneBlank(createTimeBegin)) {
lambdaQueryWrapper.ge(SysUser::getCreateTime, createTimeBegin);
}
//模糊查询创建结束时间
if (StringUtils.isNoneBlank(createTimeEnd)) {
lambdaQueryWrapper.le(SysUser::getCreateTime, createTimeEnd);
}
sysUserService.page(sysUserPage, lambdaQueryWrapper);
return Result.ok(sysUserPage);
}
}
用户状态更新
@Slf4j
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
/**
* 更新状态
*
* @param id
* @param status
* @return
*/
@Transactional
@Override
public boolean updateStatus(Long id, Integer status) {
//1.根据用户id查询用户对象
SysUser sysUser = baseMapper.selectById(id);
//2.设置修改状态
if (status == 0 || status == 1) {
sysUser.setStatus(status);
} else {
log.info("数值不合法");
}
//3.调用方法进行修改
return baseMapper.updateById(sysUser) == 1;
}
}
2.整合前端
编写路由
{
path: '/system',
name: 'system',
component: Layout,
meta: { title: '系统管理', icon: 'system', noCache: false, link: null },
hidden: false,
redirect: '/user',
alwaysShow: true,
children: [
{
path: 'user',
name: 'user',
component: () => import('@/views/system/user/index'),
meta: { title: '用户管理', icon: 'user', noCache: false, link: null }
}
]
}
编写用户管理api请求函数
import request from '@/utils/request'
const api_name = "/admin/system/sysUser"
// 新增用户
export function save(data) {
return request({
url: `${api_name}`,
method: 'post',
data: data
})
}
// 删除用户
export function remove(ids) {
return request({
url: `${api_name}/${ids}`,
method: 'delete'
})
}
// 修改用户
export function update(data) {
return request({
url: `${api_name}`,
method: 'put',
data: data
})
}
// 用户状态修改
export function updateStatus(id, status) {
return request({
url: `${api_name}/updateStatus/${id}/${status}`,
method: 'put',
})
}
// 查询用户详细
export function get(id) {
return request({
url: `${api_name}/${id}`,
method: 'get'
})
}
// 查询用户列表
export function page(pageNum, pageSize, query) {
return request({
url: `${api_name}/${pageNum}/${pageSize}`,
method: 'get',
params: query
})
}
页面展示
<template>
<div class="app-container">
<!-- 查询条件 -->
<el-form ref="queryForm" :model="queryParams" size="small" :inline="true">
<el-form-item label="关键字" prop="keyword">
<el-input
v-model="queryParams.keyword"
placeholder="请输入用户名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker
v-model="createTimes"
type="datetimerange"
:picker-options="pickerOptions"
value-format="yyyy-MM-dd HH:mm:ss"
range-separator="至"
start-placeholder="开始时间"
end-placeholder="结束时间"
style="width: 360px"
/>
</el-form-item>
<el-form-item>
<el-button
type="primary"
icon="el-icon-search"
size="mini"
@click="handleQuery"
>搜索
</el-button>
<el-button
icon="el-icon-refresh"
size="mini"
@click="resetQuery"
>重置
</el-button>
</el-form-item>
</el-form>
<!-- CRUD -->
<el-row :gutter="10" class="mb8" style="margin-bottom: 10px">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
>新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
>修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
>删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
>导出
</el-button>
</el-col>
</el-row>
<!-- 用户列表 -->
<el-table
v-loading="loading"
:data="userList"
border
header-cell-style="background-color:#EEE;color:#444;height:41px;"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="序号" width="70" align="center">
<template slot-scope="scope">
{{
(queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1
}}
</template>
</el-table-column>
<el-table-column
key="username"
label="用户名称"
align="center"
prop="username"
:show-overflow-tooltip="true"
/>
<el-table-column
key="name"
label="姓名"
align="center"
prop="name"
:show-overflow-tooltip="true"
/>
<el-table-column
key="phone"
label="手机号码"
align="center"
prop="phone"
:show-overflow-tooltip="true"
/>
<el-table-column
key="postName"
label="岗位"
align="center"
prop="postName"
:show-overflow-tooltip="true"
/>
<el-table-column
key="deptName"
label="部门"
align="center"
prop="deptName"
:show-overflow-tooltip="true"
/>
<el-table-column label="所属角色" width="130">
<template slot-scope="scope">
<span
v-for="item in scope.row.roleList"
:key="item.id"
style="margin-right: 10px"
>{{ item.roleName }}</span>
</template>
</el-table-column>
<el-table-column key="status" label="状态" align="center">
<template slot-scope="scope">
<el-switch
v-model="scope.row.status === 1"
@change="handleStatusChange(scope.row)"
/>
</template>
</el-table-column>
<el-table-column
label="创建时间"
align="center"
prop="createTime"
width="160"
sortable
/>
<el-table-column
label="操作"
align="center"
width="200"
class-name="small-padding fixed-width"
>
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
>修改
</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
>删除
</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-circle-check"
@click="handleAuthRole(scope.row)"
>分配角色
</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改用户配置对话框 -->
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-row>
<el-col :span="12">
<el-form-item label="用户名称" prop="username">
<el-input
v-model="form.username"
placeholder="请输入用户名称"
maxlength="30"
:disabled="form.id != undefined"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
v-if="form.id == undefined"
label="用户密码"
prop="password"
>
<el-input
v-model="form.password"
placeholder="请输入用户密码"
type="password"
maxlength="20"
show-password
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="姓名" prop="name">
<el-input
v-model="form.name"
placeholder="请输入用户姓名"
maxlength="30"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="手机号码" prop="phone">
<el-input
v-model="form.phone"
placeholder="请输入手机号码"
maxlength="11"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="描述">
<el-input
v-model="form.description"
type="textarea"
placeholder="请输入内容"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
<!-- 分配角色 -->
<el-dialog
:title="title"
:visible.sync="authRoleOpen"
width="600px"
append-to-body
>
<el-form ref="form" :model="authRoleForm" label-width="80px">
<el-form-item label="用户名称" prop="username">
<el-input v-model="authRoleForm.username" disabled />
</el-form-item>
<el-form-item label="角色列表">
<el-checkbox
v-model="checkAll"
:indeterminate="isIndeterminate"
@change="handleCheckAllChange"
>全选</el-checkbox>
<div style="margin: 15px 0" />
<el-checkbox-group
v-model="userRoleIds"
@change="handleUserRoleIdsChange"
>
<el-checkbox
v-for="role in allRoles"
:key="role.id"
:label="role.id"
>{{ role.roleName }}</el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="authRoleSubmitForm">确 定</el-button>
<el-button @click="authRoleCancel">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
page,
get,
remove,
update,
save,
updateStatus
} from '@/api/system/user'
import { toAssign, doAssign } from '@/api/system/role'
export default {
name: 'User',
data() {
return {
// 查询参数
queryParams: {
// 当前页码
pageNum: 1,
// 每页记录数
pageSize: 10,
// 关键字
keyword: undefined,
createTimeBegin: undefined,
createTimeEnd: undefined
},
// 创建时间
createTimes: [],
// 时间日期选择器快捷选项
pickerOptions: {
shortcuts: [{
text: '最近一周',
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
picker.$emit('pick', [start, end])
}
}, {
text: '最近一个月',
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
picker.$emit('pick', [start, end])
}
}, {
text: '最近三个月',
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
picker.$emit('pick', [start, end])
}
}, {
text: '最近半年',
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 183)
picker.$emit('pick', [start, end])
}
}, {
text: '最近一年',
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 365)
picker.$emit('pick', [start, end])
}
}
]
},
// 数据是否正在加载
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 总条数
total: 0,
// 用户表格数据
userList: null,
// 弹出层标题
title: '',
// 是否显示弹出层
open: false,
// 表单参数
form: {},
authRoleOpen: false,
authRoleForm: {},
allRoles: [], // 所有角色列表
userRoleIds: [], // 用户的角色ID的列表
isIndeterminate: false, // 是否是不确定的
checkAll: false, // 是否全选
// 表单校验
rules: {
username: [
{ required: true, message: '用户名称不能为空', trigger: 'blur' },
{
min: 2,
max: 20,
message: '用户名称长度必须介于 2 和 20 之间',
trigger: 'blur'
}
],
name: [
{ required: true, message: '用户姓名不能为空', trigger: 'blur' }
],
password: [
{ required: true, message: '用户密码不能为空', trigger: 'blur' },
{
min: 5,
max: 20,
message: '用户密码长度必须介于 5 和 20 之间',
trigger: 'blur'
}
],
phone: [
{ required: true, message: '手机号码不能为空', trigger: 'blur' },
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: '请输入正确的手机号码',
trigger: 'change'
}
]
}
}
},
created() {
this.getList()
},
methods: {
/** 查询用户列表 */
getList() {
this.loading = true
if (this.createTimes && this.createTimes.length === 2) {
this.queryParams.createTimeBegin = this.createTimes[0]
this.queryParams.createTimeEnd = this.createTimes[1]
} else {
this.queryParams.createTimeBegin = undefined
this.queryParams.createTimeEnd = undefined
}
page(
this.queryParams.pageNum,
this.queryParams.pageSize,
this.queryParams
).then((response) => {
console.log('用户列表:', response)
this.userList = response.data.records
this.total = response.data.total
this.loading = false
})
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.createTimes = []
this.$refs['queryForm'].resetFields()
this.handleQuery()
},
// 表单重置
reset() {
this.form = {
id: undefined,
username: undefined,
name: undefined,
password: undefined,
phone: undefined,
description: undefined
}
// this.$refs["form"].resetFields();
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
this.open = true
this.title = '添加用户'
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
const id = row.id || this.ids
get(id).then((response) => {
this.form = response.data
this.open = true
this.title = '修改用户'
})
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids
this.$confirm('您确定删除用户编号为[' + ids + ']的用户吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
remove(ids)
.then((res) => {
this.$message.success('删除成功')
this.getList()
})
.catch((err) => {
this.$message.error('删除失败')
})
})
.catch(() => {
this.$message.info('已取消删除')
})
},
/** 导出按钮操作 */
handleExport() {},
/** 导入按钮操作 */
handleImport() {},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map((item) => item.id)
this.single = selection.length != 1
this.multiple = !selection.length
},
/** 提交按钮 */
submitForm() {
this.$refs['form'].validate((valid) => {
if (valid) {
if (this.form.id != undefined) {
update(this.form).then((response) => {
this.$message.success('修改成功')
this.open = false
this.getList()
})
} else {
save(this.form).then((response) => {
this.$message.success('新增成功')
this.open = false
this.getList()
})
}
}
})
},
/** 取消按钮*/
cancel() {
this.open = false
this.reset()
this.$refs['form'].resetFields()
},
/** 用户状态修改 */
handleStatusChange(row) {
const text = row.status === 0 ? '启用' : '停用'
this.$confirm(
'您确定要' + text + "用户'" + row.username + "'吗?",
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
)
.then(() => {
row.status = row.status === 1 ? 0 : 1
updateStatus(row.id, row.status)
.then((res) => {
this.$message({
type: 'success',
message: text + '成功!'
})
this.getList()
})
.catch((err) => {
row.status = row.status === 0 ? 1 : 0
this.$message({
type: 'error',
message: text + '失败!'
})
})
})
.catch(() => {
this.$message.info('已取消修改')
})
},
/** 分配角色 */
handleAuthRole(row) {
this.authRoleForm = row
toAssign(row.id).then((res) => {
this.title = '分配角色'
this.authRoleOpen = true
this.allRoles = res.data.allRoleList
this.userRoleIds = res.data.assignRoleList.map((item) => item.id)
this.handleUserRoleIdsChange(this.userRoleIds)
})
},
/** 全选勾选状态发生改变的监听 */
handleCheckAllChange(val) {
// val 当前勾选状态true/false
// 如果当前全选, userRoleIds就是所有角色id的数组, 否则是空数组
this.userRoleIds = val ? this.allRoles.map((item) => item.id) : []
// 如果当前不是全选也不全不选时, 指定为false
this.isIndeterminate = false
},
/** 角色列表选中项发生改变的监听 */
handleUserRoleIdsChange(value) {
const checkedCount = value.length
this.checkAll = checkedCount === this.allRoles.length
this.isIndeterminate =
checkedCount > 0 && checkedCount < this.allRoles.length
},
/** 提交分配角色按钮 */
authRoleSubmitForm() {
const assginRoleVo = {
userId: this.authRoleForm.id,
roleIdList: this.userRoleIds
}
doAssign(assginRoleVo).then((res) => {
this.$message.success(res.message || '分配角色成功')
this.authRoleOpen = false
this.getList()
})
},
/** 取消 */
authRoleCancel() {
this.authRoleOpen = false
}
}
}
</script>
<style scoped lang="scss">
//main-container全局样式
.app-container {
padding: 20px;
}
</style>
12.角色管理
1.CRUD后台
@Api(tags = "角色管理接口")
@RestController
@RequestMapping("/admin/system/sysRole")
public class SysRoleController {
@Autowired
private SysRoleService sysRoleService;
/**
* 添加角色
*
* @param sysRole
* @return
*/
@ApiOperation("添加角色")
@PostMapping("")
public Result save(@RequestBody SysRole sysRole) {
if (sysRoleService.save(sysRole)) {
return Result.ok();
} else {
return Result.fail();
}
}
/**
* (批量)删除角色
*
* @param ids
* @return
*/
@ApiOperation("(批量)删除角色")
@DeleteMapping("/{ids}")
public Result remove(@PathVariable List<Long> ids) {
if (sysRoleService.removeByIds(ids)) {
return Result.ok();
} else {
return Result.fail();
}
}
/**
* 更新角色
*
* @param sysRole
* @return
*/
@ApiOperation("更新角色")
@PutMapping("")
public Result update(@RequestBody SysRole sysRole) {
if (sysRoleService.updateById(sysRole)) {
return Result.ok();
} else {
return Result.fail();
}
}
/**
* 获取用户
*
* @param id
* @return
*/
@ApiOperation("获取用户")
@GetMapping("/{id}")
public Result get(@PathVariable Long id) {
return Result.ok(sysRoleService.getById(id));
}
/**
* 角色条件分页查询
*
* @param pageNum
* @param pageSize
* @param sysRoleQueryVo
* @return
*/
@ApiOperation("角色条件分页查询")
@GetMapping("/{pageNum}/{pageSize}")
public Result page(@PathVariable Integer pageNum, @PathVariable Integer pageSize, SysRoleQueryVo sysRoleQueryVo) {
Page<SysRole> sysRolePage = new Page<>(pageNum, pageSize);
LambdaQueryWrapper<SysRole> sysRoleLambdaQueryWrapper = new LambdaQueryWrapper<>();
if (StringUtils.isNoneBlank(sysRoleQueryVo.getRoleName())) {
sysRoleLambdaQueryWrapper.like(SysRole::getRoleName, sysRoleQueryVo.getRoleName());
}
sysRoleService.page(sysRolePage, sysRoleLambdaQueryWrapper);
return Result.ok(sysRolePage);
}
/**
* 获取所有角色列表以及当前用户所属的所有角色
*
* @param id
* @return
*/
@ApiOperation("根据用户id获取当前用户所属的角色")
@GetMapping("/toAssign/{id}")
public Result toAssign(@PathVariable Long id) {
Map<String, Object> map = sysRoleService.findRoleDataById(id);
return Result.ok(map);
}
@ApiOperation("给用户分配角色")
@PostMapping("/doAssign")
public Result doAssign(@RequestBody AssginRoleVo assginRoleVo) {
sysRoleService.doAssign(assginRoleVo);
return Result.ok();
}
}
@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {
@Autowired
private SysUserRoleService sysUserRoleService;
/**
* 查询所有角色 和 当前用户所属角色
*
* @param userId
* @return
*/
@Override
public Map<String, Object> findRoleDataById(Long userId) {
//1.查询所有角色,返回list集合
List<SysRole> allRoleList = baseMapper.selectList(null);
//2.根据用户id查询 角色用户关系,查询用户id对应的所有角色id
LambdaQueryWrapper<SysUserRole> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(SysUserRole::getUserId, userId);
List<SysUserRole> existUserRoleList = sysUserRoleService.list(lambdaQueryWrapper);
// 3.从查询到的用户角色集合获取所有角色id
List<Long> roleIdList = new ArrayList<>();
for (SysUserRole sysUserRole : existUserRoleList) {
Long roleId = sysUserRole.getRoleId();
roleIdList.add(roleId);
}
//3 根据查询所有角色id,找到对应角色信息
//根据角色id到所有的角色的list集合进行比较
List<SysRole> assignRoleList = new ArrayList<>();
for(SysRole sysRole : allRoleList) {
//比较
if(roleIdList.contains(sysRole.getId())) {
assignRoleList.add(sysRole);
}
}
Map<String, Object> roleMap = new HashMap<>();
roleMap.put("allRoleList", allRoleList);
roleMap.put("assignRoleList", assignRoleList);
return roleMap;
}
/**
* 为用户分配角色
*
* @param assginRoleVo
* @return
*/
@Transactional
@Override
public void doAssign(AssginRoleVo assginRoleVo) {
//1.删除用户之前分配的所有角色数据
LambdaQueryWrapper<SysUserRole> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(SysUserRole::getUserId, assginRoleVo.getUserId());
sysUserRoleService.remove(lambdaQueryWrapper);
//2.重新为用户分配角色
List<Long> roleIdList = assginRoleVo.getRoleIdList();
for(Long roleId:roleIdList) {
SysUserRole sysUserRole = new SysUserRole();
sysUserRole.setUserId(assginRoleVo.getUserId());
sysUserRole.setRoleId(roleId);
sysUserRoleService.save(sysUserRole);
}
}
}
2.整合前端
编写路由
{
path: 'role',
name: 'role',
component: () => import('@/views/system/role/index'),
meta: { title: '角色管理', icon: 'peoples', noCache: false, link: null }
},
编写api请求函数
import request from '@/utils/request'
const api_name = "/admin/system/sysRole"
// 新增角色
export function save(data) {
return request({
url: `${api_name}`,
method: 'post',
data: data
})
}
// 删除角色
export function remove(ids) {
return request({
url: `${api_name}/${ids}`,
method: 'delete'
})
}
// 修改角色
export function update(data) {
return request({
url: `${api_name}`,
method: 'put',
data: data
})
}
// 查询角色详细
export function get(id) {
return request({
url: `${api_name}/${id}`,
method: 'get'
})
}
// 查询角色列表
export function page(pageNum, pageSize, query) {
return request({
url: `${api_name}/${pageNum}/${pageSize}`,
method: 'get',
params: query
})
}
// 获取角色列表以及用户所属角色
export function toAssign(id) {
return request({
url: `${api_name}/toAssign/${id}`,
method: 'get'
})
}
// 给用户分配角色
export function doAssign(data) {
return request({
url: `${api_name}/doAssign`,
method: 'post',
data: data
})
}
页面展示
<template>
<div class="app-container">
<!-- 查询条件 -->
<el-form ref="queryForm" :model="queryParams" size="small" :inline="true">
<el-form-item label="关键字" prop="roleName">
<el-input
v-model="queryParams.roleName"
placeholder="请输入角色名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button
type="primary"
icon="el-icon-search"
size="mini"
@click="handleQuery"
>搜索
</el-button>
<el-button
icon="el-icon-refresh"
size="mini"
@click="resetQuery"
>重置
</el-button>
</el-form-item>
</el-form>
<!-- CRUD -->
<el-row :gutter="10" class="mb8" style="margin-bottom: 10px">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
>新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
>修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
>删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
>导出
</el-button>
</el-col>
</el-row>
<el-row :gutter="15">
<!-- 角色列表 -->
<el-col :xs="24" :sm="24" :md="16" :lg="16" :xl="17">
<el-card class="box-card" shadow="never">
<div slot="header" class="clearfix">
<span class="role-span">角色列表</span>
</div>
<el-table
v-loading="loading"
:data="roleList"
highlight-current-row
@selection-change="handleSelectionChange"
@current-change="handleCurrentChange"
>
<el-table-column type="selection" width="50" align="center"/>
<el-table-column label="序号" width="70" align="center">
<template slot-scope="scope">
{{
(queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1
}}
</template>
</el-table-column>
<el-table-column
key="roleName"
label="角色名称"
align="center"
prop="roleName"
:show-overflow-tooltip="true"
/>
<el-table-column
key="roleCode"
label="角色编码"
align="center"
prop="roleCode"
:show-overflow-tooltip="true"
/>
<el-table-column
key="description"
label="描述"
align="center"
prop="description"
:show-overflow-tooltip="true"
/>
<el-table-column
label="创建时间"
align="center"
prop="createTime"
width="160"
sortable
/>
<el-table-column
label="操作"
align="center"
width="160"
class-name="small-padding fixed-width"
>
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
>修改
</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
>删除
</el-button>
</template>
</el-table-column>
</el-table>
<!--分页-->
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
</el-card>
</el-col>
<!-- 菜单授权 -->
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="7">
<el-card class="box-card" shadow="never">
<div slot="header" class="clearfix">
<el-tooltip class="item" effect="dark" content="选择指定角色分配菜单" placement="top">
<span class="role-span">菜单分配</span>
</el-tooltip>
<el-button
:disabled="!showButton"
:loading="menuLoading"
icon="el-icon-check"
size="mini"
style="float: right; padding: 6px 9px"
type="primary"
@click="saveMenu"
>保存
</el-button>
</div>
<el-tree
style="margin: 20px 0"
ref="tree"
:data="sysMenuList"
node-key="id"
show-checkbox
:default-expand-all="false"
:props="defaultProps"
/>
</el-card>
</el-col>
</el-row>
<!-- 添加或修改角色配置对话框 -->
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-row>
<el-col :span="12">
<el-form-item label="角色名称" prop="roleName">
<el-input
v-model="form.roleName"
placeholder="请输入角色名称"
maxlength="30"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="角色编码" prop="roleCode">
<el-input v-model="form.roleCode" placeholder="请输入角色编码"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="描述">
<el-input
v-model="form.description"
type="textarea"
placeholder="请输入内容"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { pageRole, getRole, removeRole, updateRole, saveRole } from '@/api/system/role'
import { toAssignMenu, doAssignMenu, findNodesMenu } from '@/api/system/menu'
export default {
name: 'Role',
data() {
return {
// 查询参数
queryParams: {
// 当前页码
pageNum: 1,
// 每页记录数
pageSize: 10,
// 关键字
roleName: undefined
},
// 数据是否正在加载
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 总条数
total: 0,
// 角色表格数据
roleList: null,
// 弹出层标题
title: '',
// 是否显示弹出层
open: false,
// 表单参数
form: {},
// 表单校验
rules: {
roleName: [
{ required: true, message: '角色名称不能为空', trigger: 'blur' }
],
roleCode: [
{ required: true, message: '角色编码不能为空', trigger: 'blur' }
]
},
//角色单行当前行的roleId
currentId:undefined,
//角色授权菜单按钮显示
showButton: false,
// 用来标识是否正在保存请求中的标识, 防止重复提交
menuLoading: false,
defaultProps: {
children: 'children',
label: 'name'
},
//所有menu
sysMenuList: []
}
},
created() {
this.getList()
},
methods: {
/** 查询角色列表 */
getList() {
this.loading = true
//获取角色列表
pageRole(
this.queryParams.pageNum,
this.queryParams.pageSize,
this.queryParams
).then((res) => {
this.roleList = res.data.records
this.total = res.data.total
this.loading = false
})
//获取菜单列表
findNodesMenu().then(res => {
this.sysMenuList = res.data
})
},
/** 搜索 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置 */
resetQuery() {
this.$refs['queryForm'].resetFields()
this.handleQuery()
},
/** 清空表单 */
reset() {
this.form = {
roleName: undefined,
roleCode: undefined,
description: undefined
}
// this.$refs["form"].resetFields();
},
/** 新增 */
handleAdd() {
this.reset()
this.title = '新增用户'
this.open = true
},
/** 修改 */
handleUpdate(row) {
const id = row.id || this.ids
getRole(id)
.then((res) => {
this.form = res.data
})
.catch((err) => {
})
this.title = '更新用户'
this.open = true
},
/** 删除 */
handleDelete(row) {
const ids = row.id || this.ids
this.$confirm('您确定删除角色编号[' + ids + ']的角色吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
removeRole(ids)
.then((res) => {
this.$message({ message: '删除成功', type: 'success' })
this.getList()
})
.catch((err) => {
this.$message.error('删除失败')
})
})
.catch(() => {
this.$message.info('已取消删除')
})
},
/** 导出 */
handleExport() {
},
/** 多选框选中数据 */
handleSelectionChange(selection) {
this.ids = selection.map((item) => item.id)
this.single = selection.length != 1
this.multiple = !selection.length
},
/** 提交 */
submitForm() {
this.$refs['form'].validate((valid) => {
if (valid) {
if (this.form.id != undefined) {
updateRole(this.form)
.then((res) => {
this.$message.success('修改成功')
this.open = false
this.getList()
})
.catch((err) => {
})
} else {
saveRole(this.form).then((res) => {
this.$message.success('新增成功')
this.open = false
this.getList()
})
}
}
})
},
/** 取消按钮*/
cancel() {
this.open = false
this.reset()
this.$refs['form'].resetFields()
},
/** 列表点击单行触发单选*/
handleCurrentChange(val) {
if (val) {
//保存当前id
this.currentId = val.id
// 清空菜单的选中
this.$refs.tree.setCheckedKeys([])
//获取当前角色分配的菜单
toAssignMenu(val.id).then(res => {
const menuListSelect = res.data
const checkMenuIds = this.getCheckedIds(menuListSelect)
this.$refs.tree.setCheckedKeys(checkMenuIds)
})
this.showButton = true
}
},
/**得到所有选中的id列表*/
getCheckedIds(auths, initArr = []) {
return auths.reduce((pre, item) => {
if (item.select && item.children.length === 0) {
pre.push(item.id)
} else if (item.children) {
this.getCheckedIds(item.children, initArr)
}
return pre
}, initArr)
},
/**保存菜单分配*/
saveMenu() {
this.menuLoading = true
//获取到当前子节点及父节点
const allCheckedNodes = this.$refs.tree.getCheckedNodes(false, true);
let menuIdList = allCheckedNodes.map(node => node.id);
let assginMenuVo = {
roleId: this.currentId,
menuIdList: menuIdList
}
doAssignMenu(assginMenuVo).then(res => {
this.handleCurrentChange()
this.menuLoading = false
this.$message.success('菜单分配保存成功')
}).catch(err => {
this.menuLoading = false
this.$message.error('菜单分配保存失败')
})
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss">
.role-span {
font-weight: bold;
color: #303133;
font-size: 15px;
}
</style>
13.菜单管理
1.CRUD后台
package com.atguigu.auth.controller;
import com.atguigu.auth.service.SysMenuService;
import com.atguigu.common.result.Result;
import com.atguigu.model.system.SysMenu;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* 菜单表 前端控制器
* </p>
*
* @author Yangmc
* @since 2024-01-23
*/
@Api(tags = "菜单管理接口")
@RestController
@RequestMapping("/admin/system/sysMenu")
public class SysMenuController {
@Autowired
private SysMenuService sysMenuService;
/**
* 添加菜单
*
* @param sysMenu
* @return
*/
@ApiOperation("添加菜单")
@PostMapping("")
public Result save(@RequestBody SysMenu sysMenu) {
if (sysMenuService.save(sysMenu)) {
return Result.ok();
} else {
return Result.fail();
}
}
/**
* (批量)删除菜单
*
* @param id
* @return
*/
@ApiOperation("删除菜单")
@DeleteMapping("/{id}")
public Result remove(@PathVariable Long id) {
if (sysMenuService.removeMenuById(id)) {
return Result.ok();
} else {
return Result.fail();
}
}
/**
* 更新菜单
*
* @param sysMenu
* @return
*/
@ApiOperation("更新菜单")
@PutMapping("")
public Result update(@RequestBody SysMenu sysMenu) {
if (sysMenuService.updateById(sysMenu)) {
return Result.ok();
} else {
return Result.fail();
}
}
/**
* 菜单状态更新(1:正常 0:停用)
*
* @param id
* @param status
* @return
*/
@ApiOperation("菜单状态更新")
@PutMapping("/updateStatus/{id}/{status}")
public Result updateStatus(@PathVariable long id, @PathVariable Integer status) {
if (sysMenuService.updateStatus(id, status)) {
return Result.ok();
} else {
return Result.fail();
}
}
/**
* 模糊查询菜单
*
* @return
*/
@ApiOperation("模糊查询菜单")
@PostMapping("/get")
public Result get(String name) {
List<SysMenu> list = new ArrayList<>();
LambdaQueryWrapper<SysMenu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.like(SysMenu::getName, name);
System.out.println(name);
if ("undefined".equals(name)) {
list = sysMenuService.list();
} else {
list = sysMenuService.list(lambdaQueryWrapper);
}
return Result.ok(list);
}
/**
* 根据id查询菜单详细
*
* @return
*/
@ApiOperation("根据id查询菜单详细")
@GetMapping("/get/{id}")
public Result getMenuById(@PathVariable long id){
SysMenu sysMenu = sysMenuService.getById(id);
return Result.ok(sysMenu);
}
/**
* 获取菜单列表
*
* @return
*/
@ApiOperation("获取菜单列表")
@GetMapping("/findNodes")
public Result findNodes() {
List<SysMenu> list = sysMenuService.findNodes();
return Result.ok(list);
}
}
删除菜单判断是否有子菜单service
@Override
public boolean removeMenuById(Long id) {
//判断当前菜单是否有下一层菜单
LambdaQueryWrapper<SysMenu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(SysMenu::getParentId, id);
Integer count = baseMapper.selectCount(lambdaQueryWrapper);
if (count > 0) {
throw new GuiguException(201, "当前菜单有子菜单,不能删除");
}
return baseMapper.deleteById(id) == 1;
}
获取菜单列表service
@Override
public List<SysMenu> findNodes() {
//1.查询所有菜单的数据
List<SysMenu> sysMenuList = baseMapper.selectList(null);
//2.构建树形结构
List<SysMenu> menuList = MenuHelper.buildTree(sysMenuList);
return menuList;
}
com.atguigu.auth.util.MenuHelper
/**
* @author Yangmc email:yangmc@tayo.com
* @create 2024-01-23 5:24
* @description 构建树形菜单
*/
public class MenuHelper {
/**
* 使用递归方法构建菜单
* @param sysMenuList
* @return
*/
public static List<SysMenu> buildTree(List<SysMenu> sysMenuList) {
//存放最终数据
List<SysMenu> trees = new ArrayList<>();
// 把所有的菜单数据进行遍历
for (SysMenu sysMenu : sysMenuList) {
// 递归入口parentId = 0
if (sysMenu.getParentId().longValue()==0) {
trees.add(getChildren(sysMenu,sysMenuList));
}
}
return trees;
}
/**
* 递归查找子节点
* @param sysMenu
* @param sysMenuList
* @return
*/
public static SysMenu getChildren(SysMenu sysMenu, List<SysMenu> sysMenuList) {
sysMenu.setChildren(new ArrayList<SysMenu>());
//遍历所有的菜单数据,判断id和parent_id的对应关系
for (SysMenu menu : sysMenuList) {
if (sysMenu.getId().longValue()==menu.getParentId().longValue()) {
if (sysMenu.getChildren()==null) {
sysMenu.setChildren(new ArrayList<>());
}
sysMenu.getChildren().add(getChildren(menu,sysMenuList));
}
}
return sysMenu;
}
}
2.整合前端
编写路由
{
path: 'menu',
name: 'menu',
component: () => import('@/views/system/menu/index'),
meta: { title: '菜单管理', icon: 'tree-table', noCache: false, link: null }
},
定义api请求函数
import request from '@/utils/request'
const api_name = "/admin/system/sysMenu"
// 新增菜单
export function save(data) {
return request({
url: `${api_name}`,
method: 'post',
data: data
})
}
// 删除菜单
export function remove(id) {
return request({
url: `${api_name}/${id}`,
method: 'delete'
})
}
// 修改菜单
export function update(data) {
return request({
url: `${api_name}`,
method: 'put',
data: data
})
}
// 菜单状态修改
export function updateStatus(id, status) {
return request({
url: `${api_name}/updateStatus/${id}/${status}`,
method: 'put',
})
}
// 模糊查询菜单
export function get(query) {
return request({
url: `${api_name}/get`,
method: 'post',
params: query
})
}
// 根据id查询菜单详细
export function getMenuById(id) {
return request({
url: `${api_name}/get/${id}`,
method: 'get'
})
}
// 查询菜单详细
export function findNodes() {
return request({
url: `${api_name}/findNodes`,
method: 'get'
})
}
页面展示
<template>
<div class="app-container">
<!-- 查询条件 -->
<el-form ref="queryForm" :model="queryParams" size="small" :inline="true">
<el-form-item label="菜单名称" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入菜单名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button
type="primary"
icon="el-icon-search"
size="mini"
@click="handleQuery"
>搜索
</el-button>
<el-button
icon="el-icon-refresh"
size="mini"
@click="resetQuery"
>重置
</el-button>
</el-form-item>
</el-form>
<!-- CRUD -->
<el-row :gutter="10" class="mb8" style="margin-bottom: 10px">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
>新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="el-icon-sort"
size="mini"
@click="toggleExpandAll"
>展开/折叠
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
>导出
</el-button>
</el-col>
</el-row>
<!-- 菜单列表 -->
<el-table
v-if="refreshTable"
v-loading="loading"
:data="menuList"
row-key="id"
:default-expand-all="isExpandAll"
:tree-props="{ children: 'children' }"
border
header-cell-style="background-color:#EEE;color:#444;height:41px"
>
>
<el-table-column
key="name"
label="菜单名称"
align="center"
prop="name"
:show-overflow-tooltip="true"
/>
<el-table-column prop="icon" label="图标" align="center" width="100">
<template slot-scope="scope">
<svg-icon :icon-class="scope.row.icon" />
<!-- <i :class="scope.row.icon" />-->
</template>
</el-table-column>
<el-table-column
key="perms"
label="权限标识"
align="center"
prop="perms"
:show-overflow-tooltip="true"
/>
<el-table-column
key="path"
label="路由地址"
align="center"
prop="path"
:show-overflow-tooltip="true"
/>
<el-table-column
key="component"
label="组件路径"
align="center"
prop="component"
:show-overflow-tooltip="true"
/>
<el-table-column
key="sortValue"
label="排序"
align="center"
prop="sortValue"
width="100%"
sortable
:show-overflow-tooltip="true"
/>
<el-table-column key="status" label="状态" align="center">
<template slot-scope="scope">
<el-switch
v-model="scope.row.status === 1"
@change="handleStatusChange(scope.row)"
/>
</template>
</el-table-column>
<el-table-column
label="创建时间"
align="center"
prop="createTime"
width="160"
sortable
/>
<el-table-column
label="操作"
align="center"
width="160"
class-name="small-padding fixed-width"
>
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
>修改
</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
>删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 添加或修改菜单对话框 -->
<el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-row>
<el-col :span="24">
<el-form-item label="上级菜单" prop="parentId">
<treeselect
v-model="form.parentId"
:options="menuOptions"
:normalizer="normalizer"
:show-count="true"
placeholder="请选择上级菜单"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="菜单类型" prop="type">
<el-radio-group v-model="form.type">
<el-radio :label="0">目录</el-radio>
<el-radio :label="1">菜单</el-radio>
<el-radio :label="2">按钮</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col v-if="form.type != '2'" :span="24">
<el-form-item label="菜单图标" prop="icon">
<el-popover
placement="bottom-start"
width="450"
trigger="click"
@show="$refs['iconSelect'].reset()"
>
<IconSelect ref="iconSelect" @selected="selected" />
<el-input
slot="reference"
v-model="form.icon"
style="width: 450px"
placeholder="点击选择图标"
readonly
>
<svg-icon
v-if="form.icon"
slot="prefix"
:icon-class="form.icon"
class="el-input__icon"
style="height: 32px; width: 16px"
/>
<i
v-else
slot="prefix"
class="el-icon-search el-input__icon"
/>
</el-input>
</el-popover>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="菜单名称" prop="name">
<el-input v-model="form.name" placeholder="请输入菜单名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="显示排序" prop="sortValue">
<el-input-number
v-model="form.sortValue"
controls-position="right"
:min="0"
/>
</el-form-item>
</el-col>
<el-col v-if="form.type != '2'" :span="12">
<el-form-item label="路由地址" prop="path">
<span slot="label">
<el-tooltip
content="访问的路由地址,如:`user`,如外网地址需内链访问则以`http(s)://`开头"
placement="top"
>
<i class="el-icon-question" />
</el-tooltip>
路由地址
</span>
<el-input v-model="form.path" placeholder="请输入路由地址" />
</el-form-item>
</el-col>
<el-col v-if="form.type !== 2" :span="12">
<el-form-item label="组件路径" prop="component">
<span slot="label">
<el-tooltip
content="访问的组件路径,如:`system/user/index`,默认在`views`目录下"
placement="top"
>
<i class="el-icon-question" />
</el-tooltip>
组件路径
</span>
<el-input v-model="form.component" placeholder="请输入组件路径" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="权限字符" prop="perms">
<span slot="label">
<el-tooltip
content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasPermi('system:user:list')`)"
placement="top"
>
<i class="el-icon-question" />
</el-tooltip>
权限字符
</span>
<el-input v-model="form.perms" placeholder="请输入权限字符" />
</el-form-item>
</el-col>
<el-col v-if="form.type != '2'" :span="12">
<el-form-item label="菜单状态" prop="status">
<span slot="label">
<el-tooltip
content="选择停用则路由将不会出现在侧边栏,也不能被访问"
placement="top"
>
<i class="el-icon-question" />
</el-tooltip>
菜单状态
</span>
<el-radio-group v-model="form.status">
<el-radio :label="1">启用</el-radio>
<el-radio :label="0">停用</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
findNodesMenu,
getMenu,
getMenuById,
removeMenu,
saveMenu,
updateMenu,
updateStatusMenu
} from '@/api/system/menu'
import IconSelect from '@/components/IconSelect'
export default {
name: 'Menu',
components: {
IconSelect
},
data() {
return {
// 查询参数
queryParams: {
// 关键字
name: undefined
},
// 数据是否正在加载
loading: false,
// 菜单表格数据
menuList: [],
// 菜单树选项
menuOptions: [],
// 是否展开,默认全部折叠
isExpandAll: false,
// 重新渲染表格状态
refreshTable: true,
// 弹出层标题
title: '',
// 是否显示弹出层
open: false,
// 表单参数
form: {},
// 表单校验
rules: {
name: [
{ required: true, message: '菜单名称不能为空', trigger: 'blur' }
],
sortValue: [
{ required: true, message: '菜单顺序不能为空', trigger: 'blur' }
],
path: [
{ required: true, message: '路由地址不能为空', trigger: 'blur' }
],
component: [
{ required: true, message: '组件路径不能为空', trigger: 'blur' }
]
}
}
},
created() {
this.getList()
},
methods: {
/** 查询菜单列表 */
getList() {
this.loading = true
findNodesMenu().then((res) => {
this.menuList = res.data
this.loading = false
})
},
/** 转换菜单数据结构 */
normalizer(node) {
if (node.children && !node.children.length) {
delete node.children
}
return {
id: node.id,
label: node.name,
children: node.children
}
},
/** 查询菜单下拉树结构 */
getTreeselect() {
findNodesMenu().then(res => {
this.menuOptions = []
const menu = { id: 0, name: '主类目', children: [] }
menu.children = res.data
this.menuOptions.push(menu)
})
},
/** 选择图标*/
selected(name) {
this.form.icon = name
},
/** 搜索按钮操作 */
handleQuery() {
const name = this.queryParams.name
if (name === undefined) {
this.getList()
} else {
getMenu(this.queryParams).then((res) => {
this.menuList = res.data
})
}
},
/** 重置按钮操作 */
resetQuery() {
this.queryParams.name = undefined
this.getList()
},
/** 展开/折叠操作 */
toggleExpandAll() {
this.refreshTable = false
this.isExpandAll = !this.isExpandAll
this.$nextTick(() => {
this.refreshTable = true
})
},
/** 重置表单 */
reset() {
this.form = {
id: undefined,
parentId: 0,
name: undefined,
path: undefined,
component: undefined,
perms: undefined,
icon: undefined,
sortValue: undefined,
type: 0,
status: '1'
}
// this.$refs["form"].resetFields();
},
/** 新增按钮操作 */
handleAdd(row) {
this.reset()
this.getTreeselect()
if (row != null && row.id) {
this.form.parentId = row.id
} else {
this.form.parentId = 0
}
this.title = '添加菜单'
this.open = true
},
/** 删除按钮操作 */
handleDelete(row) {
this.$confirm(
'您确定删除菜单[' + row.name + ']吗?(如果存在下级节点则不能删除)',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
)
.then(() => {
removeMenu(row.id)
.then((res) => {
this.$message({ message: '删除成功', type: 'success' })
this.getList()
})
.catch((err) => {
this.$message.error(err)
})
})
.catch(() => {
this.$message.info('已取消删除')
})
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
this.getTreeselect()
if (row != null && row.id) {
getMenuById(row.id).then(res => {
this.form = res.data
this.title = '修改菜单'
this.open = true
})
}
},
/** 导出按钮操作 */
handleExport() {
},
/** 菜单状态修改 */
handleStatusChange(row) {
const text = row.status === 0 ? '启用' : '停用'
this.$confirm('您确定要' + text + '菜单\'' + row.name + '\'吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
row.status = row.status === 1 ? 0 : 1
updateStatusMenu(row.id, row.status)
.then((res) => {
this.$message({
type: 'success',
message: text + '成功!'
})
this.getList()
})
.catch((err) => {
row.status = row.status === 0 ? 1 : 0
this.$message({
type: 'error',
message: text + '失败!'
})
})
})
.catch(() => {
this.$message.info('已取消修改')
})
},
/** 提交 */
submitForm() {
this.$refs['form'].validate((valid) => {
if (valid) {
if (this.form.id !== undefined) {
updateMenu(this.form)
.then((res) => {
this.$message.success('修改成功!')
this.open = false
this.getList()
})
.catch((err) => {
this.$message.error('修改失败!')
})
} else {
saveMenu(this.form)
.then((res) => {
this.$message.success('新增成功!')
this.open = false
this.getList()
})
.catch((err) => {
this.$message.error('新增失败!')
})
}
}
})
},
/** 取消按钮*/
cancel() {
this.open = false
this.reset()
this.$refs['form'].resetFields()
}
}
}
</script>
<style>
</style>
components\IconSelect\index.vue
<template>
<div class="app-container">
<!-- 查询条件 -->
<el-form ref="queryForm" :model="queryParams" size="small" :inline="true">
<el-form-item label="菜单名称" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入菜单名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button
type="primary"
icon="el-icon-search"
size="mini"
@click="handleQuery"
>搜索
</el-button>
<el-button
icon="el-icon-refresh"
size="mini"
@click="resetQuery"
>重置
</el-button>
</el-form-item>
</el-form>
<!-- CRUD -->
<el-row :gutter="10" class="mb8" style="margin-bottom: 10px">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
>新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="el-icon-sort"
size="mini"
@click="toggleExpandAll"
>展开/折叠
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
>导出
</el-button>
</el-col>
</el-row>
<!-- 菜单列表 -->
<el-table
v-if="refreshTable"
v-loading="loading"
:data="menuList"
row-key="id"
:default-expand-all="isExpandAll"
:tree-props="{ children: 'children' }"
border
header-cell-style="background-color:#EEE;color:#444;height:41px"
>
>
<el-table-column
key="name"
label="菜单名称"
align="center"
prop="name"
:show-overflow-tooltip="true"
/>
<el-table-column prop="icon" label="图标" align="center" width="100">
<template slot-scope="scope">
<svg-icon :icon-class="scope.row.icon" />
<!-- <i :class="scope.row.icon" />-->
</template>
</el-table-column>
<el-table-column
key="perms"
label="权限标识"
align="center"
prop="perms"
:show-overflow-tooltip="true"
/>
<el-table-column
key="path"
label="路由地址"
align="center"
prop="path"
:show-overflow-tooltip="true"
/>
<el-table-column
key="component"
label="组件路径"
align="center"
prop="component"
:show-overflow-tooltip="true"
/>
<el-table-column
key="sortValue"
label="排序"
align="center"
prop="sortValue"
width="100%"
sortable
:show-overflow-tooltip="true"
/>
<el-table-column key="status" label="状态" align="center">
<template slot-scope="scope">
<el-switch
v-model="scope.row.status === 1"
@change="handleStatusChange(scope.row)"
/>
</template>
</el-table-column>
<el-table-column
label="创建时间"
align="center"
prop="createTime"
width="160"
sortable
/>
<el-table-column
label="操作"
align="center"
width="160"
class-name="small-padding fixed-width"
>
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
>修改
</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
>删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 添加或修改菜单对话框 -->
<el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-row>
<el-col :span="24">
<el-form-item label="上级菜单" prop="parentId">
<treeselect
v-model="form.parentId"
:options="menuOptions"
:normalizer="normalizer"
:show-count="true"
placeholder="请选择上级菜单"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="菜单类型" prop="type">
<el-radio-group v-model="form.type">
<el-radio :label="0">目录</el-radio>
<el-radio :label="1">菜单</el-radio>
<el-radio :label="2">按钮</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col v-if="form.type != '2'" :span="24">
<el-form-item label="菜单图标" prop="icon">
<el-popover
placement="bottom-start"
width="450"
trigger="click"
@show="$refs['iconSelect'].reset()"
>
<IconSelect ref="iconSelect" @selected="selected" />
<el-input
slot="reference"
v-model="form.icon"
style="width: 450px"
placeholder="点击选择图标"
readonly
>
<svg-icon
v-if="form.icon"
slot="prefix"
:icon-class="form.icon"
class="el-input__icon"
style="height: 32px; width: 16px"
/>
<i
v-else
slot="prefix"
class="el-icon-search el-input__icon"
/>
</el-input>
</el-popover>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="菜单名称" prop="name">
<el-input v-model="form.name" placeholder="请输入菜单名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="显示排序" prop="sortValue">
<el-input-number
v-model="form.sortValue"
controls-position="right"
:min="0"
/>
</el-form-item>
</el-col>
<el-col v-if="form.type != '2'" :span="12">
<el-form-item label="路由地址" prop="path">
<span slot="label">
<el-tooltip
content="访问的路由地址,如:`user`,如外网地址需内链访问则以`http(s)://`开头"
placement="top"
>
<i class="el-icon-question" />
</el-tooltip>
路由地址
</span>
<el-input v-model="form.path" placeholder="请输入路由地址" />
</el-form-item>
</el-col>
<el-col v-if="form.type === '1'" :span="12">
<el-form-item label="组件路径" prop="component">
<span slot="label">
<el-tooltip
content="访问的组件路径,如:`system/user/index`,默认在`views`目录下"
placement="top"
>
<i class="el-icon-question" />
</el-tooltip>
组件路径
</span>
<el-input v-model="form.component" placeholder="请输入组件路径" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="权限字符" prop="perms">
<span slot="label">
<el-tooltip
content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasPermi('system:user:list')`)"
placement="top"
>
<i class="el-icon-question" />
</el-tooltip>
权限字符
</span>
<el-input v-model="form.perms" placeholder="请输入权限字符" />
</el-form-item>
</el-col>
<el-col v-if="form.type != '2'" :span="12">
<el-form-item label="菜单状态" prop="status">
<span slot="label">
<el-tooltip
content="选择停用则路由将不会出现在侧边栏,也不能被访问"
placement="top"
>
<i class="el-icon-question" />
</el-tooltip>
菜单状态
</span>
<el-radio-group v-model="form.status">
<el-radio :label="1">启用</el-radio>
<el-radio :label="0">停用</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
findNodes,
remove,
update,
save,
get,
updateStatus
} from '@/api/system/menu'
import IconSelect from '@/components/IconSelect'
import { handleTree } from '@/utils/index'
export default {
name: 'Menu',
components: {
IconSelect
},
data() {
return {
// 查询参数
queryParams: {
// 关键字
name: undefined
},
// 数据是否正在加载
loading: false,
// 菜单表格数据
menuList: [],
// 菜单树选项
menuOptions: [],
// 是否展开,默认全部折叠
isExpandAll: false,
// 重新渲染表格状态
refreshTable: true,
// 弹出层标题
title: '',
// 是否显示弹出层
open: false,
// 表单参数
form: {},
// 表单校验
rules: {
name: [
{ required: true, message: '菜单名称不能为空', trigger: 'blur' }
],
sortValue: [
{ required: true, message: '菜单顺序不能为空', trigger: 'blur' }
],
path: [
{ required: true, message: '路由地址不能为空', trigger: 'blur' }
],
component: [
{ required: true, message: '组件路径不能为空', trigger: 'blur' }
]
}
}
},
created() {
this.getList()
},
methods: {
/** 查询菜单列表 */
getList() {
this.loading = true
findNodes().then((res) => {
this.menuList = res.data
this.loading = false
})
},
/** 转换菜单数据结构 */
normalizer(node) {
if (node.children && !node.children.length) {
delete node.children
}
return {
id: node.id,
label: node.name,
children: node.children
}
},
/** 查询菜单下拉树结构 */
getTreeselect() {
findNodes().then(res => {
this.menuOptions = []
const menu = { id: 0, name: '主类目', children: [] }
menu.children = res.data
this.menuOptions.push(menu)
})
},
/** 选择图标*/
selected(name) {
this.form.icon = name
},
/** 搜索按钮操作 */
handleQuery() {
const name = this.queryParams.name
if (name === undefined) {
this.getList()
} else {
get(this.queryParams).then((res) => {
this.menuList = res.data
})
}
},
/** 重置按钮操作 */
resetQuery() {
this.queryParams.name = undefined
this.getList()
},
/** 展开/折叠操作 */
toggleExpandAll() {
this.refreshTable = false
this.isExpandAll = !this.isExpandAll
this.$nextTick(() => {
this.refreshTable = true
})
},
/** 重置表单 */
reset() {
this.form = {
id: undefined,
parentId: 0,
name: undefined,
path: undefined,
component: undefined,
perms: undefined,
icon: undefined,
sortValue: undefined,
type: 0,
status: '1'
}
// this.$refs["form"].resetFields();
},
/** 新增按钮操作 */
handleAdd(row) {
this.reset()
this.getTreeselect()
if (row != null && row.id) {
this.form.parentId = row.id
} else {
this.form.parentId = 0
}
this.title = '添加菜单'
this.open = true
},
/** 删除按钮操作 */
handleDelete(row) {
this.$confirm(
'您确定删除菜单[' + row.name + ']吗?(如果存在下级节点则不能删除)',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
)
.then(() => {
remove(row.id)
.then((res) => {
this.$message({ message: '删除成功', type: 'success' })
this.getList()
})
.catch((err) => {
this.$message.error(err)
})
})
.catch(() => {
this.$message.info('已取消删除')
})
},
/** 修改按钮操作 */
handleUpdate(row) {
this.form = row
this.getTreeselect()
if (row != null && row.id) {
this.form.parentId = row.parentId
} else {
this.form.parentId = 0
}
this.title = '修改菜单'
this.open = true
},
/** 导出按钮操作 */
handleExport() {},
/** 菜单状态修改 */
handleStatusChange(row) {
const text = row.status === 0 ? '启用' : '停用'
this.$confirm('您确定要' + text + "菜单'" + row.name + "'吗?", '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
row.status = row.status === 1 ? 0 : 1
updateStatus(row.id, row.status)
.then((res) => {
this.$message({
type: 'success',
message: text + '成功!'
})
this.getList()
})
.catch((err) => {
row.status = row.status === 0 ? 1 : 0
this.$message({
type: 'error',
message: text + '失败!'
})
})
})
.catch(() => {
this.$message.info('已取消修改')
})
},
/** 提交 */
submitForm() {
this.$refs['form'].validate((valid) => {
if (valid) {
if (this.form.id !== undefined) {
update(this.form)
.then((res) => {
this.$message.success('修改成功!')
this.open = false
this.getList()
})
.catch((err) => {
this.$message.error('修改失败!')
})
} else {
save(this.form)
.then((res) => {
this.$message.success('新增成功!')
this.open = false
this.getList()
})
.catch((err) => {
this.$message.error('新增失败!')
})
}
}
})
},
/** 取消按钮*/
cancel() {
this.open = false
this.reset()
this.$refs['form'].resetFields()
}
}
}
</script>
<style>
</style>
components\IconSelect\requireIcons.js
const req = require.context('@/icons/svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys()
const re = /\.\/(.*)\.svg/
const icons = requireAll(req).map(i => {
return i.match(re)[1]
})
export default icons
使用treeselect
1.安装依赖
npm install --save @riophae/vue-treeselect
2.在main.js里注册全局组件
import Treeselect from '@riophae/vue-treeselect' // 导入vue-treeselect
import '@riophae/vue-treeselect/dist/vue-treeselect.css' // 导入样式
Vue.component('Treeselect', Treeselect); // 注册组件
3.组件使用
<treeselect
v-model="form.parentId"
:options="menuOptions"
:normalizer="normalizer"
:show-count="true"
placeholder="请选择上级菜单"
/>
定义数据与方法
data() {
return {
// 菜单树选项
menuOptions: [],
}},
methods:{
/** 转换菜单数据结构 */
normalizer(node) {
if (node.children && !node.children.length) {
delete node.children
}
return {
id: node.id,
label: node.name,
children: node.children
}
},
/** 查询菜单下拉树结构 */
getTreeselect() {
findNodes().then(res => {
this.menuOptions = []
const menu = { id: 0, name: '主类目', children: [] }
menu.children = res.data //后端返回的数据是树形结构的数据
// menu.children = handleTree(res.data, "id");//后端返回的数据是单条菜单的数据
this.menuOptions.push(menu)
})
},
}
构造树形结构的数据
/**
* 构造树型结构数据
* @param {*} data 数据源
* @param {*} id id字段 默认 'id'
* @param {*} parentId 父节点字段 默认 'parentId'
* @param {*} children 孩子节点字段 默认 'children'
*/
export function handleTree(data, id, parentId, children) {
const config = {
id: id || 'id',
parentId: parentId || 'parentId',
childrenList: children || 'children'
}
var childrenListMap = {}
var nodeIds = {}
var tree = []
for (const d of data) {
const parentId = d[config.parentId]
if (childrenListMap[parentId] == null) {
childrenListMap[parentId] = []
}
nodeIds[d[config.id]] = d
childrenListMap[parentId].push(d)
}
for (const d of data) {
const parentId = d[config.parentId]
if (nodeIds[parentId] == null) {
tree.push(d)
}
}
for (const t of tree) {
adaptToChildrenList(t)
}
function adaptToChildrenList(o) {
if (childrenListMap[o[config.id]] !== null) {
o[config.childrenList] = childrenListMap[o[config.id]]
}
if (o[config.childrenList]) {
for (const c of o[config.childrenList]) {
adaptToChildrenList(c)
}
}
}
return tree
}
3.角色分配菜单功能
后台
controller
/**
* 查询所有菜单和角色分配的菜单
* @param roleId
* @return
*/
@ApiOperation(value = "查询所有菜单和角色分配的菜单")
@GetMapping("toAssign/{roleId}")
public Result toAssign(@PathVariable Long roleId) {
List<SysMenu> list = sysMenuService.findMenuByRoleId(roleId);
return Result.ok(list);
}
/**
* 为角色分配菜单
* @param assginMenuVo
* @return
*/
@ApiOperation(value = "为角色分配菜单")
@PostMapping("/doAssign")
public Result doAssign(@RequestBody AssginMenuVo assginMenuVo){
sysMenuService.doAssign(assginMenuVo);
return Result.ok();
}
service
@Autowired
private SysRoleMenuService sysRoleMenuService;
/**
* 查询所有菜单和角色分配的菜单
* @param roleId
* @return
*/
@Override
public List<SysMenu> findMenuByRoleId(Long roleId) {
// 1、查询所有的菜单 前提是 status=1
LambdaQueryWrapper<SysMenu> sysMenuLambdaQueryWrapper = new LambdaQueryWrapper<>();
sysMenuLambdaQueryWrapper.eq(SysMenu::getStatus, 1);
List<SysMenu> sysMenuList = baseMapper.selectList(sysMenuLambdaQueryWrapper);
// 2、根据 role_id 查询 sys_role_menu 对应的所有 menu_id
LambdaQueryWrapper<SysRoleMenu> sysRoleMenuLambdaQueryWrapper = new LambdaQueryWrapper<>();
sysRoleMenuLambdaQueryWrapper.eq(SysRoleMenu::getRoleId, roleId);
List<SysRoleMenu> sysRoleMenuList = sysRoleMenuService.list(sysRoleMenuLambdaQueryWrapper);
// 3、根据 menu_id , 获取菜单对象
List<Long> menuIdList = sysRoleMenuList.stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList());
// 3.1、 拿着 menu_id 和所有的 菜单集合的 id 进行比较, 如果相同,就封装
sysMenuList.forEach(item -> {
if (menuIdList.contains(item.getId())) {
item.setSelect(true);
} else {
item.setSelect(false);
}
});
// 4、返回规定格式的菜单列表
List<SysMenu> list = MenuHelper.buildTree(sysMenuList);
return list;
}
/**
* 为角色分配菜单
* @param assginMenuVo
*/
@Override
public void doAssign(AssginMenuVo assginMenuVo) {
// 1、根据 role_id 删除 sys_role_menu 中的数据
LambdaQueryWrapper<SysRoleMenu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(SysRoleMenu::getRoleId, assginMenuVo.getRoleId());
sysRoleMenuService.remove(lambdaQueryWrapper);
// 2、从 assginMenuVo 获取新的 role_id 对应的 menu_id 集合
List<Long> menuIdList = assginMenuVo.getMenuIdList();
// 遍历集合,把 menu_id 和 role_id 重新设置上
for (Long menuId : menuIdList) {
if (StringUtils.isEmpty(menuId)) {
continue;
}
SysRoleMenu sysRoleMenu = new SysRoleMenu();
sysRoleMenu.setMenuId(menuId);
sysRoleMenu.setRoleId(assginMenuVo.getRoleId());
sysRoleMenuService.save(sysRoleMenu);
}
}
前端
定义api请求函数
// 查询所有菜单和角色分配的菜单
export function toAssignMenu(roleId) {
return request({
url: `${api_name}/toAssign/${roleId}`,
method: 'get',
})
}
// 为角色分配菜单
export function doAssignMenu(data) {
return request({
url: `${api_name}/doAssign`,
method: 'post',
data: data
})
}
页面展示在角色管理页面
<template>
<!-- 菜单授权 -->
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="7">
<el-card class="box-card" shadow="never">
<div slot="header" class="clearfix">
<el-tooltip class="item" effect="dark" content="选择指定角色分配菜单" placement="top">
<span class="role-span">菜单分配</span>
</el-tooltip>
<el-button
:disabled="!showButton"
:loading="menuLoading"
icon="el-icon-check"
size="mini"
style="float: right; padding: 6px 9px"
type="primary"
@click="saveMenu"
>保存
</el-button>
</div>
<el-tree
style="margin: 20px 0"
ref="tree"
:data="sysMenuList"
node-key="id"
show-checkbox
:default-expand-all="false"
:props="defaultProps"
/>
</el-card>
</el-col>
</template>
<script>
import { toAssignMenu, doAssignMenu, findNodesMenu } from '@/api/system/menu'
export default {
data() {
return {
//角色单行当前行的roleId
currentId:undefined,
//角色授权菜单按钮显示
showButton: false,
// 用来标识是否正在保存请求中的标识, 防止重复提交
menuLoading: false,
defaultProps: {
children: 'children',
label: 'name'
},
//所有menu
sysMenuList: []
}
},
//在getList()
methods:{
getList(){
//获取菜单列表
findNodesMenu().then(res => {
this.sysMenuList = res.data
})
},
/** 列表点击单行触发单选*/
handleCurrentChange(val) {
if (val) {
//保存当前id
this.currentId = val.id
// 清空菜单的选中
this.$refs.tree.setCheckedKeys([])
//获取当前角色分配的菜单
toAssignMenu(val.id).then(res => {
const menuListSelect = res.data
const checkMenuIds = this.getCheckedIds(menuListSelect)
this.$refs.tree.setCheckedKeys(checkMenuIds)
})
this.showButton = true
}
},
/**得到所有选中的id列表*/
getCheckedIds(auths, initArr = []) {
return auths.reduce((pre, item) => {
if (item.select && item.children.length === 0) {
pre.push(item.id)
} else if (item.children) {
this.getCheckedIds(item.children, initArr)
}
return pre
}, initArr)
},
/**保存菜单分配*/
saveMenu() {
this.menuLoading = true
//获取到当前子节点及父节点
const allCheckedNodes = this.$refs.tree.getCheckedNodes(false, true);
let menuIdList = allCheckedNodes.map(node => node.id);
let assginMenuVo = {
roleId: this.currentId,
menuIdList: menuIdList
}
doAssignMenu(assginMenuVo).then(res => {
this.handleCurrentChange()
this.menuLoading = false
this.$message.success('菜单分配保存成功')
}).catch(err => {
this.menuLoading = false
this.$message.error('菜单分配保存失败')
})
}
}
}