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 1e784b08
authored
Nov 10, 2023
by
Ren Ping
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix:处理初始化工程师容量定时任务
1 parent
8905fedb
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
205 additions
and
146 deletions
project-dispatch/src/main/java/com/dituhui/pea/dispatch/constraint/DispatchConstraintProvider.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/entity/OrderInfo.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/quartz/engineerCapacity/InitEngineerCapacityScheduler.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/impl/SchedulerServiceImpl.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/impl/SolveServiceImpl.java
project-dispatch/src/main/resources/application-dev.yaml
project-dispatch/src/main/resources/logback-spring.xml
project-dispatch/src/main/java/com/dituhui/pea/dispatch/constraint/DispatchConstraintProvider.java
View file @
1e784b0
...
@@ -2,6 +2,7 @@ package com.dituhui.pea.dispatch.constraint;
...
@@ -2,6 +2,7 @@ package com.dituhui.pea.dispatch.constraint;
import
java.util.List
;
import
java.util.List
;
import
cn.hutool.core.util.StrUtil
;
import
org.optaplanner.core.api.score.buildin.hardsoftlong.HardSoftLongScore
;
import
org.optaplanner.core.api.score.buildin.hardsoftlong.HardSoftLongScore
;
import
org.optaplanner.core.api.score.stream.Constraint
;
import
org.optaplanner.core.api.score.stream.Constraint
;
import
org.optaplanner.core.api.score.stream.ConstraintFactory
;
import
org.optaplanner.core.api.score.stream.ConstraintFactory
;
...
@@ -13,97 +14,95 @@ import com.dituhui.pea.dispatch.pojo.Technician;
...
@@ -13,97 +14,95 @@ import com.dituhui.pea.dispatch.pojo.Technician;
public
class
DispatchConstraintProvider
implements
ConstraintProvider
{
public
class
DispatchConstraintProvider
implements
ConstraintProvider
{
@Override
@Override
public
Constraint
[]
defineConstraints
(
ConstraintFactory
factory
)
{
public
Constraint
[]
defineConstraints
(
ConstraintFactory
factory
)
{
return
new
Constraint
[]
{
return
new
Constraint
[]{
// 硬约束
// 硬约束
// 运行时长提升效果
// 运行时长提升效果
// 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
),
technicianTimeWindowsMatch
(
factory
),
technicianCapacityMatch
(
factory
),
technicianCapacityMatch
(
factory
),
skillMatch
(
factory
),
skillMatch
(
factory
),
dispatchedMatch
(
factory
),
dispatchedMatch
(
factory
),
// 软约束
// 软约束
technicianBalanceSoft
(
factory
),
technicianBalanceSoft
(
factory
),
totalDistance
(
factory
),
totalDistance
(
factory
),
preferredTotalDistance
(
factory
)
preferredTotalDistance
(
factory
)
};
};
}
}
// ************************************************************************
// ************************************************************************
// Hard constraints
// Hard constraints
// ************************************************************************
// ************************************************************************
// 1,技术员到达时间跟时间窗吻合customerTimeWindowsMatch
// 1,技术员到达时间跟时间窗吻合customerTimeWindowsMatch
// 2,技术员时间窗吻合technicianTimeWindowsMatch
// 2,技术员时间窗吻合technicianTimeWindowsMatch
// 3,技术员技能跟订单相匹配skillMatch
// 3,技术员技能跟订单相匹配skillMatch
public
Constraint
greaterThanZero
(
ConstraintFactory
factory
)
{
public
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
(
"每个技术员至少分配一个单子"
);
}
}
protected
Constraint
customerTimeWindowsMatch
(
ConstraintFactory
factory
)
{
protected
Constraint
customerTimeWindowsMatch
(
ConstraintFactory
factory
)
{
return
factory
.
forEach
(
Customer
.
class
).
filter
(
return
factory
.
forEach
(
Customer
.
class
).
filter
(
customer
->
customer
.
getTechnician
()
!=
null
&&
customer
.
getArrivalTime
()
>
customer
.
getEndTime
())
customer
->
customer
.
getTechnician
()
!=
null
&&
customer
.
getArrivalTime
()
>
customer
.
getEndTime
())
.
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
.
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
// 迟到每2小时扣一分
// 迟到每2小时扣一分
customer
->
(
long
)
Math
.
ceil
((
customer
.
getArrivalTime
()
-
customer
.
getEndTime
())
/
120
F
))
customer
->
(
long
)
Math
.
ceil
((
customer
.
getArrivalTime
()
-
customer
.
getEndTime
())
/
120
F
))
.
asConstraint
(
ConstraintNameEnum
.
customerTimeWindowsMatch
.
name
());
.
asConstraint
(
ConstraintNameEnum
.
customerTimeWindowsMatch
.
name
());
}
}
protected
Constraint
technicianTimeWindowsMatch
(
ConstraintFactory
factory
)
{
protected
Constraint
technicianTimeWindowsMatch
(
ConstraintFactory
factory
)
{
return
factory
.
forEach
(
Technician
.
class
).
filter
(
return
factory
.
forEach
(
Technician
.
class
).
filter
(
technician
->
{
technician
->
{
boolean
ret
=
false
;
boolean
ret
=
false
;
// 单子的服务时间都在时间窗口内
// 单子的服务时间都在时间窗口内
int
[][]
timeWindows
=
technician
.
getTimeWindows
();
int
[][]
timeWindows
=
technician
.
getTimeWindows
();
List
<
Customer
>
customers
=
technician
.
getCustomerList
();
List
<
Customer
>
customers
=
technician
.
getCustomerList
();
if
(
null
!=
timeWindows
&&
timeWindows
.
length
>
0
&&
null
!=
customers
&&
customers
.
size
()
>
0
)
{
if
(
null
!=
timeWindows
&&
timeWindows
.
length
>
0
&&
null
!=
customers
&&
customers
.
size
()
>
0
)
{
for
(
Customer
customer
:
customers
)
{
for
(
Customer
customer
:
customers
)
{
Integer
arrivalTime
=
customer
.
getArrivalTime
();
Integer
arrivalTime
=
customer
.
getArrivalTime
();
if
(
arrivalTime
!=
null
&&
arrivalTime
>
0
)
{
if
(
arrivalTime
!=
null
&&
arrivalTime
>
0
)
{
boolean
in
=
false
;
boolean
in
=
false
;
for
(
int
[]
window
:
timeWindows
)
{
for
(
int
[]
window
:
timeWindows
)
{
if
(
window
[
0
]
<=
arrivalTime
&&
window
[
1
]
>=
arrivalTime
)
{
if
(
window
[
0
]
<=
arrivalTime
&&
window
[
1
]
>=
arrivalTime
)
{
in
=
true
;
in
=
true
;
break
;
break
;
}
}
}
}
if
(!
in
)
{
if
(!
in
)
{
// 到达时间在日历窗口外,惩罚得分
// 到达时间在日历窗口外,惩罚得分
ret
=
true
;
ret
=
true
;
}
}
}
}
}
}
}
}
return
ret
;
return
ret
;
}).
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
technician
->
1
)
}).
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
technician
->
1
)
.
asConstraint
(
ConstraintNameEnum
.
technicianTimeWindowsMatch
.
name
());
.
asConstraint
(
ConstraintNameEnum
.
technicianTimeWindowsMatch
.
name
());
}
}
protected
Constraint
technicianCapacityMatch
(
ConstraintFactory
factory
)
{
protected
Constraint
technicianCapacityMatch
(
ConstraintFactory
factory
)
{
return
factory
.
forEach
(
Technician
.
class
).
filter
(
return
factory
.
forEach
(
Technician
.
class
).
filter
(
// MaxCount ==0 表示不起作用
// MaxCount ==0 表示不起作用
technician
->
technician
.
getMaxCount
()
>
0
&&
technician
.
getCustomerSize
()
>
technician
.
getMaxCount
())
technician
->
technician
.
getMaxCount
()
>
0
&&
technician
.
getCustomerSize
()
>
technician
.
getMaxCount
())
.
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
technician
->
1
)
.
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
technician
->
1
)
.
asConstraint
(
ConstraintNameEnum
.
technicianCapacityMatch
.
name
());
.
asConstraint
(
ConstraintNameEnum
.
technicianCapacityMatch
.
name
());
}
}
protected
Constraint
dispatchedMatch
(
ConstraintFactory
factory
)
{
protected
Constraint
dispatchedMatch
(
ConstraintFactory
factory
)
{
return
factory
.
forEach
(
Customer
.
class
).
filter
(
customer
->
return
factory
.
forEach
(
Customer
.
class
).
filter
(
customer
->
// 已分配
// 已分配
(
customer
.
getDispatchedTechnicianCode
()
!=
null
&&
((
customer
.
getTechnician
()
==
null
)
(
customer
.
getDispatchedTechnicianCode
()
!=
null
||
(!
StringUtils
.
equals
(
customer
.
getDispatchedTechnicianCode
(),
customer
.
getTechnician
().
getCode
()))))
&&
(
customer
.
getTechnician
()
==
null
||
!
StringUtils
.
equals
(
customer
.
getDispatchedTechnicianCode
(),
customer
.
getTechnician
().
getCode
())))
||
||
(
customer
.
getExclusiveTechnicianCode
()
!=
null
// 已排除
&&
(
customer
.
getTechnician
()
==
null
||
StrUtil
.
contains
(
","
+
customer
.
getExclusiveTechnicianCode
()
+
","
,
","
+
customer
.
getTechnician
().
getCode
()
+
","
))))
(
customer
.
getExclusiveTechnicianCode
()
!=
null
&&
((
customer
.
getTechnician
()
==
null
)
||
(
StringUtils
.
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
customer
->
50
)
.
equals
(
customer
.
getExclusiveTechnicianCode
(),
customer
.
getTechnician
().
getCode
())))))
.
asConstraint
(
ConstraintNameEnum
.
dispatchedMatch
.
name
());
.
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
customer
->
50
)
}
.
asConstraint
(
ConstraintNameEnum
.
dispatchedMatch
.
name
());
}
// protected Constraint customerTimeWindowsMatch1(ConstraintFactory factory) {
// protected Constraint customerTimeWindowsMatch1(ConstraintFactory factory) {
// return factory.forEach(Customer.class).filter(
// return factory.forEach(Customer.class).filter(
...
@@ -118,17 +117,17 @@ public class DispatchConstraintProvider implements ConstraintProvider {
...
@@ -118,17 +117,17 @@ public class DispatchConstraintProvider implements ConstraintProvider {
// .penalizeLong(HardSoftLongScore.ONE_HARD, customer -> 1).asConstraint("技术员到达时间跟时间窗吻合2");
// .penalizeLong(HardSoftLongScore.ONE_HARD, customer -> 1).asConstraint("技术员到达时间跟时间窗吻合2");
// }
// }
protected
Constraint
skillMatch
(
ConstraintFactory
factory
)
{
protected
Constraint
skillMatch
(
ConstraintFactory
factory
)
{
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
,
.
penalizeLong
(
HardSoftLongScore
.
ONE_HARD
,
// 技能匹配跟时间窗匹配存在很明显的跷跷板效应,权重小于3就会存在技能匹配问题
// 技能匹配跟时间窗匹配存在很明显的跷跷板效应,权重小于3就会存在技能匹配问题
// 3-技能匹配问题1个,时间窗问题8个
// 3-技能匹配问题1个,时间窗问题8个
// 4-技能匹配问题0个,时间窗问题14个
// 4-技能匹配问题0个,时间窗问题14个
customer
->
4
)
customer
->
4
)
.
asConstraint
(
ConstraintNameEnum
.
skillMatch
.
name
());
.
asConstraint
(
ConstraintNameEnum
.
skillMatch
.
name
());
}
}
// protected Constraint technicianBalance(ConstraintFactory factory) {
// protected Constraint technicianBalance(ConstraintFactory factory) {
// // 会导致剩余单子集中?
// // 会导致剩余单子集中?
...
@@ -144,30 +143,30 @@ public class DispatchConstraintProvider implements ConstraintProvider {
...
@@ -144,30 +143,30 @@ public class DispatchConstraintProvider implements ConstraintProvider {
// .penalizeLong(HardSoftLongScore.ONE_HARD, technician -> 1).asConstraint("订单均分2");
// .penalizeLong(HardSoftLongScore.ONE_HARD, technician -> 1).asConstraint("订单均分2");
// }
// }
// ************************************************************************
// ************************************************************************
// Soft constraints
// Soft constraints
// ************************************************************************
// ************************************************************************
// 1, 总路程最小 totalDistance
// 1, 总路程最小 totalDistance
// 2, 技术员中心点偏好 preferredTotalDistance
// 2, 技术员中心点偏好 preferredTotalDistance
// 3, 订单数量均衡 technicianBalanceSoft
// 3, 订单数量均衡 technicianBalanceSoft
protected
Constraint
totalDistance
(
ConstraintFactory
factory
)
{
protected
Constraint
totalDistance
(
ConstraintFactory
factory
)
{
return
factory
.
forEach
(
Technician
.
class
)
return
factory
.
forEach
(
Technician
.
class
)
.
penalizeLong
(
HardSoftLongScore
.
ONE_SOFT
,
Technician:
:
getTotalDistanceMeters
)
.
penalizeLong
(
HardSoftLongScore
.
ONE_SOFT
,
Technician:
:
getTotalDistanceMeters
)
.
asConstraint
(
ConstraintNameEnum
.
totalDistance
.
name
());
.
asConstraint
(
ConstraintNameEnum
.
totalDistance
.
name
());
}
}
protected
Constraint
preferredTotalDistance
(
ConstraintFactory
factory
)
{
protected
Constraint
preferredTotalDistance
(
ConstraintFactory
factory
)
{
return
factory
.
forEach
(
Technician
.
class
)
return
factory
.
forEach
(
Technician
.
class
)
.
penalizeLong
(
HardSoftLongScore
.
ONE_SOFT
,
Technician:
:
getPreferredTotalDistanceMeters
)
.
penalizeLong
(
HardSoftLongScore
.
ONE_SOFT
,
Technician:
:
getPreferredTotalDistanceMeters
)
.
asConstraint
(
ConstraintNameEnum
.
preferredTotalDistance
.
name
());
.
asConstraint
(
ConstraintNameEnum
.
preferredTotalDistance
.
name
());
}
}
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
())
*
4000
)
(
a
,
b
)
->
Math
.
abs
(
a
.
getCustomerSize
()
-
b
.
getCustomerSize
())
*
4000
)
.
asConstraint
(
ConstraintNameEnum
.
technicianBalanceSoft
.
name
());
.
asConstraint
(
ConstraintNameEnum
.
technicianBalanceSoft
.
name
());
}
}
}
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/entity/OrderInfo.java
View file @
1e784b0
...
@@ -197,4 +197,25 @@ public class OrderInfo implements Serializable {
...
@@ -197,4 +197,25 @@ public class OrderInfo implements Serializable {
@Column
(
name
=
"update_time"
)
@Column
(
name
=
"update_time"
)
private
LocalDateTime
updateTime
;
private
LocalDateTime
updateTime
;
/**
* 是否重物搬运(双人上门) 0:否 1:是 默认0
*/
@Column
(
name
=
"is_multiple"
)
private
Integer
isMultiple
=
0
;
/**
* 是否指定某个工程师/是否排除某个工程师 0:否 1:指定 2:排除 默认0
*/
@Column
(
name
=
"is_appoint_engineer"
)
private
Integer
isAppointEngineer
=
0
;
/**
* 指定某个工程师/排除某个工程师 codes 多个,分割
*/
@Column
(
name
=
"appoint_engineer_codes"
)
private
String
appointEngineerCodes
;
}
}
project-dispatch/src/main/java/com/dituhui/pea/dispatch/quartz/engineerCapacity/InitEngineerCapacityScheduler.java
View file @
1e784b0
package
com
.
dituhui
.
pea
.
dispatch
.
quartz
.
engineerCapacity
;
package
com
.
dituhui
.
pea
.
dispatch
.
quartz
.
engineerCapacity
;
import
cn.hutool.core.collection.CollectionUtil
;
import
cn.hutool.core.collection.CollectionUtil
;
import
cn.hutool.core.util.StrUtil
;
import
com.dituhui.pea.dispatch.common.DateUtil
;
import
com.dituhui.pea.dispatch.common.DateUtil
;
import
com.dituhui.pea.dispatch.common.DateUtils
;
import
com.dituhui.pea.dispatch.common.DateUtils
;
import
com.dituhui.pea.dispatch.common.OccupyInfoDetail
;
import
com.dituhui.pea.dispatch.common.OccupyInfoDetail
;
...
@@ -189,7 +190,7 @@ public class InitEngineerCapacityScheduler {
...
@@ -189,7 +190,7 @@ public class InitEngineerCapacityScheduler {
// 初始化一个工程师、一天的容量
// 初始化一个工程师、一天的容量
CapacityEngineerStatEntity
statEntity
=
capacityEngineerStatDao
.
getByWorkdayAndEngineerCode
(
date
,
engineerCode
);
CapacityEngineerStatEntity
statEntity
=
capacityEngineerStatDao
.
getByWorkdayAndEngineerCode
(
date
,
engineerCode
);
if
(
statEntity
!=
null
&&
!
rewriteForce
)
{
if
(
statEntity
!=
null
&&
!
rewriteForce
)
{
log
.
error
(
"技术员容量信息记录
已存在, 直接返回"
);
log
.
error
(
"技术员容量信息记录
(engineer: {}, date:{})已存在, 直接返回"
,
engineerCode
,
date
);
return
;
return
;
}
}
log
.
info
(
"日期[{}] 技术员[{}] 有日历记录需要特别处理 ==="
,
date
,
engineerCode
);
log
.
info
(
"日期[{}] 技术员[{}] 有日历记录需要特别处理 ==="
,
date
,
engineerCode
);
...
@@ -212,10 +213,11 @@ public class InitEngineerCapacityScheduler {
...
@@ -212,10 +213,11 @@ public class InitEngineerCapacityScheduler {
}
}
public
void
initOneEngineerByDays
(
String
bdate
,
String
edate
,
String
branchId
)
{
public
void
initOneEngineerByDays
(
String
bdate
,
String
edate
,
String
branchId
)
{
LocalDate
currentDate
=
DateUtils
.
localDateFromStr
(
bdate
);
LocalDate
endDate
=
DateUtils
.
localDateFromStr
(
edate
);
List
<
String
>
allEngineerCodes
=
engineerInfoDao
.
getAllByBranchId
(
branchId
).
stream
().
map
(
EngineerInfo:
:
getEngineerCode
).
collect
(
Collectors
.
toList
());
List
<
String
>
allEngineerCodes
=
engineerInfoDao
.
getAllByBranchId
(
branchId
).
stream
().
map
(
EngineerInfo:
:
getEngineerCode
).
collect
(
Collectors
.
toList
());
for
(
String
engineerCode:
allEngineerCodes
){
log
.
warn
(
">>> 分部工程师容量初始化开始,branchId: {},工程师数量:{}"
,
branchId
,
allEngineerCodes
.
size
());
for
(
String
engineerCode
:
allEngineerCodes
)
{
LocalDate
currentDate
=
DateUtils
.
localDateFromStr
(
bdate
);
LocalDate
endDate
=
DateUtils
.
localDateFromStr
(
edate
);
while
(!
currentDate
.
isAfter
(
endDate
))
{
while
(!
currentDate
.
isAfter
(
endDate
))
{
initOneEngineer
(
DateUtils
.
formatDate
(
currentDate
),
engineerCode
);
initOneEngineer
(
DateUtils
.
formatDate
(
currentDate
),
engineerCode
);
currentDate
=
currentDate
.
plusDays
(
1
);
currentDate
=
currentDate
.
plusDays
(
1
);
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/impl/SchedulerServiceImpl.java
View file @
1e784b0
...
@@ -84,7 +84,7 @@ public class SchedulerServiceImpl implements SchedulerService {
...
@@ -84,7 +84,7 @@ public class SchedulerServiceImpl implements SchedulerService {
return
;
return
;
}
}
OrgGroup
orgGroup
=
orgGroupRepository
.
findByGroupId
(
orgTeamEntity
.
getGroupId
()).
get
();
OrgGroup
orgGroup
=
orgGroupRepository
.
findByGroupId
(
orgTeamEntity
.
getGroupId
()).
get
();
if
(
ObjectUtil
.
equals
(
2
,
orgGroup
.
getCategory
()))
{
if
(
ObjectUtil
.
equals
(
2
,
orgGroup
.
getCategory
()))
{
log
.
error
(
">>> teamId:{} 来自网点,不自动派工"
,
teamId
);
log
.
error
(
">>> teamId:{} 来自网点,不自动派工"
,
teamId
);
...
@@ -97,6 +97,7 @@ public class SchedulerServiceImpl implements SchedulerService {
...
@@ -97,6 +97,7 @@ public class SchedulerServiceImpl implements SchedulerService {
}
}
LocalDateTime
now
=
LocalDateTime
.
now
();
LocalDateTime
now
=
LocalDateTime
.
now
();
String
today
=
DateUtil
.
format
(
now
,
"yyyy-MM-dd"
);
String
nowTime
=
DateUtil
.
format
(
now
,
"HH:mm"
);
String
nowTime
=
DateUtil
.
format
(
now
,
"HH:mm"
);
String
nowTimePlus30
=
DateUtil
.
format
(
now
.
plusMinutes
(
30
),
"HH:mm"
);
String
nowTimePlus30
=
DateUtil
.
format
(
now
.
plusMinutes
(
30
),
"HH:mm"
);
...
@@ -109,10 +110,13 @@ public class SchedulerServiceImpl implements SchedulerService {
...
@@ -109,10 +110,13 @@ public class SchedulerServiceImpl implements SchedulerService {
String
groupId
=
orgTeamEntity
.
getGroupId
();
String
groupId
=
orgTeamEntity
.
getGroupId
();
log
.
info
(
"dispatchRun group:{}, team:{} done"
,
groupId
,
teamId
);
log
.
info
(
"dispatchRun group:{}, team:{} done"
,
groupId
,
teamId
);
for
(
int
i
=
1
;
i
<=
nextDaysLimit
;
i
++)
{
for
(
int
i
=
1
;
i
<=
nextDaysLimit
;
i
++)
{
String
currDay
=
LocalDate
.
now
().
plusDays
(
i
).
format
(
DateTimeFormatter
.
ISO_LOCAL_DATE
);
String
currDay
=
LocalDate
.
now
().
plusDays
(
i
).
format
(
DateTimeFormatter
.
ISO_LOCAL_DATE
);
Optional
<
DispatchBatch
>
optional
=
dispatchBatchRepository
.
findByTeamIdAndBatchDate
(
teamId
,
currDay
);
Optional
<
DispatchBatch
>
optional
=
dispatchBatchRepository
.
findByTeamIdAndBatchDate
(
teamId
,
currDay
);
if
(
optional
.
isPresent
()
&&
Objects
.
nonNull
(
optional
.
get
().
getCutoffedTime
()))
{
if
(
optional
.
isPresent
()
&&
Objects
.
nonNull
(
optional
.
get
().
getCutoffedTime
())
&&
today
.
equals
(
DateUtil
.
format
(
optional
.
get
().
getCutoffedTime
(),
"yyyy-MM-dd"
)))
{
//自动任务截止
//自动任务截止
log
.
error
(
">>> teamId:{}, day:{} 自动任务已截止"
,
teamId
,
currDay
);
log
.
error
(
">>> teamId:{}, day:{} 自动任务已截止"
,
teamId
,
currDay
);
continue
;
continue
;
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/impl/SolveServiceImpl.java
View file @
1e784b0
package
com
.
dituhui
.
pea
.
dispatch
.
service
.
impl
;
package
com
.
dituhui
.
pea
.
dispatch
.
service
.
impl
;
import
cn.hutool.core.util.ObjectUtil
;
import
cn.hutool.core.util.StrUtil
;
import
cn.hutool.core.util.StrUtil
;
import
cn.hutool.crypto.SecureUtil
;
import
cn.hutool.crypto.SecureUtil
;
import
com.dituhui.pea.dispatch.common.GeoDistanceCalculator
;
import
com.dituhui.pea.dispatch.common.GeoDistanceCalculator
;
import
com.dituhui.pea.dispatch.constraint.DispatchConstraintProvider
;
import
com.dituhui.pea.dispatch.constraint.DispatchConstraintProvider
;
import
com.dituhui.pea.dispatch.dao.DispatchEngineerRepository
;
import
com.dituhui.pea.dispatch.dao.*
;
import
com.dituhui.pea.dispatch.dao.DispatchOrderRepository
;
import
com.dituhui.pea.dispatch.dao.OrgGroupRepository
;
import
com.dituhui.pea.dispatch.dao.OrgTeamDao
;
import
com.dituhui.pea.dispatch.entity.DispatchOrder
;
import
com.dituhui.pea.dispatch.entity.DispatchOrder
;
import
com.dituhui.pea.dispatch.entity.OrderInfo
;
import
com.dituhui.pea.dispatch.entity.OrgGroup
;
import
com.dituhui.pea.dispatch.entity.OrgGroup
;
import
com.dituhui.pea.dispatch.entity.OrgTeamEntity
;
import
com.dituhui.pea.dispatch.entity.OrgTeamEntity
;
import
com.dituhui.pea.dispatch.pojo.*
;
import
com.dituhui.pea.dispatch.pojo.*
;
...
@@ -59,6 +58,9 @@ public class SolveServiceImpl implements SolveService {
...
@@ -59,6 +58,9 @@ public class SolveServiceImpl implements SolveService {
DispatchOrderRepository
dispatchOrderRepo
;
DispatchOrderRepository
dispatchOrderRepo
;
@Autowired
@Autowired
private
OrderInfoRepository
orderInfoRepository
;
@Autowired
OrgGroupRepository
groupRepository
;
OrgGroupRepository
groupRepository
;
...
@@ -252,6 +254,17 @@ public class SolveServiceImpl implements SolveService {
...
@@ -252,6 +254,17 @@ public class SolveServiceImpl implements SolveService {
}
}
Customer
customer
=
new
Customer
(
order
.
getId
(),
order
.
getOrderId
(),
order
.
getDt
(),
location
,
start
,
end
,
order
.
getSkills
(),
order
.
getTakeTime
());
Customer
customer
=
new
Customer
(
order
.
getId
(),
order
.
getOrderId
(),
order
.
getDt
(),
location
,
start
,
end
,
order
.
getSkills
(),
order
.
getTakeTime
());
OrderInfo
orderInfo
=
orderInfoRepository
.
findByOrderId
(
order
.
getOrderId
()).
get
(
0
);
if
((
StrUtil
.
equals
(
"MANUAL"
,
orderInfo
.
getAppointmentMethod
())
&&
StrUtil
.
equals
(
"CONFIRM"
,
orderInfo
.
getAppointmentStatus
()))
||
ObjectUtil
.
equal
(
1
,
orderInfo
.
getIsAppointEngineer
()))
{
customer
.
setDispatchedTechnicianCode
(
orderInfo
.
getEngineerCode
());
}
if
(
ObjectUtil
.
equal
(
2
,
orderInfo
.
getIsAppointEngineer
()))
{
customer
.
setExclusiveTechnicianCode
(
Objects
.
nonNull
(
orderInfo
.
getAppointEngineerCodes
())
?
orderInfo
.
getAppointEngineerCodes
().
trim
()
:
null
);
}
customerList
.
add
(
customer
);
customerList
.
add
(
customer
);
});
});
...
...
project-dispatch/src/main/resources/application-dev.yaml
View file @
1e784b0
...
@@ -3,7 +3,7 @@ server:
...
@@ -3,7 +3,7 @@ server:
dispatch
:
dispatch
:
cron
:
cron
:
expr
:
0
14
8-22 * * ?
expr
:
0
55
8-22 * * ?
next-day-limit
:
2
next-day-limit
:
2
# expr: 0 */10 8-18 * * ?
# expr: 0 */10 8-18 * * ?
...
@@ -11,9 +11,9 @@ scheduler:
...
@@ -11,9 +11,9 @@ scheduler:
init-engineer-capacity
:
init-engineer-capacity
:
# 每天22点1次
# 每天22点1次
#cron-expr: 0 0 22 * * ?
#cron-expr: 0 0 22 * * ?
cron-expr
:
0
29
* * * ?
cron-expr
:
0
51
* * * ?
day-offset-begin
:
0
day-offset-begin
:
0
day-offset-end
:
14
day-offset-end
:
20
rewrite-force
:
true
rewrite-force
:
true
calc-engineer-capacity
:
calc-engineer-capacity
:
...
@@ -49,12 +49,12 @@ spring:
...
@@ -49,12 +49,12 @@ spring:
enabled
:
false
enabled
:
false
datasource
:
datasource
:
driver-class-name
:
com.mysql.cj.jdbc.Driver
driver-class-name
:
com.mysql.cj.jdbc.Driver
url
:
jdbc:mysql://127.0.0.1:3306/saas_aftersale_test?serverTimezone=Asia/Shanghai
#
url: jdbc:mysql://127.0.0.1:3306/saas_aftersale_test?serverTimezone=Asia/Shanghai
username
:
root
#
username: root
password
:
123456
#
password: 123456
#
url: jdbc:mysql://localhost:32306/saas_aftersale_test?serverTimezone=Asia/Shanghai
url
:
jdbc:mysql://localhost:32306/saas_aftersale_test?serverTimezone=Asia/Shanghai
#
username: boxi
username
:
boxi
#
password: boxi_dev_0725
password
:
boxi_dev_0725
type
:
com.alibaba.druid.pool.DruidDataSource
type
:
com.alibaba.druid.pool.DruidDataSource
jpa
:
jpa
:
...
...
project-dispatch/src/main/resources/logback-spring.xml
View file @
1e784b0
...
@@ -73,6 +73,24 @@
...
@@ -73,6 +73,24 @@
<onMatch>
ACCEPT
</onMatch>
<onMatch>
ACCEPT
</onMatch>
<onMismatch>
DENY
</onMismatch>
<onMismatch>
DENY
</onMismatch>
</filter>
</filter>
</appender>
<!-- 异常文件输出设置,将异常堆栈另外保存一份到单独的文件中,方便查找 -->
<appender
name=
"FILE_WARN"
class=
"ch.qos.logback.core.rolling.RollingFileAppender"
>
<File>
${LOG_FILE}/warn/${spring.application.name:-}.warn.log
</File>
<rollingPolicy
class=
"ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"
>
<FileNamePattern>
${LOG_FILE}/warn/${spring.application.name:-}.warn-%d{yyyy-MM-dd}-%i.zip
</FileNamePattern>
<maxFileSize>
${LOG_MAXFILESIZE}
</maxFileSize>
<maxHistory>
${LOG_FILEMAXDAY}
</maxHistory>
<totalSizeCap>
500MB
</totalSizeCap>
</rollingPolicy>
<encoder
class=
"ch.qos.logback.classic.encoder.PatternLayoutEncoder"
>
<pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level - %msg%n
</pattern>
<charset>
UTF-8
</charset>
</encoder>
<filter
class=
"ch.qos.logback.classic.filter.LevelFilter"
>
<!-- 只打印警告日志 -->
<filter
class=
"ch.qos.logback.classic.filter.LevelFilter"
>
<!-- 只打印警告日志 -->
<level>
WARN
</level>
<level>
WARN
</level>
<onMatch>
ACCEPT
</onMatch>
<onMatch>
ACCEPT
</onMatch>
...
@@ -118,6 +136,7 @@
...
@@ -118,6 +136,7 @@
<appender-ref
ref=
"console"
/>
<appender-ref
ref=
"console"
/>
<appender-ref
ref=
"FileAppender"
/>
<appender-ref
ref=
"FileAppender"
/>
<appender-ref
ref=
"FILE_ERROR"
/>
<appender-ref
ref=
"FILE_ERROR"
/>
<appender-ref
ref=
"FILE_WARN"
/>
</root>
</root>
</configuration>
</configuration>
\ No newline at end of file
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