Commit ab627f1b by Ren Ping

feat:初始化工程师容量定时任务 dispatch

1 parent c10eb803
...@@ -2,15 +2,24 @@ package com.dituhui.pea.dispatch.dao; ...@@ -2,15 +2,24 @@ package com.dituhui.pea.dispatch.dao;
import com.dituhui.pea.dispatch.entity.DispatchEngineer; import com.dituhui.pea.dispatch.entity.DispatchEngineer;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import java.util.List; import java.util.List;
import java.util.Map;
public interface DispatchEngineerRepository extends CrudRepository<DispatchEngineer, Long>, JpaRepository<DispatchEngineer, Long> { public interface DispatchEngineerRepository extends CrudRepository<DispatchEngineer, Long>, JpaRepository<DispatchEngineer, Long> {
List<DispatchEngineer> findByGroupId(String groupId); List<DispatchEngineer> findByGroupId(String groupId);
List<DispatchEngineer> findByGroupIdAndBatchNo(String groupId, String batchNo); List<DispatchEngineer> findByGroupIdAndBatchNo(String groupId, String batchNo);
List<DispatchEngineer> findByTeamIdAndBatchNo(String teamId, String batchNo); List<DispatchEngineer> findByTeamIdAndBatchNo(String teamId, String batchNo);
@Query(value = "SELECT ?1 group_id, o.team_id,?2 batch_no,o.engineer_code, a.name engineer_name, b.x, b.y , max_num, max_minute, max_distance, b.vehicle vehicle_type FROM `org_team_engineer` o\n"
+ " join engineer_info a on o.engineer_code=a.engineer_code\n"
+ " left join engineer_business b on a.engineer_code = b.engineer_code\n"
+ " WHERE o.team_id=?3 AND o.`status`=1\n",
nativeQuery = true)
List<Map<String,Object>> getNewDispatchEngineer(String groupId, String batchNo, String teamId);
} }
\ No newline at end of file
package com.dituhui.pea.dispatch.dao; package com.dituhui.pea.dispatch.dao;
import com.dituhui.pea.dispatch.entity.DispatchEngineer;
import com.dituhui.pea.dispatch.entity.DispatchOrder; import com.dituhui.pea.dispatch.entity.DispatchOrder;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
public interface DispatchOrderRepository extends CrudRepository<DispatchOrder, Long>, JpaRepository<DispatchOrder, Long> { public interface DispatchOrderRepository extends CrudRepository<DispatchOrder, Long>, JpaRepository<DispatchOrder, Long> {
...@@ -34,4 +36,30 @@ public interface DispatchOrderRepository extends CrudRepository<DispatchOrder, L ...@@ -34,4 +36,30 @@ public interface DispatchOrderRepository extends CrudRepository<DispatchOrder, L
Optional<DispatchOrder> findByGroupIdAndBatchNoAndOrderIdAndDt(String groupId, String batchNo, String orderId, String dt); Optional<DispatchOrder> findByGroupIdAndBatchNoAndOrderIdAndDt(String groupId, String batchNo, String orderId, String dt);
List<DispatchOrder> findByTeamIdAndBatchNo(String teamId, String batchNo); List<DispatchOrder> findByTeamIdAndBatchNo(String teamId, String batchNo);
@Query(value = " SELECT ?1 group_id, ?2 batch_no, a.org_team_id team_id, a.order_id, date_format(a.dt,'%Y-%m-%d') dt, a.x, a.y , \n"
+ " a.expect_time_begin, a.expect_time_end, a.tags, a.priority , \n"
+ " CONCAT(a.brand, '-', a.type, '-', a.skill) skills , a.take_time , a.appointment_status status\n"
+ " FROM order_info a \n" + " WHERE a.org_team_id=?3 AND a.dt = ?4 AND bean_status='OPEN'\n"
+ " AND appointment_method LIKE 'AUTO%' AND a.appointment_status IN ('INIT', 'PRE')\n"
+ " AND order_status ='NORMAL' AND service_status='INIT'\n"
+ " ORDER BY a.expect_time_begin ASC \n",
nativeQuery = true)
List<Map<String,Object>> getNewDispatchOrder(String groupId, String batchNo, String teamId, String batchDay);
@Query(value = " select ?1 group_id, ?2 batch_no, a.org_team_id team_id, a.order_id, date_format(a.dt,'%Y-%m-%d') dt, a.x, a.y , \n" +
" a.expect_time_begin, a.expect_time_end, a.tags, a.priority , \n" +
" concat(a.brand, '-', a.type, '-', a.skill) skills , a.take_time, a.appointment_status status, \n" +
" a.engineer_code, date_format(a.plan_start_time,'%Y-%m-%d %H:%i:%s') time_begin, date_format(a.plan_end_time,'%Y-%m-%d %H:%i:%s') time_end \n" +
" from order_info a \n" +
" where a.org_team_id=?3 and a.dt = ?4 and bean_status='OPEN'\n" +
" and appointment_method like 'AUTO%' and a.appointment_status in ('CONFIRM')\n" +
" and order_status ='NORMAL' and service_status='INIT'\n" +
" order by a.expect_time_begin asc ",
nativeQuery = true)
List<Map<String,Object>> getNewDispatchConfirmOrder(String groupId, String batchNo, String teamId, String batchDay);
} }
\ No newline at end of file
...@@ -19,202 +19,203 @@ import lombok.Data; ...@@ -19,202 +19,203 @@ import lombok.Data;
@PlanningEntity @PlanningEntity
public class Technician { public class Technician {
@PlanningId @PlanningId
private long id; private long id;
private String code; private String code;
@JsonIgnore @JsonIgnore
private Depot depot; private Depot depot;
// 上班时间窗 分钟480-1080 8-18点 // 上班时间窗 分钟480-1080 8-18点
// private int startTime; // private int startTime;
// private int endTime; // private int endTime;
/** /**
* 上班多时间窗 * 上班多时间窗
* 时间窗格式:[[起始时间段1,结束时间段1],[起始时间段2,结束时间段2]...] * 时间窗格式:[[起始时间段1,结束时间段1],[起始时间段2,结束时间段2]...]
* 时间格式:从0点开始的分钟数,如早上8点为480. * 时间格式:从0点开始的分钟数,如早上8点为480.
*/ */
private int[][] timeWindows; private int[][] timeWindows;
// 技能 // 技能
private Set<String> skills; private Set<String> skills;
// 偏好坐标 // 偏好坐标
private Location preferredlocation; private Location preferredlocation;
// technician code : customer code , distance // technician code : customer code , distance
@JsonIgnore @JsonIgnore
private Map<String, Long> preferredlocationDistanceMap = new HashMap<String, Long>(); private Map<String, Long> preferredlocationDistanceMap = new HashMap<String, Long>();
// 每日最大单量 // 每日最大单量
private int maxCount; private int maxCount;
// 每日最大工作时长 // 每日最大工作时长
private int maxMinute; private int maxMinute;
// 单位是米,这里要注意 // 单位是米,这里要注意
private int maxDistanceMeter; private int maxDistanceMeter;
// 交通方式 1汽车;2电动车;3自行车;4步行 默认是汽车 // 交通方式 1汽车;2电动车;3自行车;4步行 默认是汽车
private Integer vehicleType; private Integer vehicleType;
@PlanningListVariable @PlanningListVariable
private List<Customer> customerList = new ArrayList<>(); private List<Customer> customerList = new ArrayList<>();
public Technician() { public Technician() {
} }
public Technician(long id, String code, Depot depot, int startTime, int endTime, Set<String> skills, public Technician(long id, String code, Depot depot, int startTime, int endTime, Set<String> skills,
Map<String, Long> preferredlocationDistanceMap, Location preferredlocation) { Map<String, Long> preferredlocationDistanceMap, Location preferredlocation) {
this.id = id; this.id = id;
this.code = code; this.code = code;
this.depot = depot; this.depot = depot;
this.timeWindows = new int[][] { new int[] { startTime, endTime } }; this.timeWindows = new int[][]{new int[]{startTime, endTime}};
this.skills = skills; this.skills = skills;
this.preferredlocationDistanceMap = preferredlocationDistanceMap; this.preferredlocationDistanceMap = preferredlocationDistanceMap;
this.preferredlocation = preferredlocation; this.preferredlocation = preferredlocation;
} }
public Technician(long id, String code, int maxCount, int maxMinute, int maxDistanceMeter, Depot depot, public Technician(long id, String code, int maxCount, int maxMinute, int maxDistanceMeter, Depot depot,
int startTime, int endTime, Set<String> skills, Map<String, Long> preferredlocationDistanceMap) { int startTime, int endTime, Set<String> skills, Map<String, Long> preferredlocationDistanceMap) {
this.id = id; this.id = id;
this.code = code; this.code = code;
this.depot = depot; this.depot = depot;
this.timeWindows = new int[][] { new int[] { startTime, endTime } }; this.timeWindows = new int[][]{new int[]{startTime, endTime}};
this.skills = skills; this.skills = skills;
this.maxCount = maxCount;
this.maxMinute = maxMinute;
this.maxDistanceMeter = maxDistanceMeter;
this.preferredlocationDistanceMap = preferredlocationDistanceMap;
}
public Technician(long id, String code, int maxCount, int maxMinute, int maxDistanceMeter, Integer vehicleType, Depot depot,
int startTime, int endTime, Set<String> skills, Map<String, Long> preferredlocationDistanceMap) {
this.id = id;
this.code = code;
this.maxCount = maxCount; this.maxCount = maxCount;
this.maxMinute = maxMinute; this.maxMinute = maxMinute;
this.maxDistanceMeter = maxDistanceMeter; this.maxDistanceMeter = maxDistanceMeter;
this.preferredlocationDistanceMap = preferredlocationDistanceMap; this.vehicleType = vehicleType;
} this.depot = depot;
this.timeWindows = new int[][]{new int[]{startTime, endTime}};
public Technician(long id, String code, int maxCount, int maxMinute, int maxDistanceMeter, Integer vehicleType, Depot depot, this.skills = skills;
int startTime, int endTime, Set<String> skills, Map<String, Long> preferredlocationDistanceMap) { this.preferredlocationDistanceMap = preferredlocationDistanceMap;
this.id = id; }
this.code = code;
this.depot = depot; // ************************************************************************
this.timeWindows = new int[][] { new int[] { startTime, endTime } }; // Complex methods
this.skills = skills; // ************************************************************************
this.maxCount = maxCount;
this.maxMinute = maxMinute; /**
this.maxDistanceMeter = maxDistanceMeter; * @return route of the vehicle
this.preferredlocationDistanceMap = preferredlocationDistanceMap; */
} @JsonIgnore
public List<Location> getRoute() {
// ************************************************************************ if (customerList.isEmpty()) {
// Complex methods return Collections.emptyList();
// ************************************************************************ }
/** List<Location> route = new ArrayList<Location>();
* @return route of the vehicle
*/ route.add(depot.getLocation());
@JsonIgnore for (Customer customer : customerList) {
public List<Location> getRoute() { route.add(customer.getLocation());
if (customerList.isEmpty()) { }
return Collections.emptyList();
} return route;
}
List<Location> route = new ArrayList<Location>();
/**
route.add(depot.getLocation()); * 总路线距离
for (Customer customer : customerList) { *
route.add(customer.getLocation()); * @return
} */
public long getTotalDistanceMeters() {
return route; if (customerList.isEmpty()) {
} return 0;
}
/**
* 总路线距离 long totalDistance = 0;
* Location previousLocation = depot.getLocation();
* @return
*/ for (Customer customer : customerList) {
public long getTotalDistanceMeters() { totalDistance += previousLocation.getDistanceTo(this.getVehicleType(), customer.getLocation());
if (customerList.isEmpty()) { previousLocation = customer.getLocation();
return 0; }
} totalDistance += previousLocation.getDistanceTo(this.getVehicleType(), depot.getLocation());
long totalDistance = 0; return totalDistance;
Location previousLocation = depot.getLocation(); }
for (Customer customer : customerList) { /**
totalDistance += previousLocation.getDistanceTo(this.getVehicleType(),customer.getLocation()); * 获取偏好总距离 所有customer与该技术员的PreferredLocation距离之和
previousLocation = customer.getLocation(); *
} * @return
totalDistance += previousLocation.getDistanceTo(this.getVehicleType(), depot.getLocation()); */
public long getPreferredTotalDistanceMeters() {
return totalDistance; if (customerList.isEmpty()) {
} return 0;
}
/**
* 获取偏好总距离 所有customer与该技术员的PreferredLocation距离之和 long totalDistance = 0;
* for (Customer customer : customerList) {
* @return totalDistance += preferredlocationDistanceMap.get(customer.getCode());
*/ }
public long getPreferredTotalDistanceMeters() { return totalDistance;
if (customerList.isEmpty()) { }
return 0;
} public int getCustomerSize() {
return customerList.size();
long totalDistance = 0; }
for (Customer customer : customerList) {
totalDistance += preferredlocationDistanceMap.get(customer.getCode()); /**
} * 获取总上班时间,第一个订单到最后一个订单时间跨度
return totalDistance; *
} * @return
*/
public int getCustomerSize() { public int getWorkTime() {
return customerList.size(); int size = customerList.size();
} if (0 == size) {
return 0;
/** } else {
* 获取总上班时间,第一个订单到最后一个订单时间跨度 return customerList.get(size - 1).getArrivalTime() + customerList.get(size - 1).getServiceDuration()
* - customerList.get(0).getArrivalTime();
* @return }
*/ }
public int getWorkTime() {
int size = customerList.size(); /**
if (0 == size) { * 获取下班时间,最后一个订单完成时间
return 0; *
} else { * @return
return customerList.get(size - 1).getArrivalTime() + customerList.get(size - 1).getServiceDuration() */
- customerList.get(0).getArrivalTime(); public int getOffWorkTime() {
} int size = customerList.size();
} if (0 == size) {
return 0;
/** } else {
* 获取下班时间,最后一个订单完成时间 Customer lastCustomer = customerList.get(size - 1);
* return lastCustomer.getDepartureTime();
* @return }
*/ }
public int getOffWorkTime() {
int size = customerList.size(); @Override
if (0 == size) { public int hashCode() {
return 0; return Long.valueOf(this.id).hashCode();
} else { }
Customer lastCustomer = customerList.get(size - 1);
return lastCustomer.getDepartureTime(); @Override
} public boolean equals(Object obj) {
} if (obj == null)
return false;
@Override if (!(obj instanceof Technician))
public int hashCode() { return false;
return Long.valueOf(this.id).hashCode(); if (obj == this)
} return true;
return this.id == ((Technician) obj).getId();
@Override }
public boolean equals(Object obj) {
if (obj == null) @Override
return false; public String toString() {
if (!(obj instanceof Technician)) return "Technician{" + "id=" + id + ", code='" + code + '\'' + ", depot=" + depot + ", timeWindows=" + timeWindows
return false; + ", skills=" + skills + ", maxCount=" + maxCount + ", maxMinute=" + maxMinute
if (obj == this) + ", maxDistanceMeter=" + maxDistanceMeter + '}';
return true; }
return this.id == ((Technician) obj).getId();
}
@Override
public String toString() {
return "Technician{" + "id=" + id + ", code='" + code + '\'' + ", depot=" + depot + ", timeWindows=" + timeWindows
+ ", skills=" + skills + ", maxCount=" + maxCount + ", maxMinute=" + maxMinute
+ ", maxDistanceMeter=" + maxDistanceMeter + '}';
}
} }
...@@ -230,40 +230,54 @@ public class BatchServiceImpl implements BatchService { ...@@ -230,40 +230,54 @@ public class BatchServiceImpl implements BatchService {
//dispatchOrderRepository.deleteAllInBatch(dispatchOrderRepository.findByTeamIdAndBatchNo(teamId,batchNo)); //dispatchOrderRepository.deleteAllInBatch(dispatchOrderRepository.findByTeamIdAndBatchNo(teamId,batchNo));
log.info("写入新批次技术员、工单数据, teamId:{}, day:{}, batchNo:{}", teamId, batchDay, batchNo); log.info("写入新批次技术员、工单数据, teamId:{}, day:{}, batchNo:{}", teamId, batchDay, batchNo);
String sqlEngineer = "INSERT INTO dispatch_engineer (group_id, team_id, batch_no, engineer_code, engineer_name, x, y, max_num, max_minute, max_distance, vehicle_type)\n" // String sqlEngineer = "INSERT INTO dispatch_engineer (group_id, team_id, batch_no, engineer_code, engineer_name, x, y, max_num, max_minute, max_distance, vehicle_type)\n"
+ "SELECT ?, o.team_id,?,o.engineer_code, a.name , b.x, b.y , max_num, max_minute, max_distance, b.vehicle FROM `org_team_engineer` o\n" // + "SELECT ?, o.team_id,?,o.engineer_code, a.name , b.x, b.y , max_num, max_minute, max_distance, b.vehicle FROM `org_team_engineer` o\n"
+ " join engineer_info a on o.engineer_code=a.engineer_code\n" // + " join engineer_info a on o.engineer_code=a.engineer_code\n"
+ " left join engineer_business b on a.engineer_code = b.engineer_code\n" // + " left join engineer_business b on a.engineer_code = b.engineer_code\n"
+ " WHERE o.team_id=? AND o.`status`=1\n" // + " WHERE o.team_id=? AND o.`status`=1\n"
//+ " AND b.x IS NOT NULL AND b.x !=''" // //+ " AND b.x IS NOT NULL AND b.x !=''"
+ " order by a.engineer_code asc"; // + " order by a.engineer_code asc";
int engCount = jdbcTemplate.update(sqlEngineer, groupId, batchNo, teamId); // int engCount = jdbcTemplate.update(sqlEngineer, groupId, batchNo, teamId);
List<Map<String, Object>> engMapList = dispatchEngineerRepository.getNewDispatchEngineer(groupId, batchNo, teamId);
List<DispatchEngineer> engList = JSONObject.parseArray(JSONObject.toJSONString(engMapList), DispatchEngineer.class);
engList.forEach(eng -> eng.setExt(null));
dispatchEngineerRepository.saveAll(engList);
int engCount = engList.size();
// 未派过的工单(已派过PRE状态还可以再次派) // 未派过的工单(已派过PRE状态还可以再次派)
String sqlOrder = "INSERT INTO dispatch_order (group_id, batch_no, team_id, order_id , dt, x, y, \n" // String sqlOrder = "INSERT INTO dispatch_order (group_id, batch_no, team_id, order_id , dt, x, y, \n"
+ " expect_time_begin, expect_time_end, tags, priority , skills , take_time, status )\n" // + " expect_time_begin, expect_time_end, tags, priority , skills , take_time, status )\n"
+ " SELECT ?, ?, a.org_team_id , a.order_id, ?, a.x, a.y , \n" // + " SELECT ? group_id, ? batch_no, a.org_team_id team_id, a.order_id, a.dt dt, a.x, a.y , \n"
+ " a.expect_time_begin, a.expect_time_end, a.tags, a.priority , \n" // + " a.expect_time_begin, a.expect_time_end, a.tags, a.priority , \n"
+ " CONCAT(a.brand, '-', a.type, '-', a.skill) skills , a.take_time , a.appointment_status\n" // + " CONCAT(a.brand, '-', a.type, '-', a.skill) skills , a.take_time , a.appointment_status status\n"
+ " FROM order_info a \n" + " WHERE a.org_team_id=? AND a.dt = ? AND bean_status='OPEN'\n" // + " FROM order_info a \n" + " WHERE a.org_team_id=? AND a.dt = ? AND bean_status='OPEN'\n"
+ " AND appointment_method LIKE 'AUTO%' AND a.appointment_status IN ('INIT', 'PRE')\n" // + " AND appointment_method LIKE 'AUTO%' AND a.appointment_status IN ('INIT', 'PRE')\n"
+ " AND order_status ='NORMAL' AND service_status='INIT'\n" // + " AND order_status ='NORMAL' AND service_status='INIT'\n"
+ " ORDER BY a.expect_time_begin ASC \n"; // + " ORDER BY a.expect_time_begin ASC \n";
int orderCount = jdbcTemplate.update(sqlOrder, groupId, batchNo, batchDay, teamId, batchDay); // int orderCount = jdbcTemplate.update(sqlOrder, groupId, batchNo, batchDay, teamId, batchDay);
List<Map<String, Object>> orderList = dispatchOrderRepository.getNewDispatchOrder(groupId, batchNo, teamId, batchDay);
dispatchOrderRepository.saveAll(JSONObject.parseArray(JSONObject.toJSONString(orderList), DispatchOrder.class));
int orderCount = orderList.size();
// confirm的要做预占用,所以也加入进来 // confirm的要做预占用,所以也加入进来
String sqlOrderConfirm = "INSERT INTO dispatch_order (group_id, batch_no, team_id, order_id , dt, x, y, \n" + // String sqlOrderConfirm = "INSERT INTO dispatch_order (group_id, batch_no, team_id, order_id , dt, x, y, \n" +
" expect_time_begin, expect_time_end, tags, priority , skills , take_time, status, engineer_code, time_begin, time_end )\n" + // " expect_time_begin, expect_time_end, tags, priority , skills , take_time, status, engineer_code, time_begin, time_end )\n" +
" select ?, ?, a.org_team_id , a.order_id, a.dt, a.x, a.y , \n" + // " select ? group_id, ? batch_no, a.org_team_id team_id, a.order_id, a.dt, a.x, a.y , \n" +
" a.expect_time_begin, a.expect_time_end, a.tags, a.priority , \n" + // " a.expect_time_begin, a.expect_time_end, a.tags, a.priority , \n" +
" concat(a.brand, '-', a.type, '-', a.skill) skills , a.take_time, a.appointment_status, \n" + // " concat(a.brand, '-', a.type, '-', a.skill) skills , a.take_time, a.appointment_status status, \n" +
" a.engineer_code, a.plan_start_time, a.plan_end_time \n" + // " a.engineer_code, a.plan_start_time time_begin, a.plan_end_time time_end \n" +
" from order_info a \n" + // " from order_info a \n" +
" where a.org_team_id=? and a.dt = ? and bean_status='OPEN'\n" + // " where a.org_team_id=? and a.dt = ? and bean_status='OPEN'\n" +
" and appointment_method like 'AUTO%' and a.appointment_status in ('CONFIRM')\n" + // " and appointment_method like 'AUTO%' and a.appointment_status in ('CONFIRM')\n" +
" and order_status ='NORMAL' and service_status='INIT'\n" + // " and order_status ='NORMAL' and service_status='INIT'\n" +
" order by a.expect_time_begin asc "; // " order by a.expect_time_begin asc ";
int orderConfirmCount = jdbcTemplate.update(sqlOrderConfirm, groupId, batchNo, teamId, batchDay); // int orderConfirmCount = jdbcTemplate.update(sqlOrderConfirm, groupId, batchNo, teamId, batchDay);
List<Map<String, Object>> orderConfirmList = dispatchOrderRepository.getNewDispatchConfirmOrder(groupId, batchNo, teamId, batchDay);
dispatchOrderRepository.saveAll(JSONObject.parseArray(JSONObject.toJSONString(orderConfirmList), DispatchOrder.class));
int orderConfirmCount = orderConfirmList.size();
log.info("准备批次数据 engCount:{}, orderCount:{}, orderConfirmCount:{}", engCount, orderCount, orderConfirmCount); log.info("准备批次数据 engCount:{}, orderCount:{}, orderConfirmCount:{}", engCount, orderCount, orderConfirmCount);
......
...@@ -3,7 +3,7 @@ server: ...@@ -3,7 +3,7 @@ server:
dispatch: dispatch:
cron: cron:
expr: 0 10 8-22 * * ? expr: 0 47 8-22 * * ?
next-day-limit: 2 next-day-limit: 2
# expr: 0 */10 8-18 * * ? # expr: 0 */10 8-18 * * ?
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!