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; package com.roomroot.web.controller.jwgl;
import com.roomroot.common.core.domain.entity.SysUser;
import com.roomroot.common.utils.StringUtils; import com.roomroot.common.utils.StringUtils;
import com.roomroot.jwgl.dto.faculty.AddTeacherDTO; import com.roomroot.jwgl.dto.faculty.AddTeacherDTO;
import com.roomroot.jwgl.dto.jys.ElectiveCourseBatchDTO; import com.roomroot.jwgl.dto.jys.ElectiveCourseBatchDTO;
@@ -225,7 +226,13 @@ public class JYSController {
if (entity == null) { if (entity == null) {
return Result.error("教员不存在:" + jybh); 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 loginName 登录名(空则取教员编号)
* @param password 初始密码明文(空则取统一初始值) * @param password 初始密码明文(空则取统一初始值)
* @param roleId 角色ID(空则取默认教员角色 101) * @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())) { if (jysb == null || StringUtils.isBlank(jysb.getJysdh())) {
throw new BusinessException("教研室信息不完整,无法同步组织部门"); throw new BusinessException("教研室信息不完整,无法同步组织部门");
} }
if (jysb.getTy() != null && jysb.getTy() == 1) {
throw new BusinessException("教研室「" + jysb.getJysmc() + "」已停用,不创建组织部门");
}
// 已映射:校验部门仍存在(被手工删除则重建) // 已映射:校验部门仍存在(被手工删除则重建)
if (jysb.getBmbh() != null) { if (jysb.getBmbh() != null) {
SysDept mapped = deptService.selectDeptById(jysb.getBmbh()); SysDept mapped = deptService.selectDeptById(jysb.getBmbh());
@@ -140,7 +143,7 @@ public class OrgSyncServiceImpl implements OrgSyncService {
@Override @Override
@Transactional(rollbackFor = Exception.class) @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())) { if (jyb == null || StringUtils.isBlank(jyb.getJybh())) {
throw new BusinessException("教员信息不完整,无法创建账号"); throw new BusinessException("教员信息不完整,无法创建账号");
} }
@@ -148,7 +151,7 @@ public class OrgSyncServiceImpl implements OrgSyncService {
if (jyb.getYhbh() != null) { if (jyb.getYhbh() != null) {
SysUser mapped = userService.selectUserById(jyb.getYhbh()); SysUser mapped = userService.selectUserById(jyb.getYhbh());
if (mapped != null && !"2".equals(mapped.getDelFlag())) { if (mapped != null && !"2".equals(mapped.getDelFlag())) {
return jyb.getYhbh(); return mapped;
} }
} }
if (jyb.getLzzt() != null && jyb.getLzzt() == 1) { 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(); String name = StringUtils.isBlank(loginName) ? jyb.getJybh() : loginName.trim();
SysUser existing = userService.selectUserByUserName(name); SysUser existing = userService.selectUserByUserName(name);
if (existing != null) { if (existing != null) {
// 孤儿账号(账号在、映射丢失):复用并回填锚点,不重复建号 if (canClaim(jyb, existing)) {
JYB relink = new JYB(); // 身份吻合(自动建号备注含教员编号,或昵称=教员姓名)→ 认领并回填锚点
relink.setJybh(jyb.getJybh()); JYB relink = new JYB();
relink.setYhbh(existing.getUserId()); relink.setJybh(jyb.getJybh());
relink.setBmbh(existing.getDeptId() != null ? existing.getDeptId() : deptId); relink.setYhbh(existing.getUserId());
jybMapper.updateById(relink); relink.setBmbh(existing.getDeptId() != null ? existing.getDeptId() : deptId);
return existing.getUserId(); jybMapper.updateById(relink);
return existing;
}
// 身份不符:自动改用 原名_2 后缀,由返回的 SysUser.userName 告知调用方
name = nextAvailableLoginName(name);
} }
SysUser user = new SysUser(); SysUser user = new SysUser();
user.setUserName(name); user.setUserName(name);
@@ -190,7 +197,27 @@ public class OrgSyncServiceImpl implements OrgSyncService {
upd.setYhbh(user.getUserId()); upd.setYhbh(user.getUserId());
upd.setBmbh(deptId); upd.setBmbh(deptId);
jybMapper.updateById(upd); 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 @Override
@@ -299,6 +326,8 @@ public class OrgSyncServiceImpl implements OrgSyncService {
wrapper.in(JYB::getJybh, jybhList); wrapper.in(JYB::getJybh, jybhList);
} }
List<JYB> list = jybMapper.selectList(wrapper); List<JYB> list = jybMapper.selectList(wrapper);
// 教研室状态缓存,避免逐行回表
java.util.Map<String, JYSB> officeCache = new java.util.HashMap<>();
for (JYB jyb : list) { for (JYB jyb : list) {
try { try {
if (jyb.getYhbh() != null) { if (jyb.getYhbh() != null) {
@@ -312,8 +341,42 @@ public class OrgSyncServiceImpl implements OrgSyncService {
result.addSkip(jyb.getJyxm() + "" + jyb.getJybh() + "):已离职,不建账号"); result.addSkip(jyb.getJyxm() + "" + jyb.getJybh() + "):已离职,不建账号");
continue; continue;
} }
Long userId = ensureTeacherUser(jyb, null, null, null); // 教研室前置校验:缺失/不存在/停用统一跳过,与 alignDepts 口径一致
result.addCreate(jyb.getJyxm() + "" + jyb.getJybh() + "):新建账号 " + jyb.getJybh() + " #" + userId); 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) { } catch (Exception e) {
result.addFail(jyb.getJyxm() + "" + jyb.getJybh() + "):" + e.getMessage()); result.addFail(jyb.getJyxm() + "" + jyb.getJybh() + "):" + e.getMessage());
} }
@@ -333,6 +396,10 @@ public class OrgSyncServiceImpl implements OrgSyncService {
if (jysb == null) { if (jysb == null) {
throw new BusinessException("教研室不存在:" + jyb.getJysdh()); throw new BusinessException("教研室不存在:" + jyb.getJysdh());
} }
// 停用教研室不建部门:与 alignDepts 同一口径,必须在降级兜底之前拦截
if (jysb.getTy() != null && jysb.getTy() == 1) {
throw new BusinessException("教研室「" + jysb.getJysmc() + "」已停用,不创建组织部门");
}
try { try {
return ensureOfficeDept(jysb); return ensureOfficeDept(jysb);
} catch (Exception e) { } catch (Exception e) {
@@ -23,7 +23,7 @@ public class PageQuery extends BaseQuery {
*/ */
@NotNull(message = "页码不能为空") @NotNull(message = "页码不能为空")
@Min(value = 1, message = "页码最小为1") @Min(value = 1, message = "页码最小为1")
private Integer pageNum; private Integer pageNum = 1;
/** /**
* 每页记录数,默认20条,最小1条,最大100条 * 每页记录数,默认20条,最小1条,最大100条
@@ -31,7 +31,7 @@ public class PageQuery extends BaseQuery {
@NotNull(message = "每页大小不能为空") @NotNull(message = "每页大小不能为空")
@Min(value = 1, message = "每页最小为1条") @Min(value = 1, message = "每页最小为1条")
@Max(value = 100, message = "每页最大为100条") @Max(value = 100, message = "每页最大为100条")
private Integer pageSize; private Integer pageSize = 10;
public PageQuery() {} public PageQuery() {}