插活
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);
|
boolean hasOverlap = !(reqEnd.compareTo(existStart) < 0) && !(reqStart.compareTo(existEnd) > 0);
|
||||||
if (hasOverlap) {
|
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);
|
planSubDetailMapper.updateBatch(list);
|
||||||
//更新表主表数据
|
//更新表主表数据
|
||||||
//先看有多少个子项目
|
//先看有多少个子项目
|
||||||
Map<Long, List<PlanSubDetailDO>> collect = list.stream().collect(Collectors.groupingBy(PlanSubDetailDO::getProjectPlanSubId));
|
Map<Long, List<PlanSubDetailDO>> collect = list.stream().collect(Collectors.groupingBy(PlanSubDetailDO::getProjectSubId));
|
||||||
collect.forEach((subId,subList) -> {
|
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));
|
Map<String, List<PlanSubDetailDO>> collect1 = subList.stream().collect(Collectors.groupingBy(PlanSubDetailDO::getSubType));
|
||||||
//然后对里面的进行排序
|
for (Map.Entry<String, List<PlanSubDetailDO>> entry1 : collect1.entrySet()) {
|
||||||
collect1.forEach((type,subTypeList) ->{
|
String type = entry1.getKey();
|
||||||
|
List<PlanSubDetailDO> subTypeList = entry1.getValue();
|
||||||
List<PlanSubDetailDO> sortedList = subTypeList.stream()
|
List<PlanSubDetailDO> sortedList = subTypeList.stream()
|
||||||
.sorted(Comparator.comparing(PlanSubDetailDO::getSeqNo).reversed())
|
.sorted(Comparator.comparing(PlanSubDetailDO::getSeqNo).reversed())
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
Long num = 0L;
|
||||||
|
for (PlanSubDetailDO planSubDetailDO : sortedList) {
|
||||||
|
Long designNum = planSubDetailDO.getDesignNum();
|
||||||
|
num += designNum;
|
||||||
|
}
|
||||||
LambdaUpdateWrapper<PlanSubDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
|
LambdaUpdateWrapper<PlanSubDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
|
||||||
lambdaUpdateWrapper.eq(PlanSubDO::getProjectSubId,subId);
|
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();
|
LocalDateTime twoDimDate = sortedList.get(0).getTwoDimDate();
|
||||||
Long num = sortedList.get(0).getDesignNum();
|
|
||||||
//取最大值就是第一个
|
//取最大值就是第一个
|
||||||
if ("BLUEPRINT_WORKBLANK".equals(type)){
|
if ("BLUEPRINT_WORKBLANK".equals(type)){
|
||||||
lambdaUpdateWrapper.set(PlanSubDO::getStartBlankDate,startTwoDimDate);
|
lambdaUpdateWrapper.set(PlanSubDO::getStartBlankDate,startTwoDimDate);
|
||||||
@ -453,8 +466,8 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
|
|||||||
lambdaUpdateWrapper.set(PlanSubDO::getThreeDimNum,num);
|
lambdaUpdateWrapper.set(PlanSubDO::getThreeDimNum,num);
|
||||||
}
|
}
|
||||||
planSubMapper.update(lambdaUpdateWrapper);
|
planSubMapper.update(lambdaUpdateWrapper);
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
return CommonResult.success(true);
|
return CommonResult.success(true);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -523,7 +536,21 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
|
|||||||
});
|
});
|
||||||
return CommonResult.success(true);
|
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
|
// @Override
|
||||||
// @Transactional
|
// @Transactional
|
||||||
// public CommonResult chahuoList(PlanSubDetailSaveReqVO updateReqVO) {
|
// public CommonResult chahuoList(PlanSubDetailSaveReqVO updateReqVO) {
|
||||||
@ -987,284 +1014,198 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
|
|||||||
List<LocalDateTime> holidayList) {
|
List<LocalDateTime> holidayList) {
|
||||||
List<PlanSubDetailDO> resultList = new ArrayList<>();
|
List<PlanSubDetailDO> resultList = new ArrayList<>();
|
||||||
|
|
||||||
// 1. 如果没有插活数据,直接返回baseList
|
// 1. 先处理插活数据,不按节假日分段,保持原始范围
|
||||||
if (CollUtil.isEmpty(insertList)) {
|
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);
|
return new ArrayList<>(baseList);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 如果baseList为空,直接返回所有插活数据
|
// 3. 处理baseList为空的情况
|
||||||
if (CollUtil.isEmpty(baseList)) {
|
if (CollUtil.isEmpty(baseList)) {
|
||||||
List<PlanSubDetailDO> processedInsertList = new ArrayList<>();
|
// baseList为空,直接返回插活数据
|
||||||
for (PlanSubDetailDO insertItem : insertList) {
|
return new ArrayList<>(processedInsertList);
|
||||||
PlanSubDetailDO processedInsert = createInsertItem(insertItem, insertItem.getStartTwoDimDate(), insertItem.getTwoDimDate(), holidayList);
|
|
||||||
processedInsertList.add(processedInsert);
|
|
||||||
}
|
|
||||||
processedInsertList.sort(Comparator.comparing(PlanSubDetailDO::getStartTwoDimDate));
|
|
||||||
return processedInsertList;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 获取baseList的时间范围
|
// 4. 获取插活数据的时间范围
|
||||||
LocalDateTime baseListMinStartTime = baseList.stream()
|
LocalDateTime insertStartTime = processedInsertList.stream()
|
||||||
.map(PlanSubDetailDO::getStartTwoDimDate)
|
.map(PlanSubDetailDO::getStartTwoDimDate)
|
||||||
.min(LocalDateTime::compareTo)
|
.min(LocalDateTime::compareTo)
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
LocalDateTime baseListMaxEndTime = baseList.stream()
|
LocalDateTime insertEndTime = processedInsertList.stream()
|
||||||
.map(PlanSubDetailDO::getTwoDimDate)
|
.map(PlanSubDetailDO::getTwoDimDate)
|
||||||
.max(LocalDateTime::compareTo)
|
.max(LocalDateTime::compareTo)
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
|
|
||||||
// 4. 处理插活数据,保持原有时间范围,但重新计算designNum(排除节假日)
|
// 5. 获取baseList的时间范围
|
||||||
List<PlanSubDetailDO> processedInsertList = new ArrayList<>();
|
LocalDateTime baseMinStartTime = baseList.stream()
|
||||||
for (PlanSubDetailDO insertItem : insertList) {
|
.map(PlanSubDetailDO::getStartTwoDimDate)
|
||||||
LocalDateTime startDate = insertItem.getStartTwoDimDate();
|
.min(LocalDateTime::compareTo)
|
||||||
LocalDateTime endDate = insertItem.getTwoDimDate();
|
.orElse(null);
|
||||||
|
LocalDateTime baseMaxEndTime = baseList.stream()
|
||||||
|
.map(PlanSubDetailDO::getTwoDimDate)
|
||||||
|
.max(LocalDateTime::compareTo)
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
PlanSubDetailDO processedInsert = createInsertItem(insertItem, startDate, endDate, holidayList);
|
// 6. 边界情况处理
|
||||||
processedInsertList.add(processedInsert);
|
if (insertEndTime != null && baseMinStartTime != null && insertEndTime.isBefore(baseMinStartTime)) {
|
||||||
|
// 情况1:插活数据在所有baseList之前
|
||||||
|
resultList.addAll(processedInsertList);
|
||||||
|
resultList.addAll(baseList);
|
||||||
|
return resultList;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. 分离插活数据:在baseList之前的、在baseList之间的、在baseList之后的
|
if (insertStartTime != null && baseMaxEndTime != null && insertStartTime.isAfter(baseMaxEndTime)) {
|
||||||
List<PlanSubDetailDO> beforeBaseListInserts = new ArrayList<>();
|
// 情况2:插活数据在所有baseList之后
|
||||||
List<PlanSubDetailDO> duringBaseListInserts = new ArrayList<>();
|
resultList.addAll(baseList);
|
||||||
List<PlanSubDetailDO> afterBaseListInserts = new ArrayList<>();
|
resultList.addAll(processedInsertList);
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
|
|
||||||
for (PlanSubDetailDO insertItem : processedInsertList) {
|
// 7. 正常插活逻辑(插活数据与baseList有重叠)
|
||||||
if (insertItem.getTwoDimDate().isBefore(baseListMinStartTime)) {
|
// 分离baseList:在插活数据之前的、被打断的、在插活数据之后的
|
||||||
// 插活数据完全在baseList之前
|
List<PlanSubDetailDO> beforeInsertList = new ArrayList<>();
|
||||||
beforeBaseListInserts.add(insertItem);
|
List<PlanSubDetailDO> interruptedList = new ArrayList<>();
|
||||||
} else if (insertItem.getStartTwoDimDate().isAfter(baseListMaxEndTime)) {
|
List<PlanSubDetailDO> afterInsertList = new ArrayList<>();
|
||||||
// 插活数据完全在baseList之后
|
|
||||||
afterBaseListInserts.add(insertItem);
|
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 {
|
} else {
|
||||||
// 插活数据与baseList有重叠或在baseList之间
|
// 整个被打断,全部加入剩余列表
|
||||||
duringBaseListInserts.add(insertItem);
|
remainingBaseList.add(interruptedItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. 处理在baseList之前的插活数据:直接添加到结果列表前面
|
// 10. 添加插活数据
|
||||||
beforeBaseListInserts.sort(Comparator.comparing(PlanSubDetailDO::getStartTwoDimDate));
|
resultList.addAll(processedInsertList);
|
||||||
resultList.addAll(beforeBaseListInserts);
|
|
||||||
|
|
||||||
// 7. 处理baseList和在其间的插活数据
|
// 11. 处理剩余的baseList(被打断的剩余部分 + 原本在插活数据之后的)
|
||||||
if (CollUtil.isEmpty(duringBaseListInserts)) {
|
List<PlanSubDetailDO> allRemainingList = new ArrayList<>();
|
||||||
// 没有在baseList之间的插活数据,baseList保持原样
|
allRemainingList.addAll(remainingBaseList);
|
||||||
resultList.addAll(baseList);
|
allRemainingList.addAll(afterInsertList);
|
||||||
} else {
|
|
||||||
// 有在baseList之间的插活数据,需要重新编排
|
if (!allRemainingList.isEmpty()) {
|
||||||
// 重新构建结果列表,考虑插活数据对多个baseList的影响
|
// 获取插活数据的最后结束时间
|
||||||
resultList.addAll(rebuildListWithInserts(baseList, duringBaseListInserts, holidayList));
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8. 处理在baseList之后的插活数据:直接添加到baseList后面
|
// 12. 按开始时间排序
|
||||||
afterBaseListInserts.sort(Comparator.comparing(PlanSubDetailDO::getStartTwoDimDate));
|
|
||||||
resultList.addAll(afterBaseListInserts);
|
|
||||||
|
|
||||||
// 9. 按开始时间排序
|
|
||||||
resultList.sort(Comparator.comparing(PlanSubDetailDO::getStartTwoDimDate));
|
resultList.sort(Comparator.comparing(PlanSubDetailDO::getStartTwoDimDate));
|
||||||
|
|
||||||
return resultList;
|
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;
|
long workDays = 0;
|
||||||
LocalDateTime current = startDate.toLocalDate().atStartOfDay();
|
LocalDateTime current = startDate.toLocalDate().atStartOfDay();
|
||||||
LocalDateTime end = endDate.toLocalDate().atStartOfDay();
|
LocalDateTime end = endDate.toLocalDate().atStartOfDay();
|
||||||
|
|
||||||
while (!current.isAfter(end)) {
|
while (!current.isAfter(end)) {
|
||||||
if (!isHoliday(current, holidayList)) {
|
// 检查是否是节假日
|
||||||
|
LocalDateTime finalCurrent = current;
|
||||||
|
boolean isHoliday = holidayList.stream()
|
||||||
|
.anyMatch(holiday -> holiday.isEqual(finalCurrent));
|
||||||
|
|
||||||
|
if (!isHoliday) {
|
||||||
workDays++;
|
workDays++;
|
||||||
}
|
}
|
||||||
current = current.plusDays(1);
|
current = current.plusDays(1);
|
||||||
@ -1273,46 +1214,71 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
|
|||||||
return workDays;
|
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顺延)
|
* 创建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();
|
PlanSubDetailDO baseItem = new PlanSubDetailDO();
|
||||||
copyBaseItemProperties(baseItem, original);
|
// 复制原有属性
|
||||||
baseItem.setId(original.getId());
|
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.setStartTwoDimDate(startDate);
|
||||||
baseItem.setTwoDimDate(endDate);
|
baseItem.setTwoDimDate(endDate);
|
||||||
return baseItem;
|
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
|
@Override
|
||||||
|
@ -595,7 +595,7 @@ const saveForm = async () => {
|
|||||||
} else {
|
} else {
|
||||||
message.error('失败:当前页面无数据可供保存')
|
message.error('失败:当前页面无数据可供保存')
|
||||||
}
|
}
|
||||||
reload() // 刷新列表
|
getList()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error('失败:' + error.message)
|
message.error('失败:' + error.message)
|
||||||
} finally {
|
} finally {
|
||||||
@ -802,7 +802,7 @@ const handleDelete = async (row) => {
|
|||||||
try {
|
try {
|
||||||
await PlansubdetailApi.deletePlanSubDetail(row.id)
|
await PlansubdetailApi.deletePlanSubDetail(row.id)
|
||||||
message.success('删除成功')
|
message.success('删除成功')
|
||||||
reload() // 刷新列表
|
getList() // 刷新列表
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('删除失败:', e)
|
console.error('删除失败:', e)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user