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 e63273c7
authored
Oct 07, 2023
by
huangjinxin
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/develop' into develop
2 parents
caa47486
5eb60d24
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
280 additions
and
73 deletions
project-dispatch/src/main/java/com/dituhui/pea/dispatch/common/GeoDistanceCalculator.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/constraint/ConstraintNameEnum.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/constraint/DispatchConstraintProvider.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/dao/DispatchOrderRepository.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/dao/OrderInfoRepository.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/scheduler/BatchScheduler.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/SolveServiceImpl.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/utils/DataUtils.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/utils/DispatchSolutionUtils.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/utils/RoadDistanceUtils.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/common/GeoDistanceCalculator.java
View file @
e63273c
package
com
.
dituhui
.
pea
.
dispatch
.
common
;
package
com
.
dituhui
.
pea
.
dispatch
.
common
;
import
com.dituhui.pea.dispatch.pojo.Location
;
import
com.dituhui.pea.dispatch.pojo.Location
;
import
com.dituhui.pea.dispatch.utils.RoadDistanceUtils
;
import
com.dituhui.pea.dispatch.utils.RoadDistanceUtils.Distance
;
import
org.gavaghan.geodesy.Ellipsoid
;
import
org.gavaghan.geodesy.Ellipsoid
;
import
org.gavaghan.geodesy.GeodeticCalculator
;
import
org.gavaghan.geodesy.GeodeticCalculator
;
import
org.gavaghan.geodesy.GeodeticCurve
;
import
org.gavaghan.geodesy.GeodeticCurve
;
...
@@ -62,9 +65,10 @@ public class GeoDistanceCalculator {
...
@@ -62,9 +65,10 @@ public class GeoDistanceCalculator {
from
->
toLocations
.
stream
().
collect
(
Collectors
.
toMap
(
from
->
toLocations
.
stream
().
collect
(
Collectors
.
toMap
(
Function
.
identity
(),
Function
.
identity
(),
to
->
{
to
->
{
long
distance
=
calculateDistance
(
from
,
to
);
Distance
distance
=
RoadDistanceUtils
.
getDistance
(
from
,
to
);
long
duration
=
Math
.
round
(
distance
/
avgRate
);
long
path
=
(
long
)
distance
.
getDis
();
return
new
Pair
(
distance
,
duration
);
long
time
=
distance
.
getTime
();
return
new
Pair
(
path
,
time
);
}
}
))
))
));
));
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/constraint/ConstraintNameEnum.java
View file @
e63273c
...
@@ -14,10 +14,18 @@ public enum ConstraintNameEnum {
...
@@ -14,10 +14,18 @@ public enum ConstraintNameEnum {
*/
*/
skillMatch
,
skillMatch
,
/**
/**
*
技术员
到达时间跟时间窗吻合
*
订单
到达时间跟时间窗吻合
*/
*/
customerTimeWindowsMatch
,
customerTimeWindowsMatch
,
/**
/**
* 技术员不加班
*/
technicianTimeWindowsMatch
,
/**
* 技术员订单数量不超过最大值
*/
technicianCapacityMatch
,
/**
* 已分配匹配
* 已分配匹配
*/
*/
dispatchedMatch
,
dispatchedMatch
,
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/constraint/DispatchConstraintProvider.java
View file @
e63273c
...
@@ -19,6 +19,8 @@ public class DispatchConstraintProvider implements ConstraintProvider {
...
@@ -19,6 +19,8 @@ public class DispatchConstraintProvider implements ConstraintProvider {
// 5s/60s: 技能权重4-技能匹配问题0个,时间窗问题14个
// 5s/60s: 技能权重4-技能匹配问题0个,时间窗问题14个
// 10s/300s: 技能权重4-技能匹配问题0个,时间窗问题9个
// 10s/300s: 技能权重4-技能匹配问题0个,时间窗问题9个
customerTimeWindowsMatch
(
factory
),
customerTimeWindowsMatch
(
factory
),
technicianTimeWindowsMatch
(
factory
),
technicianCapacityMatch
(
factory
),
skillMatch
(
factory
),
skillMatch
(
factory
),
dispatchedMatch
(
factory
),
dispatchedMatch
(
factory
),
...
@@ -50,6 +52,22 @@ public class DispatchConstraintProvider implements ConstraintProvider {
...
@@ -50,6 +52,22 @@ public class DispatchConstraintProvider implements ConstraintProvider {
.
asConstraint
(
ConstraintNameEnum
.
customerTimeWindowsMatch
.
name
());
.
asConstraint
(
ConstraintNameEnum
.
customerTimeWindowsMatch
.
name
());
}
}
protected
Constraint
technicianTimeWindowsMatch
(
ConstraintFactory
factory
)
{
return
factory
.
forEach
(
Technician
.
class
).
filter
(
// EndTime ==0 表示不起作用
technician
->
technician
.
getEndTime
()
>
0
&&
technician
.
getOffWorkTime
()
>
technician
.
getEndTime
())
.
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
technician
->
1
)
.
asConstraint
(
ConstraintNameEnum
.
technicianTimeWindowsMatch
.
name
());
}
protected
Constraint
technicianCapacityMatch
(
ConstraintFactory
factory
)
{
return
factory
.
forEach
(
Technician
.
class
).
filter
(
// MaxCount ==0 表示不起作用
technician
->
technician
.
getMaxCount
()
>
0
&&
technician
.
getCustomerSize
()
>
technician
.
getMaxCount
())
.
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
technician
->
1
)
.
asConstraint
(
ConstraintNameEnum
.
technicianCapacityMatch
.
name
());
}
protected
Constraint
dispatchedMatch
(
ConstraintFactory
factory
)
{
protected
Constraint
dispatchedMatch
(
ConstraintFactory
factory
)
{
return
factory
.
forEach
(
Customer
.
class
)
return
factory
.
forEach
(
Customer
.
class
)
.
filter
(
customer
->
customer
.
getDispatchedTechnicianCode
()
!=
null
.
filter
(
customer
->
customer
.
getDispatchedTechnicianCode
()
!=
null
...
@@ -120,7 +138,7 @@ public class DispatchConstraintProvider implements ConstraintProvider {
...
@@ -120,7 +138,7 @@ public class DispatchConstraintProvider implements ConstraintProvider {
protected
Constraint
technicianBalanceSoft
(
ConstraintFactory
factory
)
{
protected
Constraint
technicianBalanceSoft
(
ConstraintFactory
factory
)
{
return
factory
.
forEachUniquePair
(
Technician
.
class
).
penalizeLong
(
HardSoftLongScore
.
ONE_SOFT
,
return
factory
.
forEachUniquePair
(
Technician
.
class
).
penalizeLong
(
HardSoftLongScore
.
ONE_SOFT
,
// 权重需要调节,差距一个相当于多一公里 FIXME 这里应该是时长均衡,不是订单量均衡
// 权重需要调节,差距一个相当于多一公里 FIXME 这里应该是时长均衡,不是订单量均衡
(
a
,
b
)
->
Math
.
abs
(
a
.
getCustomerSize
()
-
b
.
getCustomerSize
())
*
1
000
)
(
a
,
b
)
->
Math
.
abs
(
a
.
getCustomerSize
()
-
b
.
getCustomerSize
())
*
4
000
)
.
asConstraint
(
ConstraintNameEnum
.
technicianBalanceSoft
.
name
());
.
asConstraint
(
ConstraintNameEnum
.
technicianBalanceSoft
.
name
());
}
}
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/dao/DispatchOrderRepository.java
View file @
e63273c
...
@@ -14,6 +14,9 @@ public interface DispatchOrderRepository extends CrudRepository<DispatchOrder, L
...
@@ -14,6 +14,9 @@ public interface DispatchOrderRepository extends CrudRepository<DispatchOrder, L
@Query
(
"from DispatchOrder where groupId=?1 and batchNo=?2 and status !='CONFIRM' and (engineerCode is null or engineerCode='' ) "
)
@Query
(
"from DispatchOrder where groupId=?1 and batchNo=?2 and status !='CONFIRM' and (engineerCode is null or engineerCode='' ) "
)
List
<
DispatchOrder
>
findNotAssigned
(
String
groupId
,
String
batchNo
);
List
<
DispatchOrder
>
findNotAssigned
(
String
groupId
,
String
batchNo
);
// 查看未指派非confirm的,供算法计算
@Query
(
"from DispatchOrder where groupId=?1 and batchNo=?2"
)
List
<
DispatchOrder
>
findAll
(
String
groupId
,
String
batchNo
);
// 查看算法指派成功(也有抹掉技术员、时间情况),非confirm状态的
// 查看算法指派成功(也有抹掉技术员、时间情况),非confirm状态的
@Query
(
"from DispatchOrder where groupId=?1 and batchNo=?2 and status !='CONFIRM' "
)
@Query
(
"from DispatchOrder where groupId=?1 and batchNo=?2 and status !='CONFIRM' "
)
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/dao/OrderInfoRepository.java
View file @
e63273c
...
@@ -5,6 +5,7 @@ import org.springframework.data.jpa.repository.Query;
...
@@ -5,6 +5,7 @@ import org.springframework.data.jpa.repository.Query;
import
org.springframework.data.repository.CrudRepository
;
import
org.springframework.data.repository.CrudRepository
;
import
java.time.LocalDate
;
import
java.time.LocalDate
;
import
java.util.List
;
import
java.util.Optional
;
import
java.util.Optional
;
...
@@ -14,4 +15,8 @@ public interface OrderInfoRepository extends CrudRepository<OrderInfo, Long> {
...
@@ -14,4 +15,8 @@ public interface OrderInfoRepository extends CrudRepository<OrderInfo, Long> {
Optional
<
OrderInfo
>
findOrderInfoByOrderIdAndDt
(
String
orderId
,
LocalDate
dt
);
Optional
<
OrderInfo
>
findOrderInfoByOrderIdAndDt
(
String
orderId
,
LocalDate
dt
);
List
<
OrderInfo
>
findByOrderId
(
String
orderId
);
List
<
OrderInfo
>
findByOrgTeamIdAndDt
(
String
teamId
,
LocalDate
dt
);
}
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/scheduler/BatchScheduler.java
View file @
e63273c
package
com
.
dituhui
.
pea
.
dispatch
.
scheduler
;
package
com
.
dituhui
.
pea
.
dispatch
.
scheduler
;
import
com.dituhui.pea.dispatch.constraint.DispatchConstraintProvider
;
import
java.io.File
;
import
com.dituhui.pea.dispatch.entity.DispatchBatch
;
import
java.time.LocalDate
;
import
com.dituhui.pea.dispatch.pojo.Customer
;
import
java.time.format.DateTimeFormatter
;
import
com.dituhui.pea.dispatch.pojo.DispatchSolution
;
import
java.util.UUID
;
import
com.dituhui.pea.dispatch.pojo.Technician
;
import
com.dituhui.pea.dispatch.service.BatchService
;
import
com.dituhui.pea.dispatch.service.ExtractService
;
import
com.dituhui.pea.dispatch.service.SolveService
;
import
com.dituhui.pea.dispatch.utils.DispatchSolutionUtils
;
import
lombok.extern.slf4j.Slf4j
;
import
org.optaplanner.core.api.solver.Solver
;
import
org.optaplanner.core.api.solver.Solver
;
import
org.optaplanner.core.api.solver.SolverFactory
;
import
org.optaplanner.core.impl.solver.DefaultSolverFactory
;
import
org.optaplanner.core.config.solver.SolverConfig
;
import
org.optaplanner.persistence.jackson.impl.domain.solution.JacksonSolutionFileIO
;
import
org.optaplanner.persistence.jackson.impl.domain.solution.JacksonSolutionFileIO
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.stereotype.Component
;
import
org.springframework.scheduling.annotation.Scheduled
;
import
org.springframework.scheduling.annotation.Scheduled
;
import
org.springframework.stereotype.Component
;
import
java.io.File
;
import
com.dituhui.pea.dispatch.pojo.DispatchSolution
;
import
java.time.Duration
;
import
com.dituhui.pea.dispatch.service.BatchService
;
import
java.time.LocalDate
;
import
com.dituhui.pea.dispatch.service.ExtractService
;
import
java.time.LocalDateTime
;
import
com.dituhui.pea.dispatch.service.SolveService
;
import
java.time.LocalTime
;
import
com.dituhui.pea.dispatch.utils.DispatchSolutionUtils
;
import
java.time.format.DateTimeFormatter
;
import
java.util.Arrays
;
import
lombok.extern.slf4j.Slf4j
;
import
java.util.UUID
;
@Slf4j
@Slf4j
@Component
@Component
...
@@ -49,17 +41,11 @@ public class BatchScheduler {
...
@@ -49,17 +41,11 @@ public class BatchScheduler {
@Autowired
@Autowired
ExtractService
extractService
;
ExtractService
extractService
;
private
SolverFactory
<
DispatchSolution
>
solverFactory
;
private
Default
SolverFactory
<
DispatchSolution
>
solverFactory
;
private
Solver
<
DispatchSolution
>
solver
;
private
Solver
<
DispatchSolution
>
solver
;
public
BatchScheduler
()
{
public
BatchScheduler
()
{
solverFactory
=
DispatchSolutionUtils
.
getSolverFactory
(
30
,
60
*
5
);
SolverConfig
solverConfig
=
new
SolverConfig
().
withSolutionClass
(
DispatchSolution
.
class
);
solverConfig
.
withEntityClassList
(
Arrays
.
asList
(
Technician
.
class
,
Customer
.
class
));
// 这里不能漏掉,否则约束不生效
solverConfig
.
withConstraintProviderClass
(
DispatchConstraintProvider
.
class
);
solverConfig
.
withTerminationSpentLimit
(
Duration
.
ofSeconds
(
60
*
5
));
solverFactory
=
SolverFactory
.
create
(
solverConfig
);
solver
=
solverFactory
.
buildSolver
();
solver
=
solverFactory
.
buildSolver
();
}
}
...
@@ -74,8 +60,8 @@ public class BatchScheduler {
...
@@ -74,8 +60,8 @@ public class BatchScheduler {
String
currDay
=
LocalDate
.
now
().
plusDays
(
i
).
format
(
DateTimeFormatter
.
ISO_LOCAL_DATE
);
String
currDay
=
LocalDate
.
now
().
plusDays
(
i
).
format
(
DateTimeFormatter
.
ISO_LOCAL_DATE
);
log
.
info
(
"dispatchRun begin----- group:{}, day:{}"
,
groupId
,
currDay
);
log
.
info
(
"dispatchRun begin----- group:{}, day:{}"
,
groupId
,
currDay
);
LocalTime
currentTime
=
LocalTime
.
now
();
//
LocalTime currentTime = LocalTime.now();
LocalTime
cutoffTime
=
LocalTime
.
parse
(
"18:00:00"
,
DateTimeFormatter
.
ISO_LOCAL_TIME
);
//
LocalTime cutoffTime = LocalTime.parse("18:00:00", DateTimeFormatter.ISO_LOCAL_TIME);
// 明天单才有cutoff
// 明天单才有cutoff
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/impl/BatchServiceImpl.java
View file @
e63273c
package
com
.
dituhui
.
pea
.
dispatch
.
service
.
impl
;
package
com
.
dituhui
.
pea
.
dispatch
.
service
.
impl
;
import
com.dituhui.pea.dispatch.dao.DispatchBatchRepository
;
import
java.time.LocalDateTime
;
import
com.dituhui.pea.dispatch.entity.DispatchBatch
;
import
java.time.LocalTime
;
import
com.dituhui.pea.dispatch.service.BatchService
;
import
java.time.format.DateTimeFormatter
;
import
lombok.extern.slf4j.Slf4j
;
import
java.util.Optional
;
import
javax.persistence.EntityManager
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.jdbc.core.JdbcTemplate
;
import
org.springframework.jdbc.core.JdbcTemplate
;
import
org.springframework.stereotype.Service
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.PlatformTransactionManager
;
import
org.springframework.transaction.TransactionStatus
;
import
org.springframework.transaction.annotation.Isolation
;
import
org.springframework.transaction.annotation.Isolation
;
import
org.springframework.transaction.annotation.Propagation
;
import
org.springframework.transaction.annotation.Transactional
;
import
org.springframework.transaction.annotation.Transactional
;
import
org.springframework.transaction.support.DefaultTransactionDefinition
;
import
org.springframework.transaction.support.TransactionTemplate
;
import
javax.persistence.EntityManager
;
import
com.dituhui.pea.dispatch.dao.DispatchBatchRepository
;
import
javax.sql.DataSource
;
import
com.dituhui.pea.dispatch.entity.DispatchBatch
;
import
java.sql.Connection
;
import
com.dituhui.pea.dispatch.service.BatchService
;
import
java.sql.SQLException
;
import
java.time.LocalDate
;
import
lombok.extern.slf4j.Slf4j
;
import
java.time.LocalDateTime
;
import
java.time.LocalTime
;
import
java.time.format.DateTimeFormatter
;
import
java.util.List
;
import
java.util.Optional
;
/**
/**
...
@@ -112,7 +105,12 @@ public class BatchServiceImpl implements BatchService {
...
@@ -112,7 +105,12 @@ public class BatchServiceImpl implements BatchService {
" and appointment_method like 'AUTO%' and a.appointment_status in ('INIT', 'PRE')\n"
+
" and appointment_method like 'AUTO%' and a.appointment_status in ('INIT', 'PRE')\n"
+
" and order_status ='NORMAL' and service_status='INIT'\n"
+
" and order_status ='NORMAL' and service_status='INIT'\n"
+
" order by a.expect_time_begin asc "
;
" order by a.expect_time_begin asc "
;
int
orderCount
=
jdbcTemplate
.
update
(
sqlOrder
,
batchNo
,
groupId
,
batchDay
);
String
tempDay
=
"2023-08-13"
;
int
orderCount
=
jdbcTemplate
.
update
(
sqlOrder
,
batchNo
,
groupId
,
/**
* FIXME 因为系统暂时没有订单,每次固定拉取2023-08-13号数据tempDay,上线后改成batchDay
*/
tempDay
);
// confirm的要做预占用,所以也加入进来
// confirm的要做预占用,所以也加入进来
String
sqlOrderConfirm
=
"INSERT INTO dispatch_order (group_id, batch_no, team_id, order_id , dt, x, y, \n"
+
String
sqlOrderConfirm
=
"INSERT INTO dispatch_order (group_id, batch_no, team_id, order_id , dt, x, y, \n"
+
...
@@ -128,7 +126,7 @@ public class BatchServiceImpl implements BatchService {
...
@@ -128,7 +126,7 @@ public class BatchServiceImpl implements BatchService {
" order by a.expect_time_begin asc "
;
" order by a.expect_time_begin asc "
;
int
orderConfirmCount
=
jdbcTemplate
.
update
(
sqlOrderConfirm
,
batchNo
,
groupId
,
batchDay
);
int
orderConfirmCount
=
jdbcTemplate
.
update
(
sqlOrderConfirm
,
batchNo
,
groupId
,
batchDay
);
log
.
info
(
"准备批次数据
orderCount:{}, orderConfirmCount:{}"
,
orderCount
,
orderConfirmCount
);
log
.
info
(
"准备批次数据
engCount:{}, orderCount:{}, orderConfirmCount:{}"
,
engCount
,
orderCount
,
orderConfirmCount
);
if
(
orderCount
+
orderConfirmCount
>
0
)
{
if
(
orderCount
+
orderConfirmCount
>
0
)
{
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/impl/SolveServiceImpl.java
View file @
e63273c
...
@@ -12,6 +12,8 @@ import com.dituhui.pea.dispatch.pojo.*;
...
@@ -12,6 +12,8 @@ import com.dituhui.pea.dispatch.pojo.*;
import
com.dituhui.pea.dispatch.service.ExtractService
;
import
com.dituhui.pea.dispatch.service.ExtractService
;
import
com.dituhui.pea.dispatch.service.SolveService
;
import
com.dituhui.pea.dispatch.service.SolveService
;
import
com.dituhui.pea.dispatch.utils.DispatchSolutionUtils
;
import
com.dituhui.pea.dispatch.utils.DispatchSolutionUtils
;
import
com.google.common.collect.Lists
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
import
org.optaplanner.core.api.solver.Solver
;
import
org.optaplanner.core.api.solver.Solver
;
import
org.optaplanner.core.api.solver.SolverFactory
;
import
org.optaplanner.core.api.solver.SolverFactory
;
...
@@ -98,7 +100,9 @@ public class SolveServiceImpl implements SolveService {
...
@@ -98,7 +100,9 @@ public class SolveServiceImpl implements SolveService {
// customerlist
// customerlist
ArrayList
<
Customer
>
customerList
=
new
ArrayList
<>();
ArrayList
<
Customer
>
customerList
=
new
ArrayList
<>();
List
<
DispatchOrder
>
dispatchOrderList
=
dispatchOrderRepo
.
findNotAssigned
(
groupId
,
batchNo
);
// 已分配和未分配一起排班,因为已分配会影响整体排班结果
List
<
DispatchOrder
>
dispatchOrderList
=
dispatchOrderRepo
.
findAll
(
groupId
,
batchNo
);
// List<DispatchOrder> dispatchOrderList = dispatchOrderRepo.findNotAssigned(groupId, batchNo);
log
.
info
(
"组织问题对象, dispatchorder-list, groupId:{}, batchNo:{}, dispatchorder-size:{}"
,
groupId
,
batchNo
,
dispatchOrderList
.
size
());
log
.
info
(
"组织问题对象, dispatchorder-list, groupId:{}, batchNo:{}, dispatchorder-size:{}"
,
groupId
,
batchNo
,
dispatchOrderList
.
size
());
...
@@ -121,7 +125,7 @@ public class SolveServiceImpl implements SolveService {
...
@@ -121,7 +125,7 @@ public class SolveServiceImpl implements SolveService {
}
}
// 40分钟兜低(技能未能正确匹配原因)
// 40分钟兜低(技能未能正确匹配原因)
FIXME 需要跟客户沟通
if
(
null
==
order
.
getTakeTime
())
{
if
(
null
==
order
.
getTakeTime
())
{
order
.
setTakeTime
(
40
);
order
.
setTakeTime
(
40
);
}
}
...
@@ -139,14 +143,12 @@ public class SolveServiceImpl implements SolveService {
...
@@ -139,14 +143,12 @@ public class SolveServiceImpl implements SolveService {
log
.
info
(
"组织问题对象, customer-list, groupId:{}, batchNo:{}, customer-list:{}"
,
groupId
,
batchNo
,
customerList
.
size
());
log
.
info
(
"组织问题对象, customer-list, groupId:{}, batchNo:{}, customer-list:{}"
,
groupId
,
batchNo
,
customerList
.
size
());
// depotlist 技术员中收点列表
ArrayList
<
Depot
>
depotList
=
new
ArrayList
<
Depot
>();
// technicianList
// technicianList
ArrayList
<
Technician
>
technicianList
=
new
ArrayList
<>();
ArrayList
<
Technician
>
technicianList
=
new
ArrayList
<>();
dispatchEngineerRepo
.
findByGroupIdAndBatchNo
(
groupId
,
batchNo
).
forEach
(
engineer
->
{
dispatchEngineerRepo
.
findByGroupIdAndBatchNo
(
groupId
,
batchNo
).
forEach
(
engineer
->
{
Location
location
=
new
Location
(
engineer
.
getId
(),
engineer
.
getEngineerCode
(),
"中心点"
,
Double
.
parseDouble
(
engineer
.
getX
()),
Double
.
parseDouble
(
engineer
.
getY
()));
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
);
//
Depot depot = new Depot(engineer.getId(), engineer.getEngineerCode(), location, 60 * 8, 60 * 18);
depotList
.
add
(
depot
);
//
depotList.add(depot);
// log.debug("组织问题对象, technicianList groupId:{}, batchNo:{}, engineer-code:{}", groupId, batchNo, engineer.getEngineerCode());
// log.debug("组织问题对象, technicianList groupId:{}, batchNo:{}, engineer-code:{}", groupId, batchNo, engineer.getEngineerCode());
List
<
String
>
skillList
=
queryEngineerSkills
(
engineer
.
getEngineerCode
());
List
<
String
>
skillList
=
queryEngineerSkills
(
engineer
.
getEngineerCode
());
...
@@ -160,20 +162,24 @@ public class SolveServiceImpl implements SolveService {
...
@@ -160,20 +162,24 @@ public class SolveServiceImpl implements SolveService {
preferedLoctionDistanceMap
.
put
(
customer
.
getCode
(),
distance
);
preferedLoctionDistanceMap
.
put
(
customer
.
getCode
(),
distance
);
});
});
Technician
vehicle
=
new
Technician
(
engineer
.
getId
(),
engineer
.
getEngineerCode
(),
engineer
.
getMaxNum
(),
engineer
.
getMaxMinute
(),
engineer
.
getMaxDistance
()
*
1000
,
d
epot
,
60
*
8
,
60
*
18
,
Set
.
copyOf
(
skillList
),
preferedLoctionDistanceMap
);
Technician
vehicle
=
new
Technician
(
engineer
.
getId
(),
engineer
.
getEngineerCode
(),
engineer
.
getMaxNum
(),
engineer
.
getMaxMinute
(),
engineer
.
getMaxDistance
()
*
1000
,
oneD
epot
,
60
*
8
,
60
*
18
,
Set
.
copyOf
(
skillList
),
preferedLoctionDistanceMap
);
technicianList
.
add
(
vehicle
);
technicianList
.
add
(
vehicle
);
});
});
log
.
info
(
"组织问题对象, depotList-list, groupId:{}, batchNo:{}
, depotList-list:{}"
,
groupId
,
batchNo
,
depotList
.
size
()
);
log
.
info
(
"组织问题对象, depotList-list, groupId:{}, batchNo:{}
"
,
groupId
,
batchNo
);
log
.
info
(
"组织问题对象, technician-list, groupId:{}, batchNo:{}, technician-list:{}"
,
groupId
,
batchNo
,
technicianList
.
size
());
log
.
info
(
"组织问题对象, technician-list, groupId:{}, batchNo:{}, technician-list:{}"
,
groupId
,
batchNo
,
technicianList
.
size
());
//
locationlist
//
locationlist 起点+订单地点
List
<
Location
>
locationList
=
Stream
.
concat
(
depotList
.
stream
().
map
(
Depot:
:
getLocation
),
customerList
.
stream
().
map
(
Customer:
:
getLocation
)).
collect
(
Collectors
.
toList
());
List
<
Location
>
locationList
=
Stream
.
concat
(
Lists
.
newArrayList
(
oneDepot
)
.
stream
().
map
(
Depot:
:
getLocation
),
customerList
.
stream
().
map
(
Customer:
:
getLocation
)).
collect
(
Collectors
.
toList
());
DispatchSolution
solution
=
new
DispatchSolution
(
groupId
,
batchNo
,
locationList
,
oneDepot
,
technicianList
,
customerList
);
DispatchSolution
solution
=
new
DispatchSolution
(
groupId
,
batchNo
,
locationList
,
oneDepot
,
technicianList
,
customerList
);
// path 路网数据初始化,FIXME 需要专门路网数据缓存库
long
time1
=
System
.
currentTimeMillis
();
distanceCalculator
.
initDistanceMaps
(
locationList
);
distanceCalculator
.
initDistanceMaps
(
locationList
);
long
time2
=
System
.
currentTimeMillis
();
log
.
info
(
"组织问题对象 done, groupId:{}, batchNo:{}, technician-size:{}, customer-size:{}, location-size:{}
"
,
groupId
,
batchNo
,
technicianList
.
size
(),
customerList
.
size
(),
locationList
.
size
()
);
log
.
info
(
"组织问题对象 done, groupId:{}, batchNo:{}, technician-size:{}, customer-size:{}, location-size:{}
, 路网耗时path:{}ms"
,
groupId
,
batchNo
,
technicianList
.
size
(),
customerList
.
size
(),
locationList
.
size
(),
time2
-
time1
);
return
solution
;
return
solution
;
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/utils/DataUtils.java
View file @
e63273c
...
@@ -44,7 +44,31 @@ public class DataUtils {
...
@@ -44,7 +44,31 @@ public class DataUtils {
Map
<
String
,
Integer
>
customerCodeServiceTimeMap
=
loadCustomerCodeServiceTimeMap
();
Map
<
String
,
Integer
>
customerCodeServiceTimeMap
=
loadCustomerCodeServiceTimeMap
();
DispatchSolution
problem
=
createVehicleRoutingSolution
(
customerIndexMap
,
customerIndexXyMap
,
DispatchSolution
problem
=
createVehicleRoutingSolution
(
customerIndexMap
,
customerIndexXyMap
,
technicianIndexMap
,
technicianCodeSkillsMap
,
customerCodeSkillMap
,
technicianCodePreferredLocationMap
,
technicianIndexMap
,
technicianCodeSkillsMap
,
customerCodeSkillMap
,
technicianCodePreferredLocationMap
,
preferredlocationDistanceMap
,
customerCodeServiceTimeMap
);
preferredlocationDistanceMap
,
customerCodeServiceTimeMap
,
false
);
return
problem
;
}
/**
* 获取初始化测试数据
* fullDay 是否全天派工
* @return
* @throws UncheckedIOException
* @throws FileNotFoundException
*/
public
static
DispatchSolution
getInitialProblem
(
boolean
fullDay
)
throws
UncheckedIOException
,
FileNotFoundException
{
Map
<
Integer
,
String
>
customerIndexMap
=
loadCustomerIndex
();
Map
<
Integer
,
String
>
customerIndexXyMap
=
loadCustomerIndexXY
();
Map
<
Integer
,
String
>
technicianIndexMap
=
loadTechnicianIndex
();
Map
<
String
,
Set
<
String
>>
technicianCodeSkillsMap
=
loadTechnicianCodeSkillsMap
();
Map
<
String
,
String
>
customerCodeSkillMap
=
loadCustomerCodeSkillMap
();
// 偏好中心点位置
Map
<
String
,
String
>
technicianCodePreferredLocationMap
=
loadPreferredlocationMap
();
Map
<
String
,
Map
<
String
,
Long
>>
preferredlocationDistanceMap
=
loadPreferredlocationDistanceMap
(
technicianCodePreferredLocationMap
);
Map
<
String
,
Integer
>
customerCodeServiceTimeMap
=
loadCustomerCodeServiceTimeMap
();
DispatchSolution
problem
=
createVehicleRoutingSolution
(
customerIndexMap
,
customerIndexXyMap
,
technicianIndexMap
,
technicianCodeSkillsMap
,
customerCodeSkillMap
,
technicianCodePreferredLocationMap
,
preferredlocationDistanceMap
,
customerCodeServiceTimeMap
,
fullDay
);
return
problem
;
return
problem
;
}
}
...
@@ -189,7 +213,7 @@ public class DataUtils {
...
@@ -189,7 +213,7 @@ public class DataUtils {
Map
<
String
,
Set
<
String
>>
technicianCodeSkillsMap
,
Map
<
String
,
String
>
customerCodeSkillMap
,
Map
<
String
,
Set
<
String
>>
technicianCodeSkillsMap
,
Map
<
String
,
String
>
customerCodeSkillMap
,
Map
<
String
,
String
>
technicianCodePreferredLocationMap
,
Map
<
String
,
String
>
technicianCodePreferredLocationMap
,
Map
<
String
,
Map
<
String
,
Long
>>
preferredlocationDistanceMap
,
Map
<
String
,
Map
<
String
,
Long
>>
preferredlocationDistanceMap
,
Map
<
String
,
Integer
>
customerCodeServiceTimeMap
)
throws
UncheckedIOException
,
FileNotFoundException
{
Map
<
String
,
Integer
>
customerCodeServiceTimeMap
,
boolean
fullDay
)
throws
UncheckedIOException
,
FileNotFoundException
{
DispatchSolution
vehicleRoutingSolution
=
new
DispatchSolution
();
DispatchSolution
vehicleRoutingSolution
=
new
DispatchSolution
();
// 翻转map
// 翻转map
...
@@ -290,7 +314,7 @@ public class DataUtils {
...
@@ -290,7 +314,7 @@ public class DataUtils {
String
[]
temps
=
xyString
.
split
(
","
);
String
[]
temps
=
xyString
.
split
(
","
);
Location
preferredlocation
=
new
Location
(
i
+
1
,
Float
.
parseFloat
(
RegExUtils
.
removeAll
(
temps
[
0
],
"\""
)),
Location
preferredlocation
=
new
Location
(
i
+
1
,
Float
.
parseFloat
(
RegExUtils
.
removeAll
(
temps
[
0
],
"\""
)),
Float
.
parseFloat
(
RegExUtils
.
removeAll
(
temps
[
1
],
"\""
)));
Float
.
parseFloat
(
RegExUtils
.
removeAll
(
temps
[
1
],
"\""
)));
technicianList
.
add
(
new
Technician
(
i
+
1
,
technicianIndexMap
.
get
(
i
+
1
),
depot
,
480
,
1080
,
skills
,
technicianList
.
add
(
new
Technician
(
i
+
1
,
technicianIndexMap
.
get
(
i
+
1
),
depot
,
480
,
fullDay
?
1440
:
1080
,
skills
,
preferredlocationDistanceMap
.
get
(
technicianIndexMap
.
get
(
i
+
1
)),
preferredlocation
));
preferredlocationDistanceMap
.
get
(
technicianIndexMap
.
get
(
i
+
1
)),
preferredlocation
));
}
}
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/utils/DispatchSolutionUtils.java
View file @
e63273c
...
@@ -140,9 +140,11 @@ public class DispatchSolutionUtils {
...
@@ -140,9 +140,11 @@ public class DispatchSolutionUtils {
// 技术员路线
// 技术员路线
String
lines_
=
"["
;
String
lines_
=
"["
;
for
(
Technician
technician
:
solution
.
getTechnicianList
())
{
for
(
Technician
technician
:
solution
.
getTechnicianList
())
{
if
(
technician
.
getCustomerList
().
size
()
>
0
)
{
lines_
+=
"\""
+
technician
.
getCustomerList
().
stream
()
lines_
+=
"\""
+
technician
.
getCustomerList
().
stream
()
.
map
(
c
->
c
.
getLocation
().
getX
()
+
","
+
c
.
getLocation
().
getY
()).
reduce
((
a
,
b
)
->
a
+
";"
+
b
)
.
map
(
c
->
c
.
getLocation
().
getX
()
+
","
+
c
.
getLocation
().
getY
())
.
get
()
+
"\","
;
.
reduce
((
a
,
b
)
->
a
+
";"
+
b
).
get
()
+
"\","
;
}
}
}
lines_
+=
"]"
;
lines_
+=
"]"
;
final
String
lines
=
lines_
;
final
String
lines
=
lines_
;
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/utils/RoadDistanceUtils.java
0 → 100644
View file @
e63273c
package
com
.
dituhui
.
pea
.
dispatch
.
utils
;
import
java.io.BufferedReader
;
import
java.io.InputStreamReader
;
import
java.net.HttpURLConnection
;
import
java.net.URL
;
import
java.net.URLConnection
;
import
java.net.URLEncoder
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
com.dituhui.pea.dispatch.pojo.Location
;
import
com.google.common.collect.Maps
;
import
com.google.gson.Gson
;
import
lombok.Data
;
/**
* 路网组件<br>
* TODO 需要做成分布式缓存模式,这里会造成内存问题<br>
* TODO 调用方式需要改成批量调用方式
*
* @author gpzhang
*
*/
public
class
RoadDistanceUtils
{
public
static
String
URL
=
"https://api.map.baidu.com/routematrix/v2/riding?"
;
public
static
String
AK
=
"doR30pE7R0I7ivGLwMpkpsTT4bos9Akg"
;
/**
* 格式 x1,y1;x2,y2
*/
private
static
Map
<
String
,
Distance
>
distanceCache
=
Maps
.
newHashMap
();
private
static
Gson
gson
=
new
Gson
();
/**
* 获取路网距离和时间<br>
* TODO 需要做成分布式缓存模式,这里会造成内存问题<br>
* TODO 调用方式需要改成批量调用方式
*
* @param from
* @param to
* @return
*/
public
static
Distance
getDistance
(
Location
from
,
Location
to
)
{
try
{
String
key
=
from
.
getLongitude
()
+
","
+
from
.
getLatitude
()
+
";"
+
to
.
getLongitude
()
+
","
+
to
.
getLatitude
();
Distance
distance
=
distanceCache
.
get
(
key
);
if
(
null
==
distance
)
{
distance
=
getDistance
(
from
.
getLatitude
()
+
","
+
from
.
getLongitude
(),
to
.
getLatitude
()
+
","
+
to
.
getLongitude
());
if
(
null
==
distance
)
{
Distance
dis
=
new
Distance
();
return
dis
;
}
else
{
distanceCache
.
put
(
key
,
distance
);
}
return
distance
;
}
else
{
return
distance
;
}
}
catch
(
Exception
e
)
{
Distance
dis
=
new
Distance
();
return
dis
;
}
}
private
static
Distance
getDistance
(
String
yx1
,
String
yx2
)
throws
Exception
{
Map
<
String
,
String
>
params
=
new
HashMap
<
String
,
String
>();
params
.
put
(
"origins"
,
yx1
);
params
.
put
(
"destinations"
,
yx2
);
params
.
put
(
"ak"
,
AK
);
params
.
put
(
"riding_type"
,
"1"
);
// 电动自行车
params
.
put
(
"coord_type"
,
"gcj02"
);
String
text
=
requestGetAK
(
URL
,
params
);
BDResult
webResult
=
gson
.
fromJson
(
text
,
BDResult
.
class
);
float
dis
=
webResult
.
getResult
().
get
(
0
).
getDistance
().
getValue
()
/
1000
F
;
int
time
=
webResult
.
getResult
().
get
(
0
).
getDuration
().
getValue
();
Distance
d
=
new
Distance
();
d
.
setDis
(
dis
);
d
.
setTime
(
time
);
return
d
;
}
/**
* 默认ak 选择了ak,使用IP白名单校验: 根据您选择的AK已为您生成调用代码 检测到您当前的ak设置了IP白名单校验
* 您的IP白名单中的IP非公网IP,请设置为公网IP,否则将请求失败 请在IP地址为xxxxxxx的计算发起请求,否则将请求失败
*/
public
static
String
requestGetAK
(
String
strUrl
,
Map
<
String
,
String
>
param
)
throws
Exception
{
if
(
strUrl
==
null
||
strUrl
.
length
()
<=
0
||
param
==
null
||
param
.
size
()
<=
0
)
{
return
""
;
}
StringBuffer
queryString
=
new
StringBuffer
();
queryString
.
append
(
strUrl
);
for
(
Map
.
Entry
<?,
?>
pair
:
param
.
entrySet
())
{
queryString
.
append
(
pair
.
getKey
()
+
"="
);
// 第一种方式使用的 jdk 自带的转码方式 第二种方式使用的 spring 的转码方法 两种均可
queryString
.
append
(
URLEncoder
.
encode
((
String
)
pair
.
getValue
(),
"UTF-8"
).
replace
(
"+"
,
"%20"
)
+
"&"
);
}
if
(
queryString
.
length
()
>
0
)
{
queryString
.
deleteCharAt
(
queryString
.
length
()
-
1
);
}
java
.
net
.
URL
url
=
new
URL
(
queryString
.
toString
());
URLConnection
httpConnection
=
(
HttpURLConnection
)
url
.
openConnection
();
httpConnection
.
connect
();
InputStreamReader
isr
=
new
InputStreamReader
(
httpConnection
.
getInputStream
());
BufferedReader
reader
=
new
BufferedReader
(
isr
);
StringBuffer
buffer
=
new
StringBuffer
();
String
line
;
while
((
line
=
reader
.
readLine
())
!=
null
)
{
buffer
.
append
(
line
);
}
reader
.
close
();
isr
.
close
();
return
(
buffer
.
toString
());
}
@Data
public
static
class
Distance
{
float
dis
;
int
time
;
}
@Data
static
class
BDResult
{
List
<
BDDistance
>
result
;
}
@Data
static
class
BDDistance
{
Dis
distance
;
Dur
duration
;
}
@Data
static
class
Dis
{
Float
value
;
}
@Data
static
class
Dur
{
Integer
value
;
}
}
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