Commit 28d0f9a4 by chamberone

Merge branch 'develop' of https://zhangguoping@gitlab.dituhui.com/bsh/project/pr…

…oject.git into develop
2 parents e509492e 1b1cb771
Showing with 866 additions and 157 deletions
package com.dituhui.pea.dispatch.controller;
import java.util.List;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.druid.util.StringUtils;
import com.dituhui.pea.common.BusinessException;
import com.dituhui.pea.common.Result;
......@@ -16,6 +10,12 @@ import com.dituhui.pea.dispatch.pojo.Location;
import com.dituhui.pea.dispatch.utils.RoadDistanceUtils;
import com.dituhui.pea.dispatch.utils.RoadDistanceUtils.Distance;
import com.dituhui.pea.pojo.DistanceDTO;
import com.dituhui.pea.pojo.DistanceParam;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 道路控制层
......@@ -69,4 +69,19 @@ public class PathController implements IPath {
}
}
@Override
public DistanceDTO getLocationDistance(DistanceParam distanceParam) {
com.dituhui.pea.pojo.Location origin = distanceParam.getOrigin();
com.dituhui.pea.pojo.Location destination = distanceParam.getDestination();
Distance distance = roadDistanceUtils.getDistance2(
new Location(0L, null, null, origin.getLongitude(), origin.getLatitude()),
new Location(0L, null, null, destination.getLongitude(), destination.getLatitude()),
distanceParam.getVehicle());
DistanceDTO dto = new DistanceDTO();
dto.setDis(distance.getDis());
dto.setTime(distance.getTime());
return dto;
}
}
package com.dituhui.pea.dispatch;
import com.dituhui.pea.common.Result;
import com.dituhui.pea.pojo.DistanceDTO;
import com.dituhui.pea.pojo.DistanceParam;
import org.springframework.cloud.openfeign.FeignClient;
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.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import com.dituhui.pea.common.Result;
import com.dituhui.pea.pojo.DistanceDTO;
/**
* 道路相关接口
*
......@@ -29,4 +31,14 @@ public interface IPath {
@RequestParam("toOrderId") String toOrderId,
@RequestParam(name = "vehicleType", required = false) Integer vehicleType);
/**
* 根据交通方式计算两点间距离
*
* @param distanceParam 参数, 包含起始点, 交通方式
* @return 返回两点距离以及所需时间
*/
@PostMapping("/pea-dispatch/locationDistance")
DistanceDTO getLocationDistance(@RequestBody DistanceParam distanceParam);
}
......@@ -143,6 +143,8 @@ public enum StatusCodeEnum {
ORDER_RESCHEDULE_BEFORE_TIME("028", "订单不能改约到当前时间以前!", false),
TEAM_UNMATCHED("029", "工程师没有匹配到工作队", false),
ORDER_FINISHED("030", "订单已结束,请勿操作", false),
;
/**
......
package com.dituhui.pea.pojo;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class DistanceParam {
/**
* 出发点经纬度
*/
private Location origin;
/**
* 出发点经纬度
*/
private Location destination;
/**
* 交通工具:1汽车;2电动车;3自行车;默认是汽车
*/
private Integer vehicle;
}
package com.dituhui.pea.pojo;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotNull;
@Setter
@Getter
@AllArgsConstructor
public class Location {
/**
* 地址纬度
*/
@NotNull(message = "地址纬度必填")
private Double latitude;
/**
* 地址经度
*/
@NotNull(message = "地址经度必填")
private Double longitude;
}
......@@ -173,6 +173,15 @@ public interface IUser {
* @return
*/
@RequestMapping(value = "/pea-user/orgs", method = RequestMethod.GET)
Result<List<OrgInfo>> orgs(String userId);
Result<List<OrgInfo>> orgs(@RequestParam("userId") String userId);
/**
* 获取用户组织
*
* @param userId 查询条件
* @return
*/
@RequestMapping(value = "/pea-user/orgsNoName", method = RequestMethod.GET)
Result<List<OrgInfo>> orgsNoName(@RequestParam("userId") String userId);
}
......@@ -2,17 +2,19 @@ package com.dituhui.pea.order.controller;
import com.dituhui.pea.common.BusinessException;
import com.dituhui.pea.common.Result;
import com.dituhui.pea.order.common.TimeUtils;
import com.dituhui.pea.order.dto.OrderAssignReq;
import com.dituhui.pea.order.dto.OrderReschedule;
import com.dituhui.pea.order.dto.OrderRevokeAssign;
import com.dituhui.pea.order.dto.param.RecommendEngineersReq;
import com.dituhui.pea.order.service.OrderAssign;
import com.dituhui.pea.order.service.OrderInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
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.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
......@@ -27,14 +29,12 @@ public class OrderAssignController {
private OrderInfoService orderInfoService;
@GetMapping("/order/assign/recommend/engineers")
public Result<?> getOrderAssignRecommendEngineers(
@RequestParam String orderId, @RequestParam(required = false) String key,
@RequestParam(required = false) String distance, @RequestParam(required = false) String recommend) {
public Result<?> getOrderAssignRecommendEngineers(RecommendEngineersReq req) {
//服务单指派-推荐技术员列表
Result<?> res = null;
try {
res = orderAssign.getOrderAssignRecommendEngineers(orderId, key, distance, recommend);
res = orderAssign.getOrderAssignRecommendEngineers(req);
} catch (BusinessException e) {
return Result.failed(e.getMessage());
}
......
......@@ -2,12 +2,13 @@ package com.dituhui.pea.order.controller;
import com.dituhui.pea.common.BusinessException;
import com.dituhui.pea.common.Result;
import com.dituhui.pea.dispatch.IPath;
import com.dituhui.pea.enums.StatusCodeEnum;
import com.dituhui.pea.order.common.jackson.DateUtil;
import com.dituhui.pea.order.common.jackson.JsonUtil;
import com.dituhui.pea.order.dao.TableCodeCheckDao;
import com.dituhui.pea.order.dto.param.BaseDistance;
import com.dituhui.pea.order.dto.param.BaseDistanceParam;
import com.dituhui.pea.order.dto.param.BaseLocation;
import com.dituhui.pea.order.dto.param.CapacityQueryDTO;
import com.dituhui.pea.order.dto.param.EngineerCalendarResultDTO;
import com.dituhui.pea.order.dto.param.EngineerOrderParam;
......@@ -22,6 +23,9 @@ import com.dituhui.pea.order.service.EngineerCalendarService;
import com.dituhui.pea.order.service.OrderCreateService;
import com.dituhui.pea.order.service.OrderInfoService;
import com.dituhui.pea.order.service.PeaOuterAPIService;
import com.dituhui.pea.pojo.DistanceDTO;
import com.dituhui.pea.pojo.DistanceParam;
import com.dituhui.pea.pojo.Location;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Getter;
......@@ -64,6 +68,7 @@ public class PeaApiController {
private OrderInfoService orderInfoService;
private final CapacityQueryService capacityQueryService;
private final TableCodeCheckDao tableCodeCheckDao;
private final IPath path;
private static final String stage = "{\"orderId\": \"X10001\", \"engineerCode\": \"E12005\", \"engineerName\": \"祝枝山\", \"engineerCodeAssist\": \"E12446\", \"engineerNameAssist\": \"李晓阳\", \"planVisitTime\": \"2023-07-27 12:00:00\", \"realtimeInfo\": {\"engineerLocation\": {\"latitude\": 31.349701, \"longitude\": 120.675945, \"address\": \"江苏省苏州市苏州工业园区和顺路\", \"name\": \"和顺大酒店\"}, \"estimate\": {\"distance\": 2300, \"arriveTime\": \"2023-07-27 12:12:00\"}}}";
......@@ -332,9 +337,21 @@ public class PeaApiController {
public Result<BaseDistance> baseDistance(@RequestBody BaseDistanceParam param) {
BaseDistance result = new BaseDistance();
result.setOrigin(param.getOrigin());
result.setDestination(param.getDestination());
BaseLocation origin = param.getOrigin();
result.setOrigin(origin);
BaseLocation destination = param.getDestination();
result.setDestination(destination);
result.setVehicle(param.getVehicle());
DistanceParam distanceParam = new DistanceParam();
distanceParam.setOrigin(new Location(origin.getLongitude(), origin.getLatitude()));
distanceParam.setOrigin(new Location(destination.getLongitude(), destination.getLatitude()));
distanceParam.setVehicle(param.getVehicle());
DistanceDTO locationDistance = path.getLocationDistance(distanceParam);
result.setDistance((int) locationDistance.getDis());
result.setDuration((long) locationDistance.getTime());
return Result.success(result);
}
......
package com.dituhui.pea.order.dao;
import com.dituhui.pea.order.entity.EngineerSkillGroupEntity;
import com.dituhui.pea.order.entity.SkillGroupEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
......
......@@ -77,4 +77,29 @@ public interface OrderInfoDao extends JpaRepository<OrderInfoEntity, Long>, JpaS
" WHERE si.skill_group_code = :skillGroupCode AND oi.expect_time_begin >= :dateTime AND oi.is_multiple = 0 " +
" AND (appointment_status = 'INIT' AND order_status != 'CANCELED') AND oi.reason_for_failure IS NULL ", nativeQuery = true)
List<OrderInfoEntity> getSkillGroupOrder(String skillGroupCode, LocalDateTime dateTime);
@Query(value = "SELECT count(*) from order_info WHERE dt =:dt and (service_status ='INIT' or service_status ='CONTACTED') " +
"and DATE_ADD(NOW(), INTERVAL 10 MINUTE) > expect_time_begin and org_cluster_id = :orgCusterId", nativeQuery = true)
long countDelayByDtAndOrgClusterId(LocalDate dt, String orgCusterId);
@Query(value = "SELECT count(*) from order_info WHERE dt =:dt and (service_status ='INIT' or service_status ='CONTACTED') " +
"and DATE_ADD(NOW(), INTERVAL 10 MINUTE) > expect_time_begin and org_group_id = :orgGroupId", nativeQuery = true)
long countDelayByDtAndOrgGroupId(LocalDate dt, String orgGroupId);
@Query(value = "SELECT count(*) from order_info WHERE dt =:dt and (service_status ='INIT' or service_status ='CONTACTED') " +
"and DATE_ADD(NOW(), INTERVAL 10 MINUTE) > expect_time_begin and org_branch_id = :orgBranchId", nativeQuery = true)
long countDelayByDtAndOrgBranchId(LocalDate dt, String orgBranchId);
@Query(value = "SELECT count(*) from order_info WHERE dt =:dt and service_status ='STARTED' and actual_end_time is null " +
"and DATE_ADD(NOW(), INTERVAL 10 MINUTE) > plan_end_time and org_cluster_id = :orgCusterId", nativeQuery = true)
long countOvertimeByDtAndOrgClusterId(LocalDate dt, String orgCusterId);
@Query(value = "SELECT count(*) from order_info WHERE dt =:dt and service_status ='STARTED' and actual_end_time is null " +
"and DATE_ADD(NOW(), INTERVAL 10 MINUTE) > plan_end_time and org_group_id = :orgGroupId", nativeQuery = true)
long countOvertimeByDtAndOrgGroupId(LocalDate dt, String orgGroupId);
@Query(value = "SELECT count(*) from order_info WHERE dt =:dt and service_status ='STARTED' and actual_end_time is null " +
"and DATE_ADD(NOW(), INTERVAL 10 MINUTE) > plan_end_time and org_branch_id = :orgBranchId", nativeQuery = true)
long countOvertimeByDtAndOrgBranchId(LocalDate dt, String orgBranchId);
}
......@@ -45,6 +45,12 @@ public interface OrgTeamDao extends JpaRepository<OrgTeamEntity, Integer>, JpaSp
public List<OrgTeamEntity> findByTeamIdIn(List<String> ids);
public List<OrgTeamEntity> findByClusterIdIn(List<String> ids);
public List<OrgTeamEntity> findByBranchIdIn(List<String> ids);
public List<OrgTeamEntity> findByGroupIdIn(List<String> ids);
/**
* 获取工程师所在的工作队
*
......
......@@ -11,7 +11,6 @@ import java.util.List;
@Repository
@Where(clause = "status = 1")
public interface OrgTeamEngineerDao extends JpaRepository<OrgTeamEngineerEntity, Integer> {
@Query("select t from OrgTeamEngineerEntity t where t.teamId = :teamId and t.status=1")
......@@ -34,6 +33,7 @@ public interface OrgTeamEngineerDao extends JpaRepository<OrgTeamEngineerEntity,
@Query("UPDATE OrgTeamEngineerEntity tt SET tt.status = :status WHERE tt.teamId = :teamId AND tt.engineerCode IN :engineerCodes")
void updateStatusByEngineerCodes(String teamId, List<String> engineerCodes, int status);
@Query("select t from OrgTeamEngineerEntity t where t.engineerCode in :engineerCode and t.status=1")
List<OrgTeamEngineerEntity> findByEngineerCode(String engineerCode);
/**
......
package com.dituhui.pea.order.dto;
import com.dituhui.pea.order.enums.TestimonialsEngineerTag;
import lombok.Data;
import java.util.List;
......@@ -14,7 +15,10 @@ public class OrderAssignRecommendResp {
private String engineerCode;
private String engineerName;
private String location;
private String distanceDesc;
/**
* 工程师标签
*/
private TestimonialsEngineerTag distanceDesc;
private String timeDesc;
private String desc;
private String startTime;
......
......@@ -64,6 +64,8 @@ public class OrderServiceDetailResp {
private String expectTimeBegin;
private String expectTimeEnd;
private String expectTimeDesc;
private String source;
......
......@@ -34,6 +34,9 @@ public class OrderServiceList {
private String serviceStatus;
private String createTime;
private String engineerCode;
private String engineerName;
private String engineerPhone;
/**
* bean优先级,例如:紧急、正常
*/
......
......@@ -13,10 +13,12 @@ public class OrderServiceListReq {
private String levelType;
@NotNull
private String levelValue;
// @NotNull
// private String startDate;
// @NotNull
// private String endDate;
@NotNull
private String startDate;
@NotNull
private String endDate;
private String date;
@NotNull
private long page;
@NotNull
......
package com.dituhui.pea.order.dto.param;
import lombok.Data;
@Data
public class RecommendEngineersReq {
/**
* 工单ID
*/
private String orderId;
/**
* 待补充doc
*/
private String key;
/**
* 距离范围(单位:KM), 不传改值为:不限
*/
private Double distance;
/**
* 待补充doc
*/
private String recommend;
/**
* 待补充doc
*/
private String userId;
}
package com.dituhui.pea.order.entity;
import lombok.Data;
import org.hibernate.annotations.Where;
import javax.persistence.*;
import java.time.LocalDateTime;
......@@ -8,6 +9,7 @@ import java.time.LocalDateTime;
@Data
@Entity
@Table(name = "engineer_skill_group")
@Where(clause = " status = 1")
public class EngineerSkillGroupEntity {
@Id
......
......@@ -2,6 +2,7 @@ package com.dituhui.pea.order.entity;
import lombok.Data;
import lombok.experimental.Accessors;
import org.hibernate.annotations.Where;
import javax.persistence.*;
import java.time.LocalDateTime;
......@@ -10,6 +11,7 @@ import java.util.Date;
@Entity
@Data
@Accessors(chain = true)
@Where(clause = "status = 1")
@Table(name = "org_team_engineer")
public class OrgTeamEngineerEntity {
......
......@@ -6,6 +6,7 @@ public enum ServiceStatusEnum {
PENDING("PENDING", "待服务"),
CONTACTED("CONTACTED", "已排期"),
STARTED("STARTED", "已开始"),
CANCELED("CANCELED", "已取消"),
FINISHED("FINISHED", "已完成"),
UNFINISHED("UNFINISHED", "已上门未完成");
......
package com.dituhui.pea.order.enums;
import lombok.Getter;
/**
* 推荐工程师标签
*/
@Getter
public enum TestimonialsEngineerTag {
/**
* 队内 ,和工单现有人员同属一个小队
*/
TEAM,
/**
* 周边, 不同队 但在10KM内
*/
PERIPHERAL,
/**
* 搜索, 通过搜索出来的人
*/
SEARCH;
}
......@@ -11,6 +11,7 @@ import com.dituhui.pea.order.dao.EngineerBusinessDao;
import com.dituhui.pea.order.dao.EngineerInfoDao;
import com.dituhui.pea.order.dao.EngineerSliceUsedCapacityDao;
import com.dituhui.pea.order.dao.OrderInfoDao;
import com.dituhui.pea.order.dao.TimeSliceDao;
import com.dituhui.pea.order.entity.CapacityEngineerSliceUsedEntity;
import com.dituhui.pea.order.entity.CapacityEngineerStatEntity;
import com.dituhui.pea.order.entity.EngineerBusinessEntity;
......@@ -19,6 +20,7 @@ import com.dituhui.pea.order.entity.OrderInfoEntity;
import com.dituhui.pea.order.entity.TimeSliceEntity;
import com.dituhui.pea.order.service.EngineerCalendarService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
......@@ -30,10 +32,12 @@ import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
......@@ -57,6 +61,8 @@ public class CalcEngineerCapacityScheduler {
private EngineerSliceUsedCapacityDao engineerSliceUsedCapacityDao;
@Autowired
private EngineerCalendarService engineerCalendarService;
@Autowired
private TimeSliceDao timeSliceDao;
@Scheduled(cron = "${scheduler.calc-engineer-capacity.cron-expr}")
public void run() {
......@@ -108,8 +114,9 @@ public class CalcEngineerCapacityScheduler {
})
.collect(Collectors.toList());
initOneEngineerTimeSlot(date, engineerCode, configs, orders);
List<TimeSliceEntity> commonTimeSliceList = timeSliceDao.findByType("HOURS");
initOneEngineerTimeSlot(date, engineerCode, configs, orders, commonTimeSliceList);
caculateEngineerOneDay(date, businessEntity, orders, configs, statEntity);
capacityEngineerStatDao.save(statEntity);
}
......@@ -125,20 +132,51 @@ public class CalcEngineerCapacityScheduler {
List<OccupyInfoDetail> durationTime = CapacityUtils.getMaxRemainBlock(startTime, endTime, occupyInfo);
long maxRemainBlock = durationTime.stream().mapToLong(OccupyInfoDetail::getDuration).max().orElse(0L);
//总时长
long total = Duration.between(startTime, endTime).abs().toMinutes();
statEntity.setCapTotal((int)total);
statEntity.setOrderCount(orders.size());
statEntity.setCapUsed((int) totalUseTime);
statEntity.setCapLeft(statEntity.getCapTotal() - (int) totalUseTime);
statEntity.setCapLeft((int)total - (int) totalUseTime);
statEntity.setMaxDuration((int) maxRemainBlock);
statEntity.setUpdateTime(LocalDateTime.now());
}
//添加工程师日历参数
private void initOneEngineerTimeSlot(String date, String engineerCode, List<OccupyInfoDetail> configs,
List<OrderInfoEntity> orders) {
List<OrderInfoEntity> orders, List<TimeSliceEntity> commonTimeSliceList) {
final LocalDate localDate = LocalDate.parse(date, DateTimeUtil.DATE_FORMAT);
//查询时间片容量
List<CapacityEngineerSliceUsedEntity> engineerTimeSlice = engineerSliceUsedCapacityDao.findByWorkdayAndEngineerCode(date, engineerCode);
//查询哪些时间片需要新增, 哪些时间片需要删除
List<TimeSliceEntity> timeCorridor = engineerTimeSlice(engineerCode, date, commonTimeSliceList);
//需要删除的时间片记录
List<CapacityEngineerSliceUsedEntity> needDeleteTimeSlice = engineerTimeSlice.stream()
.filter(t -> timeCorridor.stream().noneMatch(ti -> Objects.equals(ti, t.getTimmeSlice())))
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(needDeleteTimeSlice)) {
engineerTimeSlice.removeAll(needDeleteTimeSlice);
engineerSliceUsedCapacityDao.deleteAll(needDeleteTimeSlice);
engineerSliceUsedCapacityDao.flush();
}
//需要增加的时间切片
List<CapacityEngineerSliceUsedEntity> needAdd = timeCorridor.stream()
.filter(slice -> engineerTimeSlice.stream()
.map(CapacityEngineerSliceUsedEntity::getTimmeSlice).noneMatch(ti -> Objects.equals(ti, slice))
).map(timeSlice -> {
CapacityEngineerSliceUsedEntity r = new CapacityEngineerSliceUsedEntity();
r.setTimmeSlice(timeSlice);
r.setEngineerCode(engineerCode);
r.setWorkday(date);
LocalTime sliceStartLocalTime = LocalTime.parse(timeSlice.getStart(), DateUtil.TIME_FORMATTER);
LocalTime sliceEndLocalTime = LocalTime.parse(timeSlice.getEnd(), DateUtil.TIME_FORMATTER);
r.setCapTotal(DateTimeUtil.betweenTwoTime(sliceStartLocalTime, sliceEndLocalTime, TimeUnit.MINUTES));
r.setCreateTime(LocalDateTime.now());
return r;
}).collect(Collectors.toList());
engineerTimeSlice.addAll(needAdd);
for (CapacityEngineerSliceUsedEntity sliceCap : engineerTimeSlice) {
final TimeSliceEntity timeSlice = sliceCap.getTimmeSlice();
LocalTime sliceStartLocalTime = LocalTime.parse(timeSlice.getStart(), DateUtil.TIME_FORMATTER);
......@@ -164,4 +202,35 @@ public class CalcEngineerCapacityScheduler {
engineerSliceUsedCapacityDao.saveAll(engineerTimeSlice);
}
private List<TimeSliceEntity> engineerTimeSlice(String engineerCode, String date, List<TimeSliceEntity> commonTimeSliceList) {
EngineerBusinessEntity businessEntity = engineerBusinessDao.getByEngineerCode(engineerCode);
LocalDateTime workStartTime = DateUtils.localDateTimeFromStr(String.format("%s %s:00", date, businessEntity.getWorkOn()));
LocalDateTime workEndTime = DateUtils.localDateTimeFromStr(String.format("%s %s:00", date, businessEntity.getWorkOff()));
return getTimeSliceEntities(workStartTime, workEndTime, commonTimeSliceList);
}
private List<TimeSliceEntity> getTimeSliceEntities(LocalDateTime workStartTime, LocalDateTime workEndTime,
List<TimeSliceEntity> commonTimeSliceList) {
//切片开始时间
LocalTime sliceStartHour = LocalTime.of(workStartTime.getHour(), 0);
//切片结束时间
LocalTime sliceEndHour;
int minuteOfHour = workEndTime.getMinute();
if (minuteOfHour > 0) {
sliceEndHour = LocalTime.of(workEndTime.getHour(), 0).plusHours(1);
} else {
sliceEndHour = LocalTime.of(workEndTime.getHour(), 0);
}
List<TimeSliceEntity> timeCorridor = commonTimeSliceList.stream()
.filter(slice -> {
LocalTime startLocalTime = LocalTime.parse(slice.getStart(), DateUtil.TIME_FORMATTER);
LocalTime endLocalTime = LocalTime.parse(slice.getEnd(), DateUtil.TIME_FORMATTER);
return (startLocalTime.isAfter(sliceStartHour) && endLocalTime.isBefore(sliceEndHour)) ||
(startLocalTime.equals(sliceStartHour) || endLocalTime.equals(sliceEndHour));
}).sorted(Comparator.comparing(TimeSliceEntity::getId)).collect(Collectors.toList());
return timeCorridor;
}
}
......@@ -10,6 +10,8 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
......@@ -100,10 +102,10 @@ public class CalcOrgCapacityScheduler {
dto.setOrgId(groupId);
dto.setLayerId((String) result[1]);
dto.setLayer((String) result[2]);
dto.setEngineerCount((Integer) result[3]);
dto.setCapTotal((Integer) result[4]);
dto.setCapUsed((Integer) result[5]);
dto.setCapLeft((Integer) result[6]);
dto.setEngineerCount(((BigInteger) result[3]).intValue());
dto.setCapTotal(((BigDecimal) result[4]).intValue());
dto.setCapUsed(((BigDecimal) result[5]).intValue());
dto.setCapLeft(((BigDecimal) result[6]).intValue());
stats.add(dto);
}
// 逐条保存
......@@ -178,7 +180,7 @@ public class CalcOrgCapacityScheduler {
}
}
private void calcAllGroupByDays(String bdate, String edate) {
public void calcAllGroupByDays(String bdate, String edate) {
LocalDate currentDate = DateUtils.localDateFromStr(bdate);
LocalDate endDate = DateUtils.localDateFromStr(edate);
List<String> allGroupIds = orgGroupDao.findAll().stream().map(OrgGroupEntity::getGroupId).collect(Collectors.toList());
......
......@@ -71,4 +71,14 @@ public interface EngineerCalendarService {
* @apiNote 时间窗格式:[[起始时间段1, 结束时间段1],[起始时间段2, 结束时间段2]] <br/> 时间格式: 从0点开始的分钟数, 如8:00AM 为480
*/
int[][] timeWindows(String engineerCode, String teamId, LocalDate targetDate);
/**
* 获取工程师的工作时间窗
*
* @param engineerCode 工程师编号
* @param teamId 工程师所属工作队 (解决一个工程师属多个多工作对情况)
* @param targetDate 目标日期
* @return 时间窗格式
*/
List<OccupyInfoDetail> timeWindowsSlice(String engineerCode, String teamId, LocalDate targetDate);
}
......@@ -3,6 +3,7 @@ package com.dituhui.pea.order.service;
import com.dituhui.pea.common.Result;
import com.dituhui.pea.order.dto.OrderAssignReq;
import com.dituhui.pea.order.dto.OrderReschedule;
import com.dituhui.pea.order.dto.param.RecommendEngineersReq;
import org.bouncycastle.asn1.cms.TimeStampAndCRL;
import java.sql.Timestamp;
......@@ -12,7 +13,7 @@ import java.time.LocalDateTime;
public interface OrderAssign {
// 服务单指派-推荐技术员列表
Result<?> getOrderAssignRecommendEngineers(String orderId, String key, String distance, String recommend);
Result<?> getOrderAssignRecommendEngineers(RecommendEngineersReq req);
// 服务单指派-指派提交
Result<?> orderAssign(OrderAssignReq req);
......
......@@ -326,6 +326,7 @@ public class DispatchServiceImpl implements DispatchService {
if (!entityResult.getCode().equals(ResultEnum.SUCCESS.getCode())) {
// return Result.failed("当前工程师无法预约合适时间");
errorList.add(entity.getOrderId());
continue;
}
entity = entityResult.getResult();
entity.setTakeTime(skill.getTakeTime());
......
......@@ -613,27 +613,47 @@ public class EngineerCalendarServiceImpl implements EngineerCalendarService {
@Override
public int[][] timeWindows(String engineerCode, String teamId, LocalDate targetDate) {
final LocalDateTime minDate = LocalDateTime.of(targetDate, LocalTime.MIN);
//工作时间与时间时间并集求差集
List<OccupyInfoDetail> result = timeWindowsSlice(engineerCode, teamId, targetDate);
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;
}
@Override
public List<OccupyInfoDetail> timeWindowsSlice(String engineerCode, String teamId, LocalDate targetDate) {
EngineerInfoEntity engineerInfoEntity = engineerInfoDao.selectEngineerByEngineerCodeAndTeamId(engineerCode, teamId);
if (Objects.isNull(engineerInfoEntity)) {
return new int[0][];
return Collections.emptyList();
}
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][];
return Collections.emptyList();
}
//是工作日, 取当前天的日历事件
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.of(targetDate, LocalTime.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()}};
OccupyInfoDetail occupyInfoDetail = new OccupyInfoDetail(workStartTime, workEndTime);
return List.of(occupyInfoDetail);
}
// 多个休息时间不存在交集
......@@ -645,23 +665,9 @@ public class EngineerCalendarServiceImpl implements EngineerCalendarService {
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 CapacityUtils.intervalTime(workStartTime, workEndTime, usedTimeInfo);
}
return ints;
}
private EngineerCalendarDTO.Calendar getEmptyCalendar(String teamId, String date) {
// 初始化一天的日历
EngineerCalendarDTO.Calendar calendar = new EngineerCalendarDTO.Calendar();
......
......@@ -180,19 +180,19 @@ public class EngineerGanttServiceImpl implements EngineerGanttService {
// 最后,还需要根据key进行过滤(需要结合数据库表)
engineerCodes = engineerUtils.filterEngineersByKey(engineerCodes, key).stream().map(EngineerInfoEntity::getEngineerCode).collect(Collectors.toList());
}
if (CollectionUtils.isNotEmpty(orderIds)) {
List<OrderInfoEntity> infoEntities = orderInfoDao.findAllByOrderIdIn(orderIds);
Set<String> skillGroupCodes = Sets.newConcurrentHashSet();
for (OrderInfoEntity orderInfo : infoEntities) {
//查询对应的技能信息
SkillInfoEntity skill = skillInfoDao.getByBrandAndTypeAndSkill(orderInfo.getBrand(), orderInfo.getType(), orderInfo.getSkill());
if (Objects.isNull(skill)) {
throw new BusinessException("查询不到对应的技能组信息:" + String.join(",", orderInfo.getType(), orderInfo.getSkill()));
}
skillGroupCodes.add(skill.getSkillGroupCode());
}
engineerCodes = engineerInfoDao.findByEngineerCodesBySkillCodes(engineerCodes, skillGroupCodes);
}
// if (CollectionUtils.isNotEmpty(orderIds)) {
// List<OrderInfoEntity> infoEntities = orderInfoDao.findAllByOrderIdIn(orderIds);
// Set<String> skillGroupCodes = Sets.newConcurrentHashSet();
// for (OrderInfoEntity orderInfo : infoEntities) {
// //查询对应的技能信息
// SkillInfoEntity skill = skillInfoDao.getByBrandAndTypeAndSkill(orderInfo.getBrand(), orderInfo.getType(), orderInfo.getSkill());
// if (Objects.isNull(skill)) {
// throw new BusinessException("查询不到对应的技能组信息:" + String.join(",", orderInfo.getType(), orderInfo.getSkill()));
// }
// skillGroupCodes.add(skill.getSkillGroupCode());
// }
// engineerCodes = engineerInfoDao.findByEngineerCodesBySkillCodes(engineerCodes, skillGroupCodes);
// }
return engineerCodes;
}
......
......@@ -5,15 +5,53 @@ import com.dituhui.pea.common.BusinessException;
import com.dituhui.pea.common.Result;
import com.dituhui.pea.common.ResultEnum;
import com.dituhui.pea.enums.StatusCodeEnum;
import com.dituhui.pea.order.common.DateUtils;
import com.dituhui.pea.order.common.OrderAssignCheck;
import com.dituhui.pea.order.common.Stapial4jUtil;
import com.dituhui.pea.order.common.TimeUtils;
import com.dituhui.pea.order.dao.*;
import com.dituhui.pea.order.dto.*;
import com.dituhui.pea.order.entity.*;
import com.dituhui.pea.order.enums.*;
import com.dituhui.pea.order.service.*;
import com.dituhui.pea.order.dao.EngineerBusinessDao;
import com.dituhui.pea.order.dao.EngineerInfoDao;
import com.dituhui.pea.order.dao.EngineerSkillGroupDao;
import com.dituhui.pea.order.dao.OrderInfoDao;
import com.dituhui.pea.order.dao.OrgBranchDao;
import com.dituhui.pea.order.dao.OrgGroupDao;
import com.dituhui.pea.order.dao.OrgTeamDao;
import com.dituhui.pea.order.dao.OrgTeamEngineerDao;
import com.dituhui.pea.order.dao.SkillInfoDao;
import com.dituhui.pea.order.dto.LabelValueDTO;
import com.dituhui.pea.order.dto.MsgDTO;
import com.dituhui.pea.order.dto.OrderAssignRecommendResp;
import com.dituhui.pea.order.dto.OrderAssignReq;
import com.dituhui.pea.order.dto.OrderReschedule;
import com.dituhui.pea.order.dto.TimeLineDTO;
import com.dituhui.pea.order.dto.param.Location;
import com.dituhui.pea.order.dto.param.RecommendEngineersReq;
import com.dituhui.pea.order.entity.EngineerBusinessEntity;
import com.dituhui.pea.order.entity.EngineerInfoEntity;
import com.dituhui.pea.order.entity.EngineerSkillGroupEntity;
import com.dituhui.pea.order.entity.OrderInfoEntity;
import com.dituhui.pea.order.entity.OrgTeamEngineerEntity;
import com.dituhui.pea.order.entity.OrgTeamEntity;
import com.dituhui.pea.order.entity.SkillInfoEntity;
import com.dituhui.pea.order.enums.AppointmentMethodEnum;
import com.dituhui.pea.order.enums.OrderEventEnum;
import com.dituhui.pea.order.enums.OrderFlowEnum;
import com.dituhui.pea.order.enums.OrderStatusEnum;
import com.dituhui.pea.order.enums.ServiceStatusEnum;
import com.dituhui.pea.order.enums.TestimonialsEngineerTag;
import com.dituhui.pea.order.service.CapacityQueryService;
import com.dituhui.pea.order.service.CommonService;
import com.dituhui.pea.order.service.FendanService;
import com.dituhui.pea.order.service.MsgService;
import com.dituhui.pea.order.service.OrderAssign;
import com.dituhui.pea.order.service.OrderInfoService;
import com.dituhui.pea.order.utils.CommonUtil;
import com.dituhui.pea.order.utils.OrderUtil;
import com.dituhui.pea.pojo.user.OrgInfo;
import com.dituhui.pea.user.IUser;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
......@@ -26,8 +64,19 @@ import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@Service
......@@ -79,24 +128,38 @@ public class OrderAssignImpl implements OrderAssign {
@Autowired
private CapacityQueryService capacityQueryService;
@Autowired
private IUser userService;
@Autowired
private EngineerBusinessDao engineerBusinessDao;
@Transactional
@Override
public Result<?> getOrderAssignRecommendEngineers(String orderId, String key, String distance, String recommend) {
public Result<?> getOrderAssignRecommendEngineers(RecommendEngineersReq req) {
// 服务单指派-推荐技术员列表
OrderInfoEntity order = orderInfoDao.getByOrderId(orderId);
OrderInfoEntity order = orderInfoDao.getByOrderId(req.getOrderId());
if (order == null) {
throw new BusinessException("订单不存在");
}
String date = TimeUtils.IsoLocalDate2String(order.getDt());
// 获取符合筛选条件的技术员
List<String> engineerCodes = this.searchEngineerCodes(order, distance, key, recommend);
// 改造本方法 让其支持标签返回
List<TempEngineer> engineerLocationList = this.searchEngineerCodes(order, req.getDistance(), req.getKey(), req.getRecommend(), req.getUserId());
List<String> engineerCodes = engineerLocationList.stream().map(TempEngineer::getEngineerCode).collect(Collectors.toList());
Map<String, TempEngineer> engineerDistanceMap = engineerLocationList.stream().collect(Collectors.toMap(
TempEngineer::getEngineerCode,
a -> a,
(k1, k2) -> k1));
List<EngineerInfoEntity> engineers = engineerInfoDao.findByEngineerCodeIn(engineerCodes);
List<OrderAssignRecommendResp.Engineer> items = new ArrayList<>();
final String orgTeamId = order.getOrgTeamId();
final BigDecimal judgeDistance = new BigDecimal("10");
for (EngineerInfoEntity engineer : engineers) {
OrderAssignCheck.Result result = orderAssignCheck.orderAssignCheck(orderId, order.getDt(), engineer.getEngineerCode());
final String engineerCode = engineer.getEngineerCode();
OrderAssignCheck.Result result = orderAssignCheck.orderAssignCheck(req.getOrderId(), order.getDt(), engineerCode);
log.info("指派检查结果:{}", result);
if (result.getIndex() < 0) {
continue;
......@@ -104,7 +167,7 @@ public class OrderAssignImpl implements OrderAssign {
// 获取已技术员已指派订单列表
List<OrderInfoEntity> orderAppointments = orderInfoDao.findByEngineerCodeAndDtAndAppointmentStatusIn(
engineer.getEngineerCode(), order.getDt(), List.of(OrderFlowEnum.CONFIRM.name()), null);
engineerCode, order.getDt(), List.of(OrderFlowEnum.CONFIRM.name()), null);
// 获取订单tips
HashMap<String, List<LabelValueDTO>> orderTips = new HashMap<>();
......@@ -113,7 +176,6 @@ public class OrderAssignImpl implements OrderAssign {
List<OrderInfoEntity> orders = orderInfoDao.findAllByDtAndOrderIdIn(order.getDt(), orderIds);
orderTips = this.packOrderTips(orders);
}
OrderAssignRecommendResp.Engineer item = new OrderAssignRecommendResp.Engineer();
OrderAssignRecommendResp.InsertInfo insertInfo = new OrderAssignRecommendResp.InsertInfo();
......@@ -121,11 +183,23 @@ public class OrderAssignImpl implements OrderAssign {
insertInfo.setTimeDesc(String.format("+%d分钟", result.getAdditionElapsed()));
insertInfo.setDistanceDesc(String.format("+%d公里", result.getAdditionDistance() / 1000));
item.setEngineerCode(engineer.getEngineerCode());
TestimonialsEngineerTag engineerTag;
//标签判定
//判定当前工程师是否在队内, 否则判定是否在10KM内, 否则
TempEngineer tempEngineer = engineerDistanceMap.get(engineerCode);
if (Objects.nonNull(orgTeamEngineerDao.findByTeamIdAndEngineerCode(orgTeamId, engineerCode))) {
engineerTag = TestimonialsEngineerTag.TEAM;
} else if (tempEngineer.getDistance().compareTo(judgeDistance) <= 0) {
engineerTag = TestimonialsEngineerTag.PERIPHERAL;
} else {
engineerTag = TestimonialsEngineerTag.SEARCH;
}
item.setEngineerCode(engineerCode);
item.setEngineerName(engineer.getName());
item.setLocation(String.format("%s,%s", order.getX(), order.getY()));
item.setInsertInfo(insertInfo);
item.setDistanceDesc("");
item.setDistanceDesc(engineerTag);
item.setTimeDesc("");
int index = result.getIndex() + 1;
......@@ -194,11 +268,23 @@ public class OrderAssignImpl implements OrderAssign {
if (order == null) {
return Result.failed("订单不存在");
}
// 更新order_request表为未指派
if (order.getOrderStatus().equals(OrderStatusEnum.CANCELED.getCode()) || order.getServiceStatus().equals(ServiceStatusEnum.FINISHED.getCode())) {
return Result.failed(StatusCodeEnum.ORDER_FINISHED);
}
OrgTeamEntity orgTeam = orgTeamDao.getByTeamId(order.getOrgTeamId());
// 判断cutoff
Integer cutoff = CommonUtil.isCutoff(order.getExpectTimeBegin(), orgTeam.getWorkOff());
order.setAppointmentStatus(OrderFlowEnum.INIT.name());
order.setServiceStatus(OrderFlowEnum.INIT.name());
if (cutoff > 0) {
// cutoff更新order_request表为人工指派
order.setAppointmentMethod(AppointmentMethodEnum.MANUAL.name());
order = OrderUtil.handleErrorOrder(order);
order.setIsCutoff(cutoff);
} else {
// 更新order_request表为未指派
order = OrderUtil.handleErrorOrder2(order);
}
orderInfoDao.save(order);
commonService.addOrderEvent(orderId, "", "PEA", "PEA", OrderEventEnum.backOrderPool.getEvent(), OrderEventEnum.backOrderPool.getMsg(), "");
......@@ -235,8 +321,8 @@ public class OrderAssignImpl implements OrderAssign {
return order;
}
private List<String> searchEngineerCodes(OrderInfoEntity order, String distance, String key, String recommend) {
Set<String> engineerCodes1 = this.searchEngineerByRecommend(order, recommend);
private List<TempEngineer> searchEngineerCodes(OrderInfoEntity order, Double distance, String key, String recommend, String userId) {
Set<String> engineerCodes1 = this.searchEngineerByRecommend(order, recommend, userId);
if (engineerCodes1.isEmpty()) {
log.info("recommend:{}筛选条件未找到技术员", recommend);
return new ArrayList<>();
......@@ -258,13 +344,13 @@ public class OrderAssignImpl implements OrderAssign {
SkillInfoEntity skill = skillInfoDao.getByBrandAndTypeAndSkill(order.getBrand(), order.getType(), order.getSkill());
if (skill == null) {
log.info("skill_info表没有匹配到技能配置:{}-{}-{}", order.getBrand(), order.getY(), order.getSkill());
return new ArrayList<>();
return Collections.emptyList();
}
Set<String> engineerCodes3 = engineerSkillGroupDao.findBySkillGroupCode(skill.getSkillGroupCode()).stream().map(
EngineerSkillGroupEntity::getEngineerCode).collect(Collectors.toSet());
if (engineerCodes3.isEmpty()) {
log.info("没有匹配到技能相匹配的技术员:{}-{}-{}", order.getBrand(), order.getType(), order.getSkill());
return new ArrayList<>();
return Collections.emptyList();
}
engineerCodes1.retainAll(engineerCodes3);
if (engineerCodes1.isEmpty()) {
......@@ -272,37 +358,128 @@ public class OrderAssignImpl implements OrderAssign {
return new ArrayList<>();
}
/*
if (StringUtils.isEmpty(distance)) {
return new ArrayList<>(engineerCodes1);
// 获取工程师位置(准实时位置)并进行距离判定, distance如果为空值 默认10KM
double orderLongitude = Double.parseDouble(order.getX());
double orderLatitude = Double.parseDouble(order.getY());
//均计算距离
List<TempEngineer> result = engineerCodes1.stream()
.map(engineerCode -> {
Location location = engineerDateLocation(engineerCode);
BigDecimal orderAndEngineerDistance = BigDecimal.valueOf(Stapial4jUtil.getDistance(location.getLongitude(), location.getLatitude(),
orderLongitude, orderLatitude));
return new TempEngineer(engineerCode, orderAndEngineerDistance);
}).collect(Collectors.toList());
// 距离过滤
if (Objects.nonNull(distance)) {
final BigDecimal finalDistance = BigDecimal.valueOf(distance);
// return ;
result = result.stream().filter(t -> t.getDistance().compareTo(finalDistance) <= 0).collect(Collectors.toList());
}
return result;
}
//进行距离匹配TODO
@Setter
@Getter
@AllArgsConstructor
class TempEngineer {
/**
* 工程师编号
*/
private String engineerCode;
/**
* 距离 (KM)
*/
private BigDecimal distance;
}
private Location engineerDateLocation(String engineerCode) {
final LocalDate currentDate = LocalDate.now();
List<OrderInfoEntity> engineerDateOrderList = orderInfoDao.getEngineerDateOrder(engineerCode, DateUtils.formatDate(currentDate));
Set<String> ss = Set.of("CANCELED", "RESCHEDULED");
engineerDateOrderList = engineerDateOrderList.stream()
.filter(e -> !ss.contains(e.getOrderStatus()))
.collect(Collectors.toList());
Location location = new Location();
//查询工程师已开始的工单
Optional<OrderInfoEntity> startedOrder = engineerDateOrderList.stream()
.filter(e -> Objects.equals("STARTED", e.getServiceStatus()))
.max(Comparator.comparing(OrderInfoEntity::getPlanStartTime));
if (startedOrder.isPresent()) {
OrderInfoEntity startedOrderInfo = startedOrder.get();
location.setAddress(startedOrderInfo.getAddress());
location.setLongitude(Double.parseDouble(startedOrderInfo.getX()));
location.setLatitude(Double.parseDouble(startedOrderInfo.getY()));
return location;
}
//如果没有已开始的工单 查询 最后一个已完成工单
Optional<OrderInfoEntity> finishedOrder = engineerDateOrderList.stream()
.filter(e -> Objects.equals("FINISHED", e.getServiceStatus()))
.max(Comparator.comparing(OrderInfoEntity::getActualEndTime));
if (finishedOrder.isPresent()) {
OrderInfoEntity finishedOrderInfo = finishedOrder.get();
location.setAddress(finishedOrderInfo.getAddress());
location.setLongitude(Double.parseDouble(finishedOrderInfo.getX()));
location.setLatitude(Double.parseDouble(finishedOrderInfo.getY()));
} else {
// 如果都没有, 则获取工程师出发地址
EngineerBusinessEntity byEngineerCode = engineerBusinessDao.getByEngineerCode(engineerCode);
location.setAddress(byEngineerCode.getAddress());
location.setLongitude(StringUtils.isNotBlank(byEngineerCode.getX()) ? Double.parseDouble(byEngineerCode.getX()) : 0.0);
location.setLatitude(StringUtils.isNotBlank(byEngineerCode.getY()) ? Double.parseDouble(byEngineerCode.getY()) : 0.0);
}
return location;
return new ArrayList<>(engineerCodes1);
}
private Set<String> searchEngineerByRecommend(OrderInfoEntity order, String recommend) {
private Set<String> searchEngineerByRecommend(OrderInfoEntity order, String recommend, String userId) {
if (StringUtils.isNotEmpty(recommend) && recommend.equals("team")) {
return orgTeamEngineerDao.findAllByTeamId(order.getOrgTeamId()).stream().map(
OrgTeamEngineerEntity::getEngineerCode).collect(Collectors.toSet());
}
String levelType;
String levelValue;
String levelType = null;
String levelValue = null;
List<OrgTeamEntity> teams = new ArrayList<>();
if (StringUtils.isEmpty(recommend) || recommend.equals("branch")) {
levelType = "branch";
levelValue = order.getOrgBranchId();
} else if (recommend.equals("group")) {
levelType = "group";
levelValue = order.getOrgGroupId();
} else if (recommend.equals("all")) {
levelType = "cluster";
levelValue = order.getOrgClusterId();
} else if (recommend.equals("all") && StringUtils.isNotBlank(userId)) {
Result<List<OrgInfo>> listResult = userService.orgsNoName(userId);
if (CollectionUtils.isEmpty(listResult.getResult())) {
return new HashSet<>();
}
List<OrgInfo> orgInfos = listResult.getResult();
Integer orgLevel = orgInfos.get(0).getOrgLevel();
List<String> collect = orgInfos.stream().map(OrgInfo::getId).collect(Collectors.toList());
switch (orgLevel) {
case -1:
teams = orgTeamDao.findAll();
break;
case 0:
teams = orgTeamDao.findByClusterIdIn(collect);
break;
case 1:
teams = orgTeamDao.findByBranchIdIn(collect);
break;
case 2:
teams = orgTeamDao.findByGroupIdIn(collect);
break;
}
List<String> groupIds = teams.stream().map(OrgTeamEntity::getGroupId).collect(Collectors.toList());
return engineerInfoDao.findByGroupIdIn(groupIds).stream().map(EngineerInfoEntity::getEngineerCode).collect(Collectors.toSet());
} else {
return new HashSet<>();
}
List<OrgTeamEntity> teams = new ArrayList<>();
if (levelType.equals("cluster")) {
teams = orgTeamDao.findAllByClusterId(levelValue);
} else if (levelType.equals("branch")) {
......
......@@ -199,11 +199,21 @@ public class OrderCreateServiceImpl implements OrderCreateService {
OrderDTO.Estimate estimate = new OrderDTO.Estimate();
// 计算两点间距离
double distance = Stapial4jUtil.getDistance(location.getLatitude(), location.getLongitude(),
double distance = Stapial4jUtil.getDistance(location.getLongitude(), location.getLatitude(),
Double.parseDouble(orderInfo.getX()), Double.parseDouble(orderInfo.getY()));
estimate.setDistance(distance);
estimate.setArriveTime(palnDate);
if (Math.abs(distance) < 1e-15) {
estimate.setArriveTime(com.dituhui.pea.order.common.jackson.DateUtil.toDate(orderInfo.getActualStartTime()));
} else {
//当前时间 加大概需要的时间
//计算大概时间, 电动车 19KM/H
double speed = 0.3167;
LocalDateTime localDateTime = LocalDateTime.now().plusMinutes((int) Math.ceil(distance / speed));
estimate.setArriveTime(com.dituhui.pea.order.common.jackson.DateUtil.toDate(localDateTime));
}
realtimeInfo.setEstimate(estimate);
stageResult.setRealtimeInfo(realtimeInfo);
......@@ -295,8 +305,10 @@ public class OrderCreateServiceImpl implements OrderCreateService {
entity.setBeanTags(joinTags);
entity.setIsMultiple(joinTags.contains("重物搬运") ? 1 : 0);
entity.setBeanPriority(req.getPriority());
if (req.getPriority().equals("1") && !DateUtil.judgeTimeIsToday(entity.getExpectTimeBegin())) {
if (req.getPriority().equals("1")) {
if (!DateUtil.judgeTimeIsToday(entity.getExpectTimeBegin())) {
entity.setAppointmentMethod(AppointmentMethodEnum.AUTO_NOW.name());
}
tags.add(OrderPeaTagsEnum.urgent.getTag());
//发送通知分部消息
// sendMsg(entity.getOrgBranchId(), orderId, entity.getExpectTimeBegin().toLocalDate());
......@@ -430,6 +442,9 @@ public class OrderCreateServiceImpl implements OrderCreateService {
if (special == 1) {
tags.add(OrderPeaTagsEnum.special.getTag());
}
if (CollectionUtils.isNotEmpty(tags)) {
tags = tags.stream().filter(e -> StringUtils.isNotBlank(e)).collect(Collectors.toList());
}
MsgDTO msgDTO = new MsgDTO();
msgDTO.setBranchId(branchId);
msgDTO.setType(0);
......
......@@ -7,6 +7,7 @@ import com.dituhui.pea.common.Result;
import com.dituhui.pea.common.ResultEnum;
import com.dituhui.pea.dispatch.IPath;
import com.dituhui.pea.enums.StatusCodeEnum;
import com.dituhui.pea.order.common.OccupyInfoDetail;
import com.dituhui.pea.order.common.TimeUtils;
import com.dituhui.pea.order.common.jackson.JsonUtil;
import com.dituhui.pea.order.constant.OrderReschedulingReason;
......@@ -74,6 +75,9 @@ public class OrderInfoServiceImpl implements OrderInfoService {
@Autowired
private IPath pathService;
@Autowired
private EngineerCalendarService engineerCalendarService;
/**
* 新增订单处理一家多单逻辑
......@@ -452,29 +456,27 @@ public class OrderInfoServiceImpl implements OrderInfoService {
@Transactional
@Override
public Result<OrderInfoEntity> insterEngineerOrders(List<OrderInfoEntity> engineerOrders, OrderInfoEntity insertOrder, SkillInfoEntity skillInfo, OrgTeamEntity orgTeam, EngineerInfoEntity engineer) {
// 没有单直接返回
// 获取团队工作起止时间
String[] teamWorkStartTime = orgTeam.getWorkOn().split(":");
String[] teamWorkEndTime = orgTeam.getWorkOff().split(":");
LocalDateTime startTeam = insertOrder.getDt().atTime(Integer.parseInt(teamWorkStartTime[0]), Integer.parseInt(teamWorkStartTime[1]), 0);
LocalDateTime endTeam = insertOrder.getDt().atTime(Integer.parseInt(teamWorkEndTime[0]), Integer.parseInt(teamWorkEndTime[1]), 0);
// 获取客户期望时间段
LocalDateTime start = insertOrder.getExpectTimeBegin();
LocalDateTime end = insertOrder.getExpectTimeEnd();
LocalDateTime workStartTime = insertOrder.getExpectTimeBegin();
LocalDateTime workEndTime = insertOrder.getExpectTimeEnd();
//查询工程师当天出勤时间
// List<OccupyInfoDetail> engineerWorkTimeSlice = engineerCalendarService.timeWindowsSlice(engineer.getEngineerCode(), orgTeam.getTeamId(), insertOrder.getDt());
//查询工程师当天请假时间
List<OccupyInfoDetail> engineerLeaveTimeSlice = engineerCalendarService.getEngineerWorkDayCalendar(engineer.getEngineerCode(), insertOrder.getDt());
log.info("【engineerWorkTimeSlice】结果------------->{}", JsonUtil.toJson(engineerLeaveTimeSlice));
// 没有单直接返回
if (CollectionUtils.isEmpty(engineerOrders)) {
// 特殊时间不插单
if (LocalDateTime.now().isBefore(startTeam) || LocalDateTime.now().isAfter(endTeam) || end.isAfter(endTeam) || end.isBefore(startTeam)) {
LocalDateTime planStartTime = handleLeaveTime(engineerLeaveTimeSlice, insertOrder.getExpectTimeBegin(), insertOrder.getExpectTimeEnd(), skillInfo.getTakeTime());
if (ObjectUtil.isNull(planStartTime)) {
return Result.failed(insertOrder);
}
insertOrder.setTakeTime(skillInfo.getTakeTime());
insertOrder.setPlanStartTime(insertOrder.getExpectTimeBegin());
insertOrder.setPlanEndTime(insertOrder.getExpectTimeBegin().plusMinutes(skillInfo.getTakeTime()));
insertOrder.setPlanStartTime(planStartTime);
insertOrder.setPlanEndTime(planStartTime.plusMinutes(skillInfo.getTakeTime()));
return Result.success(insertOrder);
}
int takeTime = skillInfo.getTakeTime();
// 计算最早派工和最晚派工时间
LocalDateTime workStartTime = start.isAfter(startTeam) ? start : startTeam;
LocalDateTime workEndTime = end.isBefore(endTeam) ? end : endTeam;
// 订单工作时间顺序排序
List<OrderSegment> orderSegments = new ArrayList<>();
for (OrderInfoEntity orderInfo : engineerOrders) {
......@@ -493,9 +495,13 @@ public class OrderInfoServiceImpl implements OrderInfoService {
}
// 没有单直接返回
if (CollectionUtils.isEmpty(orderSegments)) {
LocalDateTime planStartTime = handleLeaveTime(engineerLeaveTimeSlice, insertOrder.getExpectTimeBegin(), insertOrder.getExpectTimeEnd(), skillInfo.getTakeTime());
if (ObjectUtil.isNull(planStartTime)) {
return Result.failed(insertOrder);
}
insertOrder.setTakeTime(skillInfo.getTakeTime());
insertOrder.setPlanStartTime(insertOrder.getExpectTimeBegin());
insertOrder.setPlanEndTime(insertOrder.getExpectTimeBegin().plusMinutes(skillInfo.getTakeTime()));
insertOrder.setPlanStartTime(planStartTime);
insertOrder.setPlanEndTime(planStartTime.plusMinutes(skillInfo.getTakeTime()));
return Result.success(insertOrder);
}
orderSegments = orderSegments.stream().sorted(Comparator.comparing(OrderSegment::getStart)).collect(Collectors.toList());
......@@ -511,11 +517,13 @@ public class OrderInfoServiceImpl implements OrderInfoService {
int roadTime = distanceDTO.getTime() / 1000;
// 先判断第一单开始时间
if (i == 0 && orderSegment.getStart().compareTo(workStartTime.plusMinutes(takeTime + roadTime)) >= 0) {
LocalDateTime planStartTime = handleLeaveTime(engineerLeaveTimeSlice, insertOrder.getExpectTimeBegin(), insertOrder.getExpectTimeEnd(), skillInfo.getTakeTime());
if (ObjectUtil.isNull(planStartTime)) {
return Result.failed(insertOrder);
}
insertOrder.setTakeTime(skillInfo.getTakeTime());
// insertOrder.setArriveDistance(roadTime);
// insertOrder.setArriveDistance(Integer.valueOf(String.valueOf(distanceDTO.getDis() * 1000)));
insertOrder.setPlanStartTime(insertOrder.getExpectTimeBegin());
insertOrder.setPlanEndTime(insertOrder.getExpectTimeBegin().plusMinutes(skillInfo.getTakeTime()));
insertOrder.setPlanStartTime(planStartTime);
insertOrder.setPlanEndTime(planStartTime.plusMinutes(skillInfo.getTakeTime()));
OrderInfoEntity nestOrder = orderInfoDao.getByOrderId(orderSegment.getOrderId());
nestOrder.setArriveDistance(roadTime);
......@@ -529,11 +537,18 @@ public class OrderInfoServiceImpl implements OrderInfoService {
if (workEndTime.compareTo(orderSegment.getEnd().plusMinutes(takeTime + roadTime)) < 0) {
return Result.failed(insertOrder);
}
insertOrder.setTakeTime(skillInfo.getTakeTime());
insertOrder.setArriveDistance(roadTime);
// 判断工单开始时间
LocalDateTime planStartTime = insertOrder.getExpectTimeBegin().compareTo(orderSegment.getEnd().plusMinutes(roadTime)) >= 0 ?
insertOrder.getExpectTimeBegin() : orderSegment.getEnd().plusMinutes(roadTime);
planStartTime = handleLeaveTime(engineerLeaveTimeSlice, planStartTime, insertOrder.getExpectTimeEnd(), skillInfo.getTakeTime());
if (ObjectUtil.isNull(planStartTime)) {
return Result.failed(insertOrder);
}
insertOrder.setArriveElapsed(roadTime);
insertOrder.setArriveDistance(BigDecimal.valueOf(distanceDTO.getDis() * 1000).intValue());
insertOrder.setPlanStartTime(orderSegment.getEnd().plusMinutes(roadTime));
insertOrder.setPlanEndTime(orderSegment.getEnd().plusMinutes(takeTime + roadTime));
insertOrder.setTakeTime(skillInfo.getTakeTime());
insertOrder.setPlanStartTime(planStartTime);
insertOrder.setPlanEndTime(planStartTime.plusMinutes(skillInfo.getTakeTime()));
return Result.success(insertOrder);
}
// 当前单在中间
......@@ -545,15 +560,22 @@ public class OrderInfoServiceImpl implements OrderInfoService {
continue;
}
if (nestOrderSegment.getStart().minusMinutes(roadResult2.getResult().getTime() / 1000).compareTo(orderSegment.getEnd().plusMinutes(takeTime + roadTime)) >= 0) {
// 判断工单开始时间
LocalDateTime planStartTime = insertOrder.getExpectTimeBegin().compareTo(orderSegment.getEnd().plusMinutes(roadTime)) >= 0 ?
insertOrder.getExpectTimeBegin() : orderSegment.getEnd().plusMinutes(roadTime);
planStartTime = handleLeaveTime(engineerLeaveTimeSlice, planStartTime, insertOrder.getExpectTimeEnd(), skillInfo.getTakeTime());
if (ObjectUtil.isNull(planStartTime)) {
return Result.failed(insertOrder);
}
insertOrder.setArriveElapsed(roadTime);
insertOrder.setArriveDistance(BigDecimal.valueOf(distanceDTO.getDis() * 1000).intValue());
insertOrder.setTakeTime(skillInfo.getTakeTime());
insertOrder.setArriveDistance(roadTime);
insertOrder.setArriveElapsed(BigDecimal.valueOf(distanceDTO.getDis() * 1000).intValue());
insertOrder.setPlanStartTime(orderSegment.getEnd().plusMinutes(roadTime));
insertOrder.setPlanEndTime(orderSegment.getEnd().plusMinutes(takeTime + roadTime));
insertOrder.setPlanStartTime(planStartTime);
insertOrder.setPlanEndTime(planStartTime.plusMinutes(skillInfo.getTakeTime()));
OrderInfoEntity nestOrder = orderInfoDao.getByOrderId(nestOrderSegment.getOrderId());
nestOrder.setArriveDistance(roadResult2.getResult().getTime() / 1000);
nestOrder.setArriveElapsed(BigDecimal.valueOf(roadResult2.getResult().getDis() * 1000).intValue());
nestOrder.setArriveElapsed(roadResult2.getResult().getTime() / 1000);
nestOrder.setArriveDistance(BigDecimal.valueOf(roadResult2.getResult().getDis() * 1000).intValue());
orderInfoDao.save(nestOrder);
return Result.success(insertOrder);
}
......@@ -561,6 +583,56 @@ public class OrderInfoServiceImpl implements OrderInfoService {
return Result.failed(insertOrder);
}
/**
* 处理工程师请假时间和工单计划开始时间
*
* @param engineerLeaveTimeSlice
* @param expectTimeBegin
* @param expectTimeEnd
* @return 工单计划开始时间
*/
private LocalDateTime handleLeaveTime(List<OccupyInfoDetail> engineerLeaveTimeSlice, LocalDateTime expectTimeBegin, LocalDateTime expectTimeEnd, Integer takeTime) {
if (CollectionUtils.isEmpty(engineerLeaveTimeSlice)) {
return expectTimeBegin;
}
for (int i = 0; i < engineerLeaveTimeSlice.size(); i++) {
OccupyInfoDetail occupyInfoDetail = engineerLeaveTimeSlice.get(i);
// 处理请假开始时间
if (expectTimeBegin.plusMinutes(takeTime).compareTo(occupyInfoDetail.getBeginTime()) <= 0) {
return expectTimeBegin;
}
if (expectTimeEnd.compareTo(occupyInfoDetail.getEndTime().plusMinutes(takeTime)) >= 0) {
return expectTimeBegin.compareTo(occupyInfoDetail.getEndTime()) >= 0 ? expectTimeBegin : occupyInfoDetail.getEndTime();
}
return null;
}
return null;
}
/**
* 处理工程师出勤时间和工单计划开始时间
*
* @param engineerWorkTimeSlice
* @param expectTimeBegin
* @param expectTimeEnd
* @return 工单计划开始时间
*/
private LocalDateTime handleWorkTime(List<OccupyInfoDetail> engineerWorkTimeSlice, LocalDateTime expectTimeBegin, LocalDateTime expectTimeEnd, Integer takeTime) {
if (CollectionUtils.isEmpty(engineerWorkTimeSlice)) {
return null;
}
for (int i = 0; i < engineerWorkTimeSlice.size(); i++) {
OccupyInfoDetail occupyInfoDetail = engineerWorkTimeSlice.get(i);
LocalDateTime planStartTime = expectTimeBegin.compareTo(occupyInfoDetail.getBeginTime()) >= 0 ? expectTimeBegin : occupyInfoDetail.getBeginTime();
LocalDateTime planEndTime = expectTimeEnd.compareTo(occupyInfoDetail.getEndTime()) <= 0 ? expectTimeEnd : occupyInfoDetail.getEndTime();
if (planStartTime.plusMinutes(takeTime).compareTo(planEndTime) > 0) {
continue;
}
return planStartTime;
}
return null;
}
/**
* 订单重新分单
......
......@@ -79,6 +79,7 @@ public class OrderServiceDetailImpl implements OrderServiceDetail {
res.setSkill(order.getSkill());
res.setFaultDescribe(order.getFaultDescribe());
res.setExpectTimeBegin(TimeUtils.IsoLocalDateTime2String(order.getExpectTimeBegin()));
res.setExpectTimeEnd(TimeUtils.IsoLocalDateTime2String(order.getExpectTimeEnd()));
res.setExpectTimeDesc(order.getExpectTimeDesc());
res.setSource(order.getSource());
res.setTags(order.getTags());
......
......@@ -44,15 +44,11 @@ public class OrderServiceListServiceImpl implements OrderServiceListService {
//分页
Page<OrderInfo> pg = new Page(reqDTO.getPage(), reqDTO.getSize());
LocalDate startDate = TimeUtils.IsoDate2LocalDate(reqDTO.getStartDate());
LocalDate endDate = TimeUtils.IsoDate2LocalDate(reqDTO.getEndDate());
LambdaQueryWrapper<OrderInfo> lqw = new LambdaQueryWrapper<>();
lqw.eq(reqDTO.getLevelType().equals("cluster"), OrderInfo::getOrgClusterId, reqDTO.getLevelValue());
lqw.eq(reqDTO.getLevelType().equals("branch"), OrderInfo::getOrgBranchId, reqDTO.getLevelValue());
lqw.eq(reqDTO.getLevelType().equals("group"), OrderInfo::getOrgGroupId, reqDTO.getLevelValue());
lqw.ge(OrderInfo::getDt, startDate); //预约开始日期
lqw.le(OrderInfo::getDt, endDate); //预约开始日期
lqw.eq(OrderInfo::getDt, reqDTO.getDate()); //预约开始日期
//筛选项
if (StringUtils.isNotBlank(reqDTO.getOrderId())) {
lqw.in(StringUtils.isNotEmpty(reqDTO.getOrderId()), OrderInfo::getOrderId, reqDTO.getOrderId().split(","));
......@@ -160,6 +156,9 @@ public class OrderServiceListServiceImpl implements OrderServiceListService {
record.setAddressId(o.getAddressId());
record.setIsCutoff(o.getIsCutoff());
record.setReschedulingReason(o.getReschedulingReason());
record.setEngineerName(o.getEngineerName());
record.setEngineerCode(o.getEngineerCode());
record.setEngineerPhone(o.getEngineerPhone());
record.setActualStartTime(ObjectUtil.isNull(o.getActualStartTime()) ? "" : TimeUtils.IsoTimestamp2DateTime(o.getActualStartTime()));
record.setActualEndTime(ObjectUtil.isNull(o.getActualEndTime()) ? "" : TimeUtils.IsoTimestamp2DateTime(o.getActualEndTime()));
......
......@@ -23,9 +23,11 @@ import com.dituhui.pea.order.entity.MapBlockInfoEntity;
import com.dituhui.pea.order.entity.OrderInfoEntity;
import com.dituhui.pea.order.entity.OrgGroupEntity;
import com.dituhui.pea.order.enums.AppointmentMethodEnum;
import com.dituhui.pea.order.enums.OrderEventEnum;
import com.dituhui.pea.order.enums.OrderFlowEnum;
import com.dituhui.pea.order.enums.OrderStatusEnum;
import com.dituhui.pea.order.enums.ServiceStatusEnum;
import com.dituhui.pea.order.service.CommonService;
import com.dituhui.pea.order.service.PeaOuterAPIService;
import com.dituhui.pea.pojo.fendan.FendanDTO;
import lombok.RequiredArgsConstructor;
......@@ -63,6 +65,7 @@ public class PeaOuterAPIServiceImpl implements PeaOuterAPIService {
private final SaasUtils saasUtils;
private final MapBlockInfoDao mapBlockInfoDao;
private final EngineerInfoDao engineerInfoDao;
private final CommonService commonService;
@Override
public EstimateDTO.VisitResult estimateVisitService(String brand, String productType, String serviceType, Location clientLocation) {
......@@ -174,7 +177,7 @@ public class PeaOuterAPIServiceImpl implements PeaOuterAPIService {
orderInfo.setAppointmentStatus(String.valueOf(OrderFlowEnum.CONFIRM));
orderInfo.setServiceStatus(ServiceStatusEnum.CONTACTED.getCode());
orderInfo.setOrderStatus(OrderStatusEnum.RESCHEDULED.getCode());
orderInfo.setAppointmentStatus(String.valueOf(AppointmentMethodEnum.AUTO_NOW));
orderInfo.setAppointmentMethod(String.valueOf(AppointmentMethodEnum.AUTO_NOW));
orderInfo.setEngineerCode(engineerInfo.getEngineerCode());
orderInfo.setEngineerName(engineerInfo.getName());
// 更新上门时间, 结束时间
......@@ -187,7 +190,16 @@ public class PeaOuterAPIServiceImpl implements PeaOuterAPIService {
orderInfo.setReasonForFailure(request.getReasonForFailure());
orderInfoDao.save(orderInfo);
String memo;
if (Objects.equals(request.getAppointmentResult(), "CONFIRMED")) {
//TODO 回调BEAN 改约接口
memo = "SUCCESS";
} else {
memo = "FAIL:" + request.getReasonForFailure();
}
String msg = String.format(OrderEventEnum.reassignment.getMsg(), engineerInfo.getName());
commonService.addOrderEvent(orderInfo.getOrderId(), "", "BEAN", "BEAN", OrderEventEnum.reassignment.getEvent(),
msg, memo, LocalDateTime.now());
OrderConfirmResult orderConfirmResult = new OrderConfirmResult();
orderConfirmResult.setOrderId(orderId);
orderConfirmResult.setEngineerCode(engineerInfo.getEngineerCode());
......
package com.dituhui.pea.order.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dituhui.pea.common.Result;
import com.dituhui.pea.order.common.DateUtils;
......@@ -91,7 +92,16 @@ public class WorkbenchServiceImpl implements WorkbenchService {
HashMap<String, Long> statusSummary = this.transOrderStatus(this.queryCountByOrderStatus(levelType, levelValue, dt));
WorkbenchSummaryResp.ItemDTO statusItem = new WorkbenchSummaryResp.ItemDTO();
statusItem.setType("order");
statusItem.setRows(this.packValueOrderStatus(statusSummary));
List<WorkbenchSummaryResp.ValueDTO> valueDTOS = this.packValueOrderStatus(statusSummary);
// - 已改约:预约单状态为“已改约”的工单.
HashMap<String, List<String>> p5 = this.packParams("appointmentStatus", "RESCHEDULED");
valueDTOS.add(new WorkbenchSummaryResp.ValueDTO("已改约", queryRescheduledNum(levelType, levelValue, dt), null, null, "", p5));
// - 已延误:已到开始时间,TARO没有反馈开始的工单.
valueDTOS.add(new WorkbenchSummaryResp.ValueDTO("已延误", queryDelayNum(levelType, levelValue, dt), null, "#FF3D44", "", new HashMap<>()));
statusItem.setRows(valueDTOS);
// - 已超时:已到开始时间,TARO没有反馈开始的工单.
valueDTOS.add(new WorkbenchSummaryResp.ValueDTO("已超时", queryOvertimeNum(levelType, levelValue, dt), null, "#FF3D44", "", new HashMap<>()));
statusItem.setRows(valueDTOS);
items.add(statusItem);
WorkbenchSummaryResp res = new WorkbenchSummaryResp();
......@@ -99,6 +109,83 @@ public class WorkbenchServiceImpl implements WorkbenchService {
return Result.success(res);
}
private String queryOvertimeNum(String levelType, String levelValue, LocalDate dt) {
if ("cluster".equals(levelType)) {
long clusterCount = orderInfoDao.countOvertimeByDtAndOrgClusterId(dt, levelValue);
return String.valueOf(clusterCount);
} else if ("branch".equals(levelType)) {
long branchCount = orderInfoDao.countOvertimeByDtAndOrgBranchId(dt, levelValue);
return String.valueOf(branchCount);
} else if ("group".equals(levelType)) {
long groupCount = orderInfoDao.countOvertimeByDtAndOrgGroupId(dt, levelValue);
return String.valueOf(groupCount);
}
return "0";
}
/**
* 查询延误工单数据
*
* @param levelType
* @param levelValue
* @param dt
* @return
*/
private String queryDelayNum(String levelType, String levelValue, LocalDate dt) {
if ("cluster".equals(levelType)) {
long clusterCount = orderInfoDao.countDelayByDtAndOrgClusterId(dt, levelValue);
return String.valueOf(clusterCount);
} else if ("branch".equals(levelType)) {
long branchCount = orderInfoDao.countDelayByDtAndOrgBranchId(dt, levelValue);
return String.valueOf(branchCount);
} else if ("group".equals(levelType)) {
long groupCount = orderInfoDao.countDelayByDtAndOrgGroupId(dt, levelValue);
return String.valueOf(groupCount);
}
return "0";
}
/**
* 查询改约工单数据
*
* @param levelType
* @param levelValue
* @param dt
* @return
*/
private String queryRescheduledNum(String levelType, String levelValue, LocalDate dt) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Object[]> criteriaQuery = criteriaBuilder.createQuery(Object[].class);
Root<OrderInfoEntity> root = criteriaQuery.from(OrderInfoEntity.class);
criteriaQuery.multiselect(
criteriaBuilder.count(root).alias("count")
);
Predicate datePredicate = criteriaBuilder.equal(root.get("dt"), dt);
Predicate orderStatusPredicate = criteriaBuilder.equal(root.get("orderStatus"), "RESCHEDULED");
Predicate levelPredicate = null;
if ("cluster".equals(levelType)) {
levelPredicate = criteriaBuilder.equal(root.get("orgClusterId"), levelValue);
} else if ("branch".equals(levelType)) {
levelPredicate = criteriaBuilder.equal(root.get("orgBranchId"), levelValue);
} else if ("group".equals(levelType)) {
levelPredicate = criteriaBuilder.equal(root.get("orgGroupId"), levelValue);
}
if (levelPredicate != null) {
criteriaQuery.where(orderStatusPredicate, datePredicate, levelPredicate);
} else {
criteriaQuery.where(orderStatusPredicate, datePredicate);
}
TypedQuery<Object[]> typedQuery = entityManager.createQuery(criteriaQuery);
List<Object[]> results = typedQuery.getResultList();
String rescheduledNum = String.valueOf(ObjectUtil.isNull(results.get(0)) ? "0" : results.get(0));
return rescheduledNum;
}
private List<Map<String, Object>> queryCountByAppointmentMethod(String levelType, String levelValue, LocalDate dt) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Object[]> criteriaQuery = criteriaBuilder.createQuery(Object[].class);
......@@ -262,31 +349,27 @@ public class WorkbenchServiceImpl implements WorkbenchService {
String urlName = ""; // 不返回,前端就不跳转了
Long assigned = summary.getOrDefault("INIT", 0L);
Long contacted = summary.getOrDefault("CONTACTED", 0L);
Long pending = summary.getOrDefault("PENDING", 0L);
Long dealing = assigned + pending;
Long dealing = contacted + pending;
Long started = summary.getOrDefault("STARTED", 0L);
Long finished = summary.getOrDefault("FINISHED", 0L) + summary.getOrDefault("UNFINISHED", 0L);
Long cancel = 0L;
HashMap<String, List<String>> p1 = this.packParams("appointmentStatus", "ASSIGNED", "CONTACTED", "DEPARTED");
Long cancel = summary.getOrDefault("1", 0L);
// 服务状态:INIT-初始化/PENDING待服务/CONTACTED已排期/STARTED-已开始/FINISHED已完成/UNFINISHED-已上门未完成
// - 待上门:服务状态为“待服务、已排期”的工单.
HashMap<String, List<String>> p1 = this.packParams("appointmentStatus", "CONTACTED", "PENDING");
items.add(new WorkbenchSummaryResp.ValueDTO("待上门", dealing.toString(), null, "#469967", urlName, p1));
// - 服务中:服务状态为“已开始”的工单.
HashMap<String, List<String>> p2 = this.packParams("appointmentStatus", "STARTED");
items.add(new WorkbenchSummaryResp.ValueDTO("服务中", started.toString(), null, "#016FFF", urlName, p2));
// - 已完成:服务状态为“已完成”的工单.
HashMap<String, List<String>> p3 = this.packParams("appointmentStatus", "FINISHED");
items.add(new WorkbenchSummaryResp.ValueDTO("已完成", finished.toString(), null, null, urlName, p3));
// - 已取消:预约单状态为“已取消”的工单.
HashMap<String, List<String>> p4 = this.packParams("appointmentStatus", "CANCELED");
items.add(new WorkbenchSummaryResp.ValueDTO("已取消", cancel.toString(), null, null, urlName, p4));
HashMap<String, List<String>> p5 = this.packParams("appointmentStatus", "RESCHEDULED");
items.add(new WorkbenchSummaryResp.ValueDTO("已改约", "0", null, null, urlName, p5));
items.add(new WorkbenchSummaryResp.ValueDTO("已延误", "0", null, "#FF3D44", urlName, new HashMap<>()));
return items;
}
......
......@@ -18,4 +18,17 @@ public class OrderUtil {
return order;
}
/**
* 分单,超派,特殊时间等处理工单指派工程师,网点等数据
*
* @param order
* @return
*/
public static OrderInfoEntity handleErrorOrder2(OrderInfoEntity order) {
order.setEngineerPhone(null);
order.setEngineerName(null);
order.setEngineerCode(null);
return order;
}
}
package com.dituhui.pea.order.scheduler;
import com.dituhui.pea.order.OrderServiceApplication;
import com.dituhui.pea.order.service.EngineerCalendarService;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDate;
@SpringBootTest(classes = OrderServiceApplication.class)
class CalcEngineerCapacitySchedulerTest {
@Autowired
private CalcEngineerCapacityScheduler calcEngineerCapacityScheduler;
@Autowired
private CalcOrgCapacityScheduler calcOrgCapacityScheduler;
@Autowired
private EngineerCalendarService engineerCalendarService;
@Test
void calcOneEngineer() {
// calcEngineerCapacityScheduler.calcOneEngineer("2023-11-09", "6200044665");
// calcEngineerCapacityScheduler.calcOneEngineer("2023-11-15", "G20210H1301-jiangbei");
// calcOrgCapacityScheduler.calcAllGroupByDays("2023-11-14", "2023-11-17");
}
@Test
void engineerTimeWindow() {
// int[][] ints = engineerCalendarService.timeWindows("6200043046", "1716782616477233152", LocalDate.now().plusDays(1));
// Assertions.assertEquals(480, ints[0][0]);
}
}
\ No newline at end of file
......@@ -166,4 +166,11 @@ public class UserController implements IUser {
return Result.success(orgInfos);
}
@Override
public Result<List<OrgInfo>> orgsNoName(String userId) {
List<OrgInfo> orgInfos = userService.orgsNoName(userId);
return Result.success(orgInfos);
}
}
......@@ -887,4 +887,32 @@ public class UserService {
});
return orgInfos;
}
public List<OrgInfo> orgsNoName(String userId) {
List<OrgInfo> orgInfos = new ArrayList<>();
// 获取角色
List<UserRoleEntity> userRoles = userRoleDao.findByUserId(userId);
if (CollectionUtils.isEmpty(userRoles)) {
return null;
}
List<String> ids = userRoles.stream().map(r -> r.getRoleId()).collect(Collectors.toList());
if (ids.contains(Globals.SUPER_ADMIN_ID)) {
OrgInfo orgInfo = new OrgInfo();
orgInfo.setId("admin");
orgInfo.setOrgLevel(-1);
orgInfos.add(orgInfo);
return orgInfos;
}
List<UserOrgEntity> byUserId = userOrgDao.findByUserId(userId);
if (CollectionUtils.isEmpty(byUserId)) {
return orgInfos;
}
byUserId.forEach(e -> {
OrgInfo orgInfo = new OrgInfo();
orgInfo.setId(e.getOrgId());
orgInfo.setOrgLevel(e.getOrgLevel());
orgInfos.add(orgInfo);
});
return orgInfos;
}
}
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!