mirror of
https://gitee.com/lab1024/smart-admin.git
synced 2025-09-23 13:56:39 +08:00
v3.20.0 【新增】优化登录使用spring cache;【新增】优化部门cache;【新增】代码生成枚举;【优化】三级等保Label显示宽度
This commit is contained in:
parent
f198a949c9
commit
3fb4dfad09
@ -20,11 +20,6 @@ public class AdminCacheConst extends CacheKeyConst {
|
||||
*/
|
||||
public static final String DEPARTMENT_LIST_CACHE = "department_list_cache";
|
||||
|
||||
/**
|
||||
* 部门map
|
||||
*/
|
||||
public static final String DEPARTMENT_MAP_CACHE = "department_map_cache";
|
||||
|
||||
/**
|
||||
* 部门树
|
||||
*/
|
||||
@ -54,4 +49,20 @@ public class AdminCacheConst extends CacheKeyConst {
|
||||
public static final String CATEGORY_TREE = "category_tree_cache";
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录相关
|
||||
*/
|
||||
public static class Login {
|
||||
|
||||
/**
|
||||
* 请求用户信息
|
||||
*/
|
||||
public static final String REQUEST_EMPLOYEE = "login_request_employee";
|
||||
|
||||
/**
|
||||
* 请求用户信息权限
|
||||
*/
|
||||
public static final String USER_PERMISSION = "login_user_permission";
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.lab1024.sa.admin.module.business.goods.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import net.lab1024.sa.admin.module.business.goods.constant.GoodsStatusEnum;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package net.lab1024.sa.admin.module.business.oa.enterprise.controller;
|
||||
package net.lab1024.sa.admin.module.business.oa.enterprise;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@ -8,7 +8,6 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.lab1024.sa.admin.constant.AdminSwaggerTagConst;
|
||||
import net.lab1024.sa.admin.module.business.oa.enterprise.service.EnterpriseService;
|
||||
import net.lab1024.sa.admin.module.business.oa.enterprise.domain.form.*;
|
||||
import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseEmployeeVO;
|
||||
import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseExcelVO;
|
@ -1,4 +1,4 @@
|
||||
package net.lab1024.sa.admin.module.business.oa.enterprise.manager;
|
||||
package net.lab1024.sa.admin.module.business.oa.enterprise;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import net.lab1024.sa.admin.module.business.oa.enterprise.dao.EnterpriseEmployeeDao;
|
@ -1,4 +1,4 @@
|
||||
package net.lab1024.sa.admin.module.business.oa.enterprise.service;
|
||||
package net.lab1024.sa.admin.module.business.oa.enterprise;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.google.common.collect.Lists;
|
||||
@ -13,7 +13,6 @@ import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseEm
|
||||
import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseExcelVO;
|
||||
import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseListVO;
|
||||
import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseVO;
|
||||
import net.lab1024.sa.admin.module.business.oa.enterprise.manager.EnterpriseEmployeeManager;
|
||||
import net.lab1024.sa.admin.module.system.department.service.DepartmentService;
|
||||
import net.lab1024.sa.base.common.code.UserErrorCode;
|
||||
import net.lab1024.sa.base.common.domain.PageResult;
|
@ -3,7 +3,7 @@ package net.lab1024.sa.admin.module.business.oa.invoice.service;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.lab1024.sa.admin.module.business.oa.enterprise.service.EnterpriseService;
|
||||
import net.lab1024.sa.admin.module.business.oa.enterprise.EnterpriseService;
|
||||
import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseVO;
|
||||
import net.lab1024.sa.admin.module.business.oa.invoice.dao.InvoiceDao;
|
||||
import net.lab1024.sa.admin.module.business.oa.invoice.domain.*;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package net.lab1024.sa.admin.module.system.datascope.controller;
|
||||
package net.lab1024.sa.admin.module.system.datascope;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
@ -5,7 +5,6 @@ import net.lab1024.sa.admin.module.system.department.domain.entity.DepartmentEnt
|
||||
import net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -32,4 +31,5 @@ public interface DepartmentDao extends BaseMapper<DepartmentEntity> {
|
||||
*/
|
||||
List<DepartmentVO> listAll();
|
||||
|
||||
DepartmentVO selectDepartmentVO(@Param("departmentId")Long departmentId);
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ public class DepartmentCacheManager {
|
||||
log.info("clear " + cache);
|
||||
}
|
||||
|
||||
@CacheEvict(value = {AdminCacheConst.Department.DEPARTMENT_LIST_CACHE, AdminCacheConst.Department.DEPARTMENT_MAP_CACHE, AdminCacheConst.Department.DEPARTMENT_SELF_CHILDREN_CACHE, AdminCacheConst.Department.DEPARTMENT_TREE_CACHE, AdminCacheConst.Department.DEPARTMENT_PATH_CACHE,}, allEntries = true)
|
||||
@CacheEvict(value = {AdminCacheConst.Department.DEPARTMENT_LIST_CACHE, AdminCacheConst.Department.DEPARTMENT_SELF_CHILDREN_CACHE, AdminCacheConst.Department.DEPARTMENT_TREE_CACHE, AdminCacheConst.Department.DEPARTMENT_PATH_CACHE,}, allEntries = true)
|
||||
public void clearCache() {
|
||||
logClearInfo(AdminCacheConst.Department.DEPARTMENT_LIST_CACHE);
|
||||
}
|
||||
@ -56,19 +56,8 @@ public class DepartmentCacheManager {
|
||||
return departmentDao.listAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 部门map
|
||||
*
|
||||
*/
|
||||
@Cacheable(AdminCacheConst.Department.DEPARTMENT_MAP_CACHE)
|
||||
public Map<Long, DepartmentVO> getDepartmentMap() {
|
||||
return departmentDao.listAll().stream().collect(Collectors.toMap(DepartmentVO::getDepartmentId, Function.identity()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 缓存部门树结构
|
||||
*
|
||||
*/
|
||||
@Cacheable(AdminCacheConst.Department.DEPARTMENT_TREE_CACHE)
|
||||
public List<DepartmentTreeVO> getDepartmentTree() {
|
||||
@ -78,7 +67,6 @@ public class DepartmentCacheManager {
|
||||
|
||||
/**
|
||||
* 缓存某个部门的下级id列表
|
||||
*
|
||||
*/
|
||||
@Cacheable(AdminCacheConst.Department.DEPARTMENT_SELF_CHILDREN_CACHE)
|
||||
public List<Long> getDepartmentSelfAndChildren(Long departmentId) {
|
||||
@ -89,7 +77,6 @@ public class DepartmentCacheManager {
|
||||
|
||||
/**
|
||||
* 部门的路径名称
|
||||
*
|
||||
*/
|
||||
@Cacheable(AdminCacheConst.Department.DEPARTMENT_PATH_CACHE)
|
||||
public Map<Long, String> getDepartmentPathMap() {
|
||||
@ -125,7 +112,6 @@ public class DepartmentCacheManager {
|
||||
|
||||
/**
|
||||
* 构建部门树结构
|
||||
*
|
||||
*/
|
||||
public List<DepartmentTreeVO> buildTree(List<DepartmentVO> voList) {
|
||||
if (CollectionUtils.isEmpty(voList)) {
|
||||
@ -192,7 +178,6 @@ public class DepartmentCacheManager {
|
||||
|
||||
/**
|
||||
* 获取子元素
|
||||
*
|
||||
*/
|
||||
private List<DepartmentTreeVO> getChildren(Long departmentId, List<DepartmentVO> voList) {
|
||||
List<DepartmentVO> childrenEntityList = voList.stream().filter(e -> departmentId.equals(e.getParentId())).collect(Collectors.toList());
|
||||
@ -205,7 +190,6 @@ public class DepartmentCacheManager {
|
||||
|
||||
/**
|
||||
* 通过部门id,获取当前以及下属部门
|
||||
*
|
||||
*/
|
||||
public List<Long> selfAndChildrenIdList(Long departmentId, List<DepartmentVO> voList) {
|
||||
List<Long> selfAndChildrenIdList = Lists.newArrayList();
|
||||
|
@ -44,7 +44,6 @@ public class DepartmentService {
|
||||
|
||||
/**
|
||||
* 新增添加部门
|
||||
*
|
||||
*/
|
||||
|
||||
public ResponseDTO<String> addDepartment(DepartmentAddForm departmentAddForm) {
|
||||
@ -57,7 +56,6 @@ public class DepartmentService {
|
||||
|
||||
/**
|
||||
* 更新部门信息
|
||||
*
|
||||
*/
|
||||
public ResponseDTO<String> updateDepartment(DepartmentUpdateForm updateDTO) {
|
||||
if (updateDTO.getParentId() == null) {
|
||||
@ -78,7 +76,6 @@ public class DepartmentService {
|
||||
* 根据id删除部门
|
||||
* 1、需要判断当前部门是否有子部门,有子部门则不允许删除
|
||||
* 2、需要判断当前部门是否有员工,有员工则不能删除
|
||||
*
|
||||
*/
|
||||
public ResponseDTO<String> deleteDepartment(Long departmentId) {
|
||||
DepartmentEntity departmentEntity = departmentDao.selectById(departmentId);
|
||||
@ -122,7 +119,6 @@ public class DepartmentService {
|
||||
|
||||
/**
|
||||
* 自身以及所有下级的部门id列表
|
||||
*
|
||||
*/
|
||||
public List<Long> selfAndChildrenIdList(Long departmentId) {
|
||||
return departmentCacheManager.getDepartmentSelfAndChildren(departmentId);
|
||||
@ -131,7 +127,6 @@ public class DepartmentService {
|
||||
|
||||
/**
|
||||
* 获取所有部门
|
||||
*
|
||||
*/
|
||||
public List<DepartmentVO> listAll() {
|
||||
return departmentCacheManager.getDepartmentList();
|
||||
@ -140,10 +135,9 @@ public class DepartmentService {
|
||||
|
||||
/**
|
||||
* 获取部门
|
||||
*
|
||||
*/
|
||||
public DepartmentVO getDepartmentById(Long departmentId) {
|
||||
return departmentCacheManager.getDepartmentMap().get(departmentId);
|
||||
return departmentDao.selectDepartmentVO(departmentId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -153,38 +147,4 @@ public class DepartmentService {
|
||||
return departmentCacheManager.getDepartmentPathMap().get(departmentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询全部父级部门(不包含自己)
|
||||
*
|
||||
*/
|
||||
public List<DepartmentVO> queryAllParentDepartment(Long departmentId) {
|
||||
List<DepartmentVO> list = new ArrayList<>();
|
||||
|
||||
Map<Long, DepartmentVO> departmentMap = departmentCacheManager.getDepartmentMap();
|
||||
DepartmentVO departmentVO = departmentMap.get(departmentId);
|
||||
while (departmentVO != null) {
|
||||
list.add(departmentVO);
|
||||
departmentVO = departmentMap.get(departmentVO.getParentId());
|
||||
}
|
||||
Collections.reverse(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询全部父级部门(不包含自己)
|
||||
*
|
||||
*/
|
||||
public List<Long> queryAllParentDepartmentIdList(Long departmentId) {
|
||||
List<Long> list = new ArrayList<>();
|
||||
|
||||
Map<Long, DepartmentVO> departmentMap = departmentCacheManager.getDepartmentMap();
|
||||
DepartmentVO departmentVO = departmentMap.get(departmentId);
|
||||
while (departmentVO != null) {
|
||||
list.add(departmentVO.getDepartmentId());
|
||||
departmentVO = departmentMap.get(departmentVO.getParentId());
|
||||
}
|
||||
Collections.reverse(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,9 +2,7 @@ package net.lab1024.sa.admin.module.system.employee.domain.form;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.Data;
|
||||
import net.lab1024.sa.base.common.util.SmartVerificationUtil;
|
||||
|
||||
/**
|
||||
* 修改密码所需参数
|
||||
|
@ -0,0 +1,162 @@
|
||||
package net.lab1024.sa.admin.module.system.login.manager;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.lab1024.sa.admin.constant.AdminCacheConst;
|
||||
import net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO;
|
||||
import net.lab1024.sa.admin.module.system.department.service.DepartmentService;
|
||||
import net.lab1024.sa.admin.module.system.employee.domain.entity.EmployeeEntity;
|
||||
import net.lab1024.sa.admin.module.system.employee.service.EmployeeService;
|
||||
import net.lab1024.sa.admin.module.system.login.domain.RequestEmployee;
|
||||
import net.lab1024.sa.admin.module.system.menu.domain.vo.MenuVO;
|
||||
import net.lab1024.sa.admin.module.system.role.domain.vo.RoleVO;
|
||||
import net.lab1024.sa.admin.module.system.role.service.RoleEmployeeService;
|
||||
import net.lab1024.sa.admin.module.system.role.service.RoleMenuService;
|
||||
import net.lab1024.sa.base.common.constant.StringConst;
|
||||
import net.lab1024.sa.base.common.domain.ResponseDTO;
|
||||
import net.lab1024.sa.base.common.domain.UserPermission;
|
||||
import net.lab1024.sa.base.common.enumeration.UserTypeEnum;
|
||||
import net.lab1024.sa.base.common.util.SmartBeanUtil;
|
||||
import net.lab1024.sa.base.module.support.file.service.IFileStorageService;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.CachePut;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 登录Manager
|
||||
*
|
||||
* @Author 1024创新实验室: 卓大
|
||||
* @Date 2025-05-03 22:56:34
|
||||
* @Wechat zhuoda1024
|
||||
* @Email lab1024@163.com
|
||||
* @Copyright <a href="https://1024lab.net">1024创新实验室</a>
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class LoginManager {
|
||||
|
||||
@Resource
|
||||
private DepartmentService departmentService;
|
||||
|
||||
@Resource
|
||||
private IFileStorageService fileStorageService;
|
||||
|
||||
@Resource
|
||||
private EmployeeService employeeService;
|
||||
|
||||
@Resource
|
||||
private RoleEmployeeService roleEmployeeService;
|
||||
|
||||
@Resource
|
||||
private RoleMenuService roleMenuService;
|
||||
|
||||
|
||||
/**
|
||||
* 获取请求用户信息
|
||||
*/
|
||||
@Cacheable(AdminCacheConst.Login.REQUEST_EMPLOYEE)
|
||||
public RequestEmployee getRequestEmployee(Long requestEmployeeId ) {
|
||||
if (requestEmployeeId == null) {
|
||||
return null;
|
||||
}
|
||||
// 员工基本信息
|
||||
EmployeeEntity employeeEntity = employeeService.getById(requestEmployeeId);
|
||||
if (employeeEntity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.loadLoginInfo(employeeEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录的用户信息
|
||||
*/
|
||||
@CachePut(value = AdminCacheConst.Login.REQUEST_EMPLOYEE, key = "#employeeEntity.employeeId")
|
||||
public RequestEmployee loadLoginInfo(EmployeeEntity employeeEntity) {
|
||||
// 基础信息
|
||||
RequestEmployee requestEmployee = SmartBeanUtil.copy(employeeEntity, RequestEmployee.class);
|
||||
requestEmployee.setUserType(UserTypeEnum.ADMIN_EMPLOYEE);
|
||||
|
||||
// 部门信息
|
||||
DepartmentVO department = departmentService.getDepartmentById(employeeEntity.getDepartmentId());
|
||||
requestEmployee.setDepartmentName(null == department ? StringConst.EMPTY : department.getName());
|
||||
|
||||
// 头像信息
|
||||
String avatar = employeeEntity.getAvatar();
|
||||
if (StringUtils.isNotBlank(avatar)) {
|
||||
ResponseDTO<String> getFileUrl = fileStorageService.getFileUrl(avatar);
|
||||
if (BooleanUtils.isTrue(getFileUrl.getOk())) {
|
||||
requestEmployee.setAvatar(getFileUrl.getData());
|
||||
}
|
||||
}
|
||||
return requestEmployee;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取用户的权限(包含 角色列表、权限列表)
|
||||
*/
|
||||
@Cacheable(AdminCacheConst.Login.USER_PERMISSION)
|
||||
public UserPermission getUserPermission(Long employeeId) {
|
||||
if(null == employeeId){
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.loadUserPermission(employeeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户的权限(包含 角色列表、权限列表)
|
||||
*/
|
||||
@CachePut(AdminCacheConst.Login.USER_PERMISSION)
|
||||
public UserPermission loadUserPermission(Long employeeId) {
|
||||
UserPermission userPermission = new UserPermission();
|
||||
userPermission.setPermissionList(new ArrayList<>());
|
||||
userPermission.setRoleList(new ArrayList<>());
|
||||
|
||||
// 角色列表
|
||||
List<RoleVO> roleList = roleEmployeeService.getRoleIdList(employeeId);
|
||||
userPermission.getRoleList().addAll(roleList.stream().map(RoleVO::getRoleCode).collect(Collectors.toSet()));
|
||||
|
||||
// 前端菜单和功能点清单
|
||||
EmployeeEntity employeeEntity = employeeService.getById(employeeId);
|
||||
|
||||
List<MenuVO> menuAndPointsList = roleMenuService.getMenuList(roleList.stream().map(RoleVO::getRoleId).collect(Collectors.toList()), employeeEntity.getAdministratorFlag());
|
||||
|
||||
// 权限列表
|
||||
HashSet<String> permissionSet = new HashSet<>();
|
||||
for (MenuVO menu : menuAndPointsList) {
|
||||
if (menu.getPermsType() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String perms = menu.getApiPerms();
|
||||
if (StringUtils.isEmpty(perms)) {
|
||||
continue;
|
||||
}
|
||||
//接口权限
|
||||
String[] split = perms.split(",");
|
||||
permissionSet.addAll(Arrays.asList(split));
|
||||
}
|
||||
userPermission.getPermissionList().addAll(permissionSet);
|
||||
|
||||
return userPermission;
|
||||
}
|
||||
|
||||
|
||||
@CacheEvict(value = {AdminCacheConst.Login.USER_PERMISSION, AdminCacheConst.Login.REQUEST_EMPLOYEE}, allEntries = true)
|
||||
public void clear(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -6,17 +6,16 @@ import cn.hutool.core.lang.UUID;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.extra.servlet.JakartaServletUtil;
|
||||
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO;
|
||||
import net.lab1024.sa.admin.module.system.department.service.DepartmentService;
|
||||
import net.lab1024.sa.admin.module.system.employee.domain.entity.EmployeeEntity;
|
||||
import net.lab1024.sa.admin.module.system.employee.service.EmployeeService;
|
||||
import net.lab1024.sa.admin.module.system.login.domain.LoginForm;
|
||||
import net.lab1024.sa.admin.module.system.login.domain.LoginResultVO;
|
||||
import net.lab1024.sa.admin.module.system.login.domain.RequestEmployee;
|
||||
import net.lab1024.sa.admin.module.system.login.manager.LoginManager;
|
||||
import net.lab1024.sa.admin.module.system.menu.domain.vo.MenuVO;
|
||||
import net.lab1024.sa.admin.module.system.role.domain.vo.RoleVO;
|
||||
import net.lab1024.sa.admin.module.system.role.service.RoleEmployeeService;
|
||||
@ -48,21 +47,22 @@ import net.lab1024.sa.base.module.support.mail.MailService;
|
||||
import net.lab1024.sa.base.module.support.mail.constant.MailTemplateCodeEnum;
|
||||
import net.lab1024.sa.base.module.support.redis.RedisService;
|
||||
import net.lab1024.sa.base.module.support.securityprotect.domain.LoginFailEntity;
|
||||
import net.lab1024.sa.base.module.support.securityprotect.service.*;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import net.lab1024.sa.base.module.support.securityprotect.service.Level3ProtectConfigService;
|
||||
import net.lab1024.sa.base.module.support.securityprotect.service.SecurityLoginService;
|
||||
import net.lab1024.sa.base.module.support.securityprotect.service.SecurityPasswordService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 登录
|
||||
*
|
||||
* @Author 1024创新实验室: 开云
|
||||
* @Date 2021-12-01 22:56:34
|
||||
* @Author 1024创新实验室: 卓大
|
||||
* @Date 2025-05-03 22:56:34
|
||||
* @Wechat zhuoda1024
|
||||
* @Email lab1024@163.com
|
||||
* @Copyright <a href="https://1024lab.net">1024创新实验室</a>
|
||||
@ -76,22 +76,6 @@ public class LoginService implements StpInterface {
|
||||
*/
|
||||
private static final String SUPER_PASSWORD_LOGIN_ID_PREFIX = "S";
|
||||
|
||||
/**
|
||||
* 最大在线缓存人数
|
||||
*/
|
||||
private static final long CACHE_MAX_ONLINE_PERSON_COUNT = 1000L;
|
||||
|
||||
/**
|
||||
* 登录信息二级缓存
|
||||
*/
|
||||
private final ConcurrentMap<Long, RequestEmployee> loginEmployeeCache = new ConcurrentLinkedHashMap.Builder<Long, RequestEmployee>().maximumWeightedCapacity(CACHE_MAX_ONLINE_PERSON_COUNT).build();
|
||||
|
||||
|
||||
/**
|
||||
* 权限 缓存
|
||||
*/
|
||||
private final ConcurrentMap<Long, UserPermission> permissionCache = new ConcurrentLinkedHashMap.Builder<Long, UserPermission>().maximumWeightedCapacity(CACHE_MAX_ONLINE_PERSON_COUNT).build();
|
||||
|
||||
@Resource
|
||||
private EmployeeService employeeService;
|
||||
|
||||
@ -134,6 +118,9 @@ public class LoginService implements StpInterface {
|
||||
@Resource
|
||||
private RedisService redisService;
|
||||
|
||||
@Resource
|
||||
private LoginManager loginManager;
|
||||
|
||||
/**
|
||||
* 获取验证码
|
||||
*/
|
||||
@ -224,10 +211,7 @@ public class LoginService implements StpInterface {
|
||||
}
|
||||
|
||||
// 获取员工信息
|
||||
RequestEmployee requestEmployee = loadLoginInfo(employeeEntity);
|
||||
|
||||
// 放入缓存
|
||||
loginEmployeeCache.put(employeeEntity.getEmployeeId(), requestEmployee);
|
||||
RequestEmployee requestEmployee = loginManager.loadLoginInfo(employeeEntity);
|
||||
|
||||
// 移除登录失败
|
||||
securityLoginService.removeLoginFail(employeeEntity.getEmployeeId(), UserTypeEnum.ADMIN_EMPLOYEE);
|
||||
@ -242,8 +226,8 @@ public class LoginService implements StpInterface {
|
||||
// 设置 token
|
||||
loginResultVO.setToken(token);
|
||||
|
||||
// 清除权限缓存
|
||||
permissionCache.remove(employeeEntity.getEmployeeId());
|
||||
// 更新用户权限
|
||||
loginManager.loadUserPermission(employeeEntity.getEmployeeId());
|
||||
|
||||
return ResponseDTO.ok(loginResultVO);
|
||||
}
|
||||
@ -262,10 +246,6 @@ public class LoginService implements StpInterface {
|
||||
List<MenuVO> menuAndPointsList = roleMenuService.getMenuList(roleList.stream().map(RoleVO::getRoleId).collect(Collectors.toList()), requestEmployee.getAdministratorFlag());
|
||||
loginResultVO.setMenuList(menuAndPointsList);
|
||||
|
||||
// 更新下后端权限缓存
|
||||
UserPermission userPermission = getUserPermission(requestEmployee.getUserId());
|
||||
permissionCache.put(requestEmployee.getUserId(), userPermission);
|
||||
|
||||
// 上次登录信息
|
||||
LoginLogVO loginLogVO = loginLogService.queryLastByUserId(requestEmployee.getEmployeeId(), UserTypeEnum.ADMIN_EMPLOYEE, LoginLogResultEnum.LOGIN_SUCCESS);
|
||||
if (loginLogVO != null) {
|
||||
@ -289,32 +269,6 @@ public class LoginService implements StpInterface {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取登录的用户信息
|
||||
*/
|
||||
private RequestEmployee loadLoginInfo(EmployeeEntity employeeEntity) {
|
||||
|
||||
// 基础信息
|
||||
RequestEmployee requestEmployee = SmartBeanUtil.copy(employeeEntity, RequestEmployee.class);
|
||||
requestEmployee.setUserType(UserTypeEnum.ADMIN_EMPLOYEE);
|
||||
|
||||
// 部门信息
|
||||
DepartmentVO department = departmentService.getDepartmentById(employeeEntity.getDepartmentId());
|
||||
requestEmployee.setDepartmentName(null == department ? StringConst.EMPTY : department.getName());
|
||||
|
||||
// 头像信息
|
||||
String avatar = employeeEntity.getAvatar();
|
||||
if (StringUtils.isNotBlank(avatar)) {
|
||||
ResponseDTO<String> getFileUrl = fileStorageService.getFileUrl(avatar);
|
||||
if (BooleanUtils.isTrue(getFileUrl.getOk())) {
|
||||
requestEmployee.setAvatar(getFileUrl.getData());
|
||||
}
|
||||
}
|
||||
|
||||
return requestEmployee;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据登陆token 获取员请求工信息
|
||||
*/
|
||||
@ -328,17 +282,7 @@ public class LoginService implements StpInterface {
|
||||
return null;
|
||||
}
|
||||
|
||||
RequestEmployee requestEmployee = loginEmployeeCache.get(requestEmployeeId);
|
||||
if (requestEmployee == null) {
|
||||
// 员工基本信息
|
||||
EmployeeEntity employeeEntity = employeeService.getById(requestEmployeeId);
|
||||
if (employeeEntity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
requestEmployee = this.loadLoginInfo(employeeEntity);
|
||||
loginEmployeeCache.put(requestEmployeeId, requestEmployee);
|
||||
}
|
||||
RequestEmployee requestEmployee = loginManager.getRequestEmployee(requestEmployeeId);
|
||||
|
||||
// 更新请求ip和user agent
|
||||
requestEmployee.setUserAgent(JakartaServletUtil.getHeaderIgnoreCase(request, RequestHeaderConst.USER_AGENT));
|
||||
@ -382,7 +326,7 @@ public class LoginService implements StpInterface {
|
||||
StpUtil.logout();
|
||||
|
||||
// 清空登录信息缓存
|
||||
loginEmployeeCache.remove(requestUser.getUserId());
|
||||
loginManager.clear();
|
||||
|
||||
//保存登出日志
|
||||
LoginLogEntity loginEntity = LoginLogEntity.builder()
|
||||
@ -400,14 +344,6 @@ public class LoginService implements StpInterface {
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除员工登录缓存
|
||||
*/
|
||||
public void clearLoginEmployeeCache(Long employeeId) {
|
||||
// 清空登录信息缓存
|
||||
loginEmployeeCache.remove(employeeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存登录日志
|
||||
*/
|
||||
@ -435,12 +371,7 @@ public class LoginService implements StpInterface {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
UserPermission userPermission = permissionCache.get(employeeId);
|
||||
if (userPermission == null) {
|
||||
userPermission = getUserPermission(employeeId);
|
||||
permissionCache.put(employeeId, userPermission);
|
||||
}
|
||||
|
||||
UserPermission userPermission = loginManager.getUserPermission(employeeId);
|
||||
return userPermission.getPermissionList();
|
||||
}
|
||||
|
||||
@ -451,51 +382,10 @@ public class LoginService implements StpInterface {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
UserPermission userPermission = permissionCache.get(employeeId);
|
||||
if (userPermission == null) {
|
||||
userPermission = getUserPermission(employeeId);
|
||||
permissionCache.put(employeeId, userPermission);
|
||||
}
|
||||
UserPermission userPermission = loginManager.getUserPermission(employeeId);
|
||||
return userPermission.getRoleList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户的权限(包含 角色列表、权限列表)
|
||||
*/
|
||||
private UserPermission getUserPermission(Long employeeId) {
|
||||
|
||||
UserPermission userPermission = new UserPermission();
|
||||
userPermission.setPermissionList(new ArrayList<>());
|
||||
userPermission.setRoleList(new ArrayList<>());
|
||||
|
||||
// 角色列表
|
||||
List<RoleVO> roleList = roleEmployeeService.getRoleIdList(employeeId);
|
||||
userPermission.getRoleList().addAll(roleList.stream().map(RoleVO::getRoleCode).collect(Collectors.toSet()));
|
||||
|
||||
// 前端菜单和功能点清单
|
||||
EmployeeEntity employeeEntity = employeeService.getById(employeeId);
|
||||
|
||||
List<MenuVO> menuAndPointsList = roleMenuService.getMenuList(roleList.stream().map(RoleVO::getRoleId).collect(Collectors.toList()), employeeEntity.getAdministratorFlag());
|
||||
|
||||
// 权限列表
|
||||
HashSet<String> permissionSet = new HashSet<>();
|
||||
for (MenuVO menu : menuAndPointsList) {
|
||||
if (menu.getPermsType() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String perms = menu.getApiPerms();
|
||||
if (StringUtils.isEmpty(perms)) {
|
||||
continue;
|
||||
}
|
||||
//接口权限
|
||||
String[] split = perms.split(",");
|
||||
permissionSet.addAll(Arrays.asList(split));
|
||||
}
|
||||
userPermission.getPermissionList().addAll(permissionSet);
|
||||
|
||||
return userPermission;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 邮箱 验证码
|
||||
@ -590,4 +480,8 @@ public class LoginService implements StpInterface {
|
||||
String redisVerificationCodeKey = redisService.generateRedisKey(RedisKeyConst.Support.LOGIN_VERIFICATION_CODE, UserTypeEnum.ADMIN_EMPLOYEE.getValue() + RedisKeyConst.SEPARATOR + employeeId);
|
||||
redisService.delete(redisVerificationCodeKey);
|
||||
}
|
||||
|
||||
public void clearLoginEmployeeCache(Long employeeId) {
|
||||
loginManager.clear();
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,7 @@ package net.lab1024.sa.admin.module.system.role.manager;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import net.lab1024.sa.admin.module.system.role.dao.RoleEmployeeDao;
|
||||
import net.lab1024.sa.admin.module.system.role.domain.entity.RoleEmployeeEntity;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 角色员工 manager
|
||||
|
@ -19,5 +19,16 @@
|
||||
WHERE parent_id = #{departmentId}
|
||||
</select>
|
||||
|
||||
<select id="selectDepartmentVO"
|
||||
resultType="net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO">
|
||||
SELECT t_department.*,
|
||||
t_employee.actual_name as managerName,
|
||||
parent_department.`name` as parentName
|
||||
FROM t_department
|
||||
left join t_employee on t_department.manager_id = t_employee.employee_id
|
||||
left join t_department parent_department on t_department.parent_id = parent_department.department_id
|
||||
where t_department.department_id = #{departmentId}
|
||||
</select>
|
||||
|
||||
|
||||
</mapper>
|
@ -1,26 +0,0 @@
|
||||
package net.lab1024.sa.base.common.annoation;
|
||||
|
||||
import net.lab1024.sa.base.constant.DataSourceTypeEnum;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 切换数据源名称
|
||||
*
|
||||
* @Author 钟家兴
|
||||
* @Date 2025-05-01 14:49
|
||||
* @Wechat JavaerEngineer
|
||||
* @Email lab1024@163.com
|
||||
* @Copyright <a href="https://1024lab.net">1024创新实验室</a>
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface DataSource {
|
||||
|
||||
/**
|
||||
* 切换数据源名称
|
||||
*/
|
||||
public DataSourceTypeEnum value() default DataSourceTypeEnum.SLAVE;
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
package net.lab1024.sa.base.common.aspect;
|
||||
|
||||
import net.lab1024.sa.base.common.annoation.DataSource;
|
||||
import net.lab1024.sa.base.handler.DynamicDataSourceContextHandler;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 多数据源处理
|
||||
*
|
||||
* @Author 钟家兴
|
||||
* @Date 2025-05-01 14:49
|
||||
* @Wechat JavaerEngineer
|
||||
* @Email lab1024@163.com
|
||||
* @Copyright <a href="https://1024lab.net">1024创新实验室</a>
|
||||
*/
|
||||
@Aspect
|
||||
@Order(1)
|
||||
@Component
|
||||
public class DataSourceAspect {
|
||||
|
||||
/**
|
||||
* aop切点,有相关注解的方法才做增强处理
|
||||
*/
|
||||
@Pointcut("@annotation(net.lab1024.sa.base.common.annoation.DataSource) || @within(net.lab1024.sa.base.common.annoation.DataSource)")
|
||||
public void dsPointCut() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 环绕通知
|
||||
*/
|
||||
@Around("dsPointCut()")
|
||||
public Object around(ProceedingJoinPoint point) throws Throwable {
|
||||
DataSource dataSource = getDataSource(point);
|
||||
|
||||
if (dataSource != null) {
|
||||
DynamicDataSourceContextHandler.setDataSourceType(dataSource.value().name());
|
||||
}
|
||||
|
||||
try {
|
||||
return point.proceed();
|
||||
} finally {
|
||||
DynamicDataSourceContextHandler.clearDataSourceType();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取需要切换的数据源
|
||||
*/
|
||||
public DataSource getDataSource(ProceedingJoinPoint point) {
|
||||
MethodSignature signature = (MethodSignature) point.getSignature();
|
||||
DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);
|
||||
|
||||
// 方法注解为空,则取类注解
|
||||
if (Objects.nonNull(dataSource)) {
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package net.lab1024.sa.base.common.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -15,7 +16,7 @@ import java.util.List;
|
||||
*/
|
||||
|
||||
@Data
|
||||
public class UserPermission {
|
||||
public class UserPermission implements Serializable {
|
||||
|
||||
/**
|
||||
* 权限列表
|
||||
|
@ -1,11 +1,14 @@
|
||||
package net.lab1024.sa.base.config;
|
||||
|
||||
import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
|
||||
import net.lab1024.sa.base.module.support.cache.CacheService;
|
||||
import net.lab1024.sa.base.module.support.cache.CaffeineCacheServiceImpl;
|
||||
import net.lab1024.sa.base.module.support.cache.RedisCacheServiceImpl;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||
|
||||
/**
|
||||
* 缓存配置
|
||||
@ -19,6 +22,14 @@ public class CacheConfig {
|
||||
private static final String REDIS_CACHE = "redis";
|
||||
private static final String CAFFEINE_CACHE = "caffeine";
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = "spring.cache", name = {"type"}, havingValue = REDIS_CACHE)
|
||||
public RedisCacheConfiguration redisCacheConfiguration() {
|
||||
return RedisCacheConfiguration.defaultCacheConfig()
|
||||
.disableCachingNullValues()
|
||||
.computePrefixWith(name -> "cache:" + name + ":")
|
||||
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericFastJsonRedisSerializer()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = "spring.cache", name = {"type"}, havingValue = REDIS_CACHE)
|
||||
|
@ -0,0 +1,201 @@
|
||||
package net.lab1024.sa.base.config;
|
||||
|
||||
import com.alibaba.druid.filter.Filter;
|
||||
import com.alibaba.druid.filter.stat.StatFilter;
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.alibaba.druid.support.jakarta.StatViewServlet;
|
||||
import com.alibaba.druid.support.jakarta.WebStatFilter;
|
||||
import com.alibaba.druid.support.spring.stat.DruidStatInterceptor;
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.core.config.GlobalConfig;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.lab1024.sa.base.common.domain.DataScopePlugin;
|
||||
import net.lab1024.sa.base.handler.MybatisPlusFillHandler;
|
||||
import org.apache.ibatis.plugin.Interceptor;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.aop.support.JdkRegexpMethodPointcut;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 数据源配置
|
||||
*
|
||||
* @Author 1024创新实验室-主任: 卓大
|
||||
* @Date 2017-11-28 15:21:10
|
||||
* @Wechat zhuoda1024
|
||||
* @Email lab1024@163.com
|
||||
* @Copyright <a href="https://1024lab.net">1024创新实验室</a>
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class DataSourceConfig {
|
||||
|
||||
@Value("${spring.datasource.driver-class-name}")
|
||||
String driver;
|
||||
|
||||
@Value("${spring.datasource.url}")
|
||||
String url;
|
||||
|
||||
@Value("${spring.datasource.username}")
|
||||
String username;
|
||||
|
||||
@Value("${spring.datasource.password}")
|
||||
String password;
|
||||
|
||||
@Value("${spring.datasource.initial-size}")
|
||||
int initialSize;
|
||||
|
||||
@Value("${spring.datasource.min-idle}")
|
||||
int minIdle;
|
||||
|
||||
@Value("${spring.datasource.max-active}")
|
||||
int maxActive;
|
||||
|
||||
@Value("${spring.datasource.max-wait}")
|
||||
long maxWait;
|
||||
|
||||
@Value("${spring.datasource.time-between-eviction-runs-millis}")
|
||||
long timeBetweenEvictionRunsMillis;
|
||||
|
||||
@Value("${spring.datasource.min-evictable-idle-time-millis}")
|
||||
long minEvictableIdleTimeMillis;
|
||||
|
||||
@Value("${spring.datasource.filters}")
|
||||
String filters;
|
||||
|
||||
@Value("${spring.datasource.druid.username}")
|
||||
String druidUserName;
|
||||
|
||||
@Value("${spring.datasource.druid.password}")
|
||||
String druidPassword;
|
||||
|
||||
@Value("${spring.datasource.druid.login.enabled}")
|
||||
boolean druidLoginEnable;
|
||||
|
||||
@Value("${spring.datasource.druid.method.pointcut}")
|
||||
String methodPointcut;
|
||||
|
||||
@jakarta.annotation.Resource
|
||||
private MybatisPlusInterceptor paginationInterceptor;
|
||||
|
||||
@jakarta.annotation.Resource
|
||||
private DataScopePlugin dataScopePlugin;
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public DataSource druidDataSource() {
|
||||
DruidDataSource druidDataSource = new DruidDataSource();
|
||||
druidDataSource.setDbType(DbType.MYSQL.getDb());
|
||||
druidDataSource.setDriverClassName(driver);
|
||||
druidDataSource.setUrl(url);
|
||||
druidDataSource.setUsername(username);
|
||||
druidDataSource.setPassword(password);
|
||||
druidDataSource.setInitialSize(initialSize);
|
||||
druidDataSource.setMinIdle(minIdle);
|
||||
druidDataSource.setMaxActive(maxActive);
|
||||
druidDataSource.setMaxWait(maxWait);
|
||||
druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
|
||||
druidDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
|
||||
druidDataSource.setValidationQuery("SELECT 1");
|
||||
try {
|
||||
druidDataSource.setFilters(filters);
|
||||
ArrayList<Filter> arrayList = new ArrayList<>();
|
||||
StatFilter statFilter = new StatFilter();
|
||||
statFilter.setMergeSql(true);
|
||||
statFilter.setSlowSqlMillis(1000);
|
||||
statFilter.setLogSlowSql(true);
|
||||
arrayList.add(statFilter);
|
||||
druidDataSource.setProxyFilters(arrayList);
|
||||
druidDataSource.init();
|
||||
} catch (SQLException e) {
|
||||
log.error("初始化数据源出错", e);
|
||||
}
|
||||
|
||||
return druidDataSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SqlSessionFactory sqlSessionFactory() throws Exception {
|
||||
MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
|
||||
factoryBean.setDataSource(druidDataSource());
|
||||
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
||||
Resource[] resources = resolver.getResources("classpath*:/mapper/**/*.xml");
|
||||
factoryBean.setMapperLocations(resources);
|
||||
|
||||
// 设置 MyBatis-Plus 分页插件 注意此处myBatisPlugin一定要放在后面
|
||||
List<Interceptor> pluginsList = new ArrayList<>();
|
||||
pluginsList.add(paginationInterceptor);
|
||||
if (dataScopePlugin != null) {
|
||||
pluginsList.add(dataScopePlugin);
|
||||
}
|
||||
factoryBean.setPlugins(pluginsList.toArray(new Interceptor[0]));
|
||||
// 添加字段自动填充处理
|
||||
factoryBean.setGlobalConfig(new GlobalConfig().setBanner(false).setMetaObjectHandler(new MybatisPlusFillHandler()));
|
||||
|
||||
return factoryBean.getObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* 非正式环境 才加载
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Conditional(SystemEnvironmentConfig.class)
|
||||
@Bean
|
||||
public ServletRegistrationBean<StatViewServlet> druidServlet() {
|
||||
ServletRegistrationBean<StatViewServlet> servletRegistrationBean = new ServletRegistrationBean<>();
|
||||
servletRegistrationBean.setServlet(new StatViewServlet());
|
||||
servletRegistrationBean.addUrlMappings("/druid/*");
|
||||
Map<String, String> initParameters = new HashMap<String, String>();
|
||||
//不设置用户名密码可以直接通过druid/index.html访问
|
||||
if (druidLoginEnable) {
|
||||
initParameters.put("loginUsername", druidUserName);
|
||||
initParameters.put("loginPassword", druidPassword);
|
||||
}
|
||||
initParameters.put("resetEnable", "false");
|
||||
servletRegistrationBean.setInitParameters(initParameters);
|
||||
return servletRegistrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<WebStatFilter> filterRegistrationBean() {
|
||||
FilterRegistrationBean<WebStatFilter> filterRegistrationBean = new FilterRegistrationBean<WebStatFilter>();
|
||||
filterRegistrationBean.setFilter(new WebStatFilter());
|
||||
filterRegistrationBean.addUrlPatterns("/*");
|
||||
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/*");
|
||||
return filterRegistrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JdkRegexpMethodPointcut jdkRegexpMethodPointcut() {
|
||||
JdkRegexpMethodPointcut jdkRegexpMethodPointcut = new JdkRegexpMethodPointcut();
|
||||
jdkRegexpMethodPointcut.setPatterns(methodPointcut);
|
||||
return jdkRegexpMethodPointcut;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DefaultPointcutAdvisor defaultPointcutAdvisor() {
|
||||
DefaultPointcutAdvisor pointcutAdvisor = new DefaultPointcutAdvisor();
|
||||
pointcutAdvisor.setPointcut(jdkRegexpMethodPointcut());
|
||||
pointcutAdvisor.setAdvice(new DruidStatInterceptor());
|
||||
return pointcutAdvisor;
|
||||
}
|
||||
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
package net.lab1024.sa.base.config;
|
||||
|
||||
import com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceBuilder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.lab1024.sa.base.constant.DataSourceTypeEnum;
|
||||
import net.lab1024.sa.base.handler.DynamicDataSourceHandler;
|
||||
import net.lab1024.sa.base.properties.DruidProperties;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Druid 配置多数据源
|
||||
*
|
||||
* @Author 钟家兴
|
||||
* @Date 2025-05-01 14:49
|
||||
* @Wechat JavaerEngineer
|
||||
* @Email lab1024@163.com
|
||||
* @Copyright <a href="https://1024lab.net">1024创新实验室</a>
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class DruidConfig {
|
||||
|
||||
/**
|
||||
* 这里以map的方式存储所有的自定义的数据源,其中key是枚举类的字符串值,value是创建好且赋值好的数据源对象
|
||||
*/
|
||||
private static Map<Object, Object> targetDataSources = new HashMap<>();
|
||||
|
||||
/**
|
||||
* DruidProperties(属性配置对象,见后面6 spring会根据配置文件的值将该对象的属性赋值
|
||||
* 然后调用dataSource()方法将创建好的数据源对象赋值好然后交给spring管理
|
||||
* 这里是配置的主数据源也是默认的数据源
|
||||
*/
|
||||
@Bean
|
||||
@ConfigurationProperties("spring.datasource.druid.master")
|
||||
public DataSource masterDataSource(DruidProperties druidProperties) {
|
||||
DataSource dataSource = druidProperties.dataSource(DruidDataSourceBuilder.create().build());
|
||||
targetDataSources.put(DataSourceTypeEnum.MASTER.name(), dataSource);
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置从数据源,注意从数据源配置“name = "enabled", havingValue = "true"”参数
|
||||
*/
|
||||
@Bean
|
||||
@ConfigurationProperties("spring.datasource.druid.slave")
|
||||
@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
|
||||
public DataSource slaveDataSource(DruidProperties druidProperties) {
|
||||
DataSource dataSource = druidProperties.dataSource(DruidDataSourceBuilder.create().build());
|
||||
targetDataSources.put(DataSourceTypeEnum.SLAVE.name(), dataSource);
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* 之后所有需要增加的数据源可以在这里从上到下依次添加
|
||||
* 只需要按照上面的方式(slaveDataSource的方法照葫芦画瓢)注入bean,然后再在配置文件中配置好相关的参数
|
||||
* 最后添加该数据源所对应的枚举类作为该数据源的key即可
|
||||
**/
|
||||
|
||||
/**
|
||||
* 使用 @Qualifier 注解指定将两个数据源作为入参
|
||||
*/
|
||||
@Bean(name = "dynamicDataSource")
|
||||
@Primary
|
||||
public DynamicDataSourceHandler dataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Autowired(required = false) @Qualifier("slaveDataSource") DataSource slaveDataSource) {
|
||||
Map<Object, Object> targetDataSources = new HashMap<>();
|
||||
targetDataSources.put(DataSourceTypeEnum.MASTER.name(), masterDataSource);
|
||||
log.info("加载动态数据源:{}", DataSourceTypeEnum.MASTER.name());
|
||||
|
||||
// 如果从数据源不为空 则添加到 targetDataSources 中
|
||||
if (slaveDataSource != null) {
|
||||
targetDataSources.put(DataSourceTypeEnum.SLAVE.name(), slaveDataSource);
|
||||
log.info("加载动态数据源:{}", DataSourceTypeEnum.SLAVE.name());
|
||||
}
|
||||
|
||||
return new DynamicDataSourceHandler(masterDataSource, targetDataSources);
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
package net.lab1024.sa.base.constant;
|
||||
|
||||
/**
|
||||
* 数据源类型
|
||||
*
|
||||
* @Author 钟家兴
|
||||
* @Date 2025-05-01 14:49
|
||||
* @Wechat JavaerEngineer
|
||||
* @Email lab1024@163.com
|
||||
* @Copyright <a href="https://1024lab.net">1024创新实验室</a>
|
||||
*/
|
||||
public enum DataSourceTypeEnum {
|
||||
|
||||
/**
|
||||
* 主库
|
||||
*/
|
||||
MASTER,
|
||||
|
||||
/**
|
||||
* 从库
|
||||
*/
|
||||
SLAVE
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
package net.lab1024.sa.base.handler;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 数据源切换处理
|
||||
*
|
||||
* @Author 钟家兴
|
||||
* @Date 2025-05-01 14:49
|
||||
* @Wechat JavaerEngineer
|
||||
* @Email lab1024@163.com
|
||||
* @Copyright <a href="https://1024lab.net">1024创新实验室</a>
|
||||
*/
|
||||
@Slf4j
|
||||
public class DynamicDataSourceContextHandler {
|
||||
|
||||
/**
|
||||
* 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
|
||||
* 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
|
||||
*/
|
||||
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 设置数据源的变量
|
||||
*/
|
||||
public static void setDataSourceType(String dsType) {
|
||||
log.info("切换到 {} 数据源", dsType);
|
||||
CONTEXT_HOLDER.set(dsType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得数据源的变量
|
||||
*/
|
||||
public static String getDataSourceType() {
|
||||
return CONTEXT_HOLDER.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空数据源变量
|
||||
*/
|
||||
public static void clearDataSourceType() {
|
||||
CONTEXT_HOLDER.remove();
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
package net.lab1024.sa.base.handler;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 动态数据源
|
||||
*
|
||||
* @Author 钟家兴
|
||||
* @Date 2025-05-01 14:49
|
||||
* @Wechat JavaerEngineer
|
||||
* @Email lab1024@163.com
|
||||
* @Copyright <a href="https://1024lab.net">1024创新实验室</a>
|
||||
*/
|
||||
@Slf4j
|
||||
public class DynamicDataSourceHandler extends AbstractRoutingDataSource {
|
||||
|
||||
/**
|
||||
* targetDataSources:将所有的数据源以Map的形式传入到AbstractRoutingDataSource的实现类中,以供后面进行动态数据源选择
|
||||
*/
|
||||
public DynamicDataSourceHandler(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
|
||||
super.setDefaultTargetDataSource(defaultTargetDataSource);
|
||||
super.setTargetDataSources(targetDataSources);
|
||||
super.afterPropertiesSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统每次选择数据源的时候会执行这个方法拿到key,再通过key去内部的数据源targetDataSources Map中找到对应的数据源对象
|
||||
*/
|
||||
@Override
|
||||
protected Object determineCurrentLookupKey() {
|
||||
return DynamicDataSourceContextHandler.getDataSourceType();
|
||||
}
|
||||
}
|
@ -1,17 +1,8 @@
|
||||
package net.lab1024.sa.base.module.support.cache;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import jakarta.annotation.Resource;
|
||||
import net.lab1024.sa.base.constant.ReloadConst;
|
||||
import net.lab1024.sa.base.module.support.reload.core.annoation.SmartReload;
|
||||
import org.springframework.cache.caffeine.CaffeineCache;
|
||||
import org.springframework.cache.caffeine.CaffeineCacheManager;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 缓存服务
|
||||
|
@ -3,10 +3,8 @@ package net.lab1024.sa.base.module.support.codegenerator.service.variable.backen
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import net.lab1024.sa.base.module.support.codegenerator.constant.CodeQueryFieldQueryTypeEnum;
|
||||
import net.lab1024.sa.base.module.support.codegenerator.domain.form.CodeGeneratorConfigForm;
|
||||
import net.lab1024.sa.base.module.support.codegenerator.domain.model.CodeInsertAndUpdateField;
|
||||
import net.lab1024.sa.base.module.support.codegenerator.domain.model.CodeQueryField;
|
||||
import net.lab1024.sa.base.module.support.codegenerator.service.variable.CodeGenerateBaseVariableService;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
@ -1,13 +1,8 @@
|
||||
package net.lab1024.sa.base.module.support.job.api.domain;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import net.lab1024.sa.base.common.swagger.SchemaEnum;
|
||||
import net.lab1024.sa.base.common.validator.enumeration.CheckEnum;
|
||||
import net.lab1024.sa.base.module.support.job.constant.SmartJobTriggerTypeEnum;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
/**
|
||||
* 定时任务 更新
|
||||
|
@ -1,10 +1,13 @@
|
||||
package net.lab1024.sa.base.module.support.message.domain;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import net.lab1024.sa.base.common.enumeration.UserTypeEnum;
|
||||
import net.lab1024.sa.base.module.support.message.constant.MessageTemplateEnum;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -25,6 +28,10 @@ public class MessageTemplateSendForm {
|
||||
@NotNull(message = "接收者id不能为空")
|
||||
private Long receiverUserId;
|
||||
|
||||
@Schema(description = "接收者id")
|
||||
@NotEmpty(message = "接收者id不能为空")
|
||||
private List<Long> receiverUserIdList;
|
||||
|
||||
/**
|
||||
* 相关业务id | 可选
|
||||
* 用于跳转具体业务
|
||||
|
@ -11,9 +11,6 @@ import net.lab1024.sa.base.module.support.reload.core.thread.SmartReloadRunnable
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
|
@ -2,7 +2,6 @@ package net.lab1024.sa.base.module.support.reload.core.thread;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.lab1024.sa.base.module.support.reload.core.AbstractSmartReloadCommand;
|
||||
import net.lab1024.sa.base.module.support.reload.core.SmartReloadManager;
|
||||
import net.lab1024.sa.base.module.support.reload.core.domain.SmartReloadItem;
|
||||
import net.lab1024.sa.base.module.support.reload.core.domain.SmartReloadObject;
|
||||
import net.lab1024.sa.base.module.support.reload.core.domain.SmartReloadResult;
|
||||
|
@ -2,7 +2,6 @@ package net.lab1024.sa.base.module.support.repeatsubmit.ticket;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import net.lab1024.sa.base.module.support.repeatsubmit.annoation.RepeatSubmit;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
@ -1,9 +1,7 @@
|
||||
package net.lab1024.sa.base.module.support.repeatsubmit.ticket;
|
||||
|
||||
import net.lab1024.sa.base.module.support.repeatsubmit.annoation.RepeatSubmit;
|
||||
import org.springframework.data.redis.core.ValueOperations;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
|
@ -1,73 +0,0 @@
|
||||
package net.lab1024.sa.base.properties;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Druid 配置属性
|
||||
*
|
||||
* @Author 钟家兴
|
||||
* @Date 2025-05-01 14:49
|
||||
* @Wechat JavaerEngineer
|
||||
* @Email lab1024@163.com
|
||||
* @Copyright <a href="https://1024lab.net">1024创新实验室</a>
|
||||
*/
|
||||
@Configuration
|
||||
public class DruidProperties {
|
||||
|
||||
@Value("${spring.datasource.druid.initial-size}")
|
||||
private int initialSize;
|
||||
|
||||
@Value("${spring.datasource.druid.min-idle}")
|
||||
private int minIdle;
|
||||
|
||||
@Value("${spring.datasource.druid.max-active}")
|
||||
private int maxActive;
|
||||
|
||||
@Value("${spring.datasource.druid.max-wait}")
|
||||
private int maxWait;
|
||||
|
||||
@Value("${spring.datasource.druid.connect-timeout}")
|
||||
private int connectTimeout;
|
||||
|
||||
@Value("${spring.datasource.druid.socket-timeout}")
|
||||
private int socketTimeout;
|
||||
|
||||
@Value("${spring.datasource.druid.time-between-eviction-runs-millis}")
|
||||
private int timeBetweenEvictionRunsMillis;
|
||||
|
||||
@Value("${spring.datasource.druid.min-evictable-idle-time-millis}")
|
||||
private int minEvictableIdleTimeMillis;
|
||||
|
||||
@Value("${spring.datasource.druid.max-evictable-idle-time-millis}")
|
||||
private int maxEvictableIdleTimeMillis;
|
||||
|
||||
/**
|
||||
* 构建datasource
|
||||
*/
|
||||
public DruidDataSource dataSource(DruidDataSource datasource)
|
||||
{
|
||||
// 配置初始化大小、最小、最大
|
||||
datasource.setInitialSize(initialSize);
|
||||
datasource.setMaxActive(maxActive);
|
||||
datasource.setMinIdle(minIdle);
|
||||
|
||||
// 配置获取连接等待超时的时间
|
||||
datasource.setMaxWait(maxWait);
|
||||
|
||||
// 配置驱动连接超时时间,检测数据库建立连接的超时时间,单位是毫秒
|
||||
datasource.setConnectTimeout(connectTimeout);
|
||||
|
||||
// 配置网络超时时间,等待数据库操作完成的网络超时时间,单位是毫秒
|
||||
datasource.setSocketTimeout(socketTimeout);
|
||||
|
||||
// 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
||||
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
|
||||
|
||||
// 配置一个连接在池中最小、最大生存的时间,单位是毫秒
|
||||
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
|
||||
datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
|
||||
return datasource;
|
||||
}
|
||||
}
|
@ -1,28 +1,18 @@
|
||||
spring:
|
||||
# 数据库连接信息
|
||||
datasource:
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
|
||||
druid:
|
||||
master:
|
||||
url: jdbc:p6spy:mysql://127.0.0.1:3306/smart_admin_v3?autoReconnect=true&useServerPreparedStmts=false&rewriteBatchedStatements=true&characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true&serverTimezone=Asia/Shanghai
|
||||
username: root
|
||||
password: SmartAdmin666
|
||||
slave:
|
||||
enabled: true
|
||||
url: jdbc:p6spy:mysql://127.0.0.1:3306/smart_admin_v3_slave?autoReconnect=true&useServerPreparedStmts=false&rewriteBatchedStatements=true&characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true&serverTimezone=Asia/Shanghai
|
||||
username: root
|
||||
password: SmartAdmin666
|
||||
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
|
||||
initial-size: 2
|
||||
min-idle: 2
|
||||
max-active: 10
|
||||
max-wait: 60000
|
||||
connect-timeout: 30000
|
||||
socket-timeout: 30000
|
||||
time-between-eviction-runs-millis: 60000
|
||||
min-evictable-idle-time-millis: 300000
|
||||
max-evictable-idle-time-millis: 300000
|
||||
filters: stat
|
||||
druid:
|
||||
username: druid
|
||||
password: 1024
|
||||
login:
|
||||
@ -36,7 +26,7 @@ spring:
|
||||
database: 1
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
password: 123456
|
||||
password:
|
||||
timeout: 10000ms
|
||||
lettuce:
|
||||
pool:
|
||||
|
@ -67,7 +67,7 @@ spring:
|
||||
|
||||
# 缓存实现类型
|
||||
cache:
|
||||
type: caffeine
|
||||
type: redis
|
||||
|
||||
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
|
||||
server:
|
||||
|
@ -66,7 +66,7 @@ spring:
|
||||
|
||||
# 缓存实现类型
|
||||
cache:
|
||||
type: caffeine
|
||||
type: redis
|
||||
|
||||
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
|
||||
server:
|
||||
|
@ -67,7 +67,7 @@ spring:
|
||||
|
||||
# 缓存实现类型
|
||||
cache:
|
||||
type: caffeine
|
||||
type: redis
|
||||
|
||||
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
|
||||
server:
|
||||
|
@ -20,11 +20,6 @@ public class AdminCacheConst extends CacheKeyConst {
|
||||
*/
|
||||
public static final String DEPARTMENT_LIST_CACHE = "department_list_cache";
|
||||
|
||||
/**
|
||||
* 部门map
|
||||
*/
|
||||
public static final String DEPARTMENT_MAP_CACHE = "department_map_cache";
|
||||
|
||||
/**
|
||||
* 部门树
|
||||
*/
|
||||
@ -54,4 +49,20 @@ public class AdminCacheConst extends CacheKeyConst {
|
||||
public static final String CATEGORY_TREE = "category_tree_cache";
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录相关
|
||||
*/
|
||||
public static class Login {
|
||||
|
||||
/**
|
||||
* 请求用户信息
|
||||
*/
|
||||
public static final String REQUEST_EMPLOYEE = "login_request_employee";
|
||||
|
||||
/**
|
||||
* 请求用户信息权限
|
||||
*/
|
||||
public static final String USER_PERMISSION = "login_user_permission";
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import net.lab1024.sa.admin.module.system.department.domain.entity.DepartmentEnt
|
||||
import net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -32,4 +31,5 @@ public interface DepartmentDao extends BaseMapper<DepartmentEntity> {
|
||||
*/
|
||||
List<DepartmentVO> listAll();
|
||||
|
||||
DepartmentVO selectDepartmentVO(@Param("departmentId")Long departmentId);
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO;
|
||||
import net.lab1024.sa.base.common.util.SmartBeanUtil;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -43,7 +42,7 @@ public class DepartmentCacheManager {
|
||||
log.info("clear " + cache);
|
||||
}
|
||||
|
||||
@CacheEvict(value = {AdminCacheConst.Department.DEPARTMENT_LIST_CACHE, AdminCacheConst.Department.DEPARTMENT_MAP_CACHE, AdminCacheConst.Department.DEPARTMENT_SELF_CHILDREN_CACHE, AdminCacheConst.Department.DEPARTMENT_TREE_CACHE, AdminCacheConst.Department.DEPARTMENT_PATH_CACHE,}, allEntries = true)
|
||||
@CacheEvict(value = {AdminCacheConst.Department.DEPARTMENT_LIST_CACHE, AdminCacheConst.Department.DEPARTMENT_SELF_CHILDREN_CACHE, AdminCacheConst.Department.DEPARTMENT_TREE_CACHE, AdminCacheConst.Department.DEPARTMENT_PATH_CACHE,}, allEntries = true)
|
||||
public void clearCache() {
|
||||
logClearInfo(AdminCacheConst.Department.DEPARTMENT_LIST_CACHE);
|
||||
}
|
||||
@ -57,19 +56,8 @@ public class DepartmentCacheManager {
|
||||
return departmentDao.listAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 部门map
|
||||
*
|
||||
*/
|
||||
@Cacheable(AdminCacheConst.Department.DEPARTMENT_MAP_CACHE)
|
||||
public Map<Long, DepartmentVO> getDepartmentMap() {
|
||||
return departmentDao.listAll().stream().collect(Collectors.toMap(DepartmentVO::getDepartmentId, Function.identity()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 缓存部门树结构
|
||||
*
|
||||
*/
|
||||
@Cacheable(AdminCacheConst.Department.DEPARTMENT_TREE_CACHE)
|
||||
public List<DepartmentTreeVO> getDepartmentTree() {
|
||||
@ -79,7 +67,6 @@ public class DepartmentCacheManager {
|
||||
|
||||
/**
|
||||
* 缓存某个部门的下级id列表
|
||||
*
|
||||
*/
|
||||
@Cacheable(AdminCacheConst.Department.DEPARTMENT_SELF_CHILDREN_CACHE)
|
||||
public List<Long> getDepartmentSelfAndChildren(Long departmentId) {
|
||||
@ -90,7 +77,6 @@ public class DepartmentCacheManager {
|
||||
|
||||
/**
|
||||
* 部门的路径名称
|
||||
*
|
||||
*/
|
||||
@Cacheable(AdminCacheConst.Department.DEPARTMENT_PATH_CACHE)
|
||||
public Map<Long, String> getDepartmentPathMap() {
|
||||
@ -126,7 +112,6 @@ public class DepartmentCacheManager {
|
||||
|
||||
/**
|
||||
* 构建部门树结构
|
||||
*
|
||||
*/
|
||||
public List<DepartmentTreeVO> buildTree(List<DepartmentVO> voList) {
|
||||
if (CollectionUtils.isEmpty(voList)) {
|
||||
@ -193,7 +178,6 @@ public class DepartmentCacheManager {
|
||||
|
||||
/**
|
||||
* 获取子元素
|
||||
*
|
||||
*/
|
||||
private List<DepartmentTreeVO> getChildren(Long departmentId, List<DepartmentVO> voList) {
|
||||
List<DepartmentVO> childrenEntityList = voList.stream().filter(e -> departmentId.equals(e.getParentId())).collect(Collectors.toList());
|
||||
@ -206,7 +190,6 @@ public class DepartmentCacheManager {
|
||||
|
||||
/**
|
||||
* 通过部门id,获取当前以及下属部门
|
||||
*
|
||||
*/
|
||||
public List<Long> selfAndChildrenIdList(Long departmentId, List<DepartmentVO> voList) {
|
||||
List<Long> selfAndChildrenIdList = Lists.newArrayList();
|
||||
|
@ -14,10 +14,7 @@ import net.lab1024.sa.base.common.util.SmartBeanUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 部门 service
|
||||
@ -44,7 +41,6 @@ public class DepartmentService {
|
||||
|
||||
/**
|
||||
* 新增添加部门
|
||||
*
|
||||
*/
|
||||
|
||||
public ResponseDTO<String> addDepartment(DepartmentAddForm departmentAddForm) {
|
||||
@ -57,7 +53,6 @@ public class DepartmentService {
|
||||
|
||||
/**
|
||||
* 更新部门信息
|
||||
*
|
||||
*/
|
||||
public ResponseDTO<String> updateDepartment(DepartmentUpdateForm updateDTO) {
|
||||
if (updateDTO.getParentId() == null) {
|
||||
@ -78,7 +73,6 @@ public class DepartmentService {
|
||||
* 根据id删除部门
|
||||
* 1、需要判断当前部门是否有子部门,有子部门则不允许删除
|
||||
* 2、需要判断当前部门是否有员工,有员工则不能删除
|
||||
*
|
||||
*/
|
||||
public ResponseDTO<String> deleteDepartment(Long departmentId) {
|
||||
DepartmentEntity departmentEntity = departmentDao.selectById(departmentId);
|
||||
@ -122,7 +116,6 @@ public class DepartmentService {
|
||||
|
||||
/**
|
||||
* 自身以及所有下级的部门id列表
|
||||
*
|
||||
*/
|
||||
public List<Long> selfAndChildrenIdList(Long departmentId) {
|
||||
return departmentCacheManager.getDepartmentSelfAndChildren(departmentId);
|
||||
@ -131,7 +124,6 @@ public class DepartmentService {
|
||||
|
||||
/**
|
||||
* 获取所有部门
|
||||
*
|
||||
*/
|
||||
public List<DepartmentVO> listAll() {
|
||||
return departmentCacheManager.getDepartmentList();
|
||||
@ -140,10 +132,9 @@ public class DepartmentService {
|
||||
|
||||
/**
|
||||
* 获取部门
|
||||
*
|
||||
*/
|
||||
public DepartmentVO getDepartmentById(Long departmentId) {
|
||||
return departmentCacheManager.getDepartmentMap().get(departmentId);
|
||||
return departmentDao.selectDepartmentVO(departmentId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -153,38 +144,4 @@ public class DepartmentService {
|
||||
return departmentCacheManager.getDepartmentPathMap().get(departmentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询全部父级部门(不包含自己)
|
||||
*
|
||||
*/
|
||||
public List<DepartmentVO> queryAllParentDepartment(Long departmentId) {
|
||||
List<DepartmentVO> list = new ArrayList<>();
|
||||
|
||||
Map<Long, DepartmentVO> departmentMap = departmentCacheManager.getDepartmentMap();
|
||||
DepartmentVO departmentVO = departmentMap.get(departmentId);
|
||||
while (departmentVO != null) {
|
||||
list.add(departmentVO);
|
||||
departmentVO = departmentMap.get(departmentVO.getParentId());
|
||||
}
|
||||
Collections.reverse(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询全部父级部门(不包含自己)
|
||||
*
|
||||
*/
|
||||
public List<Long> queryAllParentDepartmentIdList(Long departmentId) {
|
||||
List<Long> list = new ArrayList<>();
|
||||
|
||||
Map<Long, DepartmentVO> departmentMap = departmentCacheManager.getDepartmentMap();
|
||||
DepartmentVO departmentVO = departmentMap.get(departmentId);
|
||||
while (departmentVO != null) {
|
||||
list.add(departmentVO.getDepartmentId());
|
||||
departmentVO = departmentMap.get(departmentVO.getParentId());
|
||||
}
|
||||
Collections.reverse(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ import net.lab1024.sa.base.common.enumeration.GenderEnum;
|
||||
import net.lab1024.sa.base.common.enumeration.UserTypeEnum;
|
||||
import net.lab1024.sa.base.common.swagger.SchemaEnum;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 请求员工登录信息
|
||||
*
|
||||
@ -17,7 +19,7 @@ import net.lab1024.sa.base.common.swagger.SchemaEnum;
|
||||
* @Copyright <a href="https://1024lab.net">1024创新实验室</a>
|
||||
*/
|
||||
@Data
|
||||
public class RequestEmployee implements RequestUser {
|
||||
public class RequestEmployee implements RequestUser, Serializable {
|
||||
|
||||
@Schema(description = "员工id")
|
||||
private Long employeeId;
|
||||
|
@ -0,0 +1,162 @@
|
||||
package net.lab1024.sa.admin.module.system.login.manager;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.lab1024.sa.admin.constant.AdminCacheConst;
|
||||
import net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO;
|
||||
import net.lab1024.sa.admin.module.system.department.service.DepartmentService;
|
||||
import net.lab1024.sa.admin.module.system.employee.domain.entity.EmployeeEntity;
|
||||
import net.lab1024.sa.admin.module.system.employee.service.EmployeeService;
|
||||
import net.lab1024.sa.admin.module.system.login.domain.RequestEmployee;
|
||||
import net.lab1024.sa.admin.module.system.menu.domain.vo.MenuVO;
|
||||
import net.lab1024.sa.admin.module.system.role.domain.vo.RoleVO;
|
||||
import net.lab1024.sa.admin.module.system.role.service.RoleEmployeeService;
|
||||
import net.lab1024.sa.admin.module.system.role.service.RoleMenuService;
|
||||
import net.lab1024.sa.base.common.constant.StringConst;
|
||||
import net.lab1024.sa.base.common.domain.ResponseDTO;
|
||||
import net.lab1024.sa.base.common.domain.UserPermission;
|
||||
import net.lab1024.sa.base.common.enumeration.UserTypeEnum;
|
||||
import net.lab1024.sa.base.common.util.SmartBeanUtil;
|
||||
import net.lab1024.sa.base.module.support.file.service.IFileStorageService;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.CachePut;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 登录Manager
|
||||
*
|
||||
* @Author 1024创新实验室: 卓大
|
||||
* @Date 2025-05-03 22:56:34
|
||||
* @Wechat zhuoda1024
|
||||
* @Email lab1024@163.com
|
||||
* @Copyright <a href="https://1024lab.net">1024创新实验室</a>
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class LoginManager {
|
||||
|
||||
@Resource
|
||||
private DepartmentService departmentService;
|
||||
|
||||
@Resource
|
||||
private IFileStorageService fileStorageService;
|
||||
|
||||
@Resource
|
||||
private EmployeeService employeeService;
|
||||
|
||||
@Resource
|
||||
private RoleEmployeeService roleEmployeeService;
|
||||
|
||||
@Resource
|
||||
private RoleMenuService roleMenuService;
|
||||
|
||||
|
||||
/**
|
||||
* 获取请求用户信息
|
||||
*/
|
||||
@Cacheable(AdminCacheConst.Login.REQUEST_EMPLOYEE)
|
||||
public RequestEmployee getRequestEmployee(Long requestEmployeeId ) {
|
||||
if (requestEmployeeId == null) {
|
||||
return null;
|
||||
}
|
||||
// 员工基本信息
|
||||
EmployeeEntity employeeEntity = employeeService.getById(requestEmployeeId);
|
||||
if (employeeEntity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.loadLoginInfo(employeeEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录的用户信息
|
||||
*/
|
||||
@CachePut(value = AdminCacheConst.Login.REQUEST_EMPLOYEE, key = "#employeeEntity.employeeId")
|
||||
public RequestEmployee loadLoginInfo(EmployeeEntity employeeEntity) {
|
||||
// 基础信息
|
||||
RequestEmployee requestEmployee = SmartBeanUtil.copy(employeeEntity, RequestEmployee.class);
|
||||
requestEmployee.setUserType(UserTypeEnum.ADMIN_EMPLOYEE);
|
||||
|
||||
// 部门信息
|
||||
DepartmentVO department = departmentService.getDepartmentById(employeeEntity.getDepartmentId());
|
||||
requestEmployee.setDepartmentName(null == department ? StringConst.EMPTY : department.getName());
|
||||
|
||||
// 头像信息
|
||||
String avatar = employeeEntity.getAvatar();
|
||||
if (StringUtils.isNotBlank(avatar)) {
|
||||
ResponseDTO<String> getFileUrl = fileStorageService.getFileUrl(avatar);
|
||||
if (BooleanUtils.isTrue(getFileUrl.getOk())) {
|
||||
requestEmployee.setAvatar(getFileUrl.getData());
|
||||
}
|
||||
}
|
||||
return requestEmployee;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取用户的权限(包含 角色列表、权限列表)
|
||||
*/
|
||||
@Cacheable(AdminCacheConst.Login.USER_PERMISSION)
|
||||
public UserPermission getUserPermission(Long employeeId) {
|
||||
if(null == employeeId){
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.loadUserPermission(employeeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户的权限(包含 角色列表、权限列表)
|
||||
*/
|
||||
@CachePut(AdminCacheConst.Login.USER_PERMISSION)
|
||||
public UserPermission loadUserPermission(Long employeeId) {
|
||||
UserPermission userPermission = new UserPermission();
|
||||
userPermission.setPermissionList(new ArrayList<>());
|
||||
userPermission.setRoleList(new ArrayList<>());
|
||||
|
||||
// 角色列表
|
||||
List<RoleVO> roleList = roleEmployeeService.getRoleIdList(employeeId);
|
||||
userPermission.getRoleList().addAll(roleList.stream().map(RoleVO::getRoleCode).collect(Collectors.toSet()));
|
||||
|
||||
// 前端菜单和功能点清单
|
||||
EmployeeEntity employeeEntity = employeeService.getById(employeeId);
|
||||
|
||||
List<MenuVO> menuAndPointsList = roleMenuService.getMenuList(roleList.stream().map(RoleVO::getRoleId).collect(Collectors.toList()), employeeEntity.getAdministratorFlag());
|
||||
|
||||
// 权限列表
|
||||
HashSet<String> permissionSet = new HashSet<>();
|
||||
for (MenuVO menu : menuAndPointsList) {
|
||||
if (menu.getPermsType() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String perms = menu.getApiPerms();
|
||||
if (StringUtils.isEmpty(perms)) {
|
||||
continue;
|
||||
}
|
||||
//接口权限
|
||||
String[] split = perms.split(",");
|
||||
permissionSet.addAll(Arrays.asList(split));
|
||||
}
|
||||
userPermission.getPermissionList().addAll(permissionSet);
|
||||
|
||||
return userPermission;
|
||||
}
|
||||
|
||||
|
||||
@CacheEvict(value = {AdminCacheConst.Login.USER_PERMISSION, AdminCacheConst.Login.REQUEST_EMPLOYEE}, allEntries = true)
|
||||
public void clear(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -6,7 +6,6 @@ import cn.hutool.core.lang.UUID;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO;
|
||||
import net.lab1024.sa.admin.module.system.department.service.DepartmentService;
|
||||
@ -15,6 +14,7 @@ import net.lab1024.sa.admin.module.system.employee.service.EmployeeService;
|
||||
import net.lab1024.sa.admin.module.system.login.domain.LoginForm;
|
||||
import net.lab1024.sa.admin.module.system.login.domain.LoginResultVO;
|
||||
import net.lab1024.sa.admin.module.system.login.domain.RequestEmployee;
|
||||
import net.lab1024.sa.admin.module.system.login.manager.LoginManager;
|
||||
import net.lab1024.sa.admin.module.system.menu.domain.vo.MenuVO;
|
||||
import net.lab1024.sa.admin.module.system.role.domain.vo.RoleVO;
|
||||
import net.lab1024.sa.admin.module.system.role.service.RoleEmployeeService;
|
||||
@ -56,15 +56,16 @@ import org.springframework.stereotype.Service;
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 登录
|
||||
*
|
||||
* @Author 1024创新实验室: 开云
|
||||
* @Date 2021-12-01 22:56:34
|
||||
* @Author 1024创新实验室: 卓大
|
||||
* @Date 2025-05-03 22:56:34
|
||||
* @Wechat zhuoda1024
|
||||
* @Email lab1024@163.com
|
||||
* @Copyright <a href="https://1024lab.net">1024创新实验室</a>
|
||||
@ -78,22 +79,6 @@ public class LoginService implements StpInterface {
|
||||
*/
|
||||
private static final String SUPER_PASSWORD_LOGIN_ID_PREFIX = "S";
|
||||
|
||||
/**
|
||||
* 最大在线缓存人数
|
||||
*/
|
||||
private static final long CACHE_MAX_ONLINE_PERSON_COUNT = 1000L;
|
||||
|
||||
/**
|
||||
* 登录信息二级缓存
|
||||
*/
|
||||
private final ConcurrentMap<Long, RequestEmployee> loginEmployeeCache = new ConcurrentLinkedHashMap.Builder<Long, RequestEmployee>().maximumWeightedCapacity(CACHE_MAX_ONLINE_PERSON_COUNT).build();
|
||||
|
||||
|
||||
/**
|
||||
* 权限 缓存
|
||||
*/
|
||||
private final ConcurrentMap<Long, UserPermission> permissionCache = new ConcurrentLinkedHashMap.Builder<Long, UserPermission>().maximumWeightedCapacity(CACHE_MAX_ONLINE_PERSON_COUNT).build();
|
||||
|
||||
@Resource
|
||||
private EmployeeService employeeService;
|
||||
|
||||
@ -136,6 +121,9 @@ public class LoginService implements StpInterface {
|
||||
@Resource
|
||||
private RedisService redisService;
|
||||
|
||||
@Resource
|
||||
private LoginManager loginManager;
|
||||
|
||||
/**
|
||||
* 获取验证码
|
||||
*/
|
||||
@ -226,10 +214,7 @@ public class LoginService implements StpInterface {
|
||||
}
|
||||
|
||||
// 获取员工信息
|
||||
RequestEmployee requestEmployee = loadLoginInfo(employeeEntity);
|
||||
|
||||
// 放入缓存
|
||||
loginEmployeeCache.put(employeeEntity.getEmployeeId(), requestEmployee);
|
||||
RequestEmployee requestEmployee = loginManager.loadLoginInfo(employeeEntity);
|
||||
|
||||
// 移除登录失败
|
||||
securityLoginService.removeLoginFail(employeeEntity.getEmployeeId(), UserTypeEnum.ADMIN_EMPLOYEE);
|
||||
@ -244,8 +229,8 @@ public class LoginService implements StpInterface {
|
||||
// 设置 token
|
||||
loginResultVO.setToken(token);
|
||||
|
||||
// 清除权限缓存
|
||||
permissionCache.remove(employeeEntity.getEmployeeId());
|
||||
// 更新用户权限
|
||||
loginManager.loadUserPermission(employeeEntity.getEmployeeId());
|
||||
|
||||
return ResponseDTO.ok(loginResultVO);
|
||||
}
|
||||
@ -264,10 +249,6 @@ public class LoginService implements StpInterface {
|
||||
List<MenuVO> menuAndPointsList = roleMenuService.getMenuList(roleList.stream().map(RoleVO::getRoleId).collect(Collectors.toList()), requestEmployee.getAdministratorFlag());
|
||||
loginResultVO.setMenuList(menuAndPointsList);
|
||||
|
||||
// 更新下后端权限缓存
|
||||
UserPermission userPermission = getUserPermission(requestEmployee.getUserId());
|
||||
permissionCache.put(requestEmployee.getUserId(), userPermission);
|
||||
|
||||
// 上次登录信息
|
||||
LoginLogVO loginLogVO = loginLogService.queryLastByUserId(requestEmployee.getEmployeeId(), UserTypeEnum.ADMIN_EMPLOYEE, LoginLogResultEnum.LOGIN_SUCCESS);
|
||||
if (loginLogVO != null) {
|
||||
@ -291,32 +272,6 @@ public class LoginService implements StpInterface {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取登录的用户信息
|
||||
*/
|
||||
private RequestEmployee loadLoginInfo(EmployeeEntity employeeEntity) {
|
||||
|
||||
// 基础信息
|
||||
RequestEmployee requestEmployee = SmartBeanUtil.copy(employeeEntity, RequestEmployee.class);
|
||||
requestEmployee.setUserType(UserTypeEnum.ADMIN_EMPLOYEE);
|
||||
|
||||
// 部门信息
|
||||
DepartmentVO department = departmentService.getDepartmentById(employeeEntity.getDepartmentId());
|
||||
requestEmployee.setDepartmentName(null == department ? StringConst.EMPTY : department.getName());
|
||||
|
||||
// 头像信息
|
||||
String avatar = employeeEntity.getAvatar();
|
||||
if (StringUtils.isNotBlank(avatar)) {
|
||||
ResponseDTO<String> getFileUrl = fileStorageService.getFileUrl(avatar);
|
||||
if (BooleanUtils.isTrue(getFileUrl.getOk())) {
|
||||
requestEmployee.setAvatar(getFileUrl.getData());
|
||||
}
|
||||
}
|
||||
|
||||
return requestEmployee;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据登陆token 获取员请求工信息
|
||||
*/
|
||||
@ -330,17 +285,7 @@ public class LoginService implements StpInterface {
|
||||
return null;
|
||||
}
|
||||
|
||||
RequestEmployee requestEmployee = loginEmployeeCache.get(requestEmployeeId);
|
||||
if (requestEmployee == null) {
|
||||
// 员工基本信息
|
||||
EmployeeEntity employeeEntity = employeeService.getById(requestEmployeeId);
|
||||
if (employeeEntity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
requestEmployee = this.loadLoginInfo(employeeEntity);
|
||||
loginEmployeeCache.put(requestEmployeeId, requestEmployee);
|
||||
}
|
||||
RequestEmployee requestEmployee = loginManager.getRequestEmployee(requestEmployeeId);
|
||||
|
||||
// 更新请求ip和user agent
|
||||
requestEmployee.setUserAgent(ServletUtil.getHeaderIgnoreCase(request, RequestHeaderConst.USER_AGENT));
|
||||
@ -384,7 +329,7 @@ public class LoginService implements StpInterface {
|
||||
StpUtil.logout();
|
||||
|
||||
// 清空登录信息缓存
|
||||
loginEmployeeCache.remove(requestUser.getUserId());
|
||||
loginManager.clear();
|
||||
|
||||
//保存登出日志
|
||||
LoginLogEntity loginEntity = LoginLogEntity.builder()
|
||||
@ -402,14 +347,6 @@ public class LoginService implements StpInterface {
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除员工登录缓存
|
||||
*/
|
||||
public void clearLoginEmployeeCache(Long employeeId) {
|
||||
// 清空登录信息缓存
|
||||
loginEmployeeCache.remove(employeeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存登录日志
|
||||
*/
|
||||
@ -437,12 +374,7 @@ public class LoginService implements StpInterface {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
UserPermission userPermission = permissionCache.get(employeeId);
|
||||
if (userPermission == null) {
|
||||
userPermission = getUserPermission(employeeId);
|
||||
permissionCache.put(employeeId, userPermission);
|
||||
}
|
||||
|
||||
UserPermission userPermission = loginManager.getUserPermission(employeeId);
|
||||
return userPermission.getPermissionList();
|
||||
}
|
||||
|
||||
@ -453,51 +385,10 @@ public class LoginService implements StpInterface {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
UserPermission userPermission = permissionCache.get(employeeId);
|
||||
if (userPermission == null) {
|
||||
userPermission = getUserPermission(employeeId);
|
||||
permissionCache.put(employeeId, userPermission);
|
||||
}
|
||||
UserPermission userPermission = loginManager.getUserPermission(employeeId);
|
||||
return userPermission.getRoleList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户的权限(包含 角色列表、权限列表)
|
||||
*/
|
||||
private UserPermission getUserPermission(Long employeeId) {
|
||||
|
||||
UserPermission userPermission = new UserPermission();
|
||||
userPermission.setPermissionList(new ArrayList<>());
|
||||
userPermission.setRoleList(new ArrayList<>());
|
||||
|
||||
// 角色列表
|
||||
List<RoleVO> roleList = roleEmployeeService.getRoleIdList(employeeId);
|
||||
userPermission.getRoleList().addAll(roleList.stream().map(RoleVO::getRoleCode).collect(Collectors.toSet()));
|
||||
|
||||
// 前端菜单和功能点清单
|
||||
EmployeeEntity employeeEntity = employeeService.getById(employeeId);
|
||||
|
||||
List<MenuVO> menuAndPointsList = roleMenuService.getMenuList(roleList.stream().map(RoleVO::getRoleId).collect(Collectors.toList()), employeeEntity.getAdministratorFlag());
|
||||
|
||||
// 权限列表
|
||||
HashSet<String> permissionSet = new HashSet<>();
|
||||
for (MenuVO menu : menuAndPointsList) {
|
||||
if (menu.getPermsType() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String perms = menu.getApiPerms();
|
||||
if (StringUtils.isEmpty(perms)) {
|
||||
continue;
|
||||
}
|
||||
//接口权限
|
||||
String[] split = perms.split(",");
|
||||
permissionSet.addAll(Arrays.asList(split));
|
||||
}
|
||||
userPermission.getPermissionList().addAll(permissionSet);
|
||||
|
||||
return userPermission;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 邮箱 验证码
|
||||
@ -592,4 +483,8 @@ public class LoginService implements StpInterface {
|
||||
String redisVerificationCodeKey = redisService.generateRedisKey(RedisKeyConst.Support.LOGIN_VERIFICATION_CODE, UserTypeEnum.ADMIN_EMPLOYEE.getValue() + RedisKeyConst.SEPARATOR + employeeId);
|
||||
redisService.delete(redisVerificationCodeKey);
|
||||
}
|
||||
|
||||
public void clearLoginEmployeeCache(Long employeeId) {
|
||||
loginManager.clear();
|
||||
}
|
||||
}
|
||||
|
@ -19,5 +19,16 @@
|
||||
WHERE parent_id = #{departmentId}
|
||||
</select>
|
||||
|
||||
<select id="selectDepartmentVO"
|
||||
resultType="net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO">
|
||||
SELECT t_department.*,
|
||||
t_employee.actual_name as managerName,
|
||||
parent_department.`name` as parentName
|
||||
FROM t_department
|
||||
left join t_employee on t_department.manager_id = t_employee.employee_id
|
||||
left join t_department parent_department on t_department.parent_id = parent_department.department_id
|
||||
where t_department.department_id = #{departmentId}
|
||||
</select>
|
||||
|
||||
|
||||
</mapper>
|
@ -2,6 +2,7 @@ package net.lab1024.sa.base.common.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -15,7 +16,7 @@ import java.util.List;
|
||||
*/
|
||||
|
||||
@Data
|
||||
public class UserPermission {
|
||||
public class UserPermission implements Serializable {
|
||||
|
||||
/**
|
||||
* 权限列表
|
||||
|
@ -1,11 +1,17 @@
|
||||
package net.lab1024.sa.base.config;
|
||||
|
||||
import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
|
||||
import net.lab1024.sa.base.module.support.cache.CacheService;
|
||||
import net.lab1024.sa.base.module.support.cache.CaffeineCacheServiceImpl;
|
||||
import net.lab1024.sa.base.module.support.cache.RedisCacheServiceImpl;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 缓存配置
|
||||
@ -20,6 +26,18 @@ public class CacheConfig {
|
||||
private static final String CAFFEINE_CACHE = "caffeine";
|
||||
|
||||
|
||||
@Resource
|
||||
private RedisConnectionFactory factory;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = "spring.cache", name = {"type"}, havingValue = REDIS_CACHE)
|
||||
public RedisCacheConfiguration redisCacheConfiguration() {
|
||||
return RedisCacheConfiguration.defaultCacheConfig()
|
||||
.disableCachingNullValues()
|
||||
.computePrefixWith(name -> "cache:" + name + ":")
|
||||
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericFastJsonRedisSerializer()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = "spring.cache", name = {"type"}, havingValue = REDIS_CACHE)
|
||||
public CacheService redisCacheService() {
|
||||
|
@ -66,7 +66,7 @@ spring:
|
||||
|
||||
# 缓存实现类型
|
||||
cache:
|
||||
type: caffeine
|
||||
type: redis
|
||||
|
||||
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
|
||||
server:
|
||||
|
@ -66,7 +66,7 @@ spring:
|
||||
|
||||
# 缓存实现类型
|
||||
cache:
|
||||
type: caffeine
|
||||
type: redis
|
||||
|
||||
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
|
||||
server:
|
||||
|
@ -65,7 +65,7 @@ spring:
|
||||
|
||||
# 缓存实现类型
|
||||
cache:
|
||||
type: caffeine
|
||||
type: redis
|
||||
|
||||
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
|
||||
server:
|
||||
|
@ -66,7 +66,7 @@ spring:
|
||||
|
||||
# 缓存实现类型
|
||||
cache:
|
||||
type: caffeine
|
||||
type: redis
|
||||
|
||||
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
|
||||
server:
|
||||
|
BIN
smart-admin-web-javascript/src/assets/images/login/login-min.gif
Normal file
BIN
smart-admin-web-javascript/src/assets/images/login/login-min.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 MiB |
@ -8,7 +8,7 @@
|
||||
|
||||
const props = defineProps({
|
||||
dictCode: String,
|
||||
dataValue: String,
|
||||
dataValue: [String, Number],
|
||||
});
|
||||
const dataLabels = computed(() => {
|
||||
return useDictStore().getDataLabels(props.dictCode, props.dataValue);
|
||||
|
@ -1,6 +1,4 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { dictApi } from '/@/api/support/dict-api';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import { DICT_SPLIT } from '/@/constants/support/dict-const.js';
|
||||
import _ from 'lodash';
|
||||
|
||||
@ -23,14 +21,21 @@ export const useDictStore = defineStore({
|
||||
|
||||
// 获取字典的值名称
|
||||
getDataLabels(dictCode, dataValue) {
|
||||
if (!dataValue) {
|
||||
if (_.isNil(dataValue) || _.isNaN(dataValue)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let dict = this.getDictData(dictCode);
|
||||
if (dict.length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// 是数字的话,需要特殊处理
|
||||
if(_.isNumber(dataValue)){
|
||||
let target = _.find(dict, { dataValue: dataValue });
|
||||
return target ? target.dataLabel : '';
|
||||
}
|
||||
|
||||
let valueArray = dataValue.split(DICT_SPLIT);
|
||||
let result = [];
|
||||
for (let item of valueArray) {
|
||||
|
@ -498,7 +498,9 @@
|
||||
|
||||
// 动态设置表格高度
|
||||
const yHeight = ref(0);
|
||||
|
||||
onMounted(() => {
|
||||
resetGetHeight();
|
||||
});
|
||||
function resetGetHeight() {
|
||||
// 搜索部分高度
|
||||
let doc = document.querySelector('.ant-form');
|
||||
@ -515,20 +517,10 @@
|
||||
yHeight.value = box.offsetHeight - dueHeight;
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// 定义一个变量来存储节流后的回调函数
|
||||
let throttledResizeHandler;
|
||||
onMounted(() => {
|
||||
window.addEventListener(
|
||||
'resize',
|
||||
_.throttle(() => {
|
||||
resetGetHeight();
|
||||
throttledResizeHandler = _.throttle(() => {
|
||||
resetGetHeight();
|
||||
}, 1000);
|
||||
|
||||
window.addEventListener('resize', throttledResizeHandler);
|
||||
});
|
||||
|
||||
// 在组件销毁时移除 resize 事件监听器
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', throttledResizeHandler);
|
||||
});
|
||||
}, 1000)
|
||||
);
|
||||
</script>
|
||||
|
@ -41,7 +41,7 @@
|
||||
|
||||
<a-table
|
||||
size="small"
|
||||
:scroll="{ y: 800 }"
|
||||
:scroll="{ x: 1000 }"
|
||||
:loading="tableLoading"
|
||||
bordered
|
||||
:dataSource="tableData"
|
||||
|
@ -56,11 +56,9 @@
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import { PAGE_SIZE, PAGE_SIZE_OPTIONS } from '/@/constants/common-const';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import SmartEnumSelect from '/@/components/framework/smart-enum-select/index.vue';
|
||||
import { employeeApi } from '/@/api/system/employee-api';
|
||||
// ---------------查询条件----------------
|
||||
const queryParamState = {
|
||||
|
@ -54,11 +54,11 @@
|
||||
</a-col>
|
||||
<!--待办、已办-->
|
||||
<a-col :span="24">
|
||||
<ToBeDoneCard />
|
||||
<ChangelogCard />
|
||||
</a-col>
|
||||
<!--更新日志-->
|
||||
<a-col :span="24">
|
||||
<ChangelogCard />
|
||||
<ToBeDoneCard />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
|
@ -80,8 +80,7 @@
|
||||
import { LOGIN_DEVICE_ENUM } from '/@/constants/system/login-device-const';
|
||||
import { useUserStore } from '/@/store/modules/system/user';
|
||||
import loginQR from '/@/assets/images/login/login-qr.png';
|
||||
import leftBg2 from '/@/assets/images/login/left-bg2.png';
|
||||
import loginGif from '/@/assets/images/login/login.gif';
|
||||
import loginGif from '/@/assets/images/login/login-min.gif';
|
||||
import wechatIcon from '/@/assets/images/login/wechat-icon.png';
|
||||
import aliIcon from '/@/assets/images/login/ali-icon.png';
|
||||
import douyinIcon from '/@/assets/images/login/douyin-icon.png';
|
||||
|
@ -12,11 +12,11 @@
|
||||
<li v-for="module in props.tree" :key="module.menuId">
|
||||
<div class="menu" :style="{ marginLeft: `${props.index * 4}%` }">
|
||||
<a-checkbox @change="selectCheckbox(module)" class="checked-box-label" :value="module.menuId">{{ module.menuName }} </a-checkbox>
|
||||
<div v-if="module.children && module.children.some((e) => e.menuType == MENU_TYPE_ENUM.POINTS.value)">
|
||||
<div v-if="module.children && module.children.some((e) => e.menuType === MENU_TYPE_ENUM.POINTS.value)">
|
||||
<RoleTreePoint :tree="module.children" @selectCheckbox="selectCheckbox" />
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="module.children && !module.children.some((e) => e.menuType == MENU_TYPE_ENUM.POINTS.value)">
|
||||
<template v-if="module.children && !module.children.some((e) => e.menuType === MENU_TYPE_ENUM.POINTS.value)">
|
||||
<RoleTreeMenu :tree="module.children" :index="props.index + 1" />
|
||||
</template>
|
||||
</li>
|
||||
@ -47,7 +47,7 @@
|
||||
let checkedData = roleStore.checkedData;
|
||||
let findIndex = checkedData.indexOf(module.menuId);
|
||||
// 选中
|
||||
if (findIndex == -1) {
|
||||
if (findIndex === -1) {
|
||||
// 选中本级以及子级
|
||||
roleStore.addCheckedDataAndChildren(module);
|
||||
// 选中上级
|
||||
|
@ -44,17 +44,14 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import dayjs from 'dayjs';
|
||||
import { computed, h, useSlots } from 'vue';
|
||||
import {computed, h} from 'vue';
|
||||
import {messages} from '/@/i18n';
|
||||
import {useAppConfigStore} from '/@/store/modules/system/app-config';
|
||||
import {useSpinStore} from '/@/store/modules/system/spin';
|
||||
import { theme } from 'ant-design-vue';
|
||||
import {Popover, theme} from 'ant-design-vue';
|
||||
import {themeColors} from '/@/theme/color.js';
|
||||
import { Popover } from 'ant-design-vue';
|
||||
import SmartCopyIcon from '/@/components/framework/smart-copy-icon/index.vue';
|
||||
import _ from 'lodash';
|
||||
|
||||
const slots = useSlots();
|
||||
const antdLocale = computed(() => messages[useAppConfigStore().language].antdLocale);
|
||||
const dayjsLocale = computed(() => messages[useAppConfigStore().language].dayjsLocale);
|
||||
dayjs.locale(dayjsLocale);
|
||||
@ -91,6 +88,7 @@
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
:deep(.ant-table-column-sorters) {
|
||||
|
BIN
smart-admin-web-typescript/src/assets/images/login/login-min.gif
Normal file
BIN
smart-admin-web-typescript/src/assets/images/login/login-min.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 MiB |
@ -8,7 +8,7 @@
|
||||
|
||||
const props = defineProps({
|
||||
dictCode: String,
|
||||
dataValue: String,
|
||||
dataValue: [String, Number],
|
||||
});
|
||||
const dataLabels = computed(() => {
|
||||
return useDictStore().getDataLabels(props.dictCode, props.dataValue);
|
||||
|
@ -7,13 +7,7 @@
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
*/
|
||||
import { AppConfig } from '/@/types/config';
|
||||
|
||||
/**
|
||||
* 应用默认配置
|
||||
*/
|
||||
|
||||
export const appDefaultConfig: AppConfig = {
|
||||
export const appDefaultConfig = {
|
||||
// i18n 语言选择
|
||||
language: 'zh_CN',
|
||||
// 布局: side 或者 side-expand 或者 top
|
||||
|
@ -208,9 +208,9 @@
|
||||
// 页面圆角
|
||||
borderRadius: appConfigStore.borderRadius,
|
||||
// 标签页
|
||||
flatPattern: appConfigStore.flatPattern,
|
||||
// 标签页
|
||||
pageTagFlag: appConfigStore.pageTagFlag,
|
||||
// 标签页
|
||||
flatPattern: appConfigStore.flatPattern,
|
||||
// 标签页 样式
|
||||
pageTagStyle: appConfigStore.pageTagStyle,
|
||||
// 面包屑
|
||||
@ -251,7 +251,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
function changePageTagLocation(e: any) {
|
||||
function changePageTagLocation(e) {
|
||||
appConfigStore.$patch({
|
||||
pageTagLocation: e.target.value,
|
||||
});
|
||||
|
@ -48,6 +48,7 @@
|
||||
const menuTree = computed(() => useUserStore().getMenuTree || []);
|
||||
const rootSubmenuKeys = computed(()=>menuTree.value.map(item=>item.menuId));
|
||||
|
||||
|
||||
//展开的菜单
|
||||
let currentRoute = useRoute();
|
||||
const selectedKeys = ref([]);
|
||||
|
@ -1,6 +1,4 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { dictApi } from '/@/api/support/dict-api';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import { DICT_SPLIT } from '/@/constants/support/dict-const.js';
|
||||
import _ from 'lodash';
|
||||
|
||||
@ -23,14 +21,21 @@ export const useDictStore = defineStore({
|
||||
|
||||
// 获取字典的值名称
|
||||
getDataLabels(dictCode, dataValue) {
|
||||
if (!dataValue) {
|
||||
if (_.isNil(dataValue) || _.isNaN(dataValue)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let dict = this.getDictData(dictCode);
|
||||
if (dict.length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// 是数字的话,需要特殊处理
|
||||
if(_.isNumber(dataValue)){
|
||||
let target = _.find(dict, { dataValue: dataValue });
|
||||
return target ? target.dataLabel : '';
|
||||
}
|
||||
|
||||
let valueArray = dataValue.split(DICT_SPLIT);
|
||||
let result = [];
|
||||
for (let item of valueArray) {
|
||||
|
@ -36,7 +36,7 @@
|
||||
</a-button>
|
||||
</a-button-group>
|
||||
|
||||
<a-button @click="addOrUpdate()" type="primary" class="smart-margin-left20" v-if="$privilege('oa:bank:add')">
|
||||
<a-button @click="addOrUpdate()" type="primary" class="smart-margin-left20">
|
||||
<template #icon>
|
||||
<PlusOutlined />
|
||||
</template>
|
||||
@ -60,8 +60,8 @@
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'action'">
|
||||
<div class="smart-table-operate">
|
||||
<a-button @click="addOrUpdate(record)" type="link" v-if="$privilege('oa:bank:update')">编辑</a-button>
|
||||
<a-button @click="confirmDelete(record.bankId)" danger type="link" v-if="$privilege('oa:bank:delete')">删除</a-button>
|
||||
<a-button @click="addOrUpdate(record)" type="link">编辑</a-button>
|
||||
<a-button @click="confirmDelete(record.bankId)" danger type="link">删除</a-button>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
@ -8,8 +8,8 @@
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
-->
|
||||
<template>
|
||||
<a-modal :open="visible" :title="form.bankId ? '编辑' : '添加'" :width="700" ok-text="确认" cancel-text="取消" @ok="onSubmit" @cancel="onClose">
|
||||
<a-form ref="formRef" :model="form" :rules="rules" :label-col="{ span: 4 }" :wrapper-col="{ span: 19 }">
|
||||
<a-modal :open="visible" :title="form.bankId ? '编辑' : '添加'" ok-text="确认" cancel-text="取消" @ok="onSubmit" @cancel="onClose">
|
||||
<a-form ref="formRef" :model="form" :rules="rules" :label-col="{ span: 5 }" :wrapper-col="{ span: 18 }">
|
||||
<a-form-item label="开户银行" name="bankName">
|
||||
<a-input v-model:value="form.bankName" placeholder="请输入开户银行" />
|
||||
</a-form-item>
|
||||
|
@ -16,20 +16,12 @@
|
||||
<a-button class="button-style" type="primary" @click="onSearch">搜索</a-button>
|
||||
<a-button class="button-style" type="default" @click="resetQueryEmployee">重置</a-button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a-button class="button-style" type="primary" @click="addEmployee" v-privilege="'oa:enterprise:addEmployee'"> 添加员工 </a-button>
|
||||
<a-button class="button-style" type="primary" danger @click="batchDelete" v-privilege="'oa:enterprise:deleteEmployee'"> 批量移除 </a-button>
|
||||
</div>
|
||||
</div>
|
||||
<a-card size="small" :bordered="false" :hoverable="false">
|
||||
<a-row justify="end">
|
||||
<TableOperator
|
||||
class="smart-margin-bottom5"
|
||||
v-model="columns"
|
||||
:tableId="TABLE_ID_CONST.BUSINESS.OA.ENTERPRISE_EMPLOYEE"
|
||||
:refresh="queryEmployee"
|
||||
/>
|
||||
</a-row>
|
||||
<a-table
|
||||
:loading="tableLoading"
|
||||
:dataSource="tableData"
|
||||
@ -40,7 +32,7 @@
|
||||
size="small"
|
||||
bordered
|
||||
>
|
||||
<template #bodyCell="{ text, record, column }">
|
||||
<template #bodyCell="{ text, record, index, column }">
|
||||
<template v-if="column.dataIndex === 'disabledFlag'">
|
||||
<a-tag :color="text ? 'error' : 'processing'">{{ text ? '禁用' : '启用' }}</a-tag>
|
||||
</template>
|
||||
@ -48,7 +40,7 @@
|
||||
<span>{{ $smartEnumPlugin.getDescByValue('GENDER_ENUM', text) }}</span>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'operate'">
|
||||
<a-button type="link" @click="deleteEmployee(record.employeeId)" v-privilege="'oa:enterprise:deleteEmployee'">移除</a-button>
|
||||
<a @click="deleteEmployee(record.employeeId)" v-privilege="'oa:enterprise:deleteEmployee'">移除</a>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
@ -68,7 +60,6 @@
|
||||
/>
|
||||
</div>
|
||||
<EmployeeTableSelectModal ref="selectEmployeeModal" @selectData="selectData" />
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
@ -81,8 +72,6 @@
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import { PAGE_SIZE, PAGE_SIZE_OPTIONS, showTableTotal } from '/@/constants/common-const';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import TableOperator from '/@/components/support/table-operator/index.vue';
|
||||
import { TABLE_ID_CONST } from '/@/constants/support/table-id-const';
|
||||
|
||||
const props = defineProps({
|
||||
enterpriseId: {
|
||||
@ -123,8 +112,7 @@
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'operate',
|
||||
width: 90,
|
||||
align: 'center',
|
||||
width: 60,
|
||||
},
|
||||
]);
|
||||
|
||||
@ -283,8 +271,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 10px 10px;
|
||||
margin-bottom: 10px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.button-style {
|
||||
|
@ -36,8 +36,7 @@
|
||||
</a-button>
|
||||
</a-button-group>
|
||||
|
||||
|
||||
<a-button @click="addOrUpdate()" type="primary" class="smart-margin-left20" v-if="$privilege('oa:invoice:add')">
|
||||
<a-button @click="addOrUpdate()" type="primary" class="smart-margin-left20">
|
||||
<template #icon>
|
||||
<PlusOutlined />
|
||||
</template>
|
||||
@ -52,14 +51,14 @@
|
||||
<TableOperator class="smart-margin-bottom5" v-model="columns" :tableId="TABLE_ID_CONST.BUSINESS.OA.ENTERPRISE_INVOICE" :refresh="ajaxQuery" />
|
||||
</a-row>
|
||||
<a-table :scroll="{ x: 1300 }" size="small" :dataSource="tableData" :columns="columns" rowKey="invoiceId" :pagination="false" bordered>
|
||||
<template #bodyCell="{ record, column }">
|
||||
<template #bodyCell="{ text, record, index, column }">
|
||||
<template v-if="column.dataIndex === 'disabledFlag'">
|
||||
{{ record.disabledFlag ? '禁用' : '启用' }}
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'action'">
|
||||
<div class="smart-table-operate">
|
||||
<a-button @click="addOrUpdate(record)" type="link" v-if="$privilege('oa:invoice:update')">编辑</a-button>
|
||||
<a-button @click="confirmDelete(record.invoiceId)" type="link" danger v-if="$privilege('oa:invoice:delete')">删除</a-button>
|
||||
<a-button @click="addOrUpdate(record)" type="link">编辑</a-button>
|
||||
<a-button @click="confirmDelete(record.invoiceId)" type="link" danger>删除</a-button>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
@ -8,8 +8,8 @@
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
-->
|
||||
<template>
|
||||
<a-modal :open="visible" :title="form.invoiceId ? '编辑' : '添加'" :width="700" ok-text="确认" cancel-text="取消" @ok="onSubmit" @cancel="onClose">
|
||||
<a-form ref="formRef" :model="form" :rules="rules" :label-col="{ span: 4 }" :wrapper-col="{ span: 19 }">
|
||||
<a-modal :open="visible" :title="form.invoiceId ? '编辑' : '添加'" ok-text="确认" cancel-text="取消" @ok="onSubmit" @cancel="onClose">
|
||||
<a-form ref="formRef" :model="form" :rules="rules" :label-col="{ span: 5 }" :wrapper-col="{ span: 12 }">
|
||||
<a-form-item label="开票抬头" name="invoiceHeads">
|
||||
<a-input v-model:value="form.invoiceHeads" placeholder="请输入开票抬头" />
|
||||
</a-form-item>
|
||||
|
@ -1,15 +1,6 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:open="visible"
|
||||
:title="form.enterpriseId ? '编辑' : '添加'"
|
||||
:width="700"
|
||||
forceRender
|
||||
ok-text="确认"
|
||||
cancel-text="取消"
|
||||
@ok="onSubmit"
|
||||
@cancel="onClose"
|
||||
>
|
||||
<a-form ref="formRef" :model="form" :rules="rules" :label-col="{ span: 5 }" :wrapper-col="{ span: 18 }">
|
||||
<a-modal :open="visible" title="添加" :width="700" forceRender ok-text="确认" cancel-text="取消" @ok="onSubmit" @cancel="onClose">
|
||||
<a-form ref="formRef" :model="form" :rules="rules" :label-col="{ span: 6 }">
|
||||
<a-form-item label="企业名称" name="enterpriseName">
|
||||
<a-input v-model:value="form.enterpriseName" placeholder="请输入企业名称" />
|
||||
</a-form-item>
|
||||
|
@ -41,7 +41,7 @@
|
||||
|
||||
<a-table
|
||||
size="small"
|
||||
:scroll="{ y: 800 }"
|
||||
:scroll="{ x: 1000 }"
|
||||
:loading="tableLoading"
|
||||
bordered
|
||||
:dataSource="tableData"
|
||||
|
@ -45,13 +45,7 @@
|
||||
新建
|
||||
</a-button>
|
||||
|
||||
<a-button
|
||||
@click="confirmBatchDelete"
|
||||
v-privilege="'support:dict:delete'"
|
||||
type="primary"
|
||||
danger
|
||||
:disabled="selectedRowKeyList.length === 0"
|
||||
>
|
||||
<a-button @click="confirmBatchDelete" v-privilege="'support:dict:delete'" type="primary" danger :disabled="selectedRowKeyList.length === 0">
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
</template>
|
||||
|
@ -54,13 +54,11 @@
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from 'vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import { PAGE_SIZE, PAGE_SIZE_OPTIONS } from '/@/constants/common-const';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import SmartEnumSelect from '/@/components/framework/smart-enum-select/index.vue';
|
||||
import { employeeApi } from '/@/api/system/employee-api';
|
||||
// ---------------查询条件----------------
|
||||
const queryParamState = {
|
||||
|
@ -24,7 +24,7 @@
|
||||
</a-modal>
|
||||
<MessageReceiverModal ref="receiverModalRef" @reloadList="addReceiverIdList" />
|
||||
</template>
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import { nextTick, reactive, ref } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
|
@ -86,7 +86,7 @@
|
||||
<MessageSendForm ref="formRef" @reloadList="queryData" />
|
||||
</a-card>
|
||||
</template>
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
|
@ -54,11 +54,11 @@
|
||||
</a-col>
|
||||
<!--待办、已办-->
|
||||
<a-col :span="24">
|
||||
<ToBeDoneCard />
|
||||
<ChangelogCard />
|
||||
</a-col>
|
||||
<!--更新日志-->
|
||||
<a-col :span="24">
|
||||
<ChangelogCard />
|
||||
<ToBeDoneCard />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
|
@ -80,8 +80,7 @@
|
||||
import { LOGIN_DEVICE_ENUM } from '/@/constants/system/login-device-const';
|
||||
import { useUserStore } from '/@/store/modules/system/user';
|
||||
import loginQR from '/@/assets/images/login/login-qr.png';
|
||||
import leftBg2 from '/@/assets/images/login/left-bg2.png';
|
||||
import loginGif from '/@/assets/images/login/login.gif';
|
||||
import loginGif from '/@/assets/images/login/login-min.gif';
|
||||
import wechatIcon from '/@/assets/images/login/wechat-icon.png';
|
||||
import aliIcon from '/@/assets/images/login/ali-icon.png';
|
||||
import douyinIcon from '/@/assets/images/login/douyin-icon.png';
|
||||
|
@ -17,7 +17,7 @@
|
||||
@close="onClose"
|
||||
destroyOnClose
|
||||
>
|
||||
<a-form ref="formRef" :labelCol="{ span: labelColSpan }" :labelWrap="true" :model="form" :rules="rules">
|
||||
<a-form ref="formRef" :labelCol="{ span: 5 }" :labelWrap="true" :model="form" :rules="rules">
|
||||
<a-form-item label="菜单类型" name="menuType">
|
||||
<a-radio-group v-model:value="form.menuType" button-style="solid">
|
||||
<a-radio-button v-for="item in MENU_TYPE_ENUM" :key="item.value" :value="item.value">
|
||||
@ -62,7 +62,13 @@
|
||||
<a-switch v-model:checked="form.visibleFlag" checked-children="显示" un-checked-children="不显示" />
|
||||
</a-form-item>
|
||||
<a-form-item label="禁用状态" name="disabledFlag">
|
||||
<a-switch v-model:checked="form.disabledFlag" :checkedValue="false" :unCheckedValue="true" checked-children="启用" un-checked-children="禁用" />
|
||||
<a-switch
|
||||
v-model:checked="form.disabledFlag"
|
||||
:checkedValue="false"
|
||||
:unCheckedValue="true"
|
||||
checked-children="启用"
|
||||
un-checked-children="禁用"
|
||||
/>
|
||||
</a-form-item>
|
||||
</template>
|
||||
<!-- 目录 菜单 end -->
|
||||
@ -75,7 +81,13 @@
|
||||
<MenuTreeSelect ref="contextMenuTreeSelect" v-model:value="form.contextMenuId" />
|
||||
</a-form-item>
|
||||
<a-form-item label="功能点状态" name="funcDisabledFlag">
|
||||
<a-switch v-model:checked="form.disabledFlag" :checkedValue="false" :unCheckedValue="true" checked-children="启用" un-checked-children="禁用" />
|
||||
<a-switch
|
||||
v-model:checked="form.disabledFlag"
|
||||
:checkedValue="false"
|
||||
:unCheckedValue="true"
|
||||
checked-children="启用"
|
||||
un-checked-children="禁用"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="权限类型" name="permsType">
|
||||
<a-radio-group v-model:value="form.permsType">
|
||||
@ -106,7 +118,7 @@
|
||||
<script setup lang="ts">
|
||||
import { message } from 'ant-design-vue';
|
||||
import _ from 'lodash';
|
||||
import { computed, nextTick, reactive, ref } from 'vue';
|
||||
import { nextTick, reactive, ref } from 'vue';
|
||||
import MenuTreeSelect from './menu-tree-select.vue';
|
||||
import { menuApi } from '/@/api/system/menu-api';
|
||||
import IconSelect from '/@/components/framework/icon-select/index.vue';
|
||||
@ -123,13 +135,6 @@
|
||||
// 是否展示抽屉
|
||||
const visible = ref(false);
|
||||
|
||||
const labelColSpan = computed(() => {
|
||||
if (form.menuType === MENU_TYPE_ENUM.POINTS.value) {
|
||||
return 6;
|
||||
}
|
||||
return 4;
|
||||
});
|
||||
|
||||
const contextMenuTreeSelect = ref();
|
||||
const parentMenuTreeSelect = ref();
|
||||
|
||||
@ -179,7 +184,7 @@
|
||||
apiPerms: undefined,
|
||||
sort: undefined,
|
||||
visibleFlag: true,
|
||||
cacheFlag: true,
|
||||
cacheFlag: false,
|
||||
component: undefined,
|
||||
contextMenuId: undefined,
|
||||
disabledFlag: false,
|
||||
@ -197,6 +202,9 @@
|
||||
formRef.value.resetFields();
|
||||
form.menuType = menuType;
|
||||
form.parentId = parentId;
|
||||
if (form.menuType === MENU_TYPE_ENUM.POINTS.value) {
|
||||
form.contextMenuId = parentId;
|
||||
}
|
||||
// 移除最后一个:后面的内容
|
||||
if (webPerms && webPerms.lastIndexOf(':')) {
|
||||
form.webPerms = webPerms.substring(0, webPerms.lastIndexOf(':') + 1);
|
||||
|
@ -126,7 +126,7 @@ function isMenuExistMenuType(menu, menuType) {
|
||||
/**
|
||||
* 过滤关键字
|
||||
*/
|
||||
function isMenuExistKeywords(menu: any, keywords: string) {
|
||||
function isMenuExistKeywords(menu, keywords) {
|
||||
if (!keywords) {
|
||||
return true;
|
||||
}
|
||||
|
@ -12,11 +12,11 @@
|
||||
<li v-for="module in props.tree" :key="module.menuId">
|
||||
<div class="menu" :style="{ marginLeft: `${props.index * 4}%` }">
|
||||
<a-checkbox @change="selectCheckbox(module)" class="checked-box-label" :value="module.menuId">{{ module.menuName }} </a-checkbox>
|
||||
<div v-if="module.children && module.children.some((e) => e.menuType == MENU_TYPE_ENUM.POINTS.value)">
|
||||
<div v-if="module.children && module.children.some((e) => e.menuType === MENU_TYPE_ENUM.POINTS.value)">
|
||||
<RoleTreePoint :tree="module.children" @selectCheckbox="selectCheckbox" />
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="module.children && !module.children.some((e) => e.menuType == MENU_TYPE_ENUM.POINTS.value)">
|
||||
<template v-if="module.children && !module.children.some((e) => e.menuType === MENU_TYPE_ENUM.POINTS.value)">
|
||||
<RoleTreeMenu :tree="module.children" :index="props.index + 1" />
|
||||
</template>
|
||||
</li>
|
||||
@ -47,7 +47,7 @@
|
||||
let checkedData = roleStore.checkedData;
|
||||
let findIndex = checkedData.indexOf(module.menuId);
|
||||
// 选中
|
||||
if (findIndex == -1) {
|
||||
if (findIndex === -1) {
|
||||
// 选中本级以及子级
|
||||
roleStore.addCheckedDataAndChildren(module);
|
||||
// 选中上级
|
||||
|
Loading…
Reference in New Issue
Block a user