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 237eeaf1
authored
Oct 30, 2023
by
huangjinxin
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/develop' into develop
2 parents
99031334
c5885899
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
295 additions
and
165 deletions
project-dispatch/src/main/java/com/dituhui/pea/dispatch/common/GeoDistanceCalculator.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/entity/DispatchEngineer.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/pojo/Customer.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/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 @
237eeaf
...
...
@@ -11,6 +11,8 @@ import org.gavaghan.geodesy.GlobalCoordinates;
import
org.springframework.stereotype.Component
;
import
java.util.Collection
;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.function.Function
;
import
java.util.stream.Collectors
;
...
...
@@ -59,13 +61,13 @@ public class GeoDistanceCalculator {
}
}
private
Map
<
Location
,
Map
<
Location
,
Pair
>>
calculateBulkDistanceDuration
(
Collection
<
Location
>
fromLocations
,
Collection
<
Location
>
toLocations
)
{
private
Map
<
Location
,
Map
<
Location
,
Pair
>>
calculateBulkDistanceDuration
(
Collection
<
Location
>
fromLocations
,
Collection
<
Location
>
toLocations
,
Integer
vehicleType
)
{
return
fromLocations
.
stream
().
collect
(
Collectors
.
toMap
(
Function
.
identity
(),
from
->
toLocations
.
stream
().
collect
(
Collectors
.
toMap
(
Function
.
identity
(),
to
->
{
Distance
distance
=
RoadDistanceUtils
.
getDistance
(
from
,
to
);
Distance
distance
=
RoadDistanceUtils
.
getDistance
(
from
,
to
,
vehicleType
);
long
path
=
(
long
)
distance
.
getDis
();
long
time
=
distance
.
getTime
();
return
new
Pair
(
path
,
time
);
...
...
@@ -74,18 +76,17 @@ public class GeoDistanceCalculator {
));
}
public
void
initDistanceMaps
(
Collection
<
Location
>
locationList
)
{
Map
<
Location
,
Map
<
Location
,
Pair
>>
distanceMatrix
=
calculateBulkDistanceDuration
(
locationList
,
locationList
);
locationList
.
forEach
(
location
->
{
Map
<
Location
,
Pair
>
mapPair
=
distanceMatrix
.
get
(
location
);
mapPair
.
forEach
((
loc2
,
pair
)
->
{
location
.
getDistanceMap
().
put
(
loc2
,
pair
.
Distance
);
location
.
getDistanceTimeMap
().
put
(
loc2
,
pair
.
Duration
);
public
void
initDistanceMaps
(
Collection
<
Location
>
locationList
,
List
<
Integer
>
vehicleTypes
)
{
for
(
Integer
vehicleType:
vehicleTypes
)
{
Map
<
Location
,
Map
<
Location
,
Pair
>>
distanceMatrix
=
calculateBulkDistanceDuration
(
locationList
,
locationList
,
vehicleType
);
locationList
.
forEach
(
location
->
{
Map
<
Location
,
Pair
>
mapPair
=
distanceMatrix
.
get
(
location
);
mapPair
.
forEach
((
loc2
,
pair
)
->
{
location
.
getDistanceMap
(
vehicleType
).
put
(
loc2
,
pair
.
Distance
);
location
.
getDistanceTimeMap
(
vehicleType
).
put
(
loc2
,
pair
.
Duration
);
});
});
});
}
}
}
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/entity/DispatchEngineer.java
View file @
237eeaf
...
...
@@ -51,6 +51,9 @@ public class DispatchEngineer implements Serializable {
@Column
(
name
=
"max_distance"
)
private
Integer
maxDistance
;
@Column
(
name
=
"vehicle_type"
)
private
Integer
vehicleType
;
private
String
ext
=
""
;
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/pojo/Customer.java
View file @
237eeaf
...
...
@@ -131,9 +131,9 @@ public class Customer {
// throw new IllegalStateException("This method must not be called when the shadow variables are not initialized yet.");
}
if
(
previousCustomer
==
null
)
{
return
technician
.
getDepot
().
getLocation
().
getDistanceTo
(
location
);
return
technician
.
getDepot
().
getLocation
().
getDistanceTo
(
technician
.
getVehicleType
(),
location
);
}
return
previousCustomer
.
getLocation
().
getDistanceTo
(
location
);
return
previousCustomer
.
getLocation
().
getDistanceTo
(
technician
.
getVehicleType
(),
location
);
}
/**
...
...
@@ -147,9 +147,9 @@ public class Customer {
// throw new IllegalStateException("This method must not be called when the shadow variables are not initialized yet.");
}
if
(
previousCustomer
==
null
)
{
return
technician
.
getDepot
().
getLocation
().
getPathTimeTo
(
location
);
return
technician
.
getDepot
().
getLocation
().
getPathTimeTo
(
technician
.
getVehicleType
(),
location
);
}
return
previousCustomer
.
getLocation
().
getPathTimeTo
(
location
);
return
previousCustomer
.
getLocation
().
getPathTimeTo
(
technician
.
getVehicleType
(),
location
);
}
@Override
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/pojo/Location.java
View file @
237eeaf
...
...
@@ -24,10 +24,26 @@ public class Location {
private
double
latitude
;
private
double
longitude
;
// 汽车路网矩阵
@JsonIgnore
private
Map
<
Location
,
Long
>
d
istanceMap
=
new
HashMap
<
Location
,
Long
>();
// 路网距离矩阵
private
Map
<
Location
,
Long
>
carD
istanceMap
=
new
HashMap
<
Location
,
Long
>();
// 路网距离矩阵
@JsonIgnore
private
Map
<
Location
,
Long
>
distanceTimeMap
=
new
HashMap
<
Location
,
Long
>();
// 路网时间矩阵
private
Map
<
Location
,
Long
>
carDistanceTimeMap
=
new
HashMap
<
Location
,
Long
>();
// 路网时间矩阵
// 电动车路网矩阵
@JsonIgnore
private
Map
<
Location
,
Long
>
electricBicycleDistanceMap
=
new
HashMap
<
Location
,
Long
>();
// 路网距离矩阵
@JsonIgnore
private
Map
<
Location
,
Long
>
electricBicycleDistanceTimeMap
=
new
HashMap
<
Location
,
Long
>();
// 路网时间矩阵
// 自行车路网矩阵
@JsonIgnore
private
Map
<
Location
,
Long
>
bicycleDistanceMap
=
new
HashMap
<
Location
,
Long
>();
// 路网距离矩阵
@JsonIgnore
private
Map
<
Location
,
Long
>
bicycleDistanceTimeMap
=
new
HashMap
<
Location
,
Long
>();
// 路网时间矩阵
// 步行路网矩阵
@JsonIgnore
private
Map
<
Location
,
Long
>
walkDistanceMap
=
new
HashMap
<
Location
,
Long
>();
// 路网距离矩阵
@JsonIgnore
private
Map
<
Location
,
Long
>
walkDistanceTimeMap
=
new
HashMap
<
Location
,
Long
>();
// 路网时间矩阵
public
Location
(
long
id
)
{
this
.
id
=
id
;
...
...
@@ -47,36 +63,101 @@ public class Location {
this
.
latitude
=
latitude
;
}
/**
* 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
* 根据不同交通方式返回不同距离
*
* @param vehicleType
* @param location
* @return
*/
public
long
getDistanceTo
(
Location
location
)
{
return
distanceMap
.
get
(
location
);
}
public
long
getDistanceTo
(
Integer
vehicleType
,
Location
location
)
{
if
(
null
==
vehicleType
)
{
return
carDistanceMap
.
get
(
location
);
}
switch
(
vehicleType
)
{
case
1
:
return
carDistanceMap
.
get
(
location
);
case
2
:
return
electricBicycleDistanceMap
.
get
(
location
);
case
3
:
return
bicycleDistanceMap
.
get
(
location
);
case
4
:
return
walkDistanceMap
.
get
(
location
);
}
return
carDistanceMap
.
get
(
location
);
}
public
Map
<
Location
,
Long
>
getDistanceMap
(
Integer
vehicleType
)
{
if
(
null
==
vehicleType
)
{
return
carDistanceMap
;
}
switch
(
vehicleType
)
{
case
1
:
return
carDistanceMap
;
case
2
:
return
electricBicycleDistanceMap
;
case
3
:
return
bicycleDistanceMap
;
case
4
:
return
walkDistanceMap
;
}
return
carDistanceMap
;
}
public
Map
<
Location
,
Long
>
getDistanceTimeMap
(
Integer
vehicleType
)
{
if
(
null
==
vehicleType
)
{
return
carDistanceTimeMap
;
}
switch
(
vehicleType
)
{
case
1
:
return
carDistanceTimeMap
;
case
2
:
return
electricBicycleDistanceTimeMap
;
case
3
:
return
bicycleDistanceTimeMap
;
case
4
:
return
walkDistanceTimeMap
;
}
return
carDistanceTimeMap
;
}
public
int
getPathTimeTo
(
Integer
vehicleType
,
Location
location
)
{
if
(
null
==
vehicleType
)
{
return
carDistanceTimeMap
.
get
(
location
).
intValue
()
/
60
;
}
switch
(
vehicleType
)
{
case
1
:
return
carDistanceTimeMap
.
get
(
location
).
intValue
()
/
60
;
case
2
:
return
electricBicycleDistanceTimeMap
.
get
(
location
).
intValue
()
/
60
;
case
3
:
return
bicycleDistanceTimeMap
.
get
(
location
).
intValue
()
/
60
;
case
4
:
return
walkDistanceTimeMap
.
get
(
location
).
intValue
()
/
60
;
}
return
carDistanceTimeMap
.
get
(
location
).
intValue
()
/
60
;
}
/**
* time to the given location in minutes.
*
* @param location other location
* @return time in minutes
*/
public
int
getPathTimeTo
(
Location
location
)
{
return
distanceTimeMap
.
get
(
location
).
intValue
()/
60
;
public
int
getCarPathTimeTo
(
Location
location
)
{
return
carDistanceTimeMap
.
get
(
location
).
intValue
()
/
60
;
}
public
int
getElectricBicyclePathTimeTo
(
Location
location
)
{
return
electricBicycleDistanceTimeMap
.
get
(
location
).
intValue
()
/
60
;
}
public
int
getBicyclePathTimeTo
(
Location
location
)
{
return
bicycleDistanceTimeMap
.
get
(
location
).
intValue
()
/
60
;
}
public
int
getWalkDathTimeTo
(
Location
location
)
{
return
walkDistanceTimeMap
.
get
(
location
).
intValue
()
/
60
;
}
// ************************************************************************
...
...
@@ -110,5 +191,4 @@ public class Location {
'}'
;
}
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/pojo/Technician.java
View file @
237eeaf
...
...
@@ -44,6 +44,9 @@ public class Technician {
// 单位是米,这里要注意
private
int
maxDistanceMeter
;
// 交通方式 1汽车;2电动车;3自行车;4步行 默认是汽车
private
Integer
vehicleType
;
@PlanningListVariable
private
List
<
Customer
>
customerList
=
new
ArrayList
<>();
...
...
@@ -76,6 +79,20 @@ public class Technician {
this
.
maxDistanceMeter
=
maxDistanceMeter
;
this
.
preferredlocationDistanceMap
=
preferredlocationDistanceMap
;
}
public
Technician
(
long
id
,
String
code
,
int
maxCount
,
int
maxMinute
,
int
maxDistanceMeter
,
Integer
vehicleType
,
Depot
depot
,
int
startTime
,
int
endTime
,
Set
<
String
>
skills
,
Map
<
String
,
Long
>
preferredlocationDistanceMap
)
{
this
.
id
=
id
;
this
.
code
=
code
;
this
.
depot
=
depot
;
this
.
startTime
=
startTime
;
this
.
endTime
=
endTime
;
this
.
skills
=
skills
;
this
.
maxCount
=
maxCount
;
this
.
maxMinute
=
maxMinute
;
this
.
maxDistanceMeter
=
maxDistanceMeter
;
this
.
preferredlocationDistanceMap
=
preferredlocationDistanceMap
;
}
// ************************************************************************
// Complex methods
...
...
@@ -114,10 +131,10 @@ public class Technician {
Location
previousLocation
=
depot
.
getLocation
();
for
(
Customer
customer
:
customerList
)
{
totalDistance
+=
previousLocation
.
getDistanceTo
(
customer
.
getLocation
());
totalDistance
+=
previousLocation
.
getDistanceTo
(
this
.
getVehicleType
(),
customer
.
getLocation
());
previousLocation
=
customer
.
getLocation
();
}
totalDistance
+=
previousLocation
.
getDistanceTo
(
depot
.
getLocation
());
totalDistance
+=
previousLocation
.
getDistanceTo
(
this
.
getVehicleType
(),
depot
.
getLocation
());
return
totalDistance
;
}
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/impl/BatchServiceImpl.java
View file @
237eeaf
...
...
@@ -210,8 +210,8 @@ public class BatchServiceImpl implements BatchService {
jdbcTemplate
.
update
(
"delete from dispatch_order where team_id=? and batch_no=?"
,
teamId
,
batchNo
);
log
.
info
(
"写入新批次技术员、工单数据, teamId:{}, day:{}, batchNo:{}"
,
teamId
,
batchDay
,
batchNo
);
String
sqlEngineer
=
"INSERT INTO dispatch_engineer (team_id, batch_no, engineer_code, engineer_name, x, y, max_num, max_minute, max_distance)\n"
+
"SELECT o.team_id,?,o.engineer_code, a.name , b.x, b.y , max_num, max_minute, max_distance FROM `org_team_engineer` o,engineer_info a,engineer_business b \r\n"
String
sqlEngineer
=
"INSERT INTO dispatch_engineer (team_id, batch_no, engineer_code, engineer_name, x, y, max_num, max_minute, max_distance
, vehicle_type
)\n"
+
"SELECT o.team_id,?,o.engineer_code, a.name , b.x, b.y , max_num, max_minute, max_distance
, b.vehicle
FROM `org_team_engineer` o,engineer_info a,engineer_business b \r\n"
+
" WHERE o.team_id=? AND `status`=1\r\n"
+
" AND o.engineer_code=a.engineer_code AND a.engineer_code = b.engineer_code \r\n"
+
" AND b.x IS NOT NULL AND b.x !=''"
+
" order by a.engineer_code asc"
;
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/impl/SolveServiceImpl.java
View file @
237eeaf
...
...
@@ -85,107 +85,108 @@ public class SolveServiceImpl implements SolveService {
// 按小组、批次号组装问题对象
@Override
public
DispatchSolution
prepareSolution
(
String
groupId
,
String
batchNo
)
{
log
.
info
(
"组织问题对象, groupId:{}, batchNo:{}"
,
groupId
,
batchNo
);
entityManager
.
clear
();
// 统一出发地
Depot
oneDepot
;
Optional
<
OrgGroup
>
optional
=
groupRepository
.
findByGroupId
(
groupId
);
if
(
optional
.
isEmpty
())
{
log
.
error
(
"组织问题对象, 未查询到组织信息 ,groupId:{}, batchNo:{}"
,
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
);
// customerlist
ArrayList
<
Customer
>
customerList
=
new
ArrayList
<>();
// 已分配和未分配一起排班,因为已分配会影响整体排班结果
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
());
if
(
dispatchOrderList
.
isEmpty
())
{
log
.
error
(
"组织问题对象, 未查询到工单信息 ,groupId:{}, batchNo:{}"
,
groupId
,
batchNo
);
}
dispatchOrderList
.
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
.
getHour
()
*
60
+
ldt1
.
getMinute
();
}
if
(
ldt2
!=
null
)
{
end
=
ldt2
.
getHour
()
*
60
+
ldt2
.
getMinute
();
}
// 40分钟兜低(技能未能正确匹配原因) FIXME 需要跟客户沟通
if
(
null
==
order
.
getTakeTime
())
{
order
.
setTakeTime
(
40
);
}
if
(
null
==
order
.
getTags
())
{
order
.
setTags
(
""
);
}
if
(
null
==
order
.
getPriority
())
{
order
.
setPriority
(
0
);
}
Customer
customer
=
new
Customer
(
order
.
getId
(),
order
.
getOrderId
(),
order
.
getDt
(),
location
,
start
,
end
,
order
.
getSkills
(),
order
.
getTakeTime
());
customerList
.
add
(
customer
);
});
log
.
info
(
"组织问题对象, customer-list, groupId:{}, batchNo:{}, customer-list:{}"
,
groupId
,
batchNo
,
customerList
.
size
());
// 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);
// log.debug("组织问题对象, technicianList groupId:{}, batchNo:{}, engineer-code:{}", groupId, batchNo, engineer.getEngineerCode());
List
<
String
>
skillList
=
queryEngineerSkills
(
engineer
.
getEngineerCode
());
// log.debug("组织问题对象, technicianList groupId:{}, batchNo:{}, engineer-code:{} , skills:{}", groupId, batchNo, engineer.getEngineerCode(), String.join(";", skillList));
// 距离偏好map
Map
<
String
,
Long
>
preferedLoctionDistanceMap
=
new
HashMap
<
String
,
Long
>();
customerList
.
forEach
(
customer
->
{
long
distance
=
distanceCalculator
.
calculateDistance
(
location
,
customer
.
getLocation
());
preferedLoctionDistanceMap
.
put
(
customer
.
getCode
(),
distance
);
});
Technician
vehicle
=
new
Technician
(
engineer
.
getId
(),
engineer
.
getEngineerCode
(),
engineer
.
getMaxNum
(),
engineer
.
getMaxMinute
(),
engineer
.
getMaxDistance
()
*
1000
,
oneDepot
,
60
*
8
,
60
*
18
,
Set
.
copyOf
(
skillList
),
preferedLoctionDistanceMap
);
technicianList
.
add
(
vehicle
);
});
log
.
info
(
"组织问题对象, depotList-list, groupId:{}, batchNo:{}"
,
groupId
,
batchNo
);
log
.
info
(
"组织问题对象, technician-list, groupId:{}, batchNo:{}, technician-list:{}"
,
groupId
,
batchNo
,
technicianList
.
size
());
// locationlist 起点+订单地点
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
);
// path 路网数据初始化,FIXME 需要专门路网数据缓存库
long
time1
=
System
.
currentTimeMillis
();
distanceCalculator
.
initDistanceMaps
(
locationList
);
long
time2
=
System
.
currentTimeMillis
();
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
null
;
// log.info("组织问题对象, groupId:{}, batchNo:{}", groupId, batchNo);
//
// entityManager.clear();
//
// // 统一出发地
// Depot oneDepot;
// Optional<OrgGroup> optional = groupRepository.findByGroupId(groupId);
// if (optional.isEmpty()) {
// log.error("组织问题对象, 未查询到组织信息 ,groupId:{}, batchNo:{}", 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);
//
//
// // customerlist
// ArrayList<Customer> customerList = new ArrayList<>();
// // 已分配和未分配一起排班,因为已分配会影响整体排班结果
// 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());
//
// if (dispatchOrderList.isEmpty()) {
// log.error("组织问题对象, 未查询到工单信息 ,groupId:{}, batchNo:{}", groupId, batchNo);
// }
//
// dispatchOrderList.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.getHour() * 60 + ldt1.getMinute();
// }
// if (ldt2 != null) {
// end = ldt2.getHour() * 60 + ldt2.getMinute();
// }
//
//
// // 40分钟兜低(技能未能正确匹配原因) FIXME 需要跟客户沟通
// if (null == order.getTakeTime()) {
// order.setTakeTime(40);
// }
// if (null == order.getTags()) {
// order.setTags("");
// }
// if (null == order.getPriority()) {
// order.setPriority(0);
// }
//
// Customer customer = new Customer(order.getId(), order.getOrderId(), order.getDt(), location, start, end, order.getSkills(), order.getTakeTime());
//
// customerList.add(customer);
// });
//
// log.info("组织问题对象, customer-list, groupId:{}, batchNo:{}, customer-list:{}", groupId, batchNo, customerList.size());
//
// // 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);
//
//// log.debug("组织问题对象, technicianList groupId:{}, batchNo:{}, engineer-code:{}", groupId, batchNo, engineer.getEngineerCode());
// List<String> skillList = queryEngineerSkills(engineer.getEngineerCode());
//
//// log.debug("组织问题对象, technicianList groupId:{}, batchNo:{}, engineer-code:{} , skills:{}", groupId, batchNo, engineer.getEngineerCode(), String.join(";", skillList));
//
// // 距离偏好map
// Map<String, Long> preferedLoctionDistanceMap = new HashMap<String, Long>();
// customerList.forEach(customer -> {
// long distance = distanceCalculator.calculateDistance(location, customer.getLocation());
// preferedLoctionDistanceMap.put(customer.getCode(), distance);
// });
//
// Technician vehicle = new Technician(engineer.getId(), engineer.getEngineerCode(), engineer.getMaxNum(), engineer.getMaxMinute(), engineer.getMaxDistance() * 1000, oneDepot, 60 * 8, 60 * 18, Set.copyOf(skillList), preferedLoctionDistanceMap);
// technicianList.add(vehicle);
// });
//
// log.info("组织问题对象, depotList-list, groupId:{}, batchNo:{}", groupId, batchNo);
// log.info("组织问题对象, technician-list, groupId:{}, batchNo:{}, technician-list:{}", groupId, batchNo, technicianList.size());
//
// // locationlist 起点+订单地点
// 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);
//
// // path 路网数据初始化,FIXME 需要专门路网数据缓存库
// long time1 = System.currentTimeMillis();
// distanceCalculator.initDistanceMaps(locationList);
// long time2 = System.currentTimeMillis();
//
// 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;
}
...
...
@@ -275,9 +276,12 @@ public class SolveServiceImpl implements SolveService {
preferedLoctionDistanceMap
.
put
(
customer
.
getCode
(),
distance
);
});
// FIXME 硬约束:电动车固定40km上限,其他无限制
Technician
vehicle
=
new
Technician
(
engineer
.
getId
(),
engineer
.
getEngineerCode
(),
engineer
.
getMaxNum
(),
engineer
.
getMaxMinute
(),
engineer
.
getMaxDistance
()
*
1000
,
oneDepot
,
60
*
8
,
60
*
18
,
Set
.
copyOf
(
skillList
),
preferedLoctionDistanceMap
);
// 硬约束:电动车固定40km上限,其他无限制
int
maxDistance
=
engineer
.
getMaxDistance
()
*
1000
;
if
(
engineer
.
getVehicleType
()
!=
null
&&
engineer
.
getVehicleType
()
==
2
)
{
maxDistance
=
40
*
1000
;
}
Technician
vehicle
=
new
Technician
(
engineer
.
getId
(),
engineer
.
getEngineerCode
(),
engineer
.
getMaxNum
(),
engineer
.
getMaxMinute
(),
maxDistance
,
engineer
.
getVehicleType
()
,
oneDepot
,
60
*
8
,
60
*
18
,
Set
.
copyOf
(
skillList
),
preferedLoctionDistanceMap
);
technicianList
.
add
(
vehicle
);
});
...
...
@@ -291,8 +295,12 @@ public class SolveServiceImpl implements SolveService {
// path 路网数据初始化,FIXME 需要专门路网数据缓存库
long
time1
=
System
.
currentTimeMillis
();
distanceCalculator
.
initDistanceMaps
(
locationList
);
long
time2
=
System
.
currentTimeMillis
();
// 根据不同的交通工具,初始化不同的路网数据
List
<
Integer
>
vehicleTypes
=
technicianList
.
stream
()
.
map
(
tec
->
tec
.
getVehicleType
()
==
null
?
1
:
tec
.
getVehicleType
()).
distinct
()
.
collect
(
Collectors
.
toList
());
distanceCalculator
.
initDistanceMaps
(
locationList
,
vehicleTypes
);
long
time2
=
System
.
currentTimeMillis
();
log
.
info
(
"组织问题对象 done, teamId:{}, batchNo:{}, technician-size:{}, customer-size:{}, location-size:{}, 路网耗时path:{}ms"
,
teamId
,
batchNo
,
technicianList
.
size
(),
customerList
.
size
(),
locationList
.
size
(),
time2
-
time1
);
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/utils/DataUtils.java
View file @
237eeaf
...
...
@@ -240,7 +240,7 @@ public class DataUtils {
Location
locationi
=
locationIndex
.
get
(
i
+
1
);
for
(
int
j
=
0
;
j
<
pathMatrix
[
i
].
length
;
j
++)
{
Location
locationj
=
locationIndex
.
get
(
j
+
1
);
locationi
.
getDistanceMap
().
put
(
locationj
,
pathMatrix
[
i
][
j
]);
locationi
.
getDistanceMap
(
1
).
put
(
locationj
,
pathMatrix
[
i
][
j
]);
}
}
...
...
@@ -259,7 +259,7 @@ public class DataUtils {
Location
locationi
=
locationIndex
.
get
(
i
+
1
);
for
(
int
j
=
0
;
j
<
pathTimeMatrix
[
i
].
length
;
j
++)
{
Location
locationj
=
locationIndex
.
get
(
j
+
1
);
locationi
.
getDistanceTimeMap
().
put
(
locationj
,
pathTimeMatrix
[
i
][
j
]);
locationi
.
getDistanceTimeMap
(
1
).
put
(
locationj
,
pathTimeMatrix
[
i
][
j
]);
}
}
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/utils/DispatchSolutionUtils.java
View file @
237eeaf
...
...
@@ -72,12 +72,12 @@ public class DispatchSolutionUtils {
startPath
=
technician
.
getDepot
().
getStartTime
();
// endPath = startPath +
// customer.getLocation().getPathTimeTo(technician.getDepot().getLocation());
endPath
=
startPath
+
technician
.
getDepot
().
getLocation
().
getPathTimeTo
(
customer
.
getLocation
());
endPath
=
startPath
+
technician
.
getDepot
().
getLocation
().
getPathTimeTo
(
technician
.
getVehicleType
(),
customer
.
getLocation
());
}
else
{
startPath
=
previousCustomer
.
getDepartureTime
();
// endPath = startPath +
// customer.getLocation().getPathTimeTo(previousCustomer.getLocation());
endPath
=
startPath
+
previousCustomer
.
getLocation
().
getPathTimeTo
(
customer
.
getLocation
());
endPath
=
startPath
+
previousCustomer
.
getLocation
().
getPathTimeTo
(
technician
.
getVehicleType
(),
customer
.
getLocation
());
}
if
(
customer
.
getArrivalTime
()
>
customer
.
getEndTime
())
{
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/utils/RoadDistanceUtils.java
View file @
237eeaf
...
...
@@ -26,7 +26,7 @@ import lombok.Data;
*/
public
class
RoadDistanceUtils
{
public
static
String
URL
=
"https://api.map.baidu.com/routematrix/v2/
riding?
"
;
public
static
String
URL
=
"https://api.map.baidu.com/routematrix/v2/"
;
public
static
String
AK
=
"doR30pE7R0I7ivGLwMpkpsTT4bos9Akg"
;
/**
...
...
@@ -42,20 +42,21 @@ public class RoadDistanceUtils {
*
* @param from
* @param to
* @param vehicleType 不能为空
* @return
*/
public
static
Distance
getDistance
(
Location
from
,
Location
to
)
{
public
static
Distance
getDistance
(
Location
from
,
Location
to
,
int
vehicleType
)
{
try
{
String
key
=
from
.
getLongitude
()
+
","
+
from
.
getLatitude
()
+
";"
+
to
.
getLongitude
()
+
","
+
to
.
getLatitude
();
+
to
.
getLatitude
()
+
"|"
+
vehicleType
;
Distance
distance
=
distanceCache
.
get
(
key
);
if
(
null
==
distance
)
{
distance
=
getDistance
(
from
.
getLatitude
()
+
","
+
from
.
getLongitude
(),
to
.
getLatitude
()
+
","
+
to
.
getLongitude
());
if
(
null
==
distance
)
{
to
.
getLatitude
()
+
","
+
to
.
getLongitude
()
,
vehicleType
);
if
(
null
==
distance
)
{
Distance
dis
=
new
Distance
();
return
dis
;
}
else
{
}
else
{
distanceCache
.
put
(
key
,
distance
);
}
return
distance
;
...
...
@@ -68,14 +69,34 @@ public class RoadDistanceUtils {
}
}
private
static
Distance
getDistance
(
String
yx1
,
String
yx2
)
throws
Exception
{
private
static
Distance
getDistance
(
String
yx1
,
String
yx2
,
int
vehicleType
)
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
);
String
url
=
""
;
switch
(
vehicleType
)
{
case
1
:
url
=
URL
+
"driving?"
;
break
;
case
2
:
params
.
put
(
"riding_type"
,
"1"
);
// 电动自行车
url
=
URL
+
"riding?"
;
break
;
case
3
:
params
.
put
(
"riding_type"
,
"0"
);
// 普通自行车
url
=
URL
+
"riding?"
;
break
;
case
4
:
url
=
URL
+
"walking?"
;
break
;
}
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
();
...
...
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