Commit a5572131 by 刘鑫

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

2 parents 03b4a352 8905fedb
Showing with 485 additions and 293 deletions
......@@ -26,7 +26,7 @@ public enum ConstraintNameEnum {
*/
technicianCapacityMatch,
/**
* 已分配匹配
* 已分配和已排除技术员匹配
*/
dispatchedMatch,
......
......@@ -93,10 +93,14 @@ public class DispatchConstraintProvider implements ConstraintProvider {
}
protected Constraint dispatchedMatch(ConstraintFactory factory) {
return factory.forEach(Customer.class)
.filter(customer -> customer.getDispatchedTechnicianCode() != null
&& ((customer.getTechnician() == null) || (!StringUtils
.equals(customer.getDispatchedTechnicianCode(), customer.getTechnician().getCode()))))
return factory.forEach(Customer.class).filter(customer ->
// 已分配
(customer.getDispatchedTechnicianCode() != null && ((customer.getTechnician() == null)
|| (!StringUtils.equals(customer.getDispatchedTechnicianCode(), customer.getTechnician().getCode()))))
||
// 已排除
(customer.getExclusiveTechnicianCode() != null && ((customer.getTechnician() == null) || (StringUtils
.equals(customer.getExclusiveTechnicianCode(), customer.getTechnician().getCode())))))
.penalizeLong(HardSoftLongScore.ONE_HARD, customer -> 50)
.asConstraint(ConstraintNameEnum.dispatchedMatch.name());
}
......
......@@ -2,15 +2,24 @@ package com.dituhui.pea.dispatch.dao;
import com.dituhui.pea.dispatch.entity.DispatchEngineer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
import java.util.Map;
public interface DispatchEngineerRepository extends CrudRepository<DispatchEngineer, Long>, JpaRepository<DispatchEngineer, Long> {
List<DispatchEngineer> findByGroupId(String groupId);
List<DispatchEngineer> findByGroupIdAndBatchNo(String groupId, 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;
import com.dituhui.pea.dispatch.entity.DispatchEngineer;
import com.dituhui.pea.dispatch.entity.DispatchOrder;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public interface DispatchOrderRepository extends CrudRepository<DispatchOrder, Long>, JpaRepository<DispatchOrder, Long> {
......@@ -34,4 +36,30 @@ public interface DispatchOrderRepository extends CrudRepository<DispatchOrder, L
Optional<DispatchOrder> findByGroupIdAndBatchNoAndOrderIdAndDt(String groupId, String batchNo, String orderId, String dt);
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
......@@ -21,8 +21,12 @@ public class Customer {
private long id;
private String code;
// 已分配
private String dispatchedTechnicianCode;
// 已排除
private String exclusiveTechnicianCode;
// orderid(code)+dt 确定唯一一条工单
private String dt;
@JsonIgnore
......
......@@ -19,202 +19,203 @@ import lombok.Data;
@PlanningEntity
public class Technician {
@PlanningId
private long id;
private String code;
@JsonIgnore
private Depot depot;
// 上班时间窗 分钟480-1080 8-18点
// private int startTime;
// private int endTime;
/**
* 上班多时间窗
* 时间窗格式:[[起始时间段1,结束时间段1],[起始时间段2,结束时间段2]...]
* 时间格式:从0点开始的分钟数,如早上8点为480.
*/
private int[][] timeWindows;
// 技能
private Set<String> skills;
// 偏好坐标
private Location preferredlocation;
// technician code : customer code , distance
@JsonIgnore
private Map<String, Long> preferredlocationDistanceMap = new HashMap<String, Long>();
// 每日最大单量
private int maxCount;
// 每日最大工作时长
private int maxMinute;
// 单位是米,这里要注意
private int maxDistanceMeter;
// 交通方式 1汽车;2电动车;3自行车;4步行 默认是汽车
private Integer vehicleType;
@PlanningListVariable
private List<Customer> customerList = new ArrayList<>();
public Technician() {
}
public Technician(long id, String code, Depot depot, int startTime, int endTime, Set<String> skills,
Map<String, Long> preferredlocationDistanceMap, Location preferredlocation) {
this.id = id;
this.code = code;
this.depot = depot;
this.timeWindows = new int[][] { new int[] { startTime, endTime } };
this.skills = skills;
this.preferredlocationDistanceMap = preferredlocationDistanceMap;
this.preferredlocation = preferredlocation;
}
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) {
this.id = id;
this.code = code;
this.depot = depot;
this.timeWindows = new int[][] { new int[] { startTime, endTime } };
this.skills = skills;
@PlanningId
private long id;
private String code;
@JsonIgnore
private Depot depot;
// 上班时间窗 分钟480-1080 8-18点
// private int startTime;
// private int endTime;
/**
* 上班多时间窗
* 时间窗格式:[[起始时间段1,结束时间段1],[起始时间段2,结束时间段2]...]
* 时间格式:从0点开始的分钟数,如早上8点为480.
*/
private int[][] timeWindows;
// 技能
private Set<String> skills;
// 偏好坐标
private Location preferredlocation;
// technician code : customer code , distance
@JsonIgnore
private Map<String, Long> preferredlocationDistanceMap = new HashMap<String, Long>();
// 每日最大单量
private int maxCount;
// 每日最大工作时长
private int maxMinute;
// 单位是米,这里要注意
private int maxDistanceMeter;
// 交通方式 1汽车;2电动车;3自行车;4步行 默认是汽车
private Integer vehicleType;
@PlanningListVariable
private List<Customer> customerList = new ArrayList<>();
public Technician() {
}
public Technician(long id, String code, Depot depot, int startTime, int endTime, Set<String> skills,
Map<String, Long> preferredlocationDistanceMap, Location preferredlocation) {
this.id = id;
this.code = code;
this.depot = depot;
this.timeWindows = new int[][]{new int[]{startTime, endTime}};
this.skills = skills;
this.preferredlocationDistanceMap = preferredlocationDistanceMap;
this.preferredlocation = preferredlocation;
}
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) {
this.id = id;
this.code = code;
this.depot = depot;
this.timeWindows = new int[][]{new int[]{startTime, endTime}};
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.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.depot = depot;
this.timeWindows = new int[][] { new int[] { startTime, endTime } };
this.skills = skills;
this.maxCount = maxCount;
this.maxMinute = maxMinute;
this.maxDistanceMeter = maxDistanceMeter;
this.preferredlocationDistanceMap = preferredlocationDistanceMap;
}
// ************************************************************************
// Complex methods
// ************************************************************************
/**
* @return route of the vehicle
*/
@JsonIgnore
public List<Location> getRoute() {
if (customerList.isEmpty()) {
return Collections.emptyList();
}
List<Location> route = new ArrayList<Location>();
route.add(depot.getLocation());
for (Customer customer : customerList) {
route.add(customer.getLocation());
}
return route;
}
/**
* 总路线距离
*
* @return
*/
public long getTotalDistanceMeters() {
if (customerList.isEmpty()) {
return 0;
}
long totalDistance = 0;
Location previousLocation = depot.getLocation();
for (Customer customer : customerList) {
totalDistance += previousLocation.getDistanceTo(this.getVehicleType(),customer.getLocation());
previousLocation = customer.getLocation();
}
totalDistance += previousLocation.getDistanceTo(this.getVehicleType(), depot.getLocation());
return totalDistance;
}
/**
* 获取偏好总距离 所有customer与该技术员的PreferredLocation距离之和
*
* @return
*/
public long getPreferredTotalDistanceMeters() {
if (customerList.isEmpty()) {
return 0;
}
long totalDistance = 0;
for (Customer customer : customerList) {
totalDistance += preferredlocationDistanceMap.get(customer.getCode());
}
return totalDistance;
}
public int getCustomerSize() {
return customerList.size();
}
/**
* 获取总上班时间,第一个订单到最后一个订单时间跨度
*
* @return
*/
public int getWorkTime() {
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 getOffWorkTime() {
int size = customerList.size();
if (0 == size) {
return 0;
} else {
Customer lastCustomer = customerList.get(size - 1);
return lastCustomer.getDepartureTime();
}
}
@Override
public int hashCode() {
return Long.valueOf(this.id).hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (!(obj instanceof Technician))
return false;
if (obj == this)
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 + '}';
}
this.vehicleType = vehicleType;
this.depot = depot;
this.timeWindows = new int[][]{new int[]{startTime, endTime}};
this.skills = skills;
this.preferredlocationDistanceMap = preferredlocationDistanceMap;
}
// ************************************************************************
// Complex methods
// ************************************************************************
/**
* @return route of the vehicle
*/
@JsonIgnore
public List<Location> getRoute() {
if (customerList.isEmpty()) {
return Collections.emptyList();
}
List<Location> route = new ArrayList<Location>();
route.add(depot.getLocation());
for (Customer customer : customerList) {
route.add(customer.getLocation());
}
return route;
}
/**
* 总路线距离
*
* @return
*/
public long getTotalDistanceMeters() {
if (customerList.isEmpty()) {
return 0;
}
long totalDistance = 0;
Location previousLocation = depot.getLocation();
for (Customer customer : customerList) {
totalDistance += previousLocation.getDistanceTo(this.getVehicleType(), customer.getLocation());
previousLocation = customer.getLocation();
}
totalDistance += previousLocation.getDistanceTo(this.getVehicleType(), depot.getLocation());
return totalDistance;
}
/**
* 获取偏好总距离 所有customer与该技术员的PreferredLocation距离之和
*
* @return
*/
public long getPreferredTotalDistanceMeters() {
if (customerList.isEmpty()) {
return 0;
}
long totalDistance = 0;
for (Customer customer : customerList) {
totalDistance += preferredlocationDistanceMap.get(customer.getCode());
}
return totalDistance;
}
public int getCustomerSize() {
return customerList.size();
}
/**
* 获取总上班时间,第一个订单到最后一个订单时间跨度
*
* @return
*/
public int getWorkTime() {
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 getOffWorkTime() {
int size = customerList.size();
if (0 == size) {
return 0;
} else {
Customer lastCustomer = customerList.get(size - 1);
return lastCustomer.getDepartureTime();
}
}
@Override
public int hashCode() {
return Long.valueOf(this.id).hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (!(obj instanceof Technician))
return false;
if (obj == this)
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 + '}';
}
}
......@@ -209,7 +209,6 @@ public class InitEngineerCapacityScheduler {
statEntity.setMaxDuration((int) stats.getRemain());
statEntity.setUpdateTime(LocalDateTime.now());
capacityEngineerStatDao.save(statEntity);
log.info("====== 处理完毕 ======");
}
public void initOneEngineerByDays(String bdate, String edate, String branchId) {
......
......@@ -69,7 +69,7 @@ public class BatchScheduler {
String currDay = LocalDate.now().plusDays(i).format(DateTimeFormatter.ISO_LOCAL_DATE);
log.info("dispatchRun begin----- teamId:{}, day:{}", teamId, currDay);
String batchNo = batchService.buildBatchData2(teamId, currDay);
String batchNo = batchService.buildBatchData2(teamId, currDay, false);
UUID problemId = solveService.generateProblemId(teamId, batchNo);
log.info("dispatchRun teamId:{}, day:{}, batch:{}, problemId:{}", teamId, currDay, batchNo, problemId);
......
......@@ -24,7 +24,7 @@ public interface BatchService {
void saveDispatchBatch(DispatchBatch batchInfo);
// 小队id
public String buildBatchData2(String teamId, String day);
public String buildBatchData2(String teamId, String day, boolean cutOff);
public DispatchBatch queryBatchInfoByDay2(String teamId, String day);
......
......@@ -192,7 +192,7 @@ public class BatchServiceImpl implements BatchService {
// 检查给定小队、日期是否有在运行的批次任务,没则返回,没有则创建
@Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
@Override
public String buildBatchData2(String teamId, String day) {
public String buildBatchData2(String teamId, String day, boolean cutOff) {
OrgTeamEntity orgTeamEntity = orgTeamDao.findByTeamId(teamId);
String groupId = orgTeamEntity.getGroupId();
entityManager.clear();
......@@ -230,50 +230,64 @@ public class BatchServiceImpl implements BatchService {
//dispatchOrderRepository.deleteAllInBatch(dispatchOrderRepository.findByTeamIdAndBatchNo(teamId,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"
+ "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"
+ " left join engineer_business b on a.engineer_code = b.engineer_code\n"
+ " WHERE o.team_id=? AND o.`status`=1\n"
//+ " AND b.x IS NOT NULL AND b.x !=''"
+ " order by a.engineer_code asc";
int engCount = jdbcTemplate.update(sqlEngineer, groupId, batchNo, teamId);
// 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"
// + " 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=? AND o.`status`=1\n"
// //+ " AND b.x IS NOT NULL AND b.x !=''"
// + " order by a.engineer_code asc";
// 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状态还可以再次派)
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"
+ " SELECT ?, ?, a.org_team_id , a.order_id, ?, 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\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 order_status ='NORMAL' AND service_status='INIT'\n"
+ " ORDER BY a.expect_time_begin ASC \n";
int orderCount = jdbcTemplate.update(sqlOrder, groupId, batchNo, batchDay, teamId, batchDay);
// 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"
// + " 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"
// + " 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"
// + " 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";
// 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的要做预占用,所以也加入进来
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" +
" select ?, ?, a.org_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" +
" concat(a.brand, '-', a.type, '-', a.skill) skills , a.take_time, a.appointment_status, \n" +
" a.engineer_code, a.plan_start_time, a.plan_end_time \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 ('CONFIRM')\n" +
" and order_status ='NORMAL' and service_status='INIT'\n" +
" order by a.expect_time_begin asc ";
int orderConfirmCount = jdbcTemplate.update(sqlOrderConfirm, groupId, batchNo, teamId, batchDay);
// 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" +
// " 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" +
// " concat(a.brand, '-', a.type, '-', a.skill) skills , a.take_time, a.appointment_status status, \n" +
// " a.engineer_code, a.plan_start_time time_begin, a.plan_end_time time_end \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 ('CONFIRM')\n" +
// " and order_status ='NORMAL' and service_status='INIT'\n" +
// " order by a.expect_time_begin asc ";
// 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);
if (orderCount + orderConfirmCount > 0) {
jdbcTemplate.update("update dispatch_batch set engineer_num=? , order_num=?, start_time=?, end_time=null, status='RUNNING' where team_id=? and batch_no=?",
engCount, orderCount + orderConfirmCount, LocalDateTime.now(), teamId, batchNo);
jdbcTemplate.update("update dispatch_batch set engineer_num=? , order_num=?, start_time=?, end_time=null, status='RUNNING', cutoffed_time=? where team_id=? and batch_no=?",
engCount, orderCount + orderConfirmCount, LocalDateTime.now(), cutOff ? LocalDateTime.now() : null, teamId, batchNo);
} else {
jdbcTemplate.update("update dispatch_batch set engineer_num=? , order_num=?, start_time=?, end_time=?, status='DONE' where team_id=? and batch_no=?",
engCount, 0, LocalDateTime.now(), LocalDateTime.now(), teamId, batchNo);
jdbcTemplate.update("update dispatch_batch set engineer_num=? , order_num=?, start_time=?, end_time=?, status='DONE', cutoffed_time=? where team_id=? and batch_no=?",
engCount, 0, LocalDateTime.now(), LocalDateTime.now(), cutOff ? LocalDateTime.now() : null, teamId, batchNo);
}
log.info("准备批次数据完成, teamId:{}, day:{}, batchNo:{}", teamId, batchDay, batchNo);
......
package com.dituhui.pea.dispatch.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.dituhui.pea.dispatch.dao.DispatchBatchRepository;
import com.dituhui.pea.dispatch.dao.OrgGroupRepository;
import com.dituhui.pea.dispatch.dao.OrgTeamDao;
import com.dituhui.pea.dispatch.entity.DispatchBatch;
import com.dituhui.pea.dispatch.entity.OrgGroup;
import com.dituhui.pea.dispatch.entity.OrgTeamEntity;
import com.dituhui.pea.dispatch.pojo.DispatchSolution;
import com.dituhui.pea.dispatch.service.BatchService;
......@@ -18,10 +25,13 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.io.File;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
/**
......@@ -34,6 +44,9 @@ import java.util.UUID;
@Slf4j
public class SchedulerServiceImpl implements SchedulerService {
//默认指派策略
public static final String DEFAULT_STRATEGY_APPOINTMENT = "指派给信息员";
@Value("${dispatch.cron.next-day-limit}")
int nextDaysLimit = 2;
......@@ -49,7 +62,13 @@ public class SchedulerServiceImpl implements SchedulerService {
@Autowired
OrgTeamDao orgTeamDao;
@Autowired
OrgGroupRepository orgGroupRepository;
private DefaultSolverFactory<DispatchSolution> solverFactory;
@Resource
private DispatchBatchRepository dispatchBatchRepository;
//private Solver<DispatchSolution> solver;
public SchedulerServiceImpl() {
......@@ -65,14 +84,44 @@ public class SchedulerServiceImpl implements SchedulerService {
return;
}
OrgGroup orgGroup=orgGroupRepository.findByGroupId(orgTeamEntity.getGroupId()).get();
if (ObjectUtil.equals(2, orgGroup.getCategory())) {
log.error(">>> teamId:{} 来自网点,不自动派工", teamId);
return;
}
String cutOffTime = orgTeamEntity.getCuteOff();
if (StrUtil.isEmpty(cutOffTime)) {
cutOffTime = "18:00";
}
LocalDateTime now = LocalDateTime.now();
String nowTime = DateUtil.format(now, "HH:mm");
String nowTimePlus30 = DateUtil.format(now.plusMinutes(30), "HH:mm");
boolean cutOff = false;
//当前时间大于等于截止时间,或者当前时间+30分钟大于截止时间,运行停止
if (nowTime.compareTo(cutOffTime) >= 0 || nowTimePlus30.compareTo(cutOffTime) > 0) {
cutOff = true;
}
String groupId = orgTeamEntity.getGroupId();
log.info("dispatchRun group:{}, team:{} done", groupId, teamId);
for (int i = 1; i <= nextDaysLimit; i++) {
String currDay = LocalDate.now().plusDays(i).format(DateTimeFormatter.ISO_LOCAL_DATE);
Optional<DispatchBatch> optional = dispatchBatchRepository.findByTeamIdAndBatchDate(teamId, currDay);
if (optional.isPresent() && Objects.nonNull(optional.get().getCutoffedTime())) {
//自动任务截止
log.error(">>> teamId:{}, day:{} 自动任务已截止", teamId, currDay);
continue;
}
try {
log.info("dispatchRun begin----- teamId:{}, day:{}", teamId, currDay);
String batchNo = batchService.buildBatchData2(teamId, currDay);
String batchNo = batchService.buildBatchData2(teamId, currDay, cutOff);
UUID problemId = solveService.generateProblemId(teamId, batchNo);
log.info("dispatchRun teamId:{}, day:{}, batch:{}, problemId:{}", teamId, currDay, batchNo, problemId);
......@@ -88,7 +137,7 @@ public class SchedulerServiceImpl implements SchedulerService {
DispatchSolutionUtils.removeHardConstraintCustomer(solution, solverFactory);
log.info("dispatchRun solve done, teamId:{}, day:{}, batch:{}, problemId:{}, score:{}", teamId, currDay, batchNo, problemId, solution.getScore().toShortString());
this.solveService.saveSolutionWrp2(solution);
this.extractService.extractDispatchToOrder2(teamId, batchNo, false);
this.extractService.extractDispatchToOrder2(teamId, batchNo, cutOff);
log.info("dispatchRun done ------ teamId:{}, day:{}", teamId, currDay);
JacksonSolutionFileIO<DispatchSolution> exporter = new JacksonSolutionFileIO<DispatchSolution>(DispatchSolution.class);
......
......@@ -3,7 +3,7 @@ server:
dispatch:
cron:
expr: 0 10 8-22 * * ?
expr: 0 14 8-22 * * ?
next-day-limit: 2
# expr: 0 */10 8-18 * * ?
......@@ -49,12 +49,12 @@ spring:
enabled: false
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://127.0.0.1:3306/saas_aftersale_test?serverTimezone=Asia/Shanghai
# username: root
# password: 123456
url: jdbc:mysql://localhost:32306/saas_aftersale_test?serverTimezone=Asia/Shanghai
username: boxi
password: boxi_dev_0725
url: jdbc:mysql://127.0.0.1:3306/saas_aftersale_test?serverTimezone=Asia/Shanghai
username: root
password: 123456
# url: jdbc:mysql://localhost:32306/saas_aftersale_test?serverTimezone=Asia/Shanghai
# username: boxi
# password: boxi_dev_0725
type: com.alibaba.druid.pool.DruidDataSource
jpa:
......
......@@ -20,7 +20,7 @@
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
<level>DEBUG</level>
</filter>
<!-- 日志输出编码 -->
<encoder>
......@@ -111,9 +111,10 @@
</appender>
<logger name="org.optaplanner" level="info"/>
<logger name="org.springframework.jdbc.core.JdbcTemplate" level="debug" />
<!-- 日志输出级别 -->
<root level="debug">
<root level="info">
<appender-ref ref="console"/>
<appender-ref ref="FileAppender"/>
<appender-ref ref="FILE_ERROR"/>
......
......@@ -140,7 +140,10 @@ public enum StatusCodeEnum {
ORDER_SKILL_NOT_EXISTS("027", "订单所需技能不存在,请核对!", false),
ORDER_RESCHEDULE_BEFORE_TIME("028", "订单不能改约到当前时间以前!", false);
ORDER_RESCHEDULE_BEFORE_TIME("028", "订单不能改约到当前时间以前!", false),
TEAM_UNMATCHED("029", "工程师没有匹配到工作队", false),
;
/**
* 状态码
......
package com.dituhui.pea.order.enums;
public enum OrderEventEnum {
// 建单,首次指派,改派,取消,改约,放回工单池
createOrder("建单", "%s通过%s创建服务工单:%s"),
firstAssignment("首次指派", "通过PEA派工给工程师%s"),
reassignment("改派", "通过PEA派工给工程师%s"),
cancel("取消", "%s在线指导解决"),
recontracting("改约", "工程师%s/%s已改约,改约时间%s,改约原因:%s"),
backOrderPool("放回工单池", "取消派工"),
;
private String event;
private String msg;
OrderEventEnum(String event, String msg) {
this.event = event;
this.msg = msg;
}
public String getEvent() {
return event;
}
public String getMsg() {
return msg;
}
}
......@@ -161,7 +161,7 @@ public class BeanRemoteServiceImpl {
return Result.failed(beanR.getMessage());
}
for (Department department : beanR.getData()) {
if (StringUtils.isBlank(department.getBsDeptId())) {
if (StringUtils.isNotBlank(department.getCode()) && department.getCode().contains("beanTest")) {
continue;
}
log.info("处理部门详情---->{}", department.getBsDeptId());
......@@ -193,8 +193,8 @@ public class BeanRemoteServiceImpl {
*/
private void disposeChildren(Department departments, String accessToken, Boolean isDisposeData, String parentId) {
for (Department department : departments.getChildren()) {
if (StringUtils.isBlank(department.getBsDeptId())) {
return;
if (StringUtils.isNotBlank(department.getCode()) && department.getCode().contains("beanTest")) {
continue;
}
log.info("处理部门详情---->{}", department.getBsDeptId());
if (!BeanRegionIdEnum.getEnumByRegionId(department.getBsDeptId())) {
......@@ -212,7 +212,7 @@ public class BeanRemoteServiceImpl {
}
disposeChildren(department, accessToken, isDisposeData, departments.getBsDeptId());
//大区数据处理完重置
if (department.getDeptLevel().equals(BeanOrgLevelEnum.REGION.getCode())) {
if (StringUtils.isBlank(department.getDeptLevel()) || department.getDeptLevel().equals(BeanOrgLevelEnum.REGION.getCode())) {
isDisposeData = false;
}
}
......@@ -293,15 +293,15 @@ public class BeanRemoteServiceImpl {
groupEntity.setWarehouseEnabled(data.getPeripheralWarehouseEnabled());
groupEntity.setReserveTimeMax(data.getPartReserveTimeMax());
//处理clusterId和branchId
OrgBranchEntity branchEntity = branchMap.get(data.getParentId());
OrgBranchEntity branchEntity = branchMap.get(data.getBelongedBranch());
if (ObjUtil.isNull(branchEntity)) {
branchEntity = orgBranchDao.getByBranchId(data.getParentId());
branchEntity = orgBranchDao.getByBranchId(data.getBelongedBranch());
if (ObjUtil.isNull(branchEntity)) {
return Result.failed();
}
branchMap.put(data.getParentId(), branchEntity);
branchMap.put(data.getBelongedBranch(), branchEntity);
}
groupEntity.setBranchId(data.getParentId());
groupEntity.setBranchId(data.getBelongedBranch());
groupEntity.setClusterId(branchEntity.getClusterId());
//处理分站外围
if (data.getDeptType().equals(BeanOrgLevelEnum.PERIPHERY.getCode())) {
......
......@@ -2,6 +2,7 @@ package com.dituhui.pea.order.service.impl;
import com.dituhui.pea.common.BusinessException;
import com.dituhui.pea.common.Result;
import com.dituhui.pea.enums.StatusCodeEnum;
import com.dituhui.pea.order.common.ListUtils;
import com.dituhui.pea.order.common.TimeUtils;
import com.dituhui.pea.order.dao.*;
......@@ -10,10 +11,12 @@ import com.dituhui.pea.order.dto.DispatchEngineerOrderListResp;
import com.dituhui.pea.order.dto.DispatchOrderListReq;
import com.dituhui.pea.order.dto.DispatchOrderListResp;
import com.dituhui.pea.order.entity.*;
import com.dituhui.pea.order.enums.AppointmentMethodEnum;
import com.dituhui.pea.order.enums.OrderFlowEnum;
import com.dituhui.pea.order.enums.OrderGroupEnum;
import com.dituhui.pea.order.enums.OrderStatusEnum;
import com.dituhui.pea.order.service.DispatchService;
import com.dituhui.pea.order.utils.CommonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
......@@ -61,6 +64,9 @@ public class DispatchServiceImpl implements DispatchService {
@Autowired
private OrgGroupDao orgGroupDao;
@Autowired
private OrgTeamEngineerDao orgTeamEngineerDao;
@Transactional
@Override
public Result<?> getDispatchOrderList(DispatchOrderListReq reqDTO) {
......@@ -279,35 +285,57 @@ public class DispatchServiceImpl implements DispatchService {
throw new BusinessException("订单不存在");
}
// 已经指派的订单
List<OrderInfoEntity> engineerOrders = orderInfoDao.findByDtAndEngineerCode(localDate, engineerCode);
engineerOrders.sort(Comparator.comparing(OrderInfoEntity::getPlanStartTime)); // 按照planStartTime排序
List<OrderInfoEntity> orderAppointments = engineerOrders.stream()
.filter(o -> o.getOrderStatus().equals("NORMAL"))
.collect(Collectors.toList()); // 过滤,只有NORMAL订单才需要处理,取消订单不需要处理
// TODO,临时处理方案,后续调用派单引擎处理
OrderRequestScheduler scheduler = new OrderRequestScheduler();
List<LineSegment> results = scheduler.scheduler(orders, orderAppointments);
for (LineSegment r : results) {
String orderId = r.id;
LocalDateTime planStartTime = scheduler.linePoint2DateTime(r.start, date);
LocalDateTime planEndTime = scheduler.linePoint2DateTime(r.end, date);
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaUpdate<OrderInfoEntity> update = criteriaBuilder.createCriteriaUpdate(OrderInfoEntity.class);
Root<OrderInfoEntity> root = update.from(OrderInfoEntity.class);
update.set(root.get("planStartTime"), planStartTime);
update.set(root.get("planEndTime"), planEndTime);
update.set(root.get("appointmentStatus"), OrderFlowEnum.CONFIRM.name());
update.set(root.get("appointmentMethod"), "MANUAL");
update.set(root.get("engineerCode"), engineerCode);
update.where(
criteriaBuilder.equal(root.get("orderId"), orderId),
criteriaBuilder.equal(root.get("dt"), localDate)
);
entityManager.createQuery(update).executeUpdate();
}
List<OrgTeamEngineerEntity> orgTeamEngineers = orgTeamEngineerDao.findByEngineerCode(engineer.getEngineerCode());
if (CollectionUtils.isEmpty(orgTeamEngineers)) {
return Result.failed(StatusCodeEnum.TEAM_UNMATCHED);
}
OrgTeamEntity byTeamId = orgTeamDao.getByTeamId(orgTeamEngineers.get(0).getTeamId());
for (OrderInfoEntity entity : orders) {
SkillInfoEntity skill = skillInfoDao.getByBrandAndTypeAndSkill(CommonUtil.fixBrand(entity.getBrand()), entity.getType(), entity.getSkill());
entity.setTakeTime(skill.getTakeTime());
entity.setPlanStartTime(entity.getExpectTimeBegin());
entity.setPlanEndTime(entity.getExpectTimeBegin().plusMinutes(skill.getTakeTime()));
entity.setEngineerCode(engineer.getEngineerCode());
entity.setEngineerName(engineer.getName());
entity.setEngineerPhone(engineer.getPhone());
entity.setAppointmentStatus(OrderFlowEnum.CONFIRM.name());
entity.setAppointmentMethod(AppointmentMethodEnum.MANUAL.name());
entity.setOrgTeamId(byTeamId.getTeamId());
entity.setOrgBranchId(byTeamId.getBranchId());
entity.setOrgClusterId(byTeamId.getClusterId());
orderInfoDao.save(entity);
}
//
// // 已经指派的订单
// List<OrderInfoEntity> engineerOrders = orderInfoDao.findByDtAndEngineerCode(localDate, engineerCode);
// engineerOrders.sort(Comparator.comparing(OrderInfoEntity::getPlanStartTime)); // 按照planStartTime排序
// List<OrderInfoEntity> orderAppointments = engineerOrders.stream()
// .filter(o -> o.getOrderStatus().equals("NORMAL"))
// .collect(Collectors.toList()); // 过滤,只有NORMAL订单才需要处理,取消订单不需要处理
//
// // TODO,临时处理方案,后续调用派单引擎处理
// OrderRequestScheduler scheduler = new OrderRequestScheduler();
// List<LineSegment> results = scheduler.scheduler(orders, orderAppointments);
// for (LineSegment r : results) {
// String orderId = r.id;
// LocalDateTime planStartTime = scheduler.linePoint2DateTime(r.start, date);
// LocalDateTime planEndTime = scheduler.linePoint2DateTime(r.end, date);
//
// CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
// CriteriaUpdate<OrderInfoEntity> update = criteriaBuilder.createCriteriaUpdate(OrderInfoEntity.class);
// Root<OrderInfoEntity> root = update.from(OrderInfoEntity.class);
// update.set(root.get("planStartTime"), planStartTime);
// update.set(root.get("planEndTime"), planEndTime);
// update.set(root.get("appointmentStatus"), OrderFlowEnum.CONFIRM.name());
// update.set(root.get("appointmentMethod"), "MANUAL");
// update.set(root.get("engineerCode"), engineerCode);
// update.where(
// criteriaBuilder.equal(root.get("orderId"), orderId),
// criteriaBuilder.equal(root.get("dt"), localDate)
// );
// entityManager.createQuery(update).executeUpdate();
// }
return Result.success(null);
}
......
......@@ -52,6 +52,7 @@ 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.service.CommonService;
......@@ -308,14 +309,17 @@ public class OrderCreateServiceImpl implements OrderCreateService {
entity.setIsAppointEngineer(req.getIsAppointEngineer());
String appointEngineerCodes = CollectionUtils.isEmpty(req.getAppointEngineerCodes()) ? null : String.join(",", req.getAppointEngineerCodes());
entity.setAppointEngineerCodes(appointEngineerCodes);
OrgTeamEntity byTeamId = null;
String engineerName = null;
if (req.getIsAppointEngineer() == 1) {
EngineerInfoEntity engineerInfo = engineerInfoDao.getByEngineerCode(req.getAppointEngineerCodes().get(0));
List<OrgTeamEngineerEntity> orgTeamEngineers = orgTeamEngineerDao.findByEngineerCode(req.getAppointEngineerCodes().get(0));
if (CollectionUtils.isEmpty(orgTeamEngineers)) {
return Result.failed(StatusCodeEnum.FENDAN_TEAM_UNMATCHED);
}
OrgTeamEntity byTeamId = orgTeamDao.getByTeamId(orgTeamEngineers.get(0).getTeamId());
byTeamId = orgTeamDao.getByTeamId(orgTeamEngineers.get(0).getTeamId());
entity.setEngineerCode(engineerInfo.getEngineerCode());
engineerName = engineerInfo.getName();
entity.setEngineerName(engineerInfo.getName());
entity.setEngineerPhone(engineerInfo.getPhone());
entity.setEngineerPhone(engineerInfo.getPhone());
......@@ -348,6 +352,9 @@ public class OrderCreateServiceImpl implements OrderCreateService {
entity.setAppointmentMethod(AppointmentMethodEnum.MANUAL.name());
//发送通知分部消息
sendMsg(branchEntity.getBranchId(), orderId, entity.getExpectTimeBegin().toLocalDate());
Integer cutoff = CommonUtil.isCutoff(LocalDateTime.now(), null);
entity.setIsCutoff(cutoff);
} else {
// 根据分单工作队,填写clusterId/branchId/groupId/teamId等
OrgTeamInfo teamInfo = fendanResult.getResult();
......@@ -361,10 +368,13 @@ public class OrderCreateServiceImpl implements OrderCreateService {
entity.getExpectTimeEnd().toLocalTime(), teamInfo.getWorkOn(), teamInfo.getWorkOff());
Integer cutoff = CommonUtil.isCutoff(LocalDateTime.now(), teamInfo.getWorkOff());
// 处理cutoff 动态排班结束后创建的当日单和次日单
boolean isToday = DateUtil.judgeTimeIsToday(entity.getExpectTimeBegin());
boolean isTomorrow = DateUtil.judgeTimeIsisTomorrow(entity.getExpectTimeBegin());
//次日单自动批量
if (isTomorrow) {
entity.setAppointmentMethod(AppointmentMethodEnum.AUTO_BATCH.name());
}
// 特殊时间段,当天单,cutoff需要人工处理
if (isToday || (isTomorrow && cutoff == 1) || special == 1) {
if (cutoff == 1 || special == 1) {
//判断是否在今天cutoff之后
entity.setIsCutoff(cutoff);
entity.setIsSpecialTime(special);
......@@ -414,7 +424,7 @@ public class OrderCreateServiceImpl implements OrderCreateService {
if (req.getPriority().equals("1")) {
entity.setAppointmentMethod(AppointmentMethodEnum.AUTO_NOW.name());
//发送通知分部消息
sendMsg(entity.getOrgBranchId(), orderId, entity.getExpectTimeBegin().toLocalDate());
// sendMsg(entity.getOrgBranchId(), orderId, entity.getExpectTimeBegin().toLocalDate());
}
entity.setIsMultiple(joinTags.contains("重物搬运") ? 1 : 0);
......@@ -424,7 +434,11 @@ public class OrderCreateServiceImpl implements OrderCreateService {
// 记录订单和节点
orderInfoDao.save(entity);
commonService.addOrderEvent(orderId, "", req.getSource(), "API", OrderStatusEnum.CREATE.getDescription(), OrderStatusEnum.CREATE.getDescription(), "");
commonService.addOrderEvent(orderId, "", req.getSource(), "API", OrderEventEnum.createOrder.getEvent(), String.format(OrderEventEnum.createOrder.getMsg(), req.getSource(), "BEAN", req.getOrderId()), "");
if (req.getIsAppointEngineer() == 1) {
commonService.addOrderEvent(orderId, "", req.getSource(), "PEA", OrderEventEnum.firstAssignment.getEvent(), String.format(OrderEventEnum.firstAssignment.getMsg(), engineerName + "-" + byTeamId.getTeamName()), "");
}
return Result.success(null);
}
......
......@@ -3,6 +3,7 @@ package com.dituhui.pea.order.utils;
import cn.hutool.core.util.StrUtil;
import com.dituhui.pea.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.time.LocalDate;
import java.time.LocalDateTime;
......@@ -88,6 +89,12 @@ public class CommonUtil {
* @return
*/
public static Integer isCutoff(LocalDateTime localTime, String strOff) {
if (DateUtil.judgeTimeIsToday(localTime)) {
return 1;
}
if (StringUtils.isBlank(strOff)) {
return 0;
}
LocalDateTime workOff = LocalDate.now().atTime(Integer.parseInt(strOff.split(":")[0]), Integer.parseInt(strOff.split(":")[1]), 0);
if (localTime.isAfter(workOff)) {
return 1;
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!