Commit ede28e8b by 张晓

批次排班数据+dispath_order 分解到order两个表

1 parent 6275f5cc
Showing with 1988 additions and 0 deletions
version: "3"
services:
nacos:
image: nacos/nacos-server:v2.2.3-slim
container_name: nacos-standalone-local
environment:
- PREFER_HOST_MODE=hostname
- MODE=standalone
- NACOS_AUTH_IDENTITY_KEY=serverIdentity
- NACOS_AUTH_IDENTITY_VALUE=security
- NACOS_AUTH_TOKEN=SecretKey012345678901234567890123456789012345678901234567890123456789
volumes:
- ./nacos-logs/:/home/nacos/logs
ports:
- "8848:8848"
- "9848:9848"
seata-server:
image: seataio/seata-server:1.6.1
hostname: seata-server
restart: always
container_name: seata-standalone-local
ports:
- "8091:8091"
environment:
- SEATA_PORT=8091
- STORE_MODE=file
# redis:
# image: redis:6.2-alpine
# hostname: redis
# restart: always
# container_name: redis-standalone-local
# ports:
# - "6379:6379"
# command: redis-server --save 20 1 --loglevel warning --requirepass 123456
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-parent</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>project-pre-dispatch</artifactId>
<name>Pea PreDispatch</name>
<properties>
<druid.version>1.1.10</druid.version>
<version.org.optaplanner>9.38.0.Final</version.org.optaplanner>
<mysql.version>8.0.28</mysql.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>project-interface</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.optaplanner</groupId>
<artifactId>optaplanner-core</artifactId>
<version>${version.org.optaplanner}</version>
</dependency>
<dependency>
<groupId>org.gavaghan</groupId>
<artifactId>geodesy</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.5</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.13.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>10</source>
<target>10</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package com.dituhui.pea.pre;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* @author zhangx
*/
@SpringBootApplication
@EnableScheduling
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
package com.dituhui.pea.pre;
import com.dituhui.pea.pre.interceptor.RequestInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@EnableJpaRepositories
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private RequestInterceptor requestInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(requestInterceptor).addPathPatterns("/**");
}
}
package com.dituhui.pea.pre.common;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;
public class DateUtil {
/**
* LocalDateTime转毫秒时间戳
*
* @param localDateTime LocalDateTime
* @return 时间戳
*/
public static Long localDateTimeToTimestamp(LocalDateTime localDateTime) {
try {
ZoneId zoneId = ZoneId.systemDefault();
Instant instant = localDateTime.atZone(zoneId).toInstant();
return instant.toEpochMilli();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 时间戳转LocalDateTime
*
* @param timestamp 时间戳
* @return LocalDateTime
*/
public static LocalDateTime timestampToLocalDateTime(long timestamp) {
try {
Instant instant = Instant.ofEpochMilli(timestamp);
ZoneId zone = ZoneId.systemDefault();
return LocalDateTime.ofInstant(instant, zone);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* Date转LocalDateTime
*
* @param date Date
* @return LocalDateTime
*/
public static LocalDateTime dateToLocalDateTime(Date date) {
try {
Instant instant = date.toInstant();
ZoneId zoneId = ZoneId.systemDefault();
return instant.atZone(zoneId).toLocalDateTime();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* LocalDateTime转Date
*
* @param localDateTime LocalDateTime
* @return Date
*/
public static Date localDateTimeToDate(LocalDateTime localDateTime) {
try {
ZoneId zoneId = ZoneId.systemDefault();
ZonedDateTime zdt = localDateTime.atZone(zoneId);
return Date.from(zdt.toInstant());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
package com.dituhui.pea.pre.dao;
import com.dituhui.pea.pre.entity.DispatchBatch;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Repository
public interface DispatchBatchRepository extends CrudRepository<DispatchBatch, Long> {
List<DispatchBatch> findByGroupId(String groupId);
Optional<DispatchBatch> findByGroupIdAndBatchDate(String groupId, String batchDay);
@Query(value = "from DispatchBatch where groupId = ?1 and batchNo=?2 ")
List<DispatchBatch> findLatestGroup(String groupId, String batchNo);
}
\ No newline at end of file
package com.dituhui.pea.pre.dao;
import com.dituhui.pea.pre.entity.DispatchEngineer;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
public interface DispatchEngineerRepository extends CrudRepository<DispatchEngineer, Long> {
List<DispatchEngineer> findByGroupId(String groupId);
List<DispatchEngineer> findByGroupIdAndBatchNo(String groupId, String batchNo);
}
\ No newline at end of file
package com.dituhui.pea.pre.dao;
import com.dituhui.pea.pre.entity.DispatchOrder;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
import java.util.Optional;
public interface DispatchOrderRepository extends CrudRepository<DispatchOrder, Long> {
List<DispatchOrder> findByGroupIdAndBatchNo(String groupId, String batchNo);
List<DispatchOrder> findByGroupIdAndBatchNoAndEngineerCodeNot(String groupId, String batchNo, String code);
@Query("from DispatchOrder where groupId=?1 and batchNo=?2 and engineerCode is not null and engineerCode!='' ")
List<DispatchOrder> findAssigned(String groupId, String batchNo);
Optional<DispatchOrder> findByGroupIdAndBatchNoAndOrderId(String groupId, String batchNo, String orderId);
}
\ No newline at end of file
package com.dituhui.pea.pre.dao;
import com.dituhui.pea.pre.entity.EngineerInfo;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
import java.util.Optional;
public interface EngineerInfoRepository extends CrudRepository<EngineerInfo, Long> {
List<EngineerInfo> findByGroupId(String groupId);
Optional<EngineerInfo> findByEngineerCode(String engineerCode);
}
\ No newline at end of file
package com.dituhui.pea.pre.dao;
import com.dituhui.pea.pre.entity.OrderAppointment;
import org.springframework.data.repository.CrudRepository;
import java.util.Optional;
public interface OrderAppointmentRepository extends CrudRepository<OrderAppointment, Long> {
Optional<OrderAppointment> findByOrderId(String orderId);
}
package com.dituhui.pea.pre.dao;
import com.dituhui.pea.pre.entity.OrderRequest;
import org.springframework.data.repository.CrudRepository;
import java.util.Optional;
public interface OrderRequestRepository extends CrudRepository<OrderRequest, Long> {
Optional<OrderRequest> findByOrderId(String orderId);
}
package com.dituhui.pea.pre.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 排班批次总表
*/
@Entity
@Data
@Table(name = "dispatch_batch")
public class DispatchBatch implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "group_id")
private String groupId;
/**
* 批次号
*/
@Column(name = "batch_no")
private String batchNo;
/**
* 跑批日期
*/
@Column(name = "batch_date")
private String batchDate;
/**
* 技术员数量
*/
@Column(name = "engineer_num")
private Integer engineerNum;
/**
* 服务单数量
*/
@Column(name = "order_num")
private Integer orderNum;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Column(name = "start_time")
private LocalDateTime startTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Column(name = "end_time")
private LocalDateTime endTime;
/**
* RUNNING,DONE
*/
@Column(name = "status")
private String status;
@Column(name = "memo")
private String memo;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Column(name = "update_time")
private LocalDateTime updateTime;
@Column(name = "ext")
private String ext;
public DispatchBatch() {
}
public DispatchBatch(String groupId, String batchNo, String batchDate, Integer engineerNum, Integer orderNum) {
this.groupId = groupId;
this.batchNo = batchNo;
this.batchDate = batchDate;
this.engineerNum = engineerNum;
this.orderNum = orderNum;
}
}
package com.dituhui.pea.pre.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name = "dispatch_engineer")
public class DispatchEngineer implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "group_id")
private String groupId;
@Column(name = "batch_no")
private String batchNo;
@Column(name = "engineer_code")
private String engineerCode;
@Column(name = "engineer_name")
private String engineerName;
@Column(name = "x")
private String X;
@Column(name = "y")
private String Y;
@Column(name = "max_num")
private Integer maxNum;
@Column(name = "max_minute")
private Integer maxMinute;
@Column(name = "max_distance")
private Integer maxDistance;
private String ext = "";
private String memo;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Column(name = "update_time")
private LocalDateTime updateTime;
}
package com.dituhui.pea.pre.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import javax.persistence.*;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
@Data
@Entity
@Table(name = "dispatch_order")
public class DispatchOrder implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "group_id")
private String groupId;
@Column(name = "batch_no")
private String batchNo;
@Column(name = "order_id")
private String orderId;
@Column(name = "x")
private String X;
@Column(name = "y")
private String Y;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Column(name = "expect_time_begin")
private Date expectTimeBegin;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Column(name = "expect_time_end")
private Date expectTimeEnd;
private String tags;
private Integer priority;
private String skills;
@Column(name = "take_time")
private Integer takeTime;
@Column(name = "engineer_code")
private String engineerCode;
private Integer seq;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Column(name = "time_begin")
private LocalDateTime timeBegin;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Column(name = "time_end")
private LocalDateTime timeEnd;
private String status;
private String ext;
private String memo;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Column(name = "update_time")
private LocalDateTime updateTime;
}
package com.dituhui.pea.pre.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name = "engineer_info")
public class EngineerInfo implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "engineer_code")
private String engineerCode;
private String name;
@Column(name = "group_id")
private String groupId;
@Column(name = "cosmos_id")
private String cosmosId;
private String gender;
private String birth;
private String phone;
private String address;
private Integer kind;
private String grade;
private String credentials;
private Integer vehicle;
@Column(name = "vehicle_no")
private String vehicleNo;
@Column(name = "bean_status")
private Integer beanStatus;
private String tags;
private String memo;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Column(name = "create_time")
private LocalDateTime createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Column(name = "update_time")
private LocalDateTime updateTime;
}
package com.dituhui.pea.pre.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name = "order_appointment")
public class OrderAppointment implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
@Column(name = "order_id")
private String orderId;
@Column(name = "suborder_id")
private String suborderId;
@Column(name = "main_sub")
private Integer mainSub;
@Column(name = "engineer_code")
private String engineerCode;
@Column(name = "engineer_name")
private String engineerName;
@Column(name = "engineer_phone")
private String engineerPhone;
@Column(name = "engineer_age")
private Integer engineerAge;
@Column(name = "is_workshop")
private Integer isWorkshop;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Column(name = "expect_start_time")
private LocalDateTime expectStartTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Column(name = "expect_end_time")
private LocalDateTime expectEndTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Column(name = "actual_time")
private LocalDateTime actualTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Column(name = "actual_start_time")
private LocalDateTime actualStartTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Column(name = "actual_end_time")
private LocalDateTime actualEndTime;
@Column(name = "pre_status")
private String preStatus;
private String status;
private String memo;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Column(name = "create_time")
private LocalDateTime createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Column(name = "update_time")
private LocalDateTime updateTime;
}
package com.dituhui.pea.pre.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name = "order_request")
public class OrderRequest implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private String id;
@Column(name = "order_id")
private String orderId;
private String name;
private String phone;
private String address;
@Column(name = "x")
private String X;
@Column(name = "y")
private String Y;
private String province;
private String city;
private String county;
@Column(name = "category_id")
private String categoryId;
private String brand;
private String type;
private String skill;
@Column(name = "apply_note")
private String applyNote;
@Column(name = "fault_describe")
private String faultDescribe;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Column(name = "expect_time_begin")
private LocalDateTime expectTimeBegin;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Column(name = "expect_time_end")
private LocalDateTime expectTimeEnd;
@Column(name = "expect_time_desc")
private String expectTimeDesc;
private String source;
@Column(name = "area_id")
private String areaId;
@Column(name = "order_priority")
private String orderPriority;
@Column(name = "order_tags")
private String orderTags;
private Integer priority;
private String tags;
private String status;
@Column(name = "appointment_status")
private String appointmentStatus;
@Column(name = "appointment_method")
private String appointmentMethod;
@Column(name = "org_cluster_id")
private String orgClusterId;
@Column(name = "org_cluster_name")
private String orgClusterName;
@Column(name = "org_branch_id")
private String orgBranchId;
@Column(name = "org_branch_name")
private String orgBranchName;
@Column(name = "org_group_id")
private String orgGroupId;
@Column(name = "org_group_name")
private String orgGroupName;
@Column(name = "org_team_id")
private String orgTeamId;
@Column(name = "org_team_name")
private String orgTeamName;
private String description;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Column(name = "create_time")
private LocalDateTime createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Column(name = "update_time")
private LocalDateTime updateTime;
}
package com.dituhui.pea.pre.interceptor;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
@Slf4j
@Aspect
@Component
public class RequestInterceptor implements HandlerInterceptor {
/**
* 以 controller 包下定义的所有请求为切入点
*/
@Pointcut(value = "execution(public * com.dituhui.pea.order.controller..*.*(..))")
public void reqOpenAPILog() {
}
/**
* 在切点之前织入
*
* @param joinPoint
* @throws Throwable
*/
@Before("reqOpenAPILog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 开始打印请求日志
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 打印请求 url
log.info("Request URL : {}", request.getRequestURL().toString());
// 打印 Http method
log.info("HTTP Method : {}", request.getMethod());
// 打印调用 controller 的全路径以及执行方法
log.info("Class Method : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
// 打印请求的 IP
log.info("Request IP : {}", request.getRemoteAddr());
// 打印请求入参
log.info("Request Args : {}", new ObjectMapper().writeValueAsString(joinPoint.getArgs()));
}
/**
* 在切点之后织入
*
* @throws Throwable
*/
@After("reqOpenAPILog()")
public void doAfter() throws Throwable {
// TODO
}
/**
* 环绕
*
* @param proceedingJoinPoint
* @return
* @throws Throwable
*/
@Around("reqOpenAPILog()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
log.info("========================================== Start ==========================================");
long startTime = System.currentTimeMillis();
Object result = proceedingJoinPoint.proceed();
// 打印出参
// log.info("Response Args : {}", result);
log.info("Response Args : {}", new ObjectMapper().writeValueAsString(result));
// 执行耗时
log.info("Time-Consuming : {} ms", System.currentTimeMillis() - startTime);
log.info("=========================================== End ===========================================");
return result;
}
}
package com.dituhui.pea.pre.opta.domain;
public class Customer {
private String id;
private Location location;
// 耗时
private int duration;
private String skill;
public Customer() {
}
public Customer(String id, Location location, int duration, String skill) {
this.id = id;
this.location = location;
this.duration = duration;
this.skill = skill;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public int getDuration() {
return duration;
}
public void setDuration(int duration) {
this.duration = duration;
}
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
// ************************************************************************
// Complex methods
// ************************************************************************
@Override
public String toString() {
return "Customer{" +
"id='" + id + '\'' +
", location=" + location +
", duration=" + duration +
", skill='" + skill + '\'' +
'}';
}
}
package com.dituhui.pea.pre.opta.domain;
// 起点
public class Depot {
private final String id;
// 类型 分站
private final String type;
private final Location location;
public Depot(String id, String type, Location location) {
this.id = id;
this.type = type;
this.location = location;
}
public String getId() {
return id;
}
public String getType() {
return type;
}
public Location getLocation() {
return location;
}
}
package com.dituhui.pea.pre.opta.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.Map;
@JsonFormat(shape = JsonFormat.Shape.ARRAY)
@JsonIgnoreProperties({ "id" })
public class Location {
private final String id;
// 类型 engineer order
private final String type;
private final double latitude;
private final double longitude;
private Map<Location, Long> distanceMap;
public Location(String id, String type, double longitude, double latitude ) {
this.id = id;
this.type = type;
this.longitude = longitude;
this.latitude = latitude;
}
@Override
public String toString() {
return "Location{" +
"id='" + id + '\'' +
", type='" + type + '\'' +
", latitude=" + latitude +
", longitude=" + longitude +
'}';
}
public String getId() {
return id;
}
public String getType() {
return type;
}
public double getLatitude() {
return latitude;
}
public double getLongitude() {
return longitude;
}
/**
* Set the distance map. Distances are in meters.
*
* @param distanceMap a map containing distances from here to other locations
*/
public void setDistanceMap(Map<Location, Long> distanceMap) {
this.distanceMap = distanceMap;
}
/**
* Distance to the given location in meters.
*
* @param location other location
* @return distance in meters
*/
public long getDistanceTo(Location location) {
return distanceMap.get(location);
}
// ************************************************************************
// Complex methods
// ************************************************************************
/**
* The angle relative to the direction EAST.
*
* @param location never null
* @return in Cartesian coordinates
*/
public double getAngle(Location location) {
// Euclidean distance (Pythagorean theorem) - not correct when the surface is a sphere
double latitudeDifference = location.latitude - latitude;
double longitudeDifference = location.longitude - longitude;
return Math.atan2(latitudeDifference, longitudeDifference);
}
}
package com.dituhui.pea.pre.opta.domain;
import org.optaplanner.core.api.solver.SolverStatus;
class Status {
public final VehicleRoutingSolution solution;
public final String scoreExplanation;
public final boolean isSolving;
Status(VehicleRoutingSolution solution, String scoreExplanation, SolverStatus solverStatus) {
this.solution = solution;
this.scoreExplanation = scoreExplanation;
this.isSolving = solverStatus != SolverStatus.NOT_SOLVING;
}
}
package com.dituhui.pea.pre.opta.domain;
import org.optaplanner.core.api.domain.entity.PlanningEntity;
import org.optaplanner.core.api.domain.lookup.PlanningId;
import org.optaplanner.core.api.domain.variable.PlanningListVariable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@PlanningEntity
public class Vehicle {
@PlanningId
private String id;
private int maxMinute;
// 单位是米,这里要注意
private int maxDistanceMeter;
private Depot depot;
private Set<String> skillSet;
@PlanningListVariable
private List<Customer> customerList;
public Vehicle() {
}
public Vehicle(String id, int maxMinute, int maxDistanceMeter, Depot depot, Set<String> skillSet) {
this.id = id;
this.maxMinute = maxMinute;
this.maxDistanceMeter = maxDistanceMeter;
this.depot = depot;
this.skillSet = skillSet;
this.customerList = new ArrayList<>();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getMaxMinute() {
return maxMinute;
}
public void setMaxMinute(int maxMinute) {
this.maxMinute = maxMinute;
}
public int getMaxDistanceMeter() {
return maxDistanceMeter;
}
public void setMaxDistanceMeter(int maxDistanceMeter) {
this.maxDistanceMeter = maxDistanceMeter;
}
public Depot getDepot() {
return depot;
}
public void setDepot(Depot depot) {
this.depot = depot;
}
public List<Customer> getCustomerList() {
return customerList;
}
public void setCustomerList(List<Customer> customerList) {
this.customerList = customerList;
}
public Set<String> getSkillSet() {
return skillSet;
}
public void setSkillSet(Set<String> skillSet) {
this.skillSet = skillSet;
}
// ************************************************************************
// Complex methods
// ************************************************************************
/**
* @return route of the vehicle
*/
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());
}
// route.add(depot.getLocation());
return route;
}
private int getTotalDuration() {
int total = 0;
for (Customer customer : customerList) {
total += customer.getDuration();
}
return total;
}
public long getTotalDurationMinutes() {
// 服务耗时
int durationMinute = getTotalDuration();
// 路程耗时
// 驾车每秒种平均距离 (高德导航历史数据计算得出) avg_rate = 7.65
int distance = getTotalDistanceMeters();
double avg_rate = 7.65;
long routeMinute = Math.round(distance / avg_rate / 60);
return durationMinute + routeMinute;
}
public int getTotalDistanceMeters() {
if (customerList.isEmpty()) {
return 0;
}
int total = 0;
Location previousLocation = depot.getLocation();
for (Customer customer : customerList) {
total += previousLocation.getDistanceTo(customer.getLocation());
previousLocation = customer.getLocation();
}
total += previousLocation.getDistanceTo(depot.getLocation());
return total;
}
@Override
public String toString() {
return "Vehicle{" +
"id='" + id + '\'' +
", maxMinute=" + maxMinute +
", maxDistanceMeter=" + maxDistanceMeter +
", depot=" + depot +
", skills=" + skillSet +
", customerList=" + customerList +
'}';
}
}
package com.dituhui.pea.pre.opta.domain;
import org.optaplanner.core.api.domain.solution.PlanningEntityCollectionProperty;
import org.optaplanner.core.api.domain.solution.PlanningScore;
import org.optaplanner.core.api.domain.solution.PlanningSolution;
import org.optaplanner.core.api.domain.solution.ProblemFactCollectionProperty;
import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider;
import org.optaplanner.core.api.score.buildin.hardsoftlong.HardSoftLongScore;
import java.util.ArrayList;
import java.util.List;
@PlanningSolution
public class VehicleRoutingSolution {
private String name;
@ProblemFactCollectionProperty
private List<Location> locationList;
@ProblemFactCollectionProperty
private List<Depot> depotList;
@PlanningEntityCollectionProperty
private List<Vehicle> vehicleList;
@ProblemFactCollectionProperty
@ValueRangeProvider
private List<Customer> customerList;
@PlanningScore
private HardSoftLongScore score;
public VehicleRoutingSolution() {
}
public VehicleRoutingSolution(String name, List<Depot> depotList, List<Vehicle> vehicleList,
List<Customer> customerList, List<Location> locationList) {
this.name = name;
this.depotList = depotList;
this.vehicleList = vehicleList;
this.customerList = customerList;
this.locationList = locationList;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Location> getLocationList() {
return locationList;
}
public void setLocationList(List<Location> locationList) {
this.locationList = locationList;
}
public List<Depot> getDepotList() {
return depotList;
}
public void setDepotList(List<Depot> depotList) {
this.depotList = depotList;
}
public List<Vehicle> getVehicleList() {
return vehicleList;
}
public void setVehicleList(List<Vehicle> vehicleList) {
this.vehicleList = vehicleList;
}
public List<Customer> getCustomerList() {
return customerList;
}
public void setCustomerList(List<Customer> customerList) {
this.customerList = customerList;
}
public HardSoftLongScore getScore() {
return score;
}
public void setScore(HardSoftLongScore score) {
this.score = score;
}
// ************************************************************************
// Complex methods
// ************************************************************************
}
package com.dituhui.pea.pre.opta.domain.geo;
import com.dituhui.pea.pre.opta.domain.Location;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@Component
public interface DistanceCalculator {
/**
* Calculate the distance between {@code from} and {@code to} in meters.
*
* @param from starting location
* @param to target location
* @return distance in meters
*/
long calculateDistance(Location from, Location to);
/**
* Bulk calculation of distance.
* Typically much more scalable than {@link #calculateDistance(Location, Location)} iteratively.
*
* @param fromLocations never null
* @param toLocations never null
* @return never null
*/
default Map<Location, Map<Location, Long>> calculateBulkDistance(
Collection<Location> fromLocations,
Collection<Location> toLocations) {
return fromLocations.stream().collect(Collectors.toMap(
Function.identity(),
from -> toLocations.stream().collect(Collectors.toMap(
Function.identity(),
to -> calculateDistance(from, to)
))
));
}
/**
* Calculate distance matrix for the given list of locations and assign distance maps accordingly.
*
* @param locationList
*/
default void initDistanceMaps(Collection<Location> locationList) {
Map<Location, Map<Location, Long>> distanceMatrix = calculateBulkDistance(locationList, locationList);
locationList.forEach(location -> location.setDistanceMap(distanceMatrix.get(location)));
}
}
package com.dituhui.pea.pre.opta.domain.geo;
import com.dituhui.pea.pre.opta.domain.Location;
import org.gavaghan.geodesy.Ellipsoid;
import org.gavaghan.geodesy.GeodeticCalculator;
import org.gavaghan.geodesy.GeodeticCurve;
import org.gavaghan.geodesy.GlobalCoordinates;
import org.springframework.stereotype.Component;
@Component
public class GeoDistanceCalculator implements DistanceCalculator {
@Override
public long calculateDistance(Location from, Location to) {
if (from.equals(to)) {
return 0L;
}
GlobalCoordinates source = new GlobalCoordinates(from.getLatitude(), from.getLongitude());
GlobalCoordinates target = new GlobalCoordinates(to.getLatitude(), to.getLongitude());
GeodeticCurve geoCurve = new GeodeticCalculator().calculateGeodeticCurve(Ellipsoid.WGS84, source, target);
long distance = Math.round(geoCurve.getEllipsoidalDistance());
// todo *1.4倍 约等于实际路线距离
distance = Math.round(distance * 1.4);
return distance;
}
}
package com.dituhui.pea.pre.opta.solver;
import com.dituhui.pea.pre.opta.domain.Vehicle;
import org.optaplanner.core.api.score.buildin.hardsoftlong.HardSoftLongScore;
import org.optaplanner.core.api.score.stream.Constraint;
import org.optaplanner.core.api.score.stream.ConstraintFactory;
import org.optaplanner.core.api.score.stream.ConstraintProvider;
import org.springframework.stereotype.Service;
import java.util.Set;
@Service
public class VehicleRoutingConstraintProvider implements ConstraintProvider {
@Override
public Constraint[] defineConstraints(ConstraintFactory factory) {
return new Constraint[]{
// skillMatchHard(factory),
mixCountHard(factory),
maxTimeCapacityHard(factory),
maxDistanceHard(factory),
totalDistance(factory),
avgCustomers(factory),
};
}
//
protected Constraint skillMatchHard(ConstraintFactory factory) {
return factory.forEach(Vehicle.class).filter(vehicle -> vehicle.getCustomerList().size() > 0)
.penalizeLong(HardSoftLongScore.ofUninitialized(0, 100, 0),
vehicle -> {
Set<String> skillSet = vehicle.getSkillSet();
final int[] missCount = {0};
vehicle.getCustomerList().forEach(customer -> {
if (!skillSet.contains(customer.getSkill())) {
missCount[0] = missCount[0] + 1;
}
});
return missCount[0];
})
.asConstraint("技能匹配");
}
// 最少n单
public Constraint mixCountHard(ConstraintFactory factory) {
return factory.forEach(Vehicle.class).filter(vehicle -> vehicle.getCustomerList().size() <= 2)
.penalizeLong(HardSoftLongScore.ofUninitialized(0, 100, 0),
vehicle -> {
// int score = 15 - vehicle.getCustomerList().size();
return 1;
})
.asConstraint("最小单数约束(3单)");
}
// 总时长限制
protected Constraint maxTimeCapacityHard(ConstraintFactory factory) {
return factory.forEach(Vehicle.class)
.filter(vehicle -> {
long span = vehicle.getTotalDurationMinutes() - vehicle.getMaxMinute();
return span > 0;
})
.penalizeLong(HardSoftLongScore.ofUninitialized(0, 20, 0),
vehicle -> {
long span = vehicle.getTotalDurationMinutes() - vehicle.getMaxMinute();
return span / 60;
})
.asConstraint("工作时长限制");
}
// 总里程限制
protected Constraint maxDistanceHard(ConstraintFactory factory) {
return factory.forEach(Vehicle.class).filter(vehicle -> {
int total = vehicle.getTotalDistanceMeters();
int max = vehicle.getMaxDistanceMeter();
int diff = total - max;
// Log.infof("DistanceHard filter vehicle:%s, customlist.size:%d , total-distance:%d, max-meter:%d diff:%s",
// vehicle.getId(), vehicle.getCustomerList().size(), total, max, diff);
return diff > 0;
})
.penalizeLong(HardSoftLongScore.ofUninitialized(0, 20, 0),
vehicle -> {
int total = vehicle.getTotalDistanceMeters();
int max = vehicle.getMaxDistanceMeter();
int diff = total - max;
// Log.infof("DistanceHard vehicle:%s, customlist.size:%d , total-distance:%d, max-meter:%d diff:%s",
// vehicle.getId(), vehicle.getCustomerList().size(), total, max, diff);
return diff / 1000;
})
.asConstraint("最大里程约束");
}
/*
protected Constraint vehicleDistanceCapacity(ConstraintFactory factory) {
return factory.forEach(Vehicle.class)
.filter(vehicle -> {
int span = Math.abs(vehicle.getTotalDistanceMeters() - vehicle.getMaxDistance());
double rate = Math.round(span / vehicle.getMaxDistance());
return rate > 0.2;
})
.penalizeLong(HardSoftLongScore.ONE_HARD,
vehicle -> {
int span = Math.abs(vehicle.getTotalDistanceMeters() - vehicle.getMaxDistance());
double rate = Math.round(span / vehicle.getMaxDistance());
return span;
})
.asConstraint("vehicleDistanceCapacity");
}*/
// ************************************************************************
// Soft constraints
// ************************************************************************
// 路径最短为最优
protected Constraint totalDistance(ConstraintFactory factory) {
return factory.forEach(Vehicle.class)
.penalizeLong(HardSoftLongScore.ofUninitialized(0, 1000, 10),
vehicle-> vehicle.getTotalDistanceMeters()/1000)
.asConstraint("里程最短最优");
}
// 车辆间货物均衡为最优级
protected Constraint avgCustomers(ConstraintFactory factory) {
return factory.forEach(Vehicle.class)
.penalizeLong(HardSoftLongScore.ofUninitialized(0, 100, 0),
vehicle -> Math.abs(9 - vehicle.getCustomerList().size()))
.asConstraint("车辆间货物均衡最优");
}
}
package com.dituhui.pea.pre.scheduler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class Scheduler {
@Scheduled(fixedRate = 1000*10)
public void RunLog(){
log.info("RunLog");
}
@Scheduled(cron = "${pre-dispatch.cron.expr}")
public void dispatchRun(){
log.info("dispatchRun");
}
}
package com.dituhui.pea.pre.service;
import java.sql.SQLException;
/**
* @author zhangx
*
* 批次排班数据准备
*
*/
public interface BatchService {
// 检查指定日期的小组是否有在运行的批次任务,有则返回,没有则创建后返回批次码
String buildBatchNo(String groupId, String day) throws SQLException;
}
package com.dituhui.pea.pre.service;
import com.dituhui.pea.pre.opta.domain.VehicleRoutingSolution;
import java.sql.SQLException;
/**
* @author zhangx
* <p>
* 排班算法数据准备
* 排班结果解析到dispatch_order(更新补充技术员工号、上门时间) ,order_appointment、order_request
*/
public interface PrepareService {
/*
* 按小组、批次号组装问题对象
* 调用optaplaner计算输出结果
* */
VehicleRoutingSolution prepareAndSolveSolution(String groupId, String batchNo);
/*
* 将计算结果回写到dispatch_order表(更新补充技术员工号、上门时间)
* */
void saveSolutionToDispatch(String groupId, String batchNo, VehicleRoutingSolution solution) throws SQLException;
/*
* 将dispath_order 中的计算结果,回写到 order_request, order_appointment
* order_appointment(新增、更新)
* order_request(主要更新状态)
* */
void extractDispatchToOrder(String groupId, String batchNo) throws SQLException;
}
package com.dituhui.pea.pre.service.impl;
import com.dituhui.pea.pre.dao.DispatchBatchRepository;
import com.dituhui.pea.pre.entity.DispatchBatch;
import com.dituhui.pea.pre.service.BatchService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Optional;
/**
* @author zhangx
*/
@Slf4j
@Service
public class BatchServiceImpl implements BatchService {
@Autowired
DispatchBatchRepository batchRepository;
private QueryRunner queryRunner;
public BatchServiceImpl(DataSource dataSource) {
this.queryRunner = new QueryRunner(dataSource);
}
// 生成最新批次日期
private String calcBatchDay() {
// 定义日期时间格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String result = LocalDate.now().format(formatter);
return result;
}
// 生成最新批次号
private String calcBatchNo() {
// 定义日期时间格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd-HHmm");
// 将当前时间转换为字符串
String result = LocalDateTime.now().format(formatter);
return result;
}
// 查询当前小组内已配置有中心点的技术员数量
private int queryEnginerCount(String groupId) {
int result = 0;
String sql = "select count(1) from engineer_info a left join engineer_business b on a.engineer_code=b.engineer_code " +
" where group_id=? and b.x is not null and b.x !='' ";
ScalarHandler<Long> scal = new ScalarHandler<>();
try {
result = Math.toIntExact(queryRunner.query(sql, scal, groupId));
} catch (SQLException e) {
throw new RuntimeException(e);
}
return result;
}
// 查询待指派工单数量
private int queryOrderCount(String groupId, String batchDay) {
int result = 0;
String sql = "select count(1) from order_request where org_group_id=? " +
" and status='OPEN' and appointment_status='NOT_ASSIGNED' and appointment_method like 'AUTO%' " +
" and expect_time_begin between ? and ? " +
" order by create_time asc ";
ScalarHandler<Long> scal = new ScalarHandler<>();
try {
long size = queryRunner.query(sql, scal, groupId, batchDay + " 00:00:00", batchDay + " 23:59:59");
result = Math.toIntExact(size);
} catch (SQLException e) {
throw new RuntimeException(e);
}
return result;
}
// 检查给定小组、日期是否有在运行的批次任务,没则返回,没有则创建
@Transactional
@Override
public String buildBatchNo(String groupId, String day) throws SQLException {
log.info("准备批次数据, groupId:{}, day:{}", groupId, day);
String batchNo = "";
String batchDay = "";
Optional<DispatchBatch> optional = batchRepository.findByGroupIdAndBatchDate(groupId, day);
if (!optional.isPresent()) {
batchNo = calcBatchNo();
batchDay = calcBatchDay();
// 执行数据库操作
String sqlInsert = "INSERT INTO `dispatch_batch` ( `group_id`, `batch_no`, `batch_date`, `engineer_num`, `order_num`, `start_time`, `end_time`, `status`) " +
" VALUES(?, ?, ?, ?, ?, ?, ?, ?)";
queryRunner.execute(sqlInsert, groupId, batchNo, batchDay, 0, 0, LocalDateTime.now(), null, "RUNNING");
log.info("生成新批次, groupId:{}, day:{}", groupId, day);
} else {
batchNo = optional.get().getBatchNo();
batchDay = optional.get().getBatchDate();
}
// int engCount = queryEnginerCount(groupId);
// int orderCount = queryOrderCount(groupId, batchDay);
log.info("清理原批次数据, groupId:{}, day:{}", groupId, day);
queryRunner.execute("delete from dispatch_engineer where group_id=? and batch_no=?", groupId, batchNo);
queryRunner.execute("delete from dispatch_order where group_id=? and batch_no=?", groupId, batchNo);
log.info("写入新批次技术员、工单数据, groupId:{}, day:{}", groupId, day);
String sqlEngineer = "INSERT INTO dispatch_engineer (group_id, batch_no, engineer_code, engineer_name, x, y, max_num, max_minute, max_distance)\n" +
"select a.group_id, ? , a.engineer_code, a.name , b.x, b.y , max_num, max_minute, max_distance from \n" +
" engineer_info a left join engineer_business b \n" +
" on a.engineer_code=b.engineer_code \n" +
" where a.group_id=? and b.x is not null and b.x !=''\n" +
" order by a.engineer_code asc";
int engCount = queryRunner.execute(sqlEngineer, batchNo, groupId);
String sqlOrder = "INSERT INTO dispatch_order (group_id, batch_no, order_id , x, y, expect_time_begin, expect_time_end, tags, priority , skills , take_time )\n" +
" select a.org_group_id, ? , a.order_id, a.x, a.y , \n" +
" a.expect_time_begin, a.expect_time_end, a.tags, a.priority , concat(a.brand, a.type, a.skill) skills , b.take_time \n" +
" from order_request a left join product_category b on (a.brand=b.brand and a.type=b.type and a.skill=b.skill )\n" +
" where a.org_group_id=? and status='OPEN' and appointment_status='NOT_ASSIGNED' and appointment_method like 'AUTO%' \n" +
" and expect_time_begin between ? and ? \n" +
" order by a.expect_time_begin asc ";
int orderCount = queryRunner.execute(sqlOrder, batchNo, groupId, batchDay + " 00:00:00", batchDay + " 23:59:59");
queryRunner.execute("update dispatch_batch set engineer_num=? , order_num=? where group_id=? and batch_no=?", engCount, orderCount, groupId, batchNo);
log.info("准备批次数据完成, groupId:{}, day:{}", groupId, day);
return batchNo;
}
}
server:
port: 8012
pre-dispatch:
cron:
expr: 0 */5 8-18 * * ?
spring:
application:
name: project-pre-dispatch
jackson:
default-property-inclusion: NON_NULL
# time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
group: project
config:
server-addr: 127.0.0.1:8848
group: project
file-extension: yaml
import-check:
# no config file
enabled: false
config:
import:
- optional:nacos:project-order.yaml
# - optional:nacos:datasource-config.yaml
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/saas_aftersale_test?serverTimezone=UTC
username: root
password: 12345678
type: com.alibaba.druid.pool.DruidDataSource
redis:
database: 0
host: 127.0.0.1
port: 6379
password: 123456
jedis:
pool:
max-active: 32
min-idle: 0
max-idle: 8
max-wait: -1
jpa:
show-sql: true
hibernate:
ddl-auto: none
seata:
application-id: ${spring.application.name}
tx-service-group: ${spring.application.name}-group
service:
vgroup-mapping:
project-order-group: default
grouplist:
default: 127.0.0.1:8091
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd'T'HH:mm:ss.SSSZ} %level [%thread] %logger{15} : %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
package com.dituhui.pea.pre;
import com.dituhui.pea.pre.service.BatchService;
import com.dituhui.pea.pre.service.impl.BatchServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.sql.SQLException;
@Slf4j
@SpringBootTest
public class BatchServiceTest {
@Autowired
BatchService batchService;
String groupId = "gsuzhou";
String day = "2023-06-16";
@Test
public void test1() {
log.info("init");
try {
batchService.buildBatchNo(groupId, day);
} catch (SQLException e) {
log.info("error %s", e);
throw new RuntimeException(e);
}
log.info("done");
}
}
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!