转出状态2
This commit is contained in:
@@ -79,7 +79,7 @@ public class GroupController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编辑组(不含移动,移动请走 group/move 后台接口):返回更新后的组节点(含 id)。
|
* 编辑组(不含移动,移动请走 group/move/{schoolId} 开放接口或后台 Move):返回更新后的组节点(含 id)。
|
||||||
*/
|
*/
|
||||||
@PostMapping("edit/{id}")
|
@PostMapping("edit/{id}")
|
||||||
public BoaGroup edit(@PathVariable Integer id,
|
public BoaGroup edit(@PathVariable Integer id,
|
||||||
|
|||||||
@@ -6,13 +6,16 @@ import com.yunhai.platform.utils.model.BoaGroup;
|
|||||||
import com.yunhai.platform.utils.model.BoaModule;
|
import com.yunhai.platform.utils.model.BoaModule;
|
||||||
import com.yunhai.platform.utils.model.BoaRoleInfo;
|
import com.yunhai.platform.utils.model.BoaRoleInfo;
|
||||||
import com.yunhai.platform.utils.model.BoaUser;
|
import com.yunhai.platform.utils.model.BoaUser;
|
||||||
|
import com.yunhai.userbase.common.annotation.OapiLog;
|
||||||
import com.yunhai.userbase.common.validation.ValidationGroups;
|
import com.yunhai.userbase.common.validation.ValidationGroups;
|
||||||
import com.yunhai.userbase.config.Config;
|
import com.yunhai.userbase.config.Config;
|
||||||
import com.yunhai.userbase.entity.ApplicationInfo;
|
import com.yunhai.userbase.entity.ApplicationInfo;
|
||||||
import com.yunhai.userbase.model.sysuser.SysUserGroupDeleteItem;
|
import com.yunhai.userbase.model.sysuser.SysUserGroupDeleteItem;
|
||||||
|
import com.yunhai.userbase.model.sysuser.SysUserGroupStateRequest;
|
||||||
import com.yunhai.userbase.model.sysuser.SysUserMoveRequest;
|
import com.yunhai.userbase.model.sysuser.SysUserMoveRequest;
|
||||||
import com.yunhai.userbase.model.sysuser.SysUserPasswordRequest;
|
import com.yunhai.userbase.model.sysuser.SysUserPasswordRequest;
|
||||||
import com.yunhai.userbase.model.sysuser.SysUserRequest;
|
import com.yunhai.userbase.model.sysuser.SysUserRequest;
|
||||||
|
import com.yunhai.userbase.model.sysuser.SysUserTransferSchoolRequest;
|
||||||
import com.yunhai.userbase.repository.ApplicationInfoRepository;
|
import com.yunhai.userbase.repository.ApplicationInfoRepository;
|
||||||
import com.yunhai.userbase.service.IGroupAuthzService;
|
import com.yunhai.userbase.service.IGroupAuthzService;
|
||||||
import com.yunhai.userbase.service.ISysUserService;
|
import com.yunhai.userbase.service.ISysUserService;
|
||||||
@@ -230,4 +233,43 @@ public class UserController {
|
|||||||
public void password(@RequestBody @Validated SysUserPasswordRequest request) {
|
public void password(@RequestBody @Validated SysUserPasswordRequest request) {
|
||||||
sysUserService.changePassword(request.getUserId(), request.getOldPassword(), request.getNewPassword());
|
sysUserService.changePassword(request.getUserId(), request.getOldPassword(), request.getNewPassword());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置用户在指定组上的状态(转出/恢复)。<br>
|
||||||
|
* state=1 转出、state=0 恢复正常;仅作关系标记,不影响成员查询、组织链与下游推送。
|
||||||
|
* 仅允许在同一学校(组)范围内操作——groupId 必须属于 schoolId 子树且不等于 schoolId。<br>
|
||||||
|
* 鉴权由过滤器层强制签名;POST 自动记 OapiLog。
|
||||||
|
*/
|
||||||
|
@PostMapping("groupState")
|
||||||
|
public void groupState(@RequestBody @Validated SysUserGroupStateRequest request) {
|
||||||
|
sysUserService.changeUserGroupState(request.getUserId(), request.getGroupId(),
|
||||||
|
request.getSchoolId(), request.getState());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户在指定组上的状态:0=正常,1=转出。<br>
|
||||||
|
* 边界与设置接口一致(groupId 必须属于 schoolId 子树且不等于 schoolId);
|
||||||
|
* 用户不在此组时返回业务错误(code=5)。
|
||||||
|
*/
|
||||||
|
@OapiLog(value = "查询用户组状态", saveResponse = false)
|
||||||
|
@GetMapping("groupState")
|
||||||
|
public Integer groupState(@RequestParam("userId") Integer userId,
|
||||||
|
@RequestParam("groupId") Integer groupId,
|
||||||
|
@RequestParam("schoolId") Integer schoolId) {
|
||||||
|
return sysUserService.getUserGroupState(userId, groupId, schoolId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跨校转入(转出后迁移到其他学校)。<br>
|
||||||
|
* 前置:用户已在原学校(fromSchoolId 子树内)存在至少一条「转出」状态的组关系(先经 groupState 置转出);<br>
|
||||||
|
* 操作成功后:删除原学校范围内全部组关系(其他学校保留),在目标学校建立目标组关系
|
||||||
|
* (主归属、状态恢复正常),并推送编辑用户订阅。<br>
|
||||||
|
* 鉴权由过滤器层强制签名;POST 自动记 OapiLog。
|
||||||
|
*/
|
||||||
|
@PostMapping("transferToSchool")
|
||||||
|
public BoaUser transferToSchool(@RequestBody @Validated SysUserTransferSchoolRequest request) {
|
||||||
|
sysUserService.transferUserToSchool(request.getUserId(), request.getFromSchoolId(),
|
||||||
|
request.getSchoolId(), request.getGroupId());
|
||||||
|
return userCenterService.getUserInfoWithDeptById(request.getUserId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ import lombok.Data;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import com.yunhai.userbase.common.converter.UserGroupRelStatusEnumConverter;
|
||||||
|
import com.yunhai.userbase.enums.UserGroupRelStatusEnum;
|
||||||
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@@ -36,6 +39,14 @@ public class SysUserGroupRel {
|
|||||||
@Column(name = "sort_no")
|
@Column(name = "sort_no")
|
||||||
private Integer sortNo;
|
private Integer sortNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组内状态:0=正常 1=转出(存量数据 NULL 视为正常)。<br>
|
||||||
|
* 转出仅作标记,不影响成员查询、组织链与下游推送;
|
||||||
|
* 改组/移动经 changeGroups 覆盖式重建关系行时状态随用户继承(同组照抄旧状态,新增组在转出流程中继承转出)。
|
||||||
|
*/
|
||||||
|
@Convert(converter = UserGroupRelStatusEnumConverter.class)
|
||||||
|
private UserGroupRelStatusEnum status;
|
||||||
|
|
||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
// 关联用户,仅查询,不维护外键
|
// 关联用户,仅查询,不维护外键
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ public class SysUserVo {
|
|||||||
private Integer type;
|
private Integer type;
|
||||||
/** 当前组维度的排序号(组内 sort_no);根节点/未选组时为 null */
|
/** 当前组维度的排序号(组内 sort_no);根节点/未选组时为 null */
|
||||||
private Integer sortNo;
|
private Integer sortNo;
|
||||||
|
/** 组内状态:UserGroupRelStatusEnum 的 key(0=正常,1=转出);仅组上下文列表有值,根节点/未选组为 null */
|
||||||
|
private Integer groupStatus;
|
||||||
private Boolean expired;
|
private Boolean expired;
|
||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
private LocalDateTime updateTime;
|
private LocalDateTime updateTime;
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public interface SysUserRepository extends JpaRepository<SysUser, Integer>, JpaS
|
|||||||
* 入参 name / disabled 为可空:为空(NULL)时该过滤条件整体跳过。
|
* 入参 name / disabled 为可空:为空(NULL)时该过滤条件整体跳过。
|
||||||
*/
|
*/
|
||||||
@Query(value =
|
@Query(value =
|
||||||
"SELECT u.id AS userId, MIN(r.sort_no) AS minSortNo " +
|
"SELECT u.id AS userId, MIN(r.sort_no) AS minSortNo, MAX(COALESCE(r.status, 0)) AS groupStatus " +
|
||||||
"FROM sys_user u " +
|
"FROM sys_user u " +
|
||||||
"INNER JOIN sys_user_group_rel r ON r.user_id = u.id " +
|
"INNER JOIN sys_user_group_rel r ON r.user_id = u.id " +
|
||||||
"WHERE r.group_id IN (:groupIds) " +
|
"WHERE r.group_id IN (:groupIds) " +
|
||||||
|
|||||||
@@ -179,4 +179,42 @@ public interface ISysUserService {
|
|||||||
* @param newPassword 新密码(弱密码规则校验后加密写入)
|
* @param newPassword 新密码(弱密码规则校验后加密写入)
|
||||||
*/
|
*/
|
||||||
void changePassword(Integer userId, String oldPassword, String newPassword);
|
void changePassword(Integer userId, String oldPassword, String newPassword);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开放接口专用:设置用户在指定组上的状态(转出/恢复)。<br>
|
||||||
|
* 仅作关系标记,不影响成员查询、组织链与下游推送;同值重复调用幂等。<br>
|
||||||
|
* 边界:groupId 必须属于 schoolId 子树且不能等于 schoolId(禁止跨校/学校根组操作)。
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param groupId 组ID
|
||||||
|
* @param schoolId 学校组ID(限定范围)
|
||||||
|
* @param state 目标状态:0=恢复正常,1=转出
|
||||||
|
*/
|
||||||
|
void changeUserGroupState(Integer userId, Integer groupId, Integer schoolId, Integer state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开放接口专用:查询用户在指定组上的状态(0=正常,1=转出)。<br>
|
||||||
|
* 存量数据 status 为 NULL 视为正常返回 0。
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param groupId 组ID
|
||||||
|
* @param schoolId 学校组ID(限定范围)
|
||||||
|
* @return 状态值 0/1
|
||||||
|
*/
|
||||||
|
Integer getUserGroupState(Integer userId, Integer groupId, Integer schoolId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开放接口专用:跨校转入(转出后迁移到其他学校)。<br>
|
||||||
|
* 前置:用户已在源学校(fromSchoolId 子树内)存在至少一条「转出」状态的组关系;
|
||||||
|
* 操作成功后:删除源学校范围内全部组关系(其他学校保留),在目标学校建立目标组关系
|
||||||
|
* (主归属、状态恢复正常,转出流程结束),并推送编辑用户订阅(UPDATE_USER)。<br>
|
||||||
|
* 边界:fromSchoolId 与目标 schoolId 均须为学校组且不相同;目标组须属于目标学校子树且不等于学校根组;
|
||||||
|
* 用户已在目标学校存在组关系时拒绝(转入语义为进入全新学校)。
|
||||||
|
*
|
||||||
|
* @param userId 待迁移用户ID
|
||||||
|
* @param fromSchoolId 原学校组ID(源学校)
|
||||||
|
* @param toSchoolId 目标学校组ID
|
||||||
|
* @param groupId 目标组ID(目标学校内的挂载组,迁移后的主归属)
|
||||||
|
*/
|
||||||
|
void transferUserToSchool(Integer userId, Integer fromSchoolId, Integer toSchoolId, Integer groupId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import com.yunhai.userbase.entity.SysGroup;
|
|||||||
import com.yunhai.platform.utils.enums.IEnum;
|
import com.yunhai.platform.utils.enums.IEnum;
|
||||||
import com.yunhai.userbase.enums.StatusEnum;
|
import com.yunhai.userbase.enums.StatusEnum;
|
||||||
import com.yunhai.userbase.enums.SysRoleEnum;
|
import com.yunhai.userbase.enums.SysRoleEnum;
|
||||||
|
import com.yunhai.userbase.enums.UserGroupRelStatusEnum;
|
||||||
import com.yunhai.userbase.enums.UserTypeEnum;
|
import com.yunhai.userbase.enums.UserTypeEnum;
|
||||||
import com.yunhai.userbase.entity.SysUser;
|
import com.yunhai.userbase.entity.SysUser;
|
||||||
import com.yunhai.userbase.entity.SysUserAppRoleRel;
|
import com.yunhai.userbase.entity.SysUserAppRoleRel;
|
||||||
@@ -338,6 +339,93 @@ public class SysUserService implements ISysUserService {
|
|||||||
sysUserGroupRelRepository.save(rel);
|
sysUserGroupRelRepository.save(rel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void changeUserGroupState(Integer userId, Integer groupId, Integer schoolId, Integer state) {
|
||||||
|
if (state == null || (state != 0 && state != 1)) {
|
||||||
|
throw new DException("state 仅支持 0=恢复正常、1=转出");
|
||||||
|
}
|
||||||
|
// 开放接口边界:groupId 必须属于 schoolId 子树且不能等于 schoolId(禁止跨校/学校根组)
|
||||||
|
assertGroupWithinSchool(groupId, schoolId);
|
||||||
|
if (!sysUserRepository.existsById(userId)) {
|
||||||
|
throw new DException("系统用户不存在");
|
||||||
|
}
|
||||||
|
// 状态按组维度存储,必须落到具体的 (userId, groupId) 关联行;同值重复调用幂等
|
||||||
|
SysUserGroupRel rel = sysUserGroupRelRepository.findByUserIdAndGroupId(userId, groupId)
|
||||||
|
.orElseThrow(() -> new DException("该用户不在此分组中"));
|
||||||
|
rel.setStatus(state == 1 ? UserGroupRelStatusEnum.TRANSFERRED_OUT : UserGroupRelStatusEnum.NORMAL);
|
||||||
|
sysUserGroupRelRepository.save(rel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getUserGroupState(Integer userId, Integer groupId, Integer schoolId) {
|
||||||
|
assertGroupWithinSchool(groupId, schoolId);
|
||||||
|
SysUserGroupRel rel = sysUserGroupRelRepository.findByUserIdAndGroupId(userId, groupId)
|
||||||
|
.orElseThrow(() -> new DException("该用户不在此分组中"));
|
||||||
|
// 存量数据 status 为 NULL,按正常返回
|
||||||
|
return rel.getStatus() == null ? UserGroupRelStatusEnum.NORMAL.getKey() : rel.getStatus().getKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void transferUserToSchool(Integer userId, Integer fromSchoolId, Integer toSchoolId, Integer groupId) {
|
||||||
|
if (userId == null) {
|
||||||
|
throw new DException("用户ID不能为空");
|
||||||
|
}
|
||||||
|
if (fromSchoolId == null) {
|
||||||
|
throw new DException("原学校ID不能为空");
|
||||||
|
}
|
||||||
|
if (toSchoolId == null) {
|
||||||
|
throw new DException("目标学校ID不能为空");
|
||||||
|
}
|
||||||
|
if (groupId == null) {
|
||||||
|
throw new DException("目标组ID不能为空");
|
||||||
|
}
|
||||||
|
// 源学校必须真实存在且为学校组(目标学校在 assertGroupWithinSchool 内一并校验)
|
||||||
|
sysGroupService.assertSchoolId(fromSchoolId);
|
||||||
|
if (fromSchoolId.equals(toSchoolId)) {
|
||||||
|
throw new DException("原学校与目标学校不能相同");
|
||||||
|
}
|
||||||
|
if (!sysUserRepository.existsById(userId)) {
|
||||||
|
throw new DException("系统用户不存在");
|
||||||
|
}
|
||||||
|
// 目标组必须属于目标学校子树且不等于学校根组(复用移动/删除的边界校验)
|
||||||
|
assertGroupWithinSchool(groupId, toSchoolId);
|
||||||
|
|
||||||
|
List<Integer> fromScope = sysGroupService.listSelfAndDescendantIds(fromSchoolId);
|
||||||
|
List<Integer> toScope = sysGroupService.listSelfAndDescendantIds(toSchoolId);
|
||||||
|
List<SysUserGroupRel> rels = sysUserGroupRelRepository.findByUserId(userId);
|
||||||
|
|
||||||
|
// ① 前置:用户在源学校范围必须存在至少一条「转出」状态的组关系
|
||||||
|
boolean hasTransferOut = rels.stream().anyMatch(r ->
|
||||||
|
r.getStatus() == UserGroupRelStatusEnum.TRANSFERRED_OUT && fromScope.contains(r.getGroupId()));
|
||||||
|
if (!hasTransferOut) {
|
||||||
|
throw new DException("该用户在原学校不存在转出状态的组关系,禁止转入");
|
||||||
|
}
|
||||||
|
// ② 目标学校范围不得已有组关系(转入语义为进入全新学校,避免覆盖歧义)
|
||||||
|
boolean existsInTarget = rels.stream().anyMatch(r -> toScope.contains(r.getGroupId()));
|
||||||
|
if (existsInTarget) {
|
||||||
|
throw new DException("用户已在该学校存在组关系,禁止重复转入");
|
||||||
|
}
|
||||||
|
// ③ 删除源学校范围内全部关系行(仅源学校,其他学校保留)
|
||||||
|
List<SysUserGroupRel> toDelete = rels.stream()
|
||||||
|
.filter(r -> fromScope.contains(r.getGroupId()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (!toDelete.isEmpty()) {
|
||||||
|
sysUserGroupRelRepository.deleteAll(toDelete);
|
||||||
|
}
|
||||||
|
// ④ 建立目标学校关系:目标组设为主归属,状态恢复正常(转出流程结束)
|
||||||
|
SysUserGroupRel rel = new SysUserGroupRel();
|
||||||
|
rel.setUserId(userId);
|
||||||
|
rel.setGroupId(groupId);
|
||||||
|
rel.setIsMain(IS_MAIN);
|
||||||
|
rel.setStatus(UserGroupRelStatusEnum.NORMAL);
|
||||||
|
rel.setCreateTime(LocalDateTime.now());
|
||||||
|
sysUserGroupRelRepository.save(rel);
|
||||||
|
// ⑤ 推送编辑用户订阅
|
||||||
|
publishUserEvent(PushInterfaceType.UPDATE_USER, userId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Page<SysUserVo> list(SysUserQuery query, Pageable pageable) {
|
public Page<SysUserVo> list(SysUserQuery query, Pageable pageable) {
|
||||||
// 组上下文(选中具体组):走原生 SQL 按「组内最小 sort_no」排序的专用分页,
|
// 组上下文(选中具体组):走原生 SQL 按「组内最小 sort_no」排序的专用分页,
|
||||||
@@ -348,7 +436,7 @@ public class SysUserService implements ISysUserService {
|
|||||||
// 根节点 / 未选组:用 Specification 过滤,按主键 id 升序(聚簇索引顺序,无 filesort)。
|
// 根节点 / 未选组:用 Specification 过滤,按主键 id 升序(聚簇索引顺序,无 filesort)。
|
||||||
Specification<SysUser> spec = buildSpecification(query);
|
Specification<SysUser> spec = buildSpecification(query);
|
||||||
Page<SysUser> page = sysUserRepository.findAll(spec, pageable);
|
Page<SysUser> page = sysUserRepository.findAll(spec, pageable);
|
||||||
return page.map(u -> convertToVo(u, null));
|
return page.map(u -> convertToVo(u, null, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -372,15 +460,19 @@ public class SysUserService implements ISysUserService {
|
|||||||
return new PageImpl<>(Collections.emptyList(), pageable, 0);
|
return new PageImpl<>(Collections.emptyList(), pageable, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保持 DB 返回的排序顺序,并记录每个用户的「组范围内最小 sort_no」
|
// 保持 DB 返回的排序顺序,并记录每个用户的「组范围内最小 sort_no」与「组内状态(任一转出即转出)」
|
||||||
List<Integer> orderedIds = new ArrayList<>(rows.size());
|
List<Integer> orderedIds = new ArrayList<>(rows.size());
|
||||||
Map<Integer, Integer> sortNoMap = new LinkedHashMap<>();
|
Map<Integer, Integer> sortNoMap = new LinkedHashMap<>();
|
||||||
|
Map<Integer, Integer> groupStatusMap = new LinkedHashMap<>();
|
||||||
for (Object[] row : rows) {
|
for (Object[] row : rows) {
|
||||||
Integer userId = ((Number) row[0]).intValue();
|
Integer userId = ((Number) row[0]).intValue();
|
||||||
Object minObj = row[1]; // MIN(sort_no) 可能为空(该用户在组范围内均未设置排序号)
|
Object minObj = row[1]; // MIN(sort_no) 可能为空(该用户在组范围内均未设置排序号)
|
||||||
Integer sortNo = minObj == null ? null : ((Number) minObj).intValue();
|
Integer sortNo = minObj == null ? null : ((Number) minObj).intValue();
|
||||||
|
Object statusObj = row[2]; // MAX(COALESCE(status,0)):组范围内任一条转出即视为转出
|
||||||
|
Integer groupStatus = statusObj == null ? null : ((Number) statusObj).intValue();
|
||||||
orderedIds.add(userId);
|
orderedIds.add(userId);
|
||||||
sortNoMap.put(userId, sortNo);
|
sortNoMap.put(userId, sortNo);
|
||||||
|
groupStatusMap.put(userId, groupStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 按有序 ID 取实体(findAllById 返回顺序不可靠,需按 orderedIds 重排)
|
// 按有序 ID 取实体(findAllById 返回顺序不可靠,需按 orderedIds 重排)
|
||||||
@@ -392,7 +484,7 @@ public class SysUserService implements ISysUserService {
|
|||||||
for (Integer id : orderedIds) {
|
for (Integer id : orderedIds) {
|
||||||
SysUser u = userMap.get(id);
|
SysUser u = userMap.get(id);
|
||||||
if (u != null) {
|
if (u != null) {
|
||||||
voList.add(convertToVo(u, sortNoMap.get(id)));
|
voList.add(convertToVo(u, sortNoMap.get(id), groupStatusMap.get(id)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new PageImpl<>(voList, pageable, idPage.getTotalElements());
|
return new PageImpl<>(voList, pageable, idPage.getTotalElements());
|
||||||
@@ -426,14 +518,29 @@ public class SysUserService implements ISysUserService {
|
|||||||
|
|
||||||
LocalDateTime now = LocalDateTime.now();
|
LocalDateTime now = LocalDateTime.now();
|
||||||
for (Integer userId : userIds) {
|
for (Integer userId : userIds) {
|
||||||
|
// 覆盖式重建前先读旧关系,用于继承组内状态(转出标记):
|
||||||
|
// 行级继承——同组照抄旧状态(管理端重设组不误改);用户级继承——新增组在用户处于转出流程中(存在任一转出行)时继承「转出」
|
||||||
|
List<SysUserGroupRel> oldRels = sysUserGroupRelRepository.findByUserId(userId);
|
||||||
|
Map<Integer, UserGroupRelStatusEnum> oldStatusByGroup = new HashMap<>();
|
||||||
|
boolean inTransferFlow = false;
|
||||||
|
for (SysUserGroupRel oldRel : oldRels) {
|
||||||
|
oldStatusByGroup.put(oldRel.getGroupId(), oldRel.getStatus());
|
||||||
|
if (oldRel.getStatus() == UserGroupRelStatusEnum.TRANSFERRED_OUT) {
|
||||||
|
inTransferFlow = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
sysUserGroupRelRepository.deleteByUserId(userId);
|
sysUserGroupRelRepository.deleteByUserId(userId);
|
||||||
List<SysUserGroupRel> rels = new ArrayList<>(groupIds.size());
|
List<SysUserGroupRel> rels = new ArrayList<>(groupIds.size());
|
||||||
for (int i = 0; i < groupIds.size(); i++) {
|
for (int i = 0; i < groupIds.size(); i++) {
|
||||||
|
Integer groupId = groupIds.get(i);
|
||||||
SysUserGroupRel rel = new SysUserGroupRel();
|
SysUserGroupRel rel = new SysUserGroupRel();
|
||||||
rel.setUserId(userId);
|
rel.setUserId(userId);
|
||||||
rel.setGroupId(groupIds.get(i));
|
rel.setGroupId(groupId);
|
||||||
rel.setIsMain(i == 0 ? IS_MAIN : 0);
|
rel.setIsMain(i == 0 ? IS_MAIN : 0);
|
||||||
rel.setCreateTime(now);
|
rel.setCreateTime(now);
|
||||||
|
rel.setStatus(oldStatusByGroup.containsKey(groupId)
|
||||||
|
? oldStatusByGroup.get(groupId)
|
||||||
|
: (inTransferFlow ? UserGroupRelStatusEnum.TRANSFERRED_OUT : UserGroupRelStatusEnum.NORMAL));
|
||||||
rels.add(rel);
|
rels.add(rel);
|
||||||
}
|
}
|
||||||
sysUserGroupRelRepository.saveAll(rels);
|
sysUserGroupRelRepository.saveAll(rels);
|
||||||
@@ -885,18 +992,19 @@ public class SysUserService implements ISysUserService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private SysUserVo convertToVo(SysUser entity) {
|
private SysUserVo convertToVo(SysUser entity) {
|
||||||
return convertToVo(entity, null);
|
return convertToVo(entity, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SysUserVo convertToVo(SysUser entity, Integer sortNo) {
|
private SysUserVo convertToVo(SysUser entity, Integer sortNo, Integer groupStatus) {
|
||||||
SysUserVo vo = new SysUserVo();
|
SysUserVo vo = new SysUserVo();
|
||||||
BeanUtils.copyProperties(entity, vo);
|
BeanUtils.copyProperties(entity, vo);
|
||||||
// disabled 为枚举,需要单独映射为 key(与 GroupTypeEnum 的 type 处理一致)
|
// disabled 为枚举,需要单独映射为 key(与 GroupTypeEnum 的 type 处理一致)
|
||||||
vo.setDisabled(entity.getDisabled() == null ? null : entity.getDisabled().getKey());
|
vo.setDisabled(entity.getDisabled() == null ? null : entity.getDisabled().getKey());
|
||||||
// type 为枚举,同样映射为 key
|
// type 为枚举,同样映射为 key
|
||||||
vo.setType(entity.getType() == null ? null : entity.getType().getKey());
|
vo.setType(entity.getType() == null ? null : entity.getType().getKey());
|
||||||
// 当前组维度的排序号;根节点 / 未选组时为 null
|
// 当前组维度的排序号与组内状态;根节点 / 未选组时为 null
|
||||||
vo.setSortNo(sortNo);
|
vo.setSortNo(sortNo);
|
||||||
|
vo.setGroupStatus(groupStatus);
|
||||||
return vo;
|
return vo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user