Commit 6a240d23 by 刘鑫

Merge branch 'develop' of https://gitlab.dituhui.com/bsh/project/project into develop

2 parents bb3c8ace 5d7a522a
...@@ -30,7 +30,7 @@ public interface DispatchOrderRepository extends CrudRepository<DispatchOrder, L ...@@ -30,7 +30,7 @@ public interface DispatchOrderRepository extends CrudRepository<DispatchOrder, L
List<DispatchOrder> findAllWithoutConfirm(String groupId, String batchNo); List<DispatchOrder> findAllWithoutConfirm(String groupId, String batchNo);
// 查看算法指派成功(也有抹掉技术员、时间情况),非confirm状态的 // 查看算法指派成功(也有抹掉技术员、时间情况),非confirm状态的
@Query("from DispatchOrder where teamId=?1 and batchNo=?2 and status !='CONFIRM' ") @Query("from DispatchOrder where teamId=?1 and batchNo=?2 ")
List<DispatchOrder> findAllWithoutConfirm2(String teamId, String batchNo); List<DispatchOrder> findAllWithoutConfirm2(String teamId, String batchNo);
Optional<DispatchOrder> findByGroupIdAndBatchNoAndOrderIdAndDt(String groupId, String batchNo, String orderId, String dt); Optional<DispatchOrder> findByGroupIdAndBatchNoAndOrderIdAndDt(String groupId, String batchNo, String orderId, String dt);
......
...@@ -20,8 +20,11 @@ import lombok.Setter; ...@@ -20,8 +20,11 @@ import lombok.Setter;
public class Customer { public class Customer {
private long id; private long id;
private String code; private String code;
private String status;
// 已分配 // 已分配
private String dispatchedTechnicianCode; private String dispatchedTechnicianCode;
// 已排除 // 已排除
...@@ -56,7 +59,7 @@ public class Customer { ...@@ -56,7 +59,7 @@ public class Customer {
} }
public Customer(long id, String code, String dt, Location location, int startTime, int endTime, String requiredSkill, public Customer(long id, String code, String dt, Location location, int startTime, int endTime, String requiredSkill,
int serviceDuration) { int serviceDuration, String status) {
this.id = id; this.id = id;
this.code = code; this.code = code;
this.dt = dt; this.dt = dt;
...@@ -65,6 +68,7 @@ public class Customer { ...@@ -65,6 +68,7 @@ public class Customer {
this.endTime = endTime; this.endTime = endTime;
this.requiredSkill = requiredSkill; this.requiredSkill = requiredSkill;
this.serviceDuration = serviceDuration; this.serviceDuration = serviceDuration;
this.status = status;
} }
@InverseRelationShadowVariable(sourceVariableName = "customerList") @InverseRelationShadowVariable(sourceVariableName = "customerList")
......
...@@ -26,7 +26,7 @@ public interface ExtractService { ...@@ -26,7 +26,7 @@ public interface ExtractService {
/* /*
* 按小队将dispath_order 中的计算结果,回写到 order_info * 按小队将dispath_order 中的计算结果,回写到 order_info
* */ * */
void extractDispatchToOrder2(String TeamId, String batchNo, boolean isConfirm) ; void extractDispatchToOrder2(String TeamId, String batchNo, boolean cutOff) ;
} }
...@@ -49,7 +49,7 @@ public class ExtractServiceImpl implements ExtractService { ...@@ -49,7 +49,7 @@ public class ExtractServiceImpl implements ExtractService {
@Autowired @Autowired
OrderInfoRepository orderInfoRepo; OrderInfoRepository orderInfoRepo;
@Autowired @Autowired
OrgTeamEngineerDao orgTeamEngineerDao; OrgTeamEngineerDao orgTeamEngineerDao;
...@@ -179,132 +179,135 @@ public class ExtractServiceImpl implements ExtractService { ...@@ -179,132 +179,135 @@ public class ExtractServiceImpl implements ExtractService {
log.info("算法结果更新到工单完成, groupId:{}, batchNo:{}", groupId, batchNo); log.info("算法结果更新到工单完成, groupId:{}, batchNo:{}", groupId, batchNo);
} }
/** /**
* 将dispath_order 中的计算结果,回写到 order_info * 将dispath_order 中的计算结果,回写到 order_info
* order_info(主要更新状态) * order_info(主要更新状态)
*/ */
@Transactional(isolation = READ_COMMITTED, propagation = Propagation.REQUIRED) @Transactional(isolation = READ_COMMITTED, propagation = Propagation.REQUIRED)
@Override @Override
public void extractDispatchToOrder2(String teamId, String batchNo, boolean isConfirm) { public void extractDispatchToOrder2(String teamId, String batchNo, boolean cutOff) {
log.info("算法结果更新到工单, teamId:{}, batchNo:{}", teamId, batchNo); log.info("算法结果更新到工单, teamId:{}, batchNo:{}", teamId, batchNo);
entityManager.clear(); entityManager.clear();
// 工程师数据准备 // 工程师数据准备
// Map<String, EngineerInfo> engineerInfoMap = // Map<String, EngineerInfo> engineerInfoMap =
// engineerInfoRepo.findByGroupId(groupId).stream().collect(Collectors.toMap(EngineerInfo::getEngineerCode, // engineerInfoRepo.findByGroupId(groupId).stream().collect(Collectors.toMap(EngineerInfo::getEngineerCode,
// y -> y)); // y -> y));
final Map<String, EngineerInfo> engineerInfoMap = Maps.newHashMap(); final Map<String, EngineerInfo> engineerInfoMap = Maps.newHashMap();
List<OrgTeamEngineerEntity> engineers = orgTeamEngineerDao.findAllByTeamId(teamId); List<OrgTeamEngineerEntity> engineers = orgTeamEngineerDao.findAllByTeamId(teamId);
if (CollectionUtils.isNotEmpty(engineers)) { if (CollectionUtils.isNotEmpty(engineers)) {
List<String> codes = engineers.stream().map(o -> o.getEngineerCode()).collect(Collectors.toList()); List<String> codes = engineers.stream().map(o -> o.getEngineerCode()).collect(Collectors.toList());
List<EngineerInfo> engineers2 = engineerInfoRepo.findByEngineerCodeIn(codes); List<EngineerInfo> engineers2 = engineerInfoRepo.findByEngineerCodeIn(codes);
if (CollectionUtils.isNotEmpty(engineers2)) { if (CollectionUtils.isNotEmpty(engineers2)) {
engineerInfoMap engineerInfoMap
.putAll(engineers2.stream().collect(Collectors.toMap(EngineerInfo::getEngineerCode, y -> y))); .putAll(engineers2.stream().collect(Collectors.toMap(EngineerInfo::getEngineerCode, y -> y)));
} }
} }
List<DispatchOrder> dispatchOrderList = dispatchOrderRepo.findAllWithoutConfirm2(teamId, batchNo); List<DispatchOrder> dispatchOrderList = dispatchOrderRepo.findAllWithoutConfirm2(teamId, batchNo);
log.info("算法结果更新到工单, step1-开始处理, teamId:{}, batchNo:{}, order-size:{}", teamId, batchNo, dispatchOrderList.size()); log.info("算法结果更新到工单, step1-开始处理, teamId:{}, batchNo:{}, order-size:{}", teamId, batchNo, dispatchOrderList.size());
AtomicInteger atomicInteger = new AtomicInteger(); AtomicInteger atomicInteger = new AtomicInteger();
dispatchOrderList.forEach(dispatchOrder -> { dispatchOrderList.forEach(dispatchOrder -> {
int idx = atomicInteger.getAndIncrement(); int idx = atomicInteger.getAndIncrement();
String orderId = dispatchOrder.getOrderId(); String orderId = dispatchOrder.getOrderId();
String dt = dispatchOrder.getDt(); String dt = dispatchOrder.getDt();
String engCode = dispatchOrder.getEngineerCode(); String engCode = dispatchOrder.getEngineerCode();
log.info("算法结果更新到工单, step1.1-loop, {}/{}, teamId:{}, batchNo:{}, orderId:{}, dt:{}, engCode:{}", log.info("算法结果更新到工单, step1.1-loop, {}/{}, teamId:{}, batchNo:{}, orderId:{}, dt:{}, engCode:{}",
idx, dispatchOrderList.size(), teamId, batchNo, orderId, dt, engCode); idx, dispatchOrderList.size(), teamId, batchNo, orderId, dt, engCode);
LocalDate localDt = LocalDate.parse(dt, DateTimeFormatter.ofPattern("yyyy-MM-dd")); LocalDate localDt = LocalDate.parse(dt, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
Optional<OrderInfo> orderOpt = orderInfoRepo.findOrderInfoByOrderIdAndDt(orderId, localDt); Optional<OrderInfo> orderOpt = orderInfoRepo.findOrderInfoByOrderIdAndDt(orderId, localDt);
if (orderOpt.isEmpty()) { if (orderOpt.isEmpty()) {
log.warn("算法结果更新到工单, step1.1-loop, 工单不存在, teamId:{}, batchNo:{}, orderId:{}", log.warn("算法结果更新到工单, step1.1-loop, 工单不存在, teamId:{}, batchNo:{}, orderId:{}",
teamId, batchNo, orderId); teamId, batchNo, orderId);
return; return;
} }
OrderInfo orderInfo = orderOpt.get(); OrderInfo orderInfo = orderOpt.get();
if (!("OPEN".equals(orderInfo.getBeanStatus()) && if (!("OPEN".equals(orderInfo.getBeanStatus())
Set.of("AUTO_NOW", "AUTO_BATCH").contains(orderInfo.getAppointmentMethod()) && && Set.of("AUTO_NOW", "AUTO_BATCH", "MANUAL").contains(orderInfo.getAppointmentMethod())
Set.of("INIT", "PRE").contains(orderInfo.getAppointmentStatus()) && && Set.of("INIT", "PRE", "CONFIRM").contains(orderInfo.getAppointmentStatus())
"NORMAL".equals(orderInfo.getOrderStatus()) && "INIT".equals(orderInfo.getServiceStatus()))) { && "NORMAL".equals(orderInfo.getOrderStatus())
&& "INIT".equals(orderInfo.getServiceStatus()))) {
log.warn("算法结果更新到工单, step1.1-loop, 工单状态异常, teamId:{}, batchNo:{}, orderId:{}, bean-status:{}, appointment-status:{}, order-status:{}, service-status:{}",
teamId, batchNo, orderId, orderInfo.getBeanStatus(), orderInfo.getAppointmentStatus(), orderInfo.getOrderStatus(), orderInfo.getServiceStatus()); log.warn("算法结果更新到工单, step1.1-loop, 工单状态异常, teamId:{}, batchNo:{}, orderId:{}, bean-status:{}, appointment-status:{}, order-status:{}, service-status:{}",
return; teamId, batchNo, orderId, orderInfo.getBeanStatus(), orderInfo.getAppointmentStatus(), orderInfo.getOrderStatus(), orderInfo.getServiceStatus());
} return;
}
// 未分配技术员时,清理原分配的信息
if (!StrUtil.isEmpty(engCode)) { // 未分配技术员时,清理原分配的信息
EngineerInfo engineerInfo = engineerInfoMap.get(engCode); if (!StrUtil.isEmpty(engCode)) {
if (engineerInfo == null) { EngineerInfo engineerInfo = engineerInfoMap.get(engCode);
log.warn("算法结果更新到工单, step1.1-loop, 未找到技术员, teamId:{}, batchNo:{}, engCode:{}", if (engineerInfo == null) {
teamId, batchNo, engCode); log.warn("算法结果更新到工单, step1.1-loop, 未找到技术员, teamId:{}, batchNo:{}, engCode:{}",
return; teamId, batchNo, engCode);
} return;
String engName = engineerInfo.getName(); }
String phone = engineerInfo.getPhone(); String engName = engineerInfo.getName();
String phone = engineerInfo.getPhone();
/*int age = 0; /*int age = 0;
if (!StringUtils.isNullOrEmpty(engineerInfo.getBirth())) { if (!StringUtils.isNullOrEmpty(engineerInfo.getBirth())) {
DateTime birthDate = DateUtil.parse(engineerInfo.getBirth(), "yyyy-MM-dd"); DateTime birthDate = DateUtil.parse(engineerInfo.getBirth(), "yyyy-MM-dd");
age = DateUtil.age(birthDate.toJdkDate(), DateUtil.date()); age = DateUtil.age(birthDate.toJdkDate(), DateUtil.date());
}*/ }*/
orderInfo.setEngineerCode(engCode); orderInfo.setEngineerCode(engCode);
orderInfo.setEngineerName(engName); orderInfo.setEngineerName(engName);
orderInfo.setEngineerPhone(phone); orderInfo.setEngineerPhone(phone);
orderInfo.setPlanStartTime(dispatchOrder.getTimeBegin()); orderInfo.setPlanStartTime(dispatchOrder.getTimeBegin());
orderInfo.setPlanEndTime(dispatchOrder.getTimeEnd()); orderInfo.setPlanEndTime(dispatchOrder.getTimeEnd());
orderInfo.setArriveElapsed(dispatchOrder.getPathTime()); orderInfo.setArriveElapsed(dispatchOrder.getPathTime());
orderInfo.setArriveDistance(dispatchOrder.getPathDistance()); orderInfo.setArriveDistance(dispatchOrder.getPathDistance());
orderInfo.setAppointmentStatus(isConfirm ? "CONFIRM" : "PRE"); if (!"CONFIRM".equals(dispatchOrder.getStatus())) {
orderInfo.setDispatcher("AUTO_BATCH"); orderInfo.setAppointmentStatus(cutOff ? "CONFIRM" : "PRE");
orderInfo.setUpdateTime(LocalDateTime.now()); }
orderInfoRepo.save(orderInfo); orderInfo.setDispatcher("AUTO_BATCH");
orderInfo.setUpdateTime(LocalDateTime.now());
if (isConfirm) { orderInfoRepo.save(orderInfo);
OrderEvent orderEvent = new OrderEvent().setOrderId(orderId).setSuborderId(orderInfo.getSubId()).setHappen(LocalDateTime.now())
.setEvent("批量自动指派").setOperator("DISPATCH").setOperatorName("算法批量指派").setSource("PEA-DISPATCH") if (cutOff) {
.setDescription(String.format("批量自动指派:<%s,%s>", engCode, engName)).setMemo("") OrderEvent orderEvent = new OrderEvent().setOrderId(orderId).setSuborderId(orderInfo.getSubId()).setHappen(LocalDateTime.now())
.setCreateTime(LocalDateTime.now()).setUpdateTime(LocalDateTime.now()); .setEvent("批量自动指派").setOperator("DISPATCH").setOperatorName("算法批量指派").setSource("PEA-DISPATCH")
orderEventRepo.save(orderEvent); .setDescription(String.format("批量自动指派:<%s,%s>", engCode, engName)).setMemo("")
} .setCreateTime(LocalDateTime.now()).setUpdateTime(LocalDateTime.now());
orderEventRepo.save(orderEvent);
OrderLog orderLog = new OrderLog().setOrderId(orderId).setSuborderId(orderInfo.getSubId()).setSource("PEA-DISPATCH").setOperator("DISPATCH") }
.setContent(String.format("批量自动指派:<%s,%s>", engCode, engName)).setContentOld("")
.setMemo("批量自动指派").setCreateTime(LocalDateTime.now()).setUpdateTime(LocalDateTime.now()); OrderLog orderLog = new OrderLog().setOrderId(orderId).setSuborderId(orderInfo.getSubId()).setSource("PEA-DISPATCH").setOperator("DISPATCH")
orderLogRepo.save(orderLog); .setContent(String.format("批量自动指派:<%s,%s>", engCode, engName)).setContentOld("")
.setMemo("批量自动指派").setCreateTime(LocalDateTime.now()).setUpdateTime(LocalDateTime.now());
} else { orderLogRepo.save(orderLog);
log.warn("算法结果更新到工单, step1.2-loop, 未能分配到技术员, teamId:{}, batchNo:{}, orderId:{}, dt:{}",
teamId, batchNo, orderId, dt); } else {
orderInfo.setEngineerCode(""); log.warn("算法结果更新到工单, step1.2-loop, 未能分配到技术员, teamId:{}, batchNo:{}, orderId:{}, dt:{}",
orderInfo.setEngineerName(""); teamId, batchNo, orderId, dt);
orderInfo.setEngineerPhone(""); orderInfo.setEngineerCode("");
orderInfo.setPlanStartTime(null); orderInfo.setEngineerName("");
orderInfo.setPlanEndTime(null); orderInfo.setEngineerPhone("");
orderInfo.setArriveElapsed(0); orderInfo.setPlanStartTime(null);
orderInfo.setArriveDistance(0); orderInfo.setPlanEndTime(null);
orderInfo.setAppointmentStatus("INIT"); orderInfo.setArriveElapsed(0);
orderInfo.setDispatcher("AUTO_BATCH"); orderInfo.setArriveDistance(0);
orderInfo.setUpdateTime(LocalDateTime.now()); orderInfo.setAppointmentStatus("INIT");
orderInfoRepo.save(orderInfo); orderInfo.setDispatcher("AUTO_BATCH");
orderInfo.setUpdateTime(LocalDateTime.now());
OrderLog orderLog = new OrderLog().setOrderId(orderId).setSuborderId(orderInfo.getSubId()).setSource("PEA-DISPATCH").setOperator("DISPATCH") orderInfoRepo.save(orderInfo);
.setContent(String.format("批量自动指派:<%s,%s>", "", "抹掉技术员")).setContentOld("")
.setMemo("批量自动指派").setCreateTime(LocalDateTime.now()).setUpdateTime(LocalDateTime.now()); OrderLog orderLog = new OrderLog().setOrderId(orderId).setSuborderId(orderInfo.getSubId()).setSource("PEA-DISPATCH").setOperator("DISPATCH")
orderLogRepo.save(orderLog); .setContent(String.format("批量自动指派:<%s,%s>", "", "抹掉技术员")).setContentOld("")
} .setMemo("批量自动指派").setCreateTime(LocalDateTime.now()).setUpdateTime(LocalDateTime.now());
orderLogRepo.save(orderLog);
}); }
log.info("算法结果更新到工单完成, teamId:{}, batchNo:{}", teamId, batchNo); });
log.info("算法结果更新到工单完成, teamId:{}, batchNo:{}", teamId, batchNo);
} }
......
...@@ -259,7 +259,7 @@ public class SolveServiceImpl implements SolveService { ...@@ -259,7 +259,7 @@ public class SolveServiceImpl implements SolveService {
order.setPriority(0); order.setPriority(0);
} }
Customer customer = new Customer(order.getId(), order.getOrderId(), order.getDt(), location, start, end, order.getSkills(), order.getTakeTime()); Customer customer = new Customer(order.getId(), order.getOrderId(), order.getDt(), location, start, end, order.getSkills(), order.getTakeTime(), order.getStatus());
OrderInfo orderInfo = orderInfoRepository.findByOrderId(order.getOrderId()).get(0); OrderInfo orderInfo = orderInfoRepository.findByOrderId(order.getOrderId()).get(0);
if ((StrUtil.equals("MANUAL", orderInfo.getAppointmentMethod()) if ((StrUtil.equals("MANUAL", orderInfo.getAppointmentMethod())
&& StrUtil.equals("CONFIRM", orderInfo.getAppointmentStatus())) && StrUtil.equals("CONFIRM", orderInfo.getAppointmentStatus()))
...@@ -271,11 +271,11 @@ public class SolveServiceImpl implements SolveService { ...@@ -271,11 +271,11 @@ public class SolveServiceImpl implements SolveService {
customer.setExclusiveTechnicianCode(Objects.nonNull(orderInfo.getAppointEngineerCodes()) ? customer.setExclusiveTechnicianCode(Objects.nonNull(orderInfo.getAppointEngineerCodes()) ?
orderInfo.getAppointEngineerCodes().trim() : null); orderInfo.getAppointEngineerCodes().trim() : null);
} }
log.info( log.info(
"订单指定排除工程师, teamId:{}, batchNo:{}, orderId:{}, dispatchedTechnicianCode:{}, exclusiveTechnicianCode:{}", "订单指定排除工程师, teamId:{}, batchNo:{}, orderId:{}, dispatchedTechnicianCode:{}, exclusiveTechnicianCode:{}",
teamId, batchNo, order.getOrderId(), customer.getDispatchedTechnicianCode(), teamId, batchNo, order.getOrderId(), customer.getDispatchedTechnicianCode(),
customer.getExclusiveTechnicianCode()); customer.getExclusiveTechnicianCode());
customerList.add(customer); customerList.add(customer);
}); });
...@@ -284,62 +284,62 @@ public class SolveServiceImpl implements SolveService { ...@@ -284,62 +284,62 @@ public class SolveServiceImpl implements SolveService {
// technicianList // technicianList
ArrayList<Technician> technicianList = new ArrayList<>(); ArrayList<Technician> technicianList = new ArrayList<>();
dispatchEngineerRepo.findByTeamIdAndBatchNo(teamId, batchNo).forEach(engineer -> { dispatchEngineerRepo.findByTeamIdAndBatchNo(teamId, batchNo).forEach(engineer -> {
// 技术员时间窗 // 技术员时间窗
int[][] timeWindows = engineerCalendarService.timeWindows(engineer.getEngineerCode(), teamId, int[][] timeWindows = engineerCalendarService.timeWindows(engineer.getEngineerCode(), teamId,
LocalDateTimeUtil.parseDate(currDay, DateTimeFormatter.ofPattern("yyyy-MM-dd"))); LocalDateTimeUtil.parseDate(currDay, DateTimeFormatter.ofPattern("yyyy-MM-dd")));
if (null != timeWindows && timeWindows.length > 0) { if (null != timeWindows && timeWindows.length > 0) {
log.info("技术员时间窗, teamId:{}, batchNo:{}, engineerName:{}, timeWindows:{}", teamId, batchNo, log.info("技术员时间窗, teamId:{}, batchNo:{}, engineerName:{}, timeWindows:{}", teamId, batchNo,
engineer.getEngineerName(), new Gson().toJson(timeWindows)); engineer.getEngineerName(), new Gson().toJson(timeWindows));
// 技术员技能 // 技术员技能
List<String> skillList = queryEngineerSkills(engineer.getEngineerCode()); List<String> skillList = queryEngineerSkills(engineer.getEngineerCode());
// 距离偏好map // 距离偏好map
Location location = new Location(engineer.getId(), engineer.getEngineerCode(), "中心点", Location location = new Location(engineer.getId(), engineer.getEngineerCode(), "中心点",
StrUtil.isEmpty(engineer.getX()) ? 0 : Double.parseDouble(engineer.getX()), StrUtil.isEmpty(engineer.getX()) ? 0 : Double.parseDouble(engineer.getX()),
StrUtil.isEmpty(engineer.getY()) ? 0 : Double.parseDouble(engineer.getY())); StrUtil.isEmpty(engineer.getY()) ? 0 : Double.parseDouble(engineer.getY()));
Map<String, Long> preferedLoctionDistanceMap = new HashMap<String, Long>(); Map<String, Long> preferedLoctionDistanceMap = new HashMap<String, Long>();
if (location.getLongitude() > 1 && location.getLatitude() > 1) { if (location.getLongitude() > 1 && location.getLatitude() > 1) {
// 设置了偏好位置 // 设置了偏好位置
customerList.forEach(customer -> { customerList.forEach(customer -> {
long distance = distanceCalculator.calculateDistance(location, customer.getLocation()); long distance = distanceCalculator.calculateDistance(location, customer.getLocation());
preferedLoctionDistanceMap.put(customer.getCode(), distance); preferedLoctionDistanceMap.put(customer.getCode(), distance);
}); });
} else { } else {
// 未设置,不参与计算 // 未设置,不参与计算
} }
// 最大距离,硬约束:电动车固定40km上限,其他无限制 // 最大距离,硬约束:电动车固定40km上限,其他无限制
int maxDistance = engineer.getMaxDistance() * 1000; int maxDistance = engineer.getMaxDistance() * 1000;
if (engineer.getVehicleType() != null && engineer.getVehicleType() == 2) { if (engineer.getVehicleType() != null && engineer.getVehicleType() == 2) {
maxDistance = 40 * 1000; maxDistance = 40 * 1000;
} }
// 技术员出发地 // 技术员出发地
Double x = null; Double x = null;
Double y = null; Double y = null;
if (ObjectUtil.equal(engineer.getDeparture(), DepartureEnum.WORK_ADDR.getCode())) { if (ObjectUtil.equal(engineer.getDeparture(), DepartureEnum.WORK_ADDR.getCode())) {
x = Double.parseDouble(engineer.getWorkX()); x = Double.parseDouble(engineer.getWorkX());
y = Double.parseDouble(engineer.getWorkY()); y = Double.parseDouble(engineer.getWorkY());
} else { } else {
x = Double.parseDouble(orgWarehouseInfoEntity.getX()); x = Double.parseDouble(orgWarehouseInfoEntity.getX());
y = Double.parseDouble(orgWarehouseInfoEntity.getY()); y = Double.parseDouble(orgWarehouseInfoEntity.getY());
} }
Location engineerLocation = new Location(engineer.getId(), engineer.getEngineerCode(), "起点", x, y); Location engineerLocation = new Location(engineer.getId(), engineer.getEngineerCode(), "起点", x, y);
Depot engineerDepot = new Depot(engineer.getId(), engineer.getEngineerCode(), engineerLocation, 60 * 8, Depot engineerDepot = new Depot(engineer.getId(), engineer.getEngineerCode(), engineerLocation, 60 * 8,
60 * 18); 60 * 18);
Technician vehicle = new Technician(engineer.getId(), engineer.getEngineerCode(), engineer.getMaxNum(), Technician vehicle = new Technician(engineer.getId(), engineer.getEngineerCode(), engineer.getMaxNum(),
engineer.getMaxMinute(), maxDistance, engineer.getVehicleType(), engineerDepot, timeWindows, engineer.getMaxMinute(), maxDistance, engineer.getVehicleType(), engineerDepot, timeWindows,
Set.copyOf(skillList), preferedLoctionDistanceMap); Set.copyOf(skillList), preferedLoctionDistanceMap);
technicianList.add(vehicle); technicianList.add(vehicle);
} else { } else {
// 没有时间窗技术员,不参与派工 // 没有时间窗技术员,不参与派工
log.info("技术员时间窗, teamId:{}, batchNo:{}, engineerName:{}, no timeWindows", teamId, batchNo, log.info("技术员时间窗, teamId:{}, batchNo:{}, engineerName:{}, no timeWindows", teamId, batchNo,
engineer.getEngineerName()); engineer.getEngineerName());
} }
}); });
log.info("组织问题对象, technician-list, teamId:{}, batchNo:{}, technician-list:{}", teamId, batchNo, technicianList.size()); log.info("组织问题对象, technician-list, teamId:{}, batchNo:{}, technician-list:{}", teamId, batchNo, technicianList.size());
// locationlist 起点+订单地点 // locationlist 起点+订单地点
...@@ -535,7 +535,8 @@ public class SolveServiceImpl implements SolveService { ...@@ -535,7 +535,8 @@ public class SolveServiceImpl implements SolveService {
log.info("算法结果回写dispatch, step1-清除历史, groupId:{}, batchNo:{}", teamId, batchNo); log.info("算法结果回写dispatch, step1-清除历史, groupId:{}, batchNo:{}", teamId, batchNo);
Object[] paramClear = {teamId, batchNo}; Object[] paramClear = {teamId, batchNo};
String sqlReset = "update dispatch_order set engineer_code='', seq=0, time_begin=null, time_end=null, path_time=0, path_distance=0 " + "where team_id=? and batch_no=? and status!='CONFIRM' "; // confirm 状态工单不清除
String sqlReset = "update dispatch_order set engineer_code=null, seq=0, time_begin=null, time_end=null, path_time=0, path_distance=0 " + "where team_id=? and batch_no=? and status!='CONFIRM' ";
jdbcTemplate.update(sqlReset, paramClear); jdbcTemplate.update(sqlReset, paramClear);
log.info("算法结果回写dispatch, step2-开始回写, teamId:{}, batchNo:{}", teamId, batchNo); log.info("算法结果回写dispatch, step2-开始回写, teamId:{}, batchNo:{}", teamId, batchNo);
...@@ -561,7 +562,7 @@ public class SolveServiceImpl implements SolveService { ...@@ -561,7 +562,7 @@ public class SolveServiceImpl implements SolveService {
int pathTime = customer.getPathTimeFromPreviousStandstill(); int pathTime = customer.getPathTimeFromPreviousStandstill();
long pathDistance = customer.getDistanceFromPreviousStandstill(); long pathDistance = customer.getDistanceFromPreviousStandstill();
String sql = "update dispatch_order set engineer_code=?, seq=?, time_begin=? ,time_end=?, path_time=?, path_distance=? " + " where team_id=? and batch_no=? and order_id=? and dt=? and status!='CONFIRM' "; String sql = "update dispatch_order set engineer_code=?, seq=?, time_begin=? ,time_end=?, path_time=?, path_distance=? " + " where team_id=? and batch_no=? and order_id=? and dt=?";
Object[] param = {technician.getCode(), idx, arriveTime, leaveTime, pathTime, pathDistance, teamId, batchNo, customer.getCode(), customer.getDt()}; Object[] param = {technician.getCode(), idx, arriveTime, leaveTime, pathTime, pathDistance, teamId, batchNo, customer.getCode(), customer.getDt()};
int rowUpdated = jdbcTemplate.update(sql, param); int rowUpdated = jdbcTemplate.update(sql, param);
log.info("算法结果回写dispatch, step3-逐个客户处理, order_id:{}, engineer_code:{}, seq: {}, begin:{}, end:{} ,rowUpdated:{}", customer.getCode(), technician.getCode(), seq, arriveTime, leaveTime, rowUpdated); log.info("算法结果回写dispatch, step3-逐个客户处理, order_id:{}, engineer_code:{}, seq: {}, begin:{}, end:{} ,rowUpdated:{}", customer.getCode(), technician.getCode(), seq, arriveTime, leaveTime, rowUpdated);
......
...@@ -24,318 +24,320 @@ import com.google.common.collect.Maps; ...@@ -24,318 +24,320 @@ import com.google.common.collect.Maps;
public class DataUtils { public class DataUtils {
/** /**
* 获取初始化测试数据 * 获取初始化测试数据
* *
* @return * @return
* @throws UncheckedIOException * @throws UncheckedIOException
* @throws FileNotFoundException * @throws FileNotFoundException
*/ */
public static DispatchSolution getInitialProblem() throws UncheckedIOException, FileNotFoundException { public static DispatchSolution getInitialProblem() throws UncheckedIOException, FileNotFoundException {
Map<Integer, String> customerIndexMap = loadCustomerIndex(); Map<Integer, String> customerIndexMap = loadCustomerIndex();
Map<Integer, String> customerIndexXyMap = loadCustomerIndexXY(); Map<Integer, String> customerIndexXyMap = loadCustomerIndexXY();
Map<Integer, String> technicianIndexMap = loadTechnicianIndex(); Map<Integer, String> technicianIndexMap = loadTechnicianIndex();
Map<String, Set<String>> technicianCodeSkillsMap = loadTechnicianCodeSkillsMap(); Map<String, Set<String>> technicianCodeSkillsMap = loadTechnicianCodeSkillsMap();
Map<String, String> customerCodeSkillMap = loadCustomerCodeSkillMap(); Map<String, String> customerCodeSkillMap = loadCustomerCodeSkillMap();
// 偏好中心点位置 // 偏好中心点位置
Map<String, String> technicianCodePreferredLocationMap = loadPreferredlocationMap(); Map<String, String> technicianCodePreferredLocationMap = loadPreferredlocationMap();
Map<String, Map<String, Long>> preferredlocationDistanceMap = loadPreferredlocationDistanceMap( Map<String, Map<String, Long>> preferredlocationDistanceMap = loadPreferredlocationDistanceMap(
technicianCodePreferredLocationMap); technicianCodePreferredLocationMap);
Map<String, Integer> customerCodeServiceTimeMap = loadCustomerCodeServiceTimeMap(); Map<String, Integer> customerCodeServiceTimeMap = loadCustomerCodeServiceTimeMap();
DispatchSolution problem = createVehicleRoutingSolution(customerIndexMap, customerIndexXyMap, DispatchSolution problem = createVehicleRoutingSolution(customerIndexMap, customerIndexXyMap,
technicianIndexMap, technicianCodeSkillsMap, customerCodeSkillMap, technicianCodePreferredLocationMap, technicianIndexMap, technicianCodeSkillsMap, customerCodeSkillMap, technicianCodePreferredLocationMap,
preferredlocationDistanceMap, customerCodeServiceTimeMap, false); preferredlocationDistanceMap, customerCodeServiceTimeMap, false);
return problem; return problem;
} }
/** /**
* 获取初始化测试数据 * 获取初始化测试数据
* fullDay 是否全天派工 * fullDay 是否全天派工
* @return *
* @throws UncheckedIOException * @return
* @throws FileNotFoundException * @throws UncheckedIOException
*/ * @throws FileNotFoundException
public static DispatchSolution getInitialProblem(boolean fullDay) throws UncheckedIOException, FileNotFoundException { */
Map<Integer, String> customerIndexMap = loadCustomerIndex(); public static DispatchSolution getInitialProblem(boolean fullDay) throws UncheckedIOException, FileNotFoundException {
Map<Integer, String> customerIndexXyMap = loadCustomerIndexXY(); Map<Integer, String> customerIndexMap = loadCustomerIndex();
Map<Integer, String> technicianIndexMap = loadTechnicianIndex(); Map<Integer, String> customerIndexXyMap = loadCustomerIndexXY();
Map<String, Set<String>> technicianCodeSkillsMap = loadTechnicianCodeSkillsMap(); Map<Integer, String> technicianIndexMap = loadTechnicianIndex();
Map<String, String> customerCodeSkillMap = loadCustomerCodeSkillMap(); Map<String, Set<String>> technicianCodeSkillsMap = loadTechnicianCodeSkillsMap();
// 偏好中心点位置 Map<String, String> customerCodeSkillMap = loadCustomerCodeSkillMap();
Map<String, String> technicianCodePreferredLocationMap = loadPreferredlocationMap(); // 偏好中心点位置
Map<String, Map<String, Long>> preferredlocationDistanceMap = loadPreferredlocationDistanceMap( Map<String, String> technicianCodePreferredLocationMap = loadPreferredlocationMap();
technicianCodePreferredLocationMap); Map<String, Map<String, Long>> preferredlocationDistanceMap = loadPreferredlocationDistanceMap(
Map<String, Integer> customerCodeServiceTimeMap = loadCustomerCodeServiceTimeMap(); technicianCodePreferredLocationMap);
DispatchSolution problem = createVehicleRoutingSolution(customerIndexMap, customerIndexXyMap, Map<String, Integer> customerCodeServiceTimeMap = loadCustomerCodeServiceTimeMap();
technicianIndexMap, technicianCodeSkillsMap, customerCodeSkillMap, technicianCodePreferredLocationMap, DispatchSolution problem = createVehicleRoutingSolution(customerIndexMap, customerIndexXyMap,
preferredlocationDistanceMap, customerCodeServiceTimeMap,fullDay); technicianIndexMap, technicianCodeSkillsMap, customerCodeSkillMap, technicianCodePreferredLocationMap,
return problem; preferredlocationDistanceMap, customerCodeServiceTimeMap, fullDay);
} return problem;
}
private static Map<String, String> loadPreferredlocationMap() throws UncheckedIOException, FileNotFoundException {
List<String> technicianCodeLocation = IOUtils.readLines(new FileInputStream("data/technicianLocation.csv"), private static Map<String, String> loadPreferredlocationMap() throws UncheckedIOException, FileNotFoundException {
"utf-8"); List<String> technicianCodeLocation = IOUtils.readLines(new FileInputStream("data/technicianLocation.csv"),
Map<String, String> technicianCodeLocationMap = new HashMap<String, String>();// 序号-code "utf-8");
for (int i = 0; i < technicianCodeLocation.size(); i++) { Map<String, String> technicianCodeLocationMap = new HashMap<String, String>();// 序号-code
String line = technicianCodeLocation.get(i); for (int i = 0; i < technicianCodeLocation.size(); i++) {
String[] temps = line.split(","); String line = technicianCodeLocation.get(i);
technicianCodeLocationMap.put(temps[0], temps[1] + "," + temps[2]); String[] temps = line.split(",");
} technicianCodeLocationMap.put(temps[0], temps[1] + "," + temps[2]);
return technicianCodeLocationMap; }
} return technicianCodeLocationMap;
}
private static Map<String, Integer> loadCustomerCodeServiceTimeMap()
throws UncheckedIOException, FileNotFoundException { private static Map<String, Integer> loadCustomerCodeServiceTimeMap()
List<String> customerServiceTime = IOUtils.readLines(new FileInputStream("data/customerServiceTime.csv"), throws UncheckedIOException, FileNotFoundException {
"utf-8"); List<String> customerServiceTime = IOUtils.readLines(new FileInputStream("data/customerServiceTime.csv"),
Map<String, Integer> customerCodeServiceTimeMap = new HashMap<String, Integer>();// code-time "utf-8");
for (int i = 0; i < customerServiceTime.size(); i++) { Map<String, Integer> customerCodeServiceTimeMap = new HashMap<String, Integer>();// code-time
String line = customerServiceTime.get(i); for (int i = 0; i < customerServiceTime.size(); i++) {
String[] temps = line.split(","); String line = customerServiceTime.get(i);
customerCodeServiceTimeMap.put(temps[0], Integer.parseInt(temps[1])); String[] temps = line.split(",");
} customerCodeServiceTimeMap.put(temps[0], Integer.parseInt(temps[1]));
return customerCodeServiceTimeMap; }
} return customerCodeServiceTimeMap;
}
private static Map<String, Map<String, Long>> loadPreferredlocationDistanceMap(
Map<String, String> technicianCodeLocationMap) throws UncheckedIOException, FileNotFoundException { private static Map<String, Map<String, Long>> loadPreferredlocationDistanceMap(
List<String> customerCodeLocation = IOUtils.readLines(new FileInputStream("data/customerLocation.csv"), Map<String, String> technicianCodeLocationMap) throws UncheckedIOException, FileNotFoundException {
"utf-8"); List<String> customerCodeLocation = IOUtils.readLines(new FileInputStream("data/customerLocation.csv"),
Map<String, String> customerCodeLocationMap = new HashMap<String, String>();// 序号-code "utf-8");
for (int i = 0; i < customerCodeLocation.size(); i++) { Map<String, String> customerCodeLocationMap = new HashMap<String, String>();// 序号-code
String line = customerCodeLocation.get(i); for (int i = 0; i < customerCodeLocation.size(); i++) {
String[] temps = line.split(","); String line = customerCodeLocation.get(i);
customerCodeLocationMap.put(temps[0], temps[1] + "," + temps[2]); String[] temps = line.split(",");
} customerCodeLocationMap.put(temps[0], temps[1] + "," + temps[2]);
}
// 生成订单和技术员的偏好距离Map 技术员-订单-距离
Map<String, Map<String, Long>> customerTecnicianDistanceMap = new HashMap<String, Map<String, Long>>(); // 生成订单和技术员的偏好距离Map 技术员-订单-距离
customerCodeLocationMap.forEach((customerCode, value) -> { Map<String, Map<String, Long>> customerTecnicianDistanceMap = new HashMap<String, Map<String, Long>>();
technicianCodeLocationMap.forEach((technicianCode, value2) -> { customerCodeLocationMap.forEach((customerCode, value) -> {
String[] temps = RegExUtils.removeAll(value, "\"").split(","); technicianCodeLocationMap.forEach((technicianCode, value2) -> {
String[] temps2 = RegExUtils.removeAll(value2, "\"").split(","); String[] temps = RegExUtils.removeAll(value, "\"").split(",");
long distance = (long) getDistance(Double.parseDouble(temps[1]), Double.parseDouble(temps[0]), String[] temps2 = RegExUtils.removeAll(value2, "\"").split(",");
Double.parseDouble(temps2[1]), Double.parseDouble(temps2[0])); long distance = (long) getDistance(Double.parseDouble(temps[1]), Double.parseDouble(temps[0]),
Map<String, Long> customerMaps = customerTecnicianDistanceMap.get(technicianCode); Double.parseDouble(temps2[1]), Double.parseDouble(temps2[0]));
if (null == customerMaps) { Map<String, Long> customerMaps = customerTecnicianDistanceMap.get(technicianCode);
customerMaps = new HashMap<String, Long>(); if (null == customerMaps) {
customerTecnicianDistanceMap.put(technicianCode, customerMaps); customerMaps = new HashMap<String, Long>();
} customerTecnicianDistanceMap.put(technicianCode, customerMaps);
customerMaps.put(customerCode, distance); }
}); customerMaps.put(customerCode, distance);
}); });
return customerTecnicianDistanceMap; });
} return customerTecnicianDistanceMap;
}
/**
* 获取经纬度距离 /**
* * 获取经纬度距离
* @param lat1 y *
* @param lon1 x * @param lat1 y
* @param lat2 y * @param lon1 x
* @param lon2 x * @param lat2 y
* @return * @param lon2 x
*/ * @return
private static double getDistance(double lat1, double lon1, double lat2, double lon2) { */
double diffLongitudes = Math.toRadians(Math.abs(lon1 - lon2)); private static double getDistance(double lat1, double lon1, double lat2, double lon2) {
double diffLatitudes = Math.toRadians(Math.abs(lat1 - lat2)); double diffLongitudes = Math.toRadians(Math.abs(lon1 - lon2));
double slat = Math.toRadians(lat1); double diffLatitudes = Math.toRadians(Math.abs(lat1 - lat2));
double flat = Math.toRadians(lat2); double slat = Math.toRadians(lat1);
// haversine formula double flat = Math.toRadians(lat2);
double a = Math.sin(diffLatitudes / 2) * Math.sin(diffLatitudes / 2) // haversine formula
+ Math.cos(slat) * Math.cos(flat) * Math.sin(diffLongitudes / 2) * Math.sin(diffLongitudes / 2); double a = Math.sin(diffLatitudes / 2) * Math.sin(diffLatitudes / 2)
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); // angular distance in radians + Math.cos(slat) * Math.cos(flat) * Math.sin(diffLongitudes / 2) * Math.sin(diffLongitudes / 2);
return 6378137 * c; double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); // angular distance in radians
} return 6378137 * c;
}
private static Map<String, String> loadCustomerCodeSkillMap() throws UncheckedIOException, FileNotFoundException {
List<String> customerSkill = IOUtils.readLines(new FileInputStream("data/customerSkill.csv"), "utf-8"); private static Map<String, String> loadCustomerCodeSkillMap() throws UncheckedIOException, FileNotFoundException {
Map<String, String> customerCodeSkillMap = new HashMap<String, String>();// code-技能 List<String> customerSkill = IOUtils.readLines(new FileInputStream("data/customerSkill.csv"), "utf-8");
for (int i = 0; i < customerSkill.size(); i++) { Map<String, String> customerCodeSkillMap = new HashMap<String, String>();// code-技能
String line = customerSkill.get(i); for (int i = 0; i < customerSkill.size(); i++) {
String[] temps = line.split(","); String line = customerSkill.get(i);
customerCodeSkillMap.put(temps[0], temps[1]); String[] temps = line.split(",");
} customerCodeSkillMap.put(temps[0], temps[1]);
return customerCodeSkillMap; }
} return customerCodeSkillMap;
}
private static Map<String, Set<String>> loadTechnicianCodeSkillsMap()
throws UncheckedIOException, FileNotFoundException { private static Map<String, Set<String>> loadTechnicianCodeSkillsMap()
List<String> technicianSkills = IOUtils.readLines(new FileInputStream("data/technicianSkills.csv"), "utf-8"); throws UncheckedIOException, FileNotFoundException {
Map<String, Set<String>> technicianCodeSkillsMap = new HashMap<String, Set<String>>();// code-技能 List<String> technicianSkills = IOUtils.readLines(new FileInputStream("data/technicianSkills.csv"), "utf-8");
for (int i = 0; i < technicianSkills.size(); i++) { Map<String, Set<String>> technicianCodeSkillsMap = new HashMap<String, Set<String>>();// code-技能
String line = technicianSkills.get(i); for (int i = 0; i < technicianSkills.size(); i++) {
String[] temps = line.split(","); String line = technicianSkills.get(i);
String[] temps = line.split(",");
String code = temps[0];
Set<String> skills = technicianCodeSkillsMap.get(code); String code = temps[0];
if (null == skills) { Set<String> skills = technicianCodeSkillsMap.get(code);
skills = new HashSet<>(); if (null == skills) {
technicianCodeSkillsMap.put(code, skills); skills = new HashSet<>();
} technicianCodeSkillsMap.put(code, skills);
skills.add(temps[1]); }
} skills.add(temps[1]);
return technicianCodeSkillsMap; }
} return technicianCodeSkillsMap;
}
private static Map<Integer, String> loadTechnicianIndex() throws UncheckedIOException, FileNotFoundException {
List<String> technicianIndexlines = IOUtils.readLines(new FileInputStream("data/technicianIndex.csv"), "utf-8"); private static Map<Integer, String> loadTechnicianIndex() throws UncheckedIOException, FileNotFoundException {
Map<Integer, String> technicianIndexMap = new HashMap<Integer, String>();// 序号-code List<String> technicianIndexlines = IOUtils.readLines(new FileInputStream("data/technicianIndex.csv"), "utf-8");
for (int i = 0; i < technicianIndexlines.size(); i++) { Map<Integer, String> technicianIndexMap = new HashMap<Integer, String>();// 序号-code
technicianIndexMap.put(i + 1, technicianIndexlines.get(i)); for (int i = 0; i < technicianIndexlines.size(); i++) {
} technicianIndexMap.put(i + 1, technicianIndexlines.get(i));
return technicianIndexMap; }
} return technicianIndexMap;
}
private static Map<Integer, String> loadCustomerIndex() throws UncheckedIOException, FileNotFoundException {
List<String> customerIndexlines = IOUtils.readLines(new FileInputStream("data/customerIndex.csv"), "utf-8"); private static Map<Integer, String> loadCustomerIndex() throws UncheckedIOException, FileNotFoundException {
Map<Integer, String> customerIndexMap = new HashMap<Integer, String>();// 序号-code List<String> customerIndexlines = IOUtils.readLines(new FileInputStream("data/customerIndex.csv"), "utf-8");
for (int i = 0; i < customerIndexlines.size(); i++) { Map<Integer, String> customerIndexMap = new HashMap<Integer, String>();// 序号-code
customerIndexMap.put(i + 1, customerIndexlines.get(i)); for (int i = 0; i < customerIndexlines.size(); i++) {
} customerIndexMap.put(i + 1, customerIndexlines.get(i));
return customerIndexMap; }
} return customerIndexMap;
}
private static Map<Integer, String> loadCustomerIndexXY() throws UncheckedIOException, FileNotFoundException {
List<String> customerCodeXYlines = IOUtils.readLines(new FileInputStream("data/customerIndexXY.csv"), "utf-8"); private static Map<Integer, String> loadCustomerIndexXY() throws UncheckedIOException, FileNotFoundException {
Map<Integer, String> customerIndexXYMap = new HashMap<Integer, String>();// 序号-code List<String> customerCodeXYlines = IOUtils.readLines(new FileInputStream("data/customerIndexXY.csv"), "utf-8");
for (int i = 0; i < customerCodeXYlines.size(); i++) { Map<Integer, String> customerIndexXYMap = new HashMap<Integer, String>();// 序号-code
String line = customerCodeXYlines.get(i); for (int i = 0; i < customerCodeXYlines.size(); i++) {
String[] temps = line.split(","); String line = customerCodeXYlines.get(i);
customerIndexXYMap.put(i + 1, String[] temps = line.split(",");
RegExUtils.removeAll(temps[1], "\"") + "," + RegExUtils.removeAll(temps[2], "\"")); customerIndexXYMap.put(i + 1,
} RegExUtils.removeAll(temps[1], "\"") + "," + RegExUtils.removeAll(temps[2], "\""));
return customerIndexXYMap; }
} return customerIndexXYMap;
}
private static DispatchSolution createVehicleRoutingSolution(Map<Integer, String> customerIndexMap,
Map<Integer, String> customerIndexXyMap, Map<Integer, String> technicianIndexMap, private static DispatchSolution createVehicleRoutingSolution(Map<Integer, String> customerIndexMap,
Map<String, Set<String>> technicianCodeSkillsMap, Map<String, String> customerCodeSkillMap, Map<Integer, String> customerIndexXyMap, Map<Integer, String> technicianIndexMap,
Map<String, String> technicianCodePreferredLocationMap, Map<String, Set<String>> technicianCodeSkillsMap, Map<String, String> customerCodeSkillMap,
Map<String, Map<String, Long>> preferredlocationDistanceMap, Map<String, String> technicianCodePreferredLocationMap,
Map<String, Integer> customerCodeServiceTimeMap, boolean fullDay) throws UncheckedIOException, FileNotFoundException { Map<String, Map<String, Long>> preferredlocationDistanceMap,
DispatchSolution vehicleRoutingSolution = new DispatchSolution(); Map<String, Integer> customerCodeServiceTimeMap, boolean fullDay) throws UncheckedIOException, FileNotFoundException {
DispatchSolution vehicleRoutingSolution = new DispatchSolution();
// 翻转map
Map<String, Integer> customerIndexMap2 = customerIndexMap.entrySet().stream() // 翻转map
.collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey)); Map<String, Integer> customerIndexMap2 = customerIndexMap.entrySet().stream()
// 初始化距离矩阵 .collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));
List<String> pathMatrixlines = IOUtils.readLines(new FileInputStream("data/pathMatrix.csv"), "utf-8"); // 初始化距离矩阵
long[][] pathMatrix = new long[customerIndexMap.keySet().size() + 1][customerIndexMap.keySet().size() + 1]; List<String> pathMatrixlines = IOUtils.readLines(new FileInputStream("data/pathMatrix.csv"), "utf-8");
for (int i = 0; i < pathMatrixlines.size(); i++) { long[][] pathMatrix = new long[customerIndexMap.keySet().size() + 1][customerIndexMap.keySet().size() + 1];
String line = pathMatrixlines.get(i); for (int i = 0; i < pathMatrixlines.size(); i++) {
String[] temps = line.split(","); String line = pathMatrixlines.get(i);
for (int j = 0; j < temps.length; j++) { String[] temps = line.split(",");
pathMatrix[i][j] = (long) (Float.parseFloat(temps[j]) * 1000); for (int j = 0; j < temps.length; j++) {
} pathMatrix[i][j] = (long) (Float.parseFloat(temps[j]) * 1000);
} }
Map<Integer, Location> locationIndex = new HashMap<Integer, Location>(); }
for (int i = 0; i < pathMatrix.length; i++) { Map<Integer, Location> locationIndex = new HashMap<Integer, Location>();
// 1 ~ N+1 for (int i = 0; i < pathMatrix.length; i++) {
String xyString = customerIndexXyMap.get(i + 1); // 1 ~ N+1
String[] temps = xyString.split(","); String xyString = customerIndexXyMap.get(i + 1);
locationIndex.put(i + 1, new Location(i + 1, Float.parseFloat(temps[0]), Float.parseFloat(temps[1]))); String[] temps = xyString.split(",");
} locationIndex.put(i + 1, new Location(i + 1, Float.parseFloat(temps[0]), Float.parseFloat(temps[1])));
for (int i = 0; i < pathMatrix.length; i++) { }
Location locationi = locationIndex.get(i + 1); for (int i = 0; i < pathMatrix.length; i++) {
for (int j = 0; j < pathMatrix[i].length; j++) { Location locationi = locationIndex.get(i + 1);
Location locationj = locationIndex.get(j + 1); for (int j = 0; j < pathMatrix[i].length; j++) {
locationi.getDistanceMap(1).put(locationj, pathMatrix[i][j]); Location locationj = locationIndex.get(j + 1);
} locationi.getDistanceMap(1).put(locationj, pathMatrix[i][j]);
} }
}
// 初始化时间矩阵
List<String> pathTimeMatrixlines = IOUtils.readLines(new FileInputStream("data/pathTimeMatrix.csv"), "utf-8"); // 初始化时间矩阵
long[][] pathTimeMatrix = new long[customerIndexMap.keySet().size() + 1][customerIndexMap.keySet().size() + 1]; List<String> pathTimeMatrixlines = IOUtils.readLines(new FileInputStream("data/pathTimeMatrix.csv"), "utf-8");
for (int i = 0; i < pathTimeMatrixlines.size(); i++) { long[][] pathTimeMatrix = new long[customerIndexMap.keySet().size() + 1][customerIndexMap.keySet().size() + 1];
String line = pathTimeMatrixlines.get(i); for (int i = 0; i < pathTimeMatrixlines.size(); i++) {
String[] temps = line.split(","); String line = pathTimeMatrixlines.get(i);
for (int j = 0; j < temps.length; j++) { String[] temps = line.split(",");
// 秒转分钟 for (int j = 0; j < temps.length; j++) {
pathTimeMatrix[i][j] = (long) (Math.round(Float.parseFloat(temps[j]) )); // 秒转分钟
} pathTimeMatrix[i][j] = (long) (Math.round(Float.parseFloat(temps[j])));
} }
for (int i = 0; i < pathTimeMatrix.length; i++) { }
Location locationi = locationIndex.get(i + 1); for (int i = 0; i < pathTimeMatrix.length; i++) {
for (int j = 0; j < pathTimeMatrix[i].length; j++) { Location locationi = locationIndex.get(i + 1);
Location locationj = locationIndex.get(j + 1); for (int j = 0; j < pathTimeMatrix[i].length; j++) {
locationi.getDistanceTimeMap(1).put(locationj, pathTimeMatrix[i][j]); Location locationj = locationIndex.get(j + 1);
} locationi.getDistanceTimeMap(1).put(locationj, pathTimeMatrix[i][j]);
} }
}
// 初始化订单服务窗
List<String> customerWindowslines = IOUtils.readLines(new FileInputStream("data/customerWindows.csv"), "utf-8"); // 初始化订单服务窗
Map<Integer, Integer> customerStartMap = new HashMap<Integer, Integer>(); List<String> customerWindowslines = IOUtils.readLines(new FileInputStream("data/customerWindows.csv"), "utf-8");
Map<Integer, Integer> customerEndMap = new HashMap<Integer, Integer>(); Map<Integer, Integer> customerStartMap = new HashMap<Integer, Integer>();
for (int i = 0; i < customerWindowslines.size(); i++) { Map<Integer, Integer> customerEndMap = new HashMap<Integer, Integer>();
String line = customerWindowslines.get(i); for (int i = 0; i < customerWindowslines.size(); i++) {
String[] temps = line.split(","); String line = customerWindowslines.get(i);
customerStartMap.put(customerIndexMap2.get(temps[0]), 480 + Integer.parseInt(temps[1])); String[] temps = line.split(",");
customerEndMap.put(customerIndexMap2.get(temps[0]), 480 + Integer.parseInt(temps[2])); customerStartMap.put(customerIndexMap2.get(temps[0]), 480 + Integer.parseInt(temps[1]));
} customerEndMap.put(customerIndexMap2.get(temps[0]), 480 + Integer.parseInt(temps[2]));
}
// 初始化订单需要技能
Map<Integer, String> customerSkillMap = new HashMap<Integer, String>(); // 初始化订单需要技能
for (int i = 0; i < customerWindowslines.size(); i++) { Map<Integer, String> customerSkillMap = new HashMap<Integer, String>();
// 获取订单技能 for (int i = 0; i < customerWindowslines.size(); i++) {
customerSkillMap.put(i + 1, customerCodeSkillMap.get(customerIndexMap.get(i + 1))); // 获取订单技能
customerSkillMap.put(i + 1, customerCodeSkillMap.get(customerIndexMap.get(i + 1)));
if (null == customerCodeSkillMap.get(customerIndexMap.get(i + 1))) {
System.err.printf("%s code:%s 没有技能 %n", i + 1, customerIndexMap.get(i + 1)); if (null == customerCodeSkillMap.get(customerIndexMap.get(i + 1))) {
System.exit(0); System.err.printf("%s code:%s 没有技能 %n", i + 1, customerIndexMap.get(i + 1));
} System.exit(0);
}
}
}
// 初始化订单+技能服务时间
List<Customer> customerList = new ArrayList<>(); // 初始化订单+技能服务时间
for (int i = 0; i < customerIndexMap.keySet().size(); i++) { List<Customer> customerList = new ArrayList<>();
customerList.add(new Customer(i + 1, customerIndexMap.get(i + 1), "2000-01-01", locationIndex.get(i + 2), for (int i = 0; i < customerIndexMap.keySet().size(); i++) {
customerStartMap.get(i + 1), customerEndMap.get(i + 1), customerSkillMap.get(i + 1), customerList.add(new Customer(i + 1, customerIndexMap.get(i + 1), "2000-01-01", locationIndex.get(i + 2),
// 初始化技能服务时间 customerStartMap.get(i + 1), customerEndMap.get(i + 1), customerSkillMap.get(i + 1),
customerCodeServiceTimeMap.get(customerIndexMap.get(i + 1)))); // 初始化技能服务时间
} customerCodeServiceTimeMap.get(customerIndexMap.get(i + 1)),
null));
// 初始化Depot }
Depot depot = new Depot(1, locationIndex.get(1), 480, 1080);
// 初始化Depot
// 初始化技术员 Depot depot = new Depot(1, locationIndex.get(1), 480, 1080);
List<Technician> technicianList = new ArrayList<>();
for (int i = 0; i < technicianIndexMap.keySet().size(); i++) { // 初始化技术员
// 获取第i+1个技术员的技能set List<Technician> technicianList = new ArrayList<>();
Set<String> skills = technicianCodeSkillsMap.get(technicianIndexMap.get(i + 1)); for (int i = 0; i < technicianIndexMap.keySet().size(); i++) {
// 获取第i+1个技术员的技能set
if (null == skills || skills.size() == 0) { Set<String> skills = technicianCodeSkillsMap.get(technicianIndexMap.get(i + 1));
System.err.printf("技术员%s code:%s 没有技能 %n", i + 1, technicianIndexMap.get(i + 1));
System.exit(0); if (null == skills || skills.size() == 0) {
} System.err.printf("技术员%s code:%s 没有技能 %n", i + 1, technicianIndexMap.get(i + 1));
System.exit(0);
String xyString = technicianCodePreferredLocationMap.get(technicianIndexMap.get(i + 1)); }
String[] temps = xyString.split(",");
Location preferredlocation = new Location(i + 1, Float.parseFloat(RegExUtils.removeAll(temps[0], "\"")), String xyString = technicianCodePreferredLocationMap.get(technicianIndexMap.get(i + 1));
Float.parseFloat(RegExUtils.removeAll(temps[1], "\""))); String[] temps = xyString.split(",");
technicianList.add(new Technician(i + 1, technicianIndexMap.get(i + 1), depot, 480, fullDay ? 1440 : 1080 , skills, Location preferredlocation = new Location(i + 1, Float.parseFloat(RegExUtils.removeAll(temps[0], "\"")),
preferredlocationDistanceMap.get(technicianIndexMap.get(i + 1)), preferredlocation)); Float.parseFloat(RegExUtils.removeAll(temps[1], "\"")));
} technicianList.add(new Technician(i + 1, technicianIndexMap.get(i + 1), depot, 480, fullDay ? 1440 : 1080, skills,
preferredlocationDistanceMap.get(technicianIndexMap.get(i + 1)), preferredlocation));
// 已分配订单 测试数据,"订单code-技术员code" }
Map<String, String> orderCodeTechnichanCodesMap = Maps.newHashMap();
orderCodeTechnichanCodesMap.put("106854117", "6200041211"); // 已分配订单 测试数据,"订单code-技术员code"
orderCodeTechnichanCodesMap.put("106854169", "6200040858"); Map<String, String> orderCodeTechnichanCodesMap = Maps.newHashMap();
orderCodeTechnichanCodesMap.put("106863823", "6200040858"); orderCodeTechnichanCodesMap.put("106854117", "6200041211");
for (Customer customer : customerList) { orderCodeTechnichanCodesMap.put("106854169", "6200040858");
if (null != orderCodeTechnichanCodesMap.get(customer.getCode())) { orderCodeTechnichanCodesMap.put("106863823", "6200040858");
System.out.println("set code"+customer.getCode()+" : "+orderCodeTechnichanCodesMap.get(customer.getCode())); for (Customer customer : customerList) {
customer.setDispatchedTechnicianCode(orderCodeTechnichanCodesMap.get(customer.getCode())); if (null != orderCodeTechnichanCodesMap.get(customer.getCode())) {
} System.out.println("set code" + customer.getCode() + " : " + orderCodeTechnichanCodesMap.get(customer.getCode()));
} customer.setDispatchedTechnicianCode(orderCodeTechnichanCodesMap.get(customer.getCode()));
}
vehicleRoutingSolution.setCustomerList(customerList); }
vehicleRoutingSolution.setDepot(depot);
vehicleRoutingSolution.setLocationList(new ArrayList<>(locationIndex.values())); vehicleRoutingSolution.setCustomerList(customerList);
vehicleRoutingSolution.setTechnicianList(technicianList); vehicleRoutingSolution.setDepot(depot);
vehicleRoutingSolution.setLocationList(new ArrayList<>(locationIndex.values()));
return vehicleRoutingSolution; vehicleRoutingSolution.setTechnicianList(technicianList);
}
return vehicleRoutingSolution;
}
} }
...@@ -11,6 +11,7 @@ import java.util.stream.Collectors; ...@@ -11,6 +11,7 @@ import java.util.stream.Collectors;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.optaplanner.constraint.streams.drools.DroolsConstraintStreamScoreDirector; import org.optaplanner.constraint.streams.drools.DroolsConstraintStreamScoreDirector;
...@@ -400,7 +401,8 @@ public class DispatchSolutionUtils { ...@@ -400,7 +401,8 @@ public class DispatchSolutionUtils {
List<Customer> customerList = new ArrayList<>(); List<Customer> customerList = new ArrayList<>();
customerList.addAll(((Technician) indictedObject).getCustomerList()); customerList.addAll(((Technician) indictedObject).getCustomerList());
for (Customer customer : customerList) { for (Customer customer : customerList) {
if (!customer.isInTechnicianTimeWindows()) { if (!customer.isInTechnicianTimeWindows()
&& !StrUtil.equals("CONFIRM", customer.getStatus())) {
// 更新shadow变量 // 更新shadow变量
updateShadowVariable(customer); updateShadowVariable(customer);
// 移除技术员 // 移除技术员
...@@ -411,6 +413,19 @@ public class DispatchSolutionUtils { ...@@ -411,6 +413,19 @@ public class DispatchSolutionUtils {
} }
} }
break; break;
case dispatchedMatch:
for (Object indictedObject : constraintMatch.getIndictedObjectList()) {
// 违反硬约束对象,根据具体约束返回不同类型对象
if (indictedObject instanceof Customer) {
Customer customer = (Customer) indictedObject;
// 更新shadow变量
updateShadowVariable(customer);
// 移除技术员
customer.getTechnician().getCustomerList().remove(customer);
solution.getUnDispatchedCustomers().add(customer);
}
}
break;
default: default:
break; break;
} }
......
...@@ -3,7 +3,7 @@ server: ...@@ -3,7 +3,7 @@ server:
dispatch: dispatch:
cron: cron:
expr: 0 10 8-23 * * ? expr: 0 9 8-23 * * ?
next-day-limit: 2 next-day-limit: 2
scheduler: scheduler:
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!