1、停用教员的同时禁用该教员的账号;

2、教员导入的时候,如果有错误,跳过并返回具体报错行;
3、教研室接口权限添加控制
This commit is contained in:
2026-09-17 14:35:06 +08:00
parent 95a3571c69
commit 8c346de4d8
5 changed files with 157 additions and 22 deletions
@@ -0,0 +1,32 @@
package com.roomroot.jwgl.dto.faculty;
import com.roomroot.jwgl.entity.JYB;
import lombok.Data;
/**
* 教员(教员表)导入行解析结果。
* <p>
* 保留 Excel 中的原始行号,便于把校验失败原因定位到具体行。
* </p>
*/
@Data
public class TeacherImportRowDTO {
/**
* Excel 行号(1 起始,含表头行)。
*/
private int rowNum;
/**
* 该行解析出的教员实体。
*/
private JYB entity;
public TeacherImportRowDTO() {
}
public TeacherImportRowDTO(int rowNum, JYB entity) {
this.rowNum = rowNum;
this.entity = entity;
}
}
@@ -3,6 +3,7 @@ package com.roomroot.jwgl.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.roomroot.jwgl.dto.faculty.AddTeacherDTO;
import com.roomroot.jwgl.dto.faculty.TeacherImportRowDTO;
import com.roomroot.jwgl.entity.*;
import com.roomroot.jwgl.mapper.*;
import com.roomroot.jwgl.mapper.*;
@@ -20,6 +21,7 @@ import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
/**
@@ -320,33 +322,53 @@ public class FacultyServiceImpl implements FacultyService {
if (file == null || file.isEmpty()) {
throw new BusinessException("导入文件不能为空");
}
List<JYB> list = ExcelParseUtil.parseJYBExcel(
List<TeacherImportRowDTO> rows = ExcelParseUtil.parseJYBExcel(
file.getInputStream(), file.getOriginalFilename());
if (list.isEmpty()) {
if (rows.isEmpty()) {
throw new BusinessException("Excel中无有效数据");
}
for (int i = 0; i < list.size(); i++) {
JYB entity = list.get(i);
// Excel 第 1 行为抬头,故数据行号 = 下标 + 2
int rowNo = i + 2;
// 第一轮:逐行校验聚合报错(不回写任何数据)
List<String> errors = new ArrayList<>();
java.util.Set<String> seenJybh = new java.util.HashSet<>();
for (TeacherImportRowDTO row : rows) {
JYB entity = row.getEntity();
int rowNo = row.getRowNum();
if (isBlank(entity.getJyxm())) {
throw new BusinessException("" + rowNo + " 行:教员姓名未填写");
errors.add("" + rowNo + " 行:教员姓名未填写");
}
// 教研室代号为非空外键,缺失会直接抛数据库非空约束异常,这里给出可定位的提示
if (isBlank(entity.getJysdh())) {
throw new BusinessException("" + rowNo + " 行:教研室代号未填写");
errors.add("" + rowNo + " 行:教研室代号未填写");
} else if (jysbMapper.selectById(entity.getJysdh().trim()) == null) {
errors.add("" + rowNo + " 行:教研室代号不存在 " + entity.getJysdh());
}
// 编号为空自动生成
if (!isBlank(entity.getJybh())) {
String jybh = entity.getJybh().trim();
if (jybMapper.selectById(jybh) != null) {
errors.add("" + rowNo + " 行:教员编号已存在 " + jybh);
} else if (!seenJybh.add(jybh)) {
errors.add("" + rowNo + " 行:教员编号在文件内重复 " + jybh);
}
}
}
if (!errors.isEmpty()) {
throw new BusinessException("导入失败,共 " + errors.size() + " 行校验未通过:\n"
+ String.join("\n", errors));
}
// 第二轮:全部校验通过才入库(事务内,任一异常整批回滚)
for (TeacherImportRowDTO row : rows) {
JYB entity = row.getEntity();
if (isBlank(entity.getJybh())) {
entity.setJybh(nextJybh());
} else if (jybMapper.selectById(entity.getJybh().trim()) != null) {
throw new BusinessException("" + rowNo + " 行:教员编号已存在 " + entity.getJybh());
} else {
entity.setJybh(entity.getJybh().trim());
}
entity.setJysdh(entity.getJysdh().trim());
// 离职状态等非空列兜底(数据库缺省值在 MyBatis-Plus 下不会生效)
applyTeacherDefaults(entity);
jybMapper.insert(entity);
}
return list.size();
return rows.size();
}
@Override
@@ -158,11 +158,18 @@ public class OrgSyncServiceImpl implements OrgSyncService {
Long deptId = resolveTeacherDeptId(jyb);
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();
}
SysUser user = new SysUser();
user.setUserName(name);
if (userService.selectUserByUserName(name) != null) {
throw new BusinessException("登录名已存在:" + name);
}
user.setNickName(jyb.getJyxm());
user.setDeptId(deptId);
user.setPhonenumber(jyb.getSjh());
@@ -189,10 +196,23 @@ public class OrgSyncServiceImpl implements OrgSyncService {
@Override
@Transactional(rollbackFor = Exception.class)
public void syncTeacherAccount(JYB before, JYB after) {
if (before == null || before.getYhbh() == null) {
if (before == null) {
return;
}
SysUser user = userService.selectUserById(before.getYhbh());
SysUser user = null;
if (before.getYhbh() != null) {
user = userService.selectUserById(before.getYhbh());
}
if (user == null && StringUtils.isNotBlank(before.getJybh())) {
// 锚点缺失(账号存在但教员表.用户编号未回填):按登录名=教员编号兜底定位孤儿账号并回填
user = userService.selectUserByUserName(before.getJybh());
if (user != null && !"2".equals(user.getDelFlag())) {
JYB relink = new JYB();
relink.setJybh(before.getJybh());
relink.setYhbh(user.getUserId());
jybMapper.updateById(relink);
}
}
if (user == null || "2".equals(user.getDelFlag())) {
return;
}
@@ -5,6 +5,7 @@ import com.roomroot.jwgl.dto.courserunning.SemesterImportDTO;
import com.roomroot.jwgl.dto.courserunning.SingleCourseImportDTO;
import com.roomroot.jwgl.dto.departmentpersonnel.DepartmentPersonnelCreateDTO;
import com.roomroot.jwgl.dto.discipline.MajorImportRowDTO;
import com.roomroot.jwgl.dto.faculty.TeacherImportRowDTO;
import com.roomroot.jwgl.entity.JXSSJH;
import com.roomroot.jwgl.entity.JYB;
import com.roomroot.jwgl.entity.JYSB;
@@ -401,8 +402,8 @@ public class ExcelParseUtil {
* @return 教员实体列表(离职状态由业务层默认填充)
* @throws Exception 解析异常
*/
public static List<JYB> parseJYBExcel(InputStream inputStream, String fileName) throws Exception {
List<JYB> result = new ArrayList<>();
public static List<TeacherImportRowDTO> parseJYBExcel(InputStream inputStream, String fileName) throws Exception {
List<TeacherImportRowDTO> result = new ArrayList<>();
Workbook workbook = createWorkbook(inputStream, fileName);
try {
Sheet sheet = workbook.getSheetAt(0);
@@ -425,10 +426,14 @@ public class ExcelParseUtil {
entity.setBz(getCellStringValue(row.getCell(9)));
entity.setXh(getCellStringValue(row.getCell(10)));
entity.setXslx(parseIntCell(row.getCell(11)));
// 至少要有姓名才视为有效行
if (entity.getJyxm() != null && !entity.getJyxm().isEmpty()) {
result.add(entity);
// 整行全空的跳过;有任何字段即保留,由业务层逐行校验并聚合报错
if (isAllBlank(entity.getJybh(), entity.getJyxm(), entity.getJysdh(),
entity.getZc(), entity.getZyjszwdj(), entity.getJylb(),
entity.getSjh(), entity.getSfzh(), entity.getBz(), entity.getXh())
&& entity.getXb() == null && entity.getXslx() == null) {
continue;
}
result.add(new TeacherImportRowDTO(rowNum + 1, entity));
}
} finally {
workbook.close();
@@ -436,6 +441,15 @@ public class ExcelParseUtil {
return result;
}
private static boolean isAllBlank(String... values) {
for (String v : values) {
if (v != null && !v.trim().isEmpty()) {
return false;
}
}
return true;
}
/**
* 解析培养方案(专业表)导入 Excel 文件(支持 .xls / .xlsx)。
* <p>表头顺序:</p>