🐛 fix 组织机构移动时层级和深度更新错误的问题 & 使用 sharding-jdbc 时无法正确处理 sql 的问题
✨ 新增组织机构层级和深度校正接口
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
package com.hccake.ballcat.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.hccake.ballcat.system.model.dto.OrganizationMoveChildParam;
|
||||
import com.hccake.ballcat.system.model.entity.SysOrganization;
|
||||
import com.hccake.ballcat.system.model.qo.SysOrganizationQO;
|
||||
import com.hccake.extend.mybatis.plus.conditions.query.LambdaQueryWrapperX;
|
||||
@@ -37,12 +39,9 @@ public interface SysOrganizationMapper extends ExtendMapper<SysOrganization> {
|
||||
|
||||
/**
|
||||
* 跟随父节点移动子节点
|
||||
* @param originHierarchy 原始父级层级
|
||||
* @param targetHierarchy 移动后的父级层级
|
||||
* @param depthDiff 移动的深度差
|
||||
* @param param OrganizationMoveChildParam 跟随移动子节点的参数对象
|
||||
*/
|
||||
void followMoveChildNode(@Param("originHierarchy") String originHierarchy,
|
||||
@Param("targetHierarchy") String targetHierarchy, @Param("depthDiff") int depthDiff);
|
||||
void followMoveChildNode(@Param("param") OrganizationMoveChildParam param);
|
||||
|
||||
/**
|
||||
* 根据组织机构Id,查询该组织下的所有子部门
|
||||
@@ -51,4 +50,18 @@ public interface SysOrganizationMapper extends ExtendMapper<SysOrganization> {
|
||||
*/
|
||||
List<SysOrganization> listChildOrganization(@Param("organizationId") Integer organizationId);
|
||||
|
||||
/**
|
||||
* 批量更新节点层级和深度
|
||||
* @param depth 深度
|
||||
* @param hierarchy 层级
|
||||
* @param organizationIds 组织id集合
|
||||
*/
|
||||
default void updateHierarchyAndPathBatch(int depth, String hierarchy, List<Integer> organizationIds) {
|
||||
LambdaUpdateWrapper<SysOrganization> wrapper = Wrappers.lambdaUpdate(SysOrganization.class)
|
||||
.set(SysOrganization::getDepth, depth).set(SysOrganization::getHierarchy, hierarchy)
|
||||
.in(SysOrganization::getId, organizationIds);
|
||||
this.update(null, wrapper);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -50,4 +50,10 @@ public interface SysOrganizationService extends ExtendService<SysOrganization> {
|
||||
*/
|
||||
List<SysOrganization> listChildOrganization(Integer organizationId);
|
||||
|
||||
/**
|
||||
* 校正组织机构层级和深度
|
||||
* @return 校正是否成功
|
||||
*/
|
||||
boolean revisedHierarchyAndPath();
|
||||
|
||||
}
|
||||
@@ -3,24 +3,29 @@ package com.hccake.ballcat.system.service.impl;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
|
||||
import com.hccake.ballcat.common.core.constant.GlobalConstants;
|
||||
import com.hccake.ballcat.common.core.exception.BusinessException;
|
||||
import com.hccake.ballcat.common.model.result.BaseResultCode;
|
||||
import com.hccake.ballcat.common.util.TreeUtils;
|
||||
import com.hccake.ballcat.system.converter.SysOrganizationConverter;
|
||||
import com.hccake.ballcat.system.mapper.SysOrganizationMapper;
|
||||
import com.hccake.ballcat.system.model.dto.OrganizationMoveChildParam;
|
||||
import com.hccake.ballcat.system.model.dto.SysOrganizationDTO;
|
||||
import com.hccake.ballcat.system.model.entity.SysOrganization;
|
||||
import com.hccake.ballcat.system.model.qo.SysOrganizationQO;
|
||||
import com.hccake.ballcat.system.model.vo.SysOrganizationTree;
|
||||
import com.hccake.ballcat.system.service.SysOrganizationService;
|
||||
import com.hccake.ballcat.common.core.constant.GlobalConstants;
|
||||
import com.hccake.ballcat.common.core.exception.BusinessException;
|
||||
import com.hccake.ballcat.common.model.result.BaseResultCode;
|
||||
import com.hccake.ballcat.common.util.TreeUtils;
|
||||
import com.hccake.extend.mybatis.plus.service.impl.ExtendServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 组织架构
|
||||
@@ -69,14 +74,14 @@ public class SysOrganizationServiceImpl extends ExtendServiceImpl<SysOrganizatio
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean update(SysOrganizationDTO sysOrganizationDTO) {
|
||||
// TODO 防止并发问题
|
||||
SysOrganization sysOrganization = SysOrganizationConverter.INSTANCE.dtoToPo(sysOrganizationDTO);
|
||||
Integer organizationId = sysOrganization.getId();
|
||||
SysOrganization newSysOrganization = SysOrganizationConverter.INSTANCE.dtoToPo(sysOrganizationDTO);
|
||||
Integer organizationId = newSysOrganization.getId();
|
||||
SysOrganization originSysOrganization = baseMapper.selectById(organizationId);
|
||||
|
||||
// 如果没有移动父节点,则直接更新
|
||||
Integer targetParentId = sysOrganizationDTO.getParentId();
|
||||
if (originSysOrganization.getParentId().equals(targetParentId)) {
|
||||
return SqlHelper.retBool(baseMapper.updateById(sysOrganization));
|
||||
return SqlHelper.retBool(baseMapper.updateById(newSysOrganization));
|
||||
}
|
||||
|
||||
// 移动了父节点,先判断不是选择自己作为父节点
|
||||
@@ -91,16 +96,33 @@ public class SysOrganizationServiceImpl extends ExtendServiceImpl<SysOrganizatio
|
||||
}
|
||||
|
||||
// 填充目标层级和深度
|
||||
fillDepthAndHierarchy(sysOrganization, targetParentId);
|
||||
// 原来的层级和深度
|
||||
String originHierarchy = originSysOrganization.getHierarchy();
|
||||
int originDepth = originSysOrganization.getDepth();
|
||||
// 计算出更换父节点后的层级和深度
|
||||
int depthDiff = originDepth - sysOrganization.getDepth();
|
||||
fillDepthAndHierarchy(newSysOrganization, targetParentId);
|
||||
// 更新其子节点的数据
|
||||
baseMapper.followMoveChildNode(originHierarchy, sysOrganization.getHierarchy(), depthDiff);
|
||||
OrganizationMoveChildParam param = getOrganizationMoveChildParam(newSysOrganization, originSysOrganization);
|
||||
baseMapper.followMoveChildNode(param);
|
||||
// 更新组织节点信息
|
||||
return SqlHelper.retBool(baseMapper.updateById(newSysOrganization));
|
||||
}
|
||||
|
||||
return SqlHelper.retBool(baseMapper.updateById(sysOrganization));
|
||||
private OrganizationMoveChildParam getOrganizationMoveChildParam(SysOrganization newSysOrganization,
|
||||
SysOrganization originSysOrganization) {
|
||||
// 父组织 id
|
||||
Integer parentId = newSysOrganization.getId();
|
||||
// 父节点原来的层级
|
||||
String originParentHierarchy = originSysOrganization.getHierarchy();
|
||||
// 修改后的父节点层级
|
||||
String targetParentHierarchy = newSysOrganization.getHierarchy();
|
||||
// 父节点移动后的深度差
|
||||
int depthDiff = originSysOrganization.getDepth() - newSysOrganization.getDepth();
|
||||
|
||||
OrganizationMoveChildParam param = new OrganizationMoveChildParam();
|
||||
param.setParentId(parentId);
|
||||
param.setOriginParentHierarchy(originParentHierarchy);
|
||||
param.setOriginParentHierarchyLengthPlusOne(originParentHierarchy.length() + 1);
|
||||
param.setTargetParentHierarchy(targetParentHierarchy);
|
||||
param.setDepthDiff(depthDiff);
|
||||
param.setGrandsonConditionalStatement(originParentHierarchy + "-" + parentId + "-%");
|
||||
return param;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,6 +145,43 @@ public class SysOrganizationServiceImpl extends ExtendServiceImpl<SysOrganizatio
|
||||
return baseMapper.listChildOrganization(organizationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校正组织机构层级和深度
|
||||
* @return 校正是否成功
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean revisedHierarchyAndPath() {
|
||||
// 组织机构一般数据量不多,一次性查询出来缓存到内存中,减少查询开销
|
||||
List<SysOrganization> sysOrganizations = baseMapper.selectList(Wrappers.emptyWrapper());
|
||||
Map<Integer, List<SysOrganization>> map = sysOrganizations.stream()
|
||||
.collect(Collectors.groupingBy(SysOrganization::getParentId));
|
||||
// 默认的父节点为根节点,
|
||||
Integer parentId = GlobalConstants.TREE_ROOT_ID;
|
||||
int depth = 1;
|
||||
String hierarchy = "0";
|
||||
updateChildHierarchyAndPath(map, parentId, depth, hierarchy);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updateChildHierarchyAndPath(Map<Integer, List<SysOrganization>> map, Integer parentId, int depth,
|
||||
String hierarchy) {
|
||||
// 获取对应 parentId 下的所有子节点
|
||||
List<SysOrganization> sysOrganizations = map.get(parentId);
|
||||
if (CollectionUtil.isEmpty(sysOrganizations)) {
|
||||
return;
|
||||
}
|
||||
// 递归更新子节点数据
|
||||
List<Integer> childrenIds = new ArrayList<>();
|
||||
for (SysOrganization sysOrganization : sysOrganizations) {
|
||||
Integer organizationId = sysOrganization.getId();
|
||||
updateChildHierarchyAndPath(map, organizationId, depth + 1, hierarchy + "-" + organizationId);
|
||||
childrenIds.add(organizationId);
|
||||
}
|
||||
baseMapper.updateHierarchyAndPathBatch(depth, hierarchy, childrenIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据组织ID 删除组织机构
|
||||
* @param organizationId 组织机构ID
|
||||
|
||||
@@ -16,14 +16,16 @@
|
||||
update_time
|
||||
</sql>
|
||||
|
||||
<!-- 这里为了兼容 shardingsphare 4.x 暂时使用 ${} 传参-->
|
||||
<update id="followMoveChildNode">
|
||||
UPDATE
|
||||
sys_organization
|
||||
SET hierarchy =
|
||||
CONCAT(#{targetHierarchy}, SUBSTR(hierarchy, LENGTH(#{originHierarchy}) + 1)),
|
||||
depth = depth - #{depthDiff}
|
||||
SET hierarchy = CONCAT(#{param.targetParentHierarchy}, SUBSTR(hierarchy, ${param.originParentHierarchyLengthPlusOne})),
|
||||
depth = depth - #{param.depthDiff}
|
||||
WHERE
|
||||
hierarchy like CONCAT(#{originHierarchy}, "-%")
|
||||
parent_id = #{param.parentId} -- 儿子节点
|
||||
or
|
||||
hierarchy like #{param.grandsonConditionalStatement} -- 孙子节点
|
||||
</update>
|
||||
|
||||
<select id="listChildOrganization" resultType="com.hccake.ballcat.system.model.entity.SysOrganization">
|
||||
|
||||
@@ -13,14 +13,7 @@ import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -42,7 +35,7 @@ public class SysOrganizationController {
|
||||
* @param qo 组织机构查询条件
|
||||
* @return R 通用返回体
|
||||
*/
|
||||
@ApiOperation(value = "组织架构树查询", notes = "组织架构树查询")
|
||||
@ApiOperation(value = "组织架构树查询")
|
||||
@GetMapping("/tree")
|
||||
@PreAuthorize("@per.hasPermission('system:organization:read')")
|
||||
public R<List<SysOrganizationTree>> getOrganizationTree(SysOrganizationQO qo) {
|
||||
@@ -54,7 +47,7 @@ public class SysOrganizationController {
|
||||
* @param sysOrganizationDTO 组织机构DTO
|
||||
* @return R 通用返回体
|
||||
*/
|
||||
@ApiOperation(value = "新增组织架构", notes = "新增组织架构")
|
||||
@ApiOperation(value = "新增组织架构")
|
||||
@CreateOperationLogging(msg = "新增组织架构")
|
||||
@PostMapping
|
||||
@PreAuthorize("@per.hasPermission('system:organization:add')")
|
||||
@@ -68,7 +61,7 @@ public class SysOrganizationController {
|
||||
* @param sysOrganizationDTO 组织机构DTO
|
||||
* @return R 通用返回体
|
||||
*/
|
||||
@ApiOperation(value = "修改组织架构", notes = "修改组织架构")
|
||||
@ApiOperation(value = "修改组织架构")
|
||||
@UpdateOperationLogging(msg = "修改组织架构")
|
||||
@PutMapping
|
||||
@PreAuthorize("@per.hasPermission('system:organization:edit')")
|
||||
@@ -82,7 +75,7 @@ public class SysOrganizationController {
|
||||
* @param id id
|
||||
* @return R 通用返回体
|
||||
*/
|
||||
@ApiOperation(value = "通过id删除组织架构", notes = "通过id删除组织架构")
|
||||
@ApiOperation(value = "通过id删除组织架构")
|
||||
@DeleteOperationLogging(msg = "通过id删除组织架构")
|
||||
@DeleteMapping("/{id}")
|
||||
@PreAuthorize("@per.hasPermission('system:organization:del')")
|
||||
@@ -91,4 +84,17 @@ public class SysOrganizationController {
|
||||
: R.failed(BaseResultCode.UPDATE_DATABASE_ERROR, "通过id删除组织架构失败");
|
||||
}
|
||||
|
||||
/**
|
||||
* 校正组织机构层级和深度
|
||||
* @return R 通用返回体
|
||||
*/
|
||||
@ApiOperation(value = "校正组织机构层级和深度")
|
||||
@UpdateOperationLogging(msg = "校正组织机构层级和深度")
|
||||
@PatchMapping("/revised")
|
||||
@PreAuthorize("@per.hasPermission('system:organization:revised')")
|
||||
public R<?> revisedHierarchyAndPath() {
|
||||
return sysOrganizationService.revisedHierarchyAndPath() ? R.ok()
|
||||
: R.failed(BaseResultCode.UPDATE_DATABASE_ERROR, "校正组织机构层级和深度失败");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.hccake.ballcat.system.model.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 组织机构移动子节点时的参数封装对象
|
||||
*
|
||||
* @author hccake
|
||||
*/
|
||||
@Data
|
||||
public class OrganizationMoveChildParam {
|
||||
|
||||
/**
|
||||
* 父级id
|
||||
*/
|
||||
private Integer parentId;
|
||||
|
||||
/**
|
||||
* 父级节点原始的层级信息
|
||||
*/
|
||||
private String originParentHierarchy;
|
||||
|
||||
/**
|
||||
* 父级节点原始的层级信息长度 + 1
|
||||
*/
|
||||
private int originParentHierarchyLengthPlusOne;
|
||||
|
||||
/**
|
||||
* 父级节点移动后的层级信息
|
||||
*/
|
||||
private String targetParentHierarchy;
|
||||
|
||||
/**
|
||||
* 移动前后的节点深度差
|
||||
*/
|
||||
private Integer depthDiff;
|
||||
|
||||
/**
|
||||
* 查询孙子节点的条件语句
|
||||
*/
|
||||
private String grandsonConditionalStatement;
|
||||
|
||||
}
|
||||
@@ -169,4 +169,7 @@ UPDATE `sys_menu` SET `title` = '访问日志查询' WHERE `id` = 110301;
|
||||
|
||||
RENAME TABLE `admin_access_log` TO `log_access_log`;
|
||||
RENAME TABLE `admin_operation_log` TO `log_operation_log`;
|
||||
RENAME TABLE `admin_login_log` TO `log_login_log`;
|
||||
RENAME TABLE `admin_login_log` TO `log_login_log`;
|
||||
|
||||
-- 添加组织机构校正功能
|
||||
INSERT INTO `sys_menu` (`id`, `parent_id`, `title`, `icon`, `permission`, `path`, `target_type`, `uri`, `sort`, `keep_alive`, `hidden`, `type`, `remarks`, `deleted`, `create_time`, `update_time`) VALUES (100705, 100700, '组织机构校正', NULL, 'system:organization:revised', NULL, 1, '', 5, 0, 0, 2, '校正组织机构层级和深度', 0, '2021-06-22 21:54:19', NULL);
|
||||
|
||||
Reference in New Issue
Block a user