package com.xjrsoft.module.courseTable.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.xjrsoft.common.enums.CourseAdjustTypeEnum;
import com.xjrsoft.common.enums.TimeNumberEnum;
import com.xjrsoft.common.enums.TimePeriodEnum;
import com.xjrsoft.common.enums.WeekEnum;
import com.xjrsoft.common.exception.MyException;
import com.xjrsoft.config.TimetableConfig;
import com.xjrsoft.module.base.entity.BaseClass;
import com.xjrsoft.module.base.entity.BaseSemester;
import com.xjrsoft.module.base.mapper.BaseSemesterMapper;
import com.xjrsoft.module.base.service.IBaseClassService;
import com.xjrsoft.module.base.service.IBaseSemesterService;
import com.xjrsoft.module.courseTable.dto.ClassListDto;
import com.xjrsoft.module.courseTable.dto.CourseTableParse;
import com.xjrsoft.module.courseTable.entity.ClassTime;
import com.xjrsoft.module.courseTable.entity.CourseTable;
import com.xjrsoft.module.courseTable.mapper.ClassTimeMapper;
import com.xjrsoft.module.courseTable.mapper.CourseTableMapper;
import com.xjrsoft.module.courseTable.service.ICourseTableService;
import com.xjrsoft.module.courseTable.vo.ClassListVo;
import com.xjrsoft.module.schedule.dto.CourseTableAdjustDto;
import com.xjrsoft.module.schedule.dto.CourseTableDto;
import com.xjrsoft.module.schedule.entity.WfCourseAdjust;
import com.xjrsoft.module.schedule.mapper.CourseTableBakMapper;
import com.xjrsoft.module.schedule.util.ScheduleUtil;
import com.xjrsoft.module.schedule.vo.CourseDetailVo;
import com.xjrsoft.module.schedule.vo.CourseListVo;
import com.xjrsoft.module.schedule.vo.CourseTableVo;
import com.xjrsoft.module.teacher.entity.BaseTeacher;
import com.xjrsoft.module.teacher.entity.XjrUser;
import com.xjrsoft.module.teacher.service.ITeacherbaseManagerService;
import lombok.AllArgsConstructor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
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 java.io.IOException;
import java.io.InputStream;
import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
*
* 课表 服务实现类
*
*
* @author baomidou
* @since 2023-09-02 02:19:56
*/
@Service
@AllArgsConstructor
public class CourseTableServiceImpl extends ServiceImpl implements ICourseTableService {
private final CourseTableMapper courseTableMapper;
private final IBaseClassService baseClassService;
private final ITeacherbaseManagerService teacherbaseManagerService;
private final IBaseSemesterService baseSemesterService;
private final TimetableConfig timetableConfig;
private final ClassTimeMapper classTimeMapper;
private final BaseSemesterMapper baseSemesterMapper;
private final CourseTableBakMapper courseTableBakMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean wordImport(InputStream inputStream) throws IOException {
List parses = courseTableWordParses(inputStream);
String semester = null;
if (parses.size() > 0) {
semester = parses.get(0).getSemester();
}
BaseSemester baseSemester = baseSemesterService.getOne(Wrappers.query().lambda().eq(BaseSemester::getName, semester));
if (baseSemester == null) {
throw new MyException(String.format("学期【%s】不存在", semester));
}
// 获取班级信息
List baseClassList = baseClassService.list();
Map baseClassMap = baseClassList.stream().collect(Collectors.toMap(BaseClass::getName, a -> a, (k1, k2) -> k1));
// 获取教师信息
MPJLambdaWrapper queryWrapper = new MPJLambdaWrapper<>();
queryWrapper
.disableSubLogicDel()
.innerJoin(BaseTeacher.class, BaseTeacher::getUserId, XjrUser::getId)
.selectAll(XjrUser.class);
List xjrUserList = teacherbaseManagerService.list(queryWrapper);
Map xjrUsersMap = xjrUserList.stream().collect(Collectors.toMap(XjrUser::getName, a -> a, (k1, k2) -> k1));
// 清空所有数据
courseTableMapper.delete(Wrappers.query().lambda().eq(CourseTable::getBaseSemesterId, baseSemester.getId()));
List params = new ArrayList<>();
for (CourseTableParse item : parses) {
CourseTable courseTable = BeanUtil.toBean(item, CourseTable.class);
courseTable.setBaseSemesterId(baseSemester.getId());
BaseClass baseClass = baseClassMap.get(item.getClassName());
if (baseClass != null) {
courseTable.setClassId(baseClass.getId());
}
XjrUser xjrUser = xjrUsersMap.get(item.getTeacherName());
if (xjrUser != null) {
courseTable.setTeacherId(xjrUser.getId());
}
if (item.getWeeksCn() != null) {
courseTable.setWeeks(WeekEnum.getCode(item.getWeeksCn()));
}
params.add(courseTable);
}
return this.saveBatch(params);
}
@Override
public List classList(ClassListDto dto) {
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(CourseTable::getClassId, dto.getClassId())
.eq(ObjectUtil.isNotEmpty(dto.getWeeks()), CourseTable::getWeeks,dto.getWeeks());
List courseTables = courseTableMapper.selectList(queryWrapper);
List classListVos = BeanUtil.copyToList(courseTables, ClassListVo.class);
Boolean isCurrentSummer = isCurrentSummer();
Map classTimeMap = getClassTimeMap();
// 获取节次时间
for (int i = 0; i < classListVos.size(); i++) {
ClassListVo c = classListVos.get(i);
String key = String.format("%d_%d", c.getTimePeriod(), c.getTimeNumber());
ClassTime ct = classTimeMap.get(key);
if (ct != null) {
if (isCurrentSummer) {
c.setStartTime(ct.getSummerStartTime());
c.setEndTime(ct.getSummerEndTime());
} else {
c.setStartTime(ct.getWinterStartTime());
c.setEndTime(ct.getWinterEndTime());
}
}
}
return classListVos;
}
@Override
public CourseTableVo getList(CourseTableDto dto) {
List classTimes = classTimeMapper.selectList(
new QueryWrapper().lambda().orderByAsc(ClassTime::getSummerStartTime)
);
CourseTableVo tableVo = new CourseTableVo();
tableVo.setClassTimeList(classTimes);
if(dto.getSemesterId() != null){
BaseSemester baseSemester = baseSemesterMapper.selectById(dto.getSemesterId());
tableVo.setSemesterName(baseSemester.getName());
LocalDateTime now = LocalDateTime.now();
//计算本周是第几周
LocalDateTime startDateTime = LocalDateTime.ofInstant(baseSemester.getStartDate().toInstant(), ZoneId.systemDefault());
LocalDateTime endDateTime = LocalDateTime.ofInstant(baseSemester.getEndDate().toInstant(), ZoneId.systemDefault());
Duration between = Duration.between(startDateTime, endDateTime);
long days = between.toDays();
int weeks = (int) Math.ceil((double) days / 7);
if(dto.getWeek() == null){
for (int i = 0; i < weeks; i ++){
LocalDateTime startDate = startDateTime.plusDays(i * 7).withHour(0).withMinute(0).withSecond(0).withNano(0);
LocalDateTime endDate = startDateTime.plusDays((i + 1) * 7).withHour(23).withMinute(59).withSecond(59).withNano(9999);
if(now.isAfter(startDate) && now.isBefore(endDate)){
tableVo.setWeek("第" + (i + 1) + "周");
}
}
}else{
LocalDateTime startDate = startDateTime.plusDays((dto.getWeek() - 1) * 7).withHour(0).withMinute(0).withSecond(0).withNano(0);
LocalDateTime endDate = startDateTime.plusDays(dto.getWeek() * 7).withHour(23).withMinute(59).withSecond(59).withNano(9999);
dto.setStartDate(startDate);
dto.setEndDate(endDate);
tableVo.setWeek("第" + dto.getWeek() + "周");
}
}
if(!StrUtil.isEmpty(dto.getTeacherName())){
List userList = teacherbaseManagerService.list(
new QueryWrapper().lambda()
.like(!StrUtil.isEmpty(dto.getTeacherName()), XjrUser::getName, dto.getTeacherName())
.like(!StrUtil.isEmpty(dto.getJobNumber()), XjrUser::getCode, dto.getJobNumber())
);
if(userList != null && !userList.isEmpty()){
XjrUser xjrUser = userList.get(0);
dto.setTeacherId(xjrUser.getId());
tableVo.setTeacherName(xjrUser.getName());
}
}
List list = courseTableMapper.getList(dto);
tableVo.setCourseList(list);
tableVo.setClassHour(list.size());
if(dto.getClassId() != null){
BaseClass baseClass = baseClassService.getById(dto.getClassId());
tableVo.setClassName(baseClass.getName());
}
return tableVo;
}
/**
* 调课顶课查询
*/
@Override
public List getAdjustList(String teacherId, String adjustDate) {
CourseTableAdjustDto dto = new CourseTableAdjustDto();
if(adjustDate != null && !"".equals(adjustDate)){
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate localDateTime = LocalDate.parse(adjustDate, formatter);
DayOfWeek dayOfWeek = localDateTime.getDayOfWeek();
dto.setWeek(dayOfWeek.getValue());
}
dto.setTeacherId(Long.parseLong(teacherId));
return courseTableMapper.getAdjustList(dto);
}
@Override
public String getPreCheck(String preCheckType, String courseId, String swapCourseId, String swapDate, String subTeacherId) {
if(preCheckType != null && !"".equals(preCheckType)){
if(CourseAdjustTypeEnum.courseExchange.getCode().equals(preCheckType)){
CourseTable courseTable = courseTableMapper.selectById(courseId);
CourseTable swapCourseTable = courseTableMapper.selectById(swapCourseId);
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate localDateTime = LocalDate.parse(swapDate, formatter);
JsonObject preCheck = getExtendPreCheck(localDateTime, courseTable, swapCourseTable);
if(!preCheck.get("data").getAsBoolean() && !preCheck.get("msg").isJsonNull()){
return preCheck.get("msg").getAsString();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}else if(CourseAdjustTypeEnum.courseSubstitute.getCode().equals(preCheckType)){
CourseTable courseTable = courseTableMapper.selectById(courseId);
try {
JsonObject jsonObject = substitutePreTestin(subTeacherId, courseTable);
if(!jsonObject.get("data").getAsBoolean() && !jsonObject.get("msg").isJsonNull()){
return jsonObject.get("msg").getAsString();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
return null;
}
@Override
public Boolean adjustCourse(WfCourseAdjust courseAdjust) throws Exception {
if(CourseAdjustTypeEnum.courseExchange.getCode().equals(courseAdjust.getAdjustType())){
//调课,将双方课程的日期(schedule_date)、时段(time_period)、节次(time_number)、周(week)、星期几(1-7)(weeks)、星期中文(weeks_cn)对调
CourseTable courseTable = courseTableMapper.selectById(courseAdjust.getCourseId());
CourseTable swapCourseTable = courseTableMapper.selectById(courseAdjust.getExchangeCourseId());
CourseTable courseTableBak = BeanUtil.toBean(courseTable, CourseTable.class);
CourseTable swapCourseTableBak = BeanUtil.toBean(swapCourseTable, CourseTable.class);
courseTable.setScheduleDate(swapCourseTableBak.getScheduleDate());
courseTable.setTimePeriod(swapCourseTableBak.getTimePeriod());
courseTable.setTimeNumber(swapCourseTableBak.getTimeNumber());
courseTable.setWeek(swapCourseTableBak.getWeek());
courseTable.setWeeks(swapCourseTableBak.getWeeks());
courseTable.setWeeksCn(swapCourseTableBak.getWeeksCn());
courseTableMapper.updateById(courseTable);
swapCourseTable.setScheduleDate(courseTableBak.getScheduleDate());
swapCourseTable.setTimePeriod(courseTableBak.getTimePeriod());
swapCourseTable.setTimeNumber(courseTableBak.getTimeNumber());
swapCourseTable.setWeek(courseTableBak.getWeek());
swapCourseTable.setWeeks(courseTableBak.getWeeks());
swapCourseTable.setWeeksCn(courseTableBak.getWeeksCn());
courseTableMapper.updateById(swapCourseTable);
//提交调课接口
sendExchange(courseTableBak, swapCourseTableBak, courseAdjust);
}else if(CourseAdjustTypeEnum.courseSubstitute.getCode().equals(courseAdjust.getAdjustType())){
CourseTable courseTable = courseTableMapper.selectById(courseAdjust.getCourseId());
courseTable.setTeacherId(courseAdjust.getExchangeTeacherId());
courseTableMapper.updateById(courseTable);
//提交顶课接口
sendSubstitute(courseTable, courseAdjust);
}
return Boolean.TRUE;
}
/**
* 提交顶课接口
* @param courseTable
* @param courseAdjust
* @throws Exception
*/
void sendSubstitute(CourseTable courseTable, WfCourseAdjust courseAdjust) throws Exception {
String url = ScheduleUtil.apiUrl + "RescheduleApply/Extend/Substitute/Submit";
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("timetableId", courseTable.getJianyueId());
jsonObject.addProperty("isCycles", Boolean.FALSE);
jsonObject.addProperty("reason", courseAdjust.getReason());
jsonObject.addProperty("teacherId", courseAdjust.getUserId());
JsonArray extendIds = new JsonArray();
extendIds.add(courseTable.getTeacherId());
jsonObject.add("extendIds", extendIds);
//获取时间戳
long timestamp = System.currentTimeMillis();
//生成签名
String sign = ScheduleUtil.createSign(timestamp);
String result = ScheduleUtil.doPost(url, jsonObject.toString(), sign, timestamp);
System.out.println(result);
}
/**
* 提交调课
* @param courseTable
* @param swapCourseTable
* @throws Exception
*/
void sendExchange(CourseTable courseTable, CourseTable swapCourseTable, WfCourseAdjust courseAdjust) throws Exception {
String url = ScheduleUtil.apiUrl + "RescheduleApply/Extend/Submit";
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("timetableId", courseTable.getJianyueId());
jsonObject.addProperty("isCycles", Boolean.FALSE);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
jsonObject.addProperty("date", swapCourseTable.getScheduleDate().format(formatter));
jsonObject.addProperty("numberOfDay", swapCourseTable.getTimeNumber());
jsonObject.addProperty("rescheduleId", swapCourseTable.getJianyueId());
jsonObject.addProperty("reason", courseAdjust.getReason());
jsonObject.addProperty("teacherId", courseAdjust.getUserId());
//获取时间戳
long timestamp = System.currentTimeMillis();
//生成签名
String sign = ScheduleUtil.createSign(timestamp);
String result = ScheduleUtil.doPost(url, jsonObject.toString(), sign, timestamp);
}
/**
* 顶课预检查
* @param courseTable
* @return 检查结果
*/
JsonObject substitutePreTestin(String subTeacherId, CourseTable courseTable) throws Exception {
JsonParser jsonParser = new JsonParser();
String url = ScheduleUtil.apiUrl + "RescheduleApply/Extend/Substitute/PreTesting";
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("timetableId", courseTable.getJianyueId());
jsonObject.addProperty("isCycles", Boolean.FALSE);
JsonArray extendIds = new JsonArray();
extendIds.add(subTeacherId);
jsonObject.add("extendIds", extendIds);
//获取时间戳
long timestamp = System.currentTimeMillis();
//生成签名
String sign = ScheduleUtil.createSign(timestamp);
String result = ScheduleUtil.doPost(url, jsonObject.toString(), sign, timestamp);
if(StrUtil.isEmpty(result)){
return null;
}
return jsonParser.parse(result).getAsJsonObject();
}
/**
* 调课预检查
* @param courseTable 需要调整的课程
* @param swapCourseTable 对调的课程
* @return 检查结果
*/
JsonObject getExtendPreCheck(LocalDate swapDate, CourseTable courseTable, CourseTable swapCourseTable) throws Exception {
JsonParser jsonParser = new JsonParser();
String url = ScheduleUtil.apiUrl + "RescheduleApply/Extend/PreTesting";
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("timetableId", courseTable.getJianyueId());
jsonObject.addProperty("isCycles", Boolean.FALSE);
// jsonObject.addProperty("startDate", "2024-01-01");
// jsonObject.addProperty("endDate", "2024-01-31");
// jsonObject.addProperty("dayOfweek", 5);
jsonObject.addProperty("numberOfday", swapCourseTable.getTimeNumber());
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
jsonObject.addProperty("date", swapDate.format(formatter));
jsonObject.addProperty("reschduleId", courseTable.getJianyueId());
//获取时间戳
long timestamp = System.currentTimeMillis();
//生成签名
String sign = ScheduleUtil.createSign(timestamp);
String result = ScheduleUtil.doPost(url, jsonObject.toString(), sign, timestamp);
if(StrUtil.isEmpty(result)){
return null;
}
return jsonParser.parse(result).getAsJsonObject();
}
/**
* 获取节次
*
* @return
*/
private Map getClassTimeMap() {
List classTimes = classTimeMapper.selectList(null);
Map result = new HashMap<>();
for (ClassTime item : classTimes) {
String key = String.format("%d_%d", item.getTimePeriod(), item.getNumber());
result.put(key, item);
}
return result;
}
/**
* 当前时间是否在夏季
*
* @return
*/
private Boolean isCurrentSummer() {
DateTime now = DateUtil.date();
DateTime summerStart = DateUtil.parse(String.format("%d-%s", now.year(), timetableConfig.getSummerStart()));
DateTime summerEnd = DateUtil.parse(String.format("%d-%s", now.year(), timetableConfig.getSummerEnd()));
DateTime winterStart = DateUtil.parse(String.format("%d-%s", now.year(), timetableConfig.getWinterStart()));
DateTime winterEnd = DateUtil.parse(String.format("%d-%s", now.year(), timetableConfig.getWinterEnd()));
// 如果开始时间大于结束时间,开始时间增加1年
if (DateUtil.compare(summerStart, summerEnd) > 0) {
summerEnd = DateUtil.offset(summerEnd, DateField.DAY_OF_YEAR, 1);
}
if (DateUtil.compare(winterStart, winterEnd) > 0) {
winterEnd = DateUtil.offset(winterEnd, DateField.DAY_OF_YEAR, 1);
}
if (DateUtil.compare(summerStart, now) > 0 && DateUtil.compare(summerEnd, now) < 0) {
return true;
}
return false;
}
/**
* 解析word课表
*
* @param inputStream
* @return
* @throws IOException
*/
private List courseTableWordParses(InputStream inputStream) throws IOException {
XWPFDocument doc = new XWPFDocument(inputStream);
List paras = doc.getParagraphs();
String semester = null;
List cNames = new ArrayList<>();
//获取标题
for (int i = 0; i < paras.size(); i++) {
String txt = paras.get(i).getText();
if (i == 0) {
semester = txt;
continue;
}
txt = txt.replaceAll("总课程表", "").replace("\n", "").trim();
if (!txt.equals("") && !txt.equals(semester)) {
cNames.add(txt);
}
}
List result = new ArrayList<>();
//获取文档中所有的表格
List tables = doc.getTables();
int tNum = 0;
for (XWPFTable table : tables) {
int rNum = 0;
String timePeriod = null;
List weeks = new ArrayList<>();
List rows = table.getRows();
for (XWPFTableRow row : rows) {
//获取行对应的单元格
List cells = row.getTableCells();
String timeNumber = null;
for (int i = 0; i < cells.size(); i++) {
String cellText = cells.get(i).getText();
if (cellText.equals("") || rNum < 1) continue;
if (rNum == 1) {
weeks.add(cellText);
continue;
}
if (i == 0) {
timePeriod = cellText;
continue;
}
if (i == 1) {
timeNumber = cellText;
continue;
}
List cParagraph = cells.get(i).getParagraphs();
CourseTableParse item = new CourseTableParse();
item.setSemester(semester);
item.setTimePeriod(TimePeriodEnum.getCode(timePeriod));
item.setTimeNumber(TimeNumberEnum.getCode(timeNumber));
String week = weeks.get(Math.max(i - 2, 0));
item.setWeeksCn(week);
item.setClassName(cNames.get(tNum));
for (int j = 0; j < cParagraph.size(); j++) {
cellText = cParagraph.get(j).getText().trim();
switch (j) {
case 0:
item.setCourseName(cellText);
break;
case 1:
item.setTeacherName(cellText);
break;
case 2:
item.setSiteName(cellText);
break;
}
}
result.add(item);
}
rNum++;
}
tNum++;
}
inputStream.close();
return result;
}
}