Commit c1a3588c by 王志超

feat: 变更工单完结时间和超期处理

parent f93efe87
......@@ -58,6 +58,7 @@ import com.netease.mail.yanxuan.change.dal.entity.ChangeFile;
import com.netease.mail.yanxuan.change.dal.entity.ChangeRecord;
import com.netease.mail.yanxuan.change.dal.entity.ChangeSubFlowRecord;
import com.netease.mail.yanxuan.change.dal.entity.ChangeType;
import com.netease.mail.yanxuan.change.dal.mapper.ChangeExecRecordMapper;
import com.netease.mail.yanxuan.change.dal.mapper.ChangeRecordMapper;
import com.netease.mail.yanxuan.change.dal.mapper.ChangeSubFlowRecordMapper;
import com.netease.mail.yanxuan.change.dal.meta.model.po.ChangeCommanderPO;
......@@ -133,6 +134,9 @@ public class ChangeFlowBiz {
private ChangeRecordMapper changeRecordMapper;
@Autowired
private ChangeExecRecordMapper changeExecRecordMapper;
@Autowired
private ChangeSubFlowRecordMapper changeSubFlowRecordMapper;
@Autowired
......@@ -1301,19 +1305,20 @@ public class ChangeFlowBiz {
if (CollectionUtils.isNotEmpty(changeRecords)) {
// 批量查询所有变更行动工单,构建 Map<changeRecordId, List<subFlowId>>,提升性能
final Map<Long, List<String>> subFlowIdsMap;
List<Long> changeRecordIds = changeRecords.stream()
.map(ChangeRecord::getId)
.collect(Collectors.toList());
// 批量查询所有行动工单,构建 Map<changeRecordId, List<ChangeSubFlowRecord>>,用于后续过滤和超期判断
final Map<Long, List<ChangeSubFlowRecord>> subFlowRecordsMap;
List<Long> changeRecordIds = changeRecords.stream().map(ChangeRecord::getId).collect(Collectors.toList());
List<ChangeSubFlowRecord> subFlowRecords = changeSubFlowRecordService.getByChangeRecordIds(changeRecordIds);
if (CollectionUtils.isNotEmpty(subFlowRecords)) {
subFlowIdsMap = subFlowRecords.stream()
.filter(record -> StringUtils.isNotBlank(record.getSubFlowId()))
.collect(Collectors.groupingBy(
ChangeSubFlowRecord::getChangeRecordId,
Collectors.mapping(ChangeSubFlowRecord::getSubFlowId, Collectors.toList())
));
subFlowIdsMap = subFlowRecords.stream().filter(record -> StringUtils.isNotBlank(record.getSubFlowId()))
.collect(Collectors.groupingBy(ChangeSubFlowRecord::getChangeRecordId,
Collectors.mapping(ChangeSubFlowRecord::getSubFlowId, Collectors.toList())));
// 按 changeRecordId 分组,不过滤状态,后续在内部方法中根据业务需求过滤
subFlowRecordsMap = subFlowRecords.stream()
.collect(Collectors.groupingBy(ChangeSubFlowRecord::getChangeRecordId));
} else {
subFlowIdsMap = new HashMap<>();
subFlowRecordsMap = new HashMap<>();
}
list = changeRecords.stream().map(c -> {
ChangeFlowVO changeFlowVO = new ChangeFlowVO();
......@@ -1382,6 +1387,9 @@ public class ChangeFlowBiz {
changeFlowVO.setFlowOwnership(flowOwnership);
}
// 设置变更完结时间和是否超期标识
buildChangeEndTime(c, changeFlowVO, subFlowRecordsMap);
return changeFlowVO;
}).collect(Collectors.toList());
......@@ -2055,4 +2063,133 @@ public class ChangeFlowBiz {
return resetCount;
}
/**
* 构建变更完结时间和是否超期标识
*
* 时间展示逻辑:
* - 未完成的工单:展示预期完成时间(changeConfirmResultTime)
* - 已完成工单(END):展示实际完成时间(updateTime)
* - 取消的工单(CANCEL):展示取消时间(updateTime)
*
* 超期判断逻辑(仅针对非完结/取消的变更单):
* - 变更单的 changeConfirmResultTime 超过两个工作日未处理
* - 或者工单下属的执行项里的 changeExecFinishTime 超过两个工作日未处理(仅判断未完结或未取消的行动工单对应的行动项)
*
* @param changeRecord 变更记录
* @param changeFlowVO 变更工单视图对象
* @param subFlowRecordsMap 所有行动工单Map,key为changeRecordId,value为该主单下所有行动工单列表
*/
private void buildChangeEndTime(ChangeRecord changeRecord, ChangeFlowVO changeFlowVO, Map<Long, List<ChangeSubFlowRecord>> subFlowRecordsMap) {
Integer state = changeRecord.getState();
Long changeConfirmResultTime = changeRecord.getChangeConfirmResultTime();
Long updateTime = changeRecord.getUpdateTime();
if (ChangeStatusEnum.END.getStatus().equals(state)) {
// 已完成工单:展示实际完成时间(updateTime)
changeFlowVO.setChangeEndTime(updateTime);
changeFlowVO.setIsOverdue(false);
} else if (ChangeStatusEnum.CANCEL.getStatus().equals(state)) {
// 取消的工单:展示取消时间(updateTime)
changeFlowVO.setChangeEndTime(updateTime);
changeFlowVO.setIsOverdue(false);
} else {
// 未完成的工单:展示预期完成时间(changeConfirmResultTime)
changeFlowVO.setChangeEndTime(changeConfirmResultTime);
// 超期判断:非完结/取消的变更单,判断是否超过两个工作日未处理
boolean isOverdue = false;
Long currentTime = DateUtils.getCurrentTime();
// 判断变更单的 changeConfirmResultTime 是否超过两个工作日
if (isOverdueByWorkdays(changeConfirmResultTime, currentTime, 2)) {
isOverdue = true;
}
// 判断执行项的 changeExecFinishTime 是否超过两个工作日
// 注意:只判断未完结或未取消的行动工单对应的行动项
if (!isOverdue) {
// 从Map中获取该主单下所有行动工单
List<ChangeSubFlowRecord> allSubFlows = subFlowRecordsMap.getOrDefault(changeRecord.getId(), new ArrayList<>());
// 内部过滤:只保留未完结或未取消的行动工单
List<ChangeSubFlowRecord> activeSubFlows = allSubFlows.stream()
.filter(subFlow -> {
Integer status = subFlow.getStatus();
return status != null
&& !ChangeSubFlowStatusEnum.FINISHED.getStatus().equals(status)
&& !ChangeSubFlowStatusEnum.CANCELLED.getStatus().equals(status);
})
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(activeSubFlows)) {
// 提取未完结或未取消的行动工单的ID
Set<Long> activeSubFlowRecordIds = activeSubFlows.stream()
.map(ChangeSubFlowRecord::getId)
.collect(Collectors.toSet());
// 批量查询这些行动工单对应的行动项
List<ChangeExecRecord> execRecords = changeExecRecordMapper.selectBySubFlowRecordIds(new ArrayList<>(activeSubFlowRecordIds));
if (CollectionUtils.isNotEmpty(execRecords)) {
for (ChangeExecRecord execRecord : execRecords) {
Long changeExecFinishTime = execRecord.getChangeExecFinishTime();
if (changeExecFinishTime != null && isOverdueByWorkdays(changeExecFinishTime, currentTime, 2)) {
isOverdue = true;
break;
}
}
}
}
}
changeFlowVO.setIsOverdue(isOverdue);
}
}
/**
* 判断指定时间是否超过指定工作日数未处理
*
* @param targetTime 目标时间(需要判断的时间)
* @param currentTime 当前时间
* @param workdays 工作日数
* @return true: 超过指定工作日数未处理;false: 未超过
*/
private boolean isOverdueByWorkdays(Long targetTime, Long currentTime, int workdays) {
if (targetTime == null || currentTime == null) {
return false;
}
// 计算目标时间加上指定工作日数后的时间
Long deadlineTime = addWorkdays(targetTime, workdays);
// 如果当前时间超过截止时间,则超期
return currentTime > deadlineTime;
}
/**
* 在指定时间基础上增加指定工作日数(排除周末)
*
* @param time 起始时间
* @param workdays 工作日数
* @return 增加工作日数后的时间
*/
private Long addWorkdays(Long time, int workdays) {
if (time == null || workdays <= 0) {
return time;
}
java.util.Calendar calendar = java.util.Calendar.getInstance();
calendar.setTimeInMillis(time);
int addedDays = 0;
while (addedDays < workdays) {
calendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
int dayOfWeek = calendar.get(java.util.Calendar.DAY_OF_WEEK);
// 排除周六(7)和周日(1)
if (dayOfWeek != java.util.Calendar.SATURDAY && dayOfWeek != java.util.Calendar.SUNDAY) {
addedDays++;
}
}
return calendar.getTimeInMillis();
}
}
......@@ -356,12 +356,37 @@ public class ChangeFlowExportCallback implements DesCallbackService {
ChangeResultEnum resultEnum = ChangeResultEnum.getByValue(record.getChangeResult());
log.debug("[obtainOther] record:{}, resultEnum:{}", JSON.toJSONString(record), resultEnum);
changeFlowExcelDTO.setChangeResult(resultEnum == null ? "/" : resultEnum.getDesc());
if (record.getState().equals(ChangeStatusEnum.CANCEL.getStatus())
|| record.getState().equals(ChangeStatusEnum.END.getStatus())) {
changeFlowExcelDTO.setChangeEndTime(DateUtils.parseLongToString(record.getUpdateTime(), DateUtils.DATE_TIME_FORMAT));
// 时间展示逻辑:
// - 未完成的工单:展示预期完成时间(changeConfirmResultTime)
// - 已完成工单(END):展示实际完成时间(updateTime)
// - 取消的工单(CANCEL):展示取消时间(updateTime)
Integer state = record.getState();
Long changeConfirmResultTime = record.getChangeConfirmResultTime();
Long updateTime = record.getUpdateTime();
if (ChangeStatusEnum.END.getStatus().equals(state)) {
// 已完成工单:展示实际完成时间(updateTime)
if (updateTime != null) {
changeFlowExcelDTO.setChangeEndTime(DateUtils.parseLongToString(updateTime, DateUtils.DATE_TIME_FORMAT));
} else {
changeFlowExcelDTO.setChangeEndTime("/");
}
} else if (ChangeStatusEnum.CANCEL.getStatus().equals(state)) {
// 取消的工单:展示取消时间(updateTime)
if (updateTime != null) {
changeFlowExcelDTO.setChangeEndTime(DateUtils.parseLongToString(updateTime, DateUtils.DATE_TIME_FORMAT));
} else {
changeFlowExcelDTO.setChangeEndTime("/");
}
} else {
// 未完成的工单:展示预期完成时间(changeConfirmResultTime)
if (changeConfirmResultTime != null) {
changeFlowExcelDTO.setChangeEndTime(DateUtils.parseLongToString(changeConfirmResultTime, DateUtils.DATE_TIME_FORMAT));
} else {
changeFlowExcelDTO.setChangeEndTime("/");
}
}
}
private void buildGoodsPrincipal(ChangeGoodsPrincipalPO changeGoodsPrincipalPO, ChangeFlowExcelDTO changeFlowExcelDTO) {
......
......@@ -162,11 +162,26 @@ public class ChangeFlowVO {
private Long createTime;
/**
* 变更结果确认时间
* 变更结果确认时间(预期完成时间)
*/
private Long changeConfirmResultTime;
/**
* 变更完结时间(实际完成时间/取消时间)
* 未完成的工单:展示预期完成时间(changeConfirmResultTime)
* 已完成工单:展示实际完成时间(updateTime)
* 取消的工单:展示取消时间(updateTime)
*/
private Long changeEndTime;
/**
* 是否超出预计完成时间(用于前端标红展示)
* true: 已完成工单的实际完成时间超出预期完成时间
* false: 其他情况
*/
private Boolean isOverdue;
/**
* 取消原因
*/
private String cancelReason;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment