Files
UserBaseService/src/main/java/com/yunhai/userbase/service/ISysUserService.java
T
2026-09-02 10:23:31 +08:00

248 lines
11 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;
import com.yunhai.platform.utils.model.BoaRoleInfo;
import com.yunhai.userbase.model.sysuser.BatchImportResult;
import com.yunhai.userbase.model.sysuser.SysUserGroupDeleteItem;
import com.yunhai.userbase.model.sysuser.SysUserQuery;
import com.yunhai.userbase.model.sysuser.SysUserRequest;
import com.yunhai.userbase.model.sysuser.SysUserVo;
import com.yunhai.userbase.model.sysuser.UserIdentityVo;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
* @author chenx
* @date 2026/7/20 16:14
* @description 系统用户服务接口
*/
public interface ISysUserService {
/** 新增用户:校验密码/手机号/身份证,BCrypt 加密,并写入组用户关联。返回创建后的用户ID。 */
Integer add(SysUserRequest request);
/** 编辑用户;密码为空时不修改密码。 */
void edit(Integer id, SysUserRequest request);
/**
* 批量新增用户:逐条走完整校验(含密码强度),返回创建后的用户ID列表(顺序与入参一致)。
*/
List<Integer> batchAdd(List<SysUserRequest> requests);
/**
* 把用户从指定组中移除;若移除后该用户已无其它组关联,则级联删除用户本身。
*
* @param userId 用户ID
* @param groupId 当前组ID
*/
void deleteFromGroup(Integer userId, Integer groupId);
/**
* 批量把用户从指定组中移除;无其它组关联者级联删除用户本身。
*
* @param userIds 用户ID列表
* @param groupId 当前组ID
*/
void batchDeleteFromGroup(List<Integer> userIds, Integer groupId);
/**
* 开放接口专用:在学校(组)范围内按组解绑用户。<br>
* 与 {@link #deleteFromGroup(Integer, Integer)} 语义一致,但额外强制边界:<br>
* ① groupId 不能等于 schoolId(禁止对学校根组解绑,避免整校移除);<br>
* ② groupId 必须属于 schoolId 子树(禁止跨校解绑)。<br>
* 任意一条不满足即抛异常。
*
* @param userId 用户ID
* @param groupId 当前组ID
* @param schoolId 学校组ID(限定解绑范围)
*/
void deleteFromGroup(Integer userId, Integer groupId, Integer schoolId);
/**
* 开放接口专用:批量删除用户-组关系;每条携带自身 (userId, groupId, schoolId),逐条做上述学校边界校验后解绑。
*
* @param items 待删除项列表({@link SysUserGroupDeleteItem})
*/
void deleteUsers(List<SysUserGroupDeleteItem> items);
/**
* 启用/禁用用户。<br>
*
* @param id 用户ID
* @param disabled true=禁用,false=启用
*/
void changeStatus(Integer id, boolean disabled);
/**
* 批量启用/禁用用户。
*
* @param userIds 用户ID列表
* @param disabled true=禁用,false=启用
*/
void batchChangeStatus(List<Integer> userIds, boolean disabled);
/**
* 分页查询组下用户。<br>
* 依据 query.groupId 与 query.withSub 决定组范围,query.name 做多字段匹配。<br>
*
* @param query 查询条件
* @param pageable 分页与排序
* @return 用户分页
*/
Page<SysUserVo> list(SysUserQuery query, Pageable pageable);
/**
* 查询指定用户当前所属的所有组ID。
*
* @param userId 用户ID
* @return 组ID列表
*/
List<Integer> findGroupIdsByUserId(Integer userId);
/**
* 查询用户身份(管理端「用户身份」回显):后端按所在组解析 schoolId 后返回 {schoolId, roleIds};<br>
* 同一学校多组返回同一 schoolId 与角色并集。前端回显唯一来源(roles 列已停写,不再作为真源)。<br>
* 编辑请求提交时原样携带返回的 {schoolId, roleIds},由后端按 schoolId 全量覆盖写库并对齐。
*
* @param userId 用户ID
* @param groupId 所在组ID(Select 当前选中项;schoolId 解析规则见 {@link com.yunhai.userbase.service.ISysGroupService#resolveSchoolId})
* @return {schoolId, roleIds}
*/
UserIdentityVo getUserIdentity(Integer userId, Integer groupId);
/**
* 批量调整用户所属组:覆盖式更新 sys_user_group_rel。<br>
* 主归属组按三级降级确定:<br>
* ① mainGroupId 显式传入(须 ∈ groupIds,否则 400)→ 所有用户统一置主;<br>
* ② 未传 → 逐用户沿用旧主组(旧主组 ∈ 新 groupIds);<br>
* ③ 旧主组不在新集合 → 取 groupIds 首项(现状行为兜底)。<br>
* ② 级为行为增强:只要用户没把主组勾掉,调整组后主组不动(旧实现按数组顺序随机重指)。
*
* @param userIds 待调整用户ID列表
* @param groupIds 目标组ID列表
* @param mainGroupId 主归属组ID(可选;null 走 ②③ 级降级)
*/
void changeGroups(List<Integer> userIds, List<Integer> groupIds, Integer mainGroupId);
/**
* 开放接口专用:在学校(组)范围内移动用户。<br>
* 语义同 {@link #changeGroups}(覆盖式把用户组归属替换为目标组,目标设为主组),但额外强制:<br>
* ① 用户当前必须已在该学校子树内(至少一个组归属落在 schoolId 子树);<br>
* ② 目标 groupId 必须也在该学校子树内。<br>
* 任意一条不满足即抛异常,禁止跨校移动。
*
* @param userId 待移动用户ID
* @param groupId 目标组ID(移动后的主归属组)
* @param schoolId 学校组ID(限定移动范围,仅允许同校内移动)
*/
void moveUserWithinSchool(Integer userId, Integer groupId, Integer schoolId);
/**
* 调整用户在某组内的排序号(sort_no)。<br>
* sortNo 为 null 时清除排序号,列表回退到 user_id 升序兜底。
*
* @param userId 用户ID
* @param groupId 组ID(排序号按组维度,必须落到具体组)
* @param sortNo 排序号(1~999),可空表示清除
*/
void changeSortNo(Integer userId, Integer groupId, Integer sortNo);
/**
* 批量导入用户:按模板解析 Excel,逐行校验并新增。
* 失败行继续处理,返回成功/失败统计及失败原因。
*
* @param file Excel 文件
* @return 导入结果
*/
BatchImportResult batchImport(MultipartFile file);
/**
* 下载用户批量导入模板(真实 .xlsx):平铺指定组及其所有子孙组,仅填充组名(路径)与组id。
*
* @param groupId 当前组ID(可空,空则取组织树根)
* @param response 直接写入 Excel 流
*/
void downloadImportTemplate(Integer groupId, HttpServletResponse response) throws IOException;
/**
* 导出组下所有用户(含子组)为 Excel:与导入模板同构,末尾追加「用户id」列。<br>
* 组名 / 组id 取每个用户实际所属的主组(isMain=1);密码为密文不可逆,留空。
*
* @param groupId 当前组ID(可空,空则取组织树根)
* @param withSub 是否包含子组:1=含所有子孙组;其它=仅当前组
* @param name 关键字(可选)
* @param response 直接写入 Excel 流
*/
void exportUsers(Integer groupId, Integer withSub, String name, HttpServletResponse response) throws IOException;
/**
* 查询用户的业务角色身份列表(oapi 开放接口专用)。
*
* @param userId 用户ID
* @return 角色身份列表(roleId/roleName + 主归属学校组上下文)
*/
List<BoaRoleInfo> findUserRoles(Integer userId);
/**
* 修改用户密码:先校验旧密码,再写入新密码(BCrypt)。<br>
* oapi 开放接口专用;不加操作日志(避免明文密码入日志)。
*
* @param userId 用户ID
* @param oldPassword 旧密码(须与库中 BCrypt 密文匹配)
* @param newPassword 新密码(弱密码规则校验后加密写入)
*/
void changePassword(Integer userId, String oldPassword, String newPassword);
/**
* 修改用户头像:校验图片(非空/≤20MB/扩展名白名单)→ 压缩 → 存储至 avatar 子目录 →
* 写入 profile_picture。oapi 开放接口专用;返回新头像完整 Web URL。
*
* @param userId 用户ID
* @param file 头像图片文件(multipart)
* @return 新头像完整可访问 URL
*/
String changeProfilePicture(Integer userId, MultipartFile file);
/**
* 开放接口专用:设置用户在指定组上的状态(转出/恢复)。<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);
}