Commit 22db7b12 by 刘鑫

Merge branch 'develop-16542' into 'develop'

容量

See merge request !363
2 parents 6e1de546 7edb439f
......@@ -87,6 +87,11 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-55</artifactId>
<version>2.21.1</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
......@@ -136,6 +141,33 @@
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
......
......@@ -19,14 +19,15 @@ import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalLong;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
......@@ -101,23 +102,29 @@ public class CapacityUtils {
}
public static Long getMaxRemainBlock(LocalDateTime startTime, LocalDateTime endTime, List<OccupyInfo> occupyInfos) {
if (org.springframework.util.CollectionUtils.isEmpty(occupyInfos)) {
return Duration.between(startTime, endTime).toMinutes();
public static List<OccupyInfoDetail> getMaxRemainBlock(LocalDateTime startTime, LocalDateTime endTime, List<OccupyInfo> occupyInfos) {
//存储空闲时间段
List<OccupyInfoDetail> leisureTime = new ArrayList<>();
if (CollectionUtils.isEmpty(occupyInfos)) {
long minutes = Duration.between(startTime, endTime).abs().toMinutes();
OccupyInfoDetail occupyInfo = new OccupyInfoDetail(startTime, endTime, minutes);
leisureTime.add(occupyInfo);
return leisureTime;
}
//空闲时间
List<Long> idlePeriods = new ArrayList<>();
LocalDateTime preLast = startTime;
for (OccupyInfo o : occupyInfos) {
if (o.getBeginTime().isAfter(preLast)) {
idlePeriods.add(Duration.between(startTime, o.getBeginTime()).abs().toMinutes());
long duraionMiu = Duration.between(startTime, o.getBeginTime()).abs().toMinutes();
leisureTime.add(new OccupyInfoDetail(startTime, o.getBeginTime(), duraionMiu));
}
preLast = o.getEndTime();
}
if (preLast.isBefore(endTime)) {
idlePeriods.add(Duration.between(preLast, endTime).abs().toMinutes());
long duraionMiu = Duration.between(preLast, endTime).abs().toMinutes();
leisureTime.add(new OccupyInfoDetail(preLast, endTime, duraionMiu));
}
return org.springframework.util.CollectionUtils.isEmpty(idlePeriods) ? Duration.between(startTime, endTime).abs().toMinutes() : Collections.max(idlePeriods);
return leisureTime;
}
......@@ -144,6 +151,59 @@ public class CapacityUtils {
}
}
// 定义一个方法,接受一个OccupyInfoDetail列表,返回它们的交集列表
public static List<OccupyInfoDetail> intersect(List<OccupyInfoDetail> timeSlots) {
// 如果列表为空或只有一个元素,直接返回原列表
if (timeSlots == null || timeSlots.size() <= 1) {
return timeSlots;
}
// 否则,使用Stream API进行处理
return timeSlots.stream()
// 对列表中的每个元素进行两两组合,得到一个二元组列表
.flatMap(a -> timeSlots.stream().map(b -> new AbstractMap.SimpleEntry<>(a, b)))
// 过滤掉自身和重复的组合,即保证a不等于b且a在b之前
.filter(entry -> !entry.getKey().equals(entry.getValue()) && timeSlots.indexOf(entry.getKey()) < timeSlots.indexOf(entry.getValue()))
// 对每个组合计算交集,并过滤掉null值
.map(entry -> entry.getKey().intersection(entry.getValue())).filter(Objects::nonNull)
// 去除重复的交集,并收集到一个列表中
.distinct().collect(Collectors.toList());
}
/**
* 定义一个方法,接受一个OccupyInfoDetail列表,返回它们的并集列表
* 1. 将所有时间片按照开始时间从小到大排序。
* 2. 创建一个空的结果列表,用于存放合并后的时间片。
* 3. 遍历排序后的时间片列表,对于每一个时间片,执行以下操作:
* - 如果结果列表为空,或者当前时间片的开始时间大于结果列表中最后一个时间片的结束时间,说明当前时间片与结果列表中的任何一个时间片都不重叠,直接将当前时间片加入结果列表。
* - 否则,说明当前时间片与结果列表中最后一个时间片有重叠部分,将当前时间片与结果列表中最后一个时间片合并成一个新的时间片,更新结果列表中最后一个时间片为新的时间片。合并的方法是取两个时间片开始时间的较小值作为新的开始时间,取两个时间片结束时间的较大值作为新的结束时间。
* 4. 返回结果列表作为最终的并集计算结果。
*/
public static List<OccupyInfoDetail> calculateUnion(List<OccupyInfoDetail> timeSlots) {
return timeSlots.stream()
.distinct()
.sorted()
.reduce(new ArrayList<OccupyInfoDetail>(), (result, current) -> {
if (result.isEmpty()) {
result.add(current);
} else {
OccupyInfoDetail last = result.get(result.size() - 1);
if (last.getEndTime().compareTo(current.getBeginTime()) >= 0) {
result.set(result.size() - 1,
new OccupyInfoDetail(last.getBeginTime(),
last.getEndTime().compareTo(current.getEndTime()) > 0 ?
last.getEndTime() : current.getEndTime()));
} else {
result.add(current);
}
}
return result;
}, (a, b) -> a)
.stream()
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
}
public static CapacityQueryDTO.Segment caculateTargetTimeSlice(int totalTakeTime, String timeSliceName,
List<CapacityEngineerSliceUsedEntity> engineerTimeSlice,
LocalTime targetStartTime,
......@@ -153,20 +213,29 @@ public class CapacityUtils {
TimeSliceEntity timeSlice = t.getTimmeSlice();
LocalTime sliceStartHour = LocalTime.parse(timeSlice.getStart(), DateUtil.TIME_FORMATTER);
LocalTime sliceEndHour = LocalTime.parse(timeSlice.getEnd(), DateUtil.TIME_FORMATTER);
return (targetStartTime.isAfter(sliceStartHour) && targetEndTime.isBefore(sliceEndHour)) ||
(targetStartTime.equals(sliceStartHour) || targetEndTime.equals(sliceEndHour));
return !(targetStartTime.isAfter(sliceEndHour) || targetEndTime.isBefore(sliceStartHour));
}).collect(Collectors.toList());
CapacityQueryDTO.Segment segment = new CapacityQueryDTO.Segment();
segment.setName(timeSliceName);
segment.setEndTime(DateUtil.toDate(LocalDateTime.of(targetDate, targetEndTime)));
segment.setBeginTime(DateUtil.toDate(LocalDateTime.of(targetDate, targetStartTime)));
if (!org.apache.commons.collections4.CollectionUtils.isEmpty(collect)) {
OptionalLong optionalLong = collect.stream().mapToLong(t -> {
Long maxDuration = t.getMaxDuration();
return Objects.isNull(maxDuration) ? 0L : maxDuration;
}).max();
long maxDuration = optionalLong.isEmpty() ? 0 : optionalLong.getAsLong();
if (!CollectionUtils.isEmpty(collect)) {
//时间区间范围空闲时间段
//按人分组
Map<String, List<CapacityEngineerSliceUsedEntity>> engineerSliceMap = collect.stream()
.collect(Collectors.groupingBy(CapacityEngineerSliceUsedEntity::getEngineerCode));
//计算最大空闲时间
List<Long> engineerMaxDurationList = new ArrayList<>();
engineerSliceMap.forEach((engineerCode, t) -> {
long engineerMaxDuration = t.stream().map(CapacityEngineerSliceUsedEntity::getDurationTime)
.flatMap(Collection::stream)
.mapToLong(OccupyInfoDetail::getDuration)
.sum();
engineerMaxDurationList.add(engineerMaxDuration);
});
long maxDuration = Collections.max(engineerMaxDurationList);
segment.setMaxDuration(maxDuration);
long remain = collect.stream().mapToLong(CapacityEngineerSliceUsedEntity::getCapLeft).sum();
segment.setRemain(remain);
......
......@@ -12,6 +12,6 @@ import java.time.LocalDateTime;
@AllArgsConstructor
@NoArgsConstructor
public class OccupyInfo {
private LocalDateTime beginTime;
private LocalDateTime endTime;
protected LocalDateTime beginTime;
protected LocalDateTime endTime;
}
package com.dituhui.pea.order.common;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@NoArgsConstructor
public class OccupyInfoDetail extends OccupyInfo implements Comparable<OccupyInfoDetail> {
/**
* 时间片时长(分钟)
*/
private long duration;
public OccupyInfoDetail(LocalDateTime beginTime, LocalDateTime endTime, long duration) {
super(beginTime, endTime);
this.duration = duration;
}
public OccupyInfoDetail(LocalDateTime beginTime, LocalDateTime endTime) {
super(beginTime, endTime);
}
// 判断两个时间片是否有交集
public boolean overlaps(OccupyInfoDetail other) {
// 如果一个时间片的开始时间在另一个时间片的结束时间之后,或者一个时间片的结束时间在另一个时间片的开始时间之前,那么他们没有交集
return !(this.beginTime.isAfter(other.endTime) || this.endTime.isBefore(other.beginTime));
}
// 计算两个时间片的交集
public OccupyInfoDetail intersection(OccupyInfoDetail other) {
// 如果两个时间片没有交集,返回null
if (!this.overlaps(other)) {
return null;
}
// 否则,返回一个新的时间片,其开始时间是两个时间片中较晚的开始时间,其结束时间是两个时间片中较早的结束时间
return new OccupyInfoDetail(this.beginTime.isAfter(other.beginTime) ? this.beginTime : other.beginTime, this.endTime.isBefore(other.endTime) ? this.endTime : other.endTime);
}
@Override
public int compareTo(OccupyInfoDetail o) {
return this.beginTime.compareTo(o.beginTime);
}
}
package com.dituhui.pea.order.controller;
import com.dituhui.pea.common.BusinessException;
import com.dituhui.pea.common.Result;
import com.dituhui.pea.enums.StatusCodeEnum;
import com.dituhui.pea.order.common.jackson.DateUtil;
......@@ -47,6 +48,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.stream.Collectors;
......@@ -124,8 +126,17 @@ public class PeaApiController {
List<CapacityQueryDTO.Service> convertService = services.stream()
.map(source -> {
TypeCodeCheckTableEntity brand = tableCodeCheckDao.findByTypeAndCode("BRAND", source.getBrand());
if (Objects.isNull(brand)) {
throw new BusinessException("查询不到:"+ source.getBrand() + "对应的品牌");
}
TypeCodeCheckTableEntity type = tableCodeCheckDao.findByTypeAndCode("TYPE", source.getProductType());
if (Objects.isNull(type)) {
throw new BusinessException("查询不到:"+ source.getProductType() + "对应的产品类型");
}
TypeCodeCheckTableEntity skill = tableCodeCheckDao.findByTypeAndCode("SKILL", source.getServiceType());
if (Objects.isNull(skill)) {
throw new BusinessException("查询不到:"+ source.getServiceType() + "对应的技能");
}
CapacityQueryDTO.Service service = new CapacityQueryDTO.Service();
service.setBrand(fixBrand(brand.getName()));
......
......@@ -11,12 +11,12 @@ public class BaseLocation {
/**
* 地址纬度
*/
@NotNull
@NotNull(message = "地址纬度必填")
private Double latitude;
/**
* 地址经度
*/
@NotNull
@NotNull(message = "地址经度必填")
private Double longitude;
}
......@@ -36,20 +36,20 @@ public class CapacityQueryDTO {
* 地址坐标信息
*/
@Valid
@NotNull
@NotNull(message = "地址坐标信息不能为空")
private Location location;
/**
* 查询起始日期
*/
@NotNull
@NotNull(message = " 查询起始日期不能为空, 格式:yyyy-MM-dd ")
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date beginDate;
/**
* 查询结束日期
*/
@NotNull
@NotNull(message = " 查询结束日期不能为空, 格式:yyyy-MM-dd ")
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date endDate;
......@@ -138,7 +138,7 @@ public class CapacityQueryDTO {
private long maxDuration;
/**
* 容量名称 全天/上午/下午/时间段
* 容量名称 全天/上午/下午/晚上/时间段
*/
private String name;
......@@ -177,18 +177,18 @@ public class CapacityQueryDTO {
/**
* 品牌 (CODE)
*/
@NotBlank
@NotBlank(message = "品牌(code)不能为空")
private String brand;
/**
* 产品类型 (CODE)
*/
@NotBlank
@NotBlank(message = "产品类型(code)不能为空")
private String productType;
/**
* 需要的技能 (CODE)
*/
@NotBlank
@NotBlank(message = "技能(code)不能为空")
private String serviceType;
}
}
......@@ -16,6 +16,6 @@ public class EngineerCode {
/**
* 工程师工号
*/
@NotBlank
@NotBlank(message = "工程师工号不能为空")
protected String engineerCode;
}
......@@ -14,7 +14,7 @@ public class EngineerOrderParam {
/**
* 工程师工号
*/
@NotBlank
@NotBlank(message = "工程师工号不能为空")
private String engineerCode;
......
package com.dituhui.pea.order.entity;
import com.dituhui.pea.order.common.OccupyInfoDetail;
import com.vladmihalcea.hibernate.type.json.JsonStringType;
import lombok.Getter;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
......@@ -9,17 +13,18 @@ import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
@Getter
@Entity
@Table(name = "capacity_engineer_slice_used")
@TypeDef(name = "json", typeClass = JsonStringType.class)
public class CapacityEngineerSliceUsedEntity {
@Id
@Column(name = "id")
......@@ -51,11 +56,13 @@ public class CapacityEngineerSliceUsedEntity {
@Column(name = "cap_left")
private Long capLeft;
@Basic
@Column(name = "order_count")
private Long orderCount;
@Basic
@Column(name = "max_duration")
private Long maxDuration;
@Type(type = "json")
@Column(name = "duration_time", columnDefinition = "json")
private List<OccupyInfoDetail> durationTime;
@Basic
@Column(name = "max_duration_type")
private String maxDurationType;
......@@ -101,14 +108,15 @@ public class CapacityEngineerSliceUsedEntity {
this.capLeft = capLeft;
}
public void setOrderCount(Long orderCount) {
this.orderCount = orderCount;
}
public void setMaxDuration(Long maxDuration) {
this.maxDuration = maxDuration;
}
public void setDurationTime(List<OccupyInfoDetail> durationTime) {
this.durationTime = durationTime;
}
public void setMaxDurationType(String maxDurationType) {
this.maxDurationType = maxDurationType;
}
......@@ -130,11 +138,11 @@ public class CapacityEngineerSliceUsedEntity {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CapacityEngineerSliceUsedEntity that = (CapacityEngineerSliceUsedEntity) o;
return id == that.id && timmeSlice == that.timmeSlice && Objects.equals(workday, that.workday) && Objects.equals(engineerCode, that.engineerCode) && Objects.equals(capTotal, that.capTotal) && Objects.equals(capUsed, that.capUsed) && Objects.equals(capUsedTravel, that.capUsedTravel) && Objects.equals(capLeft, that.capLeft) && Objects.equals(orderCount, that.orderCount) && Objects.equals(maxDuration, that.maxDuration) && Objects.equals(maxDurationType, that.maxDurationType) && Objects.equals(memo, that.memo) && Objects.equals(createTime, that.createTime) && Objects.equals(updateTime, that.updateTime);
return Objects.equals(id, that.id) && Objects.equals(timmeSlice, that.timmeSlice) && Objects.equals(workday, that.workday) && Objects.equals(engineerCode, that.engineerCode) && Objects.equals(capTotal, that.capTotal) && Objects.equals(capUsed, that.capUsed) && Objects.equals(capUsedTravel, that.capUsedTravel) && Objects.equals(capLeft, that.capLeft) && Objects.equals(maxDuration, that.maxDuration) && Objects.equals(durationTime, that.durationTime) && Objects.equals(maxDurationType, that.maxDurationType) && Objects.equals(memo, that.memo) && Objects.equals(createTime, that.createTime) && Objects.equals(updateTime, that.updateTime);
}
@Override
public int hashCode() {
return Objects.hash(id, timmeSlice, workday, engineerCode, capTotal, capUsed, capUsedTravel, capLeft, orderCount, maxDuration, maxDurationType, memo, createTime, updateTime);
return Objects.hash(id, timmeSlice, workday, engineerCode, capTotal, capUsed, capUsedTravel, capLeft, maxDuration, durationTime, maxDurationType, memo, createTime, updateTime);
}
}
......@@ -3,6 +3,7 @@ package com.dituhui.pea.order.scheduler;
import com.dituhui.pea.order.common.CapacityUtils;
import com.dituhui.pea.order.common.DateUtils;
import com.dituhui.pea.order.common.OccupyInfo;
import com.dituhui.pea.order.common.OccupyInfoDetail;
import com.dituhui.pea.order.common.jackson.DateTimeUtil;
import com.dituhui.pea.order.common.jackson.DateUtil;
import com.dituhui.pea.order.dao.CapacityEngineerCalendarDao;
......@@ -140,11 +141,14 @@ public class CalcEngineerCapacityScheduler {
//已用容量
long totalUseTime = occupyInfo.stream().mapToLong(t -> Duration.between(t.getEndTime(), t.getBeginTime()).abs().toMinutes()).sum();
//最大连续时长
Long maxRemainBlock = CapacityUtils.getMaxRemainBlock(startTime, endTime, occupyInfo);
List<OccupyInfoDetail> durationTime = CapacityUtils.getMaxRemainBlock(startTime, endTime, occupyInfo);
long maxRemainBlock = durationTime.stream().mapToLong(OccupyInfoDetail::getDuration).max().orElse(Duration.between(startTime, endTime).abs().toMinutes());
//剩余连续时间段
sliceCap.setDurationTime(durationTime);
sliceCap.setCapLeft(sliceCap.getCapTotal() - totalUseTime);
sliceCap.setCapUsed(totalUseTime);
sliceCap.setOrderCount((long) orders.size());
//计算时 存储时间差级(剩余时间段)
sliceCap.setMaxDuration(maxRemainBlock);
sliceCap.setUpdateTime(LocalDateTime.now(ZoneId.of("+8")));
}
......
package com.dituhui.pea.order.service.impl;
import com.dituhui.pea.common.BusinessException;
import com.dituhui.pea.common.Result;
import com.dituhui.pea.enums.StatusCodeEnum;
import com.dituhui.pea.order.common.CapacityUtils;
......@@ -135,6 +136,10 @@ public class CapacityQueryServiceImpl implements CapacityQueryService {
allFulfillEngineer.addAll(engineerInfoEntities);
}
log.info("[matchCapacityData]【符合技能要求的工程师总数为:{} 个】", allFulfillEngineer.size());
if (CollectionUtils.isEmpty(querySkillGroup)) {
throw new BusinessException("查询不到对应的技能组信息");
}
//计算所有查询技能的所需耗时 (querySkillGroup)
final int totalTakeTime = querySkillGroup.stream()
.mapToInt(SkillInfoEntity::getTakeTime)
......@@ -194,6 +199,14 @@ public class CapacityQueryServiceImpl implements CapacityQueryService {
//查询对应的技能信息
SkillInfoEntity skillInfo = skillInfoDao.getByBrandAndTypeAndSkill(service.getBrand(),
service.getProductType(), service.getServiceType());
// 查询不到技能组 直接返不可用
if (Objects.isNull(skillInfo)) {
CapacityQueryDTO.Segment segment = new CapacityQueryDTO.Segment();
segment.setMaxDuration(0);
segment.setRemain(0);
segment.setStatus(0);
return segment;
}
List<CapacityEngineerSliceUsedEntity> allEngineerTimeSlice = new CopyOnWriteArrayList<>();
for (EngineerInfoEntity engineerInfo : engineerInfoEntities) {
......@@ -236,7 +249,14 @@ public class CapacityQueryServiceImpl implements CapacityQueryService {
//查询对应的技能信息
SkillInfoEntity skillInfo = skillInfoDao.getByBrandAndTypeAndSkill(service.getBrand(),
service.getProductType(), service.getServiceType());
// 查询不到技能组 直接返不可用
if (Objects.isNull(skillInfo)) {
CapacityQueryDTO.Segment segment = new CapacityQueryDTO.Segment();
segment.setMaxDuration(0);
segment.setRemain(0);
segment.setStatus(0);
return segment;
}
return CapacityUtils.caculateTargetTimeSlice(skillInfo.getTakeTime(), "时间段",
new CopyOnWriteArrayList<>(engineerTimeSlice), startTime, endTime, date);
}
......@@ -353,23 +373,23 @@ public class CapacityQueryServiceImpl implements CapacityQueryService {
.findByWorkdayAndEngineerCode(DateTimeUtil.formatDate(currentDate), engineerInfo.getEngineerCode());
allEngineerTimeSlice.addAll(engineerTimeSlice);
}
//计算所有工程师半天类型容量
List<CapacityQueryDTO.Segment> objects = new ArrayList<>();
if (CollectionUtils.isNotEmpty(halfDayTypeTimeSlice)) {
List<CapacityQueryDTO.Segment> engineerHalfDay = CapacityUtils.getEngineerTypeDay(halfDayTypeTimeSlice,
allEngineerTimeSlice, currentDate, totalTakeTime);
objects.addAll(engineerHalfDay);
}
//计算所有工程师全天天类型容量
if (CollectionUtils.isNotEmpty(allDayTypeTimeSlice)) {
List<CapacityQueryDTO.Segment> engineerAllDay = CapacityUtils.getEngineerTypeDay(allDayTypeTimeSlice,
allEngineerTimeSlice, currentDate, totalTakeTime);
objects.addAll(engineerAllDay);
}
//计算所有工程师半天类型容量
if (CollectionUtils.isNotEmpty(halfDayTypeTimeSlice)) {
List<CapacityQueryDTO.Segment> engineerHalfDay = CapacityUtils.getEngineerTypeDay(halfDayTypeTimeSlice,
allEngineerTimeSlice, currentDate, totalTakeTime);
objects.addAll(engineerHalfDay);
}
//计算所有工程师时间段类型容量
/*List<CapacityQueryDTO.Segment> timeSliceTwoHour = CapacityUtils.getEngineerTypeDay(timeSliceEntities,
allEngineerTimeSlice, currentDate, totalTakeTime);*/
/*objects.addAll(timeSliceTwoHour);*/
List<CapacityQueryDTO.Segment> timeSliceTwoHour = CapacityUtils.getEngineerTypeDay(timeSliceEntities,
allEngineerTimeSlice, currentDate, totalTakeTime);
objects.addAll(timeSliceTwoHour);
CapacityQueryDTO.Data data = new CapacityQueryDTO.Data();
data.setDate(DateUtil.toDate(currentDate));
data.setSegments(objects);
......
package com.dituhui.pea.order.common;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
@ExtendWith(MockitoExtension.class)
public class CapacityUtilsTest {
@Test
public void testMaxRemainBlock() {
LocalDateTime sliceStart = LocalDateTime.of(LocalDate.now(), LocalTime.of(8, 0));
LocalDateTime sliceEnd = LocalDateTime.of(LocalDate.now(), LocalTime.of(9, 0));
OccupyInfo occupyInfo = new OccupyInfo()
.setBeginTime(LocalDateTime.of(LocalDate.now(), LocalTime.of(8, 0)))
.setEndTime(LocalDateTime.of(LocalDate.now(), LocalTime.of(8, 25)));
ArrayList<OccupyInfo> occupyInfos = new ArrayList<>();
occupyInfos.add(occupyInfo);
List<OccupyInfoDetail> remainBlock = CapacityUtils.getMaxRemainBlock(sliceStart, sliceEnd, occupyInfos);
Assertions.assertEquals(35, remainBlock.stream().mapToLong(OccupyInfoDetail::getDuration).max().orElse(Duration.between(sliceStart, sliceEnd).abs().toMinutes()));
occupyInfos.clear();
occupyInfos.add(new OccupyInfo()
.setBeginTime(LocalDateTime.of(LocalDate.now(), LocalTime.of(8, 10)))
.setEndTime(LocalDateTime.of(LocalDate.now(), LocalTime.of(8, 25))));
remainBlock = CapacityUtils.getMaxRemainBlock(sliceStart, sliceEnd, occupyInfos);
Assertions.assertEquals(35, remainBlock.stream().mapToLong(OccupyInfoDetail::getDuration).max().orElse(Duration.between(sliceStart, sliceEnd).abs().toMinutes()));
occupyInfos.clear();
occupyInfos.add(new OccupyInfo()
.setBeginTime(LocalDateTime.of(LocalDate.now(), LocalTime.of(8, 20)))
.setEndTime(LocalDateTime.of(LocalDate.now(), LocalTime.of(8, 40))));
remainBlock = CapacityUtils.getMaxRemainBlock(sliceStart, sliceEnd, occupyInfos);
Assertions.assertEquals(20, remainBlock.stream().mapToLong(OccupyInfoDetail::getDuration).max().orElse(Duration.between(sliceStart, sliceEnd).abs().toMinutes()));
}
@Test
public void calculateUnionTest() {
//三个时间片[9:00, 10:00],[9:30, 11:00]和[10:30, 12:00],那么它们的并集计算结果是[9:00, 12:00]
List<OccupyInfoDetail> occupyInfoDetails = new ArrayList<>();
occupyInfoDetails.add(
new OccupyInfoDetail(LocalDateTime.of(LocalDate.now(), LocalTime.of(9, 0)
), LocalDateTime.of(LocalDate.now(), LocalTime.of(10, 0))));
occupyInfoDetails.add(
new OccupyInfoDetail(LocalDateTime.of(LocalDate.now(), LocalTime.of(9, 30)
), LocalDateTime.of(LocalDate.now(), LocalTime.of(11, 0))));
occupyInfoDetails.add(
new OccupyInfoDetail(LocalDateTime.of(LocalDate.now(), LocalTime.of(10, 30)
), LocalDateTime.of(LocalDate.now(), LocalTime.of(12, 0))));
List<OccupyInfoDetail> occupyInfoDetails1 = CapacityUtils.calculateUnion(occupyInfoDetails);
Assertions.assertEquals(1, occupyInfoDetails1.size());
OccupyInfoDetail unionOccupyInfo = occupyInfoDetails1.get(0);
Assertions.assertEquals(LocalDateTime.of(LocalDate.now(), LocalTime.of(12, 0)), unionOccupyInfo.getEndTime());
Assertions.assertEquals(LocalDateTime.of(LocalDate.now(), LocalTime.of(9, 0)), unionOccupyInfo.getBeginTime());
occupyInfoDetails.clear();
occupyInfoDetails.add(
new OccupyInfoDetail(LocalDateTime.of(LocalDate.now(), LocalTime.of(9, 0)
), LocalDateTime.of(LocalDate.now(), LocalTime.of(10, 0))));
occupyInfoDetails.add(
new OccupyInfoDetail(LocalDateTime.of(LocalDate.now(), LocalTime.of(9, 30)
), LocalDateTime.of(LocalDate.now(), LocalTime.of(11, 0))));
occupyInfoDetails.add(
new OccupyInfoDetail(LocalDateTime.of(LocalDate.now(), LocalTime.of(11, 30)
), LocalDateTime.of(LocalDate.now(), LocalTime.of(12, 0))));
occupyInfoDetails1 = CapacityUtils.calculateUnion(occupyInfoDetails);
Assertions.assertEquals(2, occupyInfoDetails1.size());
}
}
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!