1、分页添加默认项,

2、登录名冲突无"复用/认领"机制,教员永久无法开通账号
3、两条对齐路径对"停用教研室"处理不一致
This commit is contained in:
2026-09-17 15:18:13 +08:00
parent 8c346de4d8
commit 80e91707e6
4 changed files with 92 additions and 17 deletions
@@ -1,5 +1,6 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.common.core.domain.entity.SysUser;
import com.roomroot.common.utils.StringUtils;
import com.roomroot.jwgl.dto.faculty.AddTeacherDTO;
import com.roomroot.jwgl.dto.jys.ElectiveCourseBatchDTO;
@@ -225,7 +226,13 @@ public class JYSController {
if (entity == null) {
return Result.error("教员不存在:" + jybh);
}
return Result.success(orgSyncService.ensureTeacherUser(entity, loginName, password, roleId));
SysUser user = orgSyncService.ensureTeacherUser(entity, loginName, password, roleId);
String expected = StringUtils.hasText(loginName) ? loginName.trim() : jybh;
if (!expected.equals(user.getUserName())) {
return Result.success("登录名 " + expected + " 已被无关账号占用,已自动改用 "
+ user.getUserName(), user.getUserId());
}
return Result.success(user.getUserId());
}
/**
@@ -57,9 +57,10 @@ public interface OrgSyncService {
* @param loginName 登录名(空则取教员编号)
* @param password 初始密码明文(空则取统一初始值)
* @param roleId 角色ID(空则取默认教员角色 101)
* @return 用户编号 USER_ID
* @return 创建/认领到的用户实体(含实际登录名,供调用方提示改名)
*/
Long ensureTeacherUser(JYB jyb, String loginName, String password, Long roleId);
com.roomroot.common.core.domain.entity.SysUser ensureTeacherUser(
JYB jyb, String loginName, String password, Long roleId);
/**
* 教员信息变更后同步账号(调教研室迁移部门、改名、改手机号、离职禁用/复职启用)。
@@ -55,6 +55,9 @@ public class OrgSyncServiceImpl implements OrgSyncService {
if (jysb == null || StringUtils.isBlank(jysb.getJysdh())) {
throw new BusinessException("教研室信息不完整,无法同步组织部门");
}
if (jysb.getTy() != null && jysb.getTy() == 1) {
throw new BusinessException("教研室「" + jysb.getJysmc() + "」已停用,不创建组织部门");
}
// 已映射:校验部门仍存在(被手工删除则重建)
if (jysb.getBmbh() != null) {
SysDept mapped = deptService.selectDeptById(jysb.getBmbh());
@@ -140,7 +143,7 @@ public class OrgSyncServiceImpl implements OrgSyncService {
@Override
@Transactional(rollbackFor = Exception.class)
public Long ensureTeacherUser(JYB jyb, String loginName, String password, Long roleId) {
public SysUser ensureTeacherUser(JYB jyb, String loginName, String password, Long roleId) {
if (jyb == null || StringUtils.isBlank(jyb.getJybh())) {
throw new BusinessException("教员信息不完整,无法创建账号");
}
@@ -148,7 +151,7 @@ public class OrgSyncServiceImpl implements OrgSyncService {
if (jyb.getYhbh() != null) {
SysUser mapped = userService.selectUserById(jyb.getYhbh());
if (mapped != null && !"2".equals(mapped.getDelFlag())) {
return jyb.getYhbh();
return mapped;
}
}
if (jyb.getLzzt() != null && jyb.getLzzt() == 1) {
@@ -160,13 +163,17 @@ public class OrgSyncServiceImpl implements OrgSyncService {
String name = StringUtils.isBlank(loginName) ? jyb.getJybh() : loginName.trim();
SysUser existing = userService.selectUserByUserName(name);
if (existing != null) {
// 孤儿账号(账号在、映射丢失):复用并回填锚点,不重复建号
JYB relink = new JYB();
relink.setJybh(jyb.getJybh());
relink.setYhbh(existing.getUserId());
relink.setBmbh(existing.getDeptId() != null ? existing.getDeptId() : deptId);
jybMapper.updateById(relink);
return existing.getUserId();
if (canClaim(jyb, existing)) {
// 身份吻合(自动建号备注含教员编号,或昵称=教员姓名)→ 认领并回填锚点
JYB relink = new JYB();
relink.setJybh(jyb.getJybh());
relink.setYhbh(existing.getUserId());
relink.setBmbh(existing.getDeptId() != null ? existing.getDeptId() : deptId);
jybMapper.updateById(relink);
return existing;
}
// 身份不符:自动改用 原名_2 后缀,由返回的 SysUser.userName 告知调用方
name = nextAvailableLoginName(name);
}
SysUser user = new SysUser();
user.setUserName(name);
@@ -190,7 +197,27 @@ public class OrgSyncServiceImpl implements OrgSyncService {
upd.setYhbh(user.getUserId());
upd.setBmbh(deptId);
jybMapper.updateById(upd);
return user.getUserId();
return user;
}
/** 同名账号能否认领:自动建号的备注含教员编号,或账号昵称与教员姓名一致 */
private boolean canClaim(JYB jyb, SysUser existing) {
if (existing.getRemark() != null && existing.getRemark().contains(jyb.getJybh())) {
return true;
}
return StringUtils.isNotBlank(jyb.getJyxm())
&& jyb.getJyxm().equals(existing.getNickName());
}
/** 登录名冲突时自动派生可用名:base_2、base_3…… */
private String nextAvailableLoginName(String base) {
for (int i = 2; i <= 99; i++) {
String candidate = base + "_" + i;
if (userService.selectUserByUserName(candidate) == null) {
return candidate;
}
}
throw new BusinessException("登录名 " + base + " 冲突且自动后缀已用尽,请手工指定登录名");
}
@Override
@@ -299,6 +326,8 @@ public class OrgSyncServiceImpl implements OrgSyncService {
wrapper.in(JYB::getJybh, jybhList);
}
List<JYB> list = jybMapper.selectList(wrapper);
// 教研室状态缓存,避免逐行回表
java.util.Map<String, JYSB> officeCache = new java.util.HashMap<>();
for (JYB jyb : list) {
try {
if (jyb.getYhbh() != null) {
@@ -312,8 +341,42 @@ public class OrgSyncServiceImpl implements OrgSyncService {
result.addSkip(jyb.getJyxm() + "" + jyb.getJybh() + "):已离职,不建账号");
continue;
}
Long userId = ensureTeacherUser(jyb, null, null, null);
result.addCreate(jyb.getJyxm() + "" + jyb.getJybh() + "):新建账号 " + jyb.getJybh() + " #" + userId);
// 教研室前置校验:缺失/不存在/停用统一跳过,与 alignDepts 口径一致
if (StringUtils.isBlank(jyb.getJysdh())) {
result.addSkip(jyb.getJyxm() + "" + jyb.getJybh() + "):缺教研室代号,未建账号");
continue;
}
JYSB office = officeCache.computeIfAbsent(jyb.getJysdh(),
jysbMapper::selectById);
if (office == null) {
result.addSkip(jyb.getJyxm() + "" + jyb.getJybh() + "):教研室不存在 " + jyb.getJysdh() + ",未建账号");
continue;
}
if (office.getTy() != null && office.getTy() == 1) {
result.addSkip(jyb.getJyxm() + "" + jyb.getJybh() + "):所属教研室「"
+ office.getJysmc() + "」已停用,未建账号");
continue;
}
// 手机号冲突降级为跳过:教员档案保留,修正/清空号码后可再次对齐
if (StringUtils.isNotBlank(jyb.getSjh())) {
SysUser probe = new SysUser();
probe.setPhonenumber(jyb.getSjh());
if (!userService.checkPhoneUnique(probe)) {
result.addSkip(jyb.getJyxm() + "" + jyb.getJybh() + "):手机号 "
+ jyb.getSjh() + " 已被其它账号占用,请先在教员档案中修改或清空该号码后重新对齐");
continue;
}
}
SysUser user = ensureTeacherUser(jyb, null, null, null);
String actual = user.getUserName();
if (jyb.getJybh().equals(actual)) {
result.addCreate(jyb.getJyxm() + "" + jyb.getJybh() + "):新建账号 "
+ actual + " #" + user.getUserId());
} else {
result.addCreate(jyb.getJyxm() + "" + jyb.getJybh() + "):登录名 "
+ jyb.getJybh() + " 被无关账号占用,已自动改用 " + actual
+ " #" + user.getUserId());
}
} catch (Exception e) {
result.addFail(jyb.getJyxm() + "" + jyb.getJybh() + "):" + e.getMessage());
}
@@ -333,6 +396,10 @@ public class OrgSyncServiceImpl implements OrgSyncService {
if (jysb == null) {
throw new BusinessException("教研室不存在:" + jyb.getJysdh());
}
// 停用教研室不建部门:与 alignDepts 同一口径,必须在降级兜底之前拦截
if (jysb.getTy() != null && jysb.getTy() == 1) {
throw new BusinessException("教研室「" + jysb.getJysmc() + "」已停用,不创建组织部门");
}
try {
return ensureOfficeDept(jysb);
} catch (Exception e) {
@@ -23,7 +23,7 @@ public class PageQuery extends BaseQuery {
*/
@NotNull(message = "页码不能为空")
@Min(value = 1, message = "页码最小为1")
private Integer pageNum;
private Integer pageNum = 1;
/**
* 每页记录数,默认20条,最小1条,最大100条
@@ -31,7 +31,7 @@ public class PageQuery extends BaseQuery {
@NotNull(message = "每页大小不能为空")
@Min(value = 1, message = "每页最小为1条")
@Max(value = 100, message = "每页最大为100条")
private Integer pageSize;
private Integer pageSize = 10;
public PageQuery() {}