Commit f93ab0af by Ren Ping

feat:优化自动派单任务,支持如下功能

3.1,算法运行截止时间是动态的,根据工作队的cutoff配置来的,cutoff时间之后需要将订单'指派状态'改成'已指派'
3.3,算法需要根据工作队的网点指派策略/指派到人才进行自动派单
1 parent 04cc1926
...@@ -209,7 +209,6 @@ public class InitEngineerCapacityScheduler { ...@@ -209,7 +209,6 @@ public class InitEngineerCapacityScheduler {
statEntity.setMaxDuration((int) stats.getRemain()); statEntity.setMaxDuration((int) stats.getRemain());
statEntity.setUpdateTime(LocalDateTime.now()); statEntity.setUpdateTime(LocalDateTime.now());
capacityEngineerStatDao.save(statEntity); capacityEngineerStatDao.save(statEntity);
log.info("====== 处理完毕 ======");
} }
public void initOneEngineerByDays(String bdate, String edate, String branchId) { public void initOneEngineerByDays(String bdate, String edate, String branchId) {
......
...@@ -69,7 +69,7 @@ public class BatchScheduler { ...@@ -69,7 +69,7 @@ public class BatchScheduler {
String currDay = LocalDate.now().plusDays(i).format(DateTimeFormatter.ISO_LOCAL_DATE); String currDay = LocalDate.now().plusDays(i).format(DateTimeFormatter.ISO_LOCAL_DATE);
log.info("dispatchRun begin----- teamId:{}, day:{}", teamId, currDay); 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); UUID problemId = solveService.generateProblemId(teamId, batchNo);
log.info("dispatchRun teamId:{}, day:{}, batch:{}, problemId:{}", teamId, currDay, batchNo, problemId); log.info("dispatchRun teamId:{}, day:{}, batch:{}, problemId:{}", teamId, currDay, batchNo, problemId);
......
...@@ -24,7 +24,7 @@ public interface BatchService { ...@@ -24,7 +24,7 @@ public interface BatchService {
void saveDispatchBatch(DispatchBatch batchInfo); void saveDispatchBatch(DispatchBatch batchInfo);
// 小队id // 小队id
public String buildBatchData2(String teamId, String day); public String buildBatchData2(String teamId, String day, boolean cutOff);
public DispatchBatch queryBatchInfoByDay2(String teamId, String day); public DispatchBatch queryBatchInfoByDay2(String teamId, String day);
......
...@@ -192,7 +192,7 @@ public class BatchServiceImpl implements BatchService { ...@@ -192,7 +192,7 @@ public class BatchServiceImpl implements BatchService {
// 检查给定小队、日期是否有在运行的批次任务,没则返回,没有则创建 // 检查给定小队、日期是否有在运行的批次任务,没则返回,没有则创建
@Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class) @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
@Override @Override
public String buildBatchData2(String teamId, String day) { public String buildBatchData2(String teamId, String day, boolean cutOff) {
OrgTeamEntity orgTeamEntity = orgTeamDao.findByTeamId(teamId); OrgTeamEntity orgTeamEntity = orgTeamDao.findByTeamId(teamId);
String groupId = orgTeamEntity.getGroupId(); String groupId = orgTeamEntity.getGroupId();
entityManager.clear(); entityManager.clear();
...@@ -283,11 +283,11 @@ public class BatchServiceImpl implements BatchService { ...@@ -283,11 +283,11 @@ public class BatchServiceImpl implements BatchService {
if (orderCount + orderConfirmCount > 0) { 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=?", 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(), teamId, batchNo); engCount, orderCount + orderConfirmCount, LocalDateTime.now(), cutOff ? LocalDateTime.now() : null, teamId, batchNo);
} else { } else {
jdbcTemplate.update("update dispatch_batch set engineer_num=? , order_num=?, start_time=?, end_time=?, status='DONE' where team_id=? and batch_no=?", 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(), teamId, batchNo); engCount, 0, LocalDateTime.now(), LocalDateTime.now(), cutOff ? LocalDateTime.now() : null, teamId, batchNo);
} }
log.info("准备批次数据完成, teamId:{}, day:{}, batchNo:{}", teamId, batchDay, batchNo); log.info("准备批次数据完成, teamId:{}, day:{}, batchNo:{}", teamId, batchDay, batchNo);
......
package com.dituhui.pea.dispatch.service.impl; package com.dituhui.pea.dispatch.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.dituhui.pea.dispatch.dao.DispatchBatchRepository;
import com.dituhui.pea.dispatch.dao.OrgTeamDao; import com.dituhui.pea.dispatch.dao.OrgTeamDao;
import com.dituhui.pea.dispatch.entity.DispatchBatch;
import com.dituhui.pea.dispatch.entity.OrgTeamEntity; import com.dituhui.pea.dispatch.entity.OrgTeamEntity;
import com.dituhui.pea.dispatch.pojo.DispatchSolution; import com.dituhui.pea.dispatch.pojo.DispatchSolution;
import com.dituhui.pea.dispatch.service.BatchService; import com.dituhui.pea.dispatch.service.BatchService;
...@@ -18,10 +22,13 @@ import org.springframework.stereotype.Service; ...@@ -18,10 +22,13 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.io.File; import java.io.File;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
/** /**
...@@ -34,6 +41,9 @@ import java.util.UUID; ...@@ -34,6 +41,9 @@ import java.util.UUID;
@Slf4j @Slf4j
public class SchedulerServiceImpl implements SchedulerService { public class SchedulerServiceImpl implements SchedulerService {
//默认指派策略
public static final String DEFAULT_STRATEGY_APPOINTMENT = "指派给信息员";
@Value("${dispatch.cron.next-day-limit}") @Value("${dispatch.cron.next-day-limit}")
int nextDaysLimit = 2; int nextDaysLimit = 2;
...@@ -50,6 +60,9 @@ public class SchedulerServiceImpl implements SchedulerService { ...@@ -50,6 +60,9 @@ public class SchedulerServiceImpl implements SchedulerService {
OrgTeamDao orgTeamDao; OrgTeamDao orgTeamDao;
private DefaultSolverFactory<DispatchSolution> solverFactory; private DefaultSolverFactory<DispatchSolution> solverFactory;
@Resource
private DispatchBatchRepository dispatchBatchRepository;
//private Solver<DispatchSolution> solver; //private Solver<DispatchSolution> solver;
public SchedulerServiceImpl() { public SchedulerServiceImpl() {
...@@ -65,14 +78,42 @@ public class SchedulerServiceImpl implements SchedulerService { ...@@ -65,14 +78,42 @@ public class SchedulerServiceImpl implements SchedulerService {
return; return;
} }
if (StrUtil.equals(DEFAULT_STRATEGY_APPOINTMENT, orgTeamEntity.getStrategyAppointment())) {
log.error(">>> teamId:{} " + DEFAULT_STRATEGY_APPOINTMENT, 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(); String groupId = orgTeamEntity.getGroupId();
log.info("dispatchRun group:{}, team:{} done", groupId, teamId); log.info("dispatchRun group:{}, team:{} done", groupId, teamId);
for (int i = 1; i <= nextDaysLimit; i++) { for (int i = 1; i <= nextDaysLimit; i++) {
String currDay = LocalDate.now().plusDays(i).format(DateTimeFormatter.ISO_LOCAL_DATE); 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 { try {
log.info("dispatchRun begin----- teamId:{}, day:{}", teamId, currDay); 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); UUID problemId = solveService.generateProblemId(teamId, batchNo);
log.info("dispatchRun teamId:{}, day:{}, batch:{}, problemId:{}", teamId, currDay, batchNo, problemId); log.info("dispatchRun teamId:{}, day:{}, batch:{}, problemId:{}", teamId, currDay, batchNo, problemId);
...@@ -88,7 +129,7 @@ public class SchedulerServiceImpl implements SchedulerService { ...@@ -88,7 +129,7 @@ public class SchedulerServiceImpl implements SchedulerService {
DispatchSolutionUtils.removeHardConstraintCustomer(solution, solverFactory); DispatchSolutionUtils.removeHardConstraintCustomer(solution, solverFactory);
log.info("dispatchRun solve done, teamId:{}, day:{}, batch:{}, problemId:{}, score:{}", teamId, currDay, batchNo, problemId, solution.getScore().toShortString()); log.info("dispatchRun solve done, teamId:{}, day:{}, batch:{}, problemId:{}, score:{}", teamId, currDay, batchNo, problemId, solution.getScore().toShortString());
this.solveService.saveSolutionWrp2(solution); this.solveService.saveSolutionWrp2(solution);
this.extractService.extractDispatchToOrder2(teamId, batchNo, false); this.extractService.extractDispatchToOrder2(teamId, batchNo, cutOff);
log.info("dispatchRun done ------ teamId:{}, day:{}", teamId, currDay); log.info("dispatchRun done ------ teamId:{}, day:{}", teamId, currDay);
JacksonSolutionFileIO<DispatchSolution> exporter = new JacksonSolutionFileIO<DispatchSolution>(DispatchSolution.class); JacksonSolutionFileIO<DispatchSolution> exporter = new JacksonSolutionFileIO<DispatchSolution>(DispatchSolution.class);
......
...@@ -3,7 +3,7 @@ server: ...@@ -3,7 +3,7 @@ server:
dispatch: dispatch:
cron: cron:
expr: 0 47 8-22 * * ? expr: 0 45 8-22 * * ?
next-day-limit: 2 next-day-limit: 2
# expr: 0 */10 8-18 * * ? # expr: 0 */10 8-18 * * ?
...@@ -49,12 +49,12 @@ spring: ...@@ -49,12 +49,12 @@ spring:
enabled: false enabled: false
datasource: datasource:
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://127.0.0.1:3306/saas_aftersale_test?serverTimezone=Asia/Shanghai url: jdbc:mysql://127.0.0.1:3306/saas_aftersale_test?serverTimezone=Asia/Shanghai
# username: root username: root
# password: 123456 password: 123456
url: jdbc:mysql://localhost:32306/saas_aftersale_test?serverTimezone=Asia/Shanghai # url: jdbc:mysql://localhost:32306/saas_aftersale_test?serverTimezone=Asia/Shanghai
username: boxi # username: boxi
password: boxi_dev_0725 # password: boxi_dev_0725
type: com.alibaba.druid.pool.DruidDataSource type: com.alibaba.druid.pool.DruidDataSource
jpa: jpa:
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
<!-- 控制台输出 --> <!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level> <level>DEBUG</level>
</filter> </filter>
<!-- 日志输出编码 --> <!-- 日志输出编码 -->
<encoder> <encoder>
...@@ -111,9 +111,10 @@ ...@@ -111,9 +111,10 @@
</appender> </appender>
<logger name="org.optaplanner" level="info"/> <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="console"/>
<appender-ref ref="FileAppender"/> <appender-ref ref="FileAppender"/>
<appender-ref ref="FILE_ERROR"/> <appender-ref ref="FILE_ERROR"/>
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!