diff --git a/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/JYSController.java b/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/JYSController.java index ccc78900..fb76d9d9 100644 --- a/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/JYSController.java +++ b/backend/roomroot-admin/src/main/java/com/roomroot/web/controller/jwgl/JYSController.java @@ -32,6 +32,7 @@ import com.roomroot.jwgl.vo.faculty.TeacherListVO; import com.roomroot.jwgl.vo.jys.ElectiveCourseVO; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -68,6 +69,7 @@ public class JYSController { /** * 新增教研室 */ + @PreAuthorize("@ss.hasPermi('teach:office:list')") @PostMapping("/office/add") public Result addOffice(@RequestBody JYSB entity, @RequestParam(required = false) Boolean syncDept) { @@ -82,6 +84,7 @@ public class JYSController { * 001 001 军事基础教研室 军基 基础部 * @param jysdh 教研室代号 */ + @PreAuthorize("@ss.hasPermi('teach:office:list')") @PostMapping("/office/disable") public Result disableOffice(@RequestParam("jysdh") String jysdh, @RequestParam(required = false) Boolean syncDept) { @@ -92,6 +95,7 @@ public class JYSController { /** * 更新教研室 */ + @PreAuthorize("@ss.hasPermi('teach:office:list')") @PostMapping("/office/update") public Result updateOffice(@RequestBody JYSB entity, @RequestParam(required = false) Boolean syncDeptName) { @@ -102,6 +106,7 @@ public class JYSController { /** * 单个教研室补建/对齐组织部门(幂等:已关联则直接返回部门编号)。 */ + @PreAuthorize("@ss.hasPermi('teach:office:list')") @PostMapping("/office/sync-dept") public Result syncOfficeDept(@RequestParam("jysdh") String jysdh) { JYSB entity = facultyService.getJYSBById(jysdh); @@ -115,6 +120,7 @@ public class JYSController { * 对齐组织部门:为教研室批量创建/复用组织部门(直接执行,幂等)。 * body:{ "ids": ["JYS01", ...] };ids 不传 = 全部教研室。 */ + @PreAuthorize("@ss.hasPermi('teach:office:list')") @PostMapping("/org/align-dept") public Result alignDepts( @RequestBody(required = false) java.util.Map> body) { @@ -127,6 +133,7 @@ public class JYSController { * * @param jysdh 教研室代号 */ + @PreAuthorize("@ss.hasPermi('teach:office:list')") @GetMapping("/office/get") public Result getOffice(@RequestParam("jysdh") String jysdh) { JYSB entity = facultyService.getJYSBById(jysdh); @@ -143,6 +150,7 @@ public class JYSController { * *

*/ + @PreAuthorize("@ss.hasPermi('teach:office:list')") @GetMapping("/office/list") public Result> listOffice( @RequestParam(defaultValue = "1") Integer pageNum, @@ -172,6 +180,7 @@ public class JYSController { * 未填写时返回"XX未填写";序号、停用、虚实类型等非空字段由后台自动填充。 *

*/ + @PreAuthorize("@ss.hasPermi('teach:office:list')") @PostMapping("/office/import") public Result importOffice(@RequestParam("file") MultipartFile file, @RequestParam(required = false) Boolean syncDept) throws Exception { @@ -184,6 +193,7 @@ public class JYSController { * 新增教员(同时写入教员表和教员属性表) *

教员属性中的非空字段由前端一并传入。

*/ + @PreAuthorize("@ss.hasPermi('teach:teacher:list')") @PostMapping("/teacher/add") public Result addTeacher(@RequestBody AddTeacherDTO dto) { facultyService.addJYB(dto); @@ -195,6 +205,7 @@ public class JYSController { * * @param jybh 教员编号 */ + @PreAuthorize("@ss.hasPermi('teach:teacher:list')") @PostMapping("/teacher/disable") public Result disableTeacher(@RequestParam("jybh") String jybh) { facultyService.disableJYB(jybh); @@ -204,6 +215,7 @@ public class JYSController { /** * 单个教员补建/对齐系统账号(幂等:已有账号直接返回用户编号)。 */ + @PreAuthorize("@ss.hasPermi('teach:teacher:list')") @PostMapping("/teacher/sync-user") public Result syncTeacherUser(@RequestParam("jybh") String jybh, @RequestParam(required = false) String loginName, @@ -220,6 +232,7 @@ public class JYSController { * 对齐到用户表:为无账号教员批量建账号(直接执行,幂等,逐条返回明细)。 * body:{ "ids": ["JY01", ...] };ids 不传 = 全部无账号教员。 */ + @PreAuthorize("@ss.hasPermi('teach:teacher:list')") @PostMapping("/teacher/align-user") public Result alignUsers( @RequestBody(required = false) java.util.Map> body) { @@ -230,6 +243,7 @@ public class JYSController { /** * 一键对齐:先对齐组织部门、再对齐用户账号(同一事务,幂等)。 */ + @PreAuthorize("@ss.hasPermi('teach:office:list') and @ss.hasPermi('teach:teacher:list')") @PostMapping("/org/align-apply") public Result> alignApply() { java.util.Map result = @@ -243,6 +257,7 @@ public class JYSController { * 更新教员基本信息 *

支持教学单位调整(修改教研室代号)、职称调整(修改职称、专业技术职务等级)。

*/ + @PreAuthorize("@ss.hasPermi('teach:teacher:list')") @PostMapping("/teacher/update") public Result updateTeacher(@RequestBody JYB entity) { facultyService.updateJYB(entity); @@ -254,6 +269,7 @@ public class JYSController { * * @param jybh 教员编号 */ + @PreAuthorize("@ss.hasPermi('teach:teacher:list')") @GetMapping("/teacher/get") public Result getTeacher(@RequestParam("jybh") String jybh) { JYB entity = facultyService.getJYBById(jybh); @@ -272,6 +288,7 @@ public class JYSController { * *

*/ + @PreAuthorize("@ss.hasPermi('teach:teacher:list')") @GetMapping("/teacher/list") public Result> listTeacher( @RequestParam(defaultValue = "1") Integer pageNum, @@ -297,6 +314,7 @@ public class JYSController { *

表头顺序:教员编号, 教员姓名, 教研室代号, 职称, 专业技术职务等级, 教员类别, * 性别, 手机号, 身份证号, 备注, 序号, 虚实类型。教员编号不填自动创建,离职状态默认 0。

*/ + @PreAuthorize("@ss.hasPermi('teach:teacher:list')") @PostMapping("/teacher/import") public Result importTeacher(@RequestParam("file") MultipartFile file) throws Exception { int count = facultyService.importJYBFromExcel(file); @@ -306,6 +324,7 @@ public class JYSController { /** * 导出全部在职教员到 Excel(.xlsx)。 */ + @PreAuthorize("@ss.hasPermi('teach:teacher:list')") @GetMapping("/teacher/export") public void exportTeacher(HttpServletResponse response) throws Exception { facultyService.exportJYBExcel(response); @@ -318,6 +337,7 @@ public class JYSController { * * @param jybh 教员编号 */ + @PreAuthorize("@ss.hasPermi('teach:teacher:list')") @GetMapping("/teacher/attribute/get") public Result getTeacherAttribute(@RequestParam("jybh") String jybh) { JYSX entity = facultyService.getJYSXByJYBH(jybh); @@ -328,6 +348,7 @@ public class JYSController { * 更新教员属性 *

支持岗位调整(修改职务、职务时间)和技术等级调整(修改技术等级、技术等级时间)。

*/ + @PreAuthorize("@ss.hasPermi('teach:teacher:list')") @PostMapping("/teacher/attribute/update") public Result updateTeacherAttribute(@RequestBody JYSX entity) { facultyService.updateJYSX(entity); @@ -343,6 +364,7 @@ public class JYSController { * @param entity 课表实体 * @return 操作结果 */ + @PreAuthorize("@ss.hasPermi('teach:subject:list')") @PostMapping("/kb/add") public Result addKb(@RequestBody KB entity) { kbService.add(entity); @@ -356,6 +378,7 @@ public class JYSController { * @param kbh 课编号 * @return 操作结果 */ + @PreAuthorize("@ss.hasPermi('teach:subject:list')") @PostMapping("/kb/delete") public Result deleteKb(@RequestParam("kbh") String kbh) { kbService.delete(kbh); @@ -368,6 +391,7 @@ public class JYSController { * @param entity 课表实体(须含课编号) * @return 操作结果 */ + @PreAuthorize("@ss.hasPermi('teach:subject:list')") @PostMapping("/kb/update") public Result updateKb(@RequestBody KB entity) { kbService.update(entity); @@ -380,6 +404,7 @@ public class JYSController { * @param kbh 课编号 * @return 课表详情 */ + @PreAuthorize("@ss.hasPermi('teach:subject:list')") @GetMapping("/kb/get") public Result getKb(@RequestParam("kbh") String kbh) { return Result.success(kbService.getByKbh(kbh)); @@ -399,6 +424,7 @@ public class JYSController { * @param jc 简称(模糊,可选) * @return 分页结果 */ + @PreAuthorize("@ss.hasPermi('teach:subject:list')") @GetMapping("/kb/list") public Result> listKb( @RequestParam(defaultValue = "1") Integer pageNum, @@ -430,6 +456,7 @@ public class JYSController { * 支持按授课教员、课程科目名称、可选班次年级、选修班名称、选择课状态、培训层次筛选。 *

*/ + @PreAuthorize("@ss.hasPermi('teach:elective:list')") @GetMapping("/elective/list") public Result> listElective( @RequestParam(defaultValue = "1") Integer pageNum, @@ -453,6 +480,7 @@ public class JYSController { /** * 新建选修课。 */ + @PreAuthorize("@ss.hasPermi('teach:elective:list')") @PostMapping("/elective/add") public Result addElective(@RequestBody ElectiveCourseSaveDTO dto) { electiveCourseService.add(dto); @@ -462,6 +490,7 @@ public class JYSController { /** * 所选批量开放报名。 */ + @PreAuthorize("@ss.hasPermi('teach:elective:list')") @PostMapping("/elective/batch-open") public Result batchOpenElective(@RequestBody ElectiveCourseBatchDTO dto) { int count = electiveCourseService.batchOpenRegistration(dto == null ? null : dto.getBhList()); @@ -471,6 +500,7 @@ public class JYSController { /** * 所选批量取消开放报名。 */ + @PreAuthorize("@ss.hasPermi('teach:elective:list')") @PostMapping("/elective/batch-cancel-open") public Result batchCancelOpenElective(@RequestBody ElectiveCourseBatchDTO dto) { int count = electiveCourseService.batchCancelOpenRegistration(dto == null ? null : dto.getBhList()); @@ -480,6 +510,7 @@ public class JYSController { /** * 批量停止报名。 */ + @PreAuthorize("@ss.hasPermi('teach:elective:list')") @PostMapping("/elective/batch-stop") public Result batchStopElective(@RequestBody ElectiveCourseBatchDTO dto) { int count = electiveCourseService.batchStopRegistration(dto == null ? null : dto.getBhList()); @@ -489,6 +520,7 @@ public class JYSController { /** * 所选批量根据学员反向确定班次范围。 */ + @PreAuthorize("@ss.hasPermi('teach:elective:list')") @PostMapping("/elective/batch-reverse-range") public Result batchReverseRangeElective(@RequestBody ElectiveCourseBatchDTO dto) { int count = electiveCourseService.batchReverseClassRange(dto == null ? null : dto.getBhList()); @@ -498,6 +530,7 @@ public class JYSController { /** * 下载选修班列表。 */ + @PreAuthorize("@ss.hasPermi('teach:elective:list')") @GetMapping("/elective/export") public void exportElective( @RequestParam(required = false) String jyxm, @@ -520,6 +553,7 @@ public class JYSController { /** * 下载选修班学员名单 Excel。 */ + @PreAuthorize("@ss.hasPermi('teach:elective:list')") @GetMapping("/elective/students/export-excel") public void exportElectiveStudentExcel(@RequestParam("bhList") List bhList, HttpServletResponse response) { @@ -529,6 +563,7 @@ public class JYSController { /** * 下载选修班学员名单 Word。 */ + @PreAuthorize("@ss.hasPermi('teach:elective:list')") @GetMapping("/elective/students/export-word") public void exportElectiveStudentWord(@RequestParam("bhList") List bhList, HttpServletResponse response) { @@ -540,6 +575,7 @@ public class JYSController { /** * 上传选修课数据。 */ + @PreAuthorize("@ss.hasPermi('teach:elective:list')") @PostMapping("/elective/import") public Result importElective(@RequestParam("file") MultipartFile file) throws Exception { int count = electiveCourseService.importData(file); @@ -552,6 +588,7 @@ public class JYSController { * 分页查询教学任务列表。 *

含教研室数、学员队数、合班前后课程任务数和学时。未传年度时按当前学期。

*/ + @PreAuthorize("@ss.hasPermi('teach:taskPlan:list')") @GetMapping("/task/list") public Result> listTask( @RequestParam(defaultValue = "1") Integer pageNum, @@ -571,6 +608,7 @@ public class JYSController { /** * 教学任务详情(含教研室任务书、学员队两个页签)。 */ + @PreAuthorize("@ss.hasPermi('teach:taskPlan:list')") @GetMapping("/task/get") public Result getTask(@RequestParam("bh") String bh) { return Result.success(teachingTaskManageService.getDetail(bh)); @@ -580,6 +618,7 @@ public class JYSController { * 新增教学任务。 *

机关发布;关联学员队后按专业教学计划和课表归属教研室生成教研室任务书。

*/ + @PreAuthorize("@ss.hasPermi('teach:taskPlan:list')") @PostMapping("/task/add") public Result addTask(@RequestBody TeachingTaskSaveDTO dto) { teachingTaskManageService.add(dto); @@ -589,6 +628,7 @@ public class JYSController { /** * 编辑教学任务。 */ + @PreAuthorize("@ss.hasPermi('teach:taskPlan:list')") @PostMapping("/task/update") public Result updateTask(@RequestBody TeachingTaskSaveDTO dto) { teachingTaskManageService.update(dto); @@ -598,6 +638,7 @@ public class JYSController { /** * 删除教学任务(同时逻辑删除教研室任务书,并解除学员队关联)。 */ + @PreAuthorize("@ss.hasPermi('teach:taskPlan:list')") @PostMapping("/task/delete") public Result deleteTask(@RequestParam("bh") String bh) { teachingTaskManageService.delete(bh); @@ -607,6 +648,7 @@ public class JYSController { /** * 发布教学任务,并同步发布关联的教研室任务书。 */ + @PreAuthorize("@ss.hasPermi('teach:taskPlan:list')") @PostMapping("/task/publish") public Result publishTask(@RequestParam("bh") String bh) { int count = teachingTaskManageService.publish(bh); @@ -616,6 +658,7 @@ public class JYSController { /** * 结束发布。结束后任务书和课程任务只读。 */ + @PreAuthorize("@ss.hasPermi('teach:taskPlan:list')") @PostMapping("/task/endPublish") public Result endPublishTask(@RequestParam("bh") String bh) { teachingTaskManageService.endPublish(bh); @@ -625,6 +668,7 @@ public class JYSController { /** * 教研室任务书列表。 */ + @PreAuthorize("@ss.hasPermi('teach:taskPlan:list')") @GetMapping("/task/office-book/list") public Result> listTaskOfficeBooks(@RequestParam("jxrwbh") String jxrwbh) { return Result.success(teachingTaskManageService.listOfficeBooks(jxrwbh)); @@ -633,6 +677,7 @@ public class JYSController { /** * 教研室任务书详细(该教研室在本任务下的课程任务)。 */ + @PreAuthorize("@ss.hasPermi('teach:taskPlan:list')") @GetMapping("/task/office-book/courses") public Result> listTaskOfficeBookCourses( @RequestParam("jxrwbh") String jxrwbh, @@ -643,6 +688,7 @@ public class JYSController { /** * 教学任务已关联学员队。 */ + @PreAuthorize("@ss.hasPermi('teach:taskPlan:list')") @GetMapping("/task/squad/list") public Result> listTaskSquads(@RequestParam("jxrwbh") String jxrwbh) { return Result.success(teachingTaskManageService.listBoundSquads(jxrwbh)); @@ -651,6 +697,7 @@ public class JYSController { /** * 某学期可选学员队(未占用或占用当前任务)。年度、学期第次为空时取当前学期。 */ + @PreAuthorize("@ss.hasPermi('teach:taskPlan:list')") @GetMapping("/task/squad/available") public Result> listAvailableTaskSquads( @RequestParam(required = false) Integer nd, diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/faculty/TeacherImportRowDTO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/faculty/TeacherImportRowDTO.java new file mode 100644 index 00000000..906e9e63 --- /dev/null +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/dto/faculty/TeacherImportRowDTO.java @@ -0,0 +1,32 @@ +package com.roomroot.jwgl.dto.faculty; + +import com.roomroot.jwgl.entity.JYB; +import lombok.Data; + +/** + * 教员(教员表)导入行解析结果。 + *

+ * 保留 Excel 中的原始行号,便于把校验失败原因定位到具体行。 + *

+ */ +@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; + } +} diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/FacultyServiceImpl.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/FacultyServiceImpl.java index c93cd4f0..a5554693 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/FacultyServiceImpl.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/FacultyServiceImpl.java @@ -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 list = ExcelParseUtil.parseJYBExcel( + List 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 errors = new ArrayList<>(); + java.util.Set 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 diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/OrgSyncServiceImpl.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/OrgSyncServiceImpl.java index 4282a6fa..b6f73410 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/OrgSyncServiceImpl.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/OrgSyncServiceImpl.java @@ -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; } diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/utils/ExcelParseUtil.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/utils/ExcelParseUtil.java index 0b991414..0ec8bdbf 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/utils/ExcelParseUtil.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/utils/ExcelParseUtil.java @@ -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 parseJYBExcel(InputStream inputStream, String fileName) throws Exception { - List result = new ArrayList<>(); + public static List parseJYBExcel(InputStream inputStream, String fileName) throws Exception { + List 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)。 *

表头顺序: