后端
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 {@TableIdprivate 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 {@TableIdprivate 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 {@TableIdprivate 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 mapperPUBLIC "-//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">DELETEFROM admin_roleWHERE aid = #{id}</delete><select id="findById" parameterType="int" resultMap="adminMapper">SELECT *FROM adminLEFT JOIN admin_roleON admin.aid = admin_role.aidLEFT JOIN roleON admin_role.rid = role.ridLEFT JOIN role_permissionON role.rid = role_permission.ridLEFT JOIN permissionON role_permission.pid = permission.pidWHERE admin.aid = #{id}</select><insert id="addRoleToAdmin">INSERT INTO admin_roleVALUES (#{aid}, #{rid});</insert><select id="findAllPermission" resultType="jkw.pojo.Permission" parameterType="string">SELECT DISTINCT permission.*FROM adminLEFT JOIN admin_roleON admin.aid = admin_role.aidLEFT JOIN roleON admin_role.rid = role.ridLEFT JOIN role_permissionON role.rid = role_permission.ridLEFT JOIN permissionON role_permission.pid = permission.pidWHERE 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 mapperPUBLIC "-//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">DELETEFROM role_permissionWHERE rid = #{rid}</delete><delete id="deleteRoleAllAdmin" parameterType="int">DELETEFROM admin_rolewhere rid = #{rid}</delete><select id="findById" parameterType="int" resultMap="roleMapper">SELECT *FROM roleLEFT JOIN role_permissionON role.rid = role_permission.ridLEFT JOIN permissionON role_permission.pid = permission.pidWHERE role.rid = #{id}</select><insert id="addPermissionToRole">INSERT INTO role_permissionVALUES (#{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 mapperPUBLIC "-//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">DELETEFROM role_permissionWHERE 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 {@Autowiredprivate AdminMapper adminMapper;@Overridepublic void add(Admin admin) {adminMapper.insert(admin);//初始化用户,不然添加后什么角色都没有,会报错adminMapper.addRoleToAdmin(admin.getAid(), 2);}@Overridepublic void update(Admin admin) {// 如果传来空密码则密码还是原来的密码if (!StringUtils.hasText(admin.getPassword())) {String password = adminMapper.selectById(admin.getAid()).getPassword();admin.setPassword(password);}adminMapper.updateById(admin);}@Overridepublic void delete(Integer id) {// 删除用户的所有角色adminMapper.deleteAdminAllRole(id);// 删除用户adminMapper.deleteById(id);}@Overridepublic void updateStatus(Integer id) {Admin admin = adminMapper.selectById(id);admin.setStatus(!admin.isStatus());//状态取反adminMapper.updateById(admin);}@Overridepublic Admin findById(Integer id) {return adminMapper.findById(id);}@Overridepublic Page<Admin> search(int page, int size) {return adminMapper.selectPage(new Page<>(page, size), null);}@Overridepublic void updateRoleToAdmin(Integer aid, Integer[] rids) {// 删除用户的所有角色adminMapper.deleteAdminAllRole(aid);// 重新添加管理员角色for (Integer rid : rids) {adminMapper.addRoleToAdmin(aid, rid);}}@Overridepublic Admin findByName(String username) {QueryWrapper<Admin> wrapper = new QueryWrapper();wrapper.eq("username", username);Admin admin = adminMapper.selectOne(wrapper);return admin;}@Overridepublic 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 {@Autowiredprivate RoleMapper roleMapper;@Overridepublic void add(Role role) {roleMapper.insert(role);}@Overridepublic void update(Role role) {roleMapper.updateById(role);}@Overridepublic void delete(Integer id) {// 删除角色roleMapper.deleteById(id);// 删除角色_权限中间表的相关数据roleMapper.deleteRoleAllPermission(id);// 删除用户_角色中间表的相关数据roleMapper.deleteRoleAllAdmin(id);}@Overridepublic Role findById(Integer id) {return roleMapper.findById(id);}@Overridepublic List<Role> findAll() {return roleMapper.selectList(null);}@Overridepublic Page<Role> search(int page, int size) {return roleMapper.selectPage(new Page(page,size),null);}@Overridepublic 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 {@Autowiredprivate PermissionMapper permissionMapper;@Overridepublic void add(Permission permission) {permissionMapper.insert(permission);}@Overridepublic void update(Permission permission) {permissionMapper.updateById(permission);}@Overridepublic void delete(Integer id) {// 删除权限permissionMapper.deleteById(id);// 删除角色_权限表中的相关数据permissionMapper.deletePermissionAllRole(id);}@Overridepublic Permission findById(Integer id) {return permissionMapper.selectById(id);}@Overridepublic List<Permission> findAll() {return permissionMapper.selectList(null);}@Overridepublic 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 {@Autowiredprivate AdminService adminService;@Autowiredprivate 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 {@Autowiredprivate 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 {@Autowiredprivate 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/3LYOICorsConfigurationSource 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;}@Overrideprotected 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();}@Beanpublic 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 {@Autowiredprivate AdminService adminService;@Overridepublic 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 {@Overridepublic 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 {@Overridepublic 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 {@Overridepublic 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 {@Overridepublic 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 {@Overridepublic 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.recordstotalData.value = res.data.data.total}})
}
onMounted(() => {http()
})
/*** 分页*/
const currentChangeHaddler = (val) => {currentPage.value = valhttp()
}
/*** 添加对话框弹出事件*/
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 = falsehttp()}})
}
/*** 编辑对话框 弹出事件* */
const handleEdit = (index, row) => {dialogEditorVisible.value = truesysAxios.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 = falsehttp()}})
}
/*** 修改用户状态*/
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 = truesysAxios.admin_findById({aid: row.aid}).then(res => {if (res.data.code == 200) {console.log(res.data)adminRoles.value = res.data.data.rolesadminId.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 = truesysAxios.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.recordstotalData.value = res.data.data.total}})
}
onMounted(() => {http()
})
/*** 分页*/
const currentChangeHaddler = (val) => {currentPage.value = valhttp()
}
/*** 添加对话框弹出事件*/
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 = falsehttp()}})
}
/*** 编辑对话框 弹出事件* */
const handleEdit = (index, row) => {dialogEditorVisible.value = truesysAxios.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 = falsehttp()}})
}
/**删除 */
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 = truesysAxios.role_findById({rid: row.rid}).then(res => {if (res.data.code == 200) {rolePermissions.value = res.data.data.permissionsroleId.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 = truesysAxios.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 backgroundlayout="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-dialogdraggabledestroy-on-closev-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.recordstotalData.value = res.data.data.total} else {ElMessage.error(res.data.message)}})
}
onMounted(() => {http()
})
/*** 分页*/
const currentChangeHaddler = (nowPage) => {currentPage.value = nowPagehttp()
}
/*** 搜索按钮*/
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 = falsehttp()} else {ElMessage.error(res.data.message)}})
}
/*** 编辑对话框 弹出事件* */
const handleEdit = (index, row) => {dialogEditorVisible.value = truesysAxios.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 = falsehttp()} 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-menuunique-openedrouter: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-iconname="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-iconname="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-iconname="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-iconname="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAAC51JREFUeF7tnVlsFMkZx/89NjM9hw/CEVCwwcYGA4bFsLkgCbBLjl3QPqwiXrISkEi7TyEPhOGQcihShMAQUB4SJVkJWFiwucHYBnyCLy4DxsaAuW8C4rDNwmDPTEU1WRa3p7GrPd2erp4qqWXLrv7qO37z/8o97R4JYsR0BqSYjl4EDwFAjEMgABAAxHgGYjx8oQACgBjPQIyHLxRAABDjGYjx8IUCCABiPAMxHr5QAAFAjGcgxsOPSAFWrVr1K5vNlhFJDoPB4AubzdZGCGkD0CpJ0tNAIHA3PT397rx58wKR2I72uevWrUvu6OgYbrPZhgMYFgwG6fcePf0ihNyUZXnbokWLXvXFbp8BWL16NenLghrPeQDgHoAmSZKqA4HAsWXLljVqtGHo9DVr1mQByAoEAuMkScqSJCmDEEILTg/Z0MXfGL8RCARmLV++/IbW9foEwOrVqz8F8C+ti+k0/zGAakLIcUmS6v1+f/2KFSvozwwf69ev/3ZnZ+c0Qsg0SZJCXw1flH2BjV6vdyH79P/P7BMAubm5fyKE/FnrYgbN9wM4CaBCkqSyJUuWlOu5zsqVK3NsNttcSZI+APBDPW3rbKvS6/XO0mrTCgB0j/k6gDIA5V8D8VBrUtauXTsmGAzOJYTMBaA5qVrX02l+hdfrfU+rLd0AmD59uta1Q/M7OjrQ2dmpOF6+fIlHjx4hEIh4D/gVhYEQcgjA5qVLl7b35GRubm4aIeR3AOgR8bDb7XC73fB4PKGv9JBlfbYFNTU13f0r93q972t1WlcApk3TtyU+fvw4BAI9Hj58iHv37sHn82mN8fV8uqHMj4uL+8fixYtbuhrJzc11dyn8UK0LDB48GMOGDcPw4cMxZMiQb4o9YMAAraaY5t++fRt5eXnWB0AtGxSGO3fuhI5bt27hxYsXTEnrOkmSpAK/3/83+rO4uLgcAL8GkM1iKD4+PlTslJQUpKamhopuVKHf5g+NOz8/v/uvy7xe72yWGBS50HoCna+2CaQtQG8FYPHtwYMHIWW4e/du6GtbG72coO8YOnQoMjMzQ8UeMWJEvxe8ezRvAaDU6/X+VGvkpm4BWoOh8+/fv4/Lly+HjidPnvTFROgc2rczMjJCR1paWp/tGHHizZs3sX379u6mS7xe78+0rmc5AF4ngBDyDQgtLS3w++lfi70Pp9MZUrLs7GzQTZwZhxoAhJCSpUuXGgOAvOHpTNjwV0CaBALPrK/qQY+uI1otgKVAtC1QCKgq0L3D20ZWVlao+IMGDWIxG7U5agBcsY/AF8kfUp/aIUkNCAb/4Fs4sLI3J3tVAHnjs98A+LyrId4A6Or71atXUVZWhtbWVkVuxo8fjzlz5vSWL1P8/saNG9ixY4fClyuOFHyRRK9VvRnB+LgJHZ8kNPfkdO8AbGqtAiE/sgoANI7S0lKcOXNGkZfZs2cjJ4f+QWD+oQbAZXsKNicrAYBEan3zB/Z4gaZ3ADY+o9vqBAGAecC4fv06du7cqXBIHQA8981PVtSuexQsAIS968dzC7CqArTYU7CluwIA8C1I7rHGAoCvXxI8tQA1BWixp2JL8i/CZEoAoKLcvO8Brl27hl27dikiEwBoaNFWBOCSPRVfCgVgo8CSADhG4sukn4sWwIKAAOBNlsQmkMNNIL2YtXv3bgXrF+2p2CpaAMvrn/8LQaoAOEZiqxlbAH13LpqDvoXbfWhpAWb0/8qVK9izZ48irAuOkdhmRgBOnz4dzfpjypQpEQFgRv8FABqQihUALjpGYWtS+LvBUb8QZMZXkJYWYEb/6dvae/fu7dYCRmGbACBcGqyoAOoApGFbUvgdYVFXADNuorQogBn9VwOg2T4KeckmbAEa2nW/TdUCQL85pWEhVQAcacgzowJoiKvfpvIOAL29bd++fYp8NcvpyEsMvys86i2g36qqYSHeAbh06RL279+viPi8Iw35QgHYKLAmAOnITxIKwESAFQFocqRjuwCAqf7c3xSq1gKa5NHYnhj+v6FiD6DCBO8KcPHiRRQUFCgiEwCwvfhDs3gH4MKFCzhw4IAi4kbHaOxIEgrAhAHvAKgpQKOcgR2J4c+HEC3Agi1AVQHkTOxIDH+YiQAgRgA458jAziShADHRApqbm1FYWKiI9ZyciZ1CAZjqz/0mUA2ABjkTu8wIgBnfTdOyCTSj/1wBYMYbKrQAYEb/z58/j6KiIoXcNchjsCtxZpgERn0TaMYEWhGAs3ImdpuxBQgA2PYlb5uldkdTU1MTiouLFaecdY7B7gShAGF5tOItYWoAnJEzsceMCmDGTZSWFmBG/9UBGIM9ZtwDRCaAxpytBQBjPIjMamNjIw4ePKgwcsY5FnsSZphvExhZqMacbUUATstjsFcoABswvANw7tw5HDpEn3/9ZpyWx2JvolAAJgJ4B0CtBdTLY7FPAMBUf+4vBaspQL0zC/sSfiL2ACwI8K4AAgCWKvcwh3cAGhoacPjwYUWEp+Qs7E8UCsCEhiUBcI7D/oQfixbAQoAVATgpZ6FAKABL+fm/KfTs2bMoKSlRBHvSOQ4FQgFiGYDxKEhQPNM7lIyovx3MVpL+ncV7C6BPOqcxdB0nnONxQADABhLvAKi1AAEAW+1Ds3gHQFUBXBNwwBP+0QCiBaiAwTsA9CYb+qknXcdx5wQUJpgQADO+n64FADP6rwqAKxuFnvAP7oy6AohbwjT0JpWpanc0qQFwzDkBRWZUAAFAfwGQjaIEoQBh2bbiPYH19fUoLy9XxHrMNRFFnvBPtxctwIKPij116hQqKioUANQ5s1FsRgUw4yaK902gmgLUubJRbMZNYGQd0JiztQBgjAeRWeVKASIL1ZizLQmAayKKzbgHMKaEkVnlHYCTJ0+islL5scB1AgB2KKwIQK1rIg4KBWCDwJoATMJBzw/CEhD1PwPZStK/s3gH4MSJEzhy5IgiabUuAQAzRVYEoMY1CYeEArAxYE0A3sEhz/dFC2BBgHcAjh8/jqNHjypCrXa9g8MCAJby839DiACArc5vncW7Ahw7dgxVVVVKBXBPxmH390QLYGGDdwDUFKDKNRklHgEAS/25vydQTQGq3DkocX9XKAALAbwrQF1dHaqrqxWhHnVNRqlQAJby878JVAXAnYNSoQCxDMAUlLrfFS2ABQErtoAjrhyUecQegKX+3G8Ca2trUVNTo4j1iHsKyoQCMNXfkgBUuqag3BPlFsCW/ujPam9vB33MStcxY8YM+P3+6DvH6EF3Bah0T0W5e2r09gCMfotpBmVAAGBQYnkxW+GeCnp0H4bcEPLuywv4qF15LZqXRFnVT/pxMfRjY/oFALrIXx7+26q55DKuPw79VNVvQxTg9UqTfJcxKNDGRcI8wZfI8bUgnvS80fMjDo3yaDyLS+AirnabC6ec497qq6EAcJGhLk4mBF9gblsVxnXcVHX9vCM9dFcNL8Vnyb8eANCXOB8vB4aMOEgnPnuyG4MDrYrZ9+MH45/f+pjBAkdTJDz3zU/usXZSb+HIm1qrQEj446d6O9HEv08OPscvn5Uh1f/fkJeX7SnYnPyBiT3uo2sSqfXNHxj+2JAu5noHYMPTmZAk5b+i9tEfM5023P8YH7dV4JVkx+cDPzKTazr5Ip0PxtvmdXyS0NyTwV4BoCfbt7SPtwX8/wGkSSDw6ORh1M2kd9zFNft3ou6Hzg60Q5IagnG2z3orPl2XCQCdHTTEnLyptRCEfGiI8XCjN3wLktP6aS1Dl7EOABufvw/4lU9PNCp1hCz0LRy40Sjz/WnXMgDQpDk3PP07kaTfGplAAqx9tSD590au0Z+2LQUATZxjY+s6gMyUgMm6JlKSjhNCqq1UfEvtAXQtdgwZs5wCxFDtdAlVAKBLGvk1IgDgt3a6eC4A0CWN/BoRAPBbO108FwDokkZ+jQgA+K2dLp4LAHRJI79GBAD81k4XzwUAuqSRXyMCAH5rp4vn/wO+GykIr56gUwAAAABJRU5ErkJggg=="></van-icon> <span>图书</span></el-menu-item><el-menu-item index="/book/bookCategory"><van-iconname="data:image/png;base64,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"></van-icon> <span>分类</span></el-menu-item><el-menu-item index="/book/bookPublisher"><van-iconname="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>