Commit f1b13ca2 by 刘鑫

feat(工程师工作时间窗) :时间窗格式:[[起始时间段1, 结束时间段1],[起始时间段2, 结束时间段2]] <br/> 时间格式: 从0点开始的分钟数, 如8:00AM 为480

1 parent ea051d6f
......@@ -179,6 +179,31 @@ public class CapacityUtils {
.distinct().collect(Collectors.toList());
}
public static List<OccupyInfoDetail> intervalTime(LocalDateTime startTime, LocalDateTime endTime, List<OccupyInfoDetail> timeUnitList) {
timeUnitList = calculateUnion(timeUnitList);
timeUnitList.sort(Comparator.comparing(OccupyInfo::getBeginTime));
int uniSize = 0;
LocalDateTime currentStart = startTime;
ArrayList<OccupyInfoDetail> result = new ArrayList<>();
while (uniSize < timeUnitList.size()) {
OccupyInfoDetail timeUnit = timeUnitList.get(uniSize);
//当前开始时间 < 时间片开始, 空闲时间为 当前开始时间, 时间片开始时间
if (currentStart.isBefore(timeUnit.getBeginTime())) {
OccupyInfoDetail resultUnit = new OccupyInfoDetail(currentStart, timeUnit.getBeginTime());
result.add(resultUnit);
}
currentStart = timeUnit.getEndTime();
if (uniSize + 1 == timeUnitList.size() && currentStart.isBefore(endTime)) {
OccupyInfoDetail resultUnit = new OccupyInfoDetail(currentStart, endTime);
result.add(resultUnit);
}
uniSize += 1;
}
return result;
}
/**
* 定义一个方法,接受一个OccupyInfoDetail列表,返回它们的并集列表
* 1. 将所有时间片按照开始时间从小到大排序。
......
package com.dituhui.pea.order.controller;
import com.dituhui.pea.common.Result;
import com.dituhui.pea.order.dto.param.CapacityQueryDTO;
import com.dituhui.pea.order.service.impl.BeanRemoteServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
import java.time.LocalTime;
//TODO 仅用于联通测试
@RestController
......@@ -16,7 +23,7 @@ import org.springframework.web.bind.annotation.RestController;
@Slf4j
public class TestController {
private final BeanRemoteServiceImpl beanRemoteServiceImpl;
private final com.dituhui.pea.order.service.CapacityQueryService CapacityQueryService;
@GetMapping("/test")
public Result<?> test() {
......@@ -29,4 +36,18 @@ public class TestController {
return beanRemoteServiceImpl.serviceOrgList();
}
@PostMapping("/capacity/test")
public Result<?> capacityQuery1() {
CapacityQueryDTO.Service service = new CapacityQueryDTO.Service();
service.setBrand("博世/西门子以及其他品牌");
service.setProductType("洗碗机");
service.setServiceType("标准维修");
CapacityQueryDTO.Segment segment = CapacityQueryService.queryCapacityByTeam("1689896351243501568", service,
LocalDate.now(), LocalTime.of(15, 0),
LocalTime.of(16, 0));
return Result.success(segment);
}
}
......@@ -60,4 +60,15 @@ public interface EngineerCalendarService {
* @return 工作队内日期工作时间信息
*/
boolean engineerTeamDateWorkTime(String teamId, String engineerCode, LocalDate targetDate);
/**
* 获取工程师的工作时间窗
*
* @param engineerCode 工程师编号
* @param teamId 工程师所属工作队 (解决一个工程师属多个多工作对情况)
* @param targetDate 目标日期
* @return 时间窗格式
* @apiNote 时间窗格式:[[起始时间段1, 结束时间段1],[起始时间段2, 结束时间段2]] <br/> 时间格式: 从0点开始的分钟数, 如8:00AM 为480
*/
int[][] timeWindows(String engineerCode, String teamId, LocalDate targetDate);
}
......@@ -611,6 +611,57 @@ public class EngineerCalendarServiceImpl implements EngineerCalendarService {
return workDay.contains(String.valueOf(dayOfWeek));
}
@Override
public int[][] timeWindows(String engineerCode, String teamId, LocalDate targetDate) {
EngineerInfoEntity engineerInfoEntity = engineerInfoDao.selectEngineerByEngineerCodeAndTeamId(engineerCode, teamId);
if (Objects.isNull(engineerInfoEntity)) {
return new int[0][];
}
OrgTeamEntity e = orgTeamDao.getByTeamId(teamId);
List<String> workDay = List.of(e.getWorkdays().split(","));
final int dayOfWeek = targetDate.getDayOfWeek().getValue();
if (!workDay.contains(String.valueOf(dayOfWeek))) {
return new int[0][];
}
//是工作日, 取当前天的日历事件
EngineerBusinessEntity businessEntity = engineerBusinessDao.getByEngineerCode(engineerCode);
LocalDateTime workStartTime = DateUtils.localDateTimeFromStr(String.format("%s %s:00", targetDate, businessEntity.getWorkOn()));
LocalDateTime workEndTime = DateUtils.localDateTimeFromStr(String.format("%s %s:00", targetDate, businessEntity.getWorkOff()));
final LocalDateTime minDate = LocalDateTime.MIN;
List<OccupyInfoDetail> configs = getEngineerWorkDayCalendar(engineerCode, targetDate);
if (CollectionUtils.isEmpty(configs)) {
return new int[][]{{(int) Duration.between(workStartTime, minDate).abs().toMinutes(), (int) Duration.between(workEndTime, minDate).abs().toMinutes()}};
}
// 多个休息时间不存在交集
List<OccupyInfoDetail> usedTimeInfo = configs.stream()
.map(t -> {
OccupyInfoDetail usedTime = new OccupyInfoDetail();
usedTime.setBeginTime(t.getBeginTime());
usedTime.setEndTime(t.getEndTime());
return usedTime;
}).collect(Collectors.toList());
//工作时间与时间时间并集求差集
List<OccupyInfoDetail> result = CapacityUtils.intervalTime(workStartTime, workEndTime, usedTimeInfo);
if (CollectionUtils.isEmpty(result)) {
return new int[0][];
}
int[][] ints = new int[result.size()][2];
for (int i = 0; i < result.size(); i++) {
OccupyInfoDetail occupy = result.get(i);
int start = (int) Duration.between(occupy.getBeginTime(), minDate).abs().toMinutes();
int end = (int) Duration.between(occupy.getEndTime(), minDate).abs().toMinutes();
ints[i][0] = start;
ints[i][1] = end;
}
return ints;
}
private EngineerCalendarDTO.Calendar getEmptyCalendar(String teamId, String date) {
// 初始化一天的日历
EngineerCalendarDTO.Calendar calendar = new EngineerCalendarDTO.Calendar();
......
......@@ -4,6 +4,7 @@ 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 org.springframework.util.CollectionUtils;
import java.time.Duration;
import java.time.LocalDate;
......@@ -16,6 +17,64 @@ import java.util.List;
public class CapacityUtilsTest {
@Test
public void testIntervalTime() {
LocalDateTime fixedStart = LocalDateTime.of(LocalDate.now(), LocalTime.of(8, 0));
LocalDateTime fixedEnd = LocalDateTime.of(LocalDate.now(), LocalTime.of(18, 0));
ArrayList<OccupyInfoDetail> test = new ArrayList<>();
test.add(new OccupyInfoDetail(LocalDateTime.of(LocalDate.now(), LocalTime.of(8, 0)),
LocalDateTime.of(LocalDate.now(), LocalTime.of(8, 25))));
test.add(new OccupyInfoDetail(LocalDateTime.of(LocalDate.now(), LocalTime.of(8, 25)),
LocalDateTime.of(LocalDate.now(), LocalTime.of(9, 45))));
List<OccupyInfoDetail> occupyInfoDetails = CapacityUtils.intervalTime(fixedStart, fixedEnd, test);
Assertions.assertEquals(1, occupyInfoDetails.size());
test.clear();
test.add(new OccupyInfoDetail(LocalDateTime.of(LocalDate.now(), LocalTime.of(8, 0)),
LocalDateTime.of(LocalDate.now(), LocalTime.of(8, 25))));
test.add(new OccupyInfoDetail(LocalDateTime.of(LocalDate.now(), LocalTime.of(8, 29)),
LocalDateTime.of(LocalDate.now(), LocalTime.of(9, 45))));
occupyInfoDetails = CapacityUtils.intervalTime(fixedStart, fixedEnd, test);
Assertions.assertEquals(2, occupyInfoDetails.size());
test.clear();
test.add(new OccupyInfoDetail(LocalDateTime.of(LocalDate.now(), LocalTime.of(9, 0)),
LocalDateTime.of(LocalDate.now(), LocalTime.of(9, 45))));
test.add(new OccupyInfoDetail(LocalDateTime.of(LocalDate.now(), LocalTime.of(10, 30)),
LocalDateTime.of(LocalDate.now(), LocalTime.of(12, 0))));
occupyInfoDetails = CapacityUtils.intervalTime(fixedStart, fixedEnd, test);
Assertions.assertEquals(3, occupyInfoDetails.size());
test.clear();
test.add(new OccupyInfoDetail(LocalDateTime.of(LocalDate.now(), LocalTime.of(9, 0)),
LocalDateTime.of(LocalDate.now(), LocalTime.of(9, 45))));
test.add(new OccupyInfoDetail(LocalDateTime.of(LocalDate.now(), LocalTime.of(16, 30)),
LocalDateTime.of(LocalDate.now(), LocalTime.of(18, 0))));
occupyInfoDetails = CapacityUtils.intervalTime(fixedStart, fixedEnd, test);
Assertions.assertEquals(2, occupyInfoDetails.size());
test.clear();
test.add(new OccupyInfoDetail(LocalDateTime.of(LocalDate.now(), LocalTime.of(8, 0)),
LocalDateTime.of(LocalDate.now(), LocalTime.of(18, 0))));
occupyInfoDetails = CapacityUtils.intervalTime(fixedStart, fixedEnd, test);
Assertions.assertTrue(CollectionUtils.isEmpty(occupyInfoDetails));
test.clear();
test.add(new OccupyInfoDetail(LocalDateTime.of(LocalDate.now(), LocalTime.of(7, 0)),
LocalDateTime.of(LocalDate.now(), LocalTime.of(9, 45))));
test.add(new OccupyInfoDetail(LocalDateTime.of(LocalDate.now(), LocalTime.of(16, 30)),
LocalDateTime.of(LocalDate.now(), LocalTime.of(18, 0))));
occupyInfoDetails = CapacityUtils.intervalTime(fixedStart, fixedEnd, test);
Assertions.assertEquals(1, occupyInfoDetails.size());
}
@Test
public void testMaxRemainBlock() {
LocalDateTime sliceStart = LocalDateTime.of(LocalDate.now(), LocalTime.of(8, 0));
LocalDateTime sliceEnd = LocalDateTime.of(LocalDate.now(), LocalTime.of(9, 0));
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!