This commit is contained in:
Ledo 2025-10-10 16:56:58 +08:00
parent 1041e97ce5
commit f963f2e1b5
6 changed files with 266 additions and 263 deletions

View File

@ -97,8 +97,8 @@ public class PlanSubController {
@PostMapping("/operate")
@Operation(summary = "创建生产计划子项目")
@PreAuthorize("@ss.hasPermission('heli:plan-sub:create')")
public void operate(@RequestBody List<PlanSubSaveReqVO> list) {
planSubService.operate(list);
public CommonResult operate(@RequestBody List<PlanSubSaveReqVO> list) {
return planSubService.operate(list);
}
@PutMapping("/update")
@Operation(summary = "更新生产计划子项目")

View File

@ -2,6 +2,8 @@ package com.chanko.yunxi.mes.module.heli.service.plansub;
import java.util.*;
import javax.validation.*;
import com.chanko.yunxi.mes.framework.common.pojo.CommonResult;
import com.chanko.yunxi.mes.module.heli.controller.admin.plansub.vo.*;
import com.chanko.yunxi.mes.module.heli.dal.dataobject.plansub.PlanSubDO;
import com.chanko.yunxi.mes.framework.common.pojo.PageResult;
@ -24,7 +26,7 @@ public interface PlanSubService {
Long createPlanSub(@Valid PlanSubSaveReqVO createReqVO);
void operate(List<PlanSubSaveReqVO> list);
CommonResult operate(List<PlanSubSaveReqVO> list);
/**
* 更新生产计划子项目
*

View File

@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.chanko.yunxi.mes.framework.common.exception.ErrorCode;
import com.chanko.yunxi.mes.framework.common.pojo.CommonResult;
import com.chanko.yunxi.mes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.chanko.yunxi.mes.module.heli.controller.admin.shopCalendar.vo.ShopCalendarPageReqVO;
import com.chanko.yunxi.mes.module.heli.dal.dataobject.plansubdetail.PlanSubDetailDO;
@ -66,7 +67,7 @@ public class PlanSubServiceImpl implements PlanSubService {
}
@Override
public void operate(List<PlanSubSaveReqVO> list) {
public CommonResult operate(List<PlanSubSaveReqVO> list) {
HashSet<String> userIds = new HashSet<>();
List<PlanSubSaveReqVO> inserList = new ArrayList<>();
for (PlanSubSaveReqVO planSubSaveReqVO : list) {
@ -156,6 +157,7 @@ public class PlanSubServiceImpl implements PlanSubService {
planSubDetailMapper.insertOrUpdateBatch(details);
}
}
return CommonResult.success(true);
}
@ -614,11 +616,14 @@ public class PlanSubServiceImpl implements PlanSubService {
PageResult<PlanSubDO> planSubDOPageResult = planSubMapper.selectPage(pageReqVO);
List<PlanSubDO> list = planSubDOPageResult.getList();
for (PlanSubDO planSubDO : list) {
List<PlanSubDetailDO> planSubDetailDOS1 = planSubDetailMapper.selectList(new LambdaQueryWrapperX<PlanSubDetailDO>().eq(PlanSubDetailDO::getProjectPlanSubId, planSubDO.getId())
List<PlanSubDetailDO> planSubDetailDOS1 = planSubDetailMapper.selectList(new LambdaQueryWrapperX<PlanSubDetailDO>()
.eq(PlanSubDetailDO::getProjectSubId, planSubDO.getProjectSubId())
.eq(PlanSubDetailDO::getSubType,"BLUEPRINT_WORKBLANK"));
List<PlanSubDetailDO> planSubDetailDOS2 = planSubDetailMapper.selectList(new LambdaQueryWrapperX<PlanSubDetailDO>().eq(PlanSubDetailDO::getProjectPlanSubId, planSubDO.getId())
List<PlanSubDetailDO> planSubDetailDOS2 = planSubDetailMapper.selectList(new LambdaQueryWrapperX<PlanSubDetailDO>()
.eq(PlanSubDetailDO::getProjectSubId, planSubDO.getProjectSubId())
.eq(PlanSubDetailDO::getSubType,"BLUEPRINT_2D"));
List<PlanSubDetailDO> planSubDetailDOS3 = planSubDetailMapper.selectList(new LambdaQueryWrapperX<PlanSubDetailDO>().eq(PlanSubDetailDO::getProjectPlanSubId, planSubDO.getId())
List<PlanSubDetailDO> planSubDetailDOS3 = planSubDetailMapper.selectList(new LambdaQueryWrapperX<PlanSubDetailDO>()
.eq(PlanSubDetailDO::getProjectSubId, planSubDO.getProjectSubId())
.eq(PlanSubDetailDO::getSubType,"BLUEPRINT_3D"));
if (CollUtil.isNotEmpty(planSubDetailDOS1)) {

View File

@ -332,8 +332,20 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
LambdaQueryWrapper<PlanSubDetailDO> wrapper1 = new LambdaQueryWrapper<>();
wrapper1.eq(PlanSubDetailDO::getProjectSubId,updateReqVO.getProjectSubId());
wrapper1.eq(PlanSubDetailDO::getSubType,updateReqVO.getSubType());
String type="BLUEPRINT_WORKBLANK".equals(updateReqVO.getSubType())?"毛坯":"BLUEPRINT_2D".equals(updateReqVO.getSubType())?"2D":"3D";
if (planSubDetailMapper.selectCount(wrapper1)> 0 ) return CommonResult.error(400,"该子项目"+updateReqVO.getName()+" 设计类型"+type+" 存在派工数据,请确认!");
List<PlanSubDetailDO> planSubDetailDOS1 = planSubDetailMapper.selectList(wrapper1);
for (PlanSubDetailDO planSubDetailDO : planSubDetailDOS1) {
LocalDateTime reqStart = updateReqVO.getStartTwoDimDate();
LocalDateTime reqEnd = updateReqVO.getTwoDimDate();
LocalDateTime existStart = planSubDetailDO.getStartTwoDimDate();
LocalDateTime existEnd = planSubDetailDO.getTwoDimDate();
// 判断请求时间段是否与已有时间段有重叠
boolean hasOverlap = !(reqEnd.compareTo(existStart) < 0) && !(reqStart.compareTo(existEnd) > 0);
if (hasOverlap) {
return CommonResult.error(400,"当前子项目,当前设计类型时间存在交集,请确认!");
}
}
// if (planSubDetailMapper.selectCount(wrapper1)> 0 ) return CommonResult.error(400,"该子项目"+updateReqVO.getName()+" 设计类型"+type+" 存在派工数据,请确认!");
}
@ -363,7 +375,7 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
}
}
}
if (change || ObjectUtil.isEmpty(list) ||(CollUtil.isNotEmpty(noSelfList)&& (noSelfList.get(0).getStartTwoDimDate().compareTo(updateReqVO.getTwoDimDate()) > 0 ))){
if (change || ObjectUtil.isEmpty(noSelfList) ||(noSelfList.get(0).getStartTwoDimDate().compareTo(updateReqVO.getTwoDimDate()) > 0 )){
List<PlanSubDetailDO> newList = new ArrayList<>();
newList.addAll(list);
if (ObjectUtil.isNotEmpty(updateReqVO.getId())){
@ -434,14 +446,17 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
if ("BLUEPRINT_WORKBLANK".equals(type)){
lambdaUpdateWrapper1.set(PlanSubDO::getStartBlankDate,startTwoDimDate);
lambdaUpdateWrapper1.set(PlanSubDO::getBlankDate,twoDimDate);
lambdaUpdateWrapper1.set(PlanSubDO::getBlankOwner,sortedList.get(0).getTwoDimOwner());
lambdaUpdateWrapper1.set(PlanSubDO::getBlankNum,num);
}else if ("BLUEPRINT_2D".equals(type)){
lambdaUpdateWrapper1.set(PlanSubDO::getStartTwoDimDate,startTwoDimDate);
lambdaUpdateWrapper1.set(PlanSubDO::getTwoDimDate,twoDimDate);
lambdaUpdateWrapper1.set(PlanSubDO::getTwoDimOwner,sortedList.get(0).getTwoDimOwner());
lambdaUpdateWrapper1.set(PlanSubDO::getTwoDimNum,num);
}else {
lambdaUpdateWrapper1.set(PlanSubDO::getStartThreeDimDate,startTwoDimDate);
lambdaUpdateWrapper1.set(PlanSubDO::getThreeDimDate,twoDimDate);
lambdaUpdateWrapper1.set(PlanSubDO::getThreeDimOwner,sortedList.get(0).getTwoDimOwner());
lambdaUpdateWrapper1.set(PlanSubDO::getThreeDimNum,num);
}
planSubMapper.update(lambdaUpdateWrapper1);
@ -569,22 +584,25 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
}
}
}
Map<Long, List<PlanSubDetailDO>> collect1 = list.stream().collect(Collectors.groupingBy(PlanSubDetailDO::getProjectSubId));
collect1.forEach((id,detailList) -> {
Map<String, List<PlanSubDetailDO>> collect2 = detailList.stream().collect(Collectors.groupingBy(PlanSubDetailDO::getSubType));
collect2.forEach((type,list2) ->{
int i = 1;
for (PlanSubDetailDO planSubDetailDO : list2) {
planSubDetailDO.setSeqNo(Long.valueOf(i++));
}
});
});
planSubDetailMapper.deleteBatchIds(deleteId);
// Map<Long, List<PlanSubDetailDO>> collect1 = list.stream().collect(Collectors.groupingBy(PlanSubDetailDO::getProjectSubId));
// collect1.forEach((id,detailList) -> {
// Map<String, List<PlanSubDetailDO>> collect2 = detailList.stream().collect(Collectors.groupingBy(PlanSubDetailDO::getSubType));
// collect2.forEach((type,list2) ->{
// int i = 1;
// for (PlanSubDetailDO planSubDetailDO : list2) {
// planSubDetailDO.setSeqNo(Long.valueOf(i++));
// }
// });
// });
if (CollUtil.isNotEmpty(deleteId)){
planSubDetailMapper.deleteBatchIds(deleteId);
}
//查询子项目
planSubDetailMapper.insertOrUpdateBatch(list);
//更新表主表数据
//
//先看有多少个子项目
Map<Long, List<PlanSubDetailDO>> groupBySubId = list.stream().collect(Collectors.groupingBy(PlanSubDetailDO::getProjectPlanSubId));
Map<Long, List<PlanSubDetailDO>> groupBySubId = list.stream().collect(Collectors.groupingBy(PlanSubDetailDO::getProjectSubId));
groupBySubId.forEach((subId,subList) -> {
//再根据设计类型来
Map<String, List<PlanSubDetailDO>> groupByType = subList.stream().collect(Collectors.groupingBy(PlanSubDetailDO::getSubType));
@ -595,21 +613,27 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
.collect(Collectors.toList());
LambdaUpdateWrapper<PlanSubDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
lambdaUpdateWrapper.eq(PlanSubDO::getProjectSubId,subId);
LocalDateTime startTwoDimDate = sortedList.get(0).getStartTwoDimDate();
LocalDateTime startTwoDimDate = sortedList.get(sortedList.size() - 1 ).getStartTwoDimDate();
LocalDateTime twoDimDate = sortedList.get(0).getTwoDimDate();
Long num = sortedList.get(0).getDesignNum();
Long num = 0L;
for (PlanSubDetailDO planSubDetailDO : sortedList) {
num += planSubDetailDO.getDesignNum();
}
//取最大值就是第一个
if ("BLUEPRINT_WORKBLANK".equals(type)){
lambdaUpdateWrapper.set(PlanSubDO::getStartBlankDate,startTwoDimDate);
lambdaUpdateWrapper.set(PlanSubDO::getBlankDate,twoDimDate);
lambdaUpdateWrapper.set(PlanSubDO::getBlankOwner, sortedList.get(0).getTwoDimOwner());
lambdaUpdateWrapper.set(PlanSubDO::getBlankNum,num);
}else if ("BLUEPRINT_2D".equals(type)){
lambdaUpdateWrapper.set(PlanSubDO::getStartTwoDimDate,startTwoDimDate);
lambdaUpdateWrapper.set(PlanSubDO::getTwoDimDate,twoDimDate);
lambdaUpdateWrapper.set(PlanSubDO::getTwoDimOwner, sortedList.get(0).getTwoDimOwner());
lambdaUpdateWrapper.set(PlanSubDO::getTwoDimNum,num);
}else {
lambdaUpdateWrapper.set(PlanSubDO::getStartThreeDimDate,startTwoDimDate);
lambdaUpdateWrapper.set(PlanSubDO::getThreeDimDate,twoDimDate);
lambdaUpdateWrapper.set(PlanSubDO::getThreeDimOwner, sortedList.get(0).getTwoDimOwner());
lambdaUpdateWrapper.set(PlanSubDO::getThreeDimNum,num);
}
planSubMapper.update(lambdaUpdateWrapper);
@ -1048,8 +1072,9 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
// 2. 查询最大时间往后90天内的节假日
LocalDateTime endDate = maxDate.plusDays(90);
LocalDateTime begDate = minDate.minusDays(30);
List<ShopCalendarDO> shopCalendarDOList = shopCalendarMapper.selectList(new LambdaQueryWrapper<ShopCalendarDO>().eq(ShopCalendarDO::getIfjiejiari, "true")
.between(ShopCalendarDO::getDates, minDate, endDate).orderByAsc(ShopCalendarDO::getDates));
.between(ShopCalendarDO::getDates, begDate, endDate).orderByAsc(ShopCalendarDO::getDates));
List<LocalDateTime> holidayList = new ArrayList<>();
for (ShopCalendarDO shopCalendarDO : shopCalendarDOList) {
holidayList.add(shopCalendarDO.getDates());
@ -1071,18 +1096,10 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
// 5. 执行插活逻辑
List<PlanSubDetailDO> resultList = performInsertLogic(baseList, insertList, holidayList);
Map<Long, List<PlanSubDetailDO>> collect1 = resultList.stream().collect(Collectors.groupingBy(PlanSubDetailDO::getProjectSubId));
collect1.forEach((id,detailList) -> {
Map<String, List<PlanSubDetailDO>> collect2 = detailList.stream().collect(Collectors.groupingBy(PlanSubDetailDO::getSubType));
collect2.forEach((type,list2) ->{
int i = 1;
for (PlanSubDetailDO planSubDetailDO : list2) {
planSubDetailDO.setSeqNo(Long.valueOf(i++));
}
});
});
// 6. 重新排序和设置序号
resultList.sort(Comparator.comparing(PlanSubDetailDO::getStartTwoDimDate));
// 6. 保存结果
// 7. 保存结果
updateReqVO.setList(resultList);
return CommonResult.success(updateReqVO);
}
@ -1094,8 +1111,7 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
List<PlanSubDetailDO> insertList,
List<LocalDateTime> holidayList) {
List<PlanSubDetailDO> resultList = new ArrayList<>();
// 1. 先处理插活数据保持原始时间范围但designNum排除节假日
// 1. 处理插活数据
List<PlanSubDetailDO> processedInsertList = new ArrayList<>();
for (PlanSubDetailDO insertItem : insertList) {
PlanSubDetailDO processedItem = new PlanSubDetailDO();
@ -1106,7 +1122,7 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
processedItem.setProjectPlanSubId(insertItem.getProjectPlanSubId());
processedItem.setProjectSubCode(insertItem.getProjectSubCode());
processedItem.setTwoDimOwner(insertItem.getTwoDimOwner());
processedItem.setProjectSubId(insertItem.getProjectPlanSubId());
processedItem.setProjectSubId(insertItem.getProjectSubId());
processedItem.setSubType(insertItem.getSubType());
processedItem.setName(insertItem.getName());
processedItem.setCode(insertItem.getCode());
@ -1138,195 +1154,189 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
.max(LocalDateTime::compareTo)
.orElse(null);
// 5. 获取baseList的时间范围
final LocalDateTime baseMinStartTime = baseList.stream()
.map(PlanSubDetailDO::getStartTwoDimDate)
.min(LocalDateTime::compareTo)
.orElse(null);
final LocalDateTime baseMaxEndTime = baseList.stream()
.map(PlanSubDetailDO::getTwoDimDate)
.max(LocalDateTime::compareTo)
.orElse(null);
// 5. 获取baseList第一条数据
PlanSubDetailDO firstBaseItem = baseList.get(0);
// 6. 边界情况处理
if (insertEndTime != null && baseMinStartTime != null && insertEndTime.isBefore(baseMinStartTime)) {
// 情况1插活数据在所有baseList之前
resultList.addAll(processedInsertList);
resultList.addAll(baseList);
return resultList;
}
// 6. 判断属于哪种情况
boolean isCase1 = insertStartTime != null && insertEndTime != null &&
insertStartTime.compareTo(firstBaseItem.getTwoDimDate()) <= 0 &&
insertEndTime.compareTo(firstBaseItem.getStartTwoDimDate()) >= 0 &&
firstBaseItem.getStartTwoDimDate().compareTo(insertStartTime) >= 0;
if (insertStartTime != null && baseMaxEndTime != null && insertStartTime.isAfter(baseMaxEndTime)) {
// 情况2插活数据在所有baseList之后
resultList.addAll(baseList);
resultList.addAll(processedInsertList);
return resultList;
}
boolean isCase2 = insertStartTime != null &&
insertStartTime.compareTo(firstBaseItem.getStartTwoDimDate()) > 0 &&
insertStartTime.compareTo(firstBaseItem.getTwoDimDate()) <= 0;
// 7. 检查是否有插活数据紧挨着某个baseItem的结束时间
PlanSubDetailDO mergedBaseItem = null;
List<PlanSubDetailDO> remainingInsertList = new ArrayList<>();
if (isCase1) {
// 情况1插活开始时间在第一条范围内
// 创建合并的插活项
PlanSubDetailDO mergedInsertItem = new PlanSubDetailDO();
PlanSubDetailDO firstInsert = processedInsertList.get(0);
mergedInsertItem.setId(null);
mergedInsertItem.setProjectPlanId(firstInsert.getProjectPlanId());
mergedInsertItem.setProjectId(firstInsert.getProjectId());
mergedInsertItem.setProjectPlanSubId(firstInsert.getProjectPlanSubId());
mergedInsertItem.setProjectSubCode(firstInsert.getProjectSubCode());
mergedInsertItem.setTwoDimOwner(firstInsert.getTwoDimOwner());
mergedInsertItem.setProjectSubId(firstInsert.getProjectSubId());
mergedInsertItem.setSubType(firstInsert.getSubType());
mergedInsertItem.setName(firstInsert.getName());
mergedInsertItem.setCode(firstInsert.getCode());
mergedInsertItem.setStartTwoDimDate(insertStartTime);
mergedInsertItem.setTwoDimDate(insertEndTime);
mergedInsertItem.setIsCha("Y");
mergedInsertItem.setDesignNum(calculateWorkDaysExcludeHolidays(insertStartTime, insertEndTime, holidayList));
resultList.add(mergedInsertItem);
for (PlanSubDetailDO insertItem : processedInsertList) {
boolean merged = false;
for (PlanSubDetailDO baseItem : baseList) {
LocalDateTime nextDay = baseItem.getTwoDimDate().plusDays(1);
if (insertItem.getStartTwoDimDate().isEqual(nextDay)) {
// 插活数据紧挨着baseItem的结束时间需要合并
mergedBaseItem = new PlanSubDetailDO();
// 复制baseItem的属性
mergedBaseItem.setId(baseItem.getId());
mergedBaseItem.setProjectPlanId(baseItem.getProjectPlanId());
mergedBaseItem.setProjectId(baseItem.getProjectId());
mergedBaseItem.setProjectPlanSubId(baseItem.getProjectPlanSubId());
mergedBaseItem.setProjectSubCode(baseItem.getProjectSubCode());
mergedBaseItem.setTwoDimOwner(baseItem.getTwoDimOwner());
mergedBaseItem.setProjectSubId(baseItem.getProjectSubId());
mergedBaseItem.setSubType(baseItem.getSubType());
mergedBaseItem.setName(baseItem.getName());
mergedBaseItem.setCode(baseItem.getCode());
// 合并时间范围
mergedBaseItem.setStartTwoDimDate(baseItem.getStartTwoDimDate());
mergedBaseItem.setTwoDimDate(insertItem.getTwoDimDate());
// 重新计算designNum排除节假日
mergedBaseItem.setDesignNum(calculateWorkDaysExcludeHolidays(
baseItem.getStartTwoDimDate(),
insertItem.getTwoDimDate(),
holidayList
));
merged = true;
break;
}
// 处理第一条剩余部分
LocalDateTime newStartTime = insertEndTime.plusDays(1);
// 跳过节假日
newStartTime = findNextNonHoliday(newStartTime, holidayList);
// 计算第一条剩余的designNum
Long firstSegmentDesignNum = calculateWorkDaysExcludeHolidays(
firstBaseItem.getStartTwoDimDate(),
insertStartTime.minusDays(1),
holidayList
);
Long remainingDesignNum = firstBaseItem.getDesignNum() - firstSegmentDesignNum;
if (remainingDesignNum > 0) {
LocalDateTime newEndTime = calculateEndDateByWorkDays(newStartTime, remainingDesignNum, holidayList);
PlanSubDetailDO remainingItem = createBaseItem(firstBaseItem, newStartTime, newEndTime);
remainingItem.setDesignNum(remainingDesignNum);
resultList.add(remainingItem);
newStartTime = newEndTime.plusDays(1);
}
if (!merged) {
remainingInsertList.add(insertItem);
}
}
// 8. 如果有合并的情况重新构建baseList
List<PlanSubDetailDO> newBaseList = new ArrayList<>();
if (mergedBaseItem != null) {
// 添加合并后的item
newBaseList.add(mergedBaseItem);
// 添加其他未被合并的baseItem
for (PlanSubDetailDO baseItem : baseList) {
if (!baseItem.getStartTwoDimDate().isEqual(mergedBaseItem.getStartTwoDimDate()) ||
!baseItem.getTwoDimDate().isEqual(mergedBaseItem.getTwoDimDate())) {
newBaseList.add(baseItem);
}
}
// 重新排序
newBaseList.sort(Comparator.comparing(PlanSubDetailDO::getStartTwoDimDate));
} else {
newBaseList.addAll(baseList);
}
// 处理后续baseList项
for (int i = 1; i < baseList.size(); i++) {
PlanSubDetailDO baseItem = baseList.get(i);
// 检查是否有交集使用原始结束时间
boolean hasIntersection = (insertStartTime.compareTo(baseItem.getStartTwoDimDate()) <= 0) &&
(newStartTime.compareTo(baseItem.getStartTwoDimDate()) >=0);
// 9. 正常插活逻辑插活数据与baseList有重叠
// 分离baseList在插活数据之前的被打断的在插活数据之后的
List<PlanSubDetailDO> beforeInsertList = new ArrayList<>();
List<PlanSubDetailDO> interruptedList = new ArrayList<>();
List<PlanSubDetailDO> afterInsertList = new ArrayList<>();
if (insertStartTime != null) {
for (PlanSubDetailDO baseItem : newBaseList) {
if (baseItem.getTwoDimDate().isBefore(insertStartTime)) {
// 完全在插活数据之前
beforeInsertList.add(baseItem);
} else if (baseItem.getStartTwoDimDate().isBefore(insertStartTime) &&
baseItem.getTwoDimDate().isAfter(insertStartTime.minusDays(1))) {
// 被插活数据打断
interruptedList.add(baseItem);
if (hasIntersection) {
// 有交集需要顺延
newStartTime = findNextNonHoliday(newStartTime, holidayList);
LocalDateTime newEndTime = calculateEndDateByWorkDays(newStartTime, baseItem.getDesignNum(), holidayList);
PlanSubDetailDO shiftedItem = createBaseItem(baseItem, newStartTime, newEndTime);
shiftedItem.setDesignNum(baseItem.getDesignNum());
resultList.add(shiftedItem);
newStartTime = newEndTime.plusDays(1);
} else {
// 在插活数据之后
afterInsertList.add(baseItem);
// 没有交集保持原样
resultList.add(baseItem);
}
}
} else if (isCase2) {
// 情况2插活开始时间在第一条开始时间之前
// 第一段从原开始时间到插活开始时间-1
LocalDateTime firstSegmentEnd = findBeforeNonHoliday(insertStartTime.minusDays(1),holidayList);
Long firstSegmentDesignNum = calculateWorkDaysExcludeHolidays(
firstBaseItem.getStartTwoDimDate(),
firstSegmentEnd,
holidayList
);
if (firstSegmentDesignNum > 0) {
PlanSubDetailDO firstSegment = createBaseItem(firstBaseItem, firstBaseItem.getStartTwoDimDate(), firstSegmentEnd);
firstSegment.setDesignNum(firstSegmentDesignNum);
resultList.add(firstSegment);
}
// 添加插活数据
resultList.addAll(processedInsertList);
// 第二段从插活结束时间+1开始
LocalDateTime newStartTime = insertEndTime.plusDays(1);
newStartTime = findNextNonHoliday(newStartTime, holidayList);
Long remainingDesignNum = firstBaseItem.getDesignNum() - firstSegmentDesignNum;
if (remainingDesignNum > 0) {
LocalDateTime newEndTime = calculateEndDateByWorkDays(newStartTime, remainingDesignNum, holidayList);
PlanSubDetailDO secondSegment = createBaseItem(firstBaseItem, newStartTime, newEndTime);
secondSegment.setDesignNum(remainingDesignNum);
resultList.add(secondSegment);
newStartTime = newEndTime.plusDays(1);
}
// 处理后续baseList项
for (int i = 1; i < baseList.size(); i++) {
PlanSubDetailDO baseItem = baseList.get(i);
// 检查当前条的开始时间是否 <= 前一条的结束时间
if (baseItem.getStartTwoDimDate().compareTo(newStartTime.minusDays(1)) <= 0) {
// 需要顺延
newStartTime = findNextNonHoliday(newStartTime, holidayList);
LocalDateTime newEndTime = calculateEndDateByWorkDays(newStartTime, baseItem.getDesignNum(), holidayList);
PlanSubDetailDO shiftedItem = createBaseItem(baseItem, newStartTime, newEndTime);
shiftedItem.setDesignNum(baseItem.getDesignNum());
resultList.add(shiftedItem);
newStartTime = newEndTime.plusDays(1);
} else {
// 不需要顺延保持原样
resultList.add(baseItem);
}
}
} else {
beforeInsertList.addAll(newBaseList);
// 不属于两种情况保持原样
resultList.addAll(baseList);
resultList.addAll(processedInsertList);
}
// 10. 处理插活数据之前的baseList保持原样
resultList.addAll(beforeInsertList);
// 11. 处理被打断的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稍后处理
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.getProjectSubId());
remainingItem.setSubType(interruptedItem.getSubType());
remainingItem.setName(interruptedItem.getName());
remainingItem.setCode(interruptedItem.getCode());
remainingItem.setDesignNum(interruptedItem.getDesignNum()); // 保持原始designNum
remainingBaseList.add(remainingItem);
} else {
// 整个被打断全部加入剩余列表
remainingBaseList.add(interruptedItem);
}
}
// 12. 添加剩余的插活数据未被合并的
resultList.addAll(remainingInsertList);
// 13. 处理剩余的baseList被打断的剩余部分 + 原本在插活数据之后的
List<PlanSubDetailDO> allRemainingList = new ArrayList<>();
allRemainingList.addAll(remainingBaseList);
allRemainingList.addAll(afterInsertList);
if (!allRemainingList.isEmpty()) {
// 获取插活数据的最后结束时间
final LocalDateTime lastInsertEndTime;
if (mergedBaseItem != null) {
lastInsertEndTime = mergedBaseItem.getTwoDimDate();
} else {
lastInsertEndTime = processedInsertList.stream()
.map(PlanSubDetailDO::getTwoDimDate)
.max(LocalDateTime::compareTo)
.orElse(null);
// 7 处理SeqNo逻辑
// 从baseList获取每个ProjectSubId下每种SubType的最小SeqNo
Map<String, Long> minSeqNoMap = new HashMap<>();
if (!baseList.isEmpty()) {
Map<String, Map<String, Long>> tempMap = new HashMap<>();
for (PlanSubDetailDO item : baseList) {
String key = item.getProjectSubId() + "|" + item.getSubType();
tempMap.computeIfAbsent(key, k -> new HashMap<>())
.merge("min", item.getSeqNo(), Math::min);
}
tempMap.forEach((k, v) -> minSeqNoMap.put(k, v.get("min")));
}
// 从插活数据的下一天开始顺延
LocalDateTime baseStartTime = lastInsertEndTime.plusDays(1);
for (PlanSubDetailDO baseItem : allRemainingList) {
// 找到下一个非节假日开始时间
LocalDateTime newStartTime = findNextNonHoliday(baseStartTime, holidayList);
// 根据designNum计算结束日期包含节假日
LocalDateTime newEndTime = calculateEndDateByWorkDays(newStartTime, baseItem.getDesignNum(), holidayList);
PlanSubDetailDO newBaseItem = createBaseItem(baseItem, newStartTime, newEndTime);
newBaseItem.setDesignNum(baseItem.getDesignNum()); // 保持原始designNum
resultList.add(newBaseItem);
// 更新下一个baseItem的开始时间
baseStartTime = newEndTime.plusDays(1);
// 为resultList设置SeqNo
Map<String, List<PlanSubDetailDO>> resultGroupMap = new HashMap<>();
for (PlanSubDetailDO item : resultList) {
String key = item.getProjectSubId() + "|" + item.getSubType();
resultGroupMap.computeIfAbsent(key, k -> new ArrayList<>()).add(item);
}
}
// 14. 按开始时间排序
for (Map.Entry<String, List<PlanSubDetailDO>> entry : resultGroupMap.entrySet()) {
String[] keys = entry.getKey().split("\\|");
String projectSubId = keys[0];
String subType = keys[1];
// 获取对应分组的最小SeqNo
Long baseMinSeq = minSeqNoMap.get(entry.getKey());
if (baseMinSeq == null) {
// 没有base数据时取默认值或根据业务逻辑处理
baseMinSeq = 1L;
}
List<PlanSubDetailDO> sortedList = entry.getValue().stream()
.sorted(Comparator.comparing(PlanSubDetailDO::getStartTwoDimDate))
.collect(Collectors.toList());
// 分配SeqNo
long currentSeq = baseMinSeq;
for (PlanSubDetailDO item : sortedList) {
item.setSeqNo(currentSeq++);
}
}
// 8. 按开始时间排序
resultList.sort(Comparator.comparing(PlanSubDetailDO::getStartTwoDimDate));
return resultList;
}
/**
* 找到下一个非节假日日期
*/
private LocalDateTime findNextNonHoliday(LocalDateTime startDate, List<LocalDateTime> holidayList) {
LocalDateTime current = startDate;
while (holidayList.contains(current)) {
@ -1334,19 +1344,29 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
}
return current;
}
private LocalDateTime findBeforeNonHoliday(LocalDateTime startDate, List<LocalDateTime> holidayList) {
LocalDateTime current = startDate;
while (holidayList.contains(current)) {
current = current.minusDays(1);
}
return current;
}
/**
* 计算排除节假日的工作天数
*/
private Long calculateWorkDaysExcludeHolidays(LocalDateTime startDate, LocalDateTime endDate, List<LocalDateTime> holidayList) {
if (startDate.isAfter(endDate)) {
return 0L;
}
long workDays = 0;
LocalDateTime current = startDate.toLocalDate().atStartOfDay();
LocalDateTime end = endDate.toLocalDate().atStartOfDay();
while (!current.isAfter(end)) {
// 检查是否是节假日
LocalDateTime finalCurrent = current;
boolean isHoliday = holidayList.stream()
.anyMatch(holiday -> holiday.isEqual(finalCurrent));
boolean isHoliday = holidayList.contains(current);
if (!isHoliday) {
workDays++;
@ -1366,9 +1386,7 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
while (countedWorkDays < workDays) {
// 检查是否是节假日
LocalDateTime finalCurrent = current;
boolean isHoliday = holidayList.stream()
.anyMatch(holiday -> holiday.isEqual(finalCurrent));
boolean isHoliday = holidayList.contains(current);
if (!isHoliday) {
countedWorkDays++;
@ -1383,7 +1401,7 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
}
/**
* 创建baseItem对象用于baseList顺延
* 创建baseItem对象
*/
private PlanSubDetailDO createBaseItem(PlanSubDetailDO original, LocalDateTime startDate, LocalDateTime endDate) {
PlanSubDetailDO baseItem = new PlanSubDetailDO();
@ -1394,7 +1412,7 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
baseItem.setProjectPlanSubId(original.getProjectPlanSubId());
baseItem.setProjectSubCode(original.getProjectSubCode());
baseItem.setTwoDimOwner(original.getTwoDimOwner());
baseItem.setProjectSubId(original.getProjectPlanSubId());
baseItem.setProjectSubId(original.getProjectSubId());
baseItem.setSubType(original.getSubType());
baseItem.setName(original.getName());
baseItem.setCode(original.getCode());
@ -1403,18 +1421,6 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
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());
}
@Override

View File

@ -316,7 +316,7 @@
</template>
</el-dialog>
<el-dialog v-model="addDialogVisible" title="新增" width="80%">
<el-dialog :close-on-click-modal="false" v-model="addDialogVisible" title="新增" width="80%">
<!-- 查询条件 -->
<el-form inline class="mb-4">
<el-form-item label="项目编码">
@ -510,6 +510,8 @@ const handleAddCancel = () => {
})
.then(() => {
addDialogVisible.value = false
selectedAddRow.value = []
multipleTableRef.value.clearSelection()
})
.catch(() => {})
}
@ -528,6 +530,7 @@ const handleAddConfirm = () => {
return
}
selectedAddRow.value[0].twoDimDate = null
selectedAddRow.value[0].projectPlanSubId = null
selectedAddRow.value[0].startTwoDimDate = null
selectedAddRow.value[0].twoDimOwner = null
selectedAddRow.value[0].subType = null
@ -539,6 +542,8 @@ const handleAddConfirm = () => {
selectedAddRow.value[0].id = null
list.value.unshift(selectedAddRow.value[0])
addDialogVisible.value = false
selectedAddRow.value = []
multipleTableRef.value.clearSelection()
message.success('项目添加成功')
}
@ -688,8 +693,13 @@ const addItemRow = (row) => {
flag: 1, //
userFlag: true
}
const currentIndex = list.value.findIndex(item=> item === row);
if(currentIndex !== -1){
list.value.splice(currentIndex+1,0,newRow);
}else{
list.value.unshift(newRow)
}
//message.success('')
} else {
@ -766,12 +776,13 @@ const handleConfirm = async () => {
if (res) {
message.success('插活成功')
dialogVisible.value = false
await getList()
}
} catch (error) {
message.error('插活失败:' + error.message)
await getList()
} finally {
loading2.value = false
reload() //
}
dialogVisible.value = false

View File

@ -1460,10 +1460,12 @@ const handleDateChange = async (
const rowData = formData.value.projectPlanSubs[index]
// 使
const errors = []
var deleteBlankNum = false;
var deleteEndNum = false;
// --- ---
if (typeof startBlankDate === 'undefined' || startBlankDate === null || startBlankDate === '') {
errors.push('请选择开始日期,否则无法计算设计天数')
deleteBlankNum = true;
} else {
const starDateStr = new Date(startBlankDate).toLocaleDateString('en-CA')
if (starDateStr < nowDataStr) {
@ -1484,6 +1486,7 @@ const handleDateChange = async (
// --- ---
if (typeof blankDate === 'undefined' || blankDate === null || blankDate === '') {
errors.push('请选择结束日期,否则无法计算设计天数')
deleteEndNum = true;
} else {
const endDateStr = new Date(blankDate).toLocaleDateString('en-CA')
if (endDateStr < nowDataStr) {
@ -1508,12 +1511,13 @@ const handleDateChange = async (
// rowData
if (startBlankDate === null) {
rowData[dataNumField] = null
rowData[startField] = null
}
if (blankDate === null) {
rowData[dataNumField] = null
rowData[endField] = null
}
return // return
}
//
@ -2379,39 +2383,14 @@ const submitForm = async () => {
await PlanApi.updatePlan(data)
await PlanSubApi.operate(formData.value.projectPlanSubs)
// formData.value.projectPlanSubs.forEach((item) => {
// var subData = item as unknown as PlanSubApid.PlanSubVo
// // subData.projectId = item.projectOrderId
// // subData.projectPlanId = formData.value.id
// // subData.projectSubShortName = item.projectSubShortName
// // subData.projectSubCode = item.projectSubCode
// // subData.projectSubId = item.projectSubId
// if (subData.id == undefined) {
// subData.id = 0
// subData.id = PlanSubApi.createPlanSub(subData)
// } else {
// //subData.id = item.planSubId
// PlanSubApi.updatePlanSub(subData)
// }
// //subData.id = subData.projectSubId
// })
// //
// prods.value.projectPlanSubs.forEach((item) => {
// var subData = item as unknown as PlanSubApid.PlanSubVo
// if (subData.id == undefined) {
// subData.id = 0
// subData.id = PlanSubApi.createPlanSub(subData)
// } else {
// //subData.id = item.planSubId
// PlanSubApi.updatePlanSub(subData)
// }
// //subData.id = subData.projectSubId
// })
setTimeout(() => {
reload()
},1000)
console.log()
message.success(t('common.updateSuccess'))
//
// emit('success')
} finally {
reload()
formLoading.value = false
}
}