插活
This commit is contained in:
parent
88529941bf
commit
05383c2355
@ -315,7 +315,13 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
|
||||
// 判断请求时间段是否与已有时间段有重叠
|
||||
boolean hasOverlap = !(reqEnd.compareTo(existStart) < 0) && !(reqStart.compareTo(existEnd) > 0);
|
||||
if (hasOverlap) {
|
||||
return CommonResult.error(400, "该子项目设计时间存在交叉,请确认!");
|
||||
String type="BLUEPRINT_WORKBLANK".equals(updateReqVO.getSubType())?"毛坯":"BLUEPRINT_2D".equals(updateReqVO.getSubType())?"2D":"3D";
|
||||
|
||||
String type2="BLUEPRINT_WORKBLANK".equals(planSubDetailDO.getSubType())?"毛坯":"BLUEPRINT_2D".equals(planSubDetailDO.getSubType())?"2D":"3D";
|
||||
|
||||
return CommonResult.error(400, "子项目:"+updateReqVO.getName()+" 设计类型:"+type +" "+reqStart.toString().substring(0,10)+" "+reqEnd.toString().substring(0,10)
|
||||
+"与"+"子项目:"+planSubDetailDO.getName()+" 设计类型:"+type2 +" "+existStart.toString().substring(0,10)+" "+existEnd.toString().substring(0,10)
|
||||
+"设计时间存在交叉,请确认!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -424,20 +430,27 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
|
||||
planSubDetailMapper.updateBatch(list);
|
||||
//更新表主表数据
|
||||
//先看有多少个子项目
|
||||
Map<Long, List<PlanSubDetailDO>> collect = list.stream().collect(Collectors.groupingBy(PlanSubDetailDO::getProjectPlanSubId));
|
||||
collect.forEach((subId,subList) -> {
|
||||
Map<Long, List<PlanSubDetailDO>> collect = list.stream().collect(Collectors.groupingBy(PlanSubDetailDO::getProjectSubId));
|
||||
for (Map.Entry<Long, List<PlanSubDetailDO>> entry : collect.entrySet()) {
|
||||
Long subId = entry.getKey();
|
||||
List<PlanSubDetailDO> subList = entry.getValue();
|
||||
//再根据设计类型来
|
||||
Map<String, List<PlanSubDetailDO>> collect1 = subList.stream().collect(Collectors.groupingBy(PlanSubDetailDO::getSubType));
|
||||
//然后对里面的进行排序
|
||||
collect1.forEach((type,subTypeList) ->{
|
||||
for (Map.Entry<String, List<PlanSubDetailDO>> entry1 : collect1.entrySet()) {
|
||||
String type = entry1.getKey();
|
||||
List<PlanSubDetailDO> subTypeList = entry1.getValue();
|
||||
List<PlanSubDetailDO> sortedList = subTypeList.stream()
|
||||
.sorted(Comparator.comparing(PlanSubDetailDO::getSeqNo).reversed())
|
||||
.collect(Collectors.toList());
|
||||
Long num = 0L;
|
||||
for (PlanSubDetailDO planSubDetailDO : sortedList) {
|
||||
Long designNum = planSubDetailDO.getDesignNum();
|
||||
num += designNum;
|
||||
}
|
||||
LambdaUpdateWrapper<PlanSubDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
|
||||
lambdaUpdateWrapper.eq(PlanSubDO::getProjectSubId,subId);
|
||||
LocalDateTime startTwoDimDate = sortedList.get(0).getStartTwoDimDate();
|
||||
LocalDateTime startTwoDimDate = sortedList.get(subTypeList.size()-1).getStartTwoDimDate();
|
||||
LocalDateTime twoDimDate = sortedList.get(0).getTwoDimDate();
|
||||
Long num = sortedList.get(0).getDesignNum();
|
||||
//取最大值就是第一个
|
||||
if ("BLUEPRINT_WORKBLANK".equals(type)){
|
||||
lambdaUpdateWrapper.set(PlanSubDO::getStartBlankDate,startTwoDimDate);
|
||||
@ -453,8 +466,8 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
|
||||
lambdaUpdateWrapper.set(PlanSubDO::getThreeDimNum,num);
|
||||
}
|
||||
planSubMapper.update(lambdaUpdateWrapper);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
return CommonResult.success(true);
|
||||
|
||||
}
|
||||
@ -523,7 +536,21 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
|
||||
});
|
||||
return CommonResult.success(true);
|
||||
}
|
||||
/**
|
||||
* 计算工作天数)
|
||||
*/
|
||||
private Long calculateWorkDays(LocalDateTime startDate, LocalDateTime endDate) {
|
||||
long workDays = 0;
|
||||
LocalDateTime current = startDate.toLocalDate().atStartOfDay();
|
||||
LocalDateTime end = endDate.toLocalDate().atStartOfDay();
|
||||
|
||||
while (!current.isAfter(end)) {
|
||||
workDays++;
|
||||
current = current.plusDays(1);
|
||||
}
|
||||
|
||||
return workDays;
|
||||
}
|
||||
// @Override
|
||||
// @Transactional
|
||||
// public CommonResult chahuoList(PlanSubDetailSaveReqVO updateReqVO) {
|
||||
@ -987,284 +1014,198 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
|
||||
List<LocalDateTime> holidayList) {
|
||||
List<PlanSubDetailDO> resultList = new ArrayList<>();
|
||||
|
||||
// 1. 如果没有插活数据,直接返回baseList
|
||||
if (CollUtil.isEmpty(insertList)) {
|
||||
// 1. 先处理插活数据,不按节假日分段,保持原始范围
|
||||
List<PlanSubDetailDO> processedInsertList = new ArrayList<>();
|
||||
for (PlanSubDetailDO insertItem : insertList) {
|
||||
// 插活数据保持原始时间范围,但designNum排除节假日
|
||||
PlanSubDetailDO processedItem = new PlanSubDetailDO();
|
||||
// 复制属性
|
||||
processedItem.setId(null);
|
||||
processedItem.setProjectPlanId(insertItem.getProjectPlanId());
|
||||
processedItem.setProjectId(insertItem.getProjectId());
|
||||
processedItem.setProjectPlanSubId(insertItem.getProjectPlanSubId());
|
||||
processedItem.setProjectSubCode(insertItem.getProjectSubCode());
|
||||
processedItem.setTwoDimOwner(insertItem.getTwoDimOwner());
|
||||
processedItem.setProjectSubId(insertItem.getProjectPlanSubId());
|
||||
processedItem.setSubType(insertItem.getSubType());
|
||||
processedItem.setName(insertItem.getName());
|
||||
processedItem.setCode(insertItem.getCode());
|
||||
processedItem.setStartTwoDimDate(insertItem.getStartTwoDimDate());
|
||||
processedItem.setTwoDimDate(insertItem.getTwoDimDate());
|
||||
processedItem.setIsCha("Y");
|
||||
// designNum排除节假日
|
||||
processedItem.setDesignNum(calculateWorkDaysExcludeHolidays(insertItem.getStartTwoDimDate(), insertItem.getTwoDimDate(), holidayList));
|
||||
processedInsertList.add(processedItem);
|
||||
}
|
||||
|
||||
// 2. 如果没有插活数据,直接返回baseList
|
||||
if (processedInsertList.isEmpty()) {
|
||||
return new ArrayList<>(baseList);
|
||||
}
|
||||
|
||||
// 2. 如果baseList为空,直接返回所有插活数据
|
||||
// 3. 处理baseList为空的情况
|
||||
if (CollUtil.isEmpty(baseList)) {
|
||||
List<PlanSubDetailDO> processedInsertList = new ArrayList<>();
|
||||
for (PlanSubDetailDO insertItem : insertList) {
|
||||
PlanSubDetailDO processedInsert = createInsertItem(insertItem, insertItem.getStartTwoDimDate(), insertItem.getTwoDimDate(), holidayList);
|
||||
processedInsertList.add(processedInsert);
|
||||
}
|
||||
processedInsertList.sort(Comparator.comparing(PlanSubDetailDO::getStartTwoDimDate));
|
||||
return processedInsertList;
|
||||
// baseList为空,直接返回插活数据
|
||||
return new ArrayList<>(processedInsertList);
|
||||
}
|
||||
|
||||
// 3. 获取baseList的时间范围
|
||||
LocalDateTime baseListMinStartTime = baseList.stream()
|
||||
// 4. 获取插活数据的时间范围
|
||||
LocalDateTime insertStartTime = processedInsertList.stream()
|
||||
.map(PlanSubDetailDO::getStartTwoDimDate)
|
||||
.min(LocalDateTime::compareTo)
|
||||
.orElse(null);
|
||||
LocalDateTime baseListMaxEndTime = baseList.stream()
|
||||
LocalDateTime insertEndTime = processedInsertList.stream()
|
||||
.map(PlanSubDetailDO::getTwoDimDate)
|
||||
.max(LocalDateTime::compareTo)
|
||||
.orElse(null);
|
||||
|
||||
// 4. 处理插活数据,保持原有时间范围,但重新计算designNum(排除节假日)
|
||||
List<PlanSubDetailDO> processedInsertList = new ArrayList<>();
|
||||
for (PlanSubDetailDO insertItem : insertList) {
|
||||
LocalDateTime startDate = insertItem.getStartTwoDimDate();
|
||||
LocalDateTime endDate = insertItem.getTwoDimDate();
|
||||
// 5. 获取baseList的时间范围
|
||||
LocalDateTime baseMinStartTime = baseList.stream()
|
||||
.map(PlanSubDetailDO::getStartTwoDimDate)
|
||||
.min(LocalDateTime::compareTo)
|
||||
.orElse(null);
|
||||
LocalDateTime baseMaxEndTime = baseList.stream()
|
||||
.map(PlanSubDetailDO::getTwoDimDate)
|
||||
.max(LocalDateTime::compareTo)
|
||||
.orElse(null);
|
||||
|
||||
PlanSubDetailDO processedInsert = createInsertItem(insertItem, startDate, endDate, holidayList);
|
||||
processedInsertList.add(processedInsert);
|
||||
}
|
||||
|
||||
// 5. 分离插活数据:在baseList之前的、在baseList之间的、在baseList之后的
|
||||
List<PlanSubDetailDO> beforeBaseListInserts = new ArrayList<>();
|
||||
List<PlanSubDetailDO> duringBaseListInserts = new ArrayList<>();
|
||||
List<PlanSubDetailDO> afterBaseListInserts = new ArrayList<>();
|
||||
|
||||
for (PlanSubDetailDO insertItem : processedInsertList) {
|
||||
if (insertItem.getTwoDimDate().isBefore(baseListMinStartTime)) {
|
||||
// 插活数据完全在baseList之前
|
||||
beforeBaseListInserts.add(insertItem);
|
||||
} else if (insertItem.getStartTwoDimDate().isAfter(baseListMaxEndTime)) {
|
||||
// 插活数据完全在baseList之后
|
||||
afterBaseListInserts.add(insertItem);
|
||||
} else {
|
||||
// 插活数据与baseList有重叠或在baseList之间
|
||||
duringBaseListInserts.add(insertItem);
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 处理在baseList之前的插活数据:直接添加到结果列表前面
|
||||
beforeBaseListInserts.sort(Comparator.comparing(PlanSubDetailDO::getStartTwoDimDate));
|
||||
resultList.addAll(beforeBaseListInserts);
|
||||
|
||||
// 7. 处理baseList和在其间的插活数据
|
||||
if (CollUtil.isEmpty(duringBaseListInserts)) {
|
||||
// 没有在baseList之间的插活数据,baseList保持原样
|
||||
// 6. 边界情况处理
|
||||
if (insertEndTime != null && baseMinStartTime != null && insertEndTime.isBefore(baseMinStartTime)) {
|
||||
// 情况1:插活数据在所有baseList之前
|
||||
resultList.addAll(processedInsertList);
|
||||
resultList.addAll(baseList);
|
||||
} else {
|
||||
// 有在baseList之间的插活数据,需要重新编排
|
||||
// 重新构建结果列表,考虑插活数据对多个baseList的影响
|
||||
resultList.addAll(rebuildListWithInserts(baseList, duringBaseListInserts, holidayList));
|
||||
return resultList;
|
||||
}
|
||||
|
||||
// 8. 处理在baseList之后的插活数据:直接添加到baseList后面
|
||||
afterBaseListInserts.sort(Comparator.comparing(PlanSubDetailDO::getStartTwoDimDate));
|
||||
resultList.addAll(afterBaseListInserts);
|
||||
if (insertStartTime != null && baseMaxEndTime != null && insertStartTime.isAfter(baseMaxEndTime)) {
|
||||
// 情况2:插活数据在所有baseList之后
|
||||
resultList.addAll(baseList);
|
||||
resultList.addAll(processedInsertList);
|
||||
return resultList;
|
||||
}
|
||||
|
||||
// 9. 按开始时间排序
|
||||
// 7. 正常插活逻辑(插活数据与baseList有重叠)
|
||||
// 分离baseList:在插活数据之前的、被打断的、在插活数据之后的
|
||||
List<PlanSubDetailDO> beforeInsertList = new ArrayList<>();
|
||||
List<PlanSubDetailDO> interruptedList = new ArrayList<>();
|
||||
List<PlanSubDetailDO> afterInsertList = new ArrayList<>();
|
||||
|
||||
if (insertStartTime != null) {
|
||||
for (PlanSubDetailDO baseItem : baseList) {
|
||||
if (baseItem.getTwoDimDate().isBefore(insertStartTime)) {
|
||||
// 完全在插活数据之前
|
||||
beforeInsertList.add(baseItem);
|
||||
} else if (baseItem.getStartTwoDimDate().isBefore(insertStartTime) &&
|
||||
baseItem.getTwoDimDate().isAfter(insertStartTime.minusDays(1))) {
|
||||
// 被插活数据打断
|
||||
interruptedList.add(baseItem);
|
||||
} else {
|
||||
// 在插活数据之后
|
||||
afterInsertList.add(baseItem);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
beforeInsertList.addAll(baseList);
|
||||
}
|
||||
|
||||
// 8. 处理插活数据之前的baseList(保持原样)
|
||||
resultList.addAll(beforeInsertList);
|
||||
|
||||
// 9. 处理被打断的baseList
|
||||
List<PlanSubDetailDO> remainingBaseList = new ArrayList<>();
|
||||
for (PlanSubDetailDO interruptedItem : interruptedList) {
|
||||
// 计算插活数据开始前的天数(包含节假日)
|
||||
long daysBeforeInsert = ChronoUnit.DAYS.between(interruptedItem.getStartTwoDimDate(), insertStartTime);
|
||||
|
||||
if (daysBeforeInsert > 0) {
|
||||
// 创建插活前的段落
|
||||
LocalDateTime segmentEnd = interruptedItem.getStartTwoDimDate().plusDays(daysBeforeInsert - 1);
|
||||
PlanSubDetailDO beforeSegment = createBaseItem(interruptedItem, interruptedItem.getStartTwoDimDate(), segmentEnd);
|
||||
// designNum排除节假日
|
||||
beforeSegment.setDesignNum(calculateWorkDaysExcludeHolidays(interruptedItem.getStartTwoDimDate(), segmentEnd, holidayList));
|
||||
resultList.add(beforeSegment);
|
||||
|
||||
// 保存剩余的designNum(原始designNum减去已使用的)
|
||||
Long usedDesignNum = calculateWorkDaysExcludeHolidays(interruptedItem.getStartTwoDimDate(), segmentEnd, holidayList);
|
||||
Long remainingDesignNum = interruptedItem.getDesignNum() - usedDesignNum;
|
||||
if (remainingDesignNum > 0) {
|
||||
// 创建剩余的baseItem,稍后处理
|
||||
PlanSubDetailDO remainingItem = new PlanSubDetailDO();
|
||||
// 复制属性
|
||||
remainingItem.setId(interruptedItem.getId());
|
||||
remainingItem.setProjectPlanId(interruptedItem.getProjectPlanId());
|
||||
remainingItem.setProjectId(interruptedItem.getProjectId());
|
||||
remainingItem.setProjectPlanSubId(interruptedItem.getProjectPlanSubId());
|
||||
remainingItem.setProjectSubCode(interruptedItem.getProjectSubCode());
|
||||
remainingItem.setTwoDimOwner(interruptedItem.getTwoDimOwner());
|
||||
remainingItem.setProjectSubId(interruptedItem.getProjectPlanSubId());
|
||||
remainingItem.setSubType(interruptedItem.getSubType());
|
||||
remainingItem.setName(interruptedItem.getName());
|
||||
remainingItem.setCode(interruptedItem.getCode());
|
||||
remainingItem.setDesignNum(remainingDesignNum);
|
||||
remainingBaseList.add(remainingItem);
|
||||
}
|
||||
} else {
|
||||
// 整个被打断,全部加入剩余列表
|
||||
remainingBaseList.add(interruptedItem);
|
||||
}
|
||||
}
|
||||
|
||||
// 10. 添加插活数据
|
||||
resultList.addAll(processedInsertList);
|
||||
|
||||
// 11. 处理剩余的baseList(被打断的剩余部分 + 原本在插活数据之后的)
|
||||
List<PlanSubDetailDO> allRemainingList = new ArrayList<>();
|
||||
allRemainingList.addAll(remainingBaseList);
|
||||
allRemainingList.addAll(afterInsertList);
|
||||
|
||||
if (!allRemainingList.isEmpty()) {
|
||||
// 获取插活数据的最后结束时间
|
||||
LocalDateTime lastInsertEndTime = processedInsertList.stream()
|
||||
.map(PlanSubDetailDO::getTwoDimDate)
|
||||
.max(LocalDateTime::compareTo)
|
||||
.orElse(null);
|
||||
|
||||
// 从插活数据的下一天开始顺延
|
||||
LocalDateTime baseStartTime = lastInsertEndTime.plusDays(1);
|
||||
|
||||
for (PlanSubDetailDO baseItem : allRemainingList) {
|
||||
// 按照原有的designNum计算新的时间段(排除节假日)
|
||||
LocalDateTime newStartTime = findNextNonHoliday(baseStartTime, holidayList);
|
||||
LocalDateTime newEndTime = calculateEndDateByWorkDays(newStartTime, baseItem.getDesignNum(), holidayList);
|
||||
|
||||
// 创建新的baseItem
|
||||
PlanSubDetailDO newBaseItem = createBaseItem(baseItem, newStartTime, newEndTime);
|
||||
newBaseItem.setDesignNum(baseItem.getDesignNum()); // 保持原始designNum
|
||||
resultList.add(newBaseItem);
|
||||
|
||||
// 更新下一个baseItem的开始时间
|
||||
baseStartTime = newEndTime.plusDays(1);
|
||||
}
|
||||
}
|
||||
|
||||
// 12. 按开始时间排序
|
||||
resultList.sort(Comparator.comparing(PlanSubDetailDO::getStartTwoDimDate));
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新构建包含插活数据的列表
|
||||
*/
|
||||
private List<PlanSubDetailDO> rebuildListWithInserts(List<PlanSubDetailDO> baseList,
|
||||
List<PlanSubDetailDO> insertItems,
|
||||
List<LocalDateTime> holidayList) {
|
||||
List<PlanSubDetailDO> resultList = new ArrayList<>();
|
||||
|
||||
// 按时间排序插活数据
|
||||
insertItems.sort(Comparator.comparing(PlanSubDetailDO::getStartTwoDimDate));
|
||||
|
||||
// 处理每个baseList,考虑插活数据的影响
|
||||
for (PlanSubDetailDO baseItem : baseList) {
|
||||
// 找出与这个baseItem重叠的插活数据
|
||||
List<PlanSubDetailDO> overlappingInserts = insertItems.stream()
|
||||
.filter(insert -> !(insert.getTwoDimDate().isBefore(baseItem.getStartTwoDimDate()) ||
|
||||
insert.getStartTwoDimDate().isAfter(baseItem.getTwoDimDate())))
|
||||
.sorted(Comparator.comparing(PlanSubDetailDO::getStartTwoDimDate))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (overlappingInserts.isEmpty()) {
|
||||
// 没有重叠的插活数据,保持原样
|
||||
resultList.add(baseItem);
|
||||
} else {
|
||||
// 有重叠的插活数据,需要分割baseItem
|
||||
List<PlanSubDetailDO> splitSegments = splitBaseItemByInserts(baseItem, overlappingInserts, holidayList);
|
||||
resultList.addAll(splitSegments);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加插活数据
|
||||
resultList.addAll(insertItems);
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据插活数据分割baseItem
|
||||
*/
|
||||
private List<PlanSubDetailDO> splitBaseItemByInserts(PlanSubDetailDO baseItem,
|
||||
List<PlanSubDetailDO> overlappingInserts,
|
||||
List<LocalDateTime> holidayList) {
|
||||
List<PlanSubDetailDO> segments = new ArrayList<>();
|
||||
LocalDateTime baseStart = baseItem.getStartTwoDimDate();
|
||||
LocalDateTime baseEnd = baseItem.getTwoDimDate();
|
||||
Long originalDesignNum = baseItem.getDesignNum();
|
||||
|
||||
// 处理baseItem被插活数据分割的情况
|
||||
LocalDateTime currentStart = baseStart;
|
||||
Long usedDesignNum = 0L;
|
||||
|
||||
for (PlanSubDetailDO insert : overlappingInserts) {
|
||||
LocalDateTime insertStart = insert.getStartTwoDimDate();
|
||||
LocalDateTime insertEnd = insert.getTwoDimDate();
|
||||
|
||||
// 如果当前开始时间在插活数据之前,创建一个segment
|
||||
if (currentStart.isBefore(insertStart)) {
|
||||
// 计算这个时间段内可用的工作日数
|
||||
Long availableWorkDays = calculateWorkDaysExcludingHolidays(currentStart, insertStart.minusDays(1), holidayList);
|
||||
Long segmentDesignNum = Math.min(availableWorkDays, originalDesignNum - usedDesignNum);
|
||||
|
||||
if (segmentDesignNum > 0) {
|
||||
// 根据designNum计算实际的结束日期
|
||||
LocalDateTime segmentEnd = calculateEndDateByDesignNum(currentStart, segmentDesignNum, holidayList);
|
||||
PlanSubDetailDO segment = createBaseItem(baseItem, currentStart, segmentEnd, holidayList);
|
||||
segment.setDesignNum(segmentDesignNum);
|
||||
segments.add(segment);
|
||||
usedDesignNum += segmentDesignNum;
|
||||
currentStart = segmentEnd.plusDays(1);
|
||||
}
|
||||
}
|
||||
|
||||
// 跳过插活数据的时间段
|
||||
currentStart = insertEnd.plusDays(1);
|
||||
}
|
||||
|
||||
// 处理最后一个插活数据之后的部分
|
||||
if (usedDesignNum < originalDesignNum) {
|
||||
Long remainingDesignNum = originalDesignNum - usedDesignNum;
|
||||
|
||||
// 从插活数据结束后的下一天开始,找到第一个工作日
|
||||
LocalDateTime segmentStart = findNextWorkDay(currentStart, holidayList);
|
||||
|
||||
// 根据剩余的designNum计算结束日期(包含节假日,但designNum只计算工作日)
|
||||
LocalDateTime segmentEnd = calculateEndDateByDesignNumWithHolidays(segmentStart, remainingDesignNum, holidayList);
|
||||
|
||||
PlanSubDetailDO segment = createBaseItem(baseItem, segmentStart, segmentEnd, holidayList);
|
||||
segment.setDesignNum(remainingDesignNum);
|
||||
segments.add(segment);
|
||||
}
|
||||
|
||||
return segments;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据designNum计算结束日期(包含节假日,但designNum只计算工作日)
|
||||
*/
|
||||
private LocalDateTime calculateEndDateByDesignNumWithHolidays(LocalDateTime startDate, Long designNum, List<LocalDateTime> holidayList) {
|
||||
LocalDateTime current = startDate;
|
||||
Long workDays = 0L;
|
||||
|
||||
while (workDays < designNum) {
|
||||
if (!isHoliday(current, holidayList)) {
|
||||
workDays++;
|
||||
}
|
||||
if (workDays < designNum) {
|
||||
current = current.plusDays(1);
|
||||
}
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据designNum计算结束日期(跳过节假日)
|
||||
*/
|
||||
private LocalDateTime calculateEndDateByDesignNum(LocalDateTime startDate, Long designNum, List<LocalDateTime> holidayList) {
|
||||
LocalDateTime current = startDate;
|
||||
Long workDays = 0L;
|
||||
|
||||
while (workDays < designNum) {
|
||||
if (!isHoliday(current, holidayList)) {
|
||||
workDays++;
|
||||
}
|
||||
if (workDays < designNum) {
|
||||
current = current.plusDays(1);
|
||||
}
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建插活数据项(保持原有时间范围,排除节假日计算designNum)
|
||||
*/
|
||||
private PlanSubDetailDO createInsertItem(PlanSubDetailDO original, LocalDateTime startDate, LocalDateTime endDate, List<LocalDateTime> holidayList) {
|
||||
PlanSubDetailDO insertItem = new PlanSubDetailDO();
|
||||
copyBaseItemProperties(insertItem, original);
|
||||
insertItem.setId(null); // 插活数据id为空
|
||||
insertItem.setIsCha("Y"); // 标记为插活
|
||||
insertItem.setStartTwoDimDate(startDate);
|
||||
insertItem.setTwoDimDate(endDate);
|
||||
// 计算排除节假日的工作天数
|
||||
insertItem.setDesignNum(calculateWorkDaysExcludingHolidays(startDate, endDate, holidayList));
|
||||
return insertItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制baseItem属性
|
||||
*/
|
||||
private void copyBaseItemProperties(PlanSubDetailDO target, PlanSubDetailDO source) {
|
||||
target.setProjectPlanId(source.getProjectPlanId());
|
||||
target.setProjectId(source.getProjectId());
|
||||
target.setProjectPlanSubId(source.getProjectPlanSubId());
|
||||
target.setProjectSubCode(source.getProjectSubCode());
|
||||
target.setTwoDimOwner(source.getTwoDimOwner());
|
||||
target.setProjectSubId(source.getProjectSubId());
|
||||
target.setSubType(source.getSubType());
|
||||
target.setName(source.getName());
|
||||
target.setCode(source.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找下一个工作日
|
||||
*/
|
||||
private LocalDateTime findNextWorkDay(LocalDateTime date, List<LocalDateTime> holidayList) {
|
||||
LocalDateTime current = date;
|
||||
while (isHoliday(current, holidayList)) {
|
||||
current = current.plusDays(1);
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找下一个节假日
|
||||
*/
|
||||
private LocalDateTime findNextHoliday(LocalDateTime date, List<LocalDateTime> holidayList) {
|
||||
return holidayList.stream()
|
||||
.filter(holiday -> !holiday.isBefore(date))
|
||||
.min(LocalDateTime::compareTo)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否是节假日
|
||||
*/
|
||||
private boolean isHoliday(LocalDateTime date, List<LocalDateTime> holidayList) {
|
||||
return holidayList.contains(date.toLocalDate().atStartOfDay());
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算排除节假日的工作天数
|
||||
*/
|
||||
private Long calculateWorkDaysExcludingHolidays(LocalDateTime startDate, LocalDateTime endDate, List<LocalDateTime> holidayList) {
|
||||
private Long calculateWorkDaysExcludeHolidays(LocalDateTime startDate, LocalDateTime endDate, List<LocalDateTime> holidayList) {
|
||||
long workDays = 0;
|
||||
LocalDateTime current = startDate.toLocalDate().atStartOfDay();
|
||||
LocalDateTime end = endDate.toLocalDate().atStartOfDay();
|
||||
|
||||
while (!current.isAfter(end)) {
|
||||
if (!isHoliday(current, holidayList)) {
|
||||
// 检查是否是节假日
|
||||
LocalDateTime finalCurrent = current;
|
||||
boolean isHoliday = holidayList.stream()
|
||||
.anyMatch(holiday -> holiday.isEqual(finalCurrent));
|
||||
|
||||
if (!isHoliday) {
|
||||
workDays++;
|
||||
}
|
||||
current = current.plusDays(1);
|
||||
@ -1273,46 +1214,71 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
|
||||
return workDays;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据工作天数计算结束日期(包含节假日)
|
||||
*/
|
||||
private LocalDateTime calculateEndDateByWorkDays(LocalDateTime startDate, Long workDays, List<LocalDateTime> holidayList) {
|
||||
LocalDateTime current = startDate;
|
||||
long countedWorkDays = 0;
|
||||
|
||||
while (countedWorkDays < workDays) {
|
||||
// 检查是否是节假日
|
||||
LocalDateTime finalCurrent = current;
|
||||
boolean isHoliday = holidayList.stream()
|
||||
.anyMatch(holiday -> holiday.isEqual(finalCurrent));
|
||||
|
||||
if (!isHoliday) {
|
||||
countedWorkDays++;
|
||||
}
|
||||
|
||||
if (countedWorkDays < workDays) {
|
||||
current = current.plusDays(1);
|
||||
}
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* 找到下一个非节假日日期
|
||||
*/
|
||||
private LocalDateTime findNextNonHoliday(LocalDateTime startDate, List<LocalDateTime> holidayList) {
|
||||
LocalDateTime current = startDate;
|
||||
|
||||
while (true) {
|
||||
LocalDateTime finalCurrent = current;
|
||||
boolean isHoliday = holidayList.stream()
|
||||
.anyMatch(holiday -> holiday.isEqual(finalCurrent));
|
||||
|
||||
if (!isHoliday) {
|
||||
return current;
|
||||
}
|
||||
|
||||
current = current.plusDays(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建baseItem对象(用于baseList顺延)
|
||||
*/
|
||||
private PlanSubDetailDO createBaseItem(PlanSubDetailDO original, LocalDateTime startDate, LocalDateTime endDate, List<LocalDateTime> holidayList) {
|
||||
private PlanSubDetailDO createBaseItem(PlanSubDetailDO original, LocalDateTime startDate, LocalDateTime endDate) {
|
||||
PlanSubDetailDO baseItem = new PlanSubDetailDO();
|
||||
copyBaseItemProperties(baseItem, original);
|
||||
// 复制原有属性
|
||||
baseItem.setId(original.getId());
|
||||
baseItem.setDesignNum(calculateWorkDaysExcludingHolidays(startDate, endDate, holidayList));
|
||||
baseItem.setProjectPlanId(original.getProjectPlanId());
|
||||
baseItem.setProjectId(original.getProjectId());
|
||||
baseItem.setProjectPlanSubId(original.getProjectPlanSubId());
|
||||
baseItem.setProjectSubCode(original.getProjectSubCode());
|
||||
baseItem.setTwoDimOwner(original.getTwoDimOwner());
|
||||
baseItem.setProjectSubId(original.getProjectPlanSubId());
|
||||
baseItem.setSubType(original.getSubType());
|
||||
baseItem.setName(original.getName());
|
||||
baseItem.setCode(original.getCode());
|
||||
baseItem.setStartTwoDimDate(startDate);
|
||||
baseItem.setTwoDimDate(endDate);
|
||||
return baseItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取时间段内的节假日
|
||||
*/
|
||||
private List<LocalDateTime> getHolidaysInRange(LocalDateTime startDate, LocalDateTime endDate,
|
||||
List<LocalDateTime> holidayList) {
|
||||
return holidayList.stream()
|
||||
.filter(holiday -> !holiday.isBefore(startDate) && !holiday.isAfter(endDate))
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算工作天数(排除节假日)
|
||||
*/
|
||||
private Long calculateWorkDays(LocalDateTime startDate, LocalDateTime endDate) {
|
||||
long workDays = 0;
|
||||
LocalDateTime current = startDate.toLocalDate().atStartOfDay();
|
||||
LocalDateTime end = endDate.toLocalDate().atStartOfDay();
|
||||
|
||||
while (!current.isAfter(end)) {
|
||||
workDays++;
|
||||
current = current.plusDays(1);
|
||||
}
|
||||
|
||||
return workDays;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
@ -595,7 +595,7 @@ const saveForm = async () => {
|
||||
} else {
|
||||
message.error('失败:当前页面无数据可供保存')
|
||||
}
|
||||
reload() // 刷新列表
|
||||
getList()
|
||||
} catch (error) {
|
||||
message.error('失败:' + error.message)
|
||||
} finally {
|
||||
@ -802,7 +802,7 @@ const handleDelete = async (row) => {
|
||||
try {
|
||||
await PlansubdetailApi.deletePlanSubDetail(row.id)
|
||||
message.success('删除成功')
|
||||
reload() // 刷新列表
|
||||
getList() // 刷新列表
|
||||
} catch (e) {
|
||||
console.error('删除失败:', e)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user