v3.20.0 【新增】优化登录使用spring cache;【新增】优化部门cache;【新增】代码生成枚举;【优化】三级等保Label显示宽度

This commit is contained in:
zhuoda 2025-05-03 21:31:28 +08:00
parent f198a949c9
commit 3fb4dfad09
92 changed files with 872 additions and 1023 deletions

View File

@ -20,11 +20,6 @@ public class AdminCacheConst extends CacheKeyConst {
*/ */
public static final String DEPARTMENT_LIST_CACHE = "department_list_cache"; 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 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";
}
} }

View File

@ -17,7 +17,7 @@ import org.hibernate.validator.constraints.Length;
* @Date 2021-10-25 20:26:54 * @Date 2021-10-25 20:26:54
* @Wechat zhuoda1024 * @Wechat zhuoda1024
* @Email lab1024@163.com * @Email lab1024@163.com
* @Copyright <a href="https://1024lab.net">1024创新实验室</a> * @Copyright <a href="https://1024lab.net">1024创新实验室</a>
*/ */
@Data @Data
public class GoodsQueryForm extends PageParam { public class GoodsQueryForm extends PageParam {

View File

@ -1,6 +1,5 @@
package net.lab1024.sa.admin.module.business.goods.domain.vo; 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 io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import net.lab1024.sa.admin.module.business.goods.constant.GoodsStatusEnum; import net.lab1024.sa.admin.module.business.goods.constant.GoodsStatusEnum;

View File

@ -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 cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
@ -8,7 +8,6 @@ import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; 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.form.*;
import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseEmployeeVO; import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseEmployeeVO;
import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseExcelVO; import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseExcelVO;

View File

@ -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 com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.lab1024.sa.admin.module.business.oa.enterprise.dao.EnterpriseEmployeeDao; import net.lab1024.sa.admin.module.business.oa.enterprise.dao.EnterpriseEmployeeDao;

View File

@ -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.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists; 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.EnterpriseExcelVO;
import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseListVO; 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.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.admin.module.system.department.service.DepartmentService;
import net.lab1024.sa.base.common.code.UserErrorCode; import net.lab1024.sa.base.common.code.UserErrorCode;
import net.lab1024.sa.base.common.domain.PageResult; import net.lab1024.sa.base.common.domain.PageResult;

View File

@ -3,7 +3,7 @@ package net.lab1024.sa.admin.module.business.oa.invoice.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; 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.enterprise.domain.vo.EnterpriseVO;
import net.lab1024.sa.admin.module.business.oa.invoice.dao.InvoiceDao; import net.lab1024.sa.admin.module.business.oa.invoice.dao.InvoiceDao;
import net.lab1024.sa.admin.module.business.oa.invoice.domain.*; import net.lab1024.sa.admin.module.business.oa.invoice.domain.*;

View File

@ -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.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;

View File

@ -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 net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
@ -32,4 +31,5 @@ public interface DepartmentDao extends BaseMapper<DepartmentEntity> {
*/ */
List<DepartmentVO> listAll(); List<DepartmentVO> listAll();
DepartmentVO selectDepartmentVO(@Param("departmentId")Long departmentId);
} }

View File

@ -29,7 +29,7 @@ import java.util.stream.Collectors;
* @Date 2022-01-12 20:37:48 * @Date 2022-01-12 20:37:48
* @Wechat zhuoda1024 * @Wechat zhuoda1024
* @Email lab1024@163.com * @Email lab1024@163.com
* @Copyright <a href="https://1024lab.net">1024创新实验室</a> * @Copyright <a href="https://1024lab.net">1024创新实验室</a>
*/ */
@Slf4j @Slf4j
@Service @Service
@ -42,7 +42,7 @@ public class DepartmentCacheManager {
log.info("clear " + cache); 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() { public void clearCache() {
logClearInfo(AdminCacheConst.Department.DEPARTMENT_LIST_CACHE); logClearInfo(AdminCacheConst.Department.DEPARTMENT_LIST_CACHE);
} }
@ -56,19 +56,8 @@ public class DepartmentCacheManager {
return departmentDao.listAll(); 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) @Cacheable(AdminCacheConst.Department.DEPARTMENT_TREE_CACHE)
public List<DepartmentTreeVO> getDepartmentTree() { public List<DepartmentTreeVO> getDepartmentTree() {
@ -78,7 +67,6 @@ public class DepartmentCacheManager {
/** /**
* 缓存某个部门的下级id列表 * 缓存某个部门的下级id列表
*
*/ */
@Cacheable(AdminCacheConst.Department.DEPARTMENT_SELF_CHILDREN_CACHE) @Cacheable(AdminCacheConst.Department.DEPARTMENT_SELF_CHILDREN_CACHE)
public List<Long> getDepartmentSelfAndChildren(Long departmentId) { public List<Long> getDepartmentSelfAndChildren(Long departmentId) {
@ -89,7 +77,6 @@ public class DepartmentCacheManager {
/** /**
* 部门的路径名称 * 部门的路径名称
*
*/ */
@Cacheable(AdminCacheConst.Department.DEPARTMENT_PATH_CACHE) @Cacheable(AdminCacheConst.Department.DEPARTMENT_PATH_CACHE)
public Map<Long, String> getDepartmentPathMap() { public Map<Long, String> getDepartmentPathMap() {
@ -125,7 +112,6 @@ public class DepartmentCacheManager {
/** /**
* 构建部门树结构 * 构建部门树结构
*
*/ */
public List<DepartmentTreeVO> buildTree(List<DepartmentVO> voList) { public List<DepartmentTreeVO> buildTree(List<DepartmentVO> voList) {
if (CollectionUtils.isEmpty(voList)) { if (CollectionUtils.isEmpty(voList)) {
@ -140,7 +126,7 @@ public class DepartmentCacheManager {
return treeVOList; return treeVOList;
} }
/** /**
* 构建所有根节点的下级树形结构 * 构建所有根节点的下级树形结构
* 返回值为层序遍历结果 * 返回值为层序遍历结果
* [由于departmentDao中listAll给出数据根据Sort降序 所以同一层中Sort值较大的优先遍历] * [由于departmentDao中listAll给出数据根据Sort降序 所以同一层中Sort值较大的优先遍历]
@ -148,7 +134,7 @@ public class DepartmentCacheManager {
private List<Long> recursiveBuildTree(List<DepartmentTreeVO> nodeList, List<DepartmentVO> allDepartmentList) { private List<Long> recursiveBuildTree(List<DepartmentTreeVO> nodeList, List<DepartmentVO> allDepartmentList) {
int nodeSize = nodeList.size(); int nodeSize = nodeList.size();
List<Long> childIdList = new ArrayList<>(); List<Long> childIdList = new ArrayList<>();
for(int i = 0; i < nodeSize; i++) { for (int i = 0; i < nodeSize; i++) {
int preIndex = i - 1; int preIndex = i - 1;
int nextIndex = i + 1; int nextIndex = i + 1;
DepartmentTreeVO node = nodeList.get(i); DepartmentTreeVO node = nodeList.get(i);
@ -167,14 +153,14 @@ public class DepartmentCacheManager {
tempChildIdList = this.recursiveBuildTree(children, allDepartmentList); tempChildIdList = this.recursiveBuildTree(children, allDepartmentList);
} }
if(CollectionUtils.isEmpty(node.getSelfAndAllChildrenIdList())) { if (CollectionUtils.isEmpty(node.getSelfAndAllChildrenIdList())) {
node.setSelfAndAllChildrenIdList( node.setSelfAndAllChildrenIdList(
new ArrayList<>() new ArrayList<>()
); );
} }
node.getSelfAndAllChildrenIdList().add(node.getDepartmentId()); node.getSelfAndAllChildrenIdList().add(node.getDepartmentId());
if(CollectionUtils.isNotEmpty(tempChildIdList)) { if (CollectionUtils.isNotEmpty(tempChildIdList)) {
node.getSelfAndAllChildrenIdList().addAll(tempChildIdList); node.getSelfAndAllChildrenIdList().addAll(tempChildIdList);
childIdList.addAll(tempChildIdList); childIdList.addAll(tempChildIdList);
} }
@ -182,7 +168,7 @@ public class DepartmentCacheManager {
} }
// 保证本层遍历顺序 // 保证本层遍历顺序
for(int i = nodeSize - 1; i >= 0; i--) { for (int i = nodeSize - 1; i >= 0; i--) {
childIdList.add(0, nodeList.get(i).getDepartmentId()); childIdList.add(0, nodeList.get(i).getDepartmentId());
} }
@ -192,7 +178,6 @@ public class DepartmentCacheManager {
/** /**
* 获取子元素 * 获取子元素
*
*/ */
private List<DepartmentTreeVO> getChildren(Long departmentId, List<DepartmentVO> voList) { private List<DepartmentTreeVO> getChildren(Long departmentId, List<DepartmentVO> voList) {
List<DepartmentVO> childrenEntityList = voList.stream().filter(e -> departmentId.equals(e.getParentId())).collect(Collectors.toList()); List<DepartmentVO> childrenEntityList = voList.stream().filter(e -> departmentId.equals(e.getParentId())).collect(Collectors.toList());
@ -205,7 +190,6 @@ public class DepartmentCacheManager {
/** /**
* 通过部门id,获取当前以及下属部门 * 通过部门id,获取当前以及下属部门
*
*/ */
public List<Long> selfAndChildrenIdList(Long departmentId, List<DepartmentVO> voList) { public List<Long> selfAndChildrenIdList(Long departmentId, List<DepartmentVO> voList) {
List<Long> selfAndChildrenIdList = Lists.newArrayList(); List<Long> selfAndChildrenIdList = Lists.newArrayList();

View File

@ -26,7 +26,7 @@ import java.util.Map;
* @Date 2022-01-12 20:37:48 * @Date 2022-01-12 20:37:48
* @Wechat zhuoda1024 * @Wechat zhuoda1024
* @Email lab1024@163.com * @Email lab1024@163.com
* @Copyright <a href="https://1024lab.net">1024创新实验室</a> * @Copyright <a href="https://1024lab.net">1024创新实验室</a>
*/ */
@Service @Service
public class DepartmentService { public class DepartmentService {
@ -44,7 +44,6 @@ public class DepartmentService {
/** /**
* 新增添加部门 * 新增添加部门
*
*/ */
public ResponseDTO<String> addDepartment(DepartmentAddForm departmentAddForm) { public ResponseDTO<String> addDepartment(DepartmentAddForm departmentAddForm) {
@ -57,7 +56,6 @@ public class DepartmentService {
/** /**
* 更新部门信息 * 更新部门信息
*
*/ */
public ResponseDTO<String> updateDepartment(DepartmentUpdateForm updateDTO) { public ResponseDTO<String> updateDepartment(DepartmentUpdateForm updateDTO) {
if (updateDTO.getParentId() == null) { if (updateDTO.getParentId() == null) {
@ -78,7 +76,6 @@ public class DepartmentService {
* 根据id删除部门 * 根据id删除部门
* 1需要判断当前部门是否有子部门,有子部门则不允许删除 * 1需要判断当前部门是否有子部门,有子部门则不允许删除
* 2需要判断当前部门是否有员工有员工则不能删除 * 2需要判断当前部门是否有员工有员工则不能删除
*
*/ */
public ResponseDTO<String> deleteDepartment(Long departmentId) { public ResponseDTO<String> deleteDepartment(Long departmentId) {
DepartmentEntity departmentEntity = departmentDao.selectById(departmentId); DepartmentEntity departmentEntity = departmentDao.selectById(departmentId);
@ -122,7 +119,6 @@ public class DepartmentService {
/** /**
* 自身以及所有下级的部门id列表 * 自身以及所有下级的部门id列表
*
*/ */
public List<Long> selfAndChildrenIdList(Long departmentId) { public List<Long> selfAndChildrenIdList(Long departmentId) {
return departmentCacheManager.getDepartmentSelfAndChildren(departmentId); return departmentCacheManager.getDepartmentSelfAndChildren(departmentId);
@ -131,7 +127,6 @@ public class DepartmentService {
/** /**
* 获取所有部门 * 获取所有部门
*
*/ */
public List<DepartmentVO> listAll() { public List<DepartmentVO> listAll() {
return departmentCacheManager.getDepartmentList(); return departmentCacheManager.getDepartmentList();
@ -140,10 +135,9 @@ public class DepartmentService {
/** /**
* 获取部门 * 获取部门
*
*/ */
public DepartmentVO getDepartmentById(Long departmentId) { 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); 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;
}
} }

View File

@ -2,9 +2,7 @@ package net.lab1024.sa.admin.module.system.employee.domain.form;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import lombok.Data; import lombok.Data;
import net.lab1024.sa.base.common.util.SmartVerificationUtil;
/** /**
* 修改密码所需参数 * 修改密码所需参数

View File

@ -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(){
}
}

View File

@ -6,17 +6,16 @@ import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import cn.hutool.extra.servlet.JakartaServletUtil; import cn.hutool.extra.servlet.JakartaServletUtil;
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j; 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.department.service.DepartmentService;
import net.lab1024.sa.admin.module.system.employee.domain.entity.EmployeeEntity; 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.employee.service.EmployeeService;
import net.lab1024.sa.admin.module.system.login.domain.LoginForm; 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.LoginResultVO;
import net.lab1024.sa.admin.module.system.login.domain.RequestEmployee; 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.menu.domain.vo.MenuVO;
import net.lab1024.sa.admin.module.system.role.domain.vo.RoleVO; 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.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.mail.constant.MailTemplateCodeEnum;
import net.lab1024.sa.base.module.support.redis.RedisService; 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.domain.LoginFailEntity;
import net.lab1024.sa.base.module.support.securityprotect.service.*; import net.lab1024.sa.base.module.support.securityprotect.service.Level3ProtectConfigService;
import org.apache.commons.lang3.BooleanUtils; import net.lab1024.sa.base.module.support.securityprotect.service.SecurityLoginService;
import org.apache.commons.lang3.StringUtils; import net.lab1024.sa.base.module.support.securityprotect.service.SecurityPasswordService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.*; import java.util.Collections;
import java.util.concurrent.ConcurrentMap; import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
* 登录 * 登录
* *
* @Author 1024创新实验室: 开云 * @Author 1024创新实验室: 卓大
* @Date 2021-12-01 22:56:34 * @Date 2025-05-03 22:56:34
* @Wechat zhuoda1024 * @Wechat zhuoda1024
* @Email lab1024@163.com * @Email lab1024@163.com
* @Copyright <a href="https://1024lab.net">1024创新实验室</a> * @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 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 @Resource
private EmployeeService employeeService; private EmployeeService employeeService;
@ -134,6 +118,9 @@ public class LoginService implements StpInterface {
@Resource @Resource
private RedisService redisService; private RedisService redisService;
@Resource
private LoginManager loginManager;
/** /**
* 获取验证码 * 获取验证码
*/ */
@ -224,10 +211,7 @@ public class LoginService implements StpInterface {
} }
// 获取员工信息 // 获取员工信息
RequestEmployee requestEmployee = loadLoginInfo(employeeEntity); RequestEmployee requestEmployee = loginManager.loadLoginInfo(employeeEntity);
// 放入缓存
loginEmployeeCache.put(employeeEntity.getEmployeeId(), requestEmployee);
// 移除登录失败 // 移除登录失败
securityLoginService.removeLoginFail(employeeEntity.getEmployeeId(), UserTypeEnum.ADMIN_EMPLOYEE); securityLoginService.removeLoginFail(employeeEntity.getEmployeeId(), UserTypeEnum.ADMIN_EMPLOYEE);
@ -242,8 +226,8 @@ public class LoginService implements StpInterface {
// 设置 token // 设置 token
loginResultVO.setToken(token); loginResultVO.setToken(token);
// 清除权限缓存 // 更新用户权限
permissionCache.remove(employeeEntity.getEmployeeId()); loginManager.loadUserPermission(employeeEntity.getEmployeeId());
return ResponseDTO.ok(loginResultVO); 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()); List<MenuVO> menuAndPointsList = roleMenuService.getMenuList(roleList.stream().map(RoleVO::getRoleId).collect(Collectors.toList()), requestEmployee.getAdministratorFlag());
loginResultVO.setMenuList(menuAndPointsList); 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); LoginLogVO loginLogVO = loginLogService.queryLastByUserId(requestEmployee.getEmployeeId(), UserTypeEnum.ADMIN_EMPLOYEE, LoginLogResultEnum.LOGIN_SUCCESS);
if (loginLogVO != null) { 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 获取员请求工信息 * 根据登陆token 获取员请求工信息
*/ */
@ -328,17 +282,7 @@ public class LoginService implements StpInterface {
return null; return null;
} }
RequestEmployee requestEmployee = loginEmployeeCache.get(requestEmployeeId); RequestEmployee requestEmployee = loginManager.getRequestEmployee(requestEmployeeId);
if (requestEmployee == null) {
// 员工基本信息
EmployeeEntity employeeEntity = employeeService.getById(requestEmployeeId);
if (employeeEntity == null) {
return null;
}
requestEmployee = this.loadLoginInfo(employeeEntity);
loginEmployeeCache.put(requestEmployeeId, requestEmployee);
}
// 更新请求ip和user agent // 更新请求ip和user agent
requestEmployee.setUserAgent(JakartaServletUtil.getHeaderIgnoreCase(request, RequestHeaderConst.USER_AGENT)); requestEmployee.setUserAgent(JakartaServletUtil.getHeaderIgnoreCase(request, RequestHeaderConst.USER_AGENT));
@ -382,7 +326,7 @@ public class LoginService implements StpInterface {
StpUtil.logout(); StpUtil.logout();
// 清空登录信息缓存 // 清空登录信息缓存
loginEmployeeCache.remove(requestUser.getUserId()); loginManager.clear();
//保存登出日志 //保存登出日志
LoginLogEntity loginEntity = LoginLogEntity.builder() LoginLogEntity loginEntity = LoginLogEntity.builder()
@ -400,14 +344,6 @@ public class LoginService implements StpInterface {
return ResponseDTO.ok(); return ResponseDTO.ok();
} }
/**
* 清除员工登录缓存
*/
public void clearLoginEmployeeCache(Long employeeId) {
// 清空登录信息缓存
loginEmployeeCache.remove(employeeId);
}
/** /**
* 保存登录日志 * 保存登录日志
*/ */
@ -435,12 +371,7 @@ public class LoginService implements StpInterface {
return Collections.emptyList(); return Collections.emptyList();
} }
UserPermission userPermission = permissionCache.get(employeeId); UserPermission userPermission = loginManager.getUserPermission(employeeId);
if (userPermission == null) {
userPermission = getUserPermission(employeeId);
permissionCache.put(employeeId, userPermission);
}
return userPermission.getPermissionList(); return userPermission.getPermissionList();
} }
@ -451,51 +382,10 @@ public class LoginService implements StpInterface {
return Collections.emptyList(); return Collections.emptyList();
} }
UserPermission userPermission = permissionCache.get(employeeId); UserPermission userPermission = loginManager.getUserPermission(employeeId);
if (userPermission == null) {
userPermission = getUserPermission(employeeId);
permissionCache.put(employeeId, userPermission);
}
return userPermission.getRoleList(); 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); String redisVerificationCodeKey = redisService.generateRedisKey(RedisKeyConst.Support.LOGIN_VERIFICATION_CODE, UserTypeEnum.ADMIN_EMPLOYEE.getValue() + RedisKeyConst.SEPARATOR + employeeId);
redisService.delete(redisVerificationCodeKey); redisService.delete(redisVerificationCodeKey);
} }
public void clearLoginEmployeeCache(Long employeeId) {
loginManager.clear();
}
} }

View File

@ -3,11 +3,7 @@ package net.lab1024.sa.admin.module.system.role.manager;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 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.dao.RoleEmployeeDao;
import net.lab1024.sa.admin.module.system.role.domain.entity.RoleEmployeeEntity; 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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/** /**
* 角色员工 manager * 角色员工 manager

View File

@ -19,5 +19,16 @@
WHERE parent_id = #{departmentId} WHERE parent_id = #{departmentId}
</select> </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> </mapper>

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -2,6 +2,7 @@ package net.lab1024.sa.base.common.domain;
import lombok.Data; import lombok.Data;
import java.io.Serializable;
import java.util.List; import java.util.List;
/** /**
@ -15,7 +16,7 @@ import java.util.List;
*/ */
@Data @Data
public class UserPermission { public class UserPermission implements Serializable {
/** /**
* 权限列表 * 权限列表

View File

@ -1,11 +1,14 @@
package net.lab1024.sa.base.config; 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.CacheService;
import net.lab1024.sa.base.module.support.cache.CaffeineCacheServiceImpl; import net.lab1024.sa.base.module.support.cache.CaffeineCacheServiceImpl;
import net.lab1024.sa.base.module.support.cache.RedisCacheServiceImpl; import net.lab1024.sa.base.module.support.cache.RedisCacheServiceImpl;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; 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 REDIS_CACHE = "redis";
private static final String CAFFEINE_CACHE = "caffeine"; 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 @Bean
@ConditionalOnProperty(prefix = "spring.cache", name = {"type"}, havingValue = REDIS_CACHE) @ConditionalOnProperty(prefix = "spring.cache", name = {"type"}, havingValue = REDIS_CACHE)

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -1,17 +1,8 @@
package net.lab1024.sa.base.module.support.cache; 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 org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/** /**
* 缓存服务 * 缓存服务

View File

@ -3,10 +3,8 @@ package net.lab1024.sa.base.module.support.codegenerator.service.variable.backen
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import net.lab1024.sa.base.module.support.codegenerator.constant.CodeQueryFieldQueryTypeEnum; 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.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.domain.model.CodeQueryField;
import net.lab1024.sa.base.module.support.codegenerator.service.variable.CodeGenerateBaseVariableService; import net.lab1024.sa.base.module.support.codegenerator.service.variable.CodeGenerateBaseVariableService;
import org.apache.commons.collections4.CollectionUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;

View File

@ -1,13 +1,8 @@
package net.lab1024.sa.base.module.support.job.api.domain; package net.lab1024.sa.base.module.support.job.api.domain;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.Data; 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;
/** /**
* 定时任务 更新 * 定时任务 更新

View File

@ -1,10 +1,13 @@
package net.lab1024.sa.base.module.support.message.domain; 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 jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
import net.lab1024.sa.base.common.enumeration.UserTypeEnum; import net.lab1024.sa.base.common.enumeration.UserTypeEnum;
import net.lab1024.sa.base.module.support.message.constant.MessageTemplateEnum; import net.lab1024.sa.base.module.support.message.constant.MessageTemplateEnum;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@ -25,6 +28,10 @@ public class MessageTemplateSendForm {
@NotNull(message = "接收者id不能为空") @NotNull(message = "接收者id不能为空")
private Long receiverUserId; private Long receiverUserId;
@Schema(description = "接收者id")
@NotEmpty(message = "接收者id不能为空")
private List<Long> receiverUserIdList;
/** /**
* 相关业务id | 可选 * 相关业务id | 可选
* 用于跳转具体业务 * 用于跳转具体业务

View File

@ -11,9 +11,6 @@ import net.lab1024.sa.base.module.support.reload.core.thread.SmartReloadRunnable
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor; 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.stereotype.Service;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;

View File

@ -2,7 +2,6 @@ package net.lab1024.sa.base.module.support.reload.core.thread;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.base.module.support.reload.core.AbstractSmartReloadCommand; 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.SmartReloadItem;
import net.lab1024.sa.base.module.support.reload.core.domain.SmartReloadObject; import net.lab1024.sa.base.module.support.reload.core.domain.SmartReloadObject;
import net.lab1024.sa.base.module.support.reload.core.domain.SmartReloadResult; import net.lab1024.sa.base.module.support.reload.core.domain.SmartReloadResult;

View File

@ -13,7 +13,7 @@ import java.lang.annotation.Target;
* @Date 2020-11-25 20:56:58 * @Date 2020-11-25 20:56:58
* @Wechat zhuoda1024 * @Wechat zhuoda1024
* @Email lab1024@163.com * @Email lab1024@163.com
* @Copyright <a href="https://1024lab.net">1024创新实验室</a> * @Copyright <a href="https://1024lab.net">1024创新实验室</a>
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target(ElementType.METHOD)

View File

@ -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.Cache;
import com.github.benmanes.caffeine.cache.Caffeine; 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.concurrent.TimeUnit;
import java.util.function.Function; import java.util.function.Function;

View File

@ -1,9 +1,7 @@
package net.lab1024.sa.base.module.support.repeatsubmit.ticket; 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 org.springframework.data.redis.core.ValueOperations;
import java.util.concurrent.TimeUnit;
import java.util.function.Function; import java.util.function.Function;
/** /**

View File

@ -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;
}
}

View File

@ -22,12 +22,12 @@
#end #end
#if($field.queryTypeEnum == "Dict") #if($field.queryTypeEnum == "Dict")
<a-form-item label="${field.label}" class="smart-query-form-item"> <a-form-item label="${field.label}" class="smart-query-form-item">
<DictSelect dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="${field.label}" v-model:value="queryForm.${field.fieldName}" width="${field.width}" /> <DictSelect dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="${field.label}" v-model:value="queryForm.${field.fieldName}" width="${field.width}" />
</a-form-item> </a-form-item>
#end #end
#if($field.queryTypeEnum == "Enum") #if($field.queryTypeEnum == "Enum")
<a-form-item label="$codeGeneratorTool.removeEnumDesc(${field.label})" class="smart-query-form-item"> <a-form-item label="$codeGeneratorTool.removeEnumDesc(${field.label})" class="smart-query-form-item">
<SmartEnumSelect width="${field.width}" v-model:value="queryForm.${field.fieldName}" enum-name="$!{field.frontEnumName}" placeholder="$codeGeneratorTool.removeEnumDesc(${field.label})"/> <SmartEnumSelect width="${field.width}" v-model:value="queryForm.${field.fieldName}" enum-name="$!{field.frontEnumName}" placeholder="$codeGeneratorTool.removeEnumDesc(${field.label})"/>
</a-form-item> </a-form-item>
#end #end
#if($field.queryTypeEnum == "Date") #if($field.queryTypeEnum == "Date")

View File

@ -1,28 +1,18 @@
spring: spring:
# 数据库连接信息 # 数据库连接信息
datasource: datasource:
type: com.alibaba.druid.pool.DruidDataSource 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
driver-class-name: com.p6spy.engine.spy.P6SpyDriver driver-class-name: com.p6spy.engine.spy.P6SpyDriver
initial-size: 2
min-idle: 2
max-active: 10
max-wait: 60000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
filters: stat
druid: 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
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
username: druid username: druid
password: 1024 password: 1024
login: login:
@ -36,7 +26,7 @@ spring:
database: 1 database: 1
host: 127.0.0.1 host: 127.0.0.1
port: 6379 port: 6379
password: 123456 password:
timeout: 10000ms timeout: 10000ms
lettuce: lettuce:
pool: pool:

View File

@ -67,7 +67,7 @@ spring:
# 缓存实现类型 # 缓存实现类型
cache: cache:
type: caffeine type: redis
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误) # tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
server: server:

View File

@ -66,7 +66,7 @@ spring:
# 缓存实现类型 # 缓存实现类型
cache: cache:
type: caffeine type: redis
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误) # tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
server: server:

View File

@ -67,7 +67,7 @@ spring:
# 缓存实现类型 # 缓存实现类型
cache: cache:
type: caffeine type: redis
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误) # tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
server: server:

View File

@ -20,11 +20,6 @@ public class AdminCacheConst extends CacheKeyConst {
*/ */
public static final String DEPARTMENT_LIST_CACHE = "department_list_cache"; 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 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";
}
} }

View File

@ -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 net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
@ -32,4 +31,5 @@ public interface DepartmentDao extends BaseMapper<DepartmentEntity> {
*/ */
List<DepartmentVO> listAll(); List<DepartmentVO> listAll();
DepartmentVO selectDepartmentVO(@Param("departmentId")Long departmentId);
} }

View File

@ -10,7 +10,6 @@ import net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO;
import net.lab1024.sa.base.common.util.SmartBeanUtil; import net.lab1024.sa.base.common.util.SmartBeanUtil;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.math.NumberUtils; 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.CacheEvict;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -30,7 +29,7 @@ import java.util.stream.Collectors;
* @Date 2022-01-12 20:37:48 * @Date 2022-01-12 20:37:48
* @Wechat zhuoda1024 * @Wechat zhuoda1024
* @Email lab1024@163.com * @Email lab1024@163.com
* @Copyright <a href="https://1024lab.net">1024创新实验室</a> * @Copyright <a href="https://1024lab.net">1024创新实验室</a>
*/ */
@Slf4j @Slf4j
@Service @Service
@ -43,7 +42,7 @@ public class DepartmentCacheManager {
log.info("clear " + cache); 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() { public void clearCache() {
logClearInfo(AdminCacheConst.Department.DEPARTMENT_LIST_CACHE); logClearInfo(AdminCacheConst.Department.DEPARTMENT_LIST_CACHE);
} }
@ -57,19 +56,8 @@ public class DepartmentCacheManager {
return departmentDao.listAll(); 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) @Cacheable(AdminCacheConst.Department.DEPARTMENT_TREE_CACHE)
public List<DepartmentTreeVO> getDepartmentTree() { public List<DepartmentTreeVO> getDepartmentTree() {
@ -79,7 +67,6 @@ public class DepartmentCacheManager {
/** /**
* 缓存某个部门的下级id列表 * 缓存某个部门的下级id列表
*
*/ */
@Cacheable(AdminCacheConst.Department.DEPARTMENT_SELF_CHILDREN_CACHE) @Cacheable(AdminCacheConst.Department.DEPARTMENT_SELF_CHILDREN_CACHE)
public List<Long> getDepartmentSelfAndChildren(Long departmentId) { public List<Long> getDepartmentSelfAndChildren(Long departmentId) {
@ -90,7 +77,6 @@ public class DepartmentCacheManager {
/** /**
* 部门的路径名称 * 部门的路径名称
*
*/ */
@Cacheable(AdminCacheConst.Department.DEPARTMENT_PATH_CACHE) @Cacheable(AdminCacheConst.Department.DEPARTMENT_PATH_CACHE)
public Map<Long, String> getDepartmentPathMap() { public Map<Long, String> getDepartmentPathMap() {
@ -126,7 +112,6 @@ public class DepartmentCacheManager {
/** /**
* 构建部门树结构 * 构建部门树结构
*
*/ */
public List<DepartmentTreeVO> buildTree(List<DepartmentVO> voList) { public List<DepartmentTreeVO> buildTree(List<DepartmentVO> voList) {
if (CollectionUtils.isEmpty(voList)) { if (CollectionUtils.isEmpty(voList)) {
@ -141,15 +126,15 @@ public class DepartmentCacheManager {
return treeVOList; return treeVOList;
} }
/** /**
* 构建所有根节点的下级树形结构 * 构建所有根节点的下级树形结构
* 返回值为层序遍历结果 * 返回值为层序遍历结果
* [由于departmentDao中listAll给出数据根据Sort降序 所以同一层中Sort值较大的优先遍历] * [由于departmentDao中listAll给出数据根据Sort降序 所以同一层中Sort值较大的优先遍历]
*/ */
private List<Long> recursiveBuildTree(List<DepartmentTreeVO> nodeList, List<DepartmentVO> allDepartmentList) { private List<Long> recursiveBuildTree(List<DepartmentTreeVO> nodeList, List<DepartmentVO> allDepartmentList) {
int nodeSize = nodeList.size(); int nodeSize = nodeList.size();
List<Long> childIdList = new ArrayList<>(); List<Long> childIdList = new ArrayList<>();
for(int i = 0; i < nodeSize; i++) { for (int i = 0; i < nodeSize; i++) {
int preIndex = i - 1; int preIndex = i - 1;
int nextIndex = i + 1; int nextIndex = i + 1;
DepartmentTreeVO node = nodeList.get(i); DepartmentTreeVO node = nodeList.get(i);
@ -161,39 +146,38 @@ public class DepartmentCacheManager {
} }
List<DepartmentTreeVO> children = getChildren(node.getDepartmentId(), allDepartmentList); List<DepartmentTreeVO> children = getChildren(node.getDepartmentId(), allDepartmentList);
List<Long> tempChildIdList = new ArrayList<>(); List<Long> tempChildIdList = new ArrayList<>();
if (CollectionUtils.isNotEmpty(children)) { if (CollectionUtils.isNotEmpty(children)) {
node.setChildren(children); node.setChildren(children);
tempChildIdList = this.recursiveBuildTree(children, allDepartmentList); tempChildIdList = this.recursiveBuildTree(children, allDepartmentList);
} }
if(CollectionUtils.isEmpty(node.getSelfAndAllChildrenIdList())) { if (CollectionUtils.isEmpty(node.getSelfAndAllChildrenIdList())) {
node.setSelfAndAllChildrenIdList( node.setSelfAndAllChildrenIdList(
new ArrayList<>() new ArrayList<>()
); );
} }
node.getSelfAndAllChildrenIdList().add(node.getDepartmentId()); node.getSelfAndAllChildrenIdList().add(node.getDepartmentId());
if(CollectionUtils.isNotEmpty(tempChildIdList)) { if (CollectionUtils.isNotEmpty(tempChildIdList)) {
node.getSelfAndAllChildrenIdList().addAll(tempChildIdList); node.getSelfAndAllChildrenIdList().addAll(tempChildIdList);
childIdList.addAll(tempChildIdList); childIdList.addAll(tempChildIdList);
} }
} }
// 保证本层遍历顺序 // 保证本层遍历顺序
for(int i = nodeSize - 1; i >= 0; i--) { for (int i = nodeSize - 1; i >= 0; i--) {
childIdList.add(0, nodeList.get(i).getDepartmentId()); childIdList.add(0, nodeList.get(i).getDepartmentId());
} }
return childIdList; return childIdList;
} }
/** /**
* 获取子元素 * 获取子元素
*
*/ */
private List<DepartmentTreeVO> getChildren(Long departmentId, List<DepartmentVO> voList) { private List<DepartmentTreeVO> getChildren(Long departmentId, List<DepartmentVO> voList) {
List<DepartmentVO> childrenEntityList = voList.stream().filter(e -> departmentId.equals(e.getParentId())).collect(Collectors.toList()); List<DepartmentVO> childrenEntityList = voList.stream().filter(e -> departmentId.equals(e.getParentId())).collect(Collectors.toList());
@ -206,7 +190,6 @@ public class DepartmentCacheManager {
/** /**
* 通过部门id,获取当前以及下属部门 * 通过部门id,获取当前以及下属部门
*
*/ */
public List<Long> selfAndChildrenIdList(Long departmentId, List<DepartmentVO> voList) { public List<Long> selfAndChildrenIdList(Long departmentId, List<DepartmentVO> voList) {
List<Long> selfAndChildrenIdList = Lists.newArrayList(); List<Long> selfAndChildrenIdList = Lists.newArrayList();

View File

@ -14,10 +14,7 @@ import net.lab1024.sa.base.common.util.SmartBeanUtil;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 部门 service * 部门 service
@ -26,7 +23,7 @@ import java.util.Map;
* @Date 2022-01-12 20:37:48 * @Date 2022-01-12 20:37:48
* @Wechat zhuoda1024 * @Wechat zhuoda1024
* @Email lab1024@163.com * @Email lab1024@163.com
* @Copyright <a href="https://1024lab.net">1024创新实验室</a> * @Copyright <a href="https://1024lab.net">1024创新实验室</a>
*/ */
@Service @Service
public class DepartmentService { public class DepartmentService {
@ -44,7 +41,6 @@ public class DepartmentService {
/** /**
* 新增添加部门 * 新增添加部门
*
*/ */
public ResponseDTO<String> addDepartment(DepartmentAddForm departmentAddForm) { public ResponseDTO<String> addDepartment(DepartmentAddForm departmentAddForm) {
@ -57,7 +53,6 @@ public class DepartmentService {
/** /**
* 更新部门信息 * 更新部门信息
*
*/ */
public ResponseDTO<String> updateDepartment(DepartmentUpdateForm updateDTO) { public ResponseDTO<String> updateDepartment(DepartmentUpdateForm updateDTO) {
if (updateDTO.getParentId() == null) { if (updateDTO.getParentId() == null) {
@ -78,7 +73,6 @@ public class DepartmentService {
* 根据id删除部门 * 根据id删除部门
* 1需要判断当前部门是否有子部门,有子部门则不允许删除 * 1需要判断当前部门是否有子部门,有子部门则不允许删除
* 2需要判断当前部门是否有员工有员工则不能删除 * 2需要判断当前部门是否有员工有员工则不能删除
*
*/ */
public ResponseDTO<String> deleteDepartment(Long departmentId) { public ResponseDTO<String> deleteDepartment(Long departmentId) {
DepartmentEntity departmentEntity = departmentDao.selectById(departmentId); DepartmentEntity departmentEntity = departmentDao.selectById(departmentId);
@ -122,7 +116,6 @@ public class DepartmentService {
/** /**
* 自身以及所有下级的部门id列表 * 自身以及所有下级的部门id列表
*
*/ */
public List<Long> selfAndChildrenIdList(Long departmentId) { public List<Long> selfAndChildrenIdList(Long departmentId) {
return departmentCacheManager.getDepartmentSelfAndChildren(departmentId); return departmentCacheManager.getDepartmentSelfAndChildren(departmentId);
@ -131,7 +124,6 @@ public class DepartmentService {
/** /**
* 获取所有部门 * 获取所有部门
*
*/ */
public List<DepartmentVO> listAll() { public List<DepartmentVO> listAll() {
return departmentCacheManager.getDepartmentList(); return departmentCacheManager.getDepartmentList();
@ -140,10 +132,9 @@ public class DepartmentService {
/** /**
* 获取部门 * 获取部门
*
*/ */
public DepartmentVO getDepartmentById(Long departmentId) { 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); 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;
}
} }

View File

@ -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.enumeration.UserTypeEnum;
import net.lab1024.sa.base.common.swagger.SchemaEnum; 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> * @Copyright <a href="https://1024lab.net">1024创新实验室</a>
*/ */
@Data @Data
public class RequestEmployee implements RequestUser { public class RequestEmployee implements RequestUser, Serializable {
@Schema(description = "员工id") @Schema(description = "员工id")
private Long employeeId; private Long employeeId;

View File

@ -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(){
}
}

View File

@ -6,7 +6,6 @@ import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import cn.hutool.extra.servlet.ServletUtil; import cn.hutool.extra.servlet.ServletUtil;
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO; 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.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.LoginForm;
import net.lab1024.sa.admin.module.system.login.domain.LoginResultVO; 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.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.menu.domain.vo.MenuVO;
import net.lab1024.sa.admin.module.system.role.domain.vo.RoleVO; 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.RoleEmployeeService;
@ -56,15 +56,16 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.*; import java.util.Collections;
import java.util.concurrent.ConcurrentMap; import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
* 登录 * 登录
* *
* @Author 1024创新实验室: 开云 * @Author 1024创新实验室: 卓大
* @Date 2021-12-01 22:56:34 * @Date 2025-05-03 22:56:34
* @Wechat zhuoda1024 * @Wechat zhuoda1024
* @Email lab1024@163.com * @Email lab1024@163.com
* @Copyright <a href="https://1024lab.net">1024创新实验室</a> * @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 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 @Resource
private EmployeeService employeeService; private EmployeeService employeeService;
@ -136,6 +121,9 @@ public class LoginService implements StpInterface {
@Resource @Resource
private RedisService redisService; private RedisService redisService;
@Resource
private LoginManager loginManager;
/** /**
* 获取验证码 * 获取验证码
*/ */
@ -226,10 +214,7 @@ public class LoginService implements StpInterface {
} }
// 获取员工信息 // 获取员工信息
RequestEmployee requestEmployee = loadLoginInfo(employeeEntity); RequestEmployee requestEmployee = loginManager.loadLoginInfo(employeeEntity);
// 放入缓存
loginEmployeeCache.put(employeeEntity.getEmployeeId(), requestEmployee);
// 移除登录失败 // 移除登录失败
securityLoginService.removeLoginFail(employeeEntity.getEmployeeId(), UserTypeEnum.ADMIN_EMPLOYEE); securityLoginService.removeLoginFail(employeeEntity.getEmployeeId(), UserTypeEnum.ADMIN_EMPLOYEE);
@ -244,8 +229,8 @@ public class LoginService implements StpInterface {
// 设置 token // 设置 token
loginResultVO.setToken(token); loginResultVO.setToken(token);
// 清除权限缓存 // 更新用户权限
permissionCache.remove(employeeEntity.getEmployeeId()); loginManager.loadUserPermission(employeeEntity.getEmployeeId());
return ResponseDTO.ok(loginResultVO); 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()); List<MenuVO> menuAndPointsList = roleMenuService.getMenuList(roleList.stream().map(RoleVO::getRoleId).collect(Collectors.toList()), requestEmployee.getAdministratorFlag());
loginResultVO.setMenuList(menuAndPointsList); 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); LoginLogVO loginLogVO = loginLogService.queryLastByUserId(requestEmployee.getEmployeeId(), UserTypeEnum.ADMIN_EMPLOYEE, LoginLogResultEnum.LOGIN_SUCCESS);
if (loginLogVO != null) { 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 获取员请求工信息 * 根据登陆token 获取员请求工信息
*/ */
@ -330,17 +285,7 @@ public class LoginService implements StpInterface {
return null; return null;
} }
RequestEmployee requestEmployee = loginEmployeeCache.get(requestEmployeeId); RequestEmployee requestEmployee = loginManager.getRequestEmployee(requestEmployeeId);
if (requestEmployee == null) {
// 员工基本信息
EmployeeEntity employeeEntity = employeeService.getById(requestEmployeeId);
if (employeeEntity == null) {
return null;
}
requestEmployee = this.loadLoginInfo(employeeEntity);
loginEmployeeCache.put(requestEmployeeId, requestEmployee);
}
// 更新请求ip和user agent // 更新请求ip和user agent
requestEmployee.setUserAgent(ServletUtil.getHeaderIgnoreCase(request, RequestHeaderConst.USER_AGENT)); requestEmployee.setUserAgent(ServletUtil.getHeaderIgnoreCase(request, RequestHeaderConst.USER_AGENT));
@ -384,7 +329,7 @@ public class LoginService implements StpInterface {
StpUtil.logout(); StpUtil.logout();
// 清空登录信息缓存 // 清空登录信息缓存
loginEmployeeCache.remove(requestUser.getUserId()); loginManager.clear();
//保存登出日志 //保存登出日志
LoginLogEntity loginEntity = LoginLogEntity.builder() LoginLogEntity loginEntity = LoginLogEntity.builder()
@ -402,14 +347,6 @@ public class LoginService implements StpInterface {
return ResponseDTO.ok(); return ResponseDTO.ok();
} }
/**
* 清除员工登录缓存
*/
public void clearLoginEmployeeCache(Long employeeId) {
// 清空登录信息缓存
loginEmployeeCache.remove(employeeId);
}
/** /**
* 保存登录日志 * 保存登录日志
*/ */
@ -437,12 +374,7 @@ public class LoginService implements StpInterface {
return Collections.emptyList(); return Collections.emptyList();
} }
UserPermission userPermission = permissionCache.get(employeeId); UserPermission userPermission = loginManager.getUserPermission(employeeId);
if (userPermission == null) {
userPermission = getUserPermission(employeeId);
permissionCache.put(employeeId, userPermission);
}
return userPermission.getPermissionList(); return userPermission.getPermissionList();
} }
@ -453,51 +385,10 @@ public class LoginService implements StpInterface {
return Collections.emptyList(); return Collections.emptyList();
} }
UserPermission userPermission = permissionCache.get(employeeId); UserPermission userPermission = loginManager.getUserPermission(employeeId);
if (userPermission == null) {
userPermission = getUserPermission(employeeId);
permissionCache.put(employeeId, userPermission);
}
return userPermission.getRoleList(); 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); String redisVerificationCodeKey = redisService.generateRedisKey(RedisKeyConst.Support.LOGIN_VERIFICATION_CODE, UserTypeEnum.ADMIN_EMPLOYEE.getValue() + RedisKeyConst.SEPARATOR + employeeId);
redisService.delete(redisVerificationCodeKey); redisService.delete(redisVerificationCodeKey);
} }
public void clearLoginEmployeeCache(Long employeeId) {
loginManager.clear();
}
} }

View File

@ -19,5 +19,16 @@
WHERE parent_id = #{departmentId} WHERE parent_id = #{departmentId}
</select> </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> </mapper>

View File

@ -2,6 +2,7 @@ package net.lab1024.sa.base.common.domain;
import lombok.Data; import lombok.Data;
import java.io.Serializable;
import java.util.List; import java.util.List;
/** /**
@ -15,7 +16,7 @@ import java.util.List;
*/ */
@Data @Data
public class UserPermission { public class UserPermission implements Serializable {
/** /**
* 权限列表 * 权限列表

View File

@ -1,11 +1,17 @@
package net.lab1024.sa.base.config; 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.CacheService;
import net.lab1024.sa.base.module.support.cache.CaffeineCacheServiceImpl; import net.lab1024.sa.base.module.support.cache.CaffeineCacheServiceImpl;
import net.lab1024.sa.base.module.support.cache.RedisCacheServiceImpl; import net.lab1024.sa.base.module.support.cache.RedisCacheServiceImpl;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; 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"; 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 @Bean
@ConditionalOnProperty(prefix = "spring.cache", name = {"type"}, havingValue = REDIS_CACHE) @ConditionalOnProperty(prefix = "spring.cache", name = {"type"}, havingValue = REDIS_CACHE)
public CacheService redisCacheService() { public CacheService redisCacheService() {

View File

@ -66,7 +66,7 @@ spring:
# 缓存实现类型 # 缓存实现类型
cache: cache:
type: caffeine type: redis
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误) # tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
server: server:
@ -88,8 +88,8 @@ file:
region: oss-cn-hangzhou region: oss-cn-hangzhou
endpoint: oss-cn-hangzhou.aliyuncs.com endpoint: oss-cn-hangzhou.aliyuncs.com
bucket-name: 1024lab-smart-admin bucket-name: 1024lab-smart-admin
access-key: access-key:
secret-key: secret-key:
url-prefix: https://${file.storage.cloud.bucket-name}.${file.storage.cloud.endpoint}/ url-prefix: https://${file.storage.cloud.bucket-name}.${file.storage.cloud.endpoint}/
private-url-expire-seconds: 3600 private-url-expire-seconds: 3600

View File

@ -66,7 +66,7 @@ spring:
# 缓存实现类型 # 缓存实现类型
cache: cache:
type: caffeine type: redis
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误) # tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
server: server:

View File

@ -65,7 +65,7 @@ spring:
# 缓存实现类型 # 缓存实现类型
cache: cache:
type: caffeine type: redis
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误) # tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
server: server:

View File

@ -66,7 +66,7 @@ spring:
# 缓存实现类型 # 缓存实现类型
cache: cache:
type: caffeine type: redis
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误) # tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
server: server:

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@ -8,7 +8,7 @@
const props = defineProps({ const props = defineProps({
dictCode: String, dictCode: String,
dataValue: String, dataValue: [String, Number],
}); });
const dataLabels = computed(() => { const dataLabels = computed(() => {
return useDictStore().getDataLabels(props.dictCode, props.dataValue); return useDictStore().getDataLabels(props.dictCode, props.dataValue);

View File

@ -1,6 +1,4 @@
import { defineStore } from 'pinia'; 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 { DICT_SPLIT } from '/@/constants/support/dict-const.js';
import _ from 'lodash'; import _ from 'lodash';
@ -23,14 +21,21 @@ export const useDictStore = defineStore({
// 获取字典的值名称 // 获取字典的值名称
getDataLabels(dictCode, dataValue) { getDataLabels(dictCode, dataValue) {
if (!dataValue) { if (_.isNil(dataValue) || _.isNaN(dataValue)) {
return ''; return '';
} }
let dict = this.getDictData(dictCode); let dict = this.getDictData(dictCode);
if (dict.length === 0) { if (dict.length === 0) {
return ''; return '';
} }
// 是数字的话,需要特殊处理
if(_.isNumber(dataValue)){
let target = _.find(dict, { dataValue: dataValue });
return target ? target.dataLabel : '';
}
let valueArray = dataValue.split(DICT_SPLIT); let valueArray = dataValue.split(DICT_SPLIT);
let result = []; let result = [];
for (let item of valueArray) { for (let item of valueArray) {
@ -42,7 +47,7 @@ export const useDictStore = defineStore({
return result.join(DICT_SPLIT); return result.join(DICT_SPLIT);
}, },
// 初始化字典 // 初始化字典
initData(dictDataList){ initData(dictDataList) {
this.dictMap.clear(); this.dictMap.clear();
for (let data of dictDataList) { for (let data of dictDataList) {
let dataArray = this.dictMap.get(data.dictCode); let dataArray = this.dictMap.get(data.dictCode);

View File

@ -495,40 +495,32 @@
function camelToUnderscore(str) { function camelToUnderscore(str) {
return str.replace(/([A-Z])/g, '_$1').toLowerCase(); return str.replace(/([A-Z])/g, '_$1').toLowerCase();
} }
// //
const yHeight = ref(0); const yHeight = ref(0);
onMounted(() => {
resetGetHeight();
});
function resetGetHeight() { function resetGetHeight() {
// //
let doc = document.querySelector('.ant-form'); let doc = document.querySelector('.ant-form');
// //
let btn = document.querySelector('.smart-table-btn-block'); let btn = document.querySelector('.smart-table-btn-block');
// //
let tableCell = document.querySelector('.ant-table-cell'); let tableCell = document.querySelector('.ant-table-cell');
// //
let page = document.querySelector('.smart-query-table-page'); let page = document.querySelector('.smart-query-table-page');
// //
let box = document.querySelector('.admin-content'); let box = document.querySelector('.admin-content');
setTimeout(() => { setTimeout(() => {
let dueHeight = doc.offsetHeight + 10 + 24 + btn.offsetHeight + 15 + tableCell.offsetHeight + page.offsetHeight + 20; let dueHeight = doc.offsetHeight + 10 + 24 + btn.offsetHeight + 15 + tableCell.offsetHeight + page.offsetHeight + 20;
yHeight.value = box.offsetHeight - dueHeight; yHeight.value = box.offsetHeight - dueHeight;
}, 100); }, 100);
} }
window.addEventListener(
// 'resize',
let throttledResizeHandler; _.throttle(() => {
onMounted(() => { resetGetHeight();
resetGetHeight(); }, 1000)
throttledResizeHandler = _.throttle(() => { );
resetGetHeight();
}, 1000);
window.addEventListener('resize', throttledResizeHandler);
});
// resize
onUnmounted(() => {
window.removeEventListener('resize', throttledResizeHandler);
});
</script> </script>

View File

@ -41,7 +41,7 @@
<a-table <a-table
size="small" size="small"
:scroll="{ y: 800 }" :scroll="{ x: 1000 }"
:loading="tableLoading" :loading="tableLoading"
bordered bordered
:dataSource="tableData" :dataSource="tableData"

View File

@ -1,5 +1,5 @@
<template> <template>
<a-modal v-model:open="visible" title="推送人" width="1100px" ok-text="确定" cancel-text="取消" @ok="onSubmit" @cancel="onClose" :zIndex="9999"> <a-modal v-model:open="visible" title="推送人" width="1100px" ok-text="确定" cancel-text="取消" @ok="onSubmit" @cancel="onClose" :zIndex="9999">
<a-form class="smart-query-form"> <a-form class="smart-query-form">
<a-row class="smart-query-form-row"> <a-row class="smart-query-form-row">
<a-form-item label="关键词搜索" class="smart-query-form-item"> <a-form-item label="关键词搜索" class="smart-query-form-item">
@ -56,11 +56,9 @@
<script setup> <script setup>
import { reactive, ref } from 'vue'; import { reactive, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { PAGE_SIZE, PAGE_SIZE_OPTIONS } from '/@/constants/common-const'; import { PAGE_SIZE, PAGE_SIZE_OPTIONS } from '/@/constants/common-const';
import { smartSentry } from '/@/lib/smart-sentry'; import { smartSentry } from '/@/lib/smart-sentry';
import { SmartLoading } from '/@/components/framework/smart-loading'; import { SmartLoading } from '/@/components/framework/smart-loading';
import SmartEnumSelect from '/@/components/framework/smart-enum-select/index.vue';
import { employeeApi } from '/@/api/system/employee-api'; import { employeeApi } from '/@/api/system/employee-api';
// ------------------------------- // -------------------------------
const queryParamState = { const queryParamState = {

View File

@ -54,11 +54,11 @@
</a-col> </a-col>
<!--待办已办--> <!--待办已办-->
<a-col :span="24"> <a-col :span="24">
<ToBeDoneCard /> <ChangelogCard />
</a-col> </a-col>
<!--更新日志--> <!--更新日志-->
<a-col :span="24"> <a-col :span="24">
<ChangelogCard /> <ToBeDoneCard />
</a-col> </a-col>
</a-row> </a-row>
</a-col> </a-col>

View File

@ -80,8 +80,7 @@
import { LOGIN_DEVICE_ENUM } from '/@/constants/system/login-device-const'; import { LOGIN_DEVICE_ENUM } from '/@/constants/system/login-device-const';
import { useUserStore } from '/@/store/modules/system/user'; import { useUserStore } from '/@/store/modules/system/user';
import loginQR from '/@/assets/images/login/login-qr.png'; 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-min.gif';
import loginGif from '/@/assets/images/login/login.gif';
import wechatIcon from '/@/assets/images/login/wechat-icon.png'; import wechatIcon from '/@/assets/images/login/wechat-icon.png';
import aliIcon from '/@/assets/images/login/ali-icon.png'; import aliIcon from '/@/assets/images/login/ali-icon.png';
import douyinIcon from '/@/assets/images/login/douyin-icon.png'; import douyinIcon from '/@/assets/images/login/douyin-icon.png';

View File

@ -12,11 +12,11 @@
<li v-for="module in props.tree" :key="module.menuId"> <li v-for="module in props.tree" :key="module.menuId">
<div class="menu" :style="{ marginLeft: `${props.index * 4}%` }"> <div class="menu" :style="{ marginLeft: `${props.index * 4}%` }">
<a-checkbox @change="selectCheckbox(module)" class="checked-box-label" :value="module.menuId">{{ module.menuName }} </a-checkbox> <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" /> <RoleTreePoint :tree="module.children" @selectCheckbox="selectCheckbox" />
</div> </div>
</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" /> <RoleTreeMenu :tree="module.children" :index="props.index + 1" />
</template> </template>
</li> </li>
@ -47,7 +47,7 @@
let checkedData = roleStore.checkedData; let checkedData = roleStore.checkedData;
let findIndex = checkedData.indexOf(module.menuId); let findIndex = checkedData.indexOf(module.menuId);
// //
if (findIndex == -1) { if (findIndex === -1) {
// //
roleStore.addCheckedDataAndChildren(module); roleStore.addCheckedDataAndChildren(module);
// //

View File

@ -43,18 +43,15 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { computed, h, useSlots } from 'vue'; import {computed, h} from 'vue';
import { messages } from '/@/i18n'; import {messages} from '/@/i18n';
import { useAppConfigStore } from '/@/store/modules/system/app-config'; import {useAppConfigStore} from '/@/store/modules/system/app-config';
import { useSpinStore } from '/@/store/modules/system/spin'; 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 {themeColors} from '/@/theme/color.js';
import { Popover } from 'ant-design-vue'; import SmartCopyIcon from '/@/components/framework/smart-copy-icon/index.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 antdLocale = computed(() => messages[useAppConfigStore().language].antdLocale);
const dayjsLocale = computed(() => messages[useAppConfigStore().language].dayjsLocale); const dayjsLocale = computed(() => messages[useAppConfigStore().language].dayjsLocale);
dayjs.locale(dayjsLocale); dayjs.locale(dayjsLocale);
@ -91,6 +88,7 @@
return text; return text;
} }
} }
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
:deep(.ant-table-column-sorters) { :deep(.ant-table-column-sorters) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@ -26,7 +26,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch, onMounted, getCurrentInstance} from 'vue'; import { ref, watch, onMounted, getCurrentInstance } from 'vue';
const props = defineProps({ const props = defineProps({
enumName: String, enumName: String,

View File

@ -8,7 +8,7 @@
const props = defineProps({ const props = defineProps({
dictCode: String, dictCode: String,
dataValue: String, dataValue: [String, Number],
}); });
const dataLabels = computed(() => { const dataLabels = computed(() => {
return useDictStore().getDataLabels(props.dictCode, props.dataValue); return useDictStore().getDataLabels(props.dictCode, props.dataValue);

View File

@ -7,13 +7,7 @@
* @Email: lab1024@163.com * @Email: lab1024@163.com
* @Copyright 1024 https://1024lab.net Since 2012 * @Copyright 1024 https://1024lab.net Since 2012
*/ */
import { AppConfig } from '/@/types/config'; export const appDefaultConfig = {
/**
*
*/
export const appDefaultConfig: AppConfig = {
// i18n 语言选择 // i18n 语言选择
language: 'zh_CN', language: 'zh_CN',
// 布局: side 或者 side-expand 或者 top // 布局: side 或者 side-expand 或者 top

View File

@ -208,9 +208,9 @@
// //
borderRadius: appConfigStore.borderRadius, borderRadius: appConfigStore.borderRadius,
// //
flatPattern: appConfigStore.flatPattern,
//
pageTagFlag: appConfigStore.pageTagFlag, pageTagFlag: appConfigStore.pageTagFlag,
//
flatPattern: appConfigStore.flatPattern,
// //
pageTagStyle: appConfigStore.pageTagStyle, pageTagStyle: appConfigStore.pageTagStyle,
// //
@ -251,7 +251,7 @@
}); });
} }
function changePageTagLocation(e: any) { function changePageTagLocation(e) {
appConfigStore.$patch({ appConfigStore.$patch({
pageTagLocation: e.target.value, pageTagLocation: e.target.value,
}); });

View File

@ -48,6 +48,7 @@
const menuTree = computed(() => useUserStore().getMenuTree || []); const menuTree = computed(() => useUserStore().getMenuTree || []);
const rootSubmenuKeys = computed(()=>menuTree.value.map(item=>item.menuId)); const rootSubmenuKeys = computed(()=>menuTree.value.map(item=>item.menuId));
// //
let currentRoute = useRoute(); let currentRoute = useRoute();
const selectedKeys = ref([]); const selectedKeys = ref([]);

View File

@ -1,6 +1,4 @@
import { defineStore } from 'pinia'; 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 { DICT_SPLIT } from '/@/constants/support/dict-const.js';
import _ from 'lodash'; import _ from 'lodash';
@ -23,14 +21,21 @@ export const useDictStore = defineStore({
// 获取字典的值名称 // 获取字典的值名称
getDataLabels(dictCode, dataValue) { getDataLabels(dictCode, dataValue) {
if (!dataValue) { if (_.isNil(dataValue) || _.isNaN(dataValue)) {
return ''; return '';
} }
let dict = this.getDictData(dictCode); let dict = this.getDictData(dictCode);
if (dict.length === 0) { if (dict.length === 0) {
return ''; return '';
} }
// 是数字的话,需要特殊处理
if(_.isNumber(dataValue)){
let target = _.find(dict, { dataValue: dataValue });
return target ? target.dataLabel : '';
}
let valueArray = dataValue.split(DICT_SPLIT); let valueArray = dataValue.split(DICT_SPLIT);
let result = []; let result = [];
for (let item of valueArray) { for (let item of valueArray) {
@ -42,7 +47,7 @@ export const useDictStore = defineStore({
return result.join(DICT_SPLIT); return result.join(DICT_SPLIT);
}, },
// 初始化字典 // 初始化字典
initData(dictDataList){ initData(dictDataList) {
this.dictMap.clear(); this.dictMap.clear();
for (let data of dictDataList) { for (let data of dictDataList) {
let dataArray = this.dictMap.get(data.dictCode); let dataArray = this.dictMap.get(data.dictCode);

View File

@ -36,7 +36,7 @@
</a-button> </a-button>
</a-button-group> </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> <template #icon>
<PlusOutlined /> <PlusOutlined />
</template> </template>
@ -60,8 +60,8 @@
</template> </template>
<template v-else-if="column.dataIndex === 'action'"> <template v-else-if="column.dataIndex === 'action'">
<div class="smart-table-operate"> <div class="smart-table-operate">
<a-button @click="addOrUpdate(record)" type="link" v-if="$privilege('oa:bank:update')">编辑</a-button> <a-button @click="addOrUpdate(record)" type="link">编辑</a-button>
<a-button @click="confirmDelete(record.bankId)" danger type="link" v-if="$privilege('oa:bank:delete')">删除</a-button> <a-button @click="confirmDelete(record.bankId)" danger type="link">删除</a-button>
</div> </div>
</template> </template>
</template> </template>

View File

@ -8,8 +8,8 @@
* @Copyright 1024创新实验室 https://1024lab.net Since 2012 * @Copyright 1024创新实验室 https://1024lab.net Since 2012
--> -->
<template> <template>
<a-modal :open="visible" :title="form.bankId ? '编辑' : '添加'" :width="700" ok-text="确认" cancel-text="取消" @ok="onSubmit" @cancel="onClose"> <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: 4 }" :wrapper-col="{ span: 19 }"> <a-form ref="formRef" :model="form" :rules="rules" :label-col="{ span: 5 }" :wrapper-col="{ span: 18 }">
<a-form-item label="开户银行" name="bankName"> <a-form-item label="开户银行" name="bankName">
<a-input v-model:value="form.bankName" placeholder="请输入开户银行" /> <a-input v-model:value="form.bankName" placeholder="请输入开户银行" />
</a-form-item> </a-form-item>

View File

@ -16,59 +16,50 @@
<a-button class="button-style" type="primary" @click="onSearch">搜索</a-button> <a-button class="button-style" type="primary" @click="onSearch">搜索</a-button>
<a-button class="button-style" type="default" @click="resetQueryEmployee">重置</a-button> <a-button class="button-style" type="default" @click="resetQueryEmployee">重置</a-button>
</div> </div>
<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" @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> <a-button class="button-style" type="primary" danger @click="batchDelete" v-privilege="'oa:enterprise:deleteEmployee'"> 批量移除 </a-button>
</div> </div>
</div> </div>
<a-card size="small" :bordered="false" :hoverable="false"> <a-table
<a-row justify="end"> :loading="tableLoading"
<TableOperator :dataSource="tableData"
class="smart-margin-bottom5" :columns="columns"
v-model="columns" :pagination="false"
:tableId="TABLE_ID_CONST.BUSINESS.OA.ENTERPRISE_EMPLOYEE" rowKey="employeeId"
:refresh="queryEmployee" :row-selection="{ selectedRowKeys: selectedRowKeyList, onChange: onSelectChange }"
/> size="small"
</a-row> bordered
<a-table >
:loading="tableLoading" <template #bodyCell="{ text, record, index, column }">
:dataSource="tableData" <template v-if="column.dataIndex === 'disabledFlag'">
:columns="columns" <a-tag :color="text ? 'error' : 'processing'">{{ text ? '禁用' : '启用' }}</a-tag>
:pagination="false"
rowKey="employeeId"
:row-selection="{ selectedRowKeys: selectedRowKeyList, onChange: onSelectChange }"
size="small"
bordered
>
<template #bodyCell="{ text, record, column }">
<template v-if="column.dataIndex === 'disabledFlag'">
<a-tag :color="text ? 'error' : 'processing'">{{ text ? '禁用' : '启用' }}</a-tag>
</template>
<template v-else-if="column.dataIndex === 'gender'">
<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>
</template>
</template> </template>
</a-table> <template v-else-if="column.dataIndex === 'gender'">
<div class="smart-query-table-page"> <span>{{ $smartEnumPlugin.getDescByValue('GENDER_ENUM', text) }}</span>
<a-pagination </template>
showSizeChanger <template v-if="column.dataIndex === 'operate'">
showQuickJumper <a @click="deleteEmployee(record.employeeId)" v-privilege="'oa:enterprise:deleteEmployee'">移除</a>
show-less-items </template>
:pageSizeOptions="PAGE_SIZE_OPTIONS" </template>
:defaultPageSize="queryForm.pageSize" </a-table>
v-model:current="queryForm.pageNum" <div class="smart-query-table-page">
v-model:pageSize="queryForm.pageSize" <a-pagination
:total="total" showSizeChanger
@change="queryEmployee" showQuickJumper
@showSizeChange="queryEmployee" show-less-items
:show-total="showTableTotal" :pageSizeOptions="PAGE_SIZE_OPTIONS"
/> :defaultPageSize="queryForm.pageSize"
</div> v-model:current="queryForm.pageNum"
<EmployeeTableSelectModal ref="selectEmployeeModal" @selectData="selectData" /> v-model:pageSize="queryForm.pageSize"
</a-card> :total="total"
@change="queryEmployee"
@showSizeChange="queryEmployee"
:show-total="showTableTotal"
/>
</div>
<EmployeeTableSelectModal ref="selectEmployeeModal" @selectData="selectData" />
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -81,8 +72,6 @@
import { SmartLoading } from '/@/components/framework/smart-loading'; import { SmartLoading } from '/@/components/framework/smart-loading';
import { PAGE_SIZE, PAGE_SIZE_OPTIONS, showTableTotal } from '/@/constants/common-const'; import { PAGE_SIZE, PAGE_SIZE_OPTIONS, showTableTotal } from '/@/constants/common-const';
import { smartSentry } from '/@/lib/smart-sentry'; 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({ const props = defineProps({
enterpriseId: { enterpriseId: {
@ -123,8 +112,7 @@
{ {
title: '操作', title: '操作',
dataIndex: 'operate', dataIndex: 'operate',
width: 90, width: 60,
align: 'center',
}, },
]); ]);
@ -283,8 +271,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding: 10px 10px; margin: 20px 0;
margin-bottom: 10px;
} }
.button-style { .button-style {

View File

@ -36,8 +36,7 @@
</a-button> </a-button>
</a-button-group> </a-button-group>
<a-button @click="addOrUpdate()" type="primary" class="smart-margin-left20">
<a-button @click="addOrUpdate()" type="primary" class="smart-margin-left20" v-if="$privilege('oa:invoice:add')">
<template #icon> <template #icon>
<PlusOutlined /> <PlusOutlined />
</template> </template>
@ -52,14 +51,14 @@
<TableOperator class="smart-margin-bottom5" v-model="columns" :tableId="TABLE_ID_CONST.BUSINESS.OA.ENTERPRISE_INVOICE" :refresh="ajaxQuery" /> <TableOperator class="smart-margin-bottom5" v-model="columns" :tableId="TABLE_ID_CONST.BUSINESS.OA.ENTERPRISE_INVOICE" :refresh="ajaxQuery" />
</a-row> </a-row>
<a-table :scroll="{ x: 1300 }" size="small" :dataSource="tableData" :columns="columns" rowKey="invoiceId" :pagination="false" bordered> <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'"> <template v-if="column.dataIndex === 'disabledFlag'">
{{ record.disabledFlag ? '禁用' : '启用' }} {{ record.disabledFlag ? '禁用' : '启用' }}
</template> </template>
<template v-else-if="column.dataIndex === 'action'"> <template v-else-if="column.dataIndex === 'action'">
<div class="smart-table-operate"> <div class="smart-table-operate">
<a-button @click="addOrUpdate(record)" type="link" v-if="$privilege('oa:invoice:update')">编辑</a-button> <a-button @click="addOrUpdate(record)" type="link">编辑</a-button>
<a-button @click="confirmDelete(record.invoiceId)" type="link" danger v-if="$privilege('oa:invoice:delete')">删除</a-button> <a-button @click="confirmDelete(record.invoiceId)" type="link" danger>删除</a-button>
</div> </div>
</template> </template>
</template> </template>

View File

@ -8,8 +8,8 @@
* @Copyright 1024创新实验室 https://1024lab.net Since 2012 * @Copyright 1024创新实验室 https://1024lab.net Since 2012
--> -->
<template> <template>
<a-modal :open="visible" :title="form.invoiceId ? '编辑' : '添加'" :width="700" ok-text="确认" cancel-text="取消" @ok="onSubmit" @cancel="onClose"> <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: 4 }" :wrapper-col="{ span: 19 }"> <a-form ref="formRef" :model="form" :rules="rules" :label-col="{ span: 5 }" :wrapper-col="{ span: 12 }">
<a-form-item label="开票抬头" name="invoiceHeads"> <a-form-item label="开票抬头" name="invoiceHeads">
<a-input v-model:value="form.invoiceHeads" placeholder="请输入开票抬头" /> <a-input v-model:value="form.invoiceHeads" placeholder="请输入开票抬头" />
</a-form-item> </a-form-item>

View File

@ -1,15 +1,6 @@
<template> <template>
<a-modal <a-modal :open="visible" title="添加" :width="700" forceRender ok-text="确认" cancel-text="取消" @ok="onSubmit" @cancel="onClose">
:open="visible" <a-form ref="formRef" :model="form" :rules="rules" :label-col="{ span: 6 }">
: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-form-item label="企业名称" name="enterpriseName"> <a-form-item label="企业名称" name="enterpriseName">
<a-input v-model:value="form.enterpriseName" placeholder="请输入企业名称" /> <a-input v-model:value="form.enterpriseName" placeholder="请输入企业名称" />
</a-form-item> </a-form-item>

View File

@ -41,7 +41,7 @@
<a-table <a-table
size="small" size="small"
:scroll="{ y: 800 }" :scroll="{ x: 1000 }"
:loading="tableLoading" :loading="tableLoading"
bordered bordered
:dataSource="tableData" :dataSource="tableData"

View File

@ -19,7 +19,7 @@
</a-form-item> </a-form-item>
<a-form-item label="备注" name="remark"> <a-form-item label="备注" name="remark">
<a-textarea v-model="form.remark" style="width: 100%; height: 100px; outline: none"/> <a-textarea v-model="form.remark" style="width: 100%; height: 100px; outline: none" />
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-modal> </a-modal>

View File

@ -45,13 +45,7 @@
新建 新建
</a-button> </a-button>
<a-button <a-button @click="confirmBatchDelete" v-privilege="'support:dict:delete'" type="primary" danger :disabled="selectedRowKeyList.length === 0">
@click="confirmBatchDelete"
v-privilege="'support:dict:delete'"
type="primary"
danger
:disabled="selectedRowKeyList.length === 0"
>
<template #icon> <template #icon>
<DeleteOutlined /> <DeleteOutlined />
</template> </template>

View File

@ -1,5 +1,5 @@
<template> <template>
<a-modal v-model:open="visible" title="推送人" width="1100px" ok-text="确定" cancel-text="取消" @ok="onSubmit" @cancel="onClose" :zIndex="9999"> <a-modal v-model:open="visible" title="推送人" width="1100px" ok-text="确定" cancel-text="取消" @ok="onSubmit" @cancel="onClose" :zIndex="9999">
<a-form class="smart-query-form"> <a-form class="smart-query-form">
<a-row class="smart-query-form-row"> <a-row class="smart-query-form-row">
<a-form-item label="关键词搜索" class="smart-query-form-item"> <a-form-item label="关键词搜索" class="smart-query-form-item">
@ -54,13 +54,11 @@
</a-modal> </a-modal>
</template> </template>
<script setup> <script setup lang="ts">
import { reactive, ref } from 'vue'; import { reactive, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { PAGE_SIZE, PAGE_SIZE_OPTIONS } from '/@/constants/common-const'; import { PAGE_SIZE, PAGE_SIZE_OPTIONS } from '/@/constants/common-const';
import { smartSentry } from '/@/lib/smart-sentry'; import { smartSentry } from '/@/lib/smart-sentry';
import { SmartLoading } from '/@/components/framework/smart-loading'; import { SmartLoading } from '/@/components/framework/smart-loading';
import SmartEnumSelect from '/@/components/framework/smart-enum-select/index.vue';
import { employeeApi } from '/@/api/system/employee-api'; import { employeeApi } from '/@/api/system/employee-api';
// ------------------------------- // -------------------------------
const queryParamState = { const queryParamState = {

View File

@ -24,7 +24,7 @@
</a-modal> </a-modal>
<MessageReceiverModal ref="receiverModalRef" @reloadList="addReceiverIdList" /> <MessageReceiverModal ref="receiverModalRef" @reloadList="addReceiverIdList" />
</template> </template>
<script setup> <script setup lang="ts">
import { nextTick, reactive, ref } from 'vue'; import { nextTick, reactive, ref } from 'vue';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import { SmartLoading } from '/@/components/framework/smart-loading'; import { SmartLoading } from '/@/components/framework/smart-loading';

View File

@ -86,7 +86,7 @@
<MessageSendForm ref="formRef" @reloadList="queryData" /> <MessageSendForm ref="formRef" @reloadList="queryData" />
</a-card> </a-card>
</template> </template>
<script setup> <script setup lang="ts">
import { onMounted, reactive, ref } from 'vue'; import { onMounted, reactive, ref } from 'vue';
import { message, Modal } from 'ant-design-vue'; import { message, Modal } from 'ant-design-vue';
import { SmartLoading } from '/@/components/framework/smart-loading'; import { SmartLoading } from '/@/components/framework/smart-loading';

View File

@ -54,11 +54,11 @@
</a-col> </a-col>
<!--待办已办--> <!--待办已办-->
<a-col :span="24"> <a-col :span="24">
<ToBeDoneCard /> <ChangelogCard />
</a-col> </a-col>
<!--更新日志--> <!--更新日志-->
<a-col :span="24"> <a-col :span="24">
<ChangelogCard /> <ToBeDoneCard />
</a-col> </a-col>
</a-row> </a-row>
</a-col> </a-col>

View File

@ -80,8 +80,7 @@
import { LOGIN_DEVICE_ENUM } from '/@/constants/system/login-device-const'; import { LOGIN_DEVICE_ENUM } from '/@/constants/system/login-device-const';
import { useUserStore } from '/@/store/modules/system/user'; import { useUserStore } from '/@/store/modules/system/user';
import loginQR from '/@/assets/images/login/login-qr.png'; 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-min.gif';
import loginGif from '/@/assets/images/login/login.gif';
import wechatIcon from '/@/assets/images/login/wechat-icon.png'; import wechatIcon from '/@/assets/images/login/wechat-icon.png';
import aliIcon from '/@/assets/images/login/ali-icon.png'; import aliIcon from '/@/assets/images/login/ali-icon.png';
import douyinIcon from '/@/assets/images/login/douyin-icon.png'; import douyinIcon from '/@/assets/images/login/douyin-icon.png';

View File

@ -17,7 +17,7 @@
@close="onClose" @close="onClose"
destroyOnClose 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-form-item label="菜单类型" name="menuType">
<a-radio-group v-model:value="form.menuType" button-style="solid"> <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"> <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-switch v-model:checked="form.visibleFlag" checked-children="显示" un-checked-children="不显示" />
</a-form-item> </a-form-item>
<a-form-item label="禁用状态" name="disabledFlag"> <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> </a-form-item>
</template> </template>
<!-- 目录 菜单 end --> <!-- 目录 菜单 end -->
@ -75,7 +81,13 @@
<MenuTreeSelect ref="contextMenuTreeSelect" v-model:value="form.contextMenuId" /> <MenuTreeSelect ref="contextMenuTreeSelect" v-model:value="form.contextMenuId" />
</a-form-item> </a-form-item>
<a-form-item label="功能点状态" name="funcDisabledFlag"> <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>
<a-form-item label="权限类型" name="permsType"> <a-form-item label="权限类型" name="permsType">
<a-radio-group v-model:value="form.permsType"> <a-radio-group v-model:value="form.permsType">
@ -106,7 +118,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import _ from 'lodash'; import _ from 'lodash';
import { computed, nextTick, reactive, ref } from 'vue'; import { nextTick, reactive, ref } from 'vue';
import MenuTreeSelect from './menu-tree-select.vue'; import MenuTreeSelect from './menu-tree-select.vue';
import { menuApi } from '/@/api/system/menu-api'; import { menuApi } from '/@/api/system/menu-api';
import IconSelect from '/@/components/framework/icon-select/index.vue'; import IconSelect from '/@/components/framework/icon-select/index.vue';
@ -123,13 +135,6 @@
// //
const visible = ref(false); const visible = ref(false);
const labelColSpan = computed(() => {
if (form.menuType === MENU_TYPE_ENUM.POINTS.value) {
return 6;
}
return 4;
});
const contextMenuTreeSelect = ref(); const contextMenuTreeSelect = ref();
const parentMenuTreeSelect = ref(); const parentMenuTreeSelect = ref();
@ -179,7 +184,7 @@
apiPerms: undefined, apiPerms: undefined,
sort: undefined, sort: undefined,
visibleFlag: true, visibleFlag: true,
cacheFlag: true, cacheFlag: false,
component: undefined, component: undefined,
contextMenuId: undefined, contextMenuId: undefined,
disabledFlag: false, disabledFlag: false,
@ -197,6 +202,9 @@
formRef.value.resetFields(); formRef.value.resetFields();
form.menuType = menuType; form.menuType = menuType;
form.parentId = parentId; form.parentId = parentId;
if (form.menuType === MENU_TYPE_ENUM.POINTS.value) {
form.contextMenuId = parentId;
}
// //
if (webPerms && webPerms.lastIndexOf(':')) { if (webPerms && webPerms.lastIndexOf(':')) {
form.webPerms = webPerms.substring(0, webPerms.lastIndexOf(':') + 1); form.webPerms = webPerms.substring(0, webPerms.lastIndexOf(':') + 1);

View File

@ -126,7 +126,7 @@ function isMenuExistMenuType(menu, menuType) {
/** /**
* *
*/ */
function isMenuExistKeywords(menu: any, keywords: string) { function isMenuExistKeywords(menu, keywords) {
if (!keywords) { if (!keywords) {
return true; return true;
} }

View File

@ -266,7 +266,7 @@
function showDrawer(rowData) { function showDrawer(rowData) {
menuOperateModal.value.showDrawer(rowData); menuOperateModal.value.showDrawer(rowData);
} }
function showAddSub(rowData) { function showAddSub(rowData) {
const subData = { const subData = {
parentId: rowData.menuId, parentId: rowData.menuId,

View File

@ -12,11 +12,11 @@
<li v-for="module in props.tree" :key="module.menuId"> <li v-for="module in props.tree" :key="module.menuId">
<div class="menu" :style="{ marginLeft: `${props.index * 4}%` }"> <div class="menu" :style="{ marginLeft: `${props.index * 4}%` }">
<a-checkbox @change="selectCheckbox(module)" class="checked-box-label" :value="module.menuId">{{ module.menuName }} </a-checkbox> <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" /> <RoleTreePoint :tree="module.children" @selectCheckbox="selectCheckbox" />
</div> </div>
</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" /> <RoleTreeMenu :tree="module.children" :index="props.index + 1" />
</template> </template>
</li> </li>
@ -47,7 +47,7 @@
let checkedData = roleStore.checkedData; let checkedData = roleStore.checkedData;
let findIndex = checkedData.indexOf(module.menuId); let findIndex = checkedData.indexOf(module.menuId);
// //
if (findIndex == -1) { if (findIndex === -1) {
// //
roleStore.addCheckedDataAndChildren(module); roleStore.addCheckedDataAndChildren(module);
// //