添加员工管理自动导入能力,修复了部门,岗位未显示

This commit is contained in:
2026-07-08 18:49:37 +08:00
parent 349f06b22b
commit 185231948c
6 changed files with 262 additions and 33 deletions

View File

@@ -0,0 +1,136 @@
package com.ruoyi.oa.task;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.hrm.domain.HrmEmployee;
import com.ruoyi.hrm.mapper.HrmEmployeeMapper;
import com.ruoyi.system.mapper.SysUserMapper;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 每日自动把员工挂到对应的 sys_user。
*
* 匹配规则(保守,宁可漏挂不错挂):
* 1. hrm_employee.user_id 已指向存在的 sys_user 且 nick_name/user_name 与 emp_name 一致 → 跳过
* 2. 否则按 emp_name 找候选:先看 nick_name再看 user_name
* 3. 候选唯一 + 手机号也对上 → 自动写 user_id含孤儿修复
* 4. 其余情况打日志报告,交人工处理
*
* xxl-job 调度中心 JobHandler 名称:{@code employeeUserLinkJob}
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class EmployeeUserLinkJob {
private final HrmEmployeeMapper employeeMapper;
private final SysUserMapper userMapper;
@XxlJob("employeeUserLinkJob")
public void run() {
List<HrmEmployee> emps = employeeMapper.selectList(Wrappers.<HrmEmployee>lambdaQuery()
.eq(HrmEmployee::getDelFlag, 0));
List<SysUser> users = userMapper.selectList(Wrappers.<SysUser>lambdaQuery()
.eq(SysUser::getDelFlag, "0"));
Map<Long, SysUser> byUid = users.stream()
.collect(Collectors.toMap(SysUser::getUserId, u -> u, (a, b) -> a));
// 姓名 → 候选。同名可能多人,用 List 装
Map<String, List<SysUser>> byNick = new HashMap<>();
Map<String, List<SysUser>> byUname = new HashMap<>();
for (SysUser u : users) {
if (u.getNickName() != null) {
byNick.computeIfAbsent(u.getNickName().trim(), k -> new java.util.ArrayList<>()).add(u);
}
if (u.getUserName() != null) {
byUname.computeIfAbsent(u.getUserName().trim(), k -> new java.util.ArrayList<>()).add(u);
}
}
int skip = 0, autoFix = 0, needManual = 0;
for (HrmEmployee e : emps) {
SysUser current = e.getUserId() == null ? null : byUid.get(e.getUserId());
if (current != null && nameMatches(current, e.getEmpName())) {
skip++;
continue;
}
List<SysUser> candidates = byNick.getOrDefault(e.getEmpName().trim(), java.util.Collections.emptyList());
if (candidates.isEmpty()) {
candidates = byUname.getOrDefault(e.getEmpName().trim(), java.util.Collections.emptyList());
}
SysUser picked = pickByPhone(candidates, e.getMobile());
if (picked == null) {
XxlJobHelper.log("[需人工] emp_id={} emp_name={} current_user_id={} 候选={} —— " +
"候选唯一且手机匹配才能自动挂",
e.getEmpId(), e.getEmpName(), e.getUserId(),
candidates.stream().map(SysUser::getUserId).collect(Collectors.toList()));
needManual++;
continue;
}
if (Objects.equals(picked.getUserId(), e.getUserId())) {
// 姓名判定失败但 user_id 恰好指向匹配用户;一致跳过
skip++;
continue;
}
HrmEmployee update = new HrmEmployee();
update.setEmpId(e.getEmpId());
update.setUserId(picked.getUserId());
employeeMapper.updateById(update);
XxlJobHelper.log("[已挂] emp_id={} emp_name={} user_id: {} → {} ({} / {})",
e.getEmpId(), e.getEmpName(), e.getUserId(), picked.getUserId(),
picked.getNickName(), picked.getUserName());
autoFix++;
}
String msg = String.format("员工-用户关联体检完成:总数=%d跳过=%d自动修=%d需人工=%d",
emps.size(), skip, autoFix, needManual);
XxlJobHelper.log(msg);
log.info(msg);
}
/**
* 姓名判定sys_user.nick_name 或 user_name 与员工 emp_name 完全一致
*/
private static boolean nameMatches(SysUser u, String empName) {
if (empName == null) return false;
String t = empName.trim();
return t.equals(safeTrim(u.getNickName())) || t.equals(safeTrim(u.getUserName()));
}
/**
* 候选里挑一个:唯一 + 手机号匹配。其余场景返回 null交人工。
*/
private static SysUser pickByPhone(List<SysUser> candidates, String mobile) {
if (candidates == null || candidates.isEmpty()) return null;
if (mobile == null || mobile.trim().isEmpty()) {
// 无手机号无法二次确认,只允许候选唯一时挂
return candidates.size() == 1 ? candidates.get(0) : null;
}
String m = mobile.trim();
List<SysUser> phoneHits = candidates.stream()
.filter(u -> m.equals(safeTrim(u.getPhonenumber())))
.collect(Collectors.toList());
if (phoneHits.size() == 1) return phoneHits.get(0);
// 手机号没能唯一定位:若候选只有一个且姓名对上,也允许挂(无手机号情况)
if (phoneHits.isEmpty() && candidates.size() == 1) return candidates.get(0);
return null;
}
private static String safeTrim(String s) {
return s == null ? "" : s.trim();
}
}