Skip to content
Toggle navigation
Projects
Groups
Snippets
Help
yangxiujun
/
paidan_demo
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit 998c16f9
authored
Jul 05, 2023
by
张晓
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
算法读取批次部分合并
1 parent
f26dde47
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
1333 additions
and
21 deletions
project-dispatch/pom.xml
project-dispatch/src/main/java/com/dituhui/pea/dispatch/common/DateUtil.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/common/GeoDistanceCalculator.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/constraint/DispatchConstraintProvider.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/controller/DispatchController.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/dao/DispatchBatchRepository.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/dao/DispatchEngineerRepository.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/dao/DispatchOrderRepository.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/dao/EngineerInfoRepository.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/dao/OrderAppointmentRepository.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/dao/OrderRequestRepository.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/dao/OrgGroupRepository.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/entity/DispatchBatch.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/entity/DispatchEngineer.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/entity/DispatchOrder.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/entity/EngineerInfo.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/entity/OrderAppointment.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/entity/OrderRequest.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/entity/OrgGroup.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/pojo/Depot.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/pojo/DispatchSolution.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/pojo/Location.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/pojo/Technician.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/BatchService.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/DispatchService.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/ExtractService.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/SolveService.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/impl/BatchServiceImpl.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/impl/ExtractServiceImpl.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/impl/SolveServiceImpl.java
project-dispatch/pom.xml
View file @
998c16f
...
@@ -95,6 +95,13 @@
...
@@ -95,6 +95,13 @@
<artifactId>
commons-lang3
</artifactId>
<artifactId>
commons-lang3
</artifactId>
<version>
3.12.0
</version>
<version>
3.12.0
</version>
</dependency>
</dependency>
<dependency>
<groupId>
org.gavaghan
</groupId>
<artifactId>
geodesy
</artifactId>
<version>
1.1.3
</version>
</dependency>
</dependencies>
</dependencies>
<build>
<build>
<plugins>
<plugins>
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/common/DateUtil.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
common
;
import
java.time.Instant
;
import
java.time.LocalDateTime
;
import
java.time.ZoneId
;
import
java.time.ZonedDateTime
;
import
java.util.Date
;
public
class
DateUtil
{
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
;
}
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/common/GeoDistanceCalculator.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
common
;
import
com.dituhui.pea.dispatch.pojo.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
;
import
java.util.Collection
;
import
java.util.Map
;
import
java.util.function.Function
;
import
java.util.stream.Collectors
;
@Component
public
class
GeoDistanceCalculator
{
private
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
;
}
private
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
)
))
));
}
public
void
initDistanceMaps
(
Collection
<
Location
>
locationList
)
{
Map
<
Location
,
Map
<
Location
,
Long
>>
distanceMatrix
=
calculateBulkDistance
(
locationList
,
locationList
);
locationList
.
forEach
(
location
->
location
.
setDistanceMap
(
distanceMatrix
.
get
(
location
)));
}
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/constraint/DispatchConstraintProvider.java
View file @
998c16f
...
@@ -13,11 +13,8 @@ public class DispatchConstraintProvider implements ConstraintProvider {
...
@@ -13,11 +13,8 @@ public class DispatchConstraintProvider implements ConstraintProvider {
@Override
@Override
public
Constraint
[]
defineConstraints
(
ConstraintFactory
factory
)
{
public
Constraint
[]
defineConstraints
(
ConstraintFactory
factory
)
{
return
new
Constraint
[]
{
greaterThanZero
(
factory
),
customerTimeWindowsMatch1
(
factory
),
return
new
Constraint
[]
{
greaterThanZero
(
factory
),
customerTimeWindowsMatch1
(
factory
),
customerTimeWindowsMatch2
(
factory
),
customerTimeWindowsMatch2
(
factory
),
skillMatch
(
factory
),
technicianBalance
(
factory
),
skillMatch
(
factory
),
technicianBalance2
(
factory
),
technicianBalanceSoft
(
factory
),
totalDistance
(
factory
),
technicianBalance
(
factory
),
technicianBalance2
(
factory
),
totalDistance
(
factory
),
preferredTotalDistance
(
factory
)
};
preferredTotalDistance
(
factory
)
};
}
}
...
@@ -30,7 +27,7 @@ public class DispatchConstraintProvider implements ConstraintProvider {
...
@@ -30,7 +27,7 @@ public class DispatchConstraintProvider implements ConstraintProvider {
// 4,技术员技能跟订单相匹配skillMatch
// 4,技术员技能跟订单相匹配skillMatch
// 5,订单均分technicianBalance
// 5,订单均分technicianBalance
p
rotected
Constraint
greaterThanZero
(
ConstraintFactory
factory
)
{
p
ublic
Constraint
greaterThanZero
(
ConstraintFactory
factory
)
{
return
factory
.
forEach
(
Technician
.
class
).
filter
(
technician
->
technician
.
getCustomerList
().
size
()
==
0
)
return
factory
.
forEach
(
Technician
.
class
).
filter
(
technician
->
technician
.
getCustomerList
().
size
()
==
0
)
.
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
technician
->
1
).
asConstraint
(
"每个技术员至少分配一个单子"
);
.
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
technician
->
1
).
asConstraint
(
"每个技术员至少分配一个单子"
);
}
}
...
@@ -42,6 +39,7 @@ public class DispatchConstraintProvider implements ConstraintProvider {
...
@@ -42,6 +39,7 @@ public class DispatchConstraintProvider implements ConstraintProvider {
}
}
protected
Constraint
customerTimeWindowsMatch2
(
ConstraintFactory
factory
)
{
protected
Constraint
customerTimeWindowsMatch2
(
ConstraintFactory
factory
)
{
// 迟到2小时惩罚
return
factory
.
forEach
(
Customer
.
class
).
filter
(
return
factory
.
forEach
(
Customer
.
class
).
filter
(
customer
->
customer
.
getTechnician
()
!=
null
&&
customer
.
getArrivalTime
()
>
customer
.
getEndTime
()
+
120
)
customer
->
customer
.
getTechnician
()
!=
null
&&
customer
.
getArrivalTime
()
>
customer
.
getEndTime
()
+
120
)
.
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
customer
->
1
).
asConstraint
(
"技术员到达时间跟时间窗吻合2"
);
.
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
customer
->
1
).
asConstraint
(
"技术员到达时间跟时间窗吻合2"
);
...
@@ -51,12 +49,17 @@ public class DispatchConstraintProvider implements ConstraintProvider {
...
@@ -51,12 +49,17 @@ public class DispatchConstraintProvider implements ConstraintProvider {
return
factory
.
forEach
(
Customer
.
class
)
return
factory
.
forEach
(
Customer
.
class
)
.
filter
(
customer
->
customer
.
getTechnician
()
!=
null
.
filter
(
customer
->
customer
.
getTechnician
()
!=
null
&&
!
customer
.
getTechnician
().
getSkills
().
contains
(
customer
.
getRequiredSkill
()))
&&
!
customer
.
getTechnician
().
getSkills
().
contains
(
customer
.
getRequiredSkill
()))
.
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
customer
->
1
).
asConstraint
(
"技术员技能跟订单相匹配skillMatch"
);
.
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
// 技能匹配跟时间窗匹配存在很明显的跷跷板效应,权重小于3就会存在技能匹配问题
// 3-技能匹配问题1个,时间窗问题8个
// 4-技能匹配问题0个,时间窗问题14个
customer
->
4
)
.
asConstraint
(
"技术员技能跟订单相匹配skillMatch"
);
}
}
protected
Constraint
technicianBalance
(
ConstraintFactory
factory
)
{
protected
Constraint
technicianBalance
(
ConstraintFactory
factory
)
{
// 会导致剩余单子集中?
// 会导致剩余单子集中?
return
factory
.
forEach
(
Technician
.
class
).
filter
(
technician
->
technician
.
getOffWorkTime
()
>
1
4
40
)
return
factory
.
forEach
(
Technician
.
class
).
filter
(
technician
->
technician
.
getOffWorkTime
()
>
1
1
40
)
.
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
.
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
technician
->
(
long
)
Math
.
ceil
(
technician
.
getOffWorkTime
()
/
1440
f
))
technician
->
(
long
)
Math
.
ceil
(
technician
.
getOffWorkTime
()
/
1440
f
))
.
asConstraint
(
"订单均分"
);
.
asConstraint
(
"订单均分"
);
...
@@ -64,10 +67,8 @@ public class DispatchConstraintProvider implements ConstraintProvider {
...
@@ -64,10 +67,8 @@ public class DispatchConstraintProvider implements ConstraintProvider {
protected
Constraint
technicianBalance2
(
ConstraintFactory
factory
)
{
protected
Constraint
technicianBalance2
(
ConstraintFactory
factory
)
{
// 单量不能过少 FIXME
// 单量不能过少 FIXME
return
factory
.
forEach
(
Technician
.
class
).
filter
(
technician
->
technician
.
getOffWorkTime
()
<=
1140
)
return
factory
.
forEach
(
Technician
.
class
).
filter
(
technician
->
technician
.
getOffWorkTime
()
<=
960
)
.
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
.
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
technician
->
1
).
asConstraint
(
"订单均分2"
);
technician
->
1
)
.
asConstraint
(
"订单均分2"
);
}
}
// protected Constraint technicianBalance(ConstraintFactory factory) {
// protected Constraint technicianBalance(ConstraintFactory factory) {
...
@@ -92,6 +93,7 @@ public class DispatchConstraintProvider implements ConstraintProvider {
...
@@ -92,6 +93,7 @@ public class DispatchConstraintProvider implements ConstraintProvider {
// ************************************************************************
// ************************************************************************
// 1, 总路程最小 totalDistance
// 1, 总路程最小 totalDistance
// 2, 技术员中心点偏好 preferredTotalDistance
// 2, 技术员中心点偏好 preferredTotalDistance
// 3, 订单数量均衡 technicianBalanceSoft
protected
Constraint
totalDistance
(
ConstraintFactory
factory
)
{
protected
Constraint
totalDistance
(
ConstraintFactory
factory
)
{
return
factory
.
forEach
(
Technician
.
class
)
return
factory
.
forEach
(
Technician
.
class
)
...
@@ -104,4 +106,10 @@ public class DispatchConstraintProvider implements ConstraintProvider {
...
@@ -104,4 +106,10 @@ public class DispatchConstraintProvider implements ConstraintProvider {
.
asConstraint
(
"技术员中心点偏好"
);
.
asConstraint
(
"技术员中心点偏好"
);
}
}
protected
Constraint
technicianBalanceSoft
(
ConstraintFactory
factory
)
{
return
factory
.
forEachUniquePair
(
Technician
.
class
).
penalizeLong
(
HardSoftLongScore
.
ONE_SOFT
,
// 权重需要调节,差距一个相当于多一公里 FIXME 这里应该是时长均衡,不是订单量均衡
(
a
,
b
)
->
Math
.
abs
(
a
.
getCustomerSize
()
-
b
.
getCustomerSize
())
*
1000
).
asConstraint
(
"订单均分soft"
);
}
}
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/controller/DispatchController.java
View file @
998c16f
...
@@ -19,6 +19,7 @@ package com.dituhui.pea.dispatch.controller;
...
@@ -19,6 +19,7 @@ package com.dituhui.pea.dispatch.controller;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestParam
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.bind.annotation.RestController
;
import
com.dituhui.pea.common.Result
;
import
com.dituhui.pea.common.Result
;
...
@@ -35,10 +36,19 @@ public class DispatchController {
...
@@ -35,10 +36,19 @@ public class DispatchController {
private
DispatchService
dispatchService
;
private
DispatchService
dispatchService
;
@GetMapping
(
"/manual"
)
@GetMapping
(
"/manual"
)
public
Result
<?>
manualDispatch
()
{
public
Result
<?>
manualDispatch
(
@RequestParam
(
value
=
"unimprovedSecondsSpentLimit"
,
required
=
false
)
Long
unimprovedSecondsSpentLimit
,
@RequestParam
(
value
=
"secondsSpentLimit"
,
required
=
false
)
Long
secondsSpentLimit
)
{
if
(
null
==
unimprovedSecondsSpentLimit
)
{
unimprovedSecondsSpentLimit
=
0L
;
}
if
(
null
==
secondsSpentLimit
)
{
secondsSpentLimit
=
0L
;
}
try
{
try
{
return
dispatchService
.
manualDispatch
();
return
dispatchService
.
manualDispatch
(
unimprovedSecondsSpentLimit
,
secondsSpentLimit
);
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
Result
.
failed
(
e
.
getMessage
());
return
Result
.
failed
(
e
.
getMessage
());
}
}
}
}
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/dao/DispatchBatchRepository.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
dao
;
import
com.dituhui.pea.dispatch.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
project-dispatch/src/main/java/com/dituhui/pea/dispatch/dao/DispatchEngineerRepository.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
dao
;
import
com.dituhui.pea.dispatch.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
project-dispatch/src/main/java/com/dituhui/pea/dispatch/dao/DispatchOrderRepository.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
dao
;
import
com.dituhui.pea.dispatch.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
project-dispatch/src/main/java/com/dituhui/pea/dispatch/dao/EngineerInfoRepository.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
dao
;
import
com.dituhui.pea.dispatch.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
project-dispatch/src/main/java/com/dituhui/pea/dispatch/dao/OrderAppointmentRepository.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
dao
;
import
com.dituhui.pea.dispatch.entity.OrderAppointment
;
import
org.springframework.data.repository.CrudRepository
;
import
java.util.Optional
;
public
interface
OrderAppointmentRepository
extends
CrudRepository
<
OrderAppointment
,
Long
>
{
Optional
<
OrderAppointment
>
findByOrderId
(
String
orderId
);
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/dao/OrderRequestRepository.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
dao
;
import
com.dituhui.pea.dispatch.entity.OrderRequest
;
import
org.springframework.data.repository.CrudRepository
;
import
java.util.Optional
;
public
interface
OrderRequestRepository
extends
CrudRepository
<
OrderRequest
,
Long
>
{
Optional
<
OrderRequest
>
findByOrderId
(
String
orderId
);
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/dao/OrgGroupRepository.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
dao
;
import
java.util.List
;
import
java.util.Optional
;
import
com.dituhui.pea.dispatch.entity.DispatchBatch
;
import
com.dituhui.pea.dispatch.entity.OrgGroup
;
import
org.springframework.data.repository.CrudRepository
;
import
com.fasterxml.jackson.annotation.JsonFormat
;
import
org.springframework.stereotype.Repository
;
@Repository
public
interface
OrgGroupRepository
extends
CrudRepository
<
OrgGroup
,
Long
>
{
Optional
<
OrgGroup
>
findByGroupId
(
String
groupId
);
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/entity/DispatchBatch.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
entity
;
import
com.fasterxml.jackson.annotation.JsonFormat
;
import
lombok.Data
;
import
java.io.Serializable
;
import
java.time.LocalDateTime
;
import
javax.persistence.*
;
/**
* 排班批次总表
*/
@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
;
}
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/entity/DispatchEngineer.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
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
;
}
\ No newline at end of file
project-dispatch/src/main/java/com/dituhui/pea/dispatch/entity/DispatchOrder.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
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
;
}
\ No newline at end of file
project-dispatch/src/main/java/com/dituhui/pea/dispatch/entity/EngineerInfo.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
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
;
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/entity/OrderAppointment.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
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
;
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/entity/OrderRequest.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
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
;
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/entity/OrgGroup.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
entity
;
import
lombok.Data
;
import
java.util.Date
;
import
java.io.Serializable
;
import
com.fasterxml.jackson.annotation.JsonFormat
;
import
javax.persistence.*
;
import
javax.persistence.Table
;
@Data
@Entity
@Table
(
name
=
"org_group"
)
public
class
OrgGroup
implements
Serializable
{
@Id
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
private
Integer
id
;
@Column
(
name
=
"group_id"
)
private
String
groupId
;
@Column
(
name
=
"group_name"
)
private
String
groupName
;
@Column
(
name
=
"cluster_id"
)
private
String
clusterId
;
@Column
(
name
=
"branch_id"
)
private
String
branchId
;
private
String
address
;
@Column
(
name
=
"x"
)
private
String
X
;
@Column
(
name
=
"y"
)
private
String
Y
;
@Column
(
name
=
"city_code"
)
private
String
cityCode
;
private
Integer
kind
;
private
Integer
category
;
@Column
(
name
=
"warehouse_id"
)
private
Integer
warehouseId
;
private
String
memo
;
@JsonFormat
(
pattern
=
"yyyy-MM-dd HH:mm:ss"
,
timezone
=
"GMT+8"
)
@Column
(
name
=
"create_time"
)
private
Date
createTime
;
@JsonFormat
(
pattern
=
"yyyy-MM-dd HH:mm:ss"
,
timezone
=
"GMT+8"
)
@Column
(
name
=
"update_time"
)
private
Date
updateTime
;
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/pojo/Depot.java
View file @
998c16f
...
@@ -6,12 +6,14 @@ import lombok.Data;
...
@@ -6,12 +6,14 @@ import lombok.Data;
* 出发地
* 出发地
*
*
* @author gpzhang
* @author gpzhang
*
*/
*/
@Data
@Data
public
class
Depot
{
public
class
Depot
{
private
final
long
id
;
private
final
long
id
;
private
String
code
=
""
;
private
final
Location
location
;
private
final
Location
location
;
// 时间窗 分钟
// 时间窗 分钟
...
@@ -25,4 +27,11 @@ public class Depot {
...
@@ -25,4 +27,11 @@ public class Depot {
this
.
endTime
=
endTime
;
this
.
endTime
=
endTime
;
}
}
public
Depot
(
long
id
,
String
code
,
Location
location
,
int
startTime
,
int
endTime
)
{
this
.
id
=
id
;
this
.
code
=
code
;
this
.
location
=
location
;
this
.
startTime
=
startTime
;
this
.
endTime
=
endTime
;
}
}
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/pojo/DispatchSolution.java
View file @
998c16f
...
@@ -16,6 +16,11 @@ import lombok.Data;
...
@@ -16,6 +16,11 @@ import lombok.Data;
@PlanningSolution
@PlanningSolution
public
class
DispatchSolution
{
public
class
DispatchSolution
{
private
String
groupId
;
private
String
batchNo
;
private
String
name
;
private
String
name
;
@ProblemFactCollectionProperty
@ProblemFactCollectionProperty
...
@@ -47,6 +52,15 @@ public class DispatchSolution {
...
@@ -47,6 +52,15 @@ public class DispatchSolution {
this
.
customerList
=
customerList
;
this
.
customerList
=
customerList
;
}
}
public
DispatchSolution
(
String
groupId
,
String
batchNo
,
List
<
Location
>
locationList
,
Depot
depot
,
List
<
Technician
>
technicianList
,
List
<
Customer
>
customerList
)
{
this
.
groupId
=
groupId
;
this
.
batchNo
=
batchNo
;
this
.
locationList
=
locationList
;
this
.
depot
=
depot
;
this
.
technicianList
=
technicianList
;
this
.
customerList
=
customerList
;
}
// ************************************************************************
// ************************************************************************
// Complex methods
// Complex methods
// ************************************************************************
// ************************************************************************
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/pojo/Location.java
View file @
998c16f
...
@@ -13,15 +13,40 @@ import lombok.Setter;
...
@@ -13,15 +13,40 @@ import lombok.Setter;
public
class
Location
{
public
class
Location
{
private
final
long
id
;
private
final
long
id
;
private
String
code
;
// 类型 engineer order
private
String
type
;
private
double
latitude
;
private
double
longitude
;
@JsonIgnore
@JsonIgnore
private
Map
<
Location
,
Long
>
distanceMap
=
new
HashMap
<
Location
,
Long
>();
// 路网距离矩阵
private
Map
<
Location
,
Long
>
distanceMap
=
new
HashMap
<
Location
,
Long
>();
// 路网距离矩阵
@JsonIgnore
@JsonIgnore
private
Map
<
Location
,
Long
>
distanceTimeMap
=
new
HashMap
<
Location
,
Long
>();
// 路网时间矩阵
private
Map
<
Location
,
Long
>
distanceTimeMap
=
new
HashMap
<
Location
,
Long
>();
// 路网时间矩阵
public
Location
(
long
id
)
{
public
Location
(
long
id
)
{
this
.
id
=
id
;
this
.
id
=
id
;
}
}
public
Location
(
long
id
,
String
code
,
String
type
,
double
longitude
,
double
latitude
)
{
this
.
id
=
id
;
this
.
code
=
code
;
this
.
type
=
type
;
this
.
longitude
=
longitude
;
this
.
latitude
=
latitude
;
}
@Override
public
String
toString
()
{
return
"Location{"
+
"code='"
+
code
+
'\''
+
", type='"
+
type
+
'\''
+
", latitude="
+
latitude
+
", longitude="
+
longitude
+
'}'
;
}
/**
/**
* Set the distance map. Distances are in meters.
* Set the distance map. Distances are in meters.
*
*
...
@@ -41,10 +66,10 @@ public class Location {
...
@@ -41,10 +66,10 @@ public class Location {
return
distanceMap
.
get
(
location
);
return
distanceMap
.
get
(
location
);
}
}
/**
/**
* time to the given location in minutes.
* time to the given location in minutes.
* FIXME 这里简化处理没有用时间矩阵 时间=距离/100
* FIXME 这里简化处理没有用时间矩阵 时间=距离/100
*
* @param location other location
* @param location other location
* @return time in minutes
* @return time in minutes
*/
*/
...
@@ -56,10 +81,20 @@ public class Location {
...
@@ -56,10 +81,20 @@ public class Location {
// Complex methods
// Complex methods
// ************************************************************************
// ************************************************************************
@Override
public
int
hashCode
()
{
return
Long
.
valueOf
(
this
.
id
).
hashCode
();
}
@Override
@Override
public
String
toString
()
{
public
boolean
equals
(
Object
obj
)
{
return
"Location{"
+
"id="
+
id
+
'}'
;
if
(
obj
==
null
)
return
false
;
if
(!(
obj
instanceof
Location
))
return
false
;
if
(
obj
==
this
)
return
true
;
return
this
.
id
==
((
Location
)
obj
).
getId
();
}
}
}
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/pojo/Technician.java
View file @
998c16f
...
@@ -31,6 +31,16 @@ public class Technician {
...
@@ -31,6 +31,16 @@ public class Technician {
// 技能
// 技能
private
Set
<
String
>
skills
;
private
Set
<
String
>
skills
;
// 每日最大单量
private
int
maxCount
;
// 每日最大工作时长
private
int
maxMinute
;
// 单位是米,这里要注意
private
int
maxDistanceMeter
;
// 偏好坐标
// 偏好坐标
// private Location preferredlocation;
// private Location preferredlocation;
// teck code : customer code , distance
// teck code : customer code , distance
...
@@ -54,6 +64,21 @@ public class Technician {
...
@@ -54,6 +64,21 @@ public class Technician {
this
.
preferredlocationDistanceMap
=
preferredlocationDistanceMap
;
this
.
preferredlocationDistanceMap
=
preferredlocationDistanceMap
;
}
}
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
.
startTime
=
startTime
;
this
.
endTime
=
endTime
;
this
.
skills
=
skills
;
this
.
maxCount
=
maxCount
;
this
.
maxMinute
=
maxMinute
;
this
.
maxDistanceMeter
=
maxDistanceMeter
;
this
.
preferredlocationDistanceMap
=
preferredlocationDistanceMap
;
}
// ************************************************************************
// ************************************************************************
// Complex methods
// Complex methods
// ************************************************************************
// ************************************************************************
...
@@ -99,6 +124,7 @@ public class Technician {
...
@@ -99,6 +124,7 @@ public class Technician {
return
totalDistance
;
return
totalDistance
;
}
}
/**
/**
* 获取偏好总距离 所有customer与该技术员的PreferredLocation距离之和
* 获取偏好总距离 所有customer与该技术员的PreferredLocation距离之和
*
*
...
@@ -135,6 +161,7 @@ public class Technician {
...
@@ -135,6 +161,7 @@ public class Technician {
}
}
}
}
/**
/**
* 获取下班时间,最后一个订单完成时间
* 获取下班时间,最后一个订单完成时间
*
*
...
@@ -150,4 +177,23 @@ public class Technician {
...
@@ -150,4 +177,23 @@ public class Technician {
}
}
}
}
@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
();
}
}
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/BatchService.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
service
;
import
com.dituhui.pea.dispatch.entity.DispatchBatch
;
import
org.springframework.transaction.annotation.Transactional
;
import
java.sql.SQLException
;
/**
* @author zhangx
* <p>
* 批次排班数据准备
*/
public
interface
BatchService
{
// 检查指定日期的小组是否有在运行的批次任务,有则返回,没有则创建后返回批次码
@Transactional
String
buildBatchNo
(
String
groupId
,
String
day
)
throws
SQLException
;
DispatchBatch
queryBatch
(
String
groupId
,
String
day
);
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/DispatchService.java
View file @
998c16f
...
@@ -26,6 +26,7 @@ import com.dituhui.pea.common.Result;
...
@@ -26,6 +26,7 @@ import com.dituhui.pea.common.Result;
*/
*/
public
interface
DispatchService
{
public
interface
DispatchService
{
Result
<?>
manualDispatch
()
throws
UncheckedIOException
,
IOException
;
Result
<?>
manualDispatch
(
long
unimprovedSecondsSpentLimit
,
long
secondsSpentLimit
)
throws
UncheckedIOException
,
IOException
;
}
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/ExtractService.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
service
;
import
com.dituhui.pea.dispatch.pojo.DispatchSolution
;
import
java.sql.SQLException
;
/**
* @author zhangx
* <p>
* 排班算法数据准备
* 排班结果解析到dispatch_order(更新补充技术员工号、上门时间) ,order_appointment、order_request
*/
public
interface
ExtractService
{
/*
* 将计算结果回写到dispatch2个表、以及order两个表
* 是下面两个方法的包装
* */
void
saveAndExtractSolution
(
DispatchSolution
solution
)
throws
RuntimeException
;
/*
* 将计算结果回写到dispatch_order表(更新补充技术员工号、上门时间)
* */
void
saveSolutionToDispatch
(
String
groupId
,
String
batchNo
,
DispatchSolution
solution
)
throws
RuntimeException
;
/*
* 将dispath_order 中的计算结果,回写到 order_request, order_appointment
* order_appointment(新增、更新)
* order_request(主要更新状态)
* */
void
extractDispatchToOrder
(
String
groupId
,
String
batchNo
)
throws
SQLException
;
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/SolveService.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
service
;
import
com.dituhui.pea.dispatch.pojo.DispatchSolution
;
import
java.util.UUID
;
/**
* @author zhangx
* <p>
* 排班算法执行
*/
public
interface
SolveService
{
/*
* 按小组、批次号组装问题对象
* 调用optaplaner计算输出结果
* */
DispatchSolution
prepareAndSolveSolution
(
String
groupId
,
String
batchNo
);
UUID
generateProblemId
(
String
groupId
,
String
batchNo
);
DispatchSolution
prepareSolution
(
String
groupId
,
String
batchNo
)
;
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/impl/BatchServiceImpl.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
service
.
impl
;
import
com.dituhui.pea.dispatch.dao.DispatchBatchRepository
;
import
com.dituhui.pea.dispatch.entity.DispatchBatch
;
import
com.dituhui.pea.dispatch.service.BatchService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.jdbc.core.JdbcTemplate
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.PlatformTransactionManager
;
import
org.springframework.transaction.TransactionStatus
;
import
org.springframework.transaction.annotation.Propagation
;
import
org.springframework.transaction.annotation.Transactional
;
import
org.springframework.transaction.support.DefaultTransactionDefinition
;
import
org.springframework.transaction.support.TransactionTemplate
;
import
javax.sql.DataSource
;
import
java.sql.Connection
;
import
java.sql.SQLException
;
import
java.time.LocalDate
;
import
java.time.LocalDateTime
;
import
java.time.LocalTime
;
import
java.time.format.DateTimeFormatter
;
import
java.util.List
;
import
java.util.Optional
;
/**
* @author zhangx
*/
@Slf4j
@Service
public
class
BatchServiceImpl
implements
BatchService
{
@Autowired
DispatchBatchRepository
batchRepository
;
@Autowired
private
JdbcTemplate
jdbcTemplate
;
// 生成最新批次号
private
String
calcBatchNo
(
String
day
)
{
// 定义日期时间格式
DateTimeFormatter
formatter
=
DateTimeFormatter
.
ofPattern
(
"HHmm"
);
// 将当前时间转换为字符串
String
result
=
LocalTime
.
now
().
format
(
formatter
);
return
day
.
replaceAll
(
"-"
,
""
)
+
"-"
+
result
;
}
// 检查给定小组、日期是否有在运行的批次任务,没则返回,没有则创建
@Transactional
@Override
public
String
buildBatchNo
(
String
groupId
,
String
day
)
{
log
.
info
(
"准备批次数据, groupId:{}, day:{}"
,
groupId
,
day
);
String
batchNo
=
""
;
String
batchDay
=
""
;
Optional
<
DispatchBatch
>
optional
=
batchRepository
.
findByGroupIdAndBatchDate
(
groupId
,
day
);
if
(!
optional
.
isPresent
())
{
batchNo
=
calcBatchNo
(
day
);
batchDay
=
day
;
// 执行数据库操作
String
sqlInsert
=
"INSERT INTO `dispatch_batch` ( `group_id`, `batch_no`, `batch_date`, `engineer_num`, `order_num`, `start_time`, `end_time`, `status`) "
+
" VALUES(?, ?, ?, ?, ?, ?, ?, ?)"
;
jdbcTemplate
.
update
(
sqlInsert
,
groupId
,
batchNo
,
batchDay
,
0
,
0
,
LocalDateTime
.
now
(),
null
,
"RUNNING"
);
// queryRunner.execute(sqlInsert, groupId, batchNo, batchDay, 0, 0, LocalDateTime.now(), null, "RUNNING");
log
.
info
(
"生成新批次, groupId:{}, day:{}"
,
groupId
,
batchDay
);
}
else
{
batchNo
=
optional
.
get
().
getBatchNo
();
batchDay
=
optional
.
get
().
getBatchDate
();
}
// int engCount = queryEnginerCount(groupId);
// int orderCount = queryOrderCount(groupId, batchDay);
log
.
info
(
"清理原批次数据, groupId:{}, day:{}, batchNo:{}"
,
groupId
,
batchDay
,
batchNo
);
jdbcTemplate
.
update
(
"delete from dispatch_engineer where group_id=? and batch_no=?"
,
groupId
,
batchNo
);
jdbcTemplate
.
update
(
"delete from dispatch_order where group_id=? and batch_no=?"
,
groupId
,
batchNo
);
log
.
info
(
"写入新批次技术员、工单数据, groupId:{}, day:{}, batchNo:{}"
,
groupId
,
batchDay
,
batchNo
);
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
=
jdbcTemplate
.
update
(
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
=
jdbcTemplate
.
update
(
sqlOrder
,
batchNo
,
groupId
,
batchDay
+
" 00:00:00"
,
batchDay
+
" 23:59:59"
);
jdbcTemplate
.
update
(
"update dispatch_batch set engineer_num=? , order_num=? where group_id=? and batch_no=?"
,
engCount
,
orderCount
,
groupId
,
batchNo
);
log
.
info
(
"准备批次数据完成, groupId:{}, day:{}, batchNo:{}"
,
groupId
,
batchDay
,
batchNo
);
return
batchNo
;
}
public
DispatchBatch
queryBatch
(
String
groupId
,
String
batchNo
)
{
List
<
DispatchBatch
>
batchList
=
batchRepository
.
findLatestGroup
(
groupId
,
batchNo
);
if
(
batchList
.
size
()
>
0
)
{
return
batchList
.
get
(
0
);
}
else
{
return
new
DispatchBatch
();
}
}
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/impl/ExtractServiceImpl.java
0 → 100644
View file @
998c16f
This diff is collapsed.
Click to expand it.
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/impl/SolveServiceImpl.java
0 → 100644
View file @
998c16f
package
com
.
dituhui
.
pea
.
dispatch
.
service
.
impl
;
import
cn.hutool.crypto.SecureUtil
;
import
com.dituhui.pea.dispatch.common.GeoDistanceCalculator
;
import
com.dituhui.pea.dispatch.constraint.DispatchConstraintProvider
;
import
com.dituhui.pea.dispatch.dao.DispatchEngineerRepository
;
import
com.dituhui.pea.dispatch.dao.DispatchOrderRepository
;
import
com.dituhui.pea.dispatch.dao.OrgGroupRepository
;
import
com.dituhui.pea.dispatch.entity.OrgGroup
;
import
com.dituhui.pea.dispatch.pojo.*
;
import
com.dituhui.pea.dispatch.service.ExtractService
;
import
com.dituhui.pea.dispatch.service.SolveService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.optaplanner.core.api.solver.*
;
import
org.optaplanner.core.config.solver.SolverConfig
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.jdbc.core.JdbcTemplate
;
import
org.springframework.stereotype.Service
;
import
javax.sql.DataSource
;
import
java.sql.SQLException
;
import
java.time.Duration
;
import
java.time.LocalDateTime
;
import
java.util.*
;
import
java.util.concurrent.ExecutionException
;
import
java.util.stream.Collectors
;
import
java.util.stream.Stream
;
import
static
com
.
dituhui
.
pea
.
dispatch
.
common
.
DateUtil
.
dateToLocalDateTime
;
@Slf4j
@Service
public
class
SolveServiceImpl
implements
SolveService
{
@Autowired
GeoDistanceCalculator
distanceCalculator
;
@Autowired
DispatchEngineerRepository
dispatchEngineerRepo
;
@Autowired
DispatchOrderRepository
dispatchOrderRepo
;
@Autowired
OrgGroupRepository
groupRepository
;
@Autowired
ExtractService
extractService
;
@Autowired
private
JdbcTemplate
jdbcTemplate
;
// 查询技术员所有技能集
private
List
<
String
>
queryEngineerSkills
(
String
engineerCode
)
{
List
<
String
>
result
=
new
ArrayList
<>();
String
sql
=
"select concat( b.brand, b.type, b.skill) as skill from engineer_skill a left join product_category b \n"
+
"\ton a.category_id= b.product_category_id where a.engineer_code=? and a.status=1 "
;
Object
[]
param
=
{
engineerCode
};
result
=
jdbcTemplate
.
queryForList
(
sql
,
param
,
String
.
class
);
return
result
;
}
// 按小组、批次号组装问题对象
@Override
public
DispatchSolution
prepareSolution
(
String
groupId
,
String
batchNo
)
{
log
.
info
(
"组织问题对象, groupId:{}, batchNo:{}"
,
groupId
,
batchNo
);
// 统一出发地
Depot
oneDepot
;
Optional
<
OrgGroup
>
optional
=
groupRepository
.
findByGroupId
(
groupId
);
if
(!
optional
.
isPresent
())
{
log
.
error
(
"组织问题对象, 未查询到组织信息 ,groupId:{}, batchNo:{}"
);
throw
new
RuntimeException
(
String
.
format
(
"组织问题对象, 未查询到组织信息 ,groupId:%s, batchNo:%s"
,
groupId
,
batchNo
));
}
OrgGroup
oneGroup
=
optional
.
get
();
Location
deptLocation
=
new
Location
(
oneGroup
.
getId
(),
oneGroup
.
getGroupId
(),
"起点"
,
Double
.
parseDouble
(
oneGroup
.
getX
()),
Double
.
parseDouble
(
oneGroup
.
getY
()));
oneDepot
=
new
Depot
(
oneGroup
.
getId
(),
oneGroup
.
getGroupId
(),
deptLocation
,
60
*
8
,
60
*
18
);
// depotlist 技术员中收点列表
ArrayList
<
Depot
>
depotList
=
new
ArrayList
<
Depot
>();
// technicianList
ArrayList
<
Technician
>
technicianList
=
new
ArrayList
<>();
dispatchEngineerRepo
.
findByGroupIdAndBatchNo
(
groupId
,
batchNo
).
forEach
(
engineer
->
{
Location
location
=
new
Location
(
engineer
.
getId
(),
engineer
.
getEngineerCode
(),
"中心点"
,
Double
.
parseDouble
(
engineer
.
getX
()),
Double
.
parseDouble
(
engineer
.
getY
()));
Depot
depot
=
new
Depot
(
engineer
.
getId
(),
engineer
.
getEngineerCode
(),
location
,
60
*
8
,
60
*
18
);
depotList
.
add
(
depot
);
List
<
String
>
skillList
=
queryEngineerSkills
(
engineer
.
getEngineerCode
());
// todo
// Technician vehicle = new Technician(engineer.getId(), engineer.getEngineerCode(),
// engineer.getMaxNum(), engineer.getMaxMinute(), engineer.getMaxDistance() * 1000, depot,
// 60 * 8, 60 * 18, Set.copyOf(skillList), ? );
// technicianList.add(vehicle);
});
// customerlist
ArrayList
<
Customer
>
customerList
=
new
ArrayList
<>();
dispatchOrderRepo
.
findByGroupIdAndBatchNo
(
groupId
,
batchNo
).
forEach
(
order
->
{
Location
location
=
new
Location
(
order
.
getId
(),
order
.
getOrderId
(),
"工单"
,
Double
.
parseDouble
(
order
.
getX
()),
Double
.
parseDouble
(
order
.
getY
()));
LocalDateTime
ldt1
=
dateToLocalDateTime
(
order
.
getExpectTimeBegin
());
LocalDateTime
ldt2
=
dateToLocalDateTime
(
order
.
getExpectTimeEnd
());
int
start
=
60
*
8
;
int
end
=
60
*
18
;
if
(
ldt1
!=
null
)
{
start
=
ldt1
.
getMinute
();
}
if
(
ldt2
!=
null
)
{
end
=
ldt2
.
getMinute
();
}
Customer
customer
=
new
Customer
(
order
.
getId
(),
order
.
getOrderId
(),
location
,
start
,
end
,
order
.
getSkills
(),
order
.
getTakeTime
());
customerList
.
add
(
customer
);
});
//locationlist
List
<
Location
>
locationList
=
Stream
.
concat
(
depotList
.
stream
().
map
(
Depot:
:
getLocation
),
customerList
.
stream
().
map
(
Customer:
:
getLocation
)).
collect
(
Collectors
.
toList
());
DispatchSolution
solution
=
new
DispatchSolution
(
groupId
,
batchNo
,
locationList
,
oneDepot
,
technicianList
,
customerList
);
distanceCalculator
.
initDistanceMaps
(
locationList
);
log
.
info
(
"组织问题对象, groupId:{}, batchNo:{}, technician-size:{}, customer-size:{}, location-size:{}"
,
groupId
,
batchNo
,
technicianList
.
size
(),
customerList
.
size
(),
locationList
.
size
());
return
solution
;
}
/*
* 按小组、批次号组装问题对象
* 调用optaplaner计算输出结果
* */
@Override
public
DispatchSolution
prepareAndSolveSolution
(
String
groupId
,
String
batchNo
)
{
log
.
info
(
"组织问题对象/调用引擎处理, groupId:{}, batchNo:{}"
,
groupId
,
batchNo
);
// Load the problem
DispatchSolution
problem
=
prepareSolution
(
groupId
,
batchNo
);
SolverConfig
solverConfig
=
new
SolverConfig
().
withSolutionClass
(
DispatchSolution
.
class
);
solverConfig
.
withEntityClassList
(
Arrays
.
asList
(
Technician
.
class
,
Customer
.
class
));
// 这里不能漏掉,否则约束不生效
solverConfig
.
withConstraintProviderClass
(
DispatchConstraintProvider
.
class
);
solverConfig
.
withTerminationSpentLimit
(
Duration
.
ofSeconds
(
10
));
SolverFactory
<
DispatchSolution
>
solverFactory
=
SolverFactory
.
create
(
solverConfig
);
// Solve the problem
log
.
info
(
"调用引擎处理-开始, groupId:{}, batchNo:{}"
,
groupId
,
batchNo
);
Solver
<
DispatchSolution
>
solver
=
solverFactory
.
buildSolver
();
DispatchSolution
solution
=
solver
.
solve
(
problem
);
log
.
info
(
"调用引擎处理-结束, groupId:{}, batchNo:{}, score:{}"
,
groupId
,
batchNo
,
solution
.
getScore
());
return
solution
;
}
/**
* @param groupId
* @param batchNo
* @return
*/
@Override
public
UUID
generateProblemId
(
String
groupId
,
String
batchNo
)
{
String
md5
=
SecureUtil
.
md5
(
groupId
+
"_"
+
batchNo
);
UUID
uid
=
UUID
.
nameUUIDFromBytes
(
md5
.
getBytes
());
log
.
info
(
"------uuid: {}----"
,
uid
.
toString
());
return
uid
;
}
}
Write
Preview
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment