后端
1.实体类编写
用户实体类
package jkw.pojo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* 用户
*/
@Data
public class Admin implements Serializable {
@TableId
private Integer aid;
private String username;//姓名
private String password;//密码
private String phoneNum;//手机号
private String email;//邮箱
private String adminImg;//头像
private boolean status; // 状态 true可用 false禁用
@TableField(exist = false) // 不是数据库的字段
private List<Role> roles; // 角色集合
}
角色实体类
package jkw.pojo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* 角色
*/
@Data
public class Role implements Serializable {
@TableId
private Integer rid;
private String roleName; // 角色名
private String roleDesc; // 角色介绍
@TableField(exist = false) // 不是数据库的字段
private List<Permission> permissions;// 权限集合
}
权限实体类
package jkw.pojo;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.io.Serializable;
/**
* 权限
*/
@Data
public class Permission implements Serializable {
@TableId
private Integer pid;
private String permissionName; //名称
private String permissionDesc;//详情
}
2.数据库编写
数据库版本
这里采用的是mysql5.7,编码为utf-8mb4
用户表
DROP TABLE IF EXISTS `admin`;
CREATE TABLE `admin` (
`aid` int(32) NOT NULL AUTO_INCREMENT,
`email` varchar(50) DEFAULT NULL,
`username` varchar(50) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`phoneNum` varchar(20) DEFAULT NULL,
`status` tinyint(1) DEFAULT NULL,
`adminImg` varchar(255) DEFAULT NULL,
PRIMARY KEY (`aid`),
UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
角色表
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`rid` int(32) NOT NULL AUTO_INCREMENT,
`roleName` varchar(50) DEFAULT NULL,
`roleDesc` varchar(50) DEFAULT NULL,
PRIMARY KEY (`rid`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;
权限表
DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission` (
`pid` int(32) NOT NULL AUTO_INCREMENT,
`permissionName` varchar(50) DEFAULT NULL,
`permissionDesc` varchar(50) DEFAULT NULL,
PRIMARY KEY (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `role_permission`;
CREATE TABLE `role_permission` (
`rid` varchar(32) DEFAULT NULL,
`pid` varchar(32) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
关联表
DROP TABLE IF EXISTS `admin_role`;
CREATE TABLE `admin_role` (
`aid` varchar(32) NOT NULL,
`rid` varchar(32) NOT NULL,
PRIMARY KEY (`aid`,`rid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3.数据映射层编写
包接口
用户数据接口
package jkw.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import jkw.pojo.Admin;
import jkw.pojo.Permission;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface AdminMapper extends BaseMapper<Admin> {
// 根据id查询管理员,包括角色和权限
Admin findById(Integer id);
// 删除管理员的所有角色
void deleteAdminAllRole(Integer id);
// 给管理员添加角色
void addRoleToAdmin(@Param("aid") Integer aid, @Param("rid") Integer rid);
// 根据管理员名查询权限
List<Permission> findAllPermission(String username);
}
用户数据接口映射文件
<?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="jkw.mapper.AdminMapper">
<resultMap id="adminMapper" type="jkw.pojo.Admin">
<id property="aid" column="aid"></id>
<result property="username" column="username"></result>
<result property="email" column="email"></result>
<result property="phoneNum" column="phoneNum"></result>
<result property="status" column="status"></result>
<result property="adminImg" column="adminImg"></result>
<collection property="roles" column="aid" ofType="jkw.pojo.Role">
<id property="rid" column="rid"></id>
<result property="roleName" column="roleName"></result>
<result property="roleDesc" column="roleDesc"></result>
<collection property="permissions" column="rid" ofType="jkw.pojo.Permission">
<id property="pid" column="pid"></id>
<result property="permissionName" column="permissionName"></result>
<result property="permissionDesc" column="permissionDesc"></result>
</collection>
</collection>
</resultMap>
<delete id="deleteAdminAllRole" parameterType="int">
DELETE
FROM admin_role
WHERE aid = #{id}
</delete>
<select id="findById" parameterType="int" resultMap="adminMapper">
SELECT *
FROM admin
LEFT JOIN admin_role
ON admin.aid = admin_role.aid
LEFT JOIN role
ON admin_role.rid = role.rid
LEFT JOIN role_permission
ON role.rid = role_permission.rid
LEFT JOIN permission
ON role_permission.pid = permission.pid
WHERE admin.aid = #{id}
</select>
<insert id="addRoleToAdmin">
INSERT INTO admin_role
VALUES (#{aid}, #{rid});
</insert>
<select id="findAllPermission" resultType="jkw.pojo.Permission" parameterType="string">
SELECT DISTINCT permission.*
FROM admin
LEFT JOIN admin_role
ON admin.aid = admin_role.aid
LEFT JOIN role
ON admin_role.rid = role.rid
LEFT JOIN role_permission
ON role.rid = role_permission.rid
LEFT JOIN permission
ON role_permission.pid = permission.pid
WHERE admin.username = #{username}
</select>
</mapper>
角色数据接口
package jkw.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import jkw.pojo.Role;
import org.apache.ibatis.annotations.Param;
public interface RoleMapper extends BaseMapper<Role> {
// 删除角色_权限中间表的相关数据
void deleteRoleAllPermission(Integer rid);
// 删除用户_角色表的相关数据
void deleteRoleAllAdmin(Integer rid);
// 根据id查询角色,包括权限
Role findById(Integer id);
// 给角色添加权限
void addPermissionToRole(@Param("rid") Integer rid, @Param("pid")Integer pid);
}
角色数据接口映射文件
<?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="jkw.mapper.RoleMapper">
<resultMap id="roleMapper" type="jkw.pojo.Role">
<id property="rid" column="rid"></id>
<result property="roleName" column="roleName"></result>
<result property="roleDesc" column="roleDesc"></result>
<collection property="permissions" column="rid" ofType="jkw.pojo.Permission">
<id property="pid" column="pid"></id>
<result property="permissionName" column="permissionName"></result>
<result property="permissionDesc" column="permissionDesc"></result>
</collection>
</resultMap>
<delete id="deleteRoleAllPermission" parameterType="int">
DELETE
FROM role_permission
WHERE rid = #{rid}
</delete>
<delete id="deleteRoleAllAdmin" parameterType="int">
DELETE
FROM admin_role
where rid = #{rid}
</delete>
<select id="findById" parameterType="int" resultMap="roleMapper">
SELECT *
FROM role
LEFT JOIN role_permission
ON role.rid = role_permission.rid
LEFT JOIN permission
ON role_permission.pid = permission.pid
WHERE role.rid = #{id}
</select>
<insert id="addPermissionToRole">
INSERT INTO role_permission
VALUES (#{rid}, #{pid});
</insert>
</mapper>
权限数据接口
package jkw.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import jkw.pojo.Permission;
public interface PermissionMapper extends BaseMapper<Permission> {
// 删除角色_权限表中的相关数据
void deletePermissionAllRole(Integer pid);
}
权限数据接口映射文件
<?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="jkw.mapper.PermissionMapper">
<delete id="deletePermissionAllRole" parameterType="int">
DELETE
FROM role_permission
WHERE pid = #{pid}
</delete>
</mapper>
4.服务层编写
用户服务接口
package jkw.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jkw.pojo.Admin;
import jkw.pojo.Permission;
import java.util.List;
/**
* 用户服务层
*/
public interface AdminService {
// 新增管理员
void add(Admin admin);
// 修改管理员
void update(Admin admin);
// 删除管理员【自定义】
void delete(Integer id);
//修改状态
void updateStatus(Integer id);
// 根据id查询管理员(查询用户详情)【自定义】
Admin findById(Integer id);
//分页查询管理员
Page<Admin> search(int page, int size);
// 修改管理员角色【自定义】
void updateRoleToAdmin(Integer aid, Integer[] rids);
// 根据名字查询管理员
Admin findByName(String username);
// 根据名字查询管理员所有权限
List<Permission> findAllPermission(String username);
}
用户服务实现类
package jkw.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jkw.mapper.AdminMapper;
import jkw.pojo.Admin;
import jkw.pojo.Permission;
import jkw.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.util.List;
@Service
@Transactional
public class AdminServiceImpl implements AdminService {
@Autowired
private AdminMapper adminMapper;
@Override
public void add(Admin admin) {
adminMapper.insert(admin);
//初始化用户,不然添加后什么角色都没有,会报错
adminMapper.addRoleToAdmin(admin.getAid(), 2);
}
@Override
public void update(Admin admin) {
// 如果传来空密码则密码还是原来的密码
if (!StringUtils.hasText(admin.getPassword())) {
String password = adminMapper.selectById(admin.getAid()).getPassword();
admin.setPassword(password);
}
adminMapper.updateById(admin);
}
@Override
public void delete(Integer id) {
// 删除用户的所有角色
adminMapper.deleteAdminAllRole(id);
// 删除用户
adminMapper.deleteById(id);
}
@Override
public void updateStatus(Integer id) {
Admin admin = adminMapper.selectById(id);
admin.setStatus(!admin.isStatus());//状态取反
adminMapper.updateById(admin);
}
@Override
public Admin findById(Integer id) {
return adminMapper.findById(id);
}
@Override
public Page<Admin> search(int page, int size) {
return adminMapper.selectPage(new Page<>(page, size), null);
}
@Override
public void updateRoleToAdmin(Integer aid, Integer[] rids) {
// 删除用户的所有角色
adminMapper.deleteAdminAllRole(aid);
// 重新添加管理员角色
for (Integer rid : rids) {
adminMapper.addRoleToAdmin(aid, rid);
}
}
@Override
public Admin findByName(String username) {
QueryWrapper<Admin> wrapper = new QueryWrapper();
wrapper.eq("username", username);
Admin admin = adminMapper.selectOne(wrapper);
return admin;
}
@Override
public List<Permission> findAllPermission(String username) {
return adminMapper.findAllPermission(username);
}
}
角色服务接口
package jkw.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jkw.pojo.Role;
import java.util.List;
/**
* 角色服务接口
*/
public interface RoleService {
// 新增角色
void add(Role role);
// 修改角色
void update(Role role);
// 删除角色
void delete(Integer id);
// 根据id查询角色【自定义】
Role findById(Integer id);
// 查询所有角色
List<Role> findAll();
// 分页查询角色
Page<Role> search(int page, int size);
// 修改角色的权限【自定义】
void addPermissionToRole(Integer rid, Integer[] pids);
}
角色服务实现类
package jkw.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jkw.mapper.RoleMapper;
import jkw.pojo.Role;
import jkw.service.RoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional
public class RoleServiceImpl implements RoleService {
@Autowired
private RoleMapper roleMapper;
@Override
public void add(Role role) {
roleMapper.insert(role);
}
@Override
public void update(Role role) {
roleMapper.updateById(role);
}
@Override
public void delete(Integer id) {
// 删除角色
roleMapper.deleteById(id);
// 删除角色_权限中间表的相关数据
roleMapper.deleteRoleAllPermission(id);
// 删除用户_角色中间表的相关数据
roleMapper.deleteRoleAllAdmin(id);
}
@Override
public Role findById(Integer id) {
return roleMapper.findById(id);
}
@Override
public List<Role> findAll() {
return roleMapper.selectList(null);
}
@Override
public Page<Role> search(int page, int size) {
return roleMapper.selectPage(new Page(page,size),null);
}
@Override
public void addPermissionToRole(Integer rid, Integer[] pids) {
// 删除角色的所有权限
roleMapper.deleteRoleAllPermission(rid);
// 给角色添加权限
for (Integer pid : pids) {
roleMapper.addPermissionToRole(rid,pid);
}
}
}
权限服务接口
package jkw.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jkw.pojo.Permission;
import java.util.List;
public interface PermissionService {
void add(Permission permission);
void update(Permission permission);
void delete(Integer id);
Permission findById(Integer id);
List<Permission> findAll();
Page<Permission> search(String search, int page, int size);
}
权限服务实现类
package jkw.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jkw.mapper.PermissionMapper;
import jkw.pojo.Permission;
import jkw.service.PermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Transactional
@Service
public class PermissionServiceImpl implements PermissionService {
@Autowired
private PermissionMapper permissionMapper;
@Override
public void add(Permission permission) {
permissionMapper.insert(permission);
}
@Override
public void update(Permission permission) {
permissionMapper.updateById(permission);
}
@Override
public void delete(Integer id) {
// 删除权限
permissionMapper.deleteById(id);
// 删除角色_权限表中的相关数据
permissionMapper.deletePermissionAllRole(id);
}
@Override
public Permission findById(Integer id) {
return permissionMapper.selectById(id);
}
@Override
public List<Permission> findAll() {
return permissionMapper.selectList(null);
}
@Override
public Page<Permission> search(String search, int page, int size) {
QueryWrapper<Permission> queryWrapper = new QueryWrapper<>();
if (search != null) {
queryWrapper.like("permissionDesc", search);
}
return permissionMapper.selectPage(new Page(page, size), queryWrapper);
}
}
5.控制层编写
用户控制层
package jkw.controller.back.sys;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jkw.pojo.Admin;
import jkw.service.AdminService;
import jkw.vo.BaseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
/**
* back管理员
*/
@RestController
@RequestMapping("/back/admin")
@CrossOrigin
public class AdminController {
@Autowired
private AdminService adminService;
@Autowired
private PasswordEncoder encoder;
/**
* 新增
*
* @param admin
* @return
*/
@PostMapping("/add")
@PreAuthorize("hasAnyAuthority('/admin')")
public BaseResult add(Admin admin) {
String password = admin.getPassword();
password = encoder.encode(password);
admin.setPassword(password);
adminService.add(admin);
return BaseResult.ok();
}
/**
* 修改管理员(设置空密码则还是原来密码)
*
* @param admin 管理员
* @return
*/
@PostMapping("/update")
@PreAuthorize("hasAnyAuthority('/admin')")
public BaseResult update(Admin admin) {
String password = admin.getPassword();
if (StringUtils.hasText(password)) { // 密码不为空加密
password = encoder.encode(password);
admin.setPassword(password);
}
adminService.update(admin);
return BaseResult.ok();
}
/**
* 删除
*
* @param aid
* @return
*/
@DeleteMapping("/delete")
@PreAuthorize("hasAnyAuthority('/admin')")
public BaseResult delete(Integer aid) {
adminService.delete(aid);
return BaseResult.ok();
}
/**
* 根据id查询管理员
*
* @param aid
* @return
*/
@GetMapping("/findById")
@PreAuthorize("hasAnyAuthority('/admin')")
public BaseResult<Admin> findById(Integer aid) {
Admin admin = adminService.findById(aid);
return BaseResult.ok(admin);
}
/**
* 分页查询管理员
*
* @param page 当前页
* @param size 每页条数
* @return
*/
@GetMapping("/search")
@PreAuthorize("hasAnyAuthority('/admin')")
public BaseResult<Page<Admin>> search(int page, int size) {
Page<Admin> adminPage = adminService.search(page, size);
return BaseResult.ok(adminPage);
}
/**
* 修改状态
*
* @param aid 管理员id
* @return
*/
@PostMapping("/updateStatus")
@PreAuthorize("hasAnyAuthority('/admin')")
public BaseResult updateStatus(Integer aid) {
adminService.updateStatus(aid);
return BaseResult.ok();
}
/**
* 修改管理员角色
*
* @param aid 管理员id
* @param rids 角色id
* @return
*/
@PostMapping("/updateRole")
@PreAuthorize("hasAnyAuthority('/admin')")
public BaseResult updateRoleToAdmin(Integer aid, Integer[] rids) {
adminService.updateRoleToAdmin(aid, rids);
return BaseResult.ok();
}
/**
* 获取登录管理员名
*
* @return 管理员名
*/
@GetMapping("/getUsername")
public BaseResult<String> getUsername() {
// 1.获取会话对象
SecurityContext context = SecurityContextHolder.getContext();
// 2.获取认证对象
Authentication authentication = context.getAuthentication();
// 3.获取登录用户信息
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
String username = userDetails.getUsername();
return BaseResult.ok(username);
}
/**
* 根据用户名查询管理员
*
* @param username
* @return
*/
@GetMapping("/findByUsername")
public BaseResult findByUsername(String username) {
Admin admin = adminService.findByName(username);
return BaseResult.ok(admin);
}
}
角色控制层
package jkw.controller.back.sys;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jkw.pojo.Role;
import jkw.service.RoleService;
import jkw.vo.BaseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/back/role")
@CrossOrigin
public class RoleController {
@Autowired
private RoleService roleService;
/**
* 新增角色
*
* @param role 角色对象
* @return 执行结果
*/
@PostMapping("/add")
@PreAuthorize("hasAnyAuthority('/role')")
public BaseResult add(Role role) {
roleService.add(role);
return BaseResult.ok();
}
/**
* 修改角色
*
* @param role 角色对象
* @return 执行结c果
*/
@PostMapping("/update")
@PreAuthorize("hasAnyAuthority('/role')")
public BaseResult update(Role role) {
roleService.update(role);
return BaseResult.ok();
}
/**
* 删除角色(包括中间表的管理员、权限)
*
* @param rid 角色id
* @return 执行结果
*/
@DeleteMapping("/delete")
@PreAuthorize("hasAnyAuthority('/role')")
public BaseResult delete(Integer rid) {
roleService.delete(rid);
return BaseResult.ok();
}
/**
* 根据id查询角色
*
* @param rid
* @return 查询到的角色
*/
@GetMapping("/findById")
@PreAuthorize("hasAnyAuthority('/role')")
public BaseResult<Role> findById(Integer rid) {
Role role = roleService.findById(rid);
return BaseResult.ok(role);
}
/**
* 查询所有角色
*
* @return 查询结果
*/
@GetMapping("/findAll")
@PreAuthorize("hasAnyAuthority('/role')")
public BaseResult<List<Role>> findAll() {
List<Role> all = roleService.findAll();
return BaseResult.ok(all);
}
/**
* 分页查询角色
*
* @param page 页码
* @param size 每页条数
* @return 查询结果
*/
@GetMapping("/search")
@PreAuthorize("hasAnyAuthority('/role')")
public BaseResult<Page<Role>> search(int page, int size) {
Page<Role> page1 = roleService.search(page, size);
return BaseResult.ok(page1);
}
/**
* 修改角色的权限
*
* @param rid 角色id
* @param pids 权限id
* @return 执行结果
*/
@PostMapping("/updatePermission")
@PreAuthorize("hasAnyAuthority('/role')")
public BaseResult updatePermissionToRole(Integer rid, Integer[] pids) {
roleService.addPermissionToRole(rid, pids);
return BaseResult.ok();
}
}
权限控制层
package jkw.controller.back.sys;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jkw.pojo.Permission;
import jkw.service.PermissionService;
import jkw.vo.BaseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* back_permission权限
*/
@CrossOrigin
@RestController
@RequestMapping("/back/permission")
public class PermissionController {
@Autowired
private PermissionService permissionService;
/**
* 新增
*
* @param permission
* @return 执行结果
*/
@PostMapping("/add")
@PreAuthorize("hasAnyAuthority('/permission')")
public BaseResult add(Permission permission) {
permissionService.add(permission);
return BaseResult.ok();
}
/**
* 修改
*
* @param permission
* @return 执行结果
*/
@PostMapping("/update")
@PreAuthorize("hasAnyAuthority('/permission')")
public BaseResult update(Permission permission) {
permissionService.update(permission);
return BaseResult.ok();
}
/**
* 删除
*
* @param pid id
* @return 执行结果
*/
@DeleteMapping("/delete")
@PreAuthorize("hasAnyAuthority('/permission')")
public BaseResult delete(Integer pid) {
permissionService.delete(pid);
return BaseResult.ok();
}
/**
* 根据id查询
*
* @param pid id
* @return 查询结果
*/
@GetMapping("/findById")
@PreAuthorize("hasAnyAuthority('/permission')")
public BaseResult<Permission> findById(Integer pid) {
Permission permission = permissionService.findById(pid);
return BaseResult.ok(permission);
}
/**
* 查询所有
*
* @return
*/
@GetMapping("/findAll")
@PreAuthorize("hasAnyAuthority('/permission')")
public BaseResult<List<Permission>> findAll() {
List<Permission> all = permissionService.findAll();
return BaseResult.ok(all);
}
/**
* 分页查询
*
* @param page 页面
* @param size 每页条数
* @return 查询结果
*/
@GetMapping("/search")
@PreAuthorize("hasAnyAuthority('/permission')")
public BaseResult<Page<Permission>> search(String search, int page, int size) {
Page<Permission> permissionPage = permissionService.search(search, page, size);
return BaseResult.ok(permissionPage);
}
}
6.鉴权模块编写
鉴权配置类
package jkw.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.Collections;
/**
* Security配置类
*/
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)// 开启鉴权配置注解
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//解决跨域,相关文章http://t.csdnimg.cn/3LYOI
CorsConfigurationSource configurationSource() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
// 允许cookies跨域
corsConfiguration.setAllowCredentials(true);
// 允许的请求方法
corsConfiguration.setAllowedMethods(Collections.singletonList("*"));
// 允许的请求头
corsConfiguration.setAllowedHeaders(Collections.singletonList("*"));
// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
corsConfiguration.setMaxAge(3600L);
//允许跨域访问的站点
corsConfiguration.setAllowedOrigins(Collections.singletonList("*"));
//对所有URL生效
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfiguration);
return source;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// 自定义表单登录
http.formLogin()
.usernameParameter("username") // 用户名项
.passwordParameter("password") // 密码项
.loginProcessingUrl("/back/login") // 登录提交路径
.successHandler(new MyLoginSuccessHandler()) // 登录成功处理器
.failureHandler(new MyLoginFailureHandler()); // 登录失败处理器
// 权限拦截配置
http.authorizeRequests()
.antMatchers("/back/login").permitAll() // 登录不需要认证
.antMatchers("/back/admin/findByUsername").permitAll()
.antMatchers("/").permitAll()
.antMatchers("/file/**").permitAll()
.antMatchers("/front/**").permitAll()
.anyRequest().authenticated(); // 其余请求都需要认证
// 退出登录配置
http.logout()
.logoutUrl("/back/logout") // 退出登录路径
.logoutSuccessHandler(new MyLogoutSuccessHandler()) // 登出成功处理器
.clearAuthentication(true) // 清除认证数据
.invalidateHttpSession(true); // 清除session
// 异常处理
http.exceptionHandling()
.authenticationEntryPoint(new MyAuthenticationEntryPoint()) // 未登录处理器
.accessDeniedHandler(new MyAccessDeniedHandler()); // 权限不足处理器
// 关闭csrf防护,取消跨站请求伪造防护
http.csrf().disable();
// 开启跨域访问
http.cors().configurationSource(configurationSource());
// http.cors();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
认证授权逻辑
package jkw.security;
import jkw.pojo.Admin;
import jkw.pojo.Permission;
import jkw.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* 认证授权逻辑
*/
@Service
public class MyUserDetailService implements UserDetailsService {
@Autowired
private AdminService adminService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 1.认证
Admin admin = adminService.findByName(username);
if (admin == null) {
throw new UsernameNotFoundException("用户不存在");
}
if (!admin.isStatus()) {
throw new UsernameNotFoundException("用户不可用");
}
// 2.授权
List<Permission> permissions = adminService.findAllPermission(username);
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
for (Permission permission : permissions) {
grantedAuthorities.add(new SimpleGrantedAuthority(permission.getPermissionDesc()));
}
// 3.封装为UserDetails对象
UserDetails userDetails = User.withUsername(admin.getUsername())
.password(admin.getPassword())
.authorities(grantedAuthorities)
.build();
// 4.返回封装好的UserDetails对象
return userDetails;
}
}
权限不足处理器
package jkw.security;
import com.alibaba.fastjson.JSON;
import jkw.vo.BaseResult;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 权限不足处理器
*/
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.setContentType("text/json;charset=utf-8");
BaseResult result = new BaseResult(403, "权限不足", null);
response.getWriter().write(JSON.toJSONString(result));
}
}
未登录处理器
package jkw.security;
import com.alibaba.fastjson.JSON;
import jkw.vo.BaseResult;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 未登录处理器
*/
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.setContentType("text/json;charset=utf-8");
BaseResult result = new BaseResult(401, "用户未登录,请登录", null);
response.getWriter().write(JSON.toJSONString(result));
}
}
登录失败处理器
package jkw.security;
import com.alibaba.fastjson.JSON;
import jkw.vo.BaseResult;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 登录失败处理器
*/
public class MyLoginFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
response.setContentType("text/json;charset=utf-8");
BaseResult result = new BaseResult(402, "用户名或密码错误", null);
response.getWriter().write(JSON.toJSONString(result));
}
}
登录成功处理器
package jkw.security;
import com.alibaba.fastjson.JSON;
import jkw.vo.BaseResult;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 登录成功处理器
*/
public class MyLoginSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.setContentType("text/json;charset=utf-8");
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
BaseResult result = new BaseResult(200, "登录成功", userDetails);
response.getWriter().write(JSON.toJSONString(result));
}
}
退出登录成功成功处理器
package jkw.security;
import com.alibaba.fastjson.JSON;
import jkw.vo.BaseResult;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 退出登录成功成功处理器
*/
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.setContentType("text/json;charset=utf-8");
BaseResult result = new BaseResult(200, "注销成功", null);
response.getWriter().write(JSON.toJSONString(result));
}
}
前端
1.页面编写
用户页面
<template>
<div class="data-container">
<!--添加 start-->
<div class="data-header">
<el-button round @click="addHander" class="button" size="large" type="primary">
<el-icon>
<DocumentAdd/>
</el-icon> 添加
</el-button>
</div>
<!--添加 end-->
<div class="data-table">
<!--表格数据展示 start-->
<el-table :data="adminList.list" style="width: 1100px;">
<el-table-column prop="adminImg" label="头像" width="150" align="center">
<template #default="scope">
<img :src="scope.row.adminImg" style="height:60px"/>
</template>
</el-table-column>
<el-table-column show-overflow-tooltip prop="username" label="用户名" width="120"></el-table-column>
<el-table-column prop="email" label="邮箱" width="180" align="center"></el-table-column>
<el-table-column prop="phoneNum" label="电话号码" width="120" align="center"></el-table-column>
<el-table-column prop="status" label="用户状态" width="120">
<!--利用标签帮助状态显示-->
<template #default="scope">
<el-tag :type="scope.row.status == true ? 'success' : 'error'">{{
scope.row.status == true ? '使用' : '禁用'
}}
</el-tag>
</template>
</el-table-column>
<el-table-column label="角色分配" align="center" width="200">
<template #default="scope">
<el-button size="small" type="success" @click="handleDesc(scope.$index, scope.row)">角色</el-button>
<el-button size="small" type="danger" @click="handleRole(scope.$index, scope.row)">分配</el-button>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="200">
<template #default="scope">
<el-button size="small" type="primary" @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
<el-button size="small" type="success"
@click="handleStatus(scope.$index, scope.row)">状态
</el-button>
<el-button size="small" type="danger"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
<!--表格数据展示 end-->
<!--分页 start-->
<div class="page">
<el-pagination @current-change="currentChangeHaddler" background layout="prev,pager,next,jumper"
:default-page-size="defaultPageSize" :total="totalData"></el-pagination>
</div>
<!--分页 end-->
<!--添加对话框 start-->
<el-dialog draggable destroy-on-close v-model="dialogAddVisible" title="添加用户" width="35%" center>
<el-form :inline="true" :model="addFormInfo" status-icon label-width="120px">
<el-form-item label="用户名">
<el-input v-model="addFormInfo.username" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input v-model="addFormInfo.password" placeholder="请输入密码"></el-input>
</el-form-item>
<el-form-item label="邮箱">
<el-input v-model="addFormInfo.email" placeholder="请输入邮箱"></el-input>
</el-form-item>
<el-form-item label="电话号码">
<el-input v-model="addFormInfo.phoneNum" placeholder="请输入电话号码"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogAddVisible = false">取消</el-button>
<el-button type="primary" @click="sureHandler">确定</el-button>
</span>
</template>
</el-dialog>
<!--添加对话框 end-->
<!--编辑对话框 start-->
<el-dialog draggable destroy-on-close v-model="dialogEditorVisible" title="编辑用户信息" width="35%" center>
<el-form :inline="true" :model="editorFormInfo" label-width="120px">
<el-form-item label="头像">
<el-input v-model="editorFormInfo.adminImg"></el-input>
</el-form-item>
<el-form-item label="用户名">
<el-input v-model="editorFormInfo.username" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input v-model="editorFormInfo.password" placeholder="请输入密码"></el-input>
</el-form-item>
<el-form-item label="邮箱">
<el-input v-model="editorFormInfo.email" placeholder="请输入邮箱"></el-input>
</el-form-item>
<el-form-item label="电话号码">
<el-input v-model="editorFormInfo.phoneNum" placeholder="请输入电话号码"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogEditorVisible = false">取消</el-button>
<el-button type="primary" @click="sureEditorHandler">确定</el-button>
</span>
</template>
</el-dialog>
<!--编辑对话框 end-->
<!--分配角色对话框 start-->
<el-dialog draggable destroy-on-close v-model="dialogRoleVisible" title="分配角色" width="35%" center>
<el-table ref="multipleTable" :data="allRoles" row-key="rid" @selection-change="onSelectionChange">
<el-table-column type="selection" :reserve-selection="true"/>
<el-table-column label="角色名" prop="roleName"/>
<el-table-column label="角色描述" prop="roleDesc"/>
</el-table>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogRoleVisible = false">取消</el-button>
<el-button type="primary" @click="sureRoleHandler">确定</el-button>
</span>
</template>
</el-dialog>
<!--分配角色对话框 end-->
<!--详情对话框 start-->
<el-dialog draggable destroy-on-close v-model="dialogDescVisible" title="管理员详情" width="35%" center>
<el-tag v-for="role in descInfo.list" :key="role.rid" size="large" effect="light" class="mx-1" round
:type="success">
{{ role.roleName }}:[{{ role.roleDesc }}]
</el-tag>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogDescVisible = false">关闭</el-button>
</span>
</template>
</el-dialog>
<!--详情对话框 end-->
</div>
</div>
</template>
<script setup>
import sysAxios from "@/api/sys.js"
import {onMounted, reactive, ref} from "vue";
//初始化管理员查询数据
const adminList = reactive({
list: []
})
//初始化总条数
const totalData = ref(0)
//当前页
const currentPage = ref(1)
//初始化分页显示条数
const defaultPageSize = ref(10)
//添加添加对话框控制器
const dialogAddVisible = ref(false)
//初始化添加对话框状态
const addFormInfo = reactive({
username: "",
email: "",
phoneNum: "",
password: "",
})
//编辑对话框控制器
const dialogEditorVisible = ref(false)
//初始化编辑对话框状态
const editorFormInfo = reactive({
aid: '',
username: "",
email: "",
phoneNum: "",
password: "",
status: '',
adminImg: ''
})
//分配角色对话框控制器
const dialogRoleVisible = ref(false)
//初始化角色列表
const allRoles = ref([])
const adminRoles = ref([])
const multipleTable = ref(null)
let rids = []
const adminId = ref(0)
//详情对话框控制器
const dialogDescVisible = ref(false)
//初始化详情对话框
const descInfo = reactive({
list: []
})
/**
* 网路请求:分页查询
* */
const http = () => {
sysAxios.admin_search(
{
page: currentPage.value,
size: defaultPageSize.value
}
).then(res => {
if (res.data.code == 200) {
adminList.list = res.data.data.records
totalData.value = res.data.data.total
}
})
}
onMounted(() => {
http()
})
/**
* 分页
*/
const currentChangeHaddler = (val) => {
currentPage.value = val
http()
}
/**
* 添加对话框弹出事件
*/
const addHander = () => {
dialogAddVisible.value = true
}
/**
* 添加对话框 确定事件
*/
const sureHandler = () => {
sysAxios.admin_add({
username: addFormInfo.username,
email: addFormInfo.email,
phoneNum: addFormInfo.phoneNum,
password: addFormInfo.password,
}).then(res => {
if (res.data.code == 200) {
dialogAddVisible.value = false
http()
}
})
}
/**
* 编辑对话框 弹出事件
* */
const handleEdit = (index, row) => {
dialogEditorVisible.value = true
sysAxios.admin_findById({
aid: row.aid
}).then(res => {
if (res.data.code == 200) {
editorFormInfo.aid = res.data.data.aid;
editorFormInfo.username = res.data.data.username;
editorFormInfo.password = '';
editorFormInfo.email = res.data.data.email;
editorFormInfo.phoneNum = res.data.data.phoneNum;
editorFormInfo.status = res.data.data.status;
editorFormInfo.adminImg = res.data.data.adminImg;
}
})
}
/**
* 编辑对话框 确定事件
*/
const sureEditorHandler = () => {
sysAxios.admin_update({
aid: editorFormInfo.aid,
username: editorFormInfo.username,
email: editorFormInfo.email,
phoneNum: editorFormInfo.phoneNum,
password: editorFormInfo.password,
status: editorFormInfo.status,
adminImg: editorFormInfo.adminImg,
}).then(res => {
if (res.data.code == 200) {
dialogEditorVisible.value = false
http()
}
})
}
/**
* 修改用户状态
*/
const handleStatus = (index, row) => {
sysAxios.admin_updateStatus({
aid: row.aid
}).then(res => {
if (res.data.code == 200) {
http()
}
})
}
/**删除 */
const handleDelete = (index, row) => {
ElMessageBox.confirm(
'确定删除此用户么',
'删除',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
).then(() => {
sysAxios.admin_delete({
aid: row.aid
}).then(res => {
if (res.data.code == 200) {
ElMessage({
type: 'success',
message: "删除成功!!!",
})
http()
} else {
ElMessage({
type: 'error',
message: res.data.message,
})
}
})
}).catch(error => {
ElMessage({
type: 'info',
message: "取消删除",
})
})
}
/**
* 分配角色对话框 弹出事件
*/
const handleRole = (index, row) => {
dialogRoleVisible.value = true
sysAxios.admin_findById({
aid: row.aid
}).then(res => {
if (res.data.code == 200) {
console.log(res.data)
adminRoles.value = res.data.data.roles
adminId.value = res.data.data.aid
}
})
sysAxios.role_findAll().then(res => {
if (res.data.code == 200) {
allRoles.value = res.data.data
}
})
}
const onSelectionChange = (keys) => {
rids = []
keys.map(item => {
rids.push(item.rid)
})
}
/**
* 分配角色对话框 确定事件
*/
const sureRoleHandler = () => {
dialogRoleVisible.value = false;
sysAxios.admin_updateRole({
aid: adminId.value,
rids: rids
}).then(res => {
if (res.data.code == 200) {
http()
}
})
}
/**
* 详情对话框弹出事件
*/
const handleDesc = (index, row) => {
dialogDescVisible.value = true
sysAxios.admin_findById({
aid: row.aid
}).then(res => {
if (res.data.code == 200) {
descInfo.list = res.data.data.roles
}
})
}
</script>
<style scoped lang="scss">
.data-container {
background-image: -webkit-gradient(linear, 0% 0%, 100% 100%,color-stop(0, rgb(50, 153, 152)),color-stop(1, rgb(108, 201, 156)));
background-image: -webkit-linear-gradient(top left,rgb(50, 153, 152) 0%,rgb(108, 201, 156) 100%);
background-image: linear-gradient(to bottom right,rgb(50, 153, 152) 0%,rgb(108, 201, 156) 100%);
background-image: -ms-linear-gradient(top left,rgb(50, 153, 152) 0%,rgb(108, 201, 156) 100%);
height: 800px;
.data-header {
padding: 20px;
.input {
width: 300px;
}
}
.data-table {
padding: 20px;
}
.page {
position: fixed;
right: 10px;
bottom: 10px;
}
}
</style>
角色页面
<template>
<div class="data-container">
<div class="data-header">
<el-button round @click="addHander" class="button" size="large" type="primary">
<el-icon>
<DocumentAdd/>
</el-icon> 添加
</el-button>
</div>
<div class="data-table">
<!--表格数据展示 start-->
<el-table :data="roleList.list" style="width: 830px;">
<el-table-column prop="roleName" label="名称" width="200"></el-table-column>
<el-table-column prop="roleDesc" label="角色详情" width="220"></el-table-column>
<el-table-column label="操作" align="center" width="200">
<template #default="scope">
<el-button size="small" type="success" @click="handleDesc(scope.$index, scope.row)">详情</el-button>
<el-button size="small" type="danger" @click="handlePermission(scope.$index, scope.row)">分配权限</el-button>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="200">
<template #default="scope">
<el-button size="small" type="primary" @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleDelete(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--表格数据展示 end-->
<!--分页 start-->
<div class="page">
<el-pagination @current-change="currentChangeHaddler" background layout="prev,pager,next,jumper"
default-page-size="defaultPageSize" :total="totalData"></el-pagination>
</div>
<!--分页 end-->
<!--添加对话框 start-->
<el-dialog draggable v-model="dialogAddVisible" title="添加角色" width="35%" center>
<el-form :inline="true" :model="addFormInfo" status-icon label-width="120px">
<el-form-item label="名称">
<el-input v-model="addFormInfo.roleName" placeholder="请输入名称"></el-input>
</el-form-item>
<el-form-item label="介绍">
<el-input v-model="addFormInfo.roleDesc" placeholder="请输入介绍"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogAddVisible = false">取消</el-button>
<el-button type="primary" @click="sureHandler">确定</el-button>
</span>
</template>
</el-dialog>
<!--添加对话框 end-->
<!--编辑对话框 start-->
<!--destroy-on-close:每次关闭对话框时直接销毁对话框,没有缓存-->
<el-dialog draggable destroy-on-close v-model="dialogEditorVisible" title="编辑角色" width="35%" center>
<el-form :inline="true" :model="editorFormInfo">
<el-form-item label="名称">
<el-input v-model="editorFormInfo.roleName" placeholder="请输入名称"></el-input>
</el-form-item>
<el-form-item label="介绍">
<el-input v-model="editorFormInfo.roleDesc" placeholder="请输入介绍"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogEditorVisible = false">取消</el-button>
<el-button type="primary" @click="sureEditorHandler">确定</el-button>
</span>
</template>
</el-dialog>
<!--编辑对话框 end-->
<!--分配权限对话框 start-->
<el-dialog draggable destroy-on-close v-model="dialogPermissionVisible" title="分配权限" width="35%" center>
<el-table ref="multipleTable" :data="allPermissions" row-key="rid" @selection-change="onSelectionChange">
<el-table-column type="selection" :reserve-selection="true"/>
<el-table-column label="权限名" prop="permissionName"/>
<el-table-column label="权限url" prop="permissionDesc"/>
</el-table>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogPermissionVisible = false">取消</el-button>
<el-button type="primary" @click="surePermissionHandler">确定</el-button>
</span>
</template>
</el-dialog>
<!--分配权限对话框 end-->
<!--详情对话框 start-->
<el-dialog draggable destroy-on-close v-model="dialogDescVisible" title="角色详情" width="35%" center>
<el-tag v-for="permission in descInfo.list" :key="permission.pid" size="large" effect="light" class="mx-1" round
:type="success">
{{ permission.permissionName }}:[{{ permission.permissionDesc }}]
</el-tag>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogDescVisible = false">关闭</el-button>
</span>
</template>
</el-dialog>
<!--详情对话框 end-->
</div>
</div>
</template>
<script setup>
import sysAxios from "@/api/sys.js"
import {onMounted, reactive, ref} from "vue";
//初始化角色查询数据
const roleList = reactive({
list: []
})
//初始化总条数
const totalData = ref(0)
//当前页
const currentPage = ref(1)
//初始化分页显示条数
const defaultPageSize = ref(10)
//添加添加对话框控制器
const dialogAddVisible = ref(false)
//初始化添加对话框状态
const addFormInfo = reactive({
roleName: "",
roleDesc: "",
})
//编辑对话框控制器
const dialogEditorVisible = ref(false)
//初始化编辑对话框状态
const editorFormInfo = reactive({
rid: '',
roleName: "",
roleDesc: "",
})
//分配权限对话框控制器
const dialogPermissionVisible = ref(false)
//详情对话框控制器
const dialogDescVisible = ref(false)
//初始化详情对话框
const descInfo = reactive({
list: []
})
//初始化角色列表
const allPermissions = ref([])
const rolePermissions = ref([])
const multipleTable = ref(null)
let pids = []
const roleId = ref(0)
/**
* 网路请求:分页查询
* */
const http = () => {
sysAxios.role_search({
page: currentPage.value,
size: defaultPageSize.value
}).then(res => {
if (res.data.code == 200) {
roleList.list = res.data.data.records
totalData.value = res.data.data.total
}
})
}
onMounted(() => {
http()
})
/**
* 分页
*/
const currentChangeHaddler = (val) => {
currentPage.value = val
http()
}
/**
* 添加对话框弹出事件
*/
const addHander = () => {
dialogAddVisible.value = true
}
/**
* 添加对话框 确定事件
*/
const sureHandler = () => {
sysAxios.role_add({
roleName: addFormInfo.roleName,
roleDesc: addFormInfo.roleDesc,
}).then(res => {
if (res.data.code == 200) {
dialogAddVisible.value = false
http()
}
})
}
/**
* 编辑对话框 弹出事件
* */
const handleEdit = (index, row) => {
dialogEditorVisible.value = true
sysAxios.role_findById({
rid: row.rid
}).then(res => {
if (res.data.code == 200) {
editorFormInfo.rid = res.data.data.rid;
editorFormInfo.roleName = res.data.data.roleName;
editorFormInfo.roleDesc = res.data.data.roleDesc;
}
})
}
/**
* 编辑对话框 确定事件
*/
const sureEditorHandler = () => {
sysAxios.role_update({
rid: editorFormInfo.rid,
roleName: editorFormInfo.roleName,
roleDesc: editorFormInfo.roleDesc,
}).then(res => {
if (res.data.code == 200) {
dialogEditorVisible.value = false
http()
}
})
}
/**删除 */
const handleDelete = (index, row) => {
ElMessageBox.confirm(
'确定删除此角色么',
'删除',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
).then(() => {
//确认删除
sysAxios.role_delete({
rid: row.rid
}).then(res => {
if (res.data.code == 200) {
ElMessage({
type: 'success',
message: "删除成功!!!",
})
http()
} else {
ElMessage({
type: 'error',
message: res.data.message,
})
}
})
}).catch(error => {
ElMessage({
type: 'info',
message: "取消删除",
})
})
}
/**
* 分配权限对话框 弹出事件
*/
const handlePermission = (index, row) => {
dialogPermissionVisible.value = true
sysAxios.role_findById({
rid: row.rid
}).then(res => {
if (res.data.code == 200) {
rolePermissions.value = res.data.data.permissions
roleId.value = res.data.data.rid
}
})
sysAxios.permission_findAll().then(res => {
if (res.data.code == 200) {
allPermissions.value = res.data.data
}
})
}
const onSelectionChange = (keys) => {
pids = []
keys.map(item => {
pids.push(item.pid)
})
}
/**
* 分配角色对话框 确定事件
*/
const surePermissionHandler = () => {
dialogPermissionVisible.value = false;
sysAxios.role_updatePermission({
rid: roleId.value,
pids: pids
}).then(res => {
if (res.data.code == 200) {
http()
}
})
}
/**
* 详情对话框弹出事件
*/
const handleDesc = (index, row) => {
dialogDescVisible.value = true
sysAxios.role_findById({
rid: row.rid
}).then(res => {
if (res.data.code == 200) {
descInfo.list = res.data.data.permissions
}
})
}
</script>
<style scoped lang="scss">
.data-container {
background-image: -webkit-gradient(linear, 0% 0%, 100% 100%,color-stop(0, rgb(50, 153, 152)),color-stop(1, rgb(108, 201, 156)));
background-image: -webkit-linear-gradient(top left,rgb(50, 153, 152) 0%,rgb(108, 201, 156) 100%);
background-image: linear-gradient(to bottom right,rgb(50, 153, 152) 0%,rgb(108, 201, 156) 100%);
background-image: -ms-linear-gradient(top left,rgb(50, 153, 152) 0%,rgb(108, 201, 156) 100%);
height: 800px;
.data-header {
padding: 20px;
.input {
width: 300px;
}
}
.data-table {
padding: 20px;
}
.page {
position: fixed;
right: 10px;
bottom: 10px;
}
}
</style>
权限页面
<template>
<div class="data-container">
<!--添加 start-->
<div class="data-header">
<el-input class="input" @keyup.enter="searchHandle" v-model="searchInfo" size="large"
placeholder="请输入关键字"></el-input>
<el-button @click="searchHandle" class="button" size="large" type="primary" plain>搜索</el-button>
<el-button round @click="addHander" size="large" type="primary">
<el-icon>
<DocumentAdd/>
</el-icon>
<span>新增</span>
</el-button>
</div>
<!--添加 end-->
<!--表格数据展示 start-->
<div class="data-table">
<el-table :data="dataList.list" style="width: 700px;">
<el-table-column label="权限名" prop="permissionName" align="center"></el-table-column>
<el-table-column label="权限详情" prop="permissionDesc" align="center"></el-table-column>
<el-table-column label="操作" align="center" width="220">
<template #default="scope">
<el-button size="small" type="primary" @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleDelete(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--分页 start-->
<div class="page">
<el-pagination background
layout="prev,pager,next,jumper"
:default-page-size="defaultPageSize"
:total="totalData"
@current-change="currentChangeHaddler"></el-pagination>
</div>
<!--分页 end-->
</div>
<!--表格数据展示 end-->
<!--添加对话框 start-->
<el-dialog draggable destroy-on-close v-model="dialogAddVisible" title="添加" width="35%" center>
<el-form inline :model="addFormInfo" label-width="150px">
<el-form-item label="权限名">
<el-input v-model="addFormInfo.permissionName"></el-input>
</el-form-item>
<el-form-item label="权限详情">
<el-input v-model="addFormInfo.permissionDesc"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogAddVisible = false">取消</el-button>
<el-button type="primary" @click="sureHandler">确定</el-button>
</span>
</template>
</el-dialog>
<!--添加对话框 end-->
<!--编辑对话框 start-->
<!--destroy-on-close:每次关闭对话框时直接销毁对话框,没有缓存-->
<el-dialog
draggable
destroy-on-close
v-model="dialogEditorVisible"
title="编辑"
width="35%"
center>
<el-form inline :model="editorFormInfo" label-width="150px">
<el-form-item label="权限名">
<el-input v-model="editorFormInfo.permissionName"></el-input>
</el-form-item>
<el-form-item label="权限详情">
<el-input v-model="editorFormInfo.permissionDesc"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogEditorVisible = false">取消</el-button>
<el-button type="primary" @click="sureEditorHandler">确定</el-button>
</span>
</template>
</el-dialog>
<!--编辑对话框 end-->
</div>
</template>
<script setup>
import sysAxios from "@/api/sys.js"
import {onMounted, reactive, ref} from "vue";
import {ElMessage} from "element-plus";
//初始化分页查询数据
const dataList = reactive({
list: []
})
//初始化总条数
const totalData = ref(0)
//当前页
const currentPage = ref(1)
//初始化分页显示条数
const defaultPageSize = ref(10)
//搜索初始化状态
const searchInfo = ref("")
//添加添加对话框控制器
const dialogAddVisible = ref(false)
//初始化添加对话框状态
const addFormInfo = reactive({
permissionName: "",
permissionDesc: "",
})
//编辑对话框控制器
const dialogEditorVisible = ref(false)
//初始化编辑对话框状态
const editorFormInfo = reactive({
pid: '',
permissionName: "",
permissionDesc: "",
})
/**
* 网路请求:分页查询
* */
const http = () => {
sysAxios.permission_search({
search: searchInfo.value,
page: currentPage.value,
size: defaultPageSize.value
}).then(res => {
if (res.data.code == 200) {
dataList.list = res.data.data.records
totalData.value = res.data.data.total
} else {
ElMessage.error(res.data.message)
}
})
}
onMounted(() => {
http()
})
/**
* 分页
*/
const currentChangeHaddler = (nowPage) => {
currentPage.value = nowPage
http()
}
/**
* 搜索按钮
*/
const searchHandle = () => {
http()
}
/**
* 添加对话框弹出事件
*/
const addHander = () => {
dialogAddVisible.value = true
}
/**
* 添加对话框 确定事件
*/
const sureHandler = () => {
sysAxios.permission_add({
permissionName: addFormInfo.permissionName,
permissionDesc: addFormInfo.permissionDesc,
}).then(res => {
if (res.data.code == 200) {
dialogAddVisible.value = false
http()
} else {
ElMessage.error(res.data.message)
}
})
}
/**
* 编辑对话框 弹出事件
* */
const handleEdit = (index, row) => {
dialogEditorVisible.value = true
sysAxios.permission_findById({
pid: row.pid
}).then(res => {
if (res.data.code == 200) {
editorFormInfo.pid = res.data.data.pid;
editorFormInfo.permissionName = res.data.data.permissionName;
editorFormInfo.permissionDesc = res.data.data.permissionDesc;
} else {
ElMessage.error(res.data.data.message)
}
})
}
/**
* 编辑对话框 确定事件
*/
const sureEditorHandler = () => {
sysAxios.permission_update({
pid: editorFormInfo.pid,
permissionName: editorFormInfo.permissionName,
permissionDesc: editorFormInfo.permissionDesc,
}).then(res => {
if (res.data.code == 200) {
dialogEditorVisible.value = false
http()
} else {
ElMessage.error(res.data.message)
}
})
}
/**删除 */
const handleDelete = (index, row) => {
ElMessageBox.confirm(
'确定删除么',
'删除',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
).then(() => {
//确认删除
sysAxios.permission_delete({
pid: row.pid
}).then(res => {
if (res.data.code == 200) {
ElMessage({
type: 'success',
message: "删除成功!!!",
})
http()
} else {
ElMessage({
type: 'error',
message: res.data.message,
})
}
})
}).catch(error => {
ElMessage({
type: 'info',
message: "取消删除",
})
})
}
</script>
<style scoped lang="scss">
.data-container {
background-image: -webkit-gradient(linear, 0% 0%, 100% 100%,color-stop(0, rgb(50, 153, 152)),color-stop(1, rgb(108, 201, 156)));
background-image: -webkit-linear-gradient(top left,rgb(50, 153, 152) 0%,rgb(108, 201, 156) 100%);
background-image: linear-gradient(to bottom right,rgb(50, 153, 152) 0%,rgb(108, 201, 156) 100%);
background-image: -ms-linear-gradient(top left,rgb(50, 153, 152) 0%,rgb(108, 201, 156) 100%);
height: 800px;
.data-header {
padding: 20px;
.input {
width: 300px;
}
}
.data-table {
padding: 20px;
}
.page {
position: fixed;
right: 10px;
bottom: 10px;
}
}
</style>
2.路由编写
import {createRouter, createWebHashHistory} from "vue-router"
import Layout from '@/views/Layout.vue'
import {useDataStore} from "@/stores/dataStore";
const routes = [
{
//最常见404匹配规则:没有找到对应路径地址
path: "/:pathMath(.*)*",
name: "404",
component: () => import("../views/home/404.vue"),
meta: {
key: "404"
}
},
{
path: "/home/login",
name: "login",
component: () => import("../views/home/Login.vue"),
},
{
//顶级路由
path: '/',
name: 'layout',
redirect: '/home/login',
component: Layout,
children: [
{
path: "/sys/admin",
name: 'sys_admin',
component: () => import("../views/sys/Admin.vue"),
meta: {
requiresAuth: true,
key: "管理员"
}
},
{
path: "/sys/role",
name: 'sys_role',
component: () => import("../views/sys/Role.vue"),
meta: {
requiresAuth: true,
key: "角色"
}
},
{
path: "/sys/permission",
name: 'sys_permission',
component: () => import("../views/sys/Permission.vue"),
meta: {
requiresAuth: true,
key: "权限"
}
},
{
path: "/book/book",
name: 'book_book',
component: () => import("../views/book/Book.vue"),
meta: {
requiresAuth: true,
key: "图书"
}
},
{
path: "/book/bookCategory",
name: 'book_bookCategory',
component: () => import("../views/book/BookCategory.vue"),
meta: {
requiresAuth: true,
key: "图书分类"
}
},
{
path: "/book/bookPublisher",
name: 'book_bookPublisher',
component: () => import("../views/book/BookPublisher.vue"),
meta: {
requiresAuth: true,
key: "出版社"
}
},
]
},
]
const router = createRouter({
routes,
history: createWebHashHistory(import.meta.env.BASE_URL)
})
//前置导航守卫
// router.beforeEach((to, from, next) => {
// if (to.meta.requiresAuth) {
// const dataStore = useDataStore()
// if (!dataStore.isLogin) {
// next({path: "/home/login"})
// } else {
// next()
// }
// } else {
// next()
// }
// }
// )
//后置导航
router.afterEach((to, from) => {
//存储路径(解决页面刷新后 菜单高亮与面包屑不匹配)
localStorage.setItem("active", to.path)
//若meta中的key存在,则修改当前面包屑
if (to.meta.key) {
const dataStore = useDataStore()
dataStore.breadcrumb = to.meta.key
}
})
export default router;
3.侧边栏编写
<template>
<div class="slider-navs" :style="{ width: dataStore.isCollapse ? '64px' : '210px' }">
<div v-if="dataStore.toggleStore" class="logo">{{ dataStore.isCollapse ? '图书馆' : "图书馆管理系统后台" }}</div>
<el-menu
unique-opened
router
:default-active="active"
:collapse="dataStore.isCollapse"
>
<el-sub-menu index="1" v-if="dataStore.islogin">
<template #title>
<el-icon>
<Tools/>
</el-icon>
<span style="font-size: 17px;">系统管理</span>
</template>
<el-menu-item index="/sys/admin">
<van-icon
name="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAA7VJREFUWEfFlk2IFEcUx/+ve1eRRAyKJOQDFA+aNURwBYMhsCYz3VOjXgIJHowf+HVQknV6VgkJZCUQlJme7MWLRlZFL3pQgm5N92zYwSUxB41oohCiIYQEBU+7Ioi69UL3zsjMbs90dS5b0Kf61//96r3qV0WY4UEzHB+JAfrs8mYFToGxAsDbAK4Fn0F0uuBlRpNuSBtgzwfDC2abTw8TsL1NkM9dXxxKAqENkLOkJCATa878jVvJfhGrqwm0AHJ2eTMxn9Q0fUQw3in69m86ei0Ax5I/AlijY1jTFFxf7NfRxwLs6r7aOXfBg4cAZusYhhqC53oivlyhNGb02uWVJnNw0pOMcdcX83QWxALkLO8Ngvpbx6xBc8v1xVs6a2IBAhPHKv8L8Ks6hrUSnHA9sU1HrwkgvwewQccw1DDtdCuZ73T0WgB569JqhvGzjiEIP7ieSGlpdQ5h3Shnya8I6G9nzMADMHaUKiLImNbQykDdqTd18U2TzG9BsKe6M3DcfKK+LFTX3deKXBMlAqgbO2Koi5/RchC6DMZN6uCbBZm9myRwXZsIoC878go/ebyMDZ4DRXPYVGTAHJsAxg1+Oj5BnWMdTONF336kCxMLkLe895nUZ2B0A3itjfE11xer8inZUxwW1bquTwwtaZedtgCOLY8Fh0pzN7uJkGLGRwz0l3xxMJeWW4kwCELLvtASIG/Ls4GZRvB/iHCFFB9hoq8ZeG/aGkbVrYi1UV6RAI4tT4HxSVxwBn4p+aI7/EUJC8HYAuDFFutypHAdJr1Q9DKXWh7CnDWUJ1AhLnjY8GD0Ayq40Z73hyD9iujogJe5t88uzzegDoCp8Wq+0qE6xOHh9Fjg0ZSBvOUtZqg/dYKHGoKnQHsN5j8mgXC+5IsPp653rKH7AL0cahgflyriXGQGnHR5B4iPaQNMBg13H2SBQANFP7NvGkBajoDQUz+cjfNNGXBqwiQAgLGKodZPloEqrp+xpmdA3ghf0BGHsRnAkncALNEFCHZEhEVgbH2eUoW1jX0g6AtsYKTB84zri03RJbDk40RPL+ZBBBcQNR2y38E4SIx7bKALwKcAljYA7HZ9cTQawJaDjbuJywQBo8xchsIF6qR5rPBT5BpGdcLEtoGy+GvqfFMJcmmZJcIRAIvigjfN12rrWDJ4ii8P5xhVUNi+50bVvmUf6O05/5LZOWsjk/EuMV5vC0K4DaJfYajLrszerjew+q8WPmTYOMTAyVJFnIjyir2MEmXif4hnHOA/TxJTMNnGhbcAAAAASUVORK5CYII="></van-icon>
<span>用户</span>
</el-menu-item>
<el-menu-item index="/sys/role">
<van-icon
name="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAA81JREFUWEfVV11oHFUYPefubuoGCtGSH4rFPkQfIkoftNEXKYVChRYptSvWzZJkY/rQhgoVf0A0Cv6hUg1tEbU7skmlNCBFCUKg+KAIWvJSTKD0RWiMu5tqopUq7s49ssE2Ozuzu7NBKJ2Xebjnfud857v3+2aIm/zwJvPj1hTQ5TibEUGPJR40whyMZnPJwbm1uNm0Ax3jziuURv1knFK0lC7sfzrfjJCmBNQmv06pCy5bdl7p6/slrIiaAjrGT+6FuJXAVkIzRUWPRo37A4SN9YKLXHGHUhl3D4BpGc0UkunpoH2BAgIy/YhATsDLDTMjFmT1OMnvKrEEE7nUwGT1fp+AzonMLlh8WQkUcYDCdgBPNBQAIJ8aZGc2Iw+WWHARe6C6PH4BWecLQLs9AoCdIA5TeDSMAMr2iub7amy5PIW+gVe9zlShOrOZHIBOD0gYkUE3hMNhBMT+sRuKLebXALs/z6UG99YXMJ752X/QdJoy34g63lCAcNk1sd6Iigt+rKbyqfSuBg74SwDhsgzTlAJPspdIU4Q5IWgqoFd8nE8NDNcVUOuuSzwCYx+j+Eh9F/ikqDspvLOmM9B+yrnbuLoA4DZPAOGSgPdIfFhLgMgZAC9SOgugtQr3t43w/sWnBi7VdaC8WMsFAq9Z0tZoxbMulYpYnAWxKUz2Kw2rVjaBIoTf3ZI2RWJ8F4CnlgAegvQ8yD1hyesK6Mw6RwE94w+mLaZkb1ck8nXlmsvYRoPScJA7ot1T6Bsql8X3+BxoH/+k28A8C+GAp1ZEFlafikwCGAyI9SNgX4d4H8j9ADavYlQizUvuumvHFxMH/ww8A+2Os8VElYZwqCp4xpKTRuoP1YqlaWvNIcbYQWtHqvYswmIs1mpPzCeGfrtRgo7xzDCFtwG0XScn8C3AN0UNQfDVtWFDAiZFvE+LO2BwDMJdN/aUBxb0XKEvfYpdWWefoDNVzeQtgOVrlADQFYKsNkR6wzUtxyIqfgZgm8d+2d7y1CqPzYcrMs8C+CnU6A2tjLMsKaEoyq18VYR0zjM2BVyMQEkLng8dOyyQ+GAFWjXQPAJIvmCte5U0jYdOWOJV3JKoEYoTvlvQlT3ZD3A3wNOW6AnudM0z+nYIO0QeMdCsjPkqn+w/5+sDXROZHlmeAXTv/0BZGeK8vfrX9sWDNfpAJbLNcdpaou42WO4guA9EexNi/gCwBGD5v3fzH6XVZN1jY+uurF8fj0aj8Ygpxlk0cRo3Dpo4DK+5RSy3tJaW5ufmlzE6apsQe4v+mjWTYSNsU39GjYKtZf1fR6mSeBOA3XoAAAAASUVORK5CYII="></van-icon>
<span>角色</span>
</el-menu-item>
<el-menu-item index="/sys/permission">
<van-icon
name="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAABHJJREFUWEe9l21sU1UYx//P7dZuaap7E9zSwVRw6kQhalxvR5ifVCKSqWMooS06X6IzUYdsMSoGZyKiQZMpi0LmENAwaN0IwS+6BraRSYCMF6G3i5ME6zpGW9jmNtj6mHtHoe06e1vE8605z/P//845z3N6LiHJUerozbiE8UYEgx7txHiNc1nRUDJSlEySyeF6iRhVAM1T8glHGdxwsKzw60T1VAMUO04VaFhTHgRXEOiBWEYMPkwk7BFY+L79qTskNTBXAcwOaR0zbmfAQ0TDysI4mMaAkUFGAkrVCIZiGHAS4zwRBhgYAHgmQLmDo0P60Usj7W6b+b3JzbsyRLvrM4DeSsQk0djB0SHn2OXRUiZ87raIb0YAmOzSJgJeSVRUbXzI/ErNbJEsYmXUDri3AbxCrWAicRHmk4k7JatYEbkDu6VWIixJRDgUq6dhPC38gFw6C4EZXtyKzuBCnOYixDCXD36vZBGfiD6CtkQLTRYoom58mLImJndnX16gVrshI3qSCU63RXzkugEMNIg6TTXy6cwUgMPe7EFcOGd4J3szRkgfMf+fAYjCfqzWfKSIHwqa0Bosgwf5eGGgOpAdOKmsfK9+OX7UW24MQIXwHSo02xTxb4JV2DexRDnztLG/Sj8dmKxnKfU+bMj8+MYDtATLUT+8XOnzOy8fw9v+2v8XoKMvL9A2bsrQ8Qhmj/fg/rEuBcCZvhjbDVVqdsC1j0CPqW3D8Orv8Br9Of7jmbFy12Y1wJMyK3KK8ZNkEx+PuoikZgDPqAEIP/v2/nzfLb5jWdF5sul2w6tKDUxpQ2CX2yqWRwI4pEYwbGoA6lOeRx79iQ7vLH+Ov1tZeat+BW4KBmDgizikLcFp3XwMkyG2HNG3ksW0KgLAbHfVM+g1NQD21Eexv/8230zfEWXlsvkefQK3OONLySYqhRH2byjJvVIzHcBCwYmlwi5kkg8n+g2+Gb6jWV6NEV1pixIzB8Cg9W6rSWmTawC7JRsIjdMBVApfYbGmBQe8+X7dhbOZq3Mm+z+ZQYRKl0XcEgEg/xDtUi+AgnDRu+g3lGma8RB1IlTtZ1Lmoi7ri2S85ZyLQ6PaXM/LD/49BcDscL/BzBvDlUMV39Fn9OcEjmf+nP4kerV3o0u3KFmAeskqvh5KjngTivaeGQD/CvDsUIAMYDz3SyAncDKjW1eM+pvfT9YYIBogmihxrSxxxQSYPAbXiwBdfd3OH245kT74x73y3CntAvSk3pM0ADPXuG3mT8IFYr6KRbu0A8CzMR8TSdujWbKKy6LTp32Wz9txpE3+Y0neLyIzpvmUIgxPMe7sTNePYDMDz10fBDVJVtO0N2zcD5PCrQfXMPP6JCDOM9G7boup4d9y4wLIyYVNHUuZUQuiYpUgdgiaddLKh7vjxasCUEQ+aEuZW6CtJSL5Co185F1z8RBznctm3hTPeNo2jJc4p6lzARFVE0d9QxC2jk8Idb+vKnbH04jbhmoE5jQeKCWNZq3A0IGw0WUR5fdEwuMfvbLVMJxAex8AAAAASUVORK5CYII="></van-icon>
<span>权限</span>
</el-menu-item>
</el-sub-menu>
<el-sub-menu index="2" v-if="dataStore.islogin">
<template #title>
<el-icon>
<Notebook/>
</el-icon>
<span style="font-size: 17px;">图书管理</span>
</template>
<el-menu-item index="/book/book">
<van-icon
name="data:image/png;base64,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"></van-icon>
<span>图书</span>
</el-menu-item>
<el-menu-item index="/book/bookCategory">
<van-icon
name="data:image/png;base64,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"></van-icon>
<span>分类</span>
</el-menu-item>
<el-menu-item index="/book/bookPublisher">
<van-icon
name="data:image/png;base64,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"></van-icon>
<span>出版社</span>
</el-menu-item>
</el-sub-menu>
</el-menu>
</div>
</template>
<script setup>
import {ref} from 'vue';
import {useDataStore} from "@/stores/dataStore"
const dataStore = useDataStore()
const active = ref("/")
if (localStorage.getItem("active")) {
active.value = localStorage.getItem("active")
}
</script>
<style scoped>
.slider-navs {
background-color: #ffffff;
position: fixed;
left: 0;
top: 0;
bottom: 0;
transition: 0.3s ease-in;
}
.logo {
background-color: #ffffff;
width: 100%;
height: 60px;
font-size: 20px;
font-weight: 900;
text-align: center;
line-height: 60px;
cursor: pointer;
}
/**el-menu默认样式 */
.el-menu {
border-right: 0 !important; /*去掉element menu的右侧边框 */
border-radius: 5px !important;
}
.el-menu-item {
border-radius: 15px !important;
}
.el-menu-item.is-active {
font-weight: 900 !important;
font-size: 18px !important;
color: #06b4c0 !important;
}
</style>