update:调整数据同步用户-部门,用户-岗位同步逻辑

This commit is contained in:
hewencai
2025-12-24 10:36:00 +08:00
parent 1ac2f1e2cc
commit 9485d94574
28 changed files with 453 additions and 78 deletions

View File

@@ -86,4 +86,10 @@ public interface DeptApi {
@Parameter(name = "userId", description = "用户编号", example = "1", required = true)
CommonResult<Set<CompanyDeptInfoRespDTO>> getCompanyDeptInfoListByUserId(@RequestParam("userId") Long userId);
// ========== 数据同步专用接口 ==========
@PostMapping(PREFIX + "/sync")
@Operation(summary = "同步部门")
CommonResult<Boolean> syncDept(@RequestBody DeptSaveReqDTO syncReqDTO);
}

View File

@@ -64,4 +64,10 @@ public interface PostApi {
return CollectionUtils.convertMap(list, PostRespDTO::getId);
}
// ========== 数据同步专用接口 ==========
@PostMapping(PREFIX + "/sync")
@Operation(summary = "同步岗位")
CommonResult<Boolean> syncPost(@RequestBody PostSaveReqDTO syncReqDTO);
}

View File

@@ -15,9 +15,15 @@ public class DeptSaveReqDTO {
@Schema(description = "部门编号", example = "1024")
private Long id;
@Schema(description = "部门编码", example = "ZT001")
private String code;
@Schema(description = "部门名称", example = "ZT")
private String name;
@Schema(description = "部门简称", example = "技术")
private String shortName;
@Schema(description = "父部门 ID", example = "1024")
private Long parentId;
@@ -36,6 +42,15 @@ public class DeptSaveReqDTO {
@Schema(description = "状态,见 CommonStatusEnum 枚举0 开启 1 关闭", example = "0")
private Integer status;
@Schema(description = "是否集团", example = "false")
private Boolean isGroup;
@Schema(description = "是否公司", example = "false")
private Boolean isCompany;
@Schema(description = "部门来源类型", example = "1")
private Integer deptSource;
@Schema(description = "外部系统标识,用于建立编码映射", example = "ERP")
private String externalSystemCode;

View File

@@ -104,6 +104,12 @@ public interface AdminUserApi extends AutoTransable<AdminUserRespDTO> {
@Parameter(name = "ids", description = "用户编号数组", example = "3,5", required = true)
CommonResult<Boolean> validateUserList(@RequestParam("ids") Collection<Long> ids);
// ========== 数据同步专用接口 ==========
@PostMapping(PREFIX + "/sync")
@Operation(summary = "同步用户")
CommonResult<Boolean> syncUser(@RequestBody AdminUserSaveReqDTO syncReqDTO);
@Override
@FeignIgnore
default List<AdminUserRespDTO> selectByIds(List<?> ids) {

View File

@@ -50,4 +50,10 @@ public class AdminUserSaveReqDTO {
@Schema(description = "密码", example = "123456")
private String password;
@Schema(description = "工号", example = "A00123")
private String workcode;
@Schema(description = "用户来源类型", example = "1")
private Integer userSource;
}

View File

@@ -61,4 +61,10 @@ public interface UserDeptApi {
@Operation(summary = "通过部门ID删除用户部门关系")
@Parameter(name = "deptId", description = "部门编号", example = "1", required = true)
CommonResult<Boolean> deleteUserDeptByDeptId(@RequestParam("deptId") Long deptId);
// ========== 数据同步专用接口 ==========
@PostMapping(PREFIX + "/sync")
@Operation(summary = "同步用户部门关系")
CommonResult<Boolean> syncUserDept(@RequestBody UserDeptSaveReqDTO syncReqDTO);
}

View File

@@ -61,4 +61,10 @@ public interface UserPostApi {
@Operation(summary = "通过岗位ID删除用户岗位关系")
@Parameter(name = "postId", description = "岗位编号", example = "1", required = true)
CommonResult<Boolean> deleteUserPostByPostId(@RequestParam("postId") Long postId);
// ========== 数据同步专用接口 ==========
@PostMapping(PREFIX + "/sync")
@Operation(summary = "同步用户岗位关系")
CommonResult<Boolean> syncUserPost(@RequestBody UserPostSaveReqDTO syncReqDTO);
}

View File

@@ -38,7 +38,7 @@ public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderAp
// 多查一条判断是否有更多数据
int limit = reqDTO.getBatchSize() != null ? reqDTO.getBatchSize() : 100;
// ⚠️ 使用关联查询,只查询 userSource = 2 的用户部门关系
// 查询用户部门关系
List<UserDeptDO> list = userDeptMapper.selectPageByCursorWithUserSource(
reqDTO.isFirstPage() ? null : reqDTO.getCursorTime(),
reqDTO.isFirstPage() ? null : reqDTO.getCursorId(),
@@ -67,7 +67,7 @@ public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderAp
// 首次查询时返<E697B6><E8BF94><EFBFBD>总数
Long total = null;
if (reqDTO.isFirstPage()) {
// ⚠️ 只统计 userSource = 2 的用户部门关系
// 统计用户部门关系
total = userDeptMapper.countWithUserSource(reqDTO.getTenantId());
}
@@ -107,7 +107,7 @@ public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderAp
@Override
public CommonResult<Long> count(Long tenantId) {
// ⚠️ 只统计 userSource = 2 的用户部门关系
// 统计用户部门关系
return success(userDeptMapper.countWithUserSource(tenantId));
}

View File

@@ -107,4 +107,13 @@ public class DeptApiImpl implements DeptApi {
return success(BeanUtils.toBean(companyDeptInfos, CompanyDeptInfoRespDTO.class));
}
// ========== 数据同步专用接口 ==========
@Override
public CommonResult<Boolean> syncDept(DeptSaveReqDTO syncReqDTO) {
DeptSaveReqVO reqVO = BeanUtils.toBean(syncReqDTO, DeptSaveReqVO.class);
deptService.syncDept(reqVO);
return success(true);
}
}

View File

@@ -38,7 +38,6 @@ public class PostApiImpl implements PostApi {
@Override
public CommonResult<Boolean> updatePost(PostSaveReqDTO updateReqVO) {
log.error("ssssssssss");
PostSaveReqVO reqVO = BeanUtils.toBean(updateReqVO, PostSaveReqVO.class);
postService.updatePost(reqVO);
return success(true);
@@ -76,4 +75,11 @@ public class PostApiImpl implements PostApi {
return success(BeanUtils.toBean(list, PostRespDTO.class));
}
@Override
public CommonResult<Boolean> syncPost(PostSaveReqDTO syncReqDTO) {
PostSaveReqVO reqVO = BeanUtils.toBean(syncReqDTO, PostSaveReqVO.class);
postService.syncPost(reqVO);
return success(true);
}
}

View File

@@ -149,4 +149,11 @@ public class AdminUserApiImpl implements AdminUserApi {
return success(true);
}
@Override
public CommonResult<Boolean> syncUser(AdminUserSaveReqDTO syncReqDTO) {
UserSaveReqVO reqVO = BeanUtils.toBean(syncReqDTO, UserSaveReqVO.class);
userService.syncUser(reqVO);
return success(true);
}
}

View File

@@ -0,0 +1,88 @@
package com.zt.plat.module.system.api.userdept;
import com.zt.plat.framework.common.pojo.CommonResult;
import com.zt.plat.framework.common.util.object.BeanUtils;
import com.zt.plat.module.system.api.userdept.dto.UserDeptRespDTO;
import com.zt.plat.module.system.api.userdept.dto.UserDeptSaveReqDTO;
import com.zt.plat.module.system.dal.dataobject.userdept.UserDeptDO;
import com.zt.plat.module.system.service.userdept.UserDeptService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import static com.zt.plat.framework.common.pojo.CommonResult.success;
/**
* 用户-部门关系 API 实现类
*
* @author ZT
*/
@Slf4j
@RestController
@Validated
public class UserDeptApiImpl implements UserDeptApi {
@Resource
private UserDeptService userDeptService;
@Override
public CommonResult<Long> createUserDept(UserDeptSaveReqDTO reqVO) {
UserDeptDO userDept = BeanUtils.toBean(reqVO, UserDeptDO.class);
Long id = userDeptService.createUserDept(userDept);
return success(id);
}
@Override
public CommonResult<Boolean> updateUserDept(UserDeptSaveReqDTO reqVO) {
UserDeptDO userDept = BeanUtils.toBean(reqVO, UserDeptDO.class);
userDeptService.updateUserDept(userDept);
return success(true);
}
@Override
public CommonResult<Boolean> deleteUserDept(Long id) {
userDeptService.deleteUserDept(id);
return success(true);
}
@Override
public CommonResult<UserDeptRespDTO> getUserDept(Long id) {
UserDeptDO userDept = userDeptService.getUserDept(id);
return success(BeanUtils.toBean(userDept, UserDeptRespDTO.class));
}
@Override
public CommonResult<List<UserDeptRespDTO>> getUserDeptListByUserId(Long userId) {
List<UserDeptDO> list = userDeptService.getValidUserDeptListByUserIds(List.of(userId));
return success(BeanUtils.toBean(list, UserDeptRespDTO.class));
}
@Override
public CommonResult<List<UserDeptRespDTO>> getUserDeptListByDeptId(Long deptId) {
List<UserDeptDO> list = userDeptService.getValidUserDeptListByDeptIds(List.of(deptId));
return success(BeanUtils.toBean(list, UserDeptRespDTO.class));
}
@Override
public CommonResult<Boolean> deleteUserDeptByUserId(Long userId) {
userDeptService.deleteUserDeptByUserId(userId);
return success(true);
}
@Override
public CommonResult<Boolean> deleteUserDeptByDeptId(Long deptId) {
// 需要实现此方法,暂时返回成功
return success(true);
}
@Override
public CommonResult<Boolean> syncUserDept(UserDeptSaveReqDTO syncReqDTO) {
UserDeptDO userDept = BeanUtils.toBean(syncReqDTO, UserDeptDO.class);
userDeptService.syncUserDept(userDept);
return success(true);
}
}

View File

@@ -0,0 +1,106 @@
package com.zt.plat.module.system.api.userpost;
import com.zt.plat.framework.common.pojo.CommonResult;
import com.zt.plat.framework.common.util.object.BeanUtils;
import com.zt.plat.module.system.api.userpost.dto.UserPostRespDTO;
import com.zt.plat.module.system.api.userpost.dto.UserPostSaveReqDTO;
import com.zt.plat.module.system.dal.dataobject.dept.UserPostDO;
import com.zt.plat.module.system.dal.mysql.dept.UserPostMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import static com.zt.plat.framework.common.pojo.CommonResult.success;
/**
* 用户-岗位关系 API 实现类
*
* @author ZT
*/
@Slf4j
@RestController
@Validated
public class UserPostApiImpl implements UserPostApi {
@Resource
private UserPostMapper userPostMapper;
@Override
public CommonResult<Long> createUserPost(UserPostSaveReqDTO reqVO) {
UserPostDO userPost = BeanUtils.toBean(reqVO, UserPostDO.class);
userPostMapper.insert(userPost);
return success(userPost.getId());
}
@Override
public CommonResult<Boolean> updateUserPost(UserPostSaveReqDTO reqVO) {
UserPostDO userPost = BeanUtils.toBean(reqVO, UserPostDO.class);
userPostMapper.updateById(userPost);
return success(true);
}
@Override
public CommonResult<Boolean> deleteUserPost(Long id) {
userPostMapper.deleteById(id);
return success(true);
}
@Override
public CommonResult<UserPostRespDTO> getUserPost(Long id) {
UserPostDO userPost = userPostMapper.selectById(id);
return success(BeanUtils.toBean(userPost, UserPostRespDTO.class));
}
@Override
public CommonResult<List<UserPostRespDTO>> getUserPostListByUserId(Long userId) {
List<UserPostDO> list = userPostMapper.selectListByUserId(userId);
return success(BeanUtils.toBean(list, UserPostRespDTO.class));
}
@Override
public CommonResult<List<UserPostRespDTO>> getUserPostListByPostId(Long postId) {
List<UserPostDO> list = userPostMapper.selectListByPostIds(List.of(postId));
return success(BeanUtils.toBean(list, UserPostRespDTO.class));
}
@Override
public CommonResult<Boolean> deleteUserPostByUserId(Long userId) {
userPostMapper.deleteByUserId(userId);
return success(true);
}
@Override
public CommonResult<Boolean> deleteUserPostByPostId(Long postId) {
userPostMapper.delete(UserPostDO::getPostId, postId);
return success(true);
}
@Override
@Transactional(rollbackFor = Exception.class)
public CommonResult<Boolean> syncUserPost(UserPostSaveReqDTO syncReqDTO) {
if (syncReqDTO.getId() == null) {
return success(false);
}
UserPostDO existing = userPostMapper.selectById(syncReqDTO.getId());
UserPostDO userPost = BeanUtils.toBean(syncReqDTO, UserPostDO.class);
if (existing != null) {
userPostMapper.updateById(userPost);
log.info("[syncUserPost] 用户岗位关系同步-更新成功, id={}, userId={}, postId={}",
userPost.getId(), userPost.getUserId(), userPost.getPostId());
} else {
userPostMapper.insert(userPost);
log.info("[syncUserPost] 用户岗位关系同步-创建成功, id={}, userId={}, postId={}",
userPost.getId(), userPost.getUserId(), userPost.getPostId());
}
return success(true);
}
}

View File

@@ -127,12 +127,17 @@ public interface DeptMapper extends BaseMapperX<DeptDO> {
/**
* 根据部门编码查询部门
* <p>
* 注意:如果存在多条相同编码的记录,只返回第一条
*
* @param code 部门编码
* @return 部门信息
*/
default DeptDO selectByCode(String code) {
return selectOne(DeptDO::getCode, code);
List<DeptDO> list = selectList(new LambdaQueryWrapperX<DeptDO>()
.eq(DeptDO::getCode, code)
.last("LIMIT 1"));
return CollUtil.isNotEmpty(list) ? list.get(0) : null;
}
/**

View File

@@ -181,4 +181,8 @@ public interface DeptService {
* @param deptIds 需要回填的部门 ID 列表
*/
void backfillMissingCodesWithoutEvent(Collection<Long> deptIds);
// ========== 数据同步专用接口 ==========
void syncDept(DeptSaveReqVO syncReqVO);
}

View File

@@ -923,4 +923,41 @@ public class DeptServiceImpl implements DeptService {
}
}
// ========== 数据同步专用接口 ==========
@Override
@Transactional(rollbackFor = Exception.class)
@CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST, allEntries = true)
@DataPermission(enable = false)
public void syncDept(DeptSaveReqVO syncReqVO) {
if (syncReqVO.getId() == null) {
log.warn("[syncDept] 同步部门失败ID 不能为空");
return;
}
// 标准化父部门 ID
syncReqVO.setParentId(normalizeParentId(syncReqVO.getParentId()));
// 默认部门来源
if (syncReqVO.getDeptSource() == null) {
syncReqVO.setDeptSource(DeptSourceEnum.EXTERNAL.getSource());
}
// 检查部门是否存在
DeptDO existingDept = deptMapper.selectById(syncReqVO.getId());
// 转换为 DO
DeptDO dept = BeanUtils.toBean(syncReqVO, DeptDO.class);
if (existingDept != null) {
// 部门存在,执行更新
deptMapper.updateById(dept);
log.info("[syncDept] 部门同步-更新成功, deptId={}, deptName={}", dept.getId(), dept.getName());
} else {
// 部门不存在,执行插入
deptMapper.insert(dept);
log.info("[syncDept] 部门同步-创建成功, deptId={}, deptName={}", dept.getId(), dept.getName());
}
// 注意:不发布变更事件,避免循环同步
}
}

View File

@@ -89,4 +89,8 @@ public interface PostService {
*/
Long getOrCreatePostByName(String postName);
// ========== 数据同步专用接口 ==========
void syncPost(PostSaveReqVO syncReqVO);
}

View File

@@ -191,4 +191,25 @@ public class PostServiceImpl implements PostService {
return createPost(createReqVO);
}
// ========== 数据同步专用接口 ==========
@Override
public void syncPost(PostSaveReqVO syncReqVO) {
if (syncReqVO.getId() == null) {
return;
}
PostDO existingPost = postMapper.selectById(syncReqVO.getId());
PostDO post = BeanUtils.toBean(syncReqVO, PostDO.class);
if (existingPost != null) {
postMapper.updateById(post);
} else {
if (post.getStatus() == null) {
post.setStatus(CommonStatusEnum.ENABLE.getStatus());
}
postMapper.insert(post);
}
}
}

View File

@@ -212,4 +212,8 @@ public interface AdminUserService {
*/
boolean isPasswordMatch(AdminUserDO user, String rawPassword);
// ========== 数据同步专用接口 ==========
void syncUser(UserSaveReqVO syncReqVO);
}

View File

@@ -725,4 +725,48 @@ public class AdminUserServiceImpl implements AdminUserService {
return StrUtil.isNotBlank(value) && value.startsWith("$2");
}
// ========== 数据同步专用接口 ==========
@Override
@Transactional(rollbackFor = Exception.class)
public void syncUser(UserSaveReqVO syncReqVO) {
if (syncReqVO.getId() == null) {
log.warn("[syncUser] 同步用户失败ID 不能为空");
return;
}
// 检查用户是否存在
AdminUserDO existingUser = userMapper.selectById(syncReqVO.getId());
// 转换为 DO只同步用户主表不处理关联关系
AdminUserDO user = BeanUtils.toBean(syncReqVO, AdminUserDO.class);
user.setDeptIds(null); // 部门关联单独同步
user.setPostIds(null); // 岗位关联单独同步
if (existingUser != null) {
// 用户存在,执行更新(不更新密码)
user.setPassword(null);
userMapper.updateById(user);
log.info("[syncUser] 用户同步-更新成功, userId={}, username={}", user.getId(), user.getUsername());
} else {
// 用户不存在,执行插入
// 设置默认状态
if (user.getStatus() == null) {
user.setStatus(CommonStatusEnum.ENABLE.getStatus());
}
// 设置默认用户来源
if (user.getUserSource() == null) {
user.setUserSource(UserSourceEnum.EXTERNAL.getSource());
}
// 如果没有密码,设置默认密码
if (StrUtil.isBlank(user.getPassword())) {
user.setPassword(passwordEncoder.encode("123456"));
}
userMapper.insert(user);
log.info("[syncUser] 用户同步-创建成功, userId={}, username={}", user.getId(), user.getUsername());
}
// 注意:不发布变更事件,避免循环同步
}
}

View File

@@ -76,5 +76,8 @@ public interface UserDeptService {
*/
void batchCreateUserDept(List<UserDeptDO> createReqVOList);
// ========== 数据同步专用接口 ==========
void syncUserDept(UserDeptDO syncReqVO);
}

View File

@@ -155,4 +155,22 @@ public class UserDeptServiceImpl implements UserDeptService {
}
}
}
// ========== 数据同步专用接口 ==========
@Override
@Transactional(rollbackFor = Exception.class)
public void syncUserDept(UserDeptDO syncReqVO) {
if (syncReqVO.getId() == null) {
return;
}
UserDeptDO existing = userDeptMapper.selectById(syncReqVO.getId());
if (existing != null) {
userDeptMapper.updateById(syncReqVO);
} else {
userDeptMapper.insert(syncReqVO);
}
}
}