后端代码

This commit is contained in:
liumengyu
2026-08-24 17:48:55 +08:00
parent e0485f7366
commit aa4145fd33
419 changed files with 3684 additions and 53031 deletions
@@ -20,6 +20,7 @@ import com.roomroot.jwgl.dto.courserunning.StudentLeaveQueryDTO;
import com.roomroot.jwgl.dto.courserunning.OperationAnalysisQueryDTO;
import com.roomroot.jwgl.dto.courserunning.ScheduleAdjustStrategyDTO;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.vo.courserunning.AdjustableLessonVO;
import com.roomroot.jwgl.vo.courserunning.CourseRunningImportResultVO;
import com.roomroot.jwgl.vo.courserunning.ScheduleAdjustApplyVO;
import com.roomroot.jwgl.vo.courserunning.ScheduleAdjustDetailVO;
@@ -178,6 +179,14 @@ public interface CourseRunningImportService {
*/
PageResult<ScheduleAdjustApplyVO> queryScheduleAdjustList(ScheduleAdjustQueryDTO query);
/**
* 查询当前教员可供调课的课次,关联学员队任务表、课表、课程表。
*
* @param nd 年度,可空
* @return 可选课次列表
*/
List<AdjustableLessonVO> listAdjustableLessons(Integer nd);
/**
* 查询单个调课申请的完整详情。
* <p>
@@ -0,0 +1,40 @@
package com.roomroot.jwgl.service;
import com.roomroot.jwgl.dto.jys.ElectiveCourseQuery;
import com.roomroot.jwgl.dto.jys.ElectiveCourseSaveDTO;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.vo.jys.ElectiveCourseVO;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* 选修课管理。
* <p>数据来源:学员队任务表 INNER JOIN 学员队表 INNER JOIN 课表,课类型含“选修”。</p>
*/
public interface ElectiveCourseService {
PageResult<ElectiveCourseVO> pageList(PageQuery query, ElectiveCourseQuery cond);
void add(ElectiveCourseSaveDTO dto);
int batchOpenRegistration(List<String> bhList);
int batchCancelOpenRegistration(List<String> bhList);
int batchStopRegistration(List<String> bhList);
int batchReverseClassRange(List<String> bhList);
void exportClassList(ElectiveCourseQuery cond, HttpServletResponse response);
void exportStudentExcel(List<String> bhList, HttpServletResponse response);
void exportStudentWord(List<String> bhList, HttpServletResponse response);
void downloadTemplate(HttpServletResponse response);
int importData(MultipartFile file) throws Exception;
}
@@ -1,6 +1,12 @@
package com.roomroot.jwgl.service;
import com.roomroot.jwgl.dto.kcb.TimetableQuery;
import com.roomroot.jwgl.entity.KCB;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.vo.kcb.ClassTimetableVO;
import com.roomroot.jwgl.vo.kcb.DailyWeeklyTimetableVO;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
@@ -51,4 +57,34 @@ public interface KCBService {
* @return 所有数据列表
*/
List<KCB> list();
/**
* 今日课表。未传年度时按当前时间取本学期。
*/
List<DailyWeeklyTimetableVO> listToday(TimetableQuery cond);
/**
* 本周课表(周一至周日)。未传年度时按当前时间取本学期。
*/
List<DailyWeeklyTimetableVO> listWeek(TimetableQuery cond);
/**
* 班次课表。未传年度时按当前时间取本学期,可按队别班次筛选。
*/
PageResult<ClassTimetableVO> pageClassTimetable(PageQuery query, TimetableQuery cond);
/**
* 下载学期教学实施计划(课次明细 Excel)。
*/
void exportSemesterPlan(TimetableQuery cond, HttpServletResponse response);
/**
* 下载学期成绩表 Excel。
*/
void exportSemesterGrades(TimetableQuery cond, HttpServletResponse response);
/**
* 班次课程列表另存 Excel。
*/
void exportClassCourses(TimetableQuery cond, HttpServletResponse response);
}
@@ -0,0 +1,39 @@
package com.roomroot.jwgl.service;
import com.roomroot.jwgl.dto.jys.TeachingTaskQuery;
import com.roomroot.jwgl.dto.jys.TeachingTaskSaveDTO;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.vo.jys.TeachingOfficeBookCourseVO;
import com.roomroot.jwgl.vo.jys.TeachingOfficeBookVO;
import com.roomroot.jwgl.vo.jys.TeachingTaskDetailVO;
import com.roomroot.jwgl.vo.jys.TeachingTaskSquadVO;
import com.roomroot.jwgl.vo.jys.TeachingTaskVO;
import java.util.List;
/**
* 教学任务管理(机关发布,关联教研室任务书与学员队,供排课使用)。
*/
public interface TeachingTaskManageService {
PageResult<TeachingTaskVO> pageList(PageQuery query, TeachingTaskQuery cond);
TeachingTaskDetailVO getDetail(String bh);
void add(TeachingTaskSaveDTO dto);
void update(TeachingTaskSaveDTO dto);
void delete(String bh);
int publish(String bh);
List<TeachingOfficeBookVO> listOfficeBooks(String jxrwbh);
List<TeachingOfficeBookCourseVO> listOfficeBookCourses(String jxrwbh, String jysdh);
List<TeachingTaskSquadVO> listBoundSquads(String jxrwbh);
List<TeachingTaskSquadVO> listAvailableSquads(Integer nd, Integer xqdc, String jxrwbh);
}
@@ -2,17 +2,18 @@ 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.common.utils.SecurityUtils;
import com.roomroot.common.utils.StringUtils;
import com.roomroot.jwgl.dto.courserunning.*;
import com.roomroot.jwgl.entity.*;
import com.roomroot.jwgl.mapper.*;
import com.roomroot.jwgl.vo.courserunning.*;
import com.roomroot.jwgl.mapper.*;
import com.roomroot.jwgl.service.CourseRunningImportService;
import com.roomroot.jwgl.service.DictDataService;
import com.roomroot.jwgl.unit.BusinessException;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.utils.BasicManagementConstants;
import com.roomroot.jwgl.utils.ExcelExportUtil;
import com.roomroot.jwgl.utils.JwglRoleHelper;
import com.roomroot.jwgl.utils.UuidUtil;
import com.roomroot.jwgl.validator.StudentLeaveValidator;
import com.roomroot.jwgl.vo.courserunning.*;
@@ -102,6 +103,15 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
@Resource
private SSDKSQMapper ssdksqMapper;
@Resource
private JwglRoleHelper jwglRoleHelper;
@Resource
private StudentTeamTaskMapper studentTeamTaskMapper;
@Resource
private KCBMapper kcbMapper;
/**
* 实施_调课申请审批 Mapper,用于调课申请审批记录的数据访问。
*/
@@ -863,35 +873,33 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
*/
@Override
public PageResult<ScheduleAdjustApplyVO> queryScheduleAdjustList(ScheduleAdjustQueryDTO query) {
// 步骤1:校验查询参数,确保分页参数有效
if (query == null) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "查询参数不能为空");
}
if (query.getPageNum() == null || query.getPageSize() == null) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "分页参数不能为空");
}
applyScheduleAdjustDataScope(query);
// 步骤2:构建MyBatis-Plus分页对象
Page<ScheduleAdjustApplyVO> page = new Page<>(query.getPageNum(), query.getPageSize());
// 步骤3:将日期范围转换为字符串格式,便于XML中直接拼接SQL
String cjsjStartStr = query.getCjsjStart() != null ? query.getCjsjStart().format(DATE_TIME_FORMATTER) : null;
String cjsjEndStr = query.getCjsjEnd() != null ? query.getCjsjEnd().format(DATE_TIME_FORMATTER) : null;
// 步骤4:调用Mapper执行分页查询,关联课程表和教员表
Page<ScheduleAdjustApplyVO> resultPage = ssdksqMapper.selectPageList(
page,
query.getSskcbbh(),
query.getXydrwbh(),
query.getKbh(),
query.getSqjybh(),
query.getJysdh(),
query.getNd(),
query.getJyspzzt(),
query.getJyscszt(),
query.getJgspzt(),
query.getSczt(),
cjsjStartStr,
cjsjEndStr
);
// 步骤5:封装分页结果并返回
return new PageResult<>(
resultPage.getRecords(),
resultPage.getTotal(),
@@ -900,6 +908,73 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
);
}
@Override
public List<AdjustableLessonVO> listAdjustableLessons(Integer nd) {
if (jwglRoleHelper.isDepartmentPersonnel()) {
throw new BusinessException(BasicManagementConstants.FORBIDDEN, "机关人员仅可查看和审批调课申请");
}
if (jwglRoleHelper.isResearchOffice()) {
throw new BusinessException(BasicManagementConstants.FORBIDDEN, "教研室仅可查看和审批本室调课申请");
}
String teacherId = jwglRoleHelper.requireTeacherId();
return ssdksqMapper.selectAdjustableLessons(teacherId, nd);
}
private void applyScheduleAdjustDataScope(ScheduleAdjustQueryDTO query) {
if (jwglRoleHelper.isAdmin() || jwglRoleHelper.isDepartmentPersonnel()) {
return;
}
if (jwglRoleHelper.isResearchOffice()) {
query.setJysdh(jwglRoleHelper.requireResearchOfficeId());
query.setSqjybh(null);
return;
}
if (jwglRoleHelper.isTeacher()) {
query.setSqjybh(jwglRoleHelper.requireTeacherId());
query.setJysdh(null);
return;
}
throw new BusinessException(BasicManagementConstants.FORBIDDEN, "无权查看调课申请");
}
private void assertCanViewScheduleAdjust(SSDKSQ apply) {
if (jwglRoleHelper.isAdmin() || jwglRoleHelper.isDepartmentPersonnel()) {
return;
}
if (jwglRoleHelper.isResearchOffice()) {
String officeId = jwglRoleHelper.requireResearchOfficeId();
String applyOffice = apply.getJysdh();
if (StringUtils.isEmpty(applyOffice) && StringUtils.isNotEmpty(apply.getSqjybh())) {
JYB teacher = jybMapper.selectById(apply.getSqjybh());
applyOffice = teacher == null ? null : teacher.getJysdh();
}
if (applyOffice == null || !officeId.equals(applyOffice.trim())) {
throw new BusinessException(BasicManagementConstants.FORBIDDEN, "只能查看本教研室的调课申请");
}
return;
}
if (jwglRoleHelper.isTeacher()) {
String teacherId = jwglRoleHelper.requireTeacherId();
if (apply.getSqjybh() == null || !teacherId.equals(apply.getSqjybh().trim())) {
throw new BusinessException(BasicManagementConstants.FORBIDDEN, "只能查看本人提交的调课申请");
}
return;
}
throw new BusinessException(BasicManagementConstants.FORBIDDEN, "无权查看调课申请");
}
private String currentOperatorId() {
try {
String username = SecurityUtils.getUsername();
if (StringUtils.isNotEmpty(username)) {
return username;
}
} catch (Exception ignored) {
// 未登录时由调用方继续校验
}
return null;
}
/**
* 查询单个调课申请的完整详情。
* <p>
@@ -922,6 +997,10 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
if (detail == null) {
throw new BusinessException(BasicManagementConstants.NOT_FOUND, "未找到该调课申请");
}
SSDKSQ apply = ssdksqMapper.selectById(ssdksqbh);
if (apply != null) {
assertCanViewScheduleAdjust(apply);
}
// 步骤3:查询关联的机关审批记录列表
detail.setAuditList(ssdksqspMapper.selectBySsdksqbh(ssdksqbh));
@@ -957,22 +1036,24 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
@Override
@Transactional(rollbackFor = Exception.class)
public String submitScheduleAdjust(ScheduleAdjustApplyDTO dto) {
// 步骤1:校验调课申请参数
if (dto == null) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "调课申请参数不能为空");
}
if (dto.getSskcbbh() == null || dto.getSskcbbh().trim().isEmpty()) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "课次编号不能为空");
if (jwglRoleHelper.isDepartmentPersonnel()) {
throw new BusinessException(BasicManagementConstants.FORBIDDEN, "机关人员仅可查看和审批,不能提交调课申请");
}
if (dto.getSqjybh() == null || dto.getSqjybh().trim().isEmpty()) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "申请教员编号不能为空");
if (jwglRoleHelper.isResearchOffice()) {
throw new BusinessException(BasicManagementConstants.FORBIDDEN, "教研室仅可查看和审批本室申请,不能提交调课申请");
}
if (StringUtils.isEmpty(dto.getSskcbbh())) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "课次编号不能为空");
}
if (dto.getSy() == null || dto.getSy().trim().isEmpty()) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "调课事由不能为空");
}
// 步骤2:查询课次实体,校验课次是否存在
SSKCB lesson = sskcbMapper.selectById(dto.getSskcbbh());
String teacherId = jwglRoleHelper.requireTeacherId();
SSKCB lesson = sskcbMapper.selectById(dto.getSskcbbh().trim());
if (lesson == null) {
throw new BusinessException(BasicManagementConstants.NOT_FOUND, "课次不存在");
}
@@ -980,58 +1061,63 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "该课次已删除,不允许申请调课");
}
// 调课时间段策略校验
validateScheduleAdjustTimeLimitStrategy(dto.getRq());
AdjustableLessonVO picked = null;
List<AdjustableLessonVO> mine = ssdksqMapper.selectAdjustableLessons(teacherId, lesson.getNd());
if (mine != null) {
for (AdjustableLessonVO item : mine) {
if (lesson.getBh().equals(item.getSskcbbh())) {
picked = item;
break;
}
}
}
if (picked == null) {
throw new BusinessException(BasicManagementConstants.FORBIDDEN, "只能对自己任课的课次申请调课");
}
// 判断是否命中免审批策略
validateScheduleAdjustTimeLimitStrategy(dto.getRq());
boolean autoApproved = matchAutoApproveStrategy();
// 步骤3:构建并保存调课申请主表实体
SSDKSQ apply = new SSDKSQ();
String ssdksqbh = UuidUtil.getOriginalUUID(); // 生成唯一调课申请编号
String ssdksqbh = UuidUtil.getOriginalUUID();
apply.setBh(ssdksqbh);
apply.setSskcbbh(dto.getSskcbbh()); // 课次编号
apply.setSqjybh(dto.getSqjybh()); // 申请教员编号
apply.setSy(dto.getSy()); // 调课事由
apply.setRq(dto.getRq()); // 新日期
apply.setJc(dto.getJc()); // 新节次
apply.setNd(dto.getNd()); // 年度
apply.setJxnr(dto.getJxnr()); // 教学内容
apply.setJxyd(dto.getJxyd()); // 教学要点
apply.setJxff(dto.getJxff()); // 教学方法
apply.setJxbzbz(dto.getJxbzbz()); // 教学保障备注
apply.setYcxx(dto.getYcxx()); // 用车信息
apply.setBz(dto.getBz()); // 备注
// 将原日期节次描述追加到备注中(ydsjap字段类型为Integer,用于存储其他业务数据)
apply.setSskcbbh(lesson.getBh());
apply.setXydrwbh(StringUtils.isNotEmpty(dto.getXydrwbh()) ? dto.getXydrwbh() : picked.getXydrwbh());
apply.setKbh(StringUtils.isNotEmpty(dto.getKbh()) ? dto.getKbh() : picked.getKbh());
apply.setKcbbh(StringUtils.isNotEmpty(dto.getKcbbh()) ? dto.getKcbbh() : picked.getKcbbh());
apply.setJysdh(picked.getJysdh());
apply.setYjsbh(picked.getJsbh());
apply.setXjsbh(resolveNewClassroom(dto));
apply.setSqjybh(teacherId);
apply.setSy(dto.getSy());
apply.setRq(dto.getRq());
apply.setJc(dto.getJc());
apply.setNd(dto.getNd() != null ? dto.getNd() : lesson.getNd());
apply.setJxnr(dto.getJxnr());
apply.setJxyd(dto.getJxyd());
apply.setJxff(dto.getJxff());
apply.setJxbzbz(dto.getJxbzbz());
apply.setYcxx(dto.getYcxx());
String originalDesc = buildOriginalScheduleDesc(lesson);
if (dto.getBz() != null && !dto.getBz().trim().isEmpty()) {
apply.setBz(dto.getBz() + " | " + originalDesc);
} else {
apply.setBz(originalDesc);
}
// 命中免审批策略时在备注追加标记,便于教务人员识别
if (autoApproved) {
apply.setBz((apply.getBz() == null ? "" : apply.getBz() + " | ") + "[免审批策略自动通过]");
}
// 审批状态初始化:未审批、未查收、未删除
if (autoApproved) {
// 命中免审批策略:教研室和教学系审批状态直接设为已通过,跳过三级审批
apply.setJyspzzt(1);
apply.setJxxspzzt(1);
} else {
apply.setJyspzzt(0);
}
apply.setJyscszt(0);
apply.setSczt(0);
// 时间字段
apply.setFhzt(0);
apply.setDk(1);
LocalDateTime now = LocalDateTime.now();
apply.setCreateTime(now);
apply.setUpdateTime(now);
// 步骤4:插入调课申请主表数据
apply.setCjsj(now);
ssdksqMapper.insert(apply);
// 步骤5:保存新教室关联数据
if (dto.getRoomList() != null && !dto.getRoomList().isEmpty()) {
for (AdjustRoomDTO roomDto : dto.getRoomList()) {
DKSQJS roomEntity = new DKSQJS();
@@ -1041,9 +1127,13 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
roomEntity.setBz(roomDto.getBz());
dksqjsMapper.insert(roomEntity);
}
} else if (StringUtils.isNotEmpty(apply.getXjsbh())) {
DKSQJS roomEntity = new DKSQJS();
roomEntity.setBh(UuidUtil.getOriginalUUID());
roomEntity.setDksqbh(ssdksqbh);
roomEntity.setJsbh(apply.getXjsbh());
dksqjsMapper.insert(roomEntity);
}
// 步骤6:保存新辅助教员关联数据
if (dto.getTeacherList() != null && !dto.getTeacherList().isEmpty()) {
for (AdjustTeacherDTO teacherDto : dto.getTeacherList()) {
DKSQFZJY teacherEntity = new DKSQFZJY();
@@ -1055,8 +1145,6 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
dksqfzjyMapper.insert(teacherEntity);
}
}
// 步骤7:保存新学员队关联数据
if (dto.getTeamList() != null && !dto.getTeamList().isEmpty()) {
for (AdjustTeamDTO teamDto : dto.getTeamList()) {
DKSQXYD teamEntity = new DKSQXYD();
@@ -1066,8 +1154,6 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
dksqxydMapper.insert(teamEntity);
}
}
// 步骤8:保存新保障明细关联数据
if (dto.getSupportList() != null && !dto.getSupportList().isEmpty()) {
for (AdjustSupportDTO supportDto : dto.getSupportList()) {
DKSQBZMX supportEntity = new DKSQBZMX();
@@ -1080,19 +1166,54 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
}
}
// 步骤9:更新课次数据,将日期节次替换为调整后的新值
lesson.setRq(dto.getRq());
lesson.setJc(dto.getJc());
lesson.setBdsj(now);
sskcbMapper.updateById(lesson);
if (autoApproved) {
applyApprovedSchedule(apply);
}
// 步骤10:记录调课申请操作日志
recordOperationLog(ssdksqbh, "申请", "提交调课申请:" + ssdksqbh);
// 步骤11:返回调课申请编号
return ssdksqbh;
}
private XYDRWB findRelatedTeamTask(SSKC course, SSKCB lesson) {
if (course == null || StringUtils.isEmpty(course.getKmbh()) || lesson == null) {
return null;
}
List<SSKCBXYD> teams = sskcbxyMapper.selectBySskcbh(lesson.getBh());
String teamId = (teams == null || teams.isEmpty()) ? null : teams.get(0).getXydbh();
LambdaQueryWrapper<XYDRWB> wrapper = new LambdaQueryWrapper<XYDRWB>()
.eq(XYDRWB::getKbh, course.getKmbh())
.eq(XYDRWB::getJybh, course.getJybh())
.eq(lesson.getNd() != null, XYDRWB::getNd, lesson.getNd());
if (StringUtils.isNotEmpty(teamId)) {
wrapper.eq(XYDRWB::getXydbh, teamId);
}
wrapper.last("LIMIT 1");
return studentTeamTaskMapper.selectOne(wrapper);
}
private KCB findRelatedScheduleSlot(SSKC course) {
if (course == null || StringUtils.isEmpty(course.getJybh()) || course.getJykcxh() == null) {
return null;
}
LambdaQueryWrapper<KCB> wrapper = new LambdaQueryWrapper<KCB>()
.eq(KCB::getJybh, course.getJybh())
.eq(KCB::getKcxh, course.getJykcxh())
.eq(course.getNd() != null, KCB::getNd, course.getNd())
.last("LIMIT 1");
return kcbMapper.selectOne(wrapper);
}
private String resolveNewClassroom(ScheduleAdjustApplyDTO dto) {
if (StringUtils.isNotEmpty(dto.getXjsbh())) {
return dto.getXjsbh().trim();
}
if (dto.getRoomList() != null && !dto.getRoomList().isEmpty()
&& StringUtils.isNotEmpty(dto.getRoomList().get(0).getJsbh())) {
return dto.getRoomList().get(0).getJsbh().trim();
}
return null;
}
/**
* 教研室审批调课申请。
* <p>
@@ -1105,10 +1226,18 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
@Override
@Transactional(rollbackFor = Exception.class)
public void auditByTeachingOffice(ScheduleAdjustAuditDTO dto) {
// 步骤1:校验审批参数
if (dto == null) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "审批参数不能为空");
}
if (jwglRoleHelper.isTeacher()) {
throw new BusinessException(BasicManagementConstants.FORBIDDEN, "教员无权审批调课申请");
}
if (jwglRoleHelper.isDepartmentPersonnel() && !jwglRoleHelper.isAdmin()) {
throw new BusinessException(BasicManagementConstants.FORBIDDEN, "机关人员请使用机关审批,不办理教研室审批");
}
if (!jwglRoleHelper.isAdmin() && !jwglRoleHelper.isResearchOffice()) {
throw new BusinessException(BasicManagementConstants.FORBIDDEN, "仅教研室可进行一审");
}
if (!"jys".equals(dto.getAuditRole())) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "审批角色不正确,应为jys");
}
@@ -1117,7 +1246,6 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "审批结果不正确,应为1(同意)、2(发回)或3(拒绝)");
}
// 步骤2:查询调课申请实体,校验申请是否存在
SSDKSQ apply = ssdksqMapper.selectById(dto.getSsdksqbh());
if (apply == null) {
throw new BusinessException(BasicManagementConstants.NOT_FOUND, "调课申请不存在");
@@ -1125,33 +1253,33 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
if (apply.getSczt() != null && apply.getSczt() == 1) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "该调课申请已撤销,不允许审批");
}
// 步骤3:校验申请是否已审批,避免重复审批
if (jwglRoleHelper.isResearchOffice()) {
String officeId = jwglRoleHelper.requireResearchOfficeId();
String applyOffice = apply.getJysdh();
if (StringUtils.isEmpty(applyOffice) && StringUtils.isNotEmpty(apply.getSqjybh())) {
JYB teacher = jybMapper.selectById(apply.getSqjybh());
applyOffice = teacher == null ? null : teacher.getJysdh();
}
if (applyOffice == null || !officeId.equals(applyOffice.trim())) {
throw new BusinessException(BasicManagementConstants.FORBIDDEN, "只能审批本教研室的调课申请");
}
}
if (apply.getJyspzzt() != null && apply.getJyspzzt() != 0) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "该调课申请已审批,无需重复审批");
}
// 步骤4:更新调课申请主表的教研室审批状态
LocalDateTime now = LocalDateTime.now();
apply.setJyspzzt(dto.getSpzt()); // 教研室审批状态
apply.setJyspzrbh(dto.getSprbh()); // 教研室审批人编号
apply.setJyspzsj(now); // 教研室审批时间
apply.setFhyj(dto.getFhyj()); // 发回意见
apply.setUpdateTime(now); // 更新时间
String auditor = StringUtils.isNotEmpty(dto.getSprbh()) ? dto.getSprbh() : currentOperatorId();
apply.setJyspzzt(dto.getSpzt());
apply.setJyspzrbh(auditor);
apply.setJyspzsj(now);
apply.setFhyj(dto.getFhyj());
if (dto.getSpzt() != null && dto.getSpzt() == 2) {
apply.setFhzt(1);
apply.setFhsj(now);
}
ssdksqMapper.updateById(apply);
// 步骤5:根据审批结果执行不同的后续处理
if (dto.getSpzt() == 3) {
// 拒绝:恢复课次原数据,标记申请最终结束
restoreLessonSchedule(apply);
} else if (dto.getSpzt() == 2) {
// 发回:发回教员修改,课次保留调整后数据,由教员重新申请
// 此处无需修改课次数据
} else {
// 同意:课次数据已由申请时更新,无需重复处理
}
// 步骤6:记录审批操作日志
recordOperationLog(apply.getBh(), "教研室审批", "教研室审批调课申请:" + apply.getBh()
+ ",审批结果:" + dto.getSpzt() + ",审批意见:" + dto.getFhyj());
}
@@ -1288,11 +1416,13 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
|| (dto.getSpzt() != 1 && dto.getSpzt() != 2 && dto.getSpzt() != 3)) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "审批结果不正确");
}
if (dto.getJgbh() == null || dto.getJgbh().trim().isEmpty()) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "机关编号不能为空");
if (jwglRoleHelper.isTeacher() || jwglRoleHelper.isResearchOffice()) {
throw new BusinessException(BasicManagementConstants.FORBIDDEN, "仅机关人员可进行终审");
}
if (!jwglRoleHelper.isAdmin() && !jwglRoleHelper.isDepartmentPersonnel()) {
throw new BusinessException(BasicManagementConstants.FORBIDDEN, "仅机关人员可进行终审");
}
// 步骤2:查询调课申请实体
SSDKSQ apply = ssdksqMapper.selectById(dto.getSsdksqbh());
if (apply == null) {
throw new BusinessException(BasicManagementConstants.NOT_FOUND, "调课申请不存在");
@@ -1300,23 +1430,18 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
if (apply.getSczt() != null && apply.getSczt() == 1) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "该调课申请已撤销,不允许审批");
}
// 步骤3:校验教研室是否已同意,机关审批应在教研室同意之后进行
if (apply.getJyspzzt() == null || apply.getJyspzzt() != 1) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "教研室未同意或未审批,无法进行机关审批");
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "教研室未同意,无法进行机关审批");
}
// 步骤4:校验教学系是否已同意,机关审批应在教学系同意之后进行(三级审批)
if (apply.getJxxspzzt() == null || apply.getJxxspzzt() != 1) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "教学系未同意或未审批,无法进行机关审批");
}
String jgbh = StringUtils.isNotEmpty(dto.getJgbh()) ? dto.getJgbh() : "JG";
String auditor = StringUtils.isNotEmpty(dto.getSprbh()) ? dto.getSprbh() : currentOperatorId();
// 步骤5:构建并保存机关审批记录
SSDKSQSP audit = new SSDKSQSP();
audit.setBh(UuidUtil.getOriginalUUID());
audit.setSsdksqbh(dto.getSsdksqbh());
audit.setJgbh(dto.getJgbh());
audit.setSprbh(dto.getSprbh());
audit.setJgbh(jgbh);
audit.setSprbh(auditor);
audit.setSpsj(LocalDateTime.now());
audit.setSpzt(dto.getSpzt());
audit.setFhyj(dto.getFhyj());
@@ -1325,19 +1450,12 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
audit.setUpdateTime(LocalDateTime.now());
ssdksqspMapper.insert(audit);
// 步骤5:根据审批结果执行不同的后续处理
if (dto.getSpzt() == 3) {
// 拒绝:恢复课次原数据,标记申请最终结束
restoreLessonSchedule(apply);
} else if (dto.getSpzt() == 2) {
// 发回:发回教研室或教员,课次保留调整后数据
} else {
// 同意:课次数据已由申请时更新,无需重复处理
if (dto.getSpzt() == 1) {
applyApprovedSchedule(apply);
}
// 步骤6:记录机关审批操作日志
recordOperationLog(apply.getBh(), "机关审批", "机关审批调课申请:" + apply.getBh()
+ ",机关编号:" + dto.getJgbh()
+ ",机关编号:" + jgbh
+ ",审批结果:" + dto.getSpzt() + ",审批意见:" + dto.getFhyj());
}
@@ -1412,44 +1530,34 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
@Override
@Transactional(rollbackFor = Exception.class)
public void cancelScheduleAdjust(String ssdksqbh, String sqjybh) {
// 步骤1:校验参数
if (jwglRoleHelper.isDepartmentPersonnel() || jwglRoleHelper.isResearchOffice()) {
throw new BusinessException(BasicManagementConstants.FORBIDDEN, "仅申请教员本人可撤销调课申请");
}
if (ssdksqbh == null || ssdksqbh.trim().isEmpty()) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "调课申请编号不能为空");
}
if (sqjybh == null || sqjybh.trim().isEmpty()) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "申请教员编号不能为空");
String teacherId = jwglRoleHelper.requireTeacherId();
if (sqjybh != null && !sqjybh.trim().isEmpty() && !teacherId.equals(sqjybh.trim())) {
throw new BusinessException(BasicManagementConstants.FORBIDDEN, "仅申请教员本人可撤销该调课申请");
}
sqjybh = teacherId;
// 步骤2:查询调课申请实体
SSDKSQ apply = ssdksqMapper.selectById(ssdksqbh);
if (apply == null) {
throw new BusinessException(BasicManagementConstants.NOT_FOUND, "调课申请不存在");
}
// 步骤3:校验是否已删除,避免重复撤销
if (apply.getSczt() != null && apply.getSczt() == 1) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "该调课申请已撤销,无需重复撤销");
}
// 步骤4:校验权限,仅申请教员本人可撤销
if (!sqjybh.equals(apply.getSqjybh())) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "仅申请教员本人可撤销该调课申请");
throw new BusinessException(BasicManagementConstants.FORBIDDEN, "仅申请教员本人可撤销该调课申请");
}
// 步骤5:校验审批状态,已审批通过的申请不允许撤销
if (apply.getJyspzzt() != null && apply.getJyspzzt() == 1) {
throw new BusinessException(BasicManagementConstants.BAD_REQUEST, "该调课申请教研室已同意,不允许撤销");
}
// 步骤6:软删除调课申请主表
apply.setSczt(1); // 删除状态:已删除
apply.setUpdateTime(LocalDateTime.now()); // 更新时间
apply.setSczt(1);
ssdksqMapper.updateById(apply);
// 步骤7:恢复课次原数据
restoreLessonSchedule(apply);
// 步骤8:记录撤销操作日志
recordOperationLog(apply.getBh(), "撤销", "撤销调课申请:" + apply.getBh());
}
@@ -1462,6 +1570,63 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
* @param lesson 课次实体
* @return 原日期节次描述
*/
/**
* 机关终审同意后,将调整结果写回学员队任务表、课程表,以及可选的实施课次。
*/
private void applyApprovedSchedule(SSDKSQ apply) {
if (apply == null || StringUtils.isEmpty(apply.getSskcbbh())) {
return;
}
SSKCB lesson = sskcbMapper.selectById(apply.getSskcbbh());
if (lesson != null) {
lesson.setRq(apply.getRq());
lesson.setJc(apply.getJc());
lesson.setBdsj(LocalDateTime.now());
if (StringUtils.isNotEmpty(apply.getJxnr())) {
lesson.setJxnr(apply.getJxnr());
}
if (StringUtils.isNotEmpty(apply.getJxyd())) {
lesson.setJxyd(apply.getJxyd());
}
if (StringUtils.isNotEmpty(apply.getJxff())) {
lesson.setJxff(apply.getJxff());
}
sskcbMapper.updateById(lesson);
}
String newRoom = apply.getXjsbh();
if (StringUtils.isEmpty(newRoom)) {
List<AdjustRoomVO> applyRooms = dksqjsMapper.selectByDksqbh(apply.getBh());
if (applyRooms != null && !applyRooms.isEmpty()) {
newRoom = applyRooms.get(0).getJsbh();
}
}
XYDRWB task = StringUtils.isNotEmpty(apply.getXydrwbh())
? studentTeamTaskMapper.selectById(apply.getXydrwbh())
: findRelatedTeamTask(null, lesson);
if (task != null && StringUtils.isNotEmpty(newRoom)) {
task.setJsbh(newRoom);
studentTeamTaskMapper.updateById(task);
}
KCB slot = StringUtils.isNotEmpty(apply.getKcbbh())
? kcbMapper.selectById(apply.getKcbbh())
: null;
if (slot != null) {
if (StringUtils.isNotEmpty(newRoom)) {
slot.setJsbh(newRoom);
}
if (apply.getRq() != null) {
int packed = apply.getRq().getYear() * 10000
+ apply.getRq().getMonthValue() * 100
+ apply.getRq().getDayOfMonth();
slot.setApsj(packed);
}
kcbMapper.updateById(slot);
}
}
private String buildOriginalScheduleDesc(SSKCB lesson) {
if (lesson == null) {
return "";
@@ -0,0 +1,534 @@
package com.roomroot.jwgl.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.roomroot.common.exception.ServiceException;
import com.roomroot.common.utils.StringUtils;
import com.roomroot.common.utils.file.FileUtils;
import com.roomroot.common.utils.poi.ExcelUtil;
import com.roomroot.jwgl.dto.jys.ElectiveCourseImportDTO;
import com.roomroot.jwgl.dto.jys.ElectiveCourseQuery;
import com.roomroot.jwgl.dto.jys.ElectiveCourseSaveDTO;
import com.roomroot.jwgl.entity.JSB;
import com.roomroot.jwgl.entity.JYB;
import com.roomroot.jwgl.entity.KB;
import com.roomroot.jwgl.entity.XYDB;
import com.roomroot.jwgl.entity.XYDQB;
import com.roomroot.jwgl.entity.XYDRWB;
import com.roomroot.jwgl.mapper.ClassRoomMapper;
import com.roomroot.jwgl.mapper.ElectiveCourseMapper;
import com.roomroot.jwgl.mapper.JYBMapper;
import com.roomroot.jwgl.mapper.KBMapper;
import com.roomroot.jwgl.mapper.StudentTeamTaskMapper;
import com.roomroot.jwgl.mapper.XYDBMapper;
import com.roomroot.jwgl.mapper.XYDQBMapper;
import com.roomroot.jwgl.service.ElectiveCourseService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.utils.UuidUtil;
import com.roomroot.jwgl.vo.jys.ElectiveCourseStudentVO;
import com.roomroot.jwgl.vo.jys.ElectiveCourseVO;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.OutputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import static com.roomroot.jwgl.utils.BasicManagementConstants.BAD_REQUEST;
import static com.roomroot.jwgl.utils.BasicManagementConstants.NOT_FOUND;
/**
* 选修课管理实现。
*/
@Service
public class ElectiveCourseServiceImpl implements ElectiveCourseService {
private static final String COURSE_TYPE_ELECTIVE = "选修";
private static final String STATUS_DRAFT = "拟制";
private static final String STATUS_OPEN = "开放报名";
private static final String STATUS_STOP = "停止报名";
private static final String CLASS_TYPE_ELECTIVE = "选修班";
private static final int FLAG_DRAFT = 0;
private static final int FLAG_OPEN = 1;
private static final int FLAG_STOP = 2;
@Resource
private ElectiveCourseMapper electiveCourseMapper;
@Resource
private StudentTeamTaskMapper studentTeamTaskMapper;
@Resource
private XYDBMapper xydbMapper;
@Resource
private KBMapper kbMapper;
@Resource
private JYBMapper jybMapper;
@Resource
private ClassRoomMapper classRoomMapper;
@Resource
private XYDQBMapper xydqbMapper;
@Override
public PageResult<ElectiveCourseVO> pageList(PageQuery query, ElectiveCourseQuery cond) {
ElectiveCourseQuery filter = normalizeQuery(cond);
int pageNum = query.getPageNum() == null ? 1 : query.getPageNum();
int pageSize = query.getPageSize() == null ? 20 : query.getPageSize();
Page<ElectiveCourseVO> page = new Page<>(pageNum, pageSize);
Page<ElectiveCourseVO> result = electiveCourseMapper.selectElectiveCoursePage(page, filter);
fillSerial(result.getRecords(), pageNum, pageSize);
return new PageResult<>(result.getRecords(), result.getTotal(), pageNum, pageSize);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void add(ElectiveCourseSaveDTO dto) {
if (dto == null) {
throw new ServiceException("选修课信息不能为空", BAD_REQUEST);
}
KB course = requireCourse(dto.getKbh());
String xydbh = resolveTeamId(dto.getXydbh(), dto.getXxbmc(), dto.getNj(), true);
XYDRWB task = new XYDRWB();
task.setBh(UuidUtil.getOriginalUUID());
task.setDelFlag(0);
task.setNd(dto.getNd() != null ? dto.getNd() : LocalDate.now().getYear());
task.setXydbh(xydbh);
task.setKbh(course.getKbh());
task.setXqdc(dto.getXqdc());
task.setJybh(blankToNull(dto.getJybh()));
task.setJsbh(blankToNull(dto.getJsbh()));
task.setRs(dto.getRs());
task.setXs(dto.getXs() != null ? dto.getXs() : course.getXs());
task.setXf(dto.getXf() != null ? dto.getXf() : course.getXf());
task.setKlx(ensureElectiveType(null));
task.setJysdh(StringUtils.isNotEmpty(dto.getJysdh()) ? dto.getJysdh() : course.getJysdh());
task.setBz(dto.getBz());
task.setXz(FLAG_DRAFT);
studentTeamTaskMapper.insert(task);
upsertPinban(xydbh, STATUS_DRAFT, dto.getBmkssj(), dto.getBmjssj(),
dto.getYqsm(), dto.getKxdlbc(), dto.getBz());
updateTeamDates(xydbh, dto.getKkrq(), dto.getJkrq());
}
@Override
@Transactional(rollbackFor = Exception.class)
public int batchOpenRegistration(List<String> bhList) {
return changeStatus(bhList, STATUS_OPEN, FLAG_OPEN, 1, false);
}
@Override
@Transactional(rollbackFor = Exception.class)
public int batchCancelOpenRegistration(List<String> bhList) {
return changeStatus(bhList, STATUS_DRAFT, FLAG_DRAFT, 0, false);
}
@Override
@Transactional(rollbackFor = Exception.class)
public int batchStopRegistration(List<String> bhList) {
return changeStatus(bhList, STATUS_STOP, FLAG_STOP, 0, true);
}
@Override
@Transactional(rollbackFor = Exception.class)
public int batchReverseClassRange(List<String> bhList) {
List<XYDRWB> tasks = loadElectiveTasks(bhList);
int count = 0;
Set<String> handled = new LinkedHashSet<>();
for (XYDRWB task : tasks) {
if (!handled.add(task.getXydbh())) {
continue;
}
List<String> names = electiveCourseMapper.selectOriginalClassNames(task.getXydbh());
if (names == null || names.isEmpty()) {
throw new ServiceException("选修班暂无学员,无法根据学员反向确定班次范围", BAD_REQUEST);
}
upsertPinban(task.getXydbh(), null, null, null, null, String.join(";", names), null);
count++;
}
return count;
}
@Override
public void exportClassList(ElectiveCourseQuery cond, HttpServletResponse response) {
List<ElectiveCourseVO> list = electiveCourseMapper.selectElectiveCourseList(normalizeQuery(cond));
fillSerial(list, 1, list == null ? 0 : list.size());
ExcelUtil<ElectiveCourseVO> util = new ExcelUtil<>(ElectiveCourseVO.class);
util.exportExcel(response, list, "选修班列表");
}
@Override
public void exportStudentExcel(List<String> bhList, HttpServletResponse response) {
List<ElectiveCourseStudentVO> students = loadStudents(bhList);
ExcelUtil<ElectiveCourseStudentVO> util = new ExcelUtil<>(ElectiveCourseStudentVO.class);
util.exportExcel(response, students, "选修班学员名单");
}
@Override
public void exportStudentWord(List<String> bhList, HttpServletResponse response) {
List<ElectiveCourseStudentVO> students = loadStudents(bhList);
try (XWPFDocument doc = new XWPFDocument(); OutputStream os = response.getOutputStream()) {
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
FileUtils.setAttachmentResponseHeader(response, "选修班学员名单.docx");
writeStudentWord(doc, students);
doc.write(os);
os.flush();
} catch (ServiceException e) {
throw e;
} catch (Exception e) {
throw new ServiceException("导出Word失败:" + e.getMessage(), BAD_REQUEST);
}
}
@Override
public void downloadTemplate(HttpServletResponse response) {
ExcelUtil<ElectiveCourseImportDTO> util = new ExcelUtil<>(ElectiveCourseImportDTO.class);
util.importTemplateExcel(response, "选修课数据");
}
@Override
@Transactional(rollbackFor = Exception.class)
public int importData(MultipartFile file) throws Exception {
if (file == null || file.isEmpty()) {
throw new ServiceException("导入文件不能为空", BAD_REQUEST);
}
ExcelUtil<ElectiveCourseImportDTO> util = new ExcelUtil<>(ElectiveCourseImportDTO.class);
List<ElectiveCourseImportDTO> rows = util.importExcel(file.getInputStream());
if (rows == null || rows.isEmpty()) {
throw new ServiceException("Excel中无有效数据", BAD_REQUEST);
}
int count = 0;
for (int i = 0; i < rows.size(); i++) {
ElectiveCourseImportDTO row = rows.get(i);
int line = i + 2;
if (StringUtils.isEmpty(row.getKmc())) {
throw new ServiceException("第" + line + "行课程科目名称未填写", BAD_REQUEST);
}
if (StringUtils.isEmpty(row.getXxbmc())) {
throw new ServiceException("第" + line + "行选修班名称未填写", BAD_REQUEST);
}
KB course = kbMapper.selectOne(new LambdaQueryWrapper<KB>().eq(KB::getKmc, row.getKmc().trim()));
if (course == null) {
throw new ServiceException("第" + line + "行课程科目名称不存在:" + row.getKmc(), NOT_FOUND);
}
String jybh = null;
if (StringUtils.isNotEmpty(row.getJyxm())) {
JYB teacher = jybMapper.selectOne(new LambdaQueryWrapper<JYB>().eq(JYB::getJyxm, row.getJyxm().trim()));
if (teacher == null) {
throw new ServiceException("第" + line + "行授课教员不存在:" + row.getJyxm(), NOT_FOUND);
}
jybh = teacher.getJybh();
}
String jsbh = null;
if (StringUtils.isNotEmpty(row.getJsmc())) {
JSB room = classRoomMapper.selectOne(new LambdaQueryWrapper<JSB>().eq(JSB::getJsmc, row.getJsmc().trim()));
if (room == null) {
throw new ServiceException("第" + line + "行教学场地不存在:" + row.getJsmc(), NOT_FOUND);
}
jsbh = room.getJsbh();
}
String xydbh = resolveTeamId(null, row.getXxbmc().trim(), row.getKxbcnj(), true);
XYDRWB task = new XYDRWB();
task.setBh(UuidUtil.getOriginalUUID());
task.setDelFlag(0);
task.setNd(LocalDate.now().getYear());
task.setXydbh(xydbh);
task.setKbh(course.getKbh());
task.setJybh(jybh);
task.setJsbh(jsbh);
task.setRs(row.getJhrs());
task.setXs(row.getJhxs() != null ? row.getJhxs() : course.getXs());
task.setXf(row.getXf() != null ? row.getXf() : course.getXf());
task.setKlx(ensureElectiveType(null));
task.setJysdh(course.getJysdh());
task.setXz(statusToFlag(row.getXkzt()));
studentTeamTaskMapper.insert(task);
upsertPinban(xydbh, normalizeStatus(row.getXkzt()), parseDateTime(row.getBmkssj()),
parseDateTime(row.getBmjssj()), row.getYqsm(), row.getKxbcnj(), null);
updateTeamDates(xydbh, parseDateTime(row.getKkrq()), parseDateTime(row.getJkrq()));
count++;
}
return count;
}
private int changeStatus(List<String> bhList, String status, int xzFlag, Integer allowRegister, boolean stopNow) {
List<XYDRWB> tasks = loadElectiveTasks(bhList);
Set<String> teams = new LinkedHashSet<>();
for (XYDRWB task : tasks) {
task.setXz(xzFlag);
studentTeamTaskMapper.updateById(task);
teams.add(task.getXydbh());
}
for (String xydbh : teams) {
upsertPinban(xydbh, status, null, null, null, null, null);
updatePeriodRegister(xydbh, allowRegister, stopNow);
}
return tasks.size();
}
private List<XYDRWB> loadElectiveTasks(List<String> bhList) {
if (bhList == null || bhList.isEmpty()) {
throw new ServiceException("请先选择选修课", BAD_REQUEST);
}
List<XYDRWB> tasks = new ArrayList<>();
for (String bh : bhList) {
if (StringUtils.isEmpty(bh)) {
continue;
}
XYDRWB task = studentTeamTaskMapper.selectById(bh);
if (task == null) {
throw new ServiceException("选修课不存在", NOT_FOUND);
}
if (task.getKlx() == null || !task.getKlx().contains(COURSE_TYPE_ELECTIVE)) {
throw new ServiceException("所选记录不是选修课", BAD_REQUEST);
}
tasks.add(task);
}
if (tasks.isEmpty()) {
throw new ServiceException("请先选择选修课", BAD_REQUEST);
}
return tasks;
}
private List<ElectiveCourseStudentVO> loadStudents(List<String> bhList) {
List<XYDRWB> tasks = loadElectiveTasks(bhList);
List<ElectiveCourseStudentVO> students = new ArrayList<>();
Set<String> teams = new LinkedHashSet<>();
for (XYDRWB task : tasks) {
if (!teams.add(task.getXydbh())) {
continue;
}
KB course = kbMapper.selectById(task.getKbh());
List<ElectiveCourseStudentVO> rows = electiveCourseMapper.selectElectiveStudents(task.getXydbh());
if (rows == null) {
continue;
}
for (ElectiveCourseStudentVO row : rows) {
if (course != null) {
row.setKmc(course.getKmc());
}
students.add(row);
}
}
if (students.isEmpty()) {
throw new ServiceException("所选选修班暂无学员", BAD_REQUEST);
}
for (int i = 0; i < students.size(); i++) {
students.get(i).setXh(i + 1);
}
return students;
}
private void upsertPinban(String xydbh, String zt, LocalDateTime start, LocalDateTime end,
String yqsm, String bmdtj, String bz) {
Integer exists = electiveCourseMapper.countPinban(xydbh);
if (exists == null || exists == 0) {
electiveCourseMapper.insertPinban(xydbh, zt == null ? STATUS_DRAFT : zt, start, end, yqsm, bmdtj, bz);
} else {
electiveCourseMapper.updatePinban(xydbh, zt, start, end, yqsm, bmdtj);
}
}
private String resolveTeamId(String xydbh, String xxbmc, String nj, boolean createIfMissing) {
if (StringUtils.isNotEmpty(xydbh)) {
XYDB exists = xydbMapper.selectById(xydbh);
if (exists == null) {
throw new ServiceException("选修班不存在", NOT_FOUND);
}
return xydbh;
}
if (StringUtils.isEmpty(xxbmc)) {
throw new ServiceException("选修班编号或名称不能为空", BAD_REQUEST);
}
XYDB team = xydbMapper.selectOne(new LambdaQueryWrapper<XYDB>().eq(XYDB::getXydmc, xxbmc.trim()));
if (team != null) {
return team.getXydbh();
}
if (!createIfMissing) {
throw new ServiceException("选修班不存在:" + xxbmc, NOT_FOUND);
}
XYDB created = new XYDB();
created.setXydbh(UuidUtil.getOriginalUUID());
created.setXydmc(xxbmc.trim());
created.setNj(blankToNull(nj));
created.setXydlx(CLASS_TYPE_ELECTIVE);
created.setXslx(0);
xydbMapper.insert(created);
return created.getXydbh();
}
private KB requireCourse(String kbh) {
if (StringUtils.isEmpty(kbh)) {
throw new ServiceException("课程科目不能为空", BAD_REQUEST);
}
KB course = kbMapper.selectById(kbh);
if (course == null) {
throw new ServiceException("课程科目不存在", NOT_FOUND);
}
return course;
}
private void updateTeamDates(String xydbh, LocalDateTime start, LocalDateTime end) {
if (start == null && end == null) {
return;
}
XYDB patch = new XYDB();
patch.setXydbh(xydbh);
if (start != null) {
patch.setRxrq(start);
}
if (end != null) {
patch.setByrq(end);
}
xydbMapper.updateById(patch);
}
private void updatePeriodRegister(String xydbh, Integer allowRegister, boolean stopNow) {
List<XYDQB> periods = xydqbMapper.selectList(new LambdaQueryWrapper<XYDQB>().eq(XYDQB::getXydbh, xydbh));
if (periods == null || periods.isEmpty()) {
return;
}
for (XYDQB period : periods) {
LambdaUpdateWrapper<XYDQB> update = new LambdaUpdateWrapper<XYDQB>()
.eq(XYDQB::getBh, period.getBh())
.set(XYDQB::getYxzc, allowRegister);
if (stopNow) {
update.set(XYDQB::getJszcsj, LocalDateTime.now());
}
xydqbMapper.update(null, update);
}
}
private ElectiveCourseQuery normalizeQuery(ElectiveCourseQuery cond) {
ElectiveCourseQuery filter = cond == null ? new ElectiveCourseQuery() : cond;
filter.setJyxm(blankToNull(filter.getJyxm()));
filter.setKmc(blankToNull(filter.getKmc()));
filter.setKxbcnj(blankToNull(filter.getKxbcnj()));
filter.setXxbmc(blankToNull(filter.getXxbmc()));
filter.setPxcc(normalizeNone(filter.getPxcc()));
filter.setXkzt(normalizeNone(filter.getXkzt()));
return filter;
}
private void fillSerial(List<ElectiveCourseVO> records, int pageNum, int pageSize) {
if (records == null) {
return;
}
int start = Math.max(pageNum - 1, 0) * Math.max(pageSize, 0);
for (int i = 0; i < records.size(); i++) {
records.get(i).setXh(start + i + 1);
}
}
private void writeStudentWord(XWPFDocument doc, List<ElectiveCourseStudentVO> students) {
XWPFParagraph title = doc.createParagraph();
title.setAlignment(ParagraphAlignment.CENTER);
XWPFRun titleRun = title.createRun();
titleRun.setText("选修班学员名单");
titleRun.setBold(true);
titleRun.setFontSize(16);
XWPFTable table = doc.createTable(students.size() + 1, 7);
String[] headers = {"序号", "选修班名称", "课程", "学号", "姓名", "性别", "联系电话"};
XWPFTableRow headerRow = table.getRow(0);
for (int i = 0; i < headers.length; i++) {
setCellText(headerRow.getCell(i), headers[i]);
}
for (int i = 0; i < students.size(); i++) {
ElectiveCourseStudentVO row = students.get(i);
XWPFTableRow tableRow = table.getRow(i + 1);
setCellText(tableRow.getCell(0), String.valueOf(row.getXh()));
setCellText(tableRow.getCell(1), nvl(row.getXxbmc()));
setCellText(tableRow.getCell(2), nvl(row.getKmc()));
setCellText(tableRow.getCell(3), nvl(row.getXhNo()));
setCellText(tableRow.getCell(4), nvl(row.getXm()));
setCellText(tableRow.getCell(5), nvl(row.getXb()));
setCellText(tableRow.getCell(6), nvl(row.getLxdh()));
}
}
private void setCellText(XWPFTableCell cell, String text) {
cell.removeParagraph(0);
XWPFParagraph paragraph = cell.addParagraph();
XWPFRun run = paragraph.createRun();
run.setText(text == null ? "" : text);
run.setFontSize(11);
}
private String ensureElectiveType(String klx) {
if (StringUtils.isEmpty(klx)) {
return COURSE_TYPE_ELECTIVE;
}
return klx.contains(COURSE_TYPE_ELECTIVE) ? klx : klx + COURSE_TYPE_ELECTIVE;
}
private String normalizeStatus(String status) {
String value = normalizeNone(status);
if (value == null) {
return STATUS_DRAFT;
}
if (STATUS_OPEN.equals(value) || STATUS_STOP.equals(value) || STATUS_DRAFT.equals(value)) {
return value;
}
return STATUS_DRAFT;
}
private int statusToFlag(String status) {
String value = normalizeStatus(status);
if (STATUS_OPEN.equals(value)) {
return FLAG_OPEN;
}
if (STATUS_STOP.equals(value)) {
return FLAG_STOP;
}
return FLAG_DRAFT;
}
private String normalizeNone(String value) {
String trimmed = blankToNull(value);
if (trimmed == null || "无".equals(trimmed)) {
return null;
}
return trimmed;
}
private String blankToNull(String value) {
return StringUtils.isEmpty(value) ? null : value.trim();
}
private String nvl(String value) {
return value == null ? "" : value;
}
private LocalDateTime parseDateTime(String text) {
String value = blankToNull(text);
if (value == null) {
return null;
}
try {
if (value.length() <= 10) {
if (value.contains("/")) {
return LocalDate.parse(value, DateTimeFormatter.ofPattern("yyyy/MM/dd")).atStartOfDay();
}
return LocalDate.parse(value, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay();
}
return LocalDateTime.parse(value, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
} catch (Exception e) {
throw new ServiceException("日期格式不正确:" + text, BAD_REQUEST);
}
}
}
@@ -1,13 +1,30 @@
package com.roomroot.jwgl.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.roomroot.common.utils.StringUtils;
import com.roomroot.common.utils.poi.ExcelUtil;
import com.roomroot.jwgl.dto.kcb.TimetableQuery;
import com.roomroot.jwgl.entity.KCB;
import com.roomroot.jwgl.mapper.KCBMapper;
import com.roomroot.jwgl.mapper.KcbTimetableMapper;
import com.roomroot.jwgl.mapper.SystemInitializationMapper;
import com.roomroot.jwgl.service.KCBService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.utils.UuidUtil;
import com.roomroot.jwgl.utils.JwglRoleHelper;
import com.roomroot.jwgl.vo.kcb.ClassTimetableVO;
import com.roomroot.jwgl.vo.kcb.DailyWeeklyTimetableVO;
import com.roomroot.jwgl.vo.kcb.SemesterGradeExportVO;
import com.roomroot.jwgl.vo.systeminitialization.SemesterInitializationVO;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
/**
@@ -16,9 +33,20 @@ import java.util.List;
@Service
public class KCBServiceImpl implements KCBService {
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
@Resource
private KCBMapper kcbMapper;
@Resource
private KcbTimetableMapper kcbTimetableMapper;
@Resource
private SystemInitializationMapper systemInitializationMapper;
@Resource
private JwglRoleHelper jwglRoleHelper;
@Override
public void add(KCB kcb) {
if (kcb.getCjsj() == null) {
@@ -56,4 +84,108 @@ public class KCBServiceImpl implements KCBService {
return kcbMapper.selectList(null);
}
@Override
public List<DailyWeeklyTimetableVO> listToday(TimetableQuery cond) {
TimetableQuery filter = prepareFilter(cond);
String today = LocalDate.now().format(DATE_FORMAT);
return kcbTimetableMapper.selectLessonTimetable(filter, today, today);
}
@Override
public List<DailyWeeklyTimetableVO> listWeek(TimetableQuery cond) {
TimetableQuery filter = prepareFilter(cond);
LocalDate today = LocalDate.now();
LocalDate monday = today.with(DayOfWeek.MONDAY);
LocalDate sunday = today.with(DayOfWeek.SUNDAY);
return kcbTimetableMapper.selectLessonTimetable(filter,
monday.format(DATE_FORMAT), sunday.format(DATE_FORMAT));
}
@Override
public PageResult<ClassTimetableVO> pageClassTimetable(PageQuery query, TimetableQuery cond) {
TimetableQuery filter = prepareFilter(cond);
int pageNum = (query == null || query.getPageNum() == null) ? 1 : query.getPageNum();
int pageSize = (query == null || query.getPageSize() == null) ? 20 : query.getPageSize();
Page<ClassTimetableVO> page = new Page<>(pageNum, pageSize);
Page<ClassTimetableVO> result = kcbTimetableMapper.selectClassTimetable(page, filter);
return new PageResult<>(result.getRecords(), result.getTotal(), pageNum, pageSize);
}
@Override
public void exportSemesterPlan(TimetableQuery cond, HttpServletResponse response) {
TimetableQuery filter = prepareFilter(cond);
String[] range = resolveSemesterDateRange(filter);
List<DailyWeeklyTimetableVO> list = kcbTimetableMapper.selectLessonTimetable(filter, range[0], range[1]);
ExcelUtil<DailyWeeklyTimetableVO> util = new ExcelUtil<>(DailyWeeklyTimetableVO.class);
util.exportExcel(response, list, "学期教学实施计划");
}
@Override
public void exportSemesterGrades(TimetableQuery cond, HttpServletResponse response) {
TimetableQuery filter = prepareFilter(cond);
List<SemesterGradeExportVO> list = kcbTimetableMapper.selectSemesterGrades(filter);
ExcelUtil<SemesterGradeExportVO> util = new ExcelUtil<>(SemesterGradeExportVO.class);
util.exportExcel(response, list, "学期成绩表");
}
@Override
public void exportClassCourses(TimetableQuery cond, HttpServletResponse response) {
TimetableQuery filter = prepareFilter(cond);
List<ClassTimetableVO> list = kcbTimetableMapper.selectClassTimetableList(filter);
ExcelUtil<ClassTimetableVO> util = new ExcelUtil<>(ClassTimetableVO.class);
util.exportExcel(response, list, "班次课程列表");
}
/**
* 未传年度时按当前学期填充;队别班次名称去空白。
* 学员强制只看本人所在学员队课表。
*/
private TimetableQuery prepareFilter(TimetableQuery cond) {
TimetableQuery filter = cond == null ? new TimetableQuery() : cond;
if (jwglRoleHelper.isStudent()) {
filter.setXydbh(jwglRoleHelper.requireStudentTeamId());
filter.setXydmc(null);
} else {
if (StringUtils.isNotEmpty(filter.getXydbh())) {
filter.setXydbh(filter.getXydbh().trim());
}
if (StringUtils.isNotEmpty(filter.getXydmc())) {
filter.setXydmc(filter.getXydmc().trim());
}
}
if (filter.getNd() != null) {
return filter;
}
SemesterInitializationVO semester = systemInitializationMapper.selectCurrentSemester();
if (semester != null && semester.getYear() != null) {
filter.setNd(semester.getYear());
if (filter.getXqdc() == null) {
filter.setXqdc(semester.getSequenceNumber());
}
} else {
filter.setNd(LocalDate.now().getYear());
}
return filter;
}
/**
* 本学期用开学/结束日期;查其他年度时退回该年 1 月 1 日至 12 月 31 日。
*/
private String[] resolveSemesterDateRange(TimetableQuery filter) {
SemesterInitializationVO semester = systemInitializationMapper.selectCurrentSemester();
if (semester != null && semester.getStartAt() != null && semester.getEndAt() != null
&& filter.getNd() != null && filter.getNd().equals(semester.getYear())
&& (filter.getXqdc() == null || filter.getXqdc().equals(semester.getSequenceNumber()))) {
return new String[]{
semester.getStartAt().toLocalDate().format(DATE_FORMAT),
semester.getEndAt().toLocalDate().format(DATE_FORMAT)
};
}
LocalDate now = LocalDate.now();
int year = filter.getNd() == null ? now.getYear() : filter.getNd();
LocalDate start = LocalDate.of(year, 1, 1);
LocalDate end = LocalDate.of(year, 12, 31);
return new String[]{start.format(DATE_FORMAT), end.format(DATE_FORMAT)};
}
}
@@ -39,10 +39,8 @@ public class SemesterServiceImpl extends ServiceImpl<SemesterMapper, XQ> impleme
if(insert > 0){
LocalDateTime kxrq = xq.getKxrq();
LocalDateTime jsrq = xq.getJsrq();
String startDate = localDateTimeToDateStr(kxrq);
String endDate = localDateTimeToDateStr(jsrq);
semesterCalendarService.add(startDate, endDate);
}
}
@@ -0,0 +1,412 @@
package com.roomroot.jwgl.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.roomroot.common.exception.ServiceException;
import com.roomroot.common.utils.StringUtils;
import com.roomroot.jwgl.dto.jys.TeachingTaskQuery;
import com.roomroot.jwgl.dto.jys.TeachingTaskSaveDTO;
import com.roomroot.jwgl.entity.JXRW;
import com.roomroot.jwgl.entity.JYSRWS;
import com.roomroot.jwgl.entity.KB;
import com.roomroot.jwgl.entity.XYDB;
import com.roomroot.jwgl.entity.XYDNDXQJBXXB;
import com.roomroot.jwgl.entity.XYDRWB;
import com.roomroot.jwgl.entity.ZYJXJHB;
import com.roomroot.jwgl.mapper.ClassSemesterMapper;
import com.roomroot.jwgl.mapper.KBMapper;
import com.roomroot.jwgl.mapper.OfficeTaskBookMapper;
import com.roomroot.jwgl.mapper.StudentTeamTaskMapper;
import com.roomroot.jwgl.mapper.SystemInitializationMapper;
import com.roomroot.jwgl.mapper.TeachingTaskMapper;
import com.roomroot.jwgl.mapper.XYDBMapper;
import com.roomroot.jwgl.mapper.ZYJXJHBMapper;
import com.roomroot.jwgl.service.StudentTeamTaskService;
import com.roomroot.jwgl.service.TeachingTaskManageService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.utils.UuidUtil;
import com.roomroot.jwgl.vo.jys.TeachingOfficeBookCourseVO;
import com.roomroot.jwgl.vo.jys.TeachingOfficeBookVO;
import com.roomroot.jwgl.vo.jys.TeachingTaskDetailVO;
import com.roomroot.jwgl.vo.jys.TeachingTaskSquadVO;
import com.roomroot.jwgl.vo.jys.TeachingTaskVO;
import com.roomroot.jwgl.vo.systeminitialization.SemesterInitializationVO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import jakarta.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import static com.roomroot.jwgl.utils.BasicManagementConstants.BAD_REQUEST;
import static com.roomroot.jwgl.utils.BasicManagementConstants.CONFLICT;
import static com.roomroot.jwgl.utils.BasicManagementConstants.NOT_FOUND;
/**
* 教学任务管理实现。
*/
@Service
public class TeachingTaskManageServiceImpl implements TeachingTaskManageService {
private static final String STATUS_DRAFT = "上报";
private static final String STATUS_PUBLISHED = "发布";
private static final String OFFICE_STATUS_UNREPORTED = "未上报";
private static final String OFFICE_STATUS_PUBLISHED = "发布";
@Resource
private TeachingTaskMapper teachingTaskMapper;
@Resource
private OfficeTaskBookMapper officeTaskBookMapper;
@Resource
private ClassSemesterMapper classSemesterMapper;
@Resource
private XYDBMapper xydbMapper;
@Resource
private KBMapper kbMapper;
@Resource
private ZYJXJHBMapper zyjxjhbMapper;
@Resource
private StudentTeamTaskMapper studentTeamTaskMapper;
@Resource
private StudentTeamTaskService studentTeamTaskService;
@Resource
private SystemInitializationMapper systemInitializationMapper;
@Override
public PageResult<TeachingTaskVO> pageList(PageQuery query, TeachingTaskQuery cond) {
TeachingTaskQuery filter = cond == null ? new TeachingTaskQuery() : cond;
if (StringUtils.isNotEmpty(filter.getRwmc())) {
filter.setRwmc(filter.getRwmc().trim());
}
int pageNum = query == null || query.getPageNum() == null ? 1 : query.getPageNum();
int pageSize = query == null || query.getPageSize() == null ? 20 : query.getPageSize();
Page<TeachingTaskVO> result = teachingTaskMapper.selectManagePage(new Page<>(pageNum, pageSize), filter);
if (result.getRecords() != null) {
for (TeachingTaskVO row : result.getRecords()) {
fillSemesterName(row);
}
}
return new PageResult<>(result.getRecords(), result.getTotal(), pageNum, pageSize);
}
@Override
public TeachingTaskDetailVO getDetail(String bh) {
if (StringUtils.isEmpty(bh)) {
throw new ServiceException("教学任务编号不能为空", BAD_REQUEST);
}
JXRW entity = teachingTaskMapper.selectById(bh);
if (entity == null || Integer.valueOf(1).equals(entity.getDelFlag())) {
throw new ServiceException("教学任务不存在", NOT_FOUND);
}
TeachingTaskVO vo = toSimpleVo(entity);
List<TeachingTaskSquadVO> squads = listBoundSquads(bh);
if (!squads.isEmpty() && squads.get(0).getXqdc() != null) {
vo.setXqdc(squads.get(0).getXqdc());
}
fillSemesterName(vo);
TeachingTaskDetailVO detail = new TeachingTaskDetailVO();
detail.setTask(vo);
detail.setOfficeBooks(listOfficeBooks(bh));
detail.setSquads(squads);
return detail;
}
@Transactional(rollbackFor = Exception.class)
@Override
public void add(TeachingTaskSaveDTO dto) {
if (dto == null || StringUtils.isEmpty(dto.getRwmc())) {
throw new ServiceException("任务名称不能为空", BAD_REQUEST);
}
fillSemester(dto);
JXRW entity = new JXRW();
entity.setBh(UuidUtil.getOriginalUUID());
entity.setRwmc(dto.getRwmc().trim());
entity.setNd(dto.getNd());
entity.setZt(STATUS_DRAFT);
entity.setCjsj(LocalDateTime.now());
entity.setJssj(dto.getJssj() != null ? dto.getJssj() : defaultEndTime(dto.getNd(), dto.getXqdc()));
entity.setDelFlag(0);
teachingTaskMapper.insert(entity);
bindSquads(entity.getBh(), dto.getNd(), dto.getXqdc(), dto.getXydxqbhList());
generateCourseTasksAndOfficeBooks(entity.getBh());
}
@Transactional(rollbackFor = Exception.class)
@Override
public void update(TeachingTaskSaveDTO dto) {
if (dto == null || StringUtils.isEmpty(dto.getBh())) {
throw new ServiceException("教学任务编号不能为空", BAD_REQUEST);
}
if (StringUtils.isEmpty(dto.getRwmc())) {
throw new ServiceException("任务名称不能为空", BAD_REQUEST);
}
JXRW entity = teachingTaskMapper.selectById(dto.getBh());
if (entity == null || Integer.valueOf(1).equals(entity.getDelFlag())) {
throw new ServiceException("教学任务不存在", NOT_FOUND);
}
fillSemester(dto);
entity.setRwmc(dto.getRwmc().trim());
if (dto.getJssj() != null) {
entity.setJssj(dto.getJssj());
}
teachingTaskMapper.updateById(entity);
bindSquads(entity.getBh(), dto.getNd(), dto.getXqdc(), dto.getXydxqbhList());
generateCourseTasksAndOfficeBooks(entity.getBh());
}
@Transactional(rollbackFor = Exception.class)
@Override
public void delete(String bh) {
if (StringUtils.isEmpty(bh)) {
throw new ServiceException("教学任务编号不能为空", BAD_REQUEST);
}
JXRW entity = teachingTaskMapper.selectById(bh);
if (entity == null || Integer.valueOf(1).equals(entity.getDelFlag())) {
return;
}
entity.setDelFlag(1);
teachingTaskMapper.updateById(entity);
List<JYSRWS> books = officeTaskBookMapper.selectList(new LambdaQueryWrapper<JYSRWS>()
.eq(JYSRWS::getJxrwbh, bh)
.eq(JYSRWS::getDelFlag, 0));
for (JYSRWS book : books) {
book.setDelFlag(1);
officeTaskBookMapper.updateById(book);
}
classSemesterMapper.update(null, new LambdaUpdateWrapper<XYDNDXQJBXXB>()
.eq(XYDNDXQJBXXB::getJxrwbh, bh)
.set(XYDNDXQJBXXB::getJxrwbh, null));
}
@Transactional(rollbackFor = Exception.class)
@Override
public int publish(String bh) {
if (StringUtils.isEmpty(bh)) {
throw new ServiceException("教学任务编号不能为空", BAD_REQUEST);
}
JXRW entity = teachingTaskMapper.selectById(bh);
if (entity == null || Integer.valueOf(1).equals(entity.getDelFlag())) {
throw new ServiceException("教学任务不存在", NOT_FOUND);
}
if (STATUS_PUBLISHED.equals(entity.getZt())) {
throw new ServiceException("该教学任务已发布", CONFLICT);
}
generateCourseTasksAndOfficeBooks(bh);
entity.setZt(STATUS_PUBLISHED);
entity.setFbsj(LocalDateTime.now());
teachingTaskMapper.updateById(entity);
List<JYSRWS> books = officeTaskBookMapper.selectList(new LambdaQueryWrapper<JYSRWS>()
.eq(JYSRWS::getJxrwbh, bh)
.eq(JYSRWS::getDelFlag, 0));
for (JYSRWS book : books) {
book.setZt(OFFICE_STATUS_PUBLISHED);
officeTaskBookMapper.updateById(book);
}
return books.size();
}
@Override
public List<TeachingOfficeBookVO> listOfficeBooks(String jxrwbh) {
if (StringUtils.isEmpty(jxrwbh)) {
return new ArrayList<>();
}
List<TeachingOfficeBookVO> list = teachingTaskMapper.selectOfficeBooks(jxrwbh);
return list == null ? new ArrayList<>() : list;
}
@Override
public List<TeachingOfficeBookCourseVO> listOfficeBookCourses(String jxrwbh, String jysdh) {
if (StringUtils.isEmpty(jxrwbh) || StringUtils.isEmpty(jysdh)) {
throw new ServiceException("教学任务编号和教研室代号不能为空", BAD_REQUEST);
}
List<TeachingOfficeBookCourseVO> list = teachingTaskMapper.selectOfficeBookCourses(jxrwbh, jysdh);
return list == null ? new ArrayList<>() : list;
}
@Override
public List<TeachingTaskSquadVO> listBoundSquads(String jxrwbh) {
if (StringUtils.isEmpty(jxrwbh)) {
return new ArrayList<>();
}
List<TeachingTaskSquadVO> list = teachingTaskMapper.selectBoundSquads(jxrwbh);
return list == null ? new ArrayList<>() : list;
}
@Override
public List<TeachingTaskSquadVO> listAvailableSquads(Integer nd, Integer xqdc, String jxrwbh) {
if (nd == null || xqdc == null) {
SemesterInitializationVO semester = systemInitializationMapper.selectCurrentSemester();
if (semester == null || semester.getYear() == null || semester.getSequenceNumber() == null) {
throw new ServiceException("未设置当前学期,请指定年度和学期第次", BAD_REQUEST);
}
nd = semester.getYear();
xqdc = semester.getSequenceNumber();
}
List<TeachingTaskSquadVO> list = teachingTaskMapper.selectAvailableSquads(nd, xqdc, jxrwbh);
return list == null ? new ArrayList<>() : list;
}
private void fillSemester(TeachingTaskSaveDTO dto) {
if (dto.getNd() != null && dto.getXqdc() != null) {
return;
}
SemesterInitializationVO semester = systemInitializationMapper.selectCurrentSemester();
if (semester == null || semester.getYear() == null) {
if (dto.getNd() == null) {
throw new ServiceException("请选择学期", BAD_REQUEST);
}
return;
}
if (dto.getNd() == null) {
dto.setNd(semester.getYear());
}
if (dto.getXqdc() == null) {
dto.setXqdc(semester.getSequenceNumber());
}
}
private LocalDateTime defaultEndTime(Integer nd, Integer xqdc) {
if (nd == null || xqdc == null) {
return null;
}
SemesterInitializationVO semester = systemInitializationMapper.selectSemesterByKey(nd, xqdc);
return semester == null ? null : semester.getEndAt();
}
private void fillSemesterName(TeachingTaskVO row) {
if (row == null || row.getNd() == null || row.getXqdc() == null) {
return;
}
SemesterInitializationVO semester = systemInitializationMapper.selectSemesterByKey(row.getNd(), row.getXqdc());
if (semester != null && StringUtils.isNotEmpty(semester.getSemesterName())) {
row.setXqmc(semester.getSemesterName());
} else {
row.setXqmc(row.getNd() + "年第" + row.getXqdc() + "学期");
}
}
private TeachingTaskVO toSimpleVo(JXRW entity) {
TeachingTaskVO vo = new TeachingTaskVO();
vo.setBh(entity.getBh());
vo.setRwmc(entity.getRwmc());
vo.setNd(entity.getNd());
vo.setZt(entity.getZt());
vo.setFbsj(entity.getFbsj());
vo.setCjsj(entity.getCjsj());
vo.setJssj(entity.getJssj());
return vo;
}
private void bindSquads(String jxrwbh, Integer nd, Integer xqdc, List<String> xydxqbhList) {
classSemesterMapper.update(null, new LambdaUpdateWrapper<XYDNDXQJBXXB>()
.eq(XYDNDXQJBXXB::getJxrwbh, jxrwbh)
.set(XYDNDXQJBXXB::getJxrwbh, null));
if (CollectionUtils.isEmpty(xydxqbhList)) {
return;
}
for (String xydxqbh : xydxqbhList) {
if (StringUtils.isEmpty(xydxqbh)) {
continue;
}
XYDNDXQJBXXB semester = classSemesterMapper.selectById(xydxqbh);
if (semester == null || Integer.valueOf(1).equals(semester.getDelFlag())) {
throw new ServiceException("学员队学期信息不存在:" + xydxqbh, NOT_FOUND);
}
if (nd != null && semester.getNd() != null && !nd.equals(semester.getNd())) {
throw new ServiceException("所选学员队不属于该学期", BAD_REQUEST);
}
if (xqdc != null && semester.getXqdc() != null && !xqdc.equals(semester.getXqdc())) {
throw new ServiceException("所选学员队不属于该学期", BAD_REQUEST);
}
if (StringUtils.isNotEmpty(semester.getJxrwbh()) && !jxrwbh.equals(semester.getJxrwbh())) {
throw new ServiceException("学员队已被其他教学任务占用", CONFLICT);
}
semester.setJxrwbh(jxrwbh);
classSemesterMapper.updateById(semester);
}
}
private void generateCourseTasksAndOfficeBooks(String jxrwbh) {
List<XYDNDXQJBXXB> squads = classSemesterMapper.selectList(new LambdaQueryWrapper<XYDNDXQJBXXB>()
.eq(XYDNDXQJBXXB::getJxrwbh, jxrwbh)
.eq(XYDNDXQJBXXB::getDelFlag, 0));
for (XYDNDXQJBXXB squad : squads) {
if (StringUtils.isEmpty(squad.getXydbh()) || squad.getXqdc() == null) {
continue;
}
try {
studentTeamTaskService.autoGenerateRequiredCourses(squad.getXydbh(), squad.getXqdc());
} catch (Exception ignored) {
// 课程任务已存在或计划缺失时,仍继续生成教研室任务书
}
}
Set<String> jysdhSet = collectOfficeCodes(squads);
for (String jysdh : jysdhSet) {
Long exist = officeTaskBookMapper.selectCount(new LambdaQueryWrapper<JYSRWS>()
.eq(JYSRWS::getJxrwbh, jxrwbh)
.eq(JYSRWS::getJysdh, jysdh)
.eq(JYSRWS::getDelFlag, 0));
if (exist != null && exist > 0) {
continue;
}
JYSRWS book = new JYSRWS();
book.setBh(UuidUtil.getOriginalUUID());
book.setJxrwbh(jxrwbh);
book.setJysdh(jysdh);
book.setZt(OFFICE_STATUS_UNREPORTED);
book.setDelFlag(0);
officeTaskBookMapper.insert(book);
}
}
private Set<String> collectOfficeCodes(List<XYDNDXQJBXXB> squads) {
Set<String> codes = new LinkedHashSet<>();
List<String> xydxqbhList = new ArrayList<>();
for (XYDNDXQJBXXB squad : squads) {
xydxqbhList.add(squad.getBh());
if (StringUtils.isEmpty(squad.getXydbh()) || squad.getXqdc() == null) {
continue;
}
XYDB xyd = xydbMapper.selectById(squad.getXydbh());
if (xyd == null || StringUtils.isEmpty(xyd.getZydh())) {
continue;
}
List<ZYJXJHB> plans = zyjxjhbMapper.selectList(new LambdaQueryWrapper<ZYJXJHB>()
.eq(ZYJXJHB::getZydh, xyd.getZydh())
.eq(ZYJXJHB::getXqdc, squad.getXqdc())
.eq(ZYJXJHB::getTy, 0));
for (ZYJXJHB plan : plans) {
if (StringUtils.isNotEmpty(plan.getJysdh())) {
codes.add(plan.getJysdh());
continue;
}
if (StringUtils.isEmpty(plan.getKbh())) {
continue;
}
KB kb = kbMapper.selectById(plan.getKbh());
if (kb != null && StringUtils.isNotEmpty(kb.getJysdh())) {
codes.add(kb.getJysdh());
}
}
}
if (!xydxqbhList.isEmpty()) {
List<XYDRWB> tasks = studentTeamTaskMapper.selectList(new LambdaQueryWrapper<XYDRWB>()
.in(XYDRWB::getXydxqbh, xydxqbhList)
.eq(XYDRWB::getDelFlag, 0));
for (XYDRWB task : tasks) {
if (StringUtils.isNotEmpty(task.getJysdh())) {
codes.add(task.getJysdh());
}
}
}
return codes;
}
}