5.系统权限管理
-------角色管理-------
一.关系分析
对应的是数据库表的名称
二.sql编写
边写边学
1.通过用户id 查对应的角色职务信息
-- 查询,结果显示角色里的所有数据
SELECT ro.*
-- 把表1起个别名叫ro 和 表2别名us 关联起来
FROM sys_role ro INNER JOIN sys_user_role us
-- 关联条件是 ro的id = us的rolo_id
ON ro.id = us.role_id
-- 查询条件
WHERE us.user_id = 5
白话:查询角色信息里的 (角色为5) 并且里面的 (roleid和role表的id相等) 的us表
也就是说 关系表 永远只作为 join on的条件
2.通过用户id 查对应的菜单职务信息
从下往上看: 包含条件的关系表 -->关系表-->关系表-->X个关系表 -->结果表
从上往下看: 结果表-->关系表-->关系表-->X个关系表--> 包含条件的关系表
-- DISTINCT去重 要查谁就 FROM 谁 ,通过关系表一张一张的连到 条件表
SELECT DISTINCT me.* FROM sys_menu me
INNER JOIN sys_role_menu rome ON rome.menu_id = me.id
INNER JOIN sys_user_role usro ON usro.role_id = rome.role_id
WHERE usro.user_id = 5
三.准备工作
这里前端代码很简单就不写了,直接复制文档
1.修改动态菜单为固定菜单:
const menus = getFilterMenus(fixedRoutes)
setMenus(menus)
在该文件夹下创建3个.vue文件
也就是最终的这三个界面:
3、在router/modules目录下创建system.js文件,配置路由规则
创建一个大标签的管理菜单
// 导入组件
const Layout = () => import('@/layout/index.vue')
const sysRole = () => import('@/views/system/sysRole.vue')
const sysUser = () => import('@/views/system/sysUser.vue')
const sysMenu = () => import('@/views/system/sysMenu.vue')
// 导出该组件
export default([
{
path: "/system",
component: Layout,
name: 'system',
meta: {
title: '系统管理',
},
icon: 'Location',
children: [
{
path: '/sysRole',
name: 'sysRole',
component: sysRole,
meta: {
title: '角色管理',
},
hidden: false
},
{
path: '/sysUser',
name: 'sysUser',
component: sysUser,
meta: {
title: '用户管理',
},
hidden: false
},
{
path: '/menu',
name: 'sysMenu',
component: sysMenu,
meta: {
title: '菜单管理',
},
hidden: false
}
]
}
])
4、修改router/index.js导入路由配置
把大标签放到菜单里面
import system from './modules/system'
export const fixedRoutes = [...home,...system]
四.搜索列表功能
1.后端:
在resources里创建目录不能用.要用/
首先准备好:
- Controller的API接口
- mybatis的mapper
- mybatis的xml
- service接口
- service的impl
2.1.根据名称查role
2.1.1.编写sql层
我们先做这一个:
2.1.1.1.首先通过可视化工具编写sql
用LIKE关键词,模糊查询"管理员"
但是我们后端需要字符串拼接所有,用sql的一个CONCAT
函数进行拼接
加一个ORDER BY id DESC
通过id降序排序
SELECT * FROM sys_role
-- 模糊搜索
WHERE role_name LIKE "%管理员%"
-- 降序查询
ORDER BY id DESC
2.1.1.2.改为mybatis代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--对应的接口别弄错了-->
<mapper namespace="com.zhexin.manage.mapper.SysRole.getRoleListMapper">
<!--映射到SysRole里面, autoMapping为自动映射-->
<resultMap id="ListSysRole" type="com.zhexin.model.entity.system.SysRole" autoMapping="true" />
<!--查询结果的列-->
<sql id="ListSysRoleJG">
id,role_name,role_code,description,create_time,update_time,is_deleted
</sql>
<!--查询-->
<select id="SelectRoleListByname" resultMap="ListSysRole">
SELECT <include refid="ListSysRoleJG"/> FROM sys_role
<where>
<if test="RoleName != null and RoleName != ''">
and role_name LIKE CONCAT('%',#{RoleName},'%')
</if>
</where>
-- 降序查询
ORDER BY id DESC
</select>
</mapper>
2.1.2 controller接口
因为这里需要分页:
我们用导入的配置: 这个插件来实现
前端需要传来的参数:
通过分页插件进行分页
- 当前页数
- 每页存在的数量
- 上传到查询对象
@Operation(summary = "角色查询接口") //文档注释
@PostMapping("/getRoleList/{page}/{quantity}")
public Result getRoleList(@PathVariable("page") String page, //路径中的页数
@PathVariable("quantity") String quantity, //路径中的页面数量
@RequestBody SysRoleDto sysRoleDto //请求的json参数
){
PageInfo<SysRole> info = getRoleListService.byName(page,quantity,sysRoleDto)
return Result.build(info, ResultCodeEnum.SUCCESS);
}
2.1.3 业务实现
package com.zhexin.manage.service.SysRole.Impl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zhexin.manage.mapper.SysRole.getRoleListMapper;
import com.zhexin.manage.service.SysRole.getRoleListService;
import com.zhexin.model.dto.system.SysRoleDto;
import com.zhexin.model.entity.system.SysRole;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class getRoleListServiceImpl implements getRoleListService {
@Autowired
getRoleListMapper getRoleListMapper;
@Override
public PageInfo<SysRole> byName(int page, int quantity, SysRoleDto sysRoleDto) {
PageInfo<SysRole> pageInfo = null;
//因为我们在mybatis里注册了这个插件,
//用这个方法 运行插件,他会自动拦截查询,进行分页
PageHelper.startPage(page,quantity);
//开始查询
List<SysRole> sysRoles = getRoleListMapper.SelectRoleListByname(sysRoleDto.getRoleName());
//封装返回结果对象:
pageInfo = new PageInfo<>(sysRoles);
return pageInfo;
}
}
2.前端:
1.1界面代码
- 1、搜索表单
- 2、添加按钮
- 3、数据展示表格
- 4、分页条组件
sysRole.vue 代码实现如下所示:
<template>
<div class="search-div">
<!-- 搜索表单 -->
<el-form label-width="70px" size="small">
<el-form-item label="角色名称">
<el-input
style="width: 100%"
placeholder="角色名称"
></el-input>
</el-form-item>
<el-row style="display:flex">
<el-button type="primary" size="small">
搜索
</el-button>
<el-button size="small">重置</el-button>
</el-row>
</el-form>
<!-- 添加按钮 -->
<div class="tools-div">
<el-button type="success" size="small">添 加</el-button>
</div>
<!--- 角色表格数据 -->
<el-table :data="list" style="width: 100%">
<el-table-column prop="roleName" label="角色名称" width="180" />
<el-table-column prop="roleCode" label="角色code" width="180" />
<el-table-column prop="createTime" label="创建时间" />
<el-table-column label="操作" align="center" width="280">
<el-button type="primary" size="small">
修改
</el-button>
<el-button type="danger" size="small">
删除
</el-button>
</el-table-column>
</el-table>
<!--分页条-->
<el-pagination
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next"
:total="total"
/>
</div>
</template>
<script setup>
import { ref } from 'vue';
// 分页条总记录数
let total = ref(0)
// 定义表格数据模型
let list = ref([
{"id":9 , "roleName": "系统管理员" , "roleCode":"xtgly","createTime": '2023-07-31'},
{"id":10 , "roleName": "商品管理员" , "roleCode":"spgly","createTime": '2023-07-31'}
])
</script>
<style scoped>
.search-div {
margin-bottom: 10px;
padding: 10px;
border: 1px solid #ebeef5;
border-radius: 3px;
background-color: #fff;
}
.tools-div {
margin: 10px 0;
padding: 10px;
border: 1px solid #ebeef5;
border-radius: 3px;
background-color: #fff;
}
</style>
1.2.最终效果
1.3.创建api接口
在api目录下,有我们之前登录的接口
我们按照他的写法写一个role的接口
//引入统一请求封装
import request from '@/utils/request'
//api接口常量
const url = '/zx/admin/system/role/'
// 登录接口
export const GetRole = (page,quantity,datas) => {
return request({
//在js里`表示字符串拼接${}是个表达式
url: `${url}/getRoleList/${page}/${quantity}`,
method: 'post',
//如果后端是@RequestBody则这里要加data
//否则是 params
data : datas ,
})
}
导入到sysRole.vue界面
import {
ref,
reactive,
onMounted
} from 'vue';
import {GetRole} from '@/api/role';
1.4.调用
1.4.1创建变量
// 分页条总记录数
// let total = ref(0)
// 定义表格数据模型
// let list = ref([
// {"id":9 , "roleName": "系统管理员" , "roleCode":"xtgly","createTime": '2023-07-31'},
// {"id":10 , "roleName": "商品管理员" , "roleCode":"spgly","createTime": '2023-07-31'}
// ])
//
//我们按照vue2的习惯创建一个存放数据的对象
let thiss =reactive({
// 定义表格数据模型
list:[],
//当前页码
page:1,
// 分页条总记录数
total:10,
//查询问题的文本,结果刚好可以跟后台的sysRoleDto类对应
sysRoleDto:{
roleName:''
}
})
1.4.2改掉界面里的变量
1.4.3创建访问方法
//查询接口
const getrolelest = async ()=>{
//从后台查到数据,匹配到参数里
const { code ,message ,data } = await GetRole(thiss.page , thiss.total ,thiss.sysRoleDto);
thiss.list = data.list
thiss.page = data.pageNum
thiss.total = data.pageNum
}
1.4.4 创建启动钩子, 调用访问方法
// 组件加载钩子,也就是启动函数
onMounted(()=>{
// 设置为空,即为查询所有
thiss.sysRoleDto.roleName = '';
getrolelest();
})
1.4.5 监听输入框内容,连接到变量
关于v-model: 全网最详细的v-model讲解_zayyo的博客-CSDN博客
关于v-on: Vue - v-on的使用_vue的v-on用法_学习中的小菜鸟.的博客-CSDN博客
输入框文档: 翻译 | Element Plus (element-plus.org)
修改界面
将钩子里的方法 ,提出重置方法
// 组件加载钩子,也就是启动函数
onMounted(()=>{
reset()
})
const reset = () => {
// 设置为空,即为查询所有
thiss.sysRoleDto.roleName = '';
getrolelest();
}
运行后发现, 输入的值只被赋值了一次,后面的赋值没有效果
后台日志看到这里不一样, 这个有定像我们的每页条数啊
看一下抓包: 两次的数字果然不一样
那么我猜测应该是
运维我们的钩子是,组件加载前调用
在钩子的时候使用的是我们的默认参数是10 , 当组件启动完成后, 数字就变成组件的数字了
如果是这样的话我们不用管他,继续下一步,,下一步完成就不会出现这个情况了!
1.4.6 修改分页条
Pagination 分页 | Element Plus (element-plus.org)
原来是这里写错了,修改就好了,分页条也解决了
也正符合我的推理逻辑
//查询接口
const getrolelest = async ()=>{
console.log( thiss.sysRoleDto.roleName );
//从后台查到数据,匹配到参数里
const { code ,message ,data } = await GetRole(thiss.page , thiss.total ,thiss.sysRoleDto);
thiss.list = data.list
thiss.page = data.pageNum
thiss.pageSize = data.pageSize
thiss.total = data.total
}
这时候又出现个新问题, 当我们点击重置的时候, 先设置搜索框为空 ,这时候并没有进行重置,而是为空的时候 再一次调用接口才会重置
也就是说第一次被设置搜索框顶掉了
1.4.6 最终代码:
bug都是分页条引起的
<template>
<div class="search-div">
<!-- 搜索表单 -->
<el-form label-width="70px" size="small">
<el-form-item label="角色名称">
<el-input
style="width: 100%"
placeholder="角色名称"
v-model="thiss.sysRoleDto.roleName"
></el-input>
</el-form-item>
<el-row style="display:flex">
<el-button type="primary" size="small" @click="getrolelest()">
搜索
</el-button>
<el-button size="small" @click=" reset()">重置</el-button>
</el-row>
</el-form>
<!-- 添加按钮 -->
<div class="tools-div">
<el-button type="success" size="small">添 加</el-button>
</div>
<!--- 角色表格数据 -->
<el-table :data="thiss.list" style="width: 100%">
<el-table-column prop="roleName" label="角色名称" width="180" />
<el-table-column prop="roleCode" label="角色code" width="180" />
<el-table-column prop="createTime" label="创建时间" />
<el-table-column label="操作" align="center" width="280">
<el-button type="primary" size="small">
修改
</el-button>
<el-button type="danger" size="small">
删除
</el-button>
</el-table-column>
</el-table>
<!--分页条-->
<!--监听分页,换页,和字符-->
<el-pagination
:page-sizes="[10,2, 20, 50, 100]"
layout="total, sizes, prev, pager, next"
:total="thiss.total"
@size-change="getrolelest"
@current-change="getrolelest"
v-model:current-page="thiss.pageNum"
v-model:page-size="thiss.pageSize"
/>
</div>
</template>
<script setup>
import {
ref,
reactive,
onMounted,
watch
} from 'vue';
import {GetRole} from '@/api/role';
// 分页条总记录数
// let total = ref(0)
// 定义表格数据模型
// let list = ref([
// {"id":9 , "roleName": "系统管理员" , "roleCode":"xtgly","createTime": '2023-07-31'},
// {"id":10 , "roleName": "商品管理员" , "roleCode":"spgly","createTime": '2023-07-31'}
// ])
//
//我们按照vue2的习惯创建一个存放数据的对象
let thiss =reactive({
// 定义表格数据模型
list:[],
//当前页码
pageNum:1,
//当前显示页码
pageSize:10,
// 分页条总记录数
total:'',
//查询问题的文本,结果刚好可以跟后台的sysRoleDto类对应
sysRoleDto:{
roleName:''
}
})
// 组件加载钩子,也就是启动函数
onMounted(()=>{
reset()
})
const reset = () => {
// 设置为空,即为查询所有
thiss.sysRoleDto.roleName = '';
getrolelest();
}
//查询接口
const getrolelest = async ()=>{
console.log( thiss.sysRoleDto.roleName );
//从后台查到数据,匹配到参数里
const { code ,message ,data } = await GetRole(thiss.pageNum , thiss.pageSize ,thiss.sysRoleDto);
thiss.list = data.list
thiss.pageNum = data.pageNum
thiss.pageSize = data.pageSize
thiss.total = data.total
}
</script>
<style scoped>
.search-div {
margin-bottom: 10px;
padding: 10px;
border: 1px solid #ebeef5;
border-radius: 3px;
background-color: #fff;
}
.tools-div {
margin: 10px 0;
padding: 10px;
border: 1px solid #ebeef5;
border-radius: 3px;
background-color: #fff;
}
</style>
<!--
{
"code": 200,
"message": "操作成功",
"data": {
"total": 7,
"list": [
{
"id": 39,
"createTime": "2023-09-04 02:04:41",
"updateTime": "2023-09-04 02:30:01",
"isDeleted": 1,
"roleName": "运维人员",
"roleCode": "yw",
"description": null
},
{
"id": 38,
"createTime": "2023-09-03 15:24:32",
"updateTime": "2023-09-04 02:30:06",
"isDeleted": 1,
"roleName": "开发人员",
"roleCode": "dev",
"description": null
}
],
"pageNum": 1,
"pageSize": 2,
"size": 2,
"startRow": 1,
"endRow": 2,
"pages": 4,
"prePage": 0,
"nextPage": 2,
"isFirstPage": true,
"isLastPage": false,
"hasPreviousPage": false,
"hasNextPage": true,
"navigatePages": 8,
"navigatepageNums": [
1,
2,
3,
4
],
"navigateFirstPage": 1,
"navigateLastPage": 4
}
}
-->
总结:
在vue3中 ,属性绑定参数要用 v-model:属性
事件绑定方法要用@绑定
五.添加功能
1.后端
1.Controller
@Operation(summary = "新增角色") //文档注释
@PostMapping("/DataUpRole")
public Result getRoleList( @RequestBody SysRole SysRole){ //请求的json参数
boolean jg = dataUpRoleService.insert(SysRole);
return Result.build(jg, ResultCodeEnum.SUCCESS);
}
2.Mybatis
先测试:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--对应的接口别弄错了-->
<mapper namespace="com.zhexin.manage.mapper.SysRole.DataUpRoleMapper">
<!--映射到SysRole里面, autoMapping为自动映射-->
<insert id="insert" parameterType="com.zhexin.model.entity.system.SysRole">
INSERT INTO sys_role
-- 表字段
( role_name , role_code , description )
VALUES
-- 对应的对象属性
(#{roleName}, #{roleCode} ,#{description})
</insert>
</mapper>
3.Service
@Service
public class DataUpRoleServiceImpl implements DataUpRoleService {
@Autowired
DataUpRoleMapper dataUpRoleMapper;
@Override
public boolean insert(SysRole sysRole) {
if (StrUtil.isEmpty(sysRole.getRoleName()) ||StrUtil.isEmpty( sysRole.getRoleCode()) || StrUtil.isEmpty(sysRole.getDescription())){
throw new zhexinException(201 , "添加失败,信息不完整!");
}
boolean insert = dataUpRoleMapper.insert(sysRole);
return insert;
}
}
2.前端
2.1 再里编写接口
// 添加角色请求方法
export const SaveSysRole = (data) => {
return request({
url: `${url}/DataUpRole`,
method: 'post',
data
})
}
2.2 在界面中引入
import { GetRole , SaveSysRole } from '@/api/role';
2.3 编写一个弹窗,用于输入新的信息
<!-- 添加按钮 -->
<div class="tools-div">
<el-button type="success" size="small" @click="addShow">添 加</el-button>
</div>
<!-- 添加角色表单对话框 -->
<el-dialog v-model="thiss.dialogVisible" title="添加或修改角色" width="30%">
<el-form label-width="120px">
<el-form-item label="角色名称" >
<el-input v-model="thiss.uprole.roleName"/>
</el-form-item>
<el-form-item label="角色Code" >
<el-input v-model="thiss.uprole.roleCode"/>
</el-form-item>
<el-form-item label="描述">
<el-input v-model="thiss.uprole.description"/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="upRole">提交</el-button>
<el-button @click="thiss.dialogVisible = false">取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
2.4 加入到变量
//弹窗显示控制开关
dialogVisible:false,
//添加数据
uprole:{
roleName:'',
roleCode:'' ,
description:''
}
2.4 点击打开弹窗方法
//弹窗打开方法
const addShow = ()=>{
thiss.dialogVisible = true
//清空
thiss.uprole = {
roleName:'',
roleCode:'' ,
description:''
}
}
2.5 调用请求接口
//添加接口
const upRole = async () => {
console.log(thiss.sysRoleDto.roleName);
//从后台查到数据,匹配到参数里
const { code, message, data } = await SaveSysRole(thiss.uprole);
if (+code == 200) {
ctx.$message.success(message)
//关闭弹窗
thiss.dialogVisible = false
//刷新界面
getrolelest();
} else {
ctx.$message.error(message)
}
}
2.6 测试
成功, 我又加了其他显示项
<el-table-column prop="id" label="用户ID" />
<el-table-column prop="roleName" label="角色名称" width="180" />
<el-table-column prop="roleCode" label="角色code" width="180" />
<el-table-column prop="description" label="描述" />
<el-table-column prop="createTime" label="创建时间" />
<el-table-column prop="updateTime" label="更新时间" />
<el-table-column prop= "isDeleted" label="启用" />
最后最后。。。。。。。。
剩下的增删改查功能都差不多,就不一个个说了,总结一下步骤
后端:
- 编写sql语句
- 创建service文件、mapper文件、和conrtoller接口
- 把sql转为mybatis
- 业务层判断是否空,然后调用mybatis接口
前端:
- 创建api接口,并引入
- 创建操作组件
- 创建组件变量
- 创建对应方法
- 组件和功能、属性一一绑定
- 编写显示效果,和提示
下面是我的主要代码:java层只放mybatis ,前端所有都在了
后端:
controller
package com.zhexin.manage.controller;
import com.github.pagehelper.PageInfo;
import com.zhexin.manage.service.SysRole.DataUpRoleService;
import com.zhexin.manage.service.SysRole.DeleteSysRoleService;
import com.zhexin.manage.service.SysRole.aMendRoleService;
import com.zhexin.manage.service.SysRole.getRoleListService;
import com.zhexin.model.dto.system.SysRoleDto;
import com.zhexin.model.entity.system.SysRole;
import com.zhexin.model.vo.common.Result;
import com.zhexin.model.vo.common.ResultCodeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;
@Tag(name = "角色管理接口") //swagger文档注释
@RestController //注册到bean
@RequestMapping("/admin/system/role") //注册访问路径
public class SysRoleController {
@Autowired
getRoleListService getRoleListService;
@Autowired
DataUpRoleService dataUpRoleService;
@Autowired
aMendRoleService amendRoleService;
@Autowired
DeleteSysRoleService deleteSysRoleService;
@Operation(summary = "角色查询接口") //文档注释
@PostMapping("/getRoleList/{page}/{quantity}")
public Result getRoleList(@PathVariable("page") int page, //路径中的页数
@PathVariable("quantity") int quantity, //路径中的页面数量
@RequestBody SysRoleDto sysRoleDto //请求的json参数
){
PageInfo<SysRole> info = getRoleListService.byName(page,quantity,sysRoleDto);
return Result.build(info, ResultCodeEnum.SUCCESS);
}
@Operation(summary = "新增角色") //文档注释
@PostMapping("/DataUpRole")
public Result getRoleList( @RequestBody SysRole SysRole){ //请求的json参数
boolean jg = dataUpRoleService.insert(SysRole);
return Result.build(jg, ResultCodeEnum.SUCCESS);
}
@Operation(summary = "修改角色") //文档注释
@PutMapping("/aMendRole")
public Result aMendRole( @RequestBody SysRole SysRole){ //请求的json参数
boolean jg = amendRoleService.aMend(SysRole);
return Result.build(jg, ResultCodeEnum.SUCCESS);
}
@Operation(summary = "修改角色状态") //文档注释
@GetMapping("/aMendRoleState/{roleId}/{roleState}")
public Result aMendRole( @PathVariable(value = "roleId") Long roleId ,
@PathVariable(value = "roleState") Integer roleState
){ //请求的json参数
boolean jg = amendRoleService.state(roleId , roleState);
return Result.build(jg, ResultCodeEnum.SUCCESS);
}
@Operation(summary = "删除角色") //文档注释
@DeleteMapping("/DeleteSysRoleById/{roleId}")
public Result DeleteSysRoleById( @PathVariable(value = "roleId") Long roleId){ //请求的json参数
boolean jg = deleteSysRoleService.DeleteSysRole(roleId);
return Result.build(jg, ResultCodeEnum.SUCCESS);
}
@Operation(summary = "批量删除角色") //文档注释
@DeleteMapping("/DeleteSysRoleByIdList")
public Result DeleteSysRoleByIdList( @RequestBody List<SysRole> roleId){ //请求的json参数
boolean jg = deleteSysRoleService.DeleteSysRolelist(roleId);
return Result.build(jg, ResultCodeEnum.SUCCESS);
}
}
修改和修改状态
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--对应的接口别弄错了-->
<mapper namespace="com.zhexin.manage.mapper.SysRole.aMendRoleMapper">
<!--映射到SysRole里面, autoMapping为自动映射-->
<update id="aMendRole" parameterType="com.zhexin.model.entity.system.SysRole">
UPDATE sys_role
SET
<if test="roleName != null || roleName != ''">
role_name = #{roleName} ,
</if>
<if test="roleCode != null || roleCode != ''">
role_code = #{roleCode},
</if>
<if test="description != null || description != ''">
description = #{description},
</if>
-- 更新修改时间,now为当前时间
update_time = NOW()
WHERE id = #{id}
</update>
<update id="state">
UPDATE sys_role
SET is_deleted= #{roleState}
WHERE id= #{roleId}
</update>
</mapper>
删除
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--对应的接口别弄错了-->
<mapper namespace="com.zhexin.manage.mapper.SysRole.DeleteSysRoleMapper">
<!--映射到SysRole里面, autoMapping为自动映射-->
<delete id="DeleteSysRole">
DELETE FROM sys_role
WHERE id= #{roleId}
</delete>
</mapper>
删除和批量删除Service
package com.zhexin.manage.service.SysRole.Impl;
import com.zhexin.common.service.exception.zhexinException;
import com.zhexin.manage.mapper.SysRole.DeleteSysRoleMapper;
import com.zhexin.manage.service.SysRole.DeleteSysRoleService;
import com.zhexin.model.entity.system.SysRole;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class DeleteSysRoleServiceImpl implements DeleteSysRoleService {
@Autowired
DeleteSysRoleMapper deleteSysRoleMapper;
@Override
public boolean DeleteSysRole(Long roleId) {
if ( roleId == null ){
throw new zhexinException(201 , "删除失败,信息不完整!");
}
return deleteSysRoleMapper.DeleteSysRole(roleId);
}
//批量删除
@Override
public boolean DeleteSysRolelist(List<SysRole> roleId) {
for (SysRole sysRole : roleId) {
if (!this.DeleteSysRole(sysRole.getId())){
return false;
}
}
return true;
}
}
前端:
sysRole.vue
<template>
<div class="search-div">
<!-- 搜索表单 -->
<el-form label-width="70px" size="small">
<el-form-item label="角色名称">
<el-input style="width: 100%" placeholder="角色名称" v-model="thiss.sysRoleDto.roleName"></el-input>
</el-form-item>
<el-row style="display:flex">
<el-button type="primary" size="small" @click="getrolelest()">
搜索
</el-button>
<el-button size="small" @click=" reset()">重置</el-button>
</el-row>
</el-form>
<!-- 添加按钮 -->
<div class="tools-div">
<el-button type="success" size="small" @click="addShow">添 加</el-button>
<el-button type="danger" size="small" @click="Statebutter()">批量删除</el-button>
</div>
<!-- 添加角色表单对话框 -->
<el-dialog v-model="thiss.dialogVisible" title="添加或修改角色" width="30%">
<el-form label-width="120px">
<el-form-item label="角色名称">
<el-input v-model="thiss.uprole.roleName" />
</el-form-item>
<el-form-item label="角色Code">
<el-input v-model="thiss.uprole.roleCode" />
</el-form-item>
<el-form-item label="描述">
<el-input v-model="thiss.uprole.description" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="upRole">提交</el-button>
<el-button @click="thiss.dialogVisible = false">取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
<!--- 角色表格数据 -->
<el-table :data="thiss.list" ref="ElTableref" style="width: 100%">
<el-table-column type="selection" width="55" />
<el-table-column type="index" label="序列" width="80" />
<el-table-column prop="id" label="用户ID" :sortable="true" />
<el-table-column prop="roleName" label="角色名称" width="180" />
<el-table-column prop="roleCode" label="角色code" width="180" />
<el-table-column prop="description" label="描述" />
<el-table-column prop="createTime" label="创建时间" :sortable="true" />
<el-table-column prop="updateTime" label="更新时间" :sortable="true" />
<el-table-column prop="isDeleted" label="状态" :formatter="statusFilter()" /> <!-- 过滤器 -->
<el-table-column label="操作" align="center" width="280" #default="scope"> <!-- #default 当前组件-->
<el-button type="primary" size="small" @click="amends(scope)">
修改
</el-button>
<el-button size="small" :color="thiss.StateButter" @click="setRoleState(scope)">
{{ scope.row.isDeleted == 1 ? '禁用' : '启用' }}
</el-button>
<el-button type="danger" size="small" @click="deletes(scope)">
删除
</el-button>
</el-table-column>
</el-table>
<!--分页条-->
<!--监听分页,换页,和字符-->
<el-pagination :page-sizes="[10, 2, 20, 50, 100]" layout="total, sizes, prev, pager, next" :total="thiss.total"
@size-change="getrolelest" @current-change="getrolelest" v-model:current-page="thiss.pageNum"
v-model:page-size="thiss.pageSize" />
</div>
</template>
<script setup>
import {
ref,
reactive,
onMounted,
getCurrentInstance
} from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus'
import { GetRole, SaveSysRole, aMendRole, DeleteSysRoleById , DeleteSysRoleByIdList, aMendRoleState } from '@/api/role';
// 分页条总记录数
// let total = ref(0)
// 定义表格数据模型
// let list = ref([
// {"id":9 , "roleName": "系统管理员" , "roleCode":"xtgly","createTime": '2023-07-31'},
// {"id":10 , "roleName": "商品管理员" , "roleCode":"spgly","createTime": '2023-07-31'}
// ])
//
const ElTableref =ref();
const { proxy: ctx } = getCurrentInstance() // 可以把ctx当成vue2中的this
//我们按照vue2的习惯创建一个存放数据的对象
let thiss = reactive({
// 定义表格数据模型
list: [],
//当前页码
pageNum: 1,
//当前显示页码
pageSize: 10,
// 分页条总记录数
total: 0,
//查询问题的文本,结果刚好可以跟后台的sysRoleDto类对应
sysRoleDto: {
roleName: ''
},
//弹窗显示控制开关
dialogVisible: false,
centerDialogVisible: false,
//添加数据
uprole: {
roleName: '',
roleCode: '',
description: ''
},
//按钮颜色
StateButter: "#134"
})
// 组件加载钩子,也就是启动函数
onMounted(() => {
reset()
})
//状态过滤器
const statusFilter = () => {
// 这里是你的过滤逻辑,根据 isDeleted 字段的值进行过滤
return (value, row) => {
if (+value.isDeleted === 1) {
thiss.StateButter = "#134"
return '✅';
} else {
thiss.StateButter = "#689"
return '❌';
}
};
}
const reset = () => {
// 设置为空,即为查询所有
thiss.sysRoleDto.roleName = '';
getrolelest();
}
//查询接口
const getrolelest = async () => {
//从后台查到数据,匹配到参数里
const { code, message, data } = await GetRole(thiss.pageNum, thiss.pageSize, thiss.sysRoleDto);
+code == 200 ? ctx.$message.success('列表刷新:' + message) : ctx.$message.error('列表刷新:' + message)
thiss.list = data.list
thiss.pageNum = data.pageNum
thiss.pageSize = data.pageSize
thiss.total = data.total
}
//弹窗打开方法
const addShow = () => {
thiss.dialogVisible = true
//清空
thiss.uprole = {
roleName: '',
roleCode: '',
description: ''
}
}
//添加接口
const upRole = async () => {
console.log(thiss.sysRoleDto.roleName);
//从后台查到数据,匹配到参数里
//!thiss.uprole.id等同于:thiss.uprole.id == null
//判断是修改还是添加
const { code, message, data } = !thiss.uprole.id ? await SaveSysRole(thiss.uprole) : await aMendRole(thiss.uprole);
if (+code == 200) {
ctx.$message.success(message)
//关闭弹窗
thiss.dialogVisible = false
//刷新界面
getrolelest();
} else {
ctx.$message.error(message)
}
}
//修改
const amends = information => {
console.log(information);
//打开弹窗
addShow()
//获取本列数据,传递给弹窗
thiss.uprole = information.row
}
//修改状态接口
const setRoleState = async information => {
const { code } = await aMendRoleState(information.row.id, information.row.isDeleted)
if (+code === 200) {
ElMessage.success('修改成功')
//刷新界面
getrolelest();
}
}
//删除
const deletes = information => {
ElMessageBox.confirm('此操作将永久删除该记录, 是否继续?', 'Warning', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(async () => {
const { code } = await DeleteSysRoleById(information.row.id)
if (code === 200) {
//刷新界面
getrolelest();
ElMessage.success('删除成功')
}
})
}
//批量删除
const Statebutter = () => {
ElMessageBox.confirm('此操作将永久删除, 是否继续?', 'Warning', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(async () => {
const { code } = await DeleteSysRoleByIdList(ElTableref.value.getSelectionRows())
if (code === 200) {
//刷新界面
getrolelest();
ElMessage.success('删除成功')
}
})
}
</script>
<style scoped>
.search-div {
margin-bottom: 10px;
padding: 10px;
border: 1px solid #ebeef5;
border-radius: 3px;
background-color: #fff;
}
.tools-div {
margin: 10px 0;
padding: 10px;
border: 1px solid #ebeef5;
border-radius: 3px;
background-color: #fff;
}
</style>
<!--
{
"code": 200,
"message": "操作成功",
"data": {
"total": 7,
"list": [
{
"id": 39,
"createTime": "2023-09-04 02:04:41",
"updateTime": "2023-09-04 02:30:01",
"isDeleted": 1,
"roleName": "运维人员",
"roleCode": "yw",
"description": null
},
{
"id": 38,
"createTime": "2023-09-03 15:24:32",
"updateTime": "2023-09-04 02:30:06",
"isDeleted": 1,
"roleName": "开发人员",
"roleCode": "dev",
"description": null
}
],
"pageNum": 1,
"pageSize": 2,
"size": 2,
"startRow": 1,
"endRow": 2,
"pages": 4,
"prePage": 0,
"nextPage": 2,
"isFirstPage": true,
"isLastPage": false,
"hasPreviousPage": false,
"hasNextPage": true,
"navigatePages": 8,
"navigatepageNums": [
1,
2,
3,
4
],
"navigateFirstPage": 1,
"navigateLastPage": 4
}
}
-->
role.js
//引入统一请求封装
import request from '@/utils/request'
//api接口常量
const url = '/zx/admin/system/role'
// 登录接口
export const GetRole = (page,quantity,datas) => {
return request({
//在js里`表示字符串拼接${}是个表达式
url: `${url}/getRoleList/${page}/${quantity}`,
method: 'post',
//如果后端是@RequestBody则这里要加data
//否则是 params
data : datas ,
})
}
// 添加角色请求方法
export const SaveSysRole = (data) => {
return request({
url: `${url}/DataUpRole`,
method: 'post',
data
})
}
// 修改角色请求方法
export const aMendRole = (data) => {
return request({
url: `${url}/aMendRole`,
method: 'put',
data
})
}
// 修改角色请求方法
export const aMendRoleState = (roleId,roleState) => {
return request({
url: `${url}/aMendRoleState/${roleId}/${roleState}`,
method: 'get',
})
}
// 删除角色
export const DeleteSysRoleById = (roleId) => {
return request({
url: `${url}/DeleteSysRoleById/${roleId}`,
method: 'delete'
})
}
// 批量删除角色
export const DeleteSysRoleByIdList = (rolelist) => {
return request({
url: `${url}/DeleteSysRoleByIdList`,
method: 'delete',
data : rolelist
})
}
补充:
1. 获取控件的所有属性,这里是获取每个迭代列的属性
Vue3 动态列 <el-table-column> 实现 formatter 的两种方法_eltablecolumn formatter-CSDN博客
-------用户管理-------
用户管理和角色管理一样,只是换了一个数据库表, 多了个上传头像, 就不细讲了,只说关键的
1.准备工作
创建:
编写界面:
代码
<template>
<!---搜索表单-->
<div class="search-div">
<el-form label-width="70px" size="small">
<el-row>
<el-col :span="12">
<el-form-item label="关键字">
<el-input
style="width: 100%"
placeholder="用户名"
></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="创建时间">
<el-date-picker
type="daterange"
range-separator="To"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
</el-form-item>
</el-col>
</el-row>
<el-row style="display:flex">
<el-button type="primary" size="small">
搜索
</el-button>
<el-button size="small">重置</el-button>
</el-row>
</el-form>
</div>
<!--添加按钮-->
<div class="tools-div">
<el-button type="success" size="small">添 加</el-button>
</div>
<!---数据表格-->
<el-table :data="list" style="width: 100%">
<el-table-column prop="userName" label="用户名" />
<el-table-column prop="name" label="姓名" />
<el-table-column prop="phone" label="手机" />
<el-table-column prop="avatar" label="头像" #default="scope">
<img :src="scope.row.avatar" width="50" />
</el-table-column>
<el-table-column prop="description" label="描述" />
<el-table-column prop="status" label="状态" #default="scope">
{{ scope.row.status == 1 ? '正常' : '停用' }}
</el-table-column>
<el-table-column prop="createTime" label="创建时间" />
<el-table-column label="操作" align="center" width="280" >
<el-button type="primary" size="small">
修改
</el-button>
<el-button type="danger" size="small">
删除
</el-button>
<el-button type="warning" size="small">
分配角色
</el-button>
</el-table-column>
</el-table>
<el-pagination
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next"
:total="total"
/>
</template>
<script setup>
import { ref } from 'vue';
// 表格数据模型
const list = ref([
{"id":1 , "userName":"admin" , "name": "admin" , "phone":"13121034567" , "status":1 , "createTime": "2023-05-11"} ,
{"id":2 , "userName":"admin" , "name": "admin" , "phone":"13121034567" , "status":1 , "createTime": "2023-05-11"}
]);
// 分页条数据模型
const total = ref(0)
</script>
<style scoped>
.search-div {
margin-bottom: 10px;
padding: 10px;
border: 1px solid #ebeef5;
border-radius: 3px;
background-color: #fff;
}
.tools-div {
margin: 10px 0;
padding: 10px;
border: 1px solid #ebeef5;
border-radius: 3px;
background-color: #fff;
}
.avatar-uploader .avatar {
width: 178px;
height: 178px;
display: block;
}
.avatar-uploader .el-upload {
border: 1px dashed var(--el-border-color);
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
transition: var(--el-transition-duration-fast);
}
.avatar-uploader .el-upload:hover {
border-color: var(--el-color-primary);
}
.el-icon.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
text-align: center;
}
</style>
2.前端代码
界面
<template>
<!---搜索表单-->
<div class="search-div">
<el-form label-width="70px" size="small">
<el-row>
<el-col :span="12">
<el-form-item label="关键字">
<el-input style="width: 100%" placeholder="用户名" v-model="thiss.SysUserDto.keyword"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="创建时间">
<el-date-picker
v-model="thiss.createTimes"
type="daterange"
range-separator="To"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD" />
</el-form-item>
</el-col>
</el-row>
<el-row style="display:flex">
<el-button type="primary" size="small" @click="gerthiss">
搜索
</el-button>
<el-button size="small" @click="breaks">重置</el-button>
</el-row>
</el-form>
</div>
<!--添加按钮-->
<div class="tools-div">
<el-button type="success" size="small" @click="newUsers">添 加</el-button>
</div>
<el-dialog v-model="thiss.dialogVisible" title="添加或修改" width="40%">
<el-form label-width="120px">
<el-form-item label="用户名">
<el-input v-model="thiss.user.username"/>
</el-form-item>
<el-form-item label="密码">
<el-input type="password" show-password v-model="thiss.user.password"/>
</el-form-item>
<el-form-item label="姓名">
<el-input v-model="thiss.user.name"/>
</el-form-item>
<el-form-item label="手机">
<el-input v-model="thiss.user.phone"/>
</el-form-item>
<el-form-item label="头像">
<!-- 获取请求token上传图片 -->
<el-upload
class="avatar-uploader"
action="http://localhost:10001/admin/system/user/userTX"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:headers="headers"
>
<img v-if="thiss.user.avatar" :src="thiss.user.avatar" class="avatar" />
<el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
</el-upload>
</el-form-item>
<el-form-item label="描述">
<el-input v-model="thiss.user.description"/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="newandup">提交</el-button>
<el-button @click="thiss.dialogVisible = false">取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
<!---数据表格-->
<el-table :data="thiss.userl" style="width: 100%">
<el-table-column type=index label="序列" width="80"/>
<el-table-column prop="id" label="ID" />
<el-table-column prop="username" label="用户名" />
<el-table-column prop="name" label="姓名" />
<el-table-column prop="phone" label="手机" />
<el-table-column prop="avatar" label="头像" #default="scope">
<img :src="scope.row.avatar" width="50" />
</el-table-column>
<el-table-column prop="description" label="描述" />
<el-table-column prop="status" label="状态" #default="scope">
{{ scope.row.status == 1 ? '正常' : '停用' }}
</el-table-column>
<el-table-column prop="createTime" label="创建时间" />
<el-table-column label="操作" align="center" width="280" #default="scope">
<el-button type="primary" size="small" @click="dataUpUsers(scope)">
修改
</el-button>
<el-button type="danger" size="small" @click="deleteUsers(scope)">
删除
</el-button>
<el-button type="warning" size="small" @click="fpjs(scope)">
分配角色
</el-button>
</el-table-column>
</el-table>
<!-- 分配弹窗 -->
<el-dialog v-model="thiss.dialogRoleVisible" title="分配角色" width="40%">
<el-form label-width="80px">
<el-form-item label="用户名">
<el-input disabled :value="thiss.user.username"></el-input>
</el-form-item>
<el-form-item label="角色列表">
<el-checkbox-group v-model="thiss.userRoleId">
<el-checkbox v-for="role in thiss.userRoleIds" :key="role.id" :label="role.id">
{{ role.roleName }}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="fpjstj">提交</el-button>
<el-button @click="thiss.dialogRoleVisible = false">取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
<!--分页条 @是绑定按钮的方法 , v-model是绑定参数-->
<!--监听分页,换页,和字符-->
<el-pagination :page-sizes="[10, 2, 20, 50, 100]" layout="total, sizes, prev, pager, next"
:total="thiss.total"
@size-change="getrolelest"
@current-change="getrolelest"
v-model:current-page="thiss.pageNum"
v-model:page-size="thiss.pageSize" />
</template>
<script setup>
import {
ref,
reactive,
getCurrentInstance,
onMounted
} from 'vue';
import { Md5 } from 'ts-md5';
//引入api接口
import { GetUser , newUser ,deleteUser,dataUpUser ,inUserByRole , selectUserByRole} from '@/api/user';
import { GetRole } from '@/api/role';
//token接口
import { useApp } from '@/pinia/modules/app'
const { proxy: ctx } = getCurrentInstance() // 可以把ctx当成vue2中的this
// // 表格数据模型
// const list = ref([
// { "id": 1, "username": "admin", "name": "admin", "phone": "13121034567", "status": 1, "createTime": "2023-05-11" },
// { "id": 2, "username": "admin", "name": "admin", "phone": "13121034567", "status": 1, "createTime": "2023-05-11" }
// ]);
// // 分页条数据模型
// const total = ref(0)
//用户相关参数
const thiss = reactive({
//user列表
userl:[],
//一个user,上传使用
user: {
id: null,
password:'',
username: "",
name: "",
phone: "",
avatar:"",
status: 1
},
//当前页码
pageNum: 1,
//当前显示页码
pageSize: 10,
// 分页条总记录数
total: 0,
//搜索 -- 对于搜索接口
SysUserDto:{
//搜索文本
keyword:'',
//开始接受时间 createTimes的数组下标0是开始,1是介结束
createTimeBegin:'',
createTimeEnd:''
},
//搜索时间页面参数
createTimes:[],
//控制添加框框
dialogVisible:false,
//分配角色框框
dialogRoleVisible:false,
//所有分配角色列表
userRoleIds:[],
//选中的角色
userRoleId:[],
})
// 组件加载钩子,也就是启动函数
onMounted(async () => {
gerthiss()
//调用角色列表接口
const { code, message, data } = await GetRole(1, 0,{roleName: ''});
if (+code == 200) {
thiss.userRoleIds=data.list
ctx.$message.success(message)
} else {
ctx.$message.error(message)
}
})
//分页器按钮:
const getrolelest = () => {
//重置搜索文本和时间
thiss.SysUserDto. keyword = ''
thiss.createTimes = []
gerthiss()
}
//重置
const breaks = () => {
//重置搜索文本和时间,和分页器
thiss.SysUserDto. keyword = ''
thiss.createTimes = []
thiss.pageNum=1
thiss.pageSize=10
thiss.total=0
gerthiss()
}
//搜索接口,也是列表
const gerthiss = async ()=>{
thiss.SysUserDto.createTimeBegin = thiss.createTimes[0]
thiss.SysUserDto.createTimeEnd = thiss.createTimes[1]
//发送 thiss.SysUserDto
const { code, message, data } = await GetUser(thiss.pageNum , thiss.pageSize, thiss.SysUserDto)
if (+code == 200) {
//更新列表
thiss.userl = data.list
thiss.pageNum = data.pageNum
thiss.pageSize = data.pageSize
thiss.total = data.total
ctx.$message.success(message)
} else {
ctx.$message.error(message)
}
}
//删除按钮
const deleteUsers = async data =>{
//发送取出来的 id
const { code, message } = await deleteUser(data.row.id)
if (+code == 200) {
//更新列表
breaks()
ctx.$message.success(message)
} else {
ctx.$message.error(message)
}
}
//修啊按钮
const dataUpUsers = data =>{
thiss.user= data.row
thiss.user.password = ''
thiss.dialogVisible = true
}
// 添加按钮
const newUsers = ()=>{
thiss.user = {
id: null,
password:"",
username: "",
name: "",
phone: "",
status: 1
}
thiss.dialogVisible = true
}
//修改和,添加功能
const newandup = async ()=>{
// 密码转md5
const md5 = new Md5()
thiss.user.password = md5.appendAsciiStr(thiss.user.password ).end()
// 等于空是添加,不是就是修改
const { code, message } = thiss.user.id == null ? await newUser(thiss.user) : await dataUpUser(thiss.user)
if (+code == 200) {
//更新列表
breaks()
thiss.dialogVisible = false
ctx.$message.success(message)
} else {
ctx.$message.error(message)
}
}
const headers = {
token: useApp().authorization.token // 从pinia中获取token,在进行文件上传的时候将token设置到请求头中
}
// 图像上传成功以后的事件处理函数
const handleAvatarSuccess = (response, uploadFile) => {
console.log(response.data);
thiss.user.avatar = response.data
}
//分配角色
const fpjs = async datas =>{
thiss.user= datas.row
//查询现在的分配
const { code, message, data } = await selectUserByRole(datas.row.id);
if (+code == 200) {
thiss.userRoleId = data
ctx.$message.success(message)
} else {
ctx.$message.error(message)
}
thiss.dialogRoleVisible = true
}
//分配角色提交
const fpjstj = async () =>{
//thiss.user角色信息
const { code, message, data } = await inUserByRole(thiss.user.id , thiss.userRoleId );
if (+code == 200) {
ctx.$message.success(message)
} else {
ctx.$message.error(message)
}
}
</script>
<style scoped>
.search-div {
margin-bottom: 10px;
padding: 10px;
border: 1px solid #ebeef5;
border-radius: 3px;
background-color: #fff;
}
.tools-div {
margin: 10px 0;
padding: 10px;
border: 1px solid #ebeef5;
border-radius: 3px;
background-color: #fff;
}
.avatar-uploader .avatar {
width: 178px;
height: 178px;
display: block;
}
.avatar-uploader .el-upload {
border: 1px dashed var(--el-border-color);
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
transition: var(--el-transition-duration-fast);
}
.avatar-uploader .el-upload:hover {
border-color: var(--el-color-primary);
}
.el-icon.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
text-align: center;
}
</style>
<!--
if (+code == 200) {
ctx.$message.success(message)
} else {
ctx.$message.error(message)
}
-->
接口
//引入统一请求封装
import request from '@/utils/request'
//api接口常量
const url = '/zx/admin/system/user'
// 查询接口
export const GetUser = (page,quantity,datas) => {
return request({
//在js里`表示字符串拼接${}是个表达式
url: `${url}/getUserList/${page}/${quantity}`,
method: 'post',
//如果后端是@RequestBody则这里要加data
//否则是 params
data : datas ,
})
}
// 添加角色请求方法
export const newUser = (data) => {
return request({
url: `${url}/newUser`,
method: 'post',
data
})
}
// 修改角色请求方法
export const dataUpUser = (data) => {
return request({
url: `${url}/dataUpUser`,
method: 'put',
data
})
}
// 删除角色
export const deleteUser = (roleId) => {
return request({
url: `${url}/deleteUser/${roleId}`,
method: 'delete'
})
}
// 查询用户分配的角色返回[]
export const selectUserByRole = (userid) => {
return request({
url: `${url}/selectUserByRole/${userid}`,
method: 'get',
})
}
//修改用户的角色信息
export const inUserByRole = (userid , userList) => {
return request({
url: `${url}/inUserByRole/${userid}`,
method: 'post',
data: userList
})
}
学习技术:
- 头像上传
- 时间搜索
- 分配角色的回调显示
3.后端:
controller接口
package com.zhexin.manage.controller;
import com.github.pagehelper.PageInfo;
import com.zhexin.manage.service.SysRoleUserService;
import com.zhexin.manage.service.SysUser.*;
import com.zhexin.model.dto.system.SysUserDto;
import com.zhexin.model.entity.system.SysUser;
import com.zhexin.model.vo.common.Result;
import com.zhexin.model.vo.common.ResultCodeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@Tag(name = "角色管理接口") //swagger文档注释
@RestController //注册到bean
@RequestMapping("/admin/system/user") //注册访问路径
public class SysUserController {
@Autowired
SysUserSelectService sysUserSelectService;
@Autowired
DeleteSysUserService deleteSysUserService;
@Autowired
NewUserService newUserService;
@Autowired
DataUpUserService dataUpUserService;
@Autowired
UserTX userTX;
@Autowired
SysRoleUserService sysRoleUserService;
@Operation(summary = "用户查询接口") //文档注释
@PostMapping("/getUserList/{page}/{quantity}")
public Result getUserList(
@PathVariable Integer page,
@PathVariable Integer quantity,
@RequestBody SysUserDto sysUserDto
) {
PageInfo<SysUser> jg = sysUserSelectService.SysUserByName(page, quantity, sysUserDto);
return Result.build(jg, ResultCodeEnum.SUCCESS);
}
@Operation(summary = "删除用户接口") //文档注释
@DeleteMapping("/deleteUser/{id}")
public Result deleteUser(@PathVariable Long id) {
boolean jg = deleteSysUserService.DeleteSysUser(id);
return Result.build(jg, ResultCodeEnum.SUCCESS);
}
@Operation(summary = "新增用户") //文档注释
@PostMapping("/newUser")
public Result newUser(@RequestBody SysUser sysUser) { //请求的json参数
boolean jg = newUserService.NewUser(sysUser);
return Result.build(jg, ResultCodeEnum.SUCCESS);
}
@Operation(summary = "修改用户") //文档注释
@PutMapping("/dataUpUser")
public Result dataUpUser(@RequestBody SysUser sysUser) { //请求的json参数
boolean jg = dataUpUserService.dataUpUser(sysUser);
return Result.build(jg, ResultCodeEnum.SUCCESS);
}
@Operation(summary = "上传用户头像") //文档注释
@RequestMapping("/userTX") //接收符合条件的任何请求 方式
public Result<String> userTX(@RequestParam MultipartFile file) { //这里的参数名必须是file
String jg = userTX.FileUploader(file);
return Result.build(jg , ResultCodeEnum.SUCCESS) ;
}
@Operation(summary = "查询用户的角色信息") //文档注释
@GetMapping("/selectUserByRole/{userid}") //接收符合条件的任何请求 方式
public Result<String> selectUserByRole(@PathVariable Long userid) {
List<Long> sysRoleUser = sysRoleUserService.selectUserByRole(userid);
return Result.build(sysRoleUser , ResultCodeEnum.SUCCESS) ;
}
@Operation(summary = "删除用户的角色信息") //文档注释
@DeleteMapping("/deleteUserByID/{userid}") //接收符合条件的任何请求 方式
public Result<String> deleteUserByID(@PathVariable Long userid) {
boolean sysRoleUser = sysRoleUserService.deleteUserByID(userid);
return Result.build(sysRoleUser , ResultCodeEnum.SUCCESS) ;
}
@Operation(summary = "修改新的用户角色信息") //文档注释
@PostMapping("/inUserByRole/{userId}") //接收符合条件的任何请求 方式
public Result<String> inUserByRole(@PathVariable("userId") Long userId ,
@RequestBody List<Long> userRoleId) { //这里的参数名,必须与前端保持一致
boolean jg = sysRoleUserService.inUserByRole(userId , userRoleId);
return Result.build(jg , ResultCodeEnum.SUCCESS) ;
}
}
用户头像上传service, minio
package com.zhexin.manage.service.SysUser.Impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import com.zhexin.common.service.exception.zhexinException;
import com.zhexin.manage.properties.MinioProperties;
import com.zhexin.manage.service.SysUser.UserTX;
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.errors.MinioException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
@Service
public class UserTXImpl implements UserTX {
@Autowired
MinioProperties minioProperties;
//springMVC中的文件上传工具MultipartFile
public String FileUploader(MultipartFile multipartFile) {
try {
//创建连接
MinioClient minioClient =
MinioClient.builder()
.endpoint(minioProperties.getUrl())
.credentials(minioProperties.getZh(), minioProperties.getMm())
.build();
// 判断是否存在容器,否则创建
boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(minioProperties.getRqname()).build());
if (!found) {
// 创建容器
minioClient.makeBucket(MakeBucketArgs.builder().bucket(minioProperties.getRqname()).build());
}
// 设置存储对象名称
String dateDir = DateUtil.format(new Date(), "yyyyMMdd");
String uuid = UUID.randomUUID().toString().replace("-", "");
//20230801/443e1e772bef482c95be28704bec58a901.jpg
String fileName = dateDir+"/"+uuid+multipartFile.getOriginalFilename();
//把文件写入容器
PutObjectArgs putObjectArgs = PutObjectArgs.builder()
.bucket(minioProperties.getRqname())
.object(fileName)
.stream(multipartFile.getInputStream(),multipartFile.getSize(),-1)
.build();
//发送
minioClient.putObject(putObjectArgs) ;
//要在Minio里设置这个桶的权限为public 才能访问到图片,如果访问地址得不到图片的话
//http://127.0.0.1:9000/usertx/20231212/8f4cf52b13f74d8a87511e147c67cbedv2-4c534c96dc62e9f541473ea2f5e73fd5_r.png
return minioProperties.getUrl() + "/" + minioProperties.getRqname() + "/" + fileName ;
} catch (MinioException |
IOException |
NoSuchAlgorithmException |
InvalidKeyException |
MaxUploadSizeExceededException
ee ){
throw new zhexinException(201, "图片上传失败!大小不得超过5MB");
}
}
}
分配角色service
package com.zhexin.manage.service.Impl;
import com.zhexin.common.service.exception.zhexinException;
import com.zhexin.manage.mapper.SysRoleUser.SysRoleUserMapper;
import com.zhexin.manage.service.SysRoleUserService;
import com.zhexin.model.entity.system.SysRoleUser;
import com.zhexin.model.vo.common.ResultCodeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class SysRoleUserServiceImpl implements SysRoleUserService {
@Autowired
SysRoleUserMapper sysRoleUserMapper;
//查
@Override
public List<Long> selectUserByRole(Long userid) {
List<Long> LongList = new ArrayList<>(); //初始化
if (userid == null ) { //判断不为空
throw new zhexinException(ResultCodeEnum.CSWK);
}
List<SysRoleUser> sysRoleUsersList = sysRoleUserMapper.selectUserByRole(userid); //调用查询
sysRoleUsersList.forEach(sysRoleUser -> {
LongList .add(sysRoleUser.getRoleId());
});
return LongList;
}
//添加
@Override
public boolean inUserByRole(Long userId, List<Long> roleidl) {
//初始化
boolean jg = false;
if (roleidl.isEmpty() || userId == null ) { //判断不为空
throw new zhexinException(ResultCodeEnum.CSWK);
}
//查询原先userid的id
List<SysRoleUser> yid = sysRoleUserMapper.selectUserByRole(userId);
if (!yid.isEmpty()) { //判断不为空
//删除所有原先的 -- id
boolean deleteJg = this.deleteUserByID(userId);
if (!deleteJg) {
throw new zhexinException(ResultCodeEnum.CSWK);
}
}
//放入最新的 -- list
for (Long roleid : roleidl) {
jg = sysRoleUserMapper.inUserByRole(userId, roleid);
if (!jg) {
throw new zhexinException(ResultCodeEnum.CSWK);
}
}
return jg;
}
@Override
public boolean deleteUserByID(Long userid) {
boolean jg = false; //初始化
if (userid == null ) { //判断不为空
throw new zhexinException(ResultCodeEnum.CSWK);
}
jg = sysRoleUserMapper.deleteUserByID(userid);
return jg;
}
}
分配角色mapper
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--对应的接口别弄错了-->
<mapper namespace="com.zhexin.manage.mapper.SysRoleUser.SysRoleUserMapper">
<!--映射到SysRole里面, autoMapping为自动映射-->
<select id="selectUserByRole" resultType="com.zhexin.model.entity.system.SysRoleUser" >
SELECT role_id roleId , user_id userId
FROM sys_user_role
WHERE user_id = #{userid}
</select>
<insert id="inUserByRole" parameterType="long">
INSERT INTO sys_user_role
(role_id, user_id )
VALUES
(#{roleId}, #{userId} )
</insert>
<delete id="deleteUserByID" >
DELETE FROM sys_user_role WHERE user_id = #{userid}
</delete>
</mapper>
-------菜单管理-------
后端主要代码:
1.递归实现分类列表格式:
工具类
package com.zhexin.common.uilt.Service;
import com.zhexin.model.entity.system.SysMenu;
import java.util.ArrayList;
import java.util.List;
public class MenuHelper {
private List<SysMenu> menuLs = null;
/**
* 使用递归方法建菜单
* @param sysMenuList
* @return
*/
public static List<SysMenu> buildTree(List<SysMenu> sysMenuList) {
List<SysMenu> trees = new ArrayList<>();
for (SysMenu sysMenu : sysMenuList) {
if (sysMenu.getParentId().longValue() == 0) {
trees.add(findChildren(sysMenu,sysMenuList));
}
}
return trees;
}
/**
* 递归查找子节点
* @param treeNodes
* @return
*/
public static SysMenu findChildren(SysMenu sysMenu, List<SysMenu> treeNodes) {
sysMenu.setChildren(new ArrayList<SysMenu>());
for (SysMenu it : treeNodes) {
if(sysMenu.getId().longValue() == it.getParentId().longValue()) {
//if (sysMenu.getChildren() == null) {
// sysMenu.setChildren(new ArrayList<>());
//}
sysMenu.getChildren().add(findChildren(it,treeNodes));
}
}
return sysMenu;
}
//递归查询列表开始
public static List<SysMenu> selectList(List<SysMenu> sysMenuList){
//初始化结果容器
List<SysMenu> wai = new ArrayList<>();
//循环所有,作为子列表
for (SysMenu zmenuL : sysMenuList) {
if (zmenuL.getParentId() == 0) { //第一列
//添加2级的子列
selectSysMenu(zmenuL ,sysMenuList);
//加入队列
wai.add(zmenuL);
}
}
return wai;
}
private static SysMenu selectSysMenu(SysMenu fsysMenu ,List<SysMenu> sysMenuList){
if (fsysMenu.getChildren() == null){
//初始化容器
fsysMenu.setChildren(new ArrayList<>());
}
//循环所有,作为子列表
for (SysMenu zmenuL : sysMenuList) {
if (zmenuL.getParentId() == fsysMenu.getId()) {
//递归添加X级的子列
selectSysMenu(zmenuL,sysMenuList);
//加入X队列
fsysMenu.getChildren().add(zmenuL);
}
}
//本次递归的层级
return fsysMenu;
}
}
service
package com.zhexin.manage.service.sysMenu.Impl;
import cn.hutool.core.util.StrUtil;
import com.zhexin.common.service.exception.zhexinException;
import com.zhexin.common.uilt.Service.MenuHelper;
import com.zhexin.common.uilt.Thread.ThreadlocalUser;
import com.zhexin.manage.mapper.sysMenu.sysMenuMapper;
import com.zhexin.manage.service.sysMenu.sysMenuService;
import com.zhexin.model.entity.system.SysMenu;
import com.zhexin.model.entity.system.SysUser;
import com.zhexin.model.vo.common.ResultCodeEnum;
import com.zhexin.model.vo.system.SysMenuVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.LinkedList;
import java.util.List;
@Service
public class sysMenuServiceImpl implements sysMenuService {
@Autowired
private sysMenuMapper sysMenuMapper;
//递归查询列表开始
@Override
public List<SysMenu> selectList(){
//初始化结果容器
List<SysMenu> wai = null;
//数据库查询结果
List<SysMenu> sysMenus = sysMenuMapper.selectSysMenu();
//循环所有,作为子列表
wai = MenuHelper.selectList(sysMenus);
return wai;
}
@Override
public void save(SysMenu sysMenu) {
if (sysMenu.getStatus() == null ||
sysMenu.getSortValue() == null ||
StrUtil.isEmpty(sysMenu.getTitle()) ||
StrUtil.isEmpty(sysMenu.getComponent()) ){
throw new zhexinException(ResultCodeEnum.CSCW);
}
// 添加新的节点
sysMenuMapper.insert(sysMenu) ;
// 新添加一个菜单,那么此时就需要将该菜单所对应的父级菜单设置为半开
updateSysRoleMenuIsHalf(sysMenu) ;
}
@Override
public void updateById(SysMenu sysMenu) {
sysMenuMapper.updateById(sysMenu) ;
}
@Override
public void removeById(Long id) {
int count = sysMenuMapper.countByParentId(id); // 先查询是否存在子菜单,如果存在不允许进行删除
if (count > 0) {
throw new zhexinException(ResultCodeEnum.NODE_ERROR);
}
sysMenuMapper.deleteById(id); // 不存在子菜单直接删除
}
@Override
public List<SysMenuVo> findUserMenuList() {
SysUser sysUser = ThreadlocalUser.getSysUser();
Long userId = sysUser.getId(); // 获取当前登录用户的id
List<SysMenu> sysMenuList = sysMenuMapper.selectListByUserId(userId) ;
//构建树形数据
List<SysMenu> sysMenuTreeList = MenuHelper.buildTree(sysMenuList);
return this.buildMenus(sysMenuTreeList);
}
// 将List<SysMenu>对象转换成List<SysMenuVo>对象
private List<SysMenuVo> buildMenus(List<SysMenu> menus) {
List<SysMenuVo> sysMenuVoList = new LinkedList<SysMenuVo>();
for (SysMenu sysMenu : menus) {
SysMenuVo sysMenuVo = new SysMenuVo();
sysMenuVo.setTitle(sysMenu.getTitle());
sysMenuVo.setName(sysMenu.getComponent());
List<SysMenu> children = sysMenu.getChildren();
if (!CollectionUtils.isEmpty(children)) {
sysMenuVo.setChildren(buildMenus(children));
}
sysMenuVoList.add(sysMenuVo);
}
return sysMenuVoList;
}
private void updateSysRoleMenuIsHalf(SysMenu sysMenu) {
// 查询是否存在父节点
SysMenu parentMenu = sysMenuMapper.selectById(sysMenu.getParentId());
if(parentMenu != null) {
// 将该id的菜单设置为半开
sysMenuMapper.updateSysRoleMenuIsHalf(parentMenu.getId()) ;
// 递归调用
updateSysRoleMenuIsHalf(parentMenu) ;
}
}
}
2.多表查询sql
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--对应的接口别弄错了-->
<mapper namespace="com.zhexin.manage.mapper.sysMenu.sysMenuMapper">
<resultMap id="sysMenuMap" type="com.zhexin.model.entity.system.SysMenu" autoMapping="true"></resultMap>
<!-- 用于select查询公用抽取的列 -->
<sql id="columns">
id,parent_id,title,component,sort_value,status,create_time,update_time,is_deleted
</sql>
<select id="selectSysMenu" resultType="com.zhexin.model.entity.system.SysMenu">
SELECT * FROM sys_menu
WHERE is_deleted = 0
</select>
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
insert into sys_menu
(id, parent_id, title, component, sort_value, status)
values
(#{id}, #{parentId}, #{title}, #{component}, #{sortValue}, #{status})
</insert>
<update id="updateById" >
update sys_menu set
<if test="parentId != null and parentId != ''">
parent_id = #{parentId},
</if>
<if test="title != null and title != ''">
title = #{title},
</if>
<if test="component != null and component != ''">
component = #{component},
</if>
<if test="sortValue != null">
sort_value = #{sortValue},
</if>
<if test="status != null">
status = #{status},
</if>
update_time = now()
where
id = #{id}
</update>
<select id="countByParentId" resultType="Integer">
select count(id)
from sys_menu
where
parent_id = #{parentId}
and is_deleted = 0
</select>
<update id="deleteById">
update sys_menu set
update_time = now() ,
is_deleted = 1
where
id = #{id}
</update>
<select id="selectById" resultMap="sysMenuMap">
select <include refid="columns" /> from sys_menu where id = #{id}
</select>
<select id="updateSysRoleMenuIsHalf">
update sys_role_menu srm set srm.is_half = 1 where menu_id = #{menuId}
</select>
<select id="selectListByUserId" resultMap="sysMenuMap">
SELECT DISTINCT m.* FROM sys_menu m
INNER JOIN sys_role_menu rm ON rm.menu_id = m.id
INNER JOIN sys_user_role ur ON ur.role_id = rm.role_id
WHERE ur.user_id=#{userId} and m.is_deleted = 0
</select>
</mapper>
用户菜单:
Mapper
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhexin.manage.mapper.Sysjh.SysRoleMenuMapper">
<select id="findSysRoleMenuByRoleId" resultType="long">
select menu_id
from sys_role_menu
where role_id = #{roleId}
and is_deleted = 0
and is_half = 0
</select>
<delete id="deleteByRoleId">
delete from sys_role_menu where role_id = #{roleId}
</delete>
<insert id="doAssign">
insert into sys_role_menu (
role_id,menu_id,create_time , update_time , is_deleted , is_half
) values
<foreach collection="menuIdList" item="menuInfo" separator=",">
(#{roleId} , #{menuInfo.id} , now() , now() , 0 , #{menuInfo.isHalf})
</foreach>
</insert>
</mapper>
service
package com.zhexin.manage.service.Sysjh.Impl;
import com.zhexin.common.uilt.Service.MenuHelper;
import com.zhexin.manage.mapper.Sysjh.SysRoleMenuMapper;
import com.zhexin.manage.mapper.sysMenu.sysMenuMapper;
import com.zhexin.manage.service.Sysjh.SysRoleMenuService;
import com.zhexin.model.dto.system.AssginMenuDto;
import com.zhexin.model.entity.system.SysMenu;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class SysRoleMenuServiceImpl implements SysRoleMenuService {
@Autowired
private sysMenuMapper sysMenuMapper;
@Autowired
private SysRoleMenuMapper sysRoleMenuMapper;
@Override
public Map<String, Object> findSysRoleMenuByRoleId(Long roleId) {
// 查询所有的菜单数据
List<SysMenu> sysMenuList = sysMenuMapper.selectSysMenu();
//列表加工
sysMenuList = MenuHelper.selectList(sysMenuList);
// 查询当前角色的菜单数据
List<Long> roleMenuIds = sysRoleMenuMapper.findSysRoleMenuByRoleId(roleId) ;
// 将数据存储到Map中进行返回
Map<String , Object> result = new HashMap<>() ;
result.put("sysMenuList" , sysMenuList) ;
result.put("roleMenuIds" , roleMenuIds) ;
// 返回
return result;
}
@Transactional
@Override
public void doAssign(AssginMenuDto assginMenuDto) {
// 根据角色的id删除其所对应的菜单数据
sysRoleMenuMapper.deleteByRoleId(assginMenuDto.getRoleId());
// 获取菜单的id
List<Map<String, Number>> menuInfo = assginMenuDto.getMenuIdList();
if(menuInfo != null && menuInfo.size() > 0) {
sysRoleMenuMapper.doAssign(assginMenuDto) ;
}
}
}
Controller
controller
package com.zhexin.manage.controller;
import com.zhexin.manage.service.sysMenu.sysMenuService;
import com.zhexin.model.entity.system.SysMenu;
import com.zhexin.model.vo.common.Result;
import com.zhexin.model.vo.common.ResultCodeEnum;
import com.zhexin.model.vo.system.SysMenuVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Tag(name = "用户接口") //swagger文档注释
@RestController //注册到bean
@RequestMapping("/admin/system/menu") //注册访问路径
public class SysMenuController {
@Autowired
private sysMenuService sysMenuService;
@Operation(summary = "获取树形列表") //文档注释
@GetMapping("/getlist")
public Result getlist(){
List<SysMenu> sysMenus = sysMenuService.selectList();
return Result.build(sysMenus , ResultCodeEnum.SUCCESS);
}
@Operation(summary = "添加子菜单") //文档注释
@PostMapping("/save")
public Result save(@RequestBody SysMenu sysMenu) {
sysMenuService.save(sysMenu);
return Result.build(null , ResultCodeEnum.SUCCESS) ;
}
@Operation(summary = "修改菜单") //文档注释
@PutMapping("/updateById")
public Result updateById(@RequestBody SysMenu sysMenu) {
sysMenuService.updateById(sysMenu);
return Result.build(null , ResultCodeEnum.SUCCESS) ;
}
@Operation(summary = "删除菜单") //文档注释
@DeleteMapping("/removeById/{id}")
public Result removeById(@PathVariable Long id) {
sysMenuService.removeById(id);
return Result.build(null , ResultCodeEnum.SUCCESS) ;
}
@Operation(summary = "动态菜单") //文档注释
@GetMapping("/menus")
public Result menus() {
List<SysMenuVo> sysMenuVoList = sysMenuService.findUserMenuList() ;
return Result.build(sysMenuVoList , ResultCodeEnum.SUCCESS) ;
}
}
还有一部分在之前的写的controller里,实现分配角色或者分配菜单,都是普通的增删改查,就不必显示了
前端:
由于需要分配角色,所以前面的代码都有所改变:
首先修改路由,静态路由改成动态路由:
menu.js
修改/src/api/menu.js中的请求地址,如下所示:
// 获取菜单
export const GetMenus = params => {
return request({
url: '/admin/system/index/menus',
method: 'get',
params,
})
}
index.js
更改src/router/index.js固定参数和异步菜单的路由加载:
// 固定菜单
export const fixedRoutes = [...home]
// 动态菜单
export const asyncRoutes = [...system]
menu.js
修改pinia/modules/menu.js中的generateMenus方法,注释掉方式一菜单加载,打开方式二菜单加载。
const generateMenus = async () => {
// // 方式一:只有固定菜单
// const menus = getFilterMenus(fixedRoutes)
// setMenus(menus)
// 方式二:有动态菜单
// 从后台获取菜单
const { code, data } = await GetMenus()
if (+code === 200) {
// 添加路由之前先删除所有动态路由
asyncRoutes.forEach(item => {
router.removeRoute(item.name)
})
// 过滤出需要添加的动态路由
const filterRoutes = getFilterRoutes(asyncRoutes, data)
filterRoutes.forEach(route => router.addRoute(route))
// 生成菜单
const menus = getFilterMenus([...fixedRoutes, ...filterRoutes])
setMenus(menus)
}
}
界面:
sysMenu
<template>
<div class="tools-div">
<el-button type="success" size="small" @click="addShow">添 加</el-button>
</div>
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="30%">
<el-form label-width="120px">
<el-form-item label="菜单标题">
<el-input v-model="sysMenu.title"/>
</el-form-item>
<el-form-item label="路由名称">
<el-input v-model="sysMenu.component"/>
</el-form-item>
<el-form-item label="排序" >
<el-input v-model="sysMenu.sortValue"/>
</el-form-item>
<el-form-item label="状态">
<el-radio-group v-model="sysMenu.status">
<el-radio :label="1">正常</el-radio>
<el-radio :label="0">停用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="saveOrUpdate">提交</el-button>
<el-button @click="dialogVisible = false">取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
<el-table
:data="list"
style="width: 100%; margin-bottom: 20px"
row-key="id"
border
default-expand-all
>
<el-table-column prop="title" label="菜单标题" />
<el-table-column prop="component" label="路由名称" />
<el-table-column prop="sortValue" label="排序" />
<el-table-column prop="status" label="状态" #default="scope">
{{ scope.row.status == 1 ? '正常' : '停用' }}
</el-table-column>
<el-table-column prop="createTime" label="创建时间" />
<el-table-column label="操作" align="center" width="280" #default="scope" >
<el-button type="success" size="small" @click="addShow(scope.row)">
添加下级节点
</el-button>
<el-button type="primary" size="small" @click="editShow(scope.row)">
修改
</el-button>
<el-button type="danger" size="small" @click="remove(scope.row.id)">
删除
</el-button>
</el-table-column>
</el-table>
</template>
<script setup>
//引入调用的方法
import { ref , onMounted } from "vue"
import { FindNodes , SaveMenu , UpdateSysMenuById ,RemoveSysMenuById } from '@/api/sysMenu'
import { ElMessage, ElMessageBox } from 'element-plus'
// 定义表格数据模型
const list = ref([])
// 定义添加表单菜单表单相关数据模型
const dialogTitle = ref('添加')
const dialogVisible = ref(false)
//页面表单数据
const defaultForm = {
id: '',
parentId: 0,
title: '',
url: '',
component: '',
icon: '',
sortValue: 1,
status: 1,
}
// 表单响应式数据模型对象
const sysMenu = ref(defaultForm)
//=======================加载数据=========================
onMounted(() => {
fetchData()
})
//=======================添加和修改功能====================
//进入添加
const addShow = (row) => {
sysMenu.value = {}
dialogVisible.value = true
if(!row.id) {
dialogTitle.value = '添加'
}else {
dialogTitle.value = '添加下级节点'
sysMenu.value.parentId = row.id
}
}
//进入修改
const editShow = row => {
sysMenu.value = row
dialogVisible.value = true
}
//提交保存与修改
const saveOrUpdate = () => {
if (!sysMenu.value.id) {
if(!sysMenu.value.parentId) {
sysMenu.value.parentId = 0
}
saveData()
} else {
updateData()
}
}
// 修改
const updateData = async () => {
await UpdateSysMenuById(sysMenu.value)
dialogVisible.value = false
ElMessage.success('操作成功')
fetchData()
}
// 新增
const saveData = async () => {
const { code, message } = await SaveMenu(sysMenu.value)
if (+code == 200) {
//更新列表
dialogVisible.value = false
fetchData()
ElMessage.success(message)
} else {
ElMessage.error(message)
}
}
//=======================分页列表====================
const fetchData = async () => {
const { code, data, message } = await FindNodes()
list.value = data
}
//=======================删除功能====================
const remove = async id => {
console.log('removeDataById:' + id)
ElMessageBox.confirm('此操作将永久删除该记录, 是否继续?', 'Warning', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(async () => {
const { code , message } = await RemoveSysMenuById(id)
if(code === 200) {
ElMessage.success('删除成功')
fetchData()
}else {
ElMessage.error(message)
}
})
}
</script>
<style scoped>
.search-div {
margin-bottom: 10px;
padding: 10px;
border: 1px solid #ebeef5;
border-radius: 3px;
background-color: #fff;
}
.tools-div {
margin: 10px 0;
padding: 10px;
border: 1px solid #ebeef5;
border-radius: 3px;
background-color: #fff;
}
</style>
sysRole
<template>
<div class="search-div">
<!-- 搜索表单 -->
<el-form label-width="70px" size="small">
<el-form-item label="角色名称">
<el-input style="width: 100%" placeholder="角色名称" v-model="thiss.sysRoleDto.roleName"></el-input>
</el-form-item>
<el-row style="display:flex">
<el-button type="primary" size="small" @click="getrolelest()">
搜索
</el-button>
<el-button size="small" @click=" reset()">重置</el-button>
</el-row>
</el-form>
<!-- 添加按钮 -->
<div class="tools-div">
<el-button type="success" size="small" @click="addShow">添 加</el-button>
<el-button type="danger" size="small" @click="Statebutter()">批量删除</el-button>
</div>
<!-- 添加角色表单对话框 -->
<el-dialog v-model="thiss.dialogVisible" title="添加或修改角色" width="30%">
<el-form label-width="120px">
<el-form-item label="角色名称">
<el-input v-model="thiss.uprole.roleName" />
</el-form-item>
<el-form-item label="角色Code">
<el-input v-model="thiss.uprole.roleCode" />
</el-form-item>
<el-form-item label="描述">
<el-input v-model="thiss.uprole.description" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="upRole">提交</el-button>
<el-button @click="thiss.dialogVisible = false">取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
<!--- 角色表格数据 -->
<el-table :data="thiss.list" ref="ElTableref" style="width: 100%">
<el-table-column type="selection" width="55" />
<el-table-column type="index" label="序列" width="80" />
<el-table-column prop="id" label="用户ID" :sortable="true" />
<el-table-column property="roleName" label="角色名称" width="180" />
<el-table-column prop="roleCode" label="角色code" width="180" />
<el-table-column prop="description" label="描述" />
<el-table-column prop="createTime" label="创建时间" :sortable="true" />
<el-table-column prop="updateTime" label="更新时间" :sortable="true" />
<el-table-column prop="isDeleted" label="状态" :formatter="statusFilter()" /> <!-- 过滤器 -->
<el-table-column label="操作" align="center" width="280" #default="scope"> <!-- #default 当前组件-->
<el-button type="primary" size="small" @click="amends(scope)">
修改
</el-button>
<el-button size="small" :color="thiss.StateButter" @click="setRoleState(scope)">
{{ scope.row.isDeleted == 1 ? '禁用' : '启用' }}
</el-button>
<el-button type="danger" size="small" @click="deletes(scope)">
删除
</el-button>
<el-button type="warning" size="small" @click="showAssignMenu(scope.row)">
分配菜单
</el-button>
</el-table-column>
</el-table>
<!-- 分配菜单的对话框
// tree组件添加ref属性,后期方便进行tree组件对象的获取
default-expand-all
-->
<el-dialog v-model="dialogMenuVisible" title="分配菜单" width="40%">
<el-form label-width="80px">
<el-tree
:data="sysMenuTreeList"
ref="tree"
show-checkbox
default-expand-all
:check-on-click-node="true"
node-key="id"
:props="defaultProps"
/>
<el-form-item>
<el-button type="primary" @click="doAssign">提交</el-button>
<el-button @click="dialogMenuVisible = false">取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
<!--分页条-->
<!--监听分页,换页,和字符-->
<el-pagination :page-sizes="[10, 2, 20, 50, 100]" layout="total, sizes, prev, pager, next" :total="thiss.total"
@size-change="getrolelest" @current-change="getrolelest" v-model:current-page="thiss.pageNum"
v-model:page-size="thiss.pageSize" />
</div>
</template>
<script setup>
import {
ref,
reactive,
onMounted,
getCurrentInstance
} from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus'
import { GetRole,
SaveSysRole,
aMendRole,
DeleteSysRoleById ,
DeleteSysRoleByIdList,
aMendRoleState ,
GetSysRoleMenuIds,
DoAssignMenuIdToSysRole
} from '@/api/role';
// 分页条总记录数
// let total = ref(0)
// 定义表格数据模型
// let list = ref([
// {"id":9 , "roleName": "系统管理员" , "roleCode":"xtgly","createTime": '2023-07-31'},
// {"id":10 , "roleName": "商品管理员" , "roleCode":"spgly","createTime": '2023-07-31'}
// ])
//
const ElTableref =ref();
const { proxy: ctx } = getCurrentInstance() // 可以把ctx当成vue2中的this
//我们按照vue2的习惯创建一个存放数据的对象
let thiss = reactive({
// 定义表格数据模型
list: [],
//当前页码
pageNum: 1,
//当前显示页码
pageSize: 10,
// 分页条总记录数
total: 0,
//查询问题的文本,结果刚好可以跟后台的sysRoleDto类对应
sysRoleDto: {
roleName: ''
},
//弹窗显示控制开关
dialogVisible: false,
centerDialogVisible: false,
//添加数据
uprole: {
roleName: '',
roleCode: '',
description: ''
},
//按钮颜色
StateButter: "#134"
})
const defaultProps = {
children: 'children',
label: 'title',
}
const dialogMenuVisible = ref(false)
const sysMenuTreeList = ref([])
// 树对象变量
const tree = ref()
// 默认选中的菜单数据集合
let roleId = ref()
// 组件加载钩子,也就是启动函数
onMounted(() => {
reset()
})
//状态过滤器
const statusFilter = () => {
// 这里是你的过滤逻辑,根据 isDeleted 字段的值进行过滤
return (value, row) => {
if (+value.isDeleted === 1) {
thiss.StateButter = "#134"
return '✅';
} else {
thiss.StateButter = "#689"
return '❌';
}
};
}
const reset = () => {
// 设置为空,即为查询所有
thiss.sysRoleDto.roleName = '';
getrolelest();
}
//查询接口
const getrolelest = async () => {
//从后台查到数据,匹配到参数里
const { code, message, data } = await GetRole(thiss.pageNum, thiss.pageSize, thiss.sysRoleDto);
+code == 200 ? ctx.$message.success('列表刷新:' + message) : ctx.$message.error('列表刷新:' + message)
thiss.list = data.list
thiss.pageNum = data.pageNum
thiss.pageSize = data.pageSize
thiss.total = data.total
}
//弹窗打开方法
const addShow = () => {
thiss.dialogVisible = true
//清空
thiss.uprole = {
roleName: '',
roleCode: '',
description: ''
}
}
//添加接口
const upRole = async () => {
console.log(thiss.sysRoleDto.roleName);
//从后台查到数据,匹配到参数里
//!thiss.uprole.id等同于:thiss.uprole.id == null
//判断是修改还是添加
const { code, message, data } = !thiss.uprole.id ? await SaveSysRole(thiss.uprole) : await aMendRole(thiss.uprole);
if (+code == 200) {
ctx.$message.success(message)
//关闭弹窗
thiss.dialogVisible = false
//刷新界面
getrolelest();
} else {
ctx.$message.error(message)
}
}
//修改
const amends = information => {
console.log(information);
//打开弹窗
addShow()
//获取本列数据,传递给弹窗
thiss.uprole = information.row
}
//修改状态接口
const setRoleState = async information => {
const { code } = await aMendRoleState(information.row.id, information.row.isDeleted)
if (+code === 200) {
ElMessage.success('修改成功')
//刷新界面
getrolelest();
}
}
//删除
const deletes = information => {
ElMessageBox.confirm('此操作将永久删除该记录, 是否继续?', 'Warning', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(async () => {
const { code } = await DeleteSysRoleById(information.row.id)
if (code === 200) {
//刷新界面
getrolelest();
ElMessage.success('删除成功')
}
})
}
//批量删除
const Statebutter = () => {
ElMessageBox.confirm('此操作将永久删除, 是否继续?', 'Warning', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(async () => {
const { code } = await DeleteSysRoleByIdList(ElTableref.value.getSelectionRows())
if (code === 200) {
//刷新界面
getrolelest();
ElMessage.success('删除成功')
}
})
}
const showAssignMenu = async row => {
dialogMenuVisible.value = true
roleId = row.id
const { data } = await GetSysRoleMenuIds(row.id) // 请求后端地址获取所有的菜单数据,以及当前角色所对应的菜单数据
sysMenuTreeList.value = data.sysMenuList
tree.value.setCheckedKeys(data.roleMenuIds) // 进行数据回显
}
const doAssign = async () => {
const checkedNodes = tree.value.getCheckedNodes() ; // 获取选中的节点
const checkedNodesIds = checkedNodes.map(node => { // 获取选中的节点的id
return {
id: node.id,
isHalf: 0
}
})
// 获取半选中的节点数据,当一个节点的子节点被部分选中时,该节点会呈现出半选中的状态
const halfCheckedNodes = tree.value.getHalfCheckedNodes() ;
const halfCheckedNodesIds = halfCheckedNodes.map(node => { // 获取半选中节点的id
return {
id: node.id,
isHalf: 1
}
})
// 将选中的节点id和半选中的节点的id进行合并
const menuIds = [...checkedNodesIds , ...halfCheckedNodesIds]
console.log(menuIds);
// 构建请求数据
const assignMenuDto = {
roleId: roleId,
menuIdList: menuIds
}
// 发送请求
await DoAssignMenuIdToSysRole(assignMenuDto) ;
ElMessage.success('操作成功')
dialogMenuVisible.value = false
}
</script>
<style scoped>
.search-div {
margin-bottom: 10px;
padding: 10px;
border: 1px solid #ebeef5;
border-radius: 3px;
background-color: #fff;
}
.tools-div {
margin: 10px 0;
padding: 10px;
border: 1px solid #ebeef5;
border-radius: 3px;
background-color: #fff;
}
</style>
<!--
{
"code": 200,
"message": "操作成功",
"data": {
"total": 7,
"list": [
{
"id": 39,
"createTime": "2023-09-04 02:04:41",
"updateTime": "2023-09-04 02:30:01",
"isDeleted": 1,
"roleName": "运维人员",
"roleCode": "yw",
"description": null
},
{
"id": 38,
"createTime": "2023-09-03 15:24:32",
"updateTime": "2023-09-04 02:30:06",
"isDeleted": 1,
"roleName": "开发人员",
"roleCode": "dev",
"description": null
}
],
"pageNum": 1,
"pageSize": 2,
"size": 2,
"startRow": 1,
"endRow": 2,
"pages": 4,
"prePage": 0,
"nextPage": 2,
"isFirstPage": true,
"isLastPage": false,
"hasPreviousPage": false,
"hasNextPage": true,
"navigatePages": 8,
"navigatepageNums": [
1,
2,
3,
4
],
"navigateFirstPage": 1,
"navigateLastPage": 4
}
}
-->
sysUser
<template>
<!---搜索表单-->
<div class="search-div">
<el-form label-width="70px" size="small">
<el-row>
<el-col :span="12">
<el-form-item label="关键字">
<el-input style="width: 100%" placeholder="用户名" v-model="thiss.SysUserDto.keyword"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="创建时间">
<el-date-picker
v-model="thiss.createTimes"
type="daterange"
range-separator="To"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD" />
</el-form-item>
</el-col>
</el-row>
<el-row style="display:flex">
<el-button type="primary" size="small" @click="gerthiss">
搜索
</el-button>
<el-button size="small" @click="breaks">重置</el-button>
</el-row>
</el-form>
</div>
<!--添加按钮-->
<div class="tools-div">
<el-button type="success" size="small" @click="newUsers">添 加</el-button>
</div>
<el-dialog v-model="thiss.dialogVisible" title="添加或修改" width="40%">
<el-form label-width="120px">
<el-form-item label="用户名">
<el-input v-model="thiss.user.username"/>
</el-form-item>
<el-form-item label="密码">
<el-input type="password" show-password v-model="thiss.user.password"/>
</el-form-item>
<el-form-item label="姓名">
<el-input v-model="thiss.user.name"/>
</el-form-item>
<el-form-item label="手机">
<el-input v-model="thiss.user.phone"/>
</el-form-item>
<el-form-item label="头像">
<!-- 获取请求token上传图片 -->
<el-upload
class="avatar-uploader"
action="http://localhost:10001/admin/system/user/userTX"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:headers="headers"
>
<img v-if="thiss.user.avatar" :src="thiss.user.avatar" class="avatar" />
<el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
</el-upload>
</el-form-item>
<el-form-item label="描述">
<el-input v-model="thiss.user.description"/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="newandup">提交</el-button>
<el-button @click="thiss.dialogVisible = false">取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
<!---数据表格-->
<el-table :data="thiss.userl" style="width: 100%">
<el-table-column type=index label="序列" width="80"/>
<el-table-column prop="id" label="ID" />
<el-table-column prop="username" label="用户名" />
<el-table-column prop="name" label="姓名" />
<el-table-column prop="phone" label="手机" />
<el-table-column prop="avatar" label="头像" #default="scope">
<img :src="scope.row.avatar" width="50" />
</el-table-column>
<el-table-column prop="description" label="描述" />
<el-table-column prop="status" label="状态" #default="scope">
{{ scope.row.status == 1 ? '正常' : '停用' }}
</el-table-column>
<el-table-column prop="createTime" label="创建时间" />
<el-table-column label="操作" align="center" width="280" #default="scope">
<el-button type="primary" size="small" @click="dataUpUsers(scope)">
修改
</el-button>
<el-button type="danger" size="small" @click="deleteUsers(scope)">
删除
</el-button>
<el-button type="warning" size="small" @click="fpjs(scope)">
分配角色
</el-button>
</el-table-column>
</el-table>
<!-- 分配弹窗 -->
<el-dialog v-model="thiss.dialogRoleVisible" title="分配角色" width="40%">
<el-form label-width="80px">
<el-form-item label="用户名">
<el-input disabled :value="thiss.user.username"></el-input>
</el-form-item>
<el-form-item label="角色列表">
<el-checkbox-group v-model="thiss.userRoleId">
<el-checkbox v-for="role in thiss.userRoleIds" :key="role.id" :label="role.id">
{{ role.roleName }}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="fpjstj">提交</el-button>
<el-button @click="thiss.dialogRoleVisible = false">取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
<!--分页条 @是绑定按钮的方法 , v-model是绑定参数-->
<!--监听分页,换页,和字符-->
<el-pagination :page-sizes="[10, 2, 20, 50, 100]" layout="total, sizes, prev, pager, next"
:total="thiss.total"
@size-change="getrolelest"
@current-change="getrolelest"
v-model:current-page="thiss.pageNum"
v-model:page-size="thiss.pageSize" />
</template>
<script setup>
import {
ref,
reactive,
getCurrentInstance,
onMounted
} from 'vue';
import { Md5 } from 'ts-md5';
//引入api接口
import { GetUser , newUser ,deleteUser,dataUpUser ,inUserByRole , selectUserByRole} from '@/api/user';
import { GetRole } from '@/api/role';
//token接口
import { useApp } from '@/pinia/modules/app'
const { proxy: ctx } = getCurrentInstance() // 可以把ctx当成vue2中的this
// // 表格数据模型
// const list = ref([
// { "id": 1, "username": "admin", "name": "admin", "phone": "13121034567", "status": 1, "createTime": "2023-05-11" },
// { "id": 2, "username": "admin", "name": "admin", "phone": "13121034567", "status": 1, "createTime": "2023-05-11" }
// ]);
// // 分页条数据模型
// const total = ref(0)
//用户相关参数
const thiss = reactive({
//user列表
userl:[],
//一个user,上传使用
user: {
id: null,
password:'',
username: "",
name: "",
phone: "",
avatar:"",
status: 1
},
//当前页码
pageNum: 1,
//当前显示页码
pageSize: 10,
// 分页条总记录数
total: 0,
//搜索 -- 对于搜索接口
SysUserDto:{
//搜索文本
keyword:'',
//开始接受时间 createTimes的数组下标0是开始,1是介结束
createTimeBegin:'',
createTimeEnd:''
},
//搜索时间页面参数
createTimes:[],
//控制添加框框
dialogVisible:false,
//分配角色框框
dialogRoleVisible:false,
//所有分配角色列表
userRoleIds:[],
//选中的角色
userRoleId:[],
})
// 组件加载钩子,也就是启动函数
onMounted(async () => {
gerthiss()
//调用角色列表接口
const { code, message, data } = await GetRole(1, 0,{roleName: ''});
if (+code == 200) {
thiss.userRoleIds=data.list
ctx.$message.success(message)
} else {
ctx.$message.error(message)
}
})
//分页器按钮:
const getrolelest = () => {
//重置搜索文本和时间
thiss.SysUserDto. keyword = ''
thiss.createTimes = []
gerthiss()
}
//重置
const breaks = () => {
//重置搜索文本和时间,和分页器
thiss.SysUserDto. keyword = ''
thiss.createTimes = []
thiss.pageNum=1
thiss.pageSize=10
thiss.total=0
gerthiss()
}
//搜索接口,也是列表
const gerthiss = async ()=>{
thiss.SysUserDto.createTimeBegin = thiss.createTimes[0]
thiss.SysUserDto.createTimeEnd = thiss.createTimes[1]
//发送 thiss.SysUserDto
const { code, message, data } = await GetUser(thiss.pageNum , thiss.pageSize, thiss.SysUserDto)
if (+code == 200) {
//更新列表
thiss.userl = data.list
thiss.pageNum = data.pageNum
thiss.pageSize = data.pageSize
thiss.total = data.total
ctx.$message.success(message)
} else {
ctx.$message.error(message)
}
}
//删除按钮
const deleteUsers = async data =>{
//发送取出来的 id
const { code, message } = await deleteUser(data.row.id)
if (+code == 200) {
//更新列表
breaks()
ctx.$message.success(message)
} else {
ctx.$message.error(message)
}
}
//修啊按钮
const dataUpUsers = data =>{
thiss.user= data.row
thiss.user.password = ''
thiss.dialogVisible = true
}
// 添加按钮
const newUsers = ()=>{
thiss.user = {
id: null,
password:"",
username: "",
name: "",
phone: "",
status: 1
}
thiss.dialogVisible = true
}
//修改和,添加功能
const newandup = async ()=>{
// 密码转md5
// const md5 = new Md5()
// 等于空是添加,不是就是修改
const { code, message } = thiss.user.id == null ? await newUser(thiss.user) : await dataUpUser(thiss.user)
if (+code == 200) {
//更新列表
breaks()
thiss.dialogVisible = false
ctx.$message.success(message)
} else {
ctx.$message.error(message)
}
}
const headers = {
token: useApp().authorization.token // 从pinia中获取token,在进行文件上传的时候将token设置到请求头中
}
// 图像上传成功以后的事件处理函数
const handleAvatarSuccess = (response, uploadFile) => {
console.log(response.data);
thiss.user.avatar = response.data
}
//分配角色
const fpjs = async datas =>{
thiss.user= datas.row
//查询现在的分配
const { code, message, data } = await selectUserByRole(datas.row.id);
if (+code == 200) {
thiss.userRoleId = data
ctx.$message.success(message)
} else {
ctx.$message.error(message)
}
thiss.dialogRoleVisible = true
}
//分配角色提交
const fpjstj = async () =>{
//thiss.user角色信息
const { code, message, data } = await inUserByRole(thiss.user.id , thiss.userRoleId );
if (+code == 200) {
thiss.dialogRoleVisible = false
ctx.$message.success(message)
} else {
ctx.$message.error(message)
}
}
</script>
<style scoped>
.search-div {
margin-bottom: 10px;
padding: 10px;
border: 1px solid #ebeef5;
border-radius: 3px;
background-color: #fff;
}
.tools-div {
margin: 10px 0;
padding: 10px;
border: 1px solid #ebeef5;
border-radius: 3px;
background-color: #fff;
}
.avatar-uploader .avatar {
width: 178px;
height: 178px;
display: block;
}
.avatar-uploader .el-upload {
border: 1px dashed var(--el-border-color);
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
transition: var(--el-transition-duration-fast);
}
.avatar-uploader .el-upload:hover {
border-color: var(--el-color-primary);
}
.el-icon.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
text-align: center;
}
</style>
<!--
if (+code == 200) {
ctx.$message.success(message)
} else {
ctx.$message.error(message)
}
-->
apijs接口:
Menu
import request from '@/utils/request'
const api_name = '/zx/admin/system/menu'
// 分页列表
export const FindNodes = () => {
return request({
url: `${api_name}/getlist`,
method: 'get',
})
}
// 保存信息
export const SaveMenu = sysMenu => {
return request({
url: `${api_name}/save`,
method: 'post',
data: sysMenu,
})
}
// 修改信息
export const UpdateSysMenuById = sysMenu => {
return request({
url: `${api_name}/updateById`,
method: 'put',
data: sysMenu,
})
}
// 根据id删除数据
export const RemoveSysMenuById = id => {
return request({
url: `${api_name}/removeById/${id}`,
method: 'delete',
})
}
User
//引入统一请求封装
import request from '@/utils/request'
//api接口常量
const url = '/zx/admin/system/user'
// 查询接口
export const GetUser = (page,quantity,datas) => {
return request({
//在js里`表示字符串拼接${}是个表达式
url: `${url}/getUserList/${page}/${quantity}`,
method: 'post',
//如果后端是@RequestBody则这里要加data
//否则是 params
data : datas ,
})
}
// 添加角色请求方法
export const newUser = (data) => {
return request({
url: `${url}/newUser`,
method: 'post',
data
})
}
// 修改角色请求方法
export const dataUpUser = (data) => {
return request({
url: `${url}/dataUpUser`,
method: 'put',
data
})
}
// 删除角色
export const deleteUser = (roleId) => {
return request({
url: `${url}/deleteUser/${roleId}`,
method: 'delete'
})
}
// 查询用户分配的角色返回[]
export const selectUserByRole = (userid) => {
return request({
url: `${url}/selectUserByRole/${userid}`,
method: 'get',
})
}
//修改用户的角色信息
export const inUserByRole = (userid , userList) => {
return request({
url: `${url}/inUserByRole/${userid}`,
method: 'post',
data: userList
})
}
// 批量删除角色
export const DeleteSysRoleByIdList = (rolelist) => {
return request({
url: `${url}/DeleteSysRoleByIdList`,
method: 'delete',
data : rolelist
})
}
Role
//引入统一请求封装
import request from '@/utils/request'
//api接口常量
const url = '/zx/admin/system/role'
// 查询接口
export const GetRole = (page,quantity,datas) => {
return request({
//在js里`表示字符串拼接${}是个表达式
url: `${url}/getRoleList/${page}/${quantity}`,
method: 'post',
//如果后端是@RequestBody则这里要加data
//否则是 params
data : datas ,
})
}
// 添加角色请求方法
export const SaveSysRole = (data) => {
return request({
url: `${url}/DataUpRole`,
method: 'post',
data
})
}
// 修改角色请求方法
export const aMendRole = (data) => {
return request({
url: `${url}/aMendRole`,
method: 'put',
data
})
}
// 修改角色请求方法
export const aMendRoleState = (roleId,roleState) => {
return request({
url: `${url}/aMendRoleState/${roleId}/${roleState}`,
method: 'get',
})
}
// 删除角色
export const DeleteSysRoleById = (roleId) => {
return request({
url: `${url}/DeleteSysRoleById/${roleId}`,
method: 'delete'
})
}
// 批量删除角色
export const DeleteSysRoleByIdList = (rolelist) => {
return request({
url: `${url}/DeleteSysRoleByIdList`,
method: 'delete',
data : rolelist
})
}
// 查询指定角色所对应的菜单id
export const GetSysRoleMenuIds = (roleId) => {
return request({
url: `${url}/findSysRoleMenuByRoleId/`+ roleId,
method: 'get'
})
}
// 根据角色分配菜单请求方法
export const DoAssignMenuIdToSysRole = (assignMenuDto) => {
return request({
url: `${url}/doAssign`,
method: 'post',
data: assignMenuDto
})
}
至此这部分功能就搞定了:
主要学习菜单的内容:
- 递归查询子目录
- 为角色分配菜单的多表查询
总结:
这篇文章写的时候很卡不知道为什么,
所以没怎么好好写
主要学习:
- 数据库的关联查询
- 数据库的事务关联
- 前端的列表操作
- 前端数据绑定
- 递归思想
到这里的代码:
前端里的: 忘记删除了,可以有点大