187 lines
7.3 KiB
Java
187 lines
7.3 KiB
Java
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());
|
||
}
|
||
}
|