实现单用户多部门支持:创建中间表、实体类、Mapper和多部门操作方法,修改钉钉登录逻辑支持匹配多个部门
This commit is contained in:
parent
f36ec495a2
commit
9dc5b1d9ee
@ -0,0 +1,49 @@
|
|||||||
|
package com.designhub.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
|
import lombok.Data;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户部门关联实体类
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("sys_user_department")
|
||||||
|
public class UserDepartment implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户ID
|
||||||
|
*/
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门ID
|
||||||
|
*/
|
||||||
|
private Long deptId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为主部门:0-否,1-是
|
||||||
|
*/
|
||||||
|
private Integer isPrimary;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@TableField(fill = FieldFill.INSERT)
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
package com.designhub.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.designhub.entity.UserDepartment;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户部门关联Mapper接口
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface UserDepartmentMapper extends BaseMapper<UserDepartment> {
|
||||||
|
}
|
||||||
@ -7,13 +7,16 @@ import com.designhub.dto.LoginDTO;
|
|||||||
import com.designhub.dto.RegisterDTO;
|
import com.designhub.dto.RegisterDTO;
|
||||||
import com.designhub.entity.Department;
|
import com.designhub.entity.Department;
|
||||||
import com.designhub.entity.User;
|
import com.designhub.entity.User;
|
||||||
|
import com.designhub.entity.UserDepartment;
|
||||||
import com.designhub.exception.BusinessException;
|
import com.designhub.exception.BusinessException;
|
||||||
import com.designhub.mapper.UserMapper;
|
import com.designhub.mapper.UserMapper;
|
||||||
import com.designhub.mapper.DepartmentMapper;
|
import com.designhub.mapper.DepartmentMapper;
|
||||||
|
import com.designhub.mapper.UserDepartmentMapper;
|
||||||
import com.designhub.common.ResultCode;
|
import com.designhub.common.ResultCode;
|
||||||
import com.designhub.util.JwtUtil;
|
import com.designhub.util.JwtUtil;
|
||||||
import com.designhub.vo.LoginVO;
|
import com.designhub.vo.LoginVO;
|
||||||
import com.designhub.vo.UserInfoVO;
|
import com.designhub.vo.UserInfoVO;
|
||||||
|
import com.designhub.vo.UserDepartmentVO;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
@ -25,6 +28,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,6 +41,7 @@ public class UserService {
|
|||||||
|
|
||||||
private final UserMapper userMapper;
|
private final UserMapper userMapper;
|
||||||
private final DepartmentMapper departmentMapper;
|
private final DepartmentMapper departmentMapper;
|
||||||
|
private final UserDepartmentMapper userDepartmentMapper;
|
||||||
private final TeamScorePoolService teamScorePoolService;
|
private final TeamScorePoolService teamScorePoolService;
|
||||||
private final RoleService roleService;
|
private final RoleService roleService;
|
||||||
private final DingTalkService dingTalkService;
|
private final DingTalkService dingTalkService;
|
||||||
@ -487,73 +492,52 @@ public class UserService {
|
|||||||
needUpdate = true;
|
needUpdate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 检查部门是否需要更新
|
// 3. 同步部门(支持多部门)
|
||||||
if (dingDepartments != null && !dingDepartments.isEmpty()) {
|
if (dingDepartments != null && !dingDepartments.isEmpty()) {
|
||||||
if (user.getDeptId() != null) {
|
// 匹配多个部门
|
||||||
// 用户已有部门:检查是否需要更新
|
List<Long> matchedDeptIds = matchSystemDepartments(dingDepartments);
|
||||||
Department currentDept = departmentMapper.selectById(user.getDeptId());
|
|
||||||
if (currentDept != null && StringUtils.hasText(currentDept.getDingDeptId())) {
|
if (!matchedDeptIds.isEmpty()) {
|
||||||
// 检查用户是否还在原部门
|
// 同步多个部门到sys_user_department表
|
||||||
boolean stillInDept = dingDepartments.stream()
|
// 第一个匹配的部门作为主部门
|
||||||
.anyMatch(d -> currentDept.getDingDeptId().equals(d.get("dept_id").toString()));
|
Long primaryDeptId = matchedDeptIds.get(0);
|
||||||
|
setUserDepartments(user.getId(), matchedDeptIds, primaryDeptId);
|
||||||
if (!stillInDept) {
|
|
||||||
String newDeptNames = dingDepartments.stream()
|
// 更新sys_user表的主部门(向后兼容)
|
||||||
.map(d -> String.valueOf(d.get("name")))
|
Department primaryDept = departmentMapper.selectById(primaryDeptId);
|
||||||
.collect(Collectors.joining(","));
|
if (primaryDept != null) {
|
||||||
log.warn("用户钉钉部门已变化: userId={}, 原部门={}, 钉钉部门={}",
|
user.setDeptId(primaryDeptId);
|
||||||
user.getId(), currentDept.getDeptName(), newDeptNames);
|
user.setDeptName(primaryDept.getDeptName());
|
||||||
|
// 根据主部门类型设置角色
|
||||||
// 尝试重新匹配部门
|
user.setRoleIds("receiving".equals(primaryDept.getDeptType()) ? "5" : "6");
|
||||||
Long newDeptId = matchSystemDepartment(dingDepartments);
|
|
||||||
if (newDeptId != null && !newDeptId.equals(user.getDeptId())) {
|
|
||||||
Department newDept = departmentMapper.selectById(newDeptId);
|
|
||||||
user.setDeptId(newDeptId);
|
|
||||||
user.setDeptName(newDept.getDeptName());
|
|
||||||
// 根据部门类型设置角色
|
|
||||||
user.setRoleIds("receiving".equals(newDept.getDeptType()) ? "5" : "6");
|
|
||||||
user.setStatus(1); // 启用用户
|
|
||||||
needUpdate = true;
|
|
||||||
log.info("自动同步到新部门: userId={}, 新部门={}",
|
|
||||||
user.getId(), newDept.getDeptName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 用户没有部门:尝试匹配部门
|
|
||||||
Long matchedDeptId = matchSystemDepartment(dingDepartments);
|
|
||||||
if (matchedDeptId != null) {
|
|
||||||
Department dept = departmentMapper.selectById(matchedDeptId);
|
|
||||||
user.setDeptId(matchedDeptId);
|
|
||||||
user.setDeptName(dept.getDeptName());
|
|
||||||
user.setRoleIds("receiving".equals(dept.getDeptType()) ? "5" : "6");
|
|
||||||
user.setStatus(1); // 启用用户
|
user.setStatus(1); // 启用用户
|
||||||
needUpdate = true;
|
needUpdate = true;
|
||||||
log.info("已有用户匹配到部门: userId={}, deptId={}, deptName={}",
|
log.info("同步用户多个部门: userId={}, 部门数量={}, 主部门={}",
|
||||||
user.getId(), matchedDeptId, dept.getDeptName());
|
user.getId(), matchedDeptIds.size(), primaryDept.getDeptName());
|
||||||
} else {
|
}
|
||||||
// 无法匹配,使用第一个可用部门作为默认值
|
} else {
|
||||||
List<Department> availableDepts = departmentMapper.selectList(
|
// 无法匹配,使用第一个可用部门作为默认值
|
||||||
new LambdaQueryWrapper<Department>()
|
List<Department> availableDepts = departmentMapper.selectList(
|
||||||
.eq(Department::getStatus, 1)
|
new LambdaQueryWrapper<Department>()
|
||||||
.eq(Department::getDeleted, 0)
|
.eq(Department::getStatus, 1)
|
||||||
.orderByAsc(Department::getSortOrder)
|
.eq(Department::getDeleted, 0)
|
||||||
.orderByAsc(Department::getId)
|
.orderByAsc(Department::getSortOrder)
|
||||||
);
|
.orderByAsc(Department::getId)
|
||||||
|
);
|
||||||
if (!availableDepts.isEmpty()) {
|
|
||||||
Department defaultDept = availableDepts.get(0);
|
if (!availableDepts.isEmpty()) {
|
||||||
user.setDeptId(defaultDept.getId());
|
Department defaultDept = availableDepts.get(0);
|
||||||
user.setDeptName(defaultDept.getDeptName());
|
setUserDepartments(user.getId(), List.of(defaultDept.getId()), defaultDept.getId());
|
||||||
user.setRoleIds("receiving".equals(defaultDept.getDeptType()) ? "5" : "6");
|
user.setDeptId(defaultDept.getId());
|
||||||
user.setStatus(1); // 启用用户
|
user.setDeptName(defaultDept.getDeptName());
|
||||||
needUpdate = true;
|
user.setRoleIds("receiving".equals(defaultDept.getDeptType()) ? "5" : "6");
|
||||||
log.warn("已有用户无法匹配,使用默认部门: userId={}, deptId={}, deptName={}, 钉钉部门: {}",
|
user.setStatus(1); // 启用用户
|
||||||
user.getId(), defaultDept.getId(), defaultDept.getDeptName(),
|
needUpdate = true;
|
||||||
dingDepartments.stream()
|
log.warn("已有用户无法匹配,使用默认部门: userId={}, deptId={}, deptName={}, 钉钉部门: {}",
|
||||||
.map(d -> String.valueOf(d.get("name")))
|
user.getId(), defaultDept.getId(), defaultDept.getDeptName(),
|
||||||
.collect(Collectors.joining(", ")));
|
dingDepartments.stream()
|
||||||
}
|
.map(d -> String.valueOf(d.get("name")))
|
||||||
|
.collect(Collectors.joining(", ")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -624,8 +608,8 @@ public class UserService {
|
|||||||
// 需要用户手动选择部门类型和具体部门
|
// 需要用户手动选择部门类型和具体部门
|
||||||
log.info("钉钉用户首次登录,创建临时账号: email={}", email);
|
log.info("钉钉用户首次登录,创建临时账号: email={}", email);
|
||||||
|
|
||||||
// 尝试匹配系统部门
|
// 尝试匹配系统部门(支持多部门)
|
||||||
Long matchedDeptId = matchSystemDepartment(dingDepartments);
|
List<Long> matchedDeptIds = matchSystemDepartments(dingDepartments);
|
||||||
String username = detailedInfo != null && detailedInfo.get("job_number") != null
|
String username = detailedInfo != null && detailedInfo.get("job_number") != null
|
||||||
? (String) detailedInfo.get("job_number") : "DT_" + unionId.substring(0, 8);
|
? (String) detailedInfo.get("job_number") : "DT_" + unionId.substring(0, 8);
|
||||||
|
|
||||||
@ -642,15 +626,16 @@ public class UserService {
|
|||||||
user.setStatus(1);
|
user.setStatus(1);
|
||||||
user.setDeleted(0);
|
user.setDeleted(0);
|
||||||
|
|
||||||
if (matchedDeptId != null) {
|
if (!matchedDeptIds.isEmpty()) {
|
||||||
// 自动匹配到部门
|
// 自动匹配到多个部门,第一个作为主部门
|
||||||
Department dept = departmentMapper.selectById(matchedDeptId);
|
Long primaryDeptId = matchedDeptIds.get(0);
|
||||||
user.setDeptId(matchedDeptId);
|
Department primaryDept = departmentMapper.selectById(primaryDeptId);
|
||||||
user.setDeptName(dept.getDeptName());
|
user.setDeptId(primaryDeptId);
|
||||||
// 根据部门类型设置默认角色
|
user.setDeptName(primaryDept.getDeptName());
|
||||||
user.setRoleIds("receiving".equals(dept.getDeptType()) ? "5" : "6");
|
// 根据主部门类型设置默认角色
|
||||||
log.info("自动匹配到系统部门: deptId={}, deptName={}, type={}",
|
user.setRoleIds("receiving".equals(primaryDept.getDeptType()) ? "5" : "6");
|
||||||
matchedDeptId, dept.getDeptName(), dept.getDeptType());
|
log.info("自动匹配到系统部门(多部门): userId={}, 部门数量={}, 主部门={}",
|
||||||
|
username, matchedDeptIds.size(), primaryDept.getDeptName());
|
||||||
} else {
|
} else {
|
||||||
// 无法自动匹配,使用第一个可用部门作为默认值
|
// 无法自动匹配,使用第一个可用部门作为默认值
|
||||||
List<Department> availableDepts = departmentMapper.selectList(
|
List<Department> availableDepts = departmentMapper.selectList(
|
||||||
@ -667,6 +652,7 @@ public class UserService {
|
|||||||
user.setDeptId(defaultDept.getId());
|
user.setDeptId(defaultDept.getId());
|
||||||
user.setDeptName(defaultDept.getDeptName());
|
user.setDeptName(defaultDept.getDeptName());
|
||||||
user.setRoleIds("receiving".equals(defaultDept.getDeptType()) ? "5" : "6");
|
user.setRoleIds("receiving".equals(defaultDept.getDeptType()) ? "5" : "6");
|
||||||
|
matchedDeptIds = List.of(defaultDept.getId());
|
||||||
log.warn("无法自动匹配系统部门,使用默认部门: deptId={}, deptName={}, 钉钉部门: {}",
|
log.warn("无法自动匹配系统部门,使用默认部门: deptId={}, deptName={}, 钉钉部门: {}",
|
||||||
defaultDept.getId(), defaultDept.getDeptName(),
|
defaultDept.getId(), defaultDept.getDeptName(),
|
||||||
dingDepartments.stream()
|
dingDepartments.stream()
|
||||||
@ -686,6 +672,12 @@ public class UserService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
userMapper.insert(user);
|
userMapper.insert(user);
|
||||||
|
|
||||||
|
// 同步多个部门到sys_user_department表
|
||||||
|
if (!matchedDeptIds.isEmpty()) {
|
||||||
|
Long primaryDeptId = matchedDeptIds.get(0);
|
||||||
|
setUserDepartments(user.getId(), matchedDeptIds, primaryDeptId);
|
||||||
|
}
|
||||||
log.info("钉钉用户创建成功: userId={}, username={}, needSelectDept={}",
|
log.info("钉钉用户创建成功: userId={}, username={}, needSelectDept={}",
|
||||||
user.getId(), user.getUsername(), matchedDeptId == null);
|
user.getId(), user.getUsername(), matchedDeptId == null);
|
||||||
|
|
||||||
@ -861,6 +853,43 @@ public class UserService {
|
|||||||
log.warn("检查部门负责人状态失败: userId={}, error={}", user.getId(), e.getMessage());
|
log.warn("检查部门负责人状态失败: userId={}, error={}", user.getId(), e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取用户的所有部门列表
|
||||||
|
List<UserDepartmentVO> departments = List.of();
|
||||||
|
try {
|
||||||
|
List<UserDepartment> userDepts = userDepartmentMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<UserDepartment>()
|
||||||
|
.eq(UserDepartment::getUserId, user.getId())
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!userDepts.isEmpty()) {
|
||||||
|
List<Long> deptIds = userDepts.stream()
|
||||||
|
.map(UserDepartment::getDeptId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
List<Department> depts = departmentMapper.selectBatchIds(deptIds);
|
||||||
|
|
||||||
|
// 构建部门VO列表,保持isPrimary顺序
|
||||||
|
Map<Long, Department> deptMap = depts.stream()
|
||||||
|
.collect(Collectors.toMap(Department::getId, d -> d));
|
||||||
|
|
||||||
|
departments = userDepts.stream()
|
||||||
|
.map(ud -> {
|
||||||
|
Department dept = deptMap.get(ud.getDeptId());
|
||||||
|
if (dept != null) {
|
||||||
|
return UserDepartmentVO.builder()
|
||||||
|
.deptId(dept.getId())
|
||||||
|
.deptName(dept.getDeptName())
|
||||||
|
.isPrimary(ud.getIsPrimary())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
.filter(d -> d != null)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("获取用户部门列表失败: userId={}, error={}", user.getId(), e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
UserInfoVO userInfoVO = UserInfoVO.builder()
|
UserInfoVO userInfoVO = UserInfoVO.builder()
|
||||||
.id(user.getId())
|
.id(user.getId())
|
||||||
.username(user.getUsername())
|
.username(user.getUsername())
|
||||||
@ -870,6 +899,7 @@ public class UserService {
|
|||||||
.avatar(user.getAvatar())
|
.avatar(user.getAvatar())
|
||||||
.deptId(user.getDeptId())
|
.deptId(user.getDeptId())
|
||||||
.deptName(user.getDeptName())
|
.deptName(user.getDeptName())
|
||||||
|
.departments(departments)
|
||||||
.roleIds(user.getRoleIds())
|
.roleIds(user.getRoleIds())
|
||||||
.roles(roleCodes)
|
.roles(roleCodes)
|
||||||
.status(user.getStatus())
|
.status(user.getStatus())
|
||||||
@ -918,4 +948,217 @@ public class UserService {
|
|||||||
.roleIds(user.getRoleIds())
|
.roleIds(user.getRoleIds())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 多部门支持方法 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户的所有部门ID列表
|
||||||
|
*/
|
||||||
|
public List<Long> getUserDepartmentIds(Long userId) {
|
||||||
|
List<UserDepartment> userDepts = userDepartmentMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<UserDepartment>()
|
||||||
|
.eq(UserDepartment::getUserId, userId)
|
||||||
|
);
|
||||||
|
return userDepts.stream()
|
||||||
|
.map(UserDepartment::getDeptId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户的所有部门信息
|
||||||
|
*/
|
||||||
|
public List<Department> getUserDepartments(Long userId) {
|
||||||
|
List<Long> deptIds = getUserDepartmentIds(userId);
|
||||||
|
if (deptIds.isEmpty()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
return departmentMapper.selectBatchIds(deptIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加用户到部门(如果不存在则添加)
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void addUserToDepartment(Long userId, Long deptId, boolean isPrimary) {
|
||||||
|
// 检查是否已存在
|
||||||
|
UserDepartment exist = userDepartmentMapper.selectOne(
|
||||||
|
new LambdaQueryWrapper<UserDepartment>()
|
||||||
|
.eq(UserDepartment::getUserId, userId)
|
||||||
|
.eq(UserDepartment::getDeptId, deptId)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (exist == null) {
|
||||||
|
UserDepartment userDept = new UserDepartment();
|
||||||
|
userDept.setUserId(userId);
|
||||||
|
userDept.setDeptId(deptId);
|
||||||
|
userDept.setIsPrimary(isPrimary ? 1 : 0);
|
||||||
|
userDepartmentMapper.insert(userDept);
|
||||||
|
log.info("添加用户到部门: userId={}, deptId={}, isPrimary={}", userId, deptId, isPrimary);
|
||||||
|
} else if (isPrimary && exist.getIsPrimary() == 0) {
|
||||||
|
// 更新为主部门
|
||||||
|
exist.setIsPrimary(1);
|
||||||
|
userDepartmentMapper.updateById(exist);
|
||||||
|
log.info("设置为主部门: userId={}, deptId={}", userId, deptId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果设置为主部门,需要更新sys_user表的dept_id
|
||||||
|
if (isPrimary) {
|
||||||
|
Department dept = departmentMapper.selectById(deptId);
|
||||||
|
if (dept != null) {
|
||||||
|
User user = userMapper.selectById(userId);
|
||||||
|
if (user != null) {
|
||||||
|
user.setDeptId(deptId);
|
||||||
|
user.setDeptName(dept.getDeptName());
|
||||||
|
userMapper.updateById(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将其他部门设置为非主部门
|
||||||
|
userDepartmentMapper.update(null,
|
||||||
|
new LambdaUpdateWrapper<UserDepartment>()
|
||||||
|
.eq(UserDepartment::getUserId, userId)
|
||||||
|
.ne(UserDepartment::getDeptId, deptId)
|
||||||
|
.set(UserDepartment::getIsPrimary, 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从部门中移除用户
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void removeUserFromDepartment(Long userId, Long deptId) {
|
||||||
|
// 检查是否为主部门
|
||||||
|
UserDepartment userDept = userDepartmentMapper.selectOne(
|
||||||
|
new LambdaQueryWrapper<UserDepartment>()
|
||||||
|
.eq(UserDepartment::getUserId, userId)
|
||||||
|
.eq(UserDepartment::getDeptId, deptId)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (userDept != null && userDept.getIsPrimary() == 1) {
|
||||||
|
// 如果是主部门,需要设置另一个部门为主部门,或清空主部门
|
||||||
|
List<UserDepartment> otherDepts = userDepartmentMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<UserDepartment>()
|
||||||
|
.eq(UserDepartment::getUserId, userId)
|
||||||
|
.ne(UserDepartment::getDeptId, deptId)
|
||||||
|
.last("LIMIT 1")
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!otherDepts.isEmpty()) {
|
||||||
|
// 设置第一个其他部门为主部门
|
||||||
|
UserDepartment newPrimary = otherDepts.get(0);
|
||||||
|
newPrimary.setIsPrimary(1);
|
||||||
|
userDepartmentMapper.updateById(newPrimary);
|
||||||
|
|
||||||
|
Department newDept = departmentMapper.selectById(newPrimary.getDeptId());
|
||||||
|
if (newDept != null) {
|
||||||
|
User user = userMapper.selectById(userId);
|
||||||
|
if (user != null) {
|
||||||
|
user.setDeptId(newDept.getId());
|
||||||
|
user.setDeptName(newDept.getDeptName());
|
||||||
|
userMapper.updateById(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 没有其他部门,清空主部门
|
||||||
|
User user = userMapper.selectById(userId);
|
||||||
|
if (user != null) {
|
||||||
|
user.setDeptId(null);
|
||||||
|
user.setDeptName(null);
|
||||||
|
userMapper.updateById(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除关联
|
||||||
|
userDepartmentMapper.delete(
|
||||||
|
new LambdaQueryWrapper<UserDepartment>()
|
||||||
|
.eq(UserDepartment::getUserId, userId)
|
||||||
|
.eq(UserDepartment::getDeptId, deptId)
|
||||||
|
);
|
||||||
|
log.info("从部门移除用户: userId={}, deptId={}", userId, deptId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置用户的部门列表(替换现有部门)
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void setUserDepartments(Long userId, List<Long> deptIds, Long primaryDeptId) {
|
||||||
|
// 删除所有现有关联
|
||||||
|
userDepartmentMapper.delete(
|
||||||
|
new LambdaQueryWrapper<UserDepartment>()
|
||||||
|
.eq(UserDepartment::getUserId, userId)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 添加新关联
|
||||||
|
if (deptIds != null && !deptIds.isEmpty()) {
|
||||||
|
for (Long deptId : deptIds) {
|
||||||
|
boolean isPrimary = deptId.equals(primaryDeptId);
|
||||||
|
addUserToDepartment(userId, deptId, isPrimary);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 清空部门
|
||||||
|
User user = userMapper.selectById(userId);
|
||||||
|
if (user != null) {
|
||||||
|
user.setDeptId(null);
|
||||||
|
user.setDeptName(null);
|
||||||
|
userMapper.updateById(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 匹配多个系统部门(根据钉钉部门列表)
|
||||||
|
*/
|
||||||
|
private List<Long> matchSystemDepartments(List<Map<String, Object>> dingDepartments) {
|
||||||
|
if (dingDepartments == null || dingDepartments.isEmpty()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取所有系统部门
|
||||||
|
List<Department> systemDepts = departmentMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<Department>()
|
||||||
|
.eq(Department::getStatus, 1)
|
||||||
|
.eq(Department::getDeleted, 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
List<Long> matchedDeptIds = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Map<String, Object> dingDept : dingDepartments) {
|
||||||
|
String dingDeptName = (String) dingDept.get("name");
|
||||||
|
Object dingDeptIdObj = dingDept.get("dept_id");
|
||||||
|
String dingDeptId = dingDeptIdObj != null ? dingDeptIdObj.toString() : null;
|
||||||
|
|
||||||
|
Department matched = null;
|
||||||
|
|
||||||
|
// 1. 优先通过钉钉部门ID精确匹配
|
||||||
|
if (dingDeptId != null) {
|
||||||
|
matched = systemDepts.stream()
|
||||||
|
.filter(d -> dingDeptId.equals(d.getDingDeptId()))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
if (matched != null) {
|
||||||
|
log.info("通过钉钉部门ID精确匹配: {} -> {}", dingDeptId, matched.getDeptName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 通过部门名称模糊匹配
|
||||||
|
if (matched == null && dingDeptName != null) {
|
||||||
|
matched = systemDepts.stream()
|
||||||
|
.filter(d -> d.getDeptName().contains(dingDeptName) ||
|
||||||
|
dingDeptName.contains(d.getDeptName()))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
if (matched != null) {
|
||||||
|
log.info("通过部门名称模糊匹配: {} -> {}", dingDeptName, matched.getDeptName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matched != null && !matchedDeptIds.contains(matched.getId())) {
|
||||||
|
matchedDeptIds.add(matched.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matchedDeptIds;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
26
backend/src/main/java/com/designhub/vo/UserDepartmentVO.java
Normal file
26
backend/src/main/java/com/designhub/vo/UserDepartmentVO.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package com.designhub.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Builder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户部门信息VO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class UserDepartmentVO {
|
||||||
|
/**
|
||||||
|
* 部门ID
|
||||||
|
*/
|
||||||
|
private Long deptId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门名称
|
||||||
|
*/
|
||||||
|
private String deptName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为主部门:0-否,1-是
|
||||||
|
*/
|
||||||
|
private Integer isPrimary;
|
||||||
|
}
|
||||||
@ -42,14 +42,19 @@ public class UserInfoVO {
|
|||||||
private String avatar;
|
private String avatar;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 部门ID
|
* 部门ID(主部门,向后兼容)
|
||||||
*/
|
*/
|
||||||
private Long deptId;
|
private Long deptId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 部门名称
|
* 部门名称(主部门,向后兼容)
|
||||||
*/
|
*/
|
||||||
private String deptName;
|
private String deptName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户的所有部门列表(多部门支持)
|
||||||
|
*/
|
||||||
|
private List<UserDepartmentVO> departments;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 角色ID列表(逗号分隔)
|
* 角色ID列表(逗号分隔)
|
||||||
|
|||||||
25
database/add_user_department_table.sql
Normal file
25
database/add_user_department_table.sql
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
-- 用户部门关联表(支持多部门)
|
||||||
|
-- 创建时间: 2026-01-02
|
||||||
|
-- 说明: 支持单用户属于多个部门
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `sys_user_department` (
|
||||||
|
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`user_id` BIGINT NOT NULL COMMENT '用户ID',
|
||||||
|
`dept_id` BIGINT NOT NULL COMMENT '部门ID',
|
||||||
|
`is_primary` TINYINT DEFAULT 0 COMMENT '是否为主部门:0-否,1-是',
|
||||||
|
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_user_dept` (`user_id`, `dept_id`),
|
||||||
|
KEY `idx_user_id` (`user_id`),
|
||||||
|
KEY `idx_dept_id` (`dept_id`),
|
||||||
|
CONSTRAINT `fk_user_dept_user` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`id`) ON DELETE CASCADE,
|
||||||
|
CONSTRAINT `fk_user_dept_dept` FOREIGN KEY (`dept_id`) REFERENCES `sys_dept` (`id`) ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户部门关联表';
|
||||||
|
|
||||||
|
-- 数据迁移:将现有sys_user表中的dept_id迁移到sys_user_department表
|
||||||
|
INSERT INTO `sys_user_department` (`user_id`, `dept_id`, `is_primary`)
|
||||||
|
SELECT `id`, `dept_id`, 1
|
||||||
|
FROM `sys_user`
|
||||||
|
WHERE `dept_id` IS NOT NULL AND `dept_id` > 0
|
||||||
|
ON DUPLICATE KEY UPDATE `is_primary` = 1;
|
||||||
89
deploy_from_git.sh
Executable file
89
deploy_from_git.sh
Executable file
@ -0,0 +1,89 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
###############################################################################
|
||||||
|
# 从Git拉取代码并部署到服务器
|
||||||
|
# 服务器: 45.192.99.48
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
SERVER_IP="45.192.99.48"
|
||||||
|
SERVER_USER="root"
|
||||||
|
SERVER_PASSWORD="1blZllMIp7"
|
||||||
|
APP_DIR="/opt/designhub"
|
||||||
|
GIT_REPO="http://chenpei:jsjj654321@git.1080p.hk/chenpei/qiangdanxitong.git"
|
||||||
|
|
||||||
|
# 颜色定义
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
echo "========================================"
|
||||||
|
echo -e "${GREEN}从Git拉取代码并部署${NC}"
|
||||||
|
echo "========================================"
|
||||||
|
echo ""
|
||||||
|
echo "服务器: ${SERVER_IP}"
|
||||||
|
echo "Git仓库: ${GIT_REPO}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 检查sshpass
|
||||||
|
if ! command -v sshpass &> /dev/null; then
|
||||||
|
echo "正在安装sshpass..."
|
||||||
|
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||||
|
brew install hudochenkov/sshpass/sshpass 2>/dev/null || {
|
||||||
|
echo -e "${RED}请先安装sshpass: brew install hudochenkov/sshpass/sshpass${NC}"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 在服务器上执行部署
|
||||||
|
sshpass -p "${SERVER_PASSWORD}" ssh -o StrictHostKeyChecking=no ${SERVER_USER}@${SERVER_IP} << ENDSSH
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo -e "${BLUE}[1/6] 检查Git仓库...${NC}"
|
||||||
|
cd ${APP_DIR}
|
||||||
|
|
||||||
|
if [ ! -d ".git" ]; then
|
||||||
|
echo "初始化Git仓库..."
|
||||||
|
# 先暂存现有文件
|
||||||
|
git init
|
||||||
|
git remote add origin ${GIT_REPO} 2>/dev/null || git remote set-url origin ${GIT_REPO}
|
||||||
|
# 添加现有文件到Git
|
||||||
|
git add -A 2>/dev/null || true
|
||||||
|
git commit -m "Backup existing files" 2>/dev/null || true
|
||||||
|
# 拉取最新代码(允许合并)
|
||||||
|
git pull origin main --allow-unrelated-histories || git fetch origin main:main && git checkout main
|
||||||
|
else
|
||||||
|
echo "拉取最新代码..."
|
||||||
|
git fetch origin
|
||||||
|
git reset --hard origin/main
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${BLUE}[2/6] 备份当前JAR文件...${NC}"
|
||||||
|
if [ -f "${APP_DIR}/designhub.jar" ]; then
|
||||||
|
cp ${APP_DIR}/designhub.jar ${APP_DIR}/designhub.jar.backup.\$(date +%Y%m%d_%H%M%S) || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${BLUE}[3/6] 构建后端...${NC}"
|
||||||
|
cd ${APP_DIR}/backend
|
||||||
|
mvn clean package -DskipTests
|
||||||
|
|
||||||
|
echo -e "${BLUE}[4/6] 复制JAR文件...${NC}"
|
||||||
|
cp target/designhub-backend-1.0.0.jar ${APP_DIR}/designhub.jar
|
||||||
|
|
||||||
|
echo -e "${BLUE}[5/6] 重启服务...${NC}"
|
||||||
|
systemctl restart designhub
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}等待服务启动...${NC}"
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${BLUE}[6/6] 检查服务状态...${NC}"
|
||||||
|
systemctl status designhub --no-pager | head -15
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}✅ 部署完成!${NC}"
|
||||||
|
ENDSSH
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}✅ 部署脚本执行完成!${NC}"
|
||||||
35
服务器部署命令.txt
Normal file
35
服务器部署命令.txt
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# 在服务器上执行以下命令部署最新代码
|
||||||
|
|
||||||
|
# 1. 连接到服务器
|
||||||
|
ssh root@45.192.99.48
|
||||||
|
# 密码: 1blZllMIp7
|
||||||
|
|
||||||
|
# 2. 进入项目目录
|
||||||
|
cd /opt/designhub
|
||||||
|
|
||||||
|
# 3. 如果还没有Git仓库,先初始化
|
||||||
|
if [ ! -d ".git" ]; then
|
||||||
|
git init
|
||||||
|
git remote add origin http://chenpei:jsjj654321@git.1080p.hk/chenpei/qiangdanxitong.git
|
||||||
|
git fetch origin
|
||||||
|
git checkout -b main origin/main
|
||||||
|
else
|
||||||
|
# 拉取最新代码
|
||||||
|
git pull origin main
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4. 构建后端
|
||||||
|
cd backend
|
||||||
|
mvn clean package -DskipTests
|
||||||
|
|
||||||
|
# 5. 复制JAR文件
|
||||||
|
cp target/designhub-backend-1.0.0.jar /opt/designhub/designhub.jar
|
||||||
|
|
||||||
|
# 6. 重启服务
|
||||||
|
systemctl restart designhub
|
||||||
|
|
||||||
|
# 7. 检查服务状态
|
||||||
|
systemctl status designhub
|
||||||
|
|
||||||
|
# 8. 查看日志(可选)
|
||||||
|
tail -f /opt/designhub/logs/application.log
|
||||||
Loading…
x
Reference in New Issue
Block a user