提交代码
This commit is contained in:
1 parent
bf25ceba66
commit
55457496b7
7 files changed
+1494
-167
No files matched your search
+11
@@ -111,4 +111,15 @@ public class XgHolidayStayController extends BaseController {
|
||||
public TableDataInfo<StudentOptionVo> getStudentOptions(StudentOptionBo bo, PageQuery pageQuery) {
|
||||
return xgHolidayStayService.getStudentOptions(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询单人留宿有效数据
|
||||
* 获取所有有效的假期留宿数据,筛选出在同一时间段内该宿舍只有一个学生留宿的记录
|
||||
*/
|
||||
@SaCheckPermission("holidayStay:holidayStay:list")
|
||||
@GetMapping("/singlePersonValidStay")
|
||||
public R<List<XgHolidayStayVo>> getSinglePersonValidStay() {
|
||||
List<XgHolidayStayVo> result = xgHolidayStayService.querySinglePersonValidStay();
|
||||
return R.ok(result);
|
||||
}
|
||||
}
|
||||
+8
@@ -77,4 +77,12 @@ public interface IXgHolidayStayService {
|
||||
*/
|
||||
TableDataInfo<StudentOptionVo> getStudentOptions(StudentOptionBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询单人留宿有效数据
|
||||
* 获取所有有效的假期留宿数据,筛选出在同一时间段内该宿舍只有一个学生留宿的记录
|
||||
*
|
||||
* @return 单人留宿有效数据列表
|
||||
*/
|
||||
List<XgHolidayStayVo> querySinglePersonValidStay();
|
||||
|
||||
}
|
||||
+515
-18
@@ -22,6 +22,15 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Calendar;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
/**
|
||||
* 假期留宿管理Service业务层处理
|
||||
@@ -165,30 +174,19 @@ public class XgHolidayStayServiceImpl implements IXgHolidayStayService {
|
||||
|
||||
if (StringUtils.isNotBlank(statusType) && StringUtils.isNotBlank(currentTime)) {
|
||||
if ("valid".equals(statusType)) {
|
||||
// 有效状态:当前时间在留宿开始时间和结束时间之间(包含边界)
|
||||
// 条件:applyStartDate <= currentTime AND applyEndDate >= currentTime
|
||||
// AND applyStartDate IS NOT NULL AND applyEndDate IS NOT NULL
|
||||
lqw.le(XgHolidayStay::getApplyStartDate, currentTime)
|
||||
.ge(XgHolidayStay::getApplyEndDate, currentTime)
|
||||
.isNotNull(XgHolidayStay::getApplyStartDate)
|
||||
// 有效状态:当前时间还没有超过留宿结束时间(包括预约状态)
|
||||
// 条件:applyEndDate >= currentTime AND applyEndDate IS NOT NULL
|
||||
lqw.ge(XgHolidayStay::getApplyEndDate, currentTime)
|
||||
.isNotNull(XgHolidayStay::getApplyEndDate);
|
||||
log.debug(
|
||||
"添加有效状态过滤条件: apply_start_date <= {} AND apply_end_date >= {} AND start/end dates are not null",
|
||||
currentTime, currentTime);
|
||||
log.debug("添加有效状态过滤条件: apply_end_date >= {} AND end_date is not null", currentTime);
|
||||
} else if ("invalid".equals(statusType)) {
|
||||
// 失效状态:当前时间不在留宿时间范围内
|
||||
// 条件:applyStartDate > currentTime OR applyEndDate < currentTime
|
||||
// OR applyStartDate IS NULL OR applyEndDate IS NULL
|
||||
// 失效状态:当前时间已超过留宿结束时间
|
||||
// 条件:applyEndDate < currentTime OR applyEndDate IS NULL
|
||||
lqw.and(wrapper -> wrapper
|
||||
.gt(XgHolidayStay::getApplyStartDate, currentTime)
|
||||
.or()
|
||||
.lt(XgHolidayStay::getApplyEndDate, currentTime)
|
||||
.or()
|
||||
.isNull(XgHolidayStay::getApplyStartDate)
|
||||
.or()
|
||||
.isNull(XgHolidayStay::getApplyEndDate));
|
||||
log.debug("添加失效状态过滤条件: apply_start_date > {} OR apply_end_date < {} OR start/end dates are null",
|
||||
currentTime, currentTime);
|
||||
log.debug("添加失效状态过滤条件: apply_end_date < {} OR end_date is null", currentTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,4 +256,503 @@ public class XgHolidayStayServiceImpl implements IXgHolidayStayService {
|
||||
Page<StudentOptionVo> result = baseMapper.selectStudentOptions(pageQuery.build(), bo);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询单人留宿有效数据
|
||||
* 获取所有有效的假期留宿数据,筛选出在同一时间段内该宿舍只有一个学生留宿的记录
|
||||
*
|
||||
* @return 单人留宿有效数据列表
|
||||
*/
|
||||
@Override
|
||||
public List<XgHolidayStayVo> querySinglePersonValidStay() {
|
||||
// 1. 获取所有有效的假期留宿数据
|
||||
XgHolidayStayBo bo = new XgHolidayStayBo();
|
||||
Map<String, Object> params = bo.getParams();
|
||||
if (params == null) {
|
||||
params = new HashMap<>();
|
||||
bo.setParams(params);
|
||||
}
|
||||
|
||||
// 设置查询有效状态的留宿数据
|
||||
String currentTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
|
||||
params.put("statusType", "valid");
|
||||
params.put("currentTime", currentTime);
|
||||
|
||||
List<XgHolidayStayVo> validStayList = queryList(bo);
|
||||
log.info("查询到有效的假期留宿数据总数: {}", validStayList.size());
|
||||
|
||||
if (validStayList.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 2. 按房间分组,筛选出单人留宿的数据
|
||||
List<XgHolidayStayVo> singlePersonStayList = new ArrayList<>();
|
||||
|
||||
// 按房间ID分组
|
||||
Map<Long, List<XgHolidayStayVo>> roomGroupMap = validStayList.stream()
|
||||
.filter(stay -> stay.getRoomId() != null)
|
||||
.collect(Collectors.groupingBy(XgHolidayStayVo::getRoomId));
|
||||
|
||||
log.info("按房间分组后,涉及房间数量: {}", roomGroupMap.size());
|
||||
|
||||
// 遍历每个房间的留宿数据
|
||||
for (Map.Entry<Long, List<XgHolidayStayVo>> entry : roomGroupMap.entrySet()) {
|
||||
Long roomId = entry.getKey();
|
||||
List<XgHolidayStayVo> roomStayList = entry.getValue();
|
||||
|
||||
log.debug("处理房间ID: {}, 该房间留宿人数: {}", roomId, roomStayList.size());
|
||||
|
||||
// 3. 对于每个房间,检查是否存在单人留宿的时间段
|
||||
List<XgHolidayStayVo> singlePersonInRoom = findSinglePersonPeriodsInRoom(roomStayList);
|
||||
singlePersonStayList.addAll(singlePersonInRoom);
|
||||
}
|
||||
|
||||
log.info("筛选出单人留宿有效数据总数: {}", singlePersonStayList.size());
|
||||
|
||||
// 按ID倒序排序(作为时间排序的替代)
|
||||
return singlePersonStayList.stream()
|
||||
.sorted((a, b) -> {
|
||||
if (a.getId() == null && b.getId() == null)
|
||||
return 0;
|
||||
if (a.getId() == null)
|
||||
return 1;
|
||||
if (b.getId() == null)
|
||||
return -1;
|
||||
return b.getId().compareTo(a.getId());
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查房间内是否存在单人留宿的时间段
|
||||
*
|
||||
* @param roomStayList 同一房间内的留宿数据列表
|
||||
* @return 单人留宿的数据列表
|
||||
*/
|
||||
private List<XgHolidayStayVo> findSinglePersonPeriodsInRoom(List<XgHolidayStayVo> roomStayList) {
|
||||
List<XgHolidayStayVo> singlePersonList = new ArrayList<>();
|
||||
|
||||
if (roomStayList == null || roomStayList.isEmpty()) {
|
||||
return singlePersonList;
|
||||
}
|
||||
|
||||
// 如果房间内只有一个人留宿,直接返回
|
||||
if (roomStayList.size() == 1) {
|
||||
singlePersonList.add(roomStayList.get(0));
|
||||
log.debug("房间 {} 只有一个人留宿: {}", roomStayList.get(0).getRoomName(), roomStayList.get(0).getStudentName());
|
||||
return singlePersonList;
|
||||
}
|
||||
|
||||
// 按学生分组,处理每个学生的多个留宿记录
|
||||
Map<Long, List<XgHolidayStayVo>> studentStaysMap = roomStayList.stream()
|
||||
.collect(Collectors.groupingBy(XgHolidayStayVo::getStudentId));
|
||||
|
||||
// 为每个学生创建时间段
|
||||
Map<Long, List<TimeSegment>> studentTimeSegments = new HashMap<>();
|
||||
for (Map.Entry<Long, List<XgHolidayStayVo>> entry : studentStaysMap.entrySet()) {
|
||||
Long studentId = entry.getKey();
|
||||
List<XgHolidayStayVo> stays = entry.getValue();
|
||||
|
||||
List<TimeSegment> segments = new ArrayList<>();
|
||||
for (XgHolidayStayVo stay : stays) {
|
||||
if (stay.getApplyStartDate() != null && stay.getApplyEndDate() != null) {
|
||||
segments.add(new TimeSegment(stay.getApplyStartDate(), stay.getApplyEndDate(), studentId, stay));
|
||||
}
|
||||
}
|
||||
|
||||
// 合并同一学生的重叠时间段
|
||||
List<TimeSegment> mergedSegments = mergeTimeSegments(segments);
|
||||
studentTimeSegments.put(studentId, mergedSegments);
|
||||
}
|
||||
|
||||
// 收集所有关键时间点
|
||||
Set<Date> keyTimePoints = new TreeSet<>();
|
||||
for (List<TimeSegment> segments : studentTimeSegments.values()) {
|
||||
for (TimeSegment segment : segments) {
|
||||
keyTimePoints.add(segment.getStartTime());
|
||||
keyTimePoints.add(segment.getEndTime());
|
||||
}
|
||||
}
|
||||
|
||||
List<Date> sortedTimePoints = new ArrayList<>(keyTimePoints);
|
||||
log.debug("房间 {} 关键时间点数量: {}", roomStayList.get(0).getRoomName(), sortedTimePoints.size());
|
||||
|
||||
// 分析每个时间段内的留宿人数
|
||||
for (int i = 0; i < sortedTimePoints.size() - 1; i++) {
|
||||
Date segmentStart = sortedTimePoints.get(i);
|
||||
Date segmentEnd = sortedTimePoints.get(i + 1);
|
||||
|
||||
// 找出在这个时间段内留宿的所有学生
|
||||
List<Long> studentsInSegment = new ArrayList<>();
|
||||
Map<Long, XgHolidayStayVo> studentStayMap = new HashMap<>();
|
||||
|
||||
for (Map.Entry<Long, List<TimeSegment>> entry : studentTimeSegments.entrySet()) {
|
||||
Long studentId = entry.getKey();
|
||||
List<TimeSegment> segments = entry.getValue();
|
||||
|
||||
for (TimeSegment segment : segments) {
|
||||
// 检查时间段是否重叠(注意边界条件)
|
||||
if (segment.getStartTime().compareTo(segmentEnd) < 0 &&
|
||||
segment.getEndTime().compareTo(segmentStart) > 0) {
|
||||
studentsInSegment.add(studentId);
|
||||
studentStayMap.put(studentId, segment.getOriginalStay());
|
||||
break; // 一个学生在同一时间段内只能有一个记录
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果只有一个学生,这是单人留宿时间段
|
||||
if (studentsInSegment.size() == 1) {
|
||||
Long singleStudentId = studentsInSegment.get(0);
|
||||
XgHolidayStayVo originalStay = studentStayMap.get(singleStudentId);
|
||||
|
||||
// 创建单人留宿记录
|
||||
XgHolidayStayVo singlePersonStay = createSinglePersonStayFromSegment(
|
||||
originalStay, segmentStart, segmentEnd);
|
||||
singlePersonList.add(singlePersonStay);
|
||||
|
||||
log.debug("找到单人留宿时间段: {} ({} - {}) 学生: {}",
|
||||
originalStay.getRoomName(),
|
||||
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(segmentStart),
|
||||
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(segmentEnd),
|
||||
originalStay.getStudentName());
|
||||
}
|
||||
}
|
||||
|
||||
// 合并同一学生的连续单人留宿时间段
|
||||
return mergeConsecutiveSinglePersonStays(singlePersonList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取两个日期之间的所有日期(包含起始和结束日期)
|
||||
*
|
||||
* @param startDate 开始日期
|
||||
* @param endDate 结束日期
|
||||
* @param dateFormat 日期格式化器
|
||||
* @return 日期字符串列表
|
||||
*/
|
||||
private List<String> getDatesBetween(Date startDate, Date endDate, SimpleDateFormat dateFormat) {
|
||||
List<String> dates = new ArrayList<>();
|
||||
|
||||
if (startDate == null || endDate == null) {
|
||||
return dates;
|
||||
}
|
||||
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(startDate);
|
||||
|
||||
// 只取日期部分,忽略时间
|
||||
calendar.set(Calendar.HOUR_OF_DAY, 0);
|
||||
calendar.set(Calendar.MINUTE, 0);
|
||||
calendar.set(Calendar.SECOND, 0);
|
||||
calendar.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
Calendar endCalendar = Calendar.getInstance();
|
||||
endCalendar.setTime(endDate);
|
||||
endCalendar.set(Calendar.HOUR_OF_DAY, 0);
|
||||
endCalendar.set(Calendar.MINUTE, 0);
|
||||
endCalendar.set(Calendar.SECOND, 0);
|
||||
endCalendar.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
// 生成日期列表
|
||||
while (!calendar.after(endCalendar)) {
|
||||
dates.add(dateFormat.format(calendar.getTime()));
|
||||
calendar.add(Calendar.DAY_OF_MONTH, 1);
|
||||
}
|
||||
|
||||
return dates;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建单人留宿记录,调整时间范围为单人留宿的日期范围
|
||||
*
|
||||
* @param originalStay 原始留宿记录
|
||||
* @param singlePersonDates 单人留宿的日期列表
|
||||
* @param dateFormat 日期格式化器
|
||||
* @return 调整后的单人留宿记录
|
||||
*/
|
||||
private XgHolidayStayVo createSinglePersonStayRecord(XgHolidayStayVo originalStay, List<String> singlePersonDates,
|
||||
SimpleDateFormat dateFormat) {
|
||||
if (singlePersonDates.isEmpty()) {
|
||||
return originalStay;
|
||||
}
|
||||
|
||||
try {
|
||||
// 排序日期列表
|
||||
singlePersonDates.sort(String::compareTo);
|
||||
|
||||
// 获取单人留宿的开始和结束日期
|
||||
String startDateStr = singlePersonDates.get(0);
|
||||
String endDateStr = singlePersonDates.get(singlePersonDates.size() - 1);
|
||||
|
||||
// 克隆原始记录
|
||||
XgHolidayStayVo singlePersonStay = new XgHolidayStayVo();
|
||||
BeanUtils.copyProperties(originalStay, singlePersonStay);
|
||||
|
||||
// 调整时间范围为单人留宿的日期范围
|
||||
Date adjustedStartDate = dateFormat.parse(startDateStr);
|
||||
Date adjustedEndDate = dateFormat.parse(endDateStr);
|
||||
|
||||
// 结束日期设置为当天的23:59:59
|
||||
Calendar endCalendar = Calendar.getInstance();
|
||||
endCalendar.setTime(adjustedEndDate);
|
||||
endCalendar.set(Calendar.HOUR_OF_DAY, 23);
|
||||
endCalendar.set(Calendar.MINUTE, 59);
|
||||
endCalendar.set(Calendar.SECOND, 59);
|
||||
adjustedEndDate = endCalendar.getTime();
|
||||
|
||||
singlePersonStay.setApplyStartDate(adjustedStartDate);
|
||||
singlePersonStay.setApplyEndDate(adjustedEndDate);
|
||||
|
||||
// 在备注中添加单人留宿信息
|
||||
String originalRemark = singlePersonStay.getRemark() == null ? "" : singlePersonStay.getRemark();
|
||||
String singlePersonInfo = String.format("【单人留宿】%s天(%s至%s)",
|
||||
singlePersonDates.size(), startDateStr, endDateStr);
|
||||
singlePersonStay
|
||||
.setRemark(originalRemark.isEmpty() ? singlePersonInfo : originalRemark + " " + singlePersonInfo);
|
||||
|
||||
log.debug("为学生 {} 创建单人留宿记录: {} 天 ({} - {})",
|
||||
singlePersonStay.getStudentName(), singlePersonDates.size(), startDateStr, endDateStr);
|
||||
|
||||
return singlePersonStay;
|
||||
} catch (Exception e) {
|
||||
log.error("创建单人留宿记录失败", e);
|
||||
return originalStay;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查两个留宿时间段是否重叠
|
||||
*
|
||||
* @param stay1 留宿记录1
|
||||
* @param stay2 留宿记录2
|
||||
* @return 是否重叠
|
||||
*/
|
||||
private boolean isTimeOverlap(XgHolidayStayVo stay1, XgHolidayStayVo stay2) {
|
||||
if (stay1.getApplyStartDate() == null || stay1.getApplyEndDate() == null ||
|
||||
stay2.getApplyStartDate() == null || stay2.getApplyEndDate() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Date start1 = stay1.getApplyStartDate();
|
||||
Date end1 = stay1.getApplyEndDate();
|
||||
Date start2 = stay2.getApplyStartDate();
|
||||
Date end2 = stay2.getApplyEndDate();
|
||||
|
||||
// 检查时间段是否重叠:两个时间段重叠当且仅当 start1 <= end2 && start2 <= end1
|
||||
boolean overlap = start1.compareTo(end2) <= 0 && start2.compareTo(end1) <= 0;
|
||||
|
||||
if (overlap) {
|
||||
log.debug("时间段重叠: {} ({} - {}) 与 {} ({} - {})",
|
||||
stay1.getStudentName(), start1, end1,
|
||||
stay2.getStudentName(), start2, end2);
|
||||
}
|
||||
|
||||
return overlap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并同一学生的重叠时间段
|
||||
*/
|
||||
private List<TimeSegment> mergeTimeSegments(List<TimeSegment> segments) {
|
||||
if (segments.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 按开始时间排序
|
||||
segments.sort(Comparator.comparing(TimeSegment::getStartTime));
|
||||
|
||||
List<TimeSegment> merged = new ArrayList<>();
|
||||
TimeSegment current = segments.get(0);
|
||||
|
||||
for (int i = 1; i < segments.size(); i++) {
|
||||
TimeSegment next = segments.get(i);
|
||||
|
||||
// 如果时间段重叠或相邻,合并它们
|
||||
if (current.getEndTime().compareTo(next.getStartTime()) >= 0) {
|
||||
// 扩展当前时间段
|
||||
if (next.getEndTime().compareTo(current.getEndTime()) > 0) {
|
||||
current = new TimeSegment(
|
||||
current.getStartTime(),
|
||||
next.getEndTime(),
|
||||
current.getStudentId(),
|
||||
current.getOriginalStay()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// 不重叠,添加当前时间段到结果中
|
||||
merged.add(current);
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
|
||||
// 添加最后一个时间段
|
||||
merged.add(current);
|
||||
return merged;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从时间段创建单人留宿记录
|
||||
*/
|
||||
private XgHolidayStayVo createSinglePersonStayFromSegment(XgHolidayStayVo template, Date startTime, Date endTime) {
|
||||
XgHolidayStayVo singlePersonStay = new XgHolidayStayVo();
|
||||
|
||||
// 复制基本信息
|
||||
BeanUtils.copyProperties(template, singlePersonStay);
|
||||
|
||||
// 设置ID为null,表示这是计算出来的记录
|
||||
singlePersonStay.setId(null);
|
||||
|
||||
// 设置单人留宿的时间段
|
||||
singlePersonStay.setApplyStartDate(startTime);
|
||||
singlePersonStay.setApplyEndDate(endTime);
|
||||
|
||||
// 计算单人留宿天数
|
||||
long timeDiff = endTime.getTime() - startTime.getTime();
|
||||
long days = Math.max(1, timeDiff / (24 * 60 * 60 * 1000) + 1); // 至少1天
|
||||
|
||||
// 设置备注信息
|
||||
String originalRemark = template.getRemark() != null ? template.getRemark() : "";
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
String singlePersonRemark = String.format("单人留宿%d天 (%s至%s)",
|
||||
days,
|
||||
sdf.format(startTime),
|
||||
sdf.format(endTime)
|
||||
);
|
||||
|
||||
if (!originalRemark.isEmpty()) {
|
||||
singlePersonStay.setRemark(originalRemark + " | " + singlePersonRemark);
|
||||
} else {
|
||||
singlePersonStay.setRemark(singlePersonRemark);
|
||||
}
|
||||
|
||||
return singlePersonStay;
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并同一学生的连续单人留宿时间段
|
||||
*/
|
||||
private List<XgHolidayStayVo> mergeConsecutiveSinglePersonStays(List<XgHolidayStayVo> singlePersonStays) {
|
||||
if (singlePersonStays.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 按学生ID和开始时间分组排序
|
||||
Map<Long, List<XgHolidayStayVo>> studentStaysMap = singlePersonStays.stream()
|
||||
.collect(Collectors.groupingBy(XgHolidayStayVo::getStudentId));
|
||||
|
||||
List<XgHolidayStayVo> mergedStays = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<Long, List<XgHolidayStayVo>> entry : studentStaysMap.entrySet()) {
|
||||
List<XgHolidayStayVo> stays = entry.getValue();
|
||||
|
||||
// 按开始时间排序
|
||||
stays.sort(Comparator.comparing(XgHolidayStayVo::getApplyStartDate));
|
||||
|
||||
XgHolidayStayVo current = stays.get(0);
|
||||
|
||||
for (int i = 1; i < stays.size(); i++) {
|
||||
XgHolidayStayVo next = stays.get(i);
|
||||
|
||||
// 如果时间段连续或重叠,合并它们
|
||||
if (current.getApplyEndDate().compareTo(next.getApplyStartDate()) >= 0) {
|
||||
// 扩展当前时间段
|
||||
if (next.getApplyEndDate().compareTo(current.getApplyEndDate()) > 0) {
|
||||
current.setApplyEndDate(next.getApplyEndDate());
|
||||
}
|
||||
|
||||
// 更新备注信息
|
||||
updateMergedRemark(current, next);
|
||||
} else {
|
||||
// 不连续,添加当前时间段到结果中
|
||||
mergedStays.add(current);
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
|
||||
// 添加最后一个时间段
|
||||
mergedStays.add(current);
|
||||
}
|
||||
|
||||
return mergedStays;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新合并后的备注信息
|
||||
*/
|
||||
private void updateMergedRemark(XgHolidayStayVo current, XgHolidayStayVo next) {
|
||||
// 重新计算合并后的天数
|
||||
long timeDiff = current.getApplyEndDate().getTime() - current.getApplyStartDate().getTime();
|
||||
long totalDays = Math.max(1, timeDiff / (24 * 60 * 60 * 1000) + 1);
|
||||
|
||||
// 更新备注
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
String mergedRemark = String.format("单人留宿%d天 (%s至%s)",
|
||||
totalDays,
|
||||
sdf.format(current.getApplyStartDate()),
|
||||
sdf.format(current.getApplyEndDate())
|
||||
);
|
||||
|
||||
// 保留原始备注的非单人留宿信息
|
||||
String originalPart = extractOriginalRemark(current.getRemark());
|
||||
if (!originalPart.isEmpty()) {
|
||||
current.setRemark(originalPart + " | " + mergedRemark);
|
||||
} else {
|
||||
current.setRemark(mergedRemark);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取原始备注信息(去除单人留宿相关的备注)
|
||||
*/
|
||||
private String extractOriginalRemark(String remark) {
|
||||
if (remark == null || remark.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// 如果包含单人留宿标记,提取原始部分
|
||||
if (remark.contains(" | 单人留宿")) {
|
||||
return remark.split(" \\| 单人留宿")[0].trim();
|
||||
}
|
||||
|
||||
// 如果以单人留宿开头,返回空
|
||||
if (remark.startsWith("单人留宿")) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return remark;
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间段内部类
|
||||
*/
|
||||
private static class TimeSegment {
|
||||
private Date startTime;
|
||||
private Date endTime;
|
||||
private Long studentId;
|
||||
private XgHolidayStayVo originalStay;
|
||||
|
||||
public TimeSegment(Date startTime, Date endTime, Long studentId, XgHolidayStayVo originalStay) {
|
||||
this.startTime = startTime;
|
||||
this.endTime = endTime;
|
||||
this.studentId = studentId;
|
||||
this.originalStay = originalStay;
|
||||
}
|
||||
|
||||
public Date getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public Date getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
|
||||
public Long getStudentId() {
|
||||
return studentId;
|
||||
}
|
||||
|
||||
public XgHolidayStayVo getOriginalStay() {
|
||||
return originalStay;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
- [宿舍管理员授权API](./宿舍管理员授权API.md)
|
||||
- [学生管理员授权关系API](./学生管理员授权关系API.md)
|
||||
- [学生销假管理API](./学生销假管理API.md)
|
||||
- [假期留宿管理API](./假期留宿管理API.md) - **重要修复:单人留宿计算逻辑**(2025-01-03)
|
||||
|
||||
### 1. 用户认证登录
|
||||
|
||||
|
||||
@@ -80,6 +80,18 @@ export const getStudentOptions = (
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询单人留宿有效数据
|
||||
* 获取所有有效的假期留宿数据,筛选出在同一时间段内该宿舍只有一个学生留宿的记录
|
||||
* @returns 单人留宿有效数据列表
|
||||
*/
|
||||
export const getSinglePersonValidStay = (): AxiosPromise<HolidayStayVO[]> => {
|
||||
return request({
|
||||
url: '/holidayStay/holidayStay/singlePersonValidStay',
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取校区选项列表
|
||||
* @returns 校区选项列表
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -723,7 +723,7 @@ const data = reactive<PageData<HolidayStayForm, HolidayStayQuery>>({
|
||||
extField1: undefined,
|
||||
extField2: undefined,
|
||||
extField3: undefined,
|
||||
status: undefined,
|
||||
status: 'valid', // 默认显示有效状态的记录
|
||||
params: {}
|
||||
},
|
||||
rules: {
|
||||
@@ -769,7 +769,7 @@ const getList = async () => {
|
||||
const requestParams = { ...queryParams.value };
|
||||
|
||||
// 添加创建人过滤条件 - 班主任只能看到自己创建的数据
|
||||
requestParams.createBy = userStore.userId;
|
||||
(requestParams as any).createBy = userStore.userId;
|
||||
|
||||
// 根据状态设置时间过滤条件
|
||||
if (requestParams.status) {
|
||||
@@ -855,6 +855,44 @@ const handleUpdate = async (row?: HolidayStayVO) => {
|
||||
const res = await getHolidayStay(_id);
|
||||
Object.assign(form.value, res.data);
|
||||
|
||||
// 确保当前学生信息在选项中(修复学生选择器显示问题)
|
||||
if (form.value.studentId && form.value.studentName && form.value.studentNo) {
|
||||
const currentStudent: StudentOptionVO = {
|
||||
id: form.value.studentId,
|
||||
name: form.value.studentName,
|
||||
studentNo: form.value.studentNo,
|
||||
gender: '0', // 默认值,实际不影响显示
|
||||
phone: form.value.studentPhone,
|
||||
collegeId: form.value.collegeId,
|
||||
collegeName: form.value.collegeName,
|
||||
majorId: form.value.majorId,
|
||||
majorName: form.value.majorName,
|
||||
classId: form.value.classId,
|
||||
className: form.value.className,
|
||||
dormInfo: {
|
||||
campusId: form.value.campusId,
|
||||
campusName: form.value.campusName,
|
||||
areaId: form.value.areaId,
|
||||
areaName: form.value.areaName,
|
||||
buildingId: form.value.buildingId,
|
||||
buildingName: form.value.buildingName,
|
||||
roomId: form.value.roomId,
|
||||
roomName: form.value.roomName,
|
||||
bedId: form.value.bedId,
|
||||
bedName: form.value.bedName
|
||||
}
|
||||
};
|
||||
|
||||
// 检查是否已经存在,避免重复添加
|
||||
const existingStudent = studentOptions.value.find((s) => s.id === form.value.studentId);
|
||||
if (!existingStudent) {
|
||||
studentOptions.value = [currentStudent];
|
||||
} else {
|
||||
// 更新现有学生信息
|
||||
Object.assign(existingStudent, currentStudent);
|
||||
}
|
||||
}
|
||||
|
||||
// 根据已有数据级联加载宿舍选项
|
||||
await loadCascadeOptionsForUpdate(form.value);
|
||||
|
||||
@@ -921,7 +959,7 @@ const remoteSearchStudents = async (query: string) => {
|
||||
const res = await getStudentOptions(params);
|
||||
// 根据实际接口返回格式调整数据获取方式
|
||||
console.log('学生搜索响应:', res);
|
||||
studentOptions.value = res.rows || [];
|
||||
studentOptions.value = (res as any).rows || [];
|
||||
|
||||
// 调试:检查第一个学生的数据
|
||||
if (studentOptions.value.length > 0) {
|
||||
@@ -964,7 +1002,7 @@ const loadInitialStudents = async () => {
|
||||
const res = await getStudentOptions(params);
|
||||
// 根据实际接口返回格式调整数据获取方式
|
||||
console.log('初始学生数据响应:', res);
|
||||
studentOptions.value = res.rows || [];
|
||||
studentOptions.value = (res as any).rows || [];
|
||||
|
||||
// 调试:检查第一个学生的数据
|
||||
if (studentOptions.value.length > 0) {
|
||||
@@ -1542,6 +1580,7 @@ const handleAttachmentData = async () => {
|
||||
|
||||
// 将逗号分隔的字符串转换为数组
|
||||
const ossIdsArray = form.value.attachmentOssIds
|
||||
.toString()
|
||||
.split(',')
|
||||
.map((id) => id.trim())
|
||||
.filter((id) => id);
|
||||
|
||||
Reference in new issue
Block a user