Files
UserBaseService/src/main/java/com/yunhai/userbase/service/push/PushPayloadAssembler.java
T
2026-08-14 09:03:17 +08:00

187 lines
7.3 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.yunhai.userbase.service.push;
import com.yunhai.userbase.entity.SysGroup;
import com.yunhai.userbase.entity.SysUser;
import com.yunhai.userbase.entity.SysUserGroupRel;
import com.yunhai.userbase.enums.GroupTypeEnum;
import com.yunhai.userbase.enums.StatusEnum;
import com.yunhai.userbase.model.push.dto.PushGroupDTO;
import com.yunhai.userbase.model.push.dto.PushUserDTO;
import com.yunhai.userbase.repository.SysGroupRepository;
import com.yunhai.userbase.repository.SysUserGroupRelRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
/**
* 领域模型 → 文档契约 DTO 的装配器。<br><br>
* 关键映射(方案 v5 §2 / 文档 3.x):
* <ul>
* <li>组 type:GroupTypeEnum.key 直接透传(1-8 零映射)</li>
* <li>用户 status:NORMAL(0)→0正常 / DISABLED(1)→2禁用</li>
* <li>groups[].schoolId:组所属学校范围 id(沿 parentId 向上最近 SCHOOL_GROUP)</li>
* <li>roleList[].schId:用户主组所属学校范围 id(userbase 无角色-学校关联,统一取主校)</li>
* </ul>
*
* @author chenx
* @date 2026/8/14
*/
@Service
public class PushPayloadAssembler {
private static final int ROOT_PARENT_ID = 0;
private static final int IS_MAIN = 1;
@Autowired
private SysGroupRepository sysGroupRepository;
@Autowired
private SysUserGroupRelRepository sysUserGroupRelRepository;
@Autowired
private GroupScopeHelper groupScopeHelper;
// ===================== 组 =====================
/** 组节点(不含 children)。AddGroup / UpdateGroup 使用。 */
public PushGroupDTO toGroupDto(SysGroup g) {
if (g == null) {
return null;
}
PushGroupDTO d = new PushGroupDTO();
d.setId(g.getId());
d.setName(g.getName());
// 文档 code 为「机构代码」,userbase 的 sys_group 无此属性,按可选项留空(序列化后为 null)
d.setType(g.getType() == null ? null : g.getType().getKey());
d.setPid(g.getParentId());
d.setNo(g.getSort());
return d;
}
/** 组节点 + 递归 children(SyncGroup 使用)。 */
public PushGroupDTO toGroupDtoWithChildren(SysGroup g, Map<Integer, List<SysGroup>> childrenMap) {
PushGroupDTO d = toGroupDto(g);
List<SysGroup> children = childrenMap.get(g.getId());
if (children != null) {
d.setChildren(children.stream()
.map(c -> toGroupDtoWithChildren(c, childrenMap))
.collect(Collectors.toList()));
}
return d;
}
/** 多个组(AddGroup / UpdateGroup),无 children,带 pid。 */
public List<PushGroupDTO> toGroupDtoList(List<SysGroup> groups) {
if (groups == null) {
return Collections.emptyList();
}
return groups.stream().map(this::toGroupDto).collect(Collectors.toList());
}
// ===================== 用户 =====================
/** 单个用户 → PushUserDTO(含 groups / roleList,学校 id 已解析)。 */
public PushUserDTO toUserDto(SysUser u) {
if (u == null) {
return null;
}
PushUserDTO d = new PushUserDTO();
d.setId(u.getId());
d.setAccount(u.getAccount());
d.setName(u.getRealName());
d.setIdcard(u.getIdcard());
d.setPhone(u.getPhone());
d.setEmail(u.getEmail());
d.setGender(u.getGender());
d.setBirthday(u.getBirthday() == null ? null : u.getBirthday().toString());
// status:NORMAL(0)→0正常 / DISABLED(1)→2禁用
d.setStatus(u.getDisabled() == StatusEnum.NORMAL ? 0 : 2);
d.setProfilePicture(u.getProfilePicture());
List<SysUserGroupRel> rels = sysUserGroupRelRepository.findByUserId(u.getId());
Integer mainSchoolId = resolveMainSchoolId(rels);
// groups
List<PushUserDTO.PushUserGroupRef> groupRefs = new ArrayList<>();
for (SysUserGroupRel rel : rels) {
PushUserDTO.PushUserGroupRef ref = new PushUserDTO.PushUserGroupRef();
ref.setGroupId(rel.getGroupId());
ref.setNo(rel.getSortNo());
ref.setSchoolId(groupScopeHelper.resolveSchoolId(rel.getGroupId()));
groupRefs.add(ref);
}
d.setGroups(groupRefs);
// roleList:每个 roleId 一行,schId 取主组学校(userbase 无角色-学校关联)
List<PushUserDTO.PushUserRoleRef> roleRefs = new ArrayList<>();
if (u.getRoles() != null) {
for (Integer roleId : u.getRoles()) {
PushUserDTO.PushUserRoleRef ref = new PushUserDTO.PushUserRoleRef();
ref.setRoleId(roleId);
ref.setSchId(mainSchoolId);
roleRefs.add(ref);
}
}
d.setRoleList(roleRefs);
return d;
}
/** 多个用户(AddUser / UpdateUser / SyncUser)。 */
public List<PushUserDTO> toUserDtoList(List<SysUser> users) {
if (users == null) {
return Collections.emptyList();
}
return users.stream().map(this::toUserDto).collect(Collectors.toList());
}
/** 取用户主组(isMain=1,否则首个关联)所属学校范围 id。 */
private Integer resolveMainSchoolId(List<SysUserGroupRel> rels) {
if (rels == null || rels.isEmpty()) {
return null;
}
Integer mainGroupId = rels.stream()
.filter(r -> r.getIsMain() != null && r.getIsMain() == IS_MAIN)
.map(SysUserGroupRel::getGroupId)
.findFirst()
.orElse(rels.get(0).getGroupId());
return groupScopeHelper.resolveSchoolId(mainGroupId);
}
// ===================== 公共工具 =====================
/** 构建 parentId → 直接子节点列表(null 视为根 0),同层按 sort / id 升序。 */
public Map<Integer, List<SysGroup>> buildChildrenMap(List<SysGroup> all) {
Map<Integer, List<SysGroup>> childrenMap = new HashMap<>();
for (SysGroup g : all) {
Integer key = (g.getParentId() == null) ? ROOT_PARENT_ID : g.getParentId();
childrenMap.computeIfAbsent(key, k -> new ArrayList<>()).add(g);
}
Comparator<SysGroup> order = (a, b) -> {
int sa = a.getSort() == null ? 999 : a.getSort();
int sb = b.getSort() == null ? 999 : b.getSort();
if (sa != sb) {
return Integer.compare(sa, sb);
}
return Integer.compare(a.getId(), b.getId());
};
for (List<SysGroup> siblings : childrenMap.values()) {
siblings.sort(order);
}
return childrenMap;
}
/** 构建整棵组树(从根 pid=0 起),SyncGroup 全量同步入口。 */
public List<PushGroupDTO> buildFullGroupTree() {
List<SysGroup> all = sysGroupRepository.findAll();
if (all.isEmpty()) {
return Collections.emptyList();
}
Map<Integer, List<SysGroup>> childrenMap = buildChildrenMap(all);
List<SysGroup> roots = childrenMap.getOrDefault(ROOT_PARENT_ID, new ArrayList<>());
return roots.stream()
.map(r -> toGroupDtoWithChildren(r, childrenMap))
.collect(Collectors.toList());
}
}