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 22db7b12
authored
Nov 02, 2023
by
刘鑫
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop-16542' into 'develop'
容量 See merge request !363
2 parents
6e1de546
7edb439f
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
330 additions
and
51 deletions
project-order/pom.xml
project-order/src/main/java/com/dituhui/pea/order/common/CapacityUtils.java
project-order/src/main/java/com/dituhui/pea/order/common/OccupyInfo.java
project-order/src/main/java/com/dituhui/pea/order/common/OccupyInfoDetail.java
project-order/src/main/java/com/dituhui/pea/order/controller/PeaApiController.java
project-order/src/main/java/com/dituhui/pea/order/dto/param/BaseLocation.java
project-order/src/main/java/com/dituhui/pea/order/dto/param/CapacityQueryDTO.java
project-order/src/main/java/com/dituhui/pea/order/dto/param/EngineerCode.java
project-order/src/main/java/com/dituhui/pea/order/dto/param/EngineerOrderParam.java
project-order/src/main/java/com/dituhui/pea/order/entity/CapacityEngineerSliceUsedEntity.java
project-order/src/main/java/com/dituhui/pea/order/scheduler/CalcEngineerCapacityScheduler.java
project-order/src/main/java/com/dituhui/pea/order/service/impl/CapacityQueryServiceImpl.java
project-order/src/test/java/com/dituhui/pea/order/common/CapacityUtilsTest.java
project-order/pom.xml
View file @
22db7b1
...
...
@@ -87,6 +87,11 @@
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-data-jpa
</artifactId>
</dependency>
<dependency>
<groupId>
com.vladmihalcea
</groupId>
<artifactId>
hibernate-types-55
</artifactId>
<version>
2.21.1
</version>
</dependency>
<dependency>
<groupId>
com.mysql
</groupId>
...
...
@@ -136,6 +141,33 @@
<artifactId>
poi-ooxml
</artifactId>
<version>
3.17
</version>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-test
</artifactId>
<scope>
test
</scope>
</dependency>
<dependency>
<groupId>
org.junit.jupiter
</groupId>
<artifactId>
junit-jupiter-engine
</artifactId>
<scope>
test
</scope>
</dependency>
<dependency>
<groupId>
org.junit.platform
</groupId>
<artifactId>
junit-platform-launcher
</artifactId>
<scope>
test
</scope>
</dependency>
<dependency>
<groupId>
org.mockito
</groupId>
<artifactId>
mockito-core
</artifactId>
<scope>
test
</scope>
</dependency>
<dependency>
<groupId>
org.mockito
</groupId>
<artifactId>
mockito-junit-jupiter
</artifactId>
<scope>
test
</scope>
</dependency>
</dependencies>
<build>
...
...
project-order/src/main/java/com/dituhui/pea/order/common/CapacityUtils.java
View file @
22db7b1
...
...
@@ -19,14 +19,15 @@ import java.time.Duration;
import
java.time.LocalDate
;
import
java.time.LocalDateTime
;
import
java.time.LocalTime
;
import
java.util.AbstractMap
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.Collections
;
import
java.util.Comparator
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Objects
;
import
java.util.Optional
;
import
java.util.OptionalLong
;
import
java.util.concurrent.ExecutionException
;
import
java.util.concurrent.ForkJoinPool
;
import
java.util.concurrent.ForkJoinTask
;
...
...
@@ -101,23 +102,29 @@ public class CapacityUtils {
}
public
static
Long
getMaxRemainBlock
(
LocalDateTime
startTime
,
LocalDateTime
endTime
,
List
<
OccupyInfo
>
occupyInfos
)
{
if
(
org
.
springframework
.
util
.
CollectionUtils
.
isEmpty
(
occupyInfos
))
{
return
Duration
.
between
(
startTime
,
endTime
).
toMinutes
();
public
static
List
<
OccupyInfoDetail
>
getMaxRemainBlock
(
LocalDateTime
startTime
,
LocalDateTime
endTime
,
List
<
OccupyInfo
>
occupyInfos
)
{
//存储空闲时间段
List
<
OccupyInfoDetail
>
leisureTime
=
new
ArrayList
<>();
if
(
CollectionUtils
.
isEmpty
(
occupyInfos
))
{
long
minutes
=
Duration
.
between
(
startTime
,
endTime
).
abs
().
toMinutes
();
OccupyInfoDetail
occupyInfo
=
new
OccupyInfoDetail
(
startTime
,
endTime
,
minutes
);
leisureTime
.
add
(
occupyInfo
);
return
leisureTime
;
}
//空闲时间
List
<
Long
>
idlePeriods
=
new
ArrayList
<>();
LocalDateTime
preLast
=
startTime
;
for
(
OccupyInfo
o
:
occupyInfos
)
{
if
(
o
.
getBeginTime
().
isAfter
(
preLast
))
{
idlePeriods
.
add
(
Duration
.
between
(
startTime
,
o
.
getBeginTime
()).
abs
().
toMinutes
());
long
duraionMiu
=
Duration
.
between
(
startTime
,
o
.
getBeginTime
()).
abs
().
toMinutes
();
leisureTime
.
add
(
new
OccupyInfoDetail
(
startTime
,
o
.
getBeginTime
(),
duraionMiu
));
}
preLast
=
o
.
getEndTime
();
}
if
(
preLast
.
isBefore
(
endTime
))
{
idlePeriods
.
add
(
Duration
.
between
(
preLast
,
endTime
).
abs
().
toMinutes
());
long
duraionMiu
=
Duration
.
between
(
preLast
,
endTime
).
abs
().
toMinutes
();
leisureTime
.
add
(
new
OccupyInfoDetail
(
preLast
,
endTime
,
duraionMiu
));
}
return
org
.
springframework
.
util
.
CollectionUtils
.
isEmpty
(
idlePeriods
)
?
Duration
.
between
(
startTime
,
endTime
).
abs
().
toMinutes
()
:
Collections
.
max
(
idlePeriods
)
;
return
leisureTime
;
}
...
...
@@ -144,6 +151,59 @@ public class CapacityUtils {
}
}
// 定义一个方法,接受一个OccupyInfoDetail列表,返回它们的交集列表
public
static
List
<
OccupyInfoDetail
>
intersect
(
List
<
OccupyInfoDetail
>
timeSlots
)
{
// 如果列表为空或只有一个元素,直接返回原列表
if
(
timeSlots
==
null
||
timeSlots
.
size
()
<=
1
)
{
return
timeSlots
;
}
// 否则,使用Stream API进行处理
return
timeSlots
.
stream
()
// 对列表中的每个元素进行两两组合,得到一个二元组列表
.
flatMap
(
a
->
timeSlots
.
stream
().
map
(
b
->
new
AbstractMap
.
SimpleEntry
<>(
a
,
b
)))
// 过滤掉自身和重复的组合,即保证a不等于b且a在b之前
.
filter
(
entry
->
!
entry
.
getKey
().
equals
(
entry
.
getValue
())
&&
timeSlots
.
indexOf
(
entry
.
getKey
())
<
timeSlots
.
indexOf
(
entry
.
getValue
()))
// 对每个组合计算交集,并过滤掉null值
.
map
(
entry
->
entry
.
getKey
().
intersection
(
entry
.
getValue
())).
filter
(
Objects:
:
nonNull
)
// 去除重复的交集,并收集到一个列表中
.
distinct
().
collect
(
Collectors
.
toList
());
}
/**
* 定义一个方法,接受一个OccupyInfoDetail列表,返回它们的并集列表
* 1. 将所有时间片按照开始时间从小到大排序。
* 2. 创建一个空的结果列表,用于存放合并后的时间片。
* 3. 遍历排序后的时间片列表,对于每一个时间片,执行以下操作:
* - 如果结果列表为空,或者当前时间片的开始时间大于结果列表中最后一个时间片的结束时间,说明当前时间片与结果列表中的任何一个时间片都不重叠,直接将当前时间片加入结果列表。
* - 否则,说明当前时间片与结果列表中最后一个时间片有重叠部分,将当前时间片与结果列表中最后一个时间片合并成一个新的时间片,更新结果列表中最后一个时间片为新的时间片。合并的方法是取两个时间片开始时间的较小值作为新的开始时间,取两个时间片结束时间的较大值作为新的结束时间。
* 4. 返回结果列表作为最终的并集计算结果。
*/
public
static
List
<
OccupyInfoDetail
>
calculateUnion
(
List
<
OccupyInfoDetail
>
timeSlots
)
{
return
timeSlots
.
stream
()
.
distinct
()
.
sorted
()
.
reduce
(
new
ArrayList
<
OccupyInfoDetail
>(),
(
result
,
current
)
->
{
if
(
result
.
isEmpty
())
{
result
.
add
(
current
);
}
else
{
OccupyInfoDetail
last
=
result
.
get
(
result
.
size
()
-
1
);
if
(
last
.
getEndTime
().
compareTo
(
current
.
getBeginTime
())
>=
0
)
{
result
.
set
(
result
.
size
()
-
1
,
new
OccupyInfoDetail
(
last
.
getBeginTime
(),
last
.
getEndTime
().
compareTo
(
current
.
getEndTime
())
>
0
?
last
.
getEndTime
()
:
current
.
getEndTime
()));
}
else
{
result
.
add
(
current
);
}
}
return
result
;
},
(
a
,
b
)
->
a
)
.
stream
()
.
collect
(
ArrayList:
:
new
,
ArrayList:
:
add
,
ArrayList:
:
addAll
);
}
public
static
CapacityQueryDTO
.
Segment
caculateTargetTimeSlice
(
int
totalTakeTime
,
String
timeSliceName
,
List
<
CapacityEngineerSliceUsedEntity
>
engineerTimeSlice
,
LocalTime
targetStartTime
,
...
...
@@ -153,20 +213,29 @@ public class CapacityUtils {
TimeSliceEntity
timeSlice
=
t
.
getTimmeSlice
();
LocalTime
sliceStartHour
=
LocalTime
.
parse
(
timeSlice
.
getStart
(),
DateUtil
.
TIME_FORMATTER
);
LocalTime
sliceEndHour
=
LocalTime
.
parse
(
timeSlice
.
getEnd
(),
DateUtil
.
TIME_FORMATTER
);
return
(
targetStartTime
.
isAfter
(
sliceStartHour
)
&&
targetEndTime
.
isBefore
(
sliceEndHour
))
||
(
targetStartTime
.
equals
(
sliceStartHour
)
||
targetEndTime
.
equals
(
sliceEndHour
));
return
!(
targetStartTime
.
isAfter
(
sliceEndHour
)
||
targetEndTime
.
isBefore
(
sliceStartHour
));
}).
collect
(
Collectors
.
toList
());
CapacityQueryDTO
.
Segment
segment
=
new
CapacityQueryDTO
.
Segment
();
segment
.
setName
(
timeSliceName
);
segment
.
setEndTime
(
DateUtil
.
toDate
(
LocalDateTime
.
of
(
targetDate
,
targetEndTime
)));
segment
.
setBeginTime
(
DateUtil
.
toDate
(
LocalDateTime
.
of
(
targetDate
,
targetStartTime
)));
if
(!
org
.
apache
.
commons
.
collections4
.
CollectionUtils
.
isEmpty
(
collect
))
{
OptionalLong
optionalLong
=
collect
.
stream
().
mapToLong
(
t
->
{
Long
maxDuration
=
t
.
getMaxDuration
();
return
Objects
.
isNull
(
maxDuration
)
?
0L
:
maxDuration
;
}).
max
();
long
maxDuration
=
optionalLong
.
isEmpty
()
?
0
:
optionalLong
.
getAsLong
();
if
(!
CollectionUtils
.
isEmpty
(
collect
))
{
//时间区间范围空闲时间段
//按人分组
Map
<
String
,
List
<
CapacityEngineerSliceUsedEntity
>>
engineerSliceMap
=
collect
.
stream
()
.
collect
(
Collectors
.
groupingBy
(
CapacityEngineerSliceUsedEntity:
:
getEngineerCode
));
//计算最大空闲时间
List
<
Long
>
engineerMaxDurationList
=
new
ArrayList
<>();
engineerSliceMap
.
forEach
((
engineerCode
,
t
)
->
{
long
engineerMaxDuration
=
t
.
stream
().
map
(
CapacityEngineerSliceUsedEntity:
:
getDurationTime
)
.
flatMap
(
Collection:
:
stream
)
.
mapToLong
(
OccupyInfoDetail:
:
getDuration
)
.
sum
();
engineerMaxDurationList
.
add
(
engineerMaxDuration
);
});
long
maxDuration
=
Collections
.
max
(
engineerMaxDurationList
);
segment
.
setMaxDuration
(
maxDuration
);
long
remain
=
collect
.
stream
().
mapToLong
(
CapacityEngineerSliceUsedEntity:
:
getCapLeft
).
sum
();
segment
.
setRemain
(
remain
);
...
...
project-order/src/main/java/com/dituhui/pea/order/common/OccupyInfo.java
View file @
22db7b1
...
...
@@ -12,6 +12,6 @@ import java.time.LocalDateTime;
@AllArgsConstructor
@NoArgsConstructor
public
class
OccupyInfo
{
pr
ivate
LocalDateTime
beginTime
;
pr
ivate
LocalDateTime
endTime
;
pr
otected
LocalDateTime
beginTime
;
pr
otected
LocalDateTime
endTime
;
}
project-order/src/main/java/com/dituhui/pea/order/common/OccupyInfoDetail.java
0 → 100644
View file @
22db7b1
package
com
.
dituhui
.
pea
.
order
.
common
;
import
lombok.Data
;
import
lombok.EqualsAndHashCode
;
import
lombok.NoArgsConstructor
;
import
lombok.experimental.Accessors
;
import
java.time.LocalDateTime
;
import
java.util.ArrayList
;
import
java.util.List
;
@EqualsAndHashCode
(
callSuper
=
true
)
@Data
@Accessors
(
chain
=
true
)
@NoArgsConstructor
public
class
OccupyInfoDetail
extends
OccupyInfo
implements
Comparable
<
OccupyInfoDetail
>
{
/**
* 时间片时长(分钟)
*/
private
long
duration
;
public
OccupyInfoDetail
(
LocalDateTime
beginTime
,
LocalDateTime
endTime
,
long
duration
)
{
super
(
beginTime
,
endTime
);
this
.
duration
=
duration
;
}
public
OccupyInfoDetail
(
LocalDateTime
beginTime
,
LocalDateTime
endTime
)
{
super
(
beginTime
,
endTime
);
}
// 判断两个时间片是否有交集
public
boolean
overlaps
(
OccupyInfoDetail
other
)
{
// 如果一个时间片的开始时间在另一个时间片的结束时间之后,或者一个时间片的结束时间在另一个时间片的开始时间之前,那么他们没有交集
return
!(
this
.
beginTime
.
isAfter
(
other
.
endTime
)
||
this
.
endTime
.
isBefore
(
other
.
beginTime
));
}
// 计算两个时间片的交集
public
OccupyInfoDetail
intersection
(
OccupyInfoDetail
other
)
{
// 如果两个时间片没有交集,返回null
if
(!
this
.
overlaps
(
other
))
{
return
null
;
}
// 否则,返回一个新的时间片,其开始时间是两个时间片中较晚的开始时间,其结束时间是两个时间片中较早的结束时间
return
new
OccupyInfoDetail
(
this
.
beginTime
.
isAfter
(
other
.
beginTime
)
?
this
.
beginTime
:
other
.
beginTime
,
this
.
endTime
.
isBefore
(
other
.
endTime
)
?
this
.
endTime
:
other
.
endTime
);
}
@Override
public
int
compareTo
(
OccupyInfoDetail
o
)
{
return
this
.
beginTime
.
compareTo
(
o
.
beginTime
);
}
}
project-order/src/main/java/com/dituhui/pea/order/controller/PeaApiController.java
View file @
22db7b1
package
com
.
dituhui
.
pea
.
order
.
controller
;
import
com.dituhui.pea.common.BusinessException
;
import
com.dituhui.pea.common.Result
;
import
com.dituhui.pea.enums.StatusCodeEnum
;
import
com.dituhui.pea.order.common.jackson.DateUtil
;
...
...
@@ -47,6 +48,7 @@ import java.util.Date;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Objects
;
import
java.util.Random
;
import
java.util.stream.Collectors
;
...
...
@@ -124,8 +126,17 @@ public class PeaApiController {
List
<
CapacityQueryDTO
.
Service
>
convertService
=
services
.
stream
()
.
map
(
source
->
{
TypeCodeCheckTableEntity
brand
=
tableCodeCheckDao
.
findByTypeAndCode
(
"BRAND"
,
source
.
getBrand
());
if
(
Objects
.
isNull
(
brand
))
{
throw
new
BusinessException
(
"查询不到:"
+
source
.
getBrand
()
+
"对应的品牌"
);
}
TypeCodeCheckTableEntity
type
=
tableCodeCheckDao
.
findByTypeAndCode
(
"TYPE"
,
source
.
getProductType
());
if
(
Objects
.
isNull
(
type
))
{
throw
new
BusinessException
(
"查询不到:"
+
source
.
getProductType
()
+
"对应的产品类型"
);
}
TypeCodeCheckTableEntity
skill
=
tableCodeCheckDao
.
findByTypeAndCode
(
"SKILL"
,
source
.
getServiceType
());
if
(
Objects
.
isNull
(
skill
))
{
throw
new
BusinessException
(
"查询不到:"
+
source
.
getServiceType
()
+
"对应的技能"
);
}
CapacityQueryDTO
.
Service
service
=
new
CapacityQueryDTO
.
Service
();
service
.
setBrand
(
fixBrand
(
brand
.
getName
()));
...
...
project-order/src/main/java/com/dituhui/pea/order/dto/param/BaseLocation.java
View file @
22db7b1
...
...
@@ -11,12 +11,12 @@ public class BaseLocation {
/**
* 地址纬度
*/
@NotNull
@NotNull
(
message
=
"地址纬度必填"
)
private
Double
latitude
;
/**
* 地址经度
*/
@NotNull
@NotNull
(
message
=
"地址经度必填"
)
private
Double
longitude
;
}
project-order/src/main/java/com/dituhui/pea/order/dto/param/CapacityQueryDTO.java
View file @
22db7b1
...
...
@@ -36,20 +36,20 @@ public class CapacityQueryDTO {
* 地址坐标信息
*/
@Valid
@NotNull
@NotNull
(
message
=
"地址坐标信息不能为空"
)
private
Location
location
;
/**
* 查询起始日期
*/
@NotNull
@NotNull
(
message
=
" 查询起始日期不能为空, 格式:yyyy-MM-dd "
)
@DateTimeFormat
(
pattern
=
"yyyy-MM-dd"
)
@JsonFormat
(
pattern
=
"yyyy-MM-dd"
,
timezone
=
"GMT+8"
)
private
Date
beginDate
;
/**
* 查询结束日期
*/
@NotNull
@NotNull
(
message
=
" 查询结束日期不能为空, 格式:yyyy-MM-dd "
)
@DateTimeFormat
(
pattern
=
"yyyy-MM-dd"
)
@JsonFormat
(
pattern
=
"yyyy-MM-dd"
,
timezone
=
"GMT+8"
)
private
Date
endDate
;
...
...
@@ -138,7 +138,7 @@ public class CapacityQueryDTO {
private
long
maxDuration
;
/**
* 容量名称 全天/上午/下午/时间段
* 容量名称 全天/上午/下午/
晚上/
时间段
*/
private
String
name
;
...
...
@@ -177,18 +177,18 @@ public class CapacityQueryDTO {
/**
* 品牌 (CODE)
*/
@NotBlank
@NotBlank
(
message
=
"品牌(code)不能为空"
)
private
String
brand
;
/**
* 产品类型 (CODE)
*/
@NotBlank
@NotBlank
(
message
=
"产品类型(code)不能为空"
)
private
String
productType
;
/**
* 需要的技能 (CODE)
*/
@NotBlank
@NotBlank
(
message
=
"技能(code)不能为空"
)
private
String
serviceType
;
}
}
project-order/src/main/java/com/dituhui/pea/order/dto/param/EngineerCode.java
View file @
22db7b1
...
...
@@ -16,6 +16,6 @@ public class EngineerCode {
/**
* 工程师工号
*/
@NotBlank
@NotBlank
(
message
=
"工程师工号不能为空"
)
protected
String
engineerCode
;
}
project-order/src/main/java/com/dituhui/pea/order/dto/param/EngineerOrderParam.java
View file @
22db7b1
...
...
@@ -14,7 +14,7 @@ public class EngineerOrderParam {
/**
* 工程师工号
*/
@NotBlank
@NotBlank
(
message
=
"工程师工号不能为空"
)
private
String
engineerCode
;
...
...
project-order/src/main/java/com/dituhui/pea/order/entity/CapacityEngineerSliceUsedEntity.java
View file @
22db7b1
package
com
.
dituhui
.
pea
.
order
.
entity
;
import
com.dituhui.pea.order.common.OccupyInfoDetail
;
import
com.vladmihalcea.hibernate.type.json.JsonStringType
;
import
lombok.Getter
;
import
org.hibernate.annotations.GenericGenerator
;
import
org.hibernate.annotations.Type
;
import
org.hibernate.annotations.TypeDef
;
import
javax.persistence.Basic
;
import
javax.persistence.CascadeType
;
...
...
@@ -9,17 +13,18 @@ import javax.persistence.Column;
import
javax.persistence.Entity
;
import
javax.persistence.FetchType
;
import
javax.persistence.GeneratedValue
;
import
javax.persistence.GenerationType
;
import
javax.persistence.Id
;
import
javax.persistence.JoinColumn
;
import
javax.persistence.OneToOne
;
import
javax.persistence.Table
;
import
java.time.LocalDateTime
;
import
java.util.List
;
import
java.util.Objects
;
@Getter
@Entity
@Table
(
name
=
"capacity_engineer_slice_used"
)
@TypeDef
(
name
=
"json"
,
typeClass
=
JsonStringType
.
class
)
public
class
CapacityEngineerSliceUsedEntity
{
@Id
@Column
(
name
=
"id"
)
...
...
@@ -51,11 +56,13 @@ public class CapacityEngineerSliceUsedEntity {
@Column
(
name
=
"cap_left"
)
private
Long
capLeft
;
@Basic
@Column
(
name
=
"order_count"
)
private
Long
orderCount
;
@Basic
@Column
(
name
=
"max_duration"
)
private
Long
maxDuration
;
@Type
(
type
=
"json"
)
@Column
(
name
=
"duration_time"
,
columnDefinition
=
"json"
)
private
List
<
OccupyInfoDetail
>
durationTime
;
@Basic
@Column
(
name
=
"max_duration_type"
)
private
String
maxDurationType
;
...
...
@@ -101,14 +108,15 @@ public class CapacityEngineerSliceUsedEntity {
this
.
capLeft
=
capLeft
;
}
public
void
setOrderCount
(
Long
orderCount
)
{
this
.
orderCount
=
orderCount
;
}
public
void
setMaxDuration
(
Long
maxDuration
)
{
this
.
maxDuration
=
maxDuration
;
}
public
void
setDurationTime
(
List
<
OccupyInfoDetail
>
durationTime
)
{
this
.
durationTime
=
durationTime
;
}
public
void
setMaxDurationType
(
String
maxDurationType
)
{
this
.
maxDurationType
=
maxDurationType
;
}
...
...
@@ -130,11 +138,11 @@ public class CapacityEngineerSliceUsedEntity {
if
(
this
==
o
)
return
true
;
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
())
return
false
;
CapacityEngineerSliceUsedEntity
that
=
(
CapacityEngineerSliceUsedEntity
)
o
;
return
id
==
that
.
id
&&
timmeSlice
==
that
.
timmeSlice
&&
Objects
.
equals
(
workday
,
that
.
workday
)
&&
Objects
.
equals
(
engineerCode
,
that
.
engineerCode
)
&&
Objects
.
equals
(
capTotal
,
that
.
capTotal
)
&&
Objects
.
equals
(
capUsed
,
that
.
capUsed
)
&&
Objects
.
equals
(
capUsedTravel
,
that
.
capUsedTravel
)
&&
Objects
.
equals
(
capLeft
,
that
.
capLeft
)
&&
Objects
.
equals
(
orderCount
,
that
.
orderCount
)
&&
Objects
.
equals
(
maxDuration
,
that
.
maxDuration
)
&&
Objects
.
equals
(
maxDurationType
,
that
.
maxDurationType
)
&&
Objects
.
equals
(
memo
,
that
.
memo
)
&&
Objects
.
equals
(
createTime
,
that
.
createTime
)
&&
Objects
.
equals
(
updateTime
,
that
.
updateTime
);
return
Objects
.
equals
(
id
,
that
.
id
)
&&
Objects
.
equals
(
timmeSlice
,
that
.
timmeSlice
)
&&
Objects
.
equals
(
workday
,
that
.
workday
)
&&
Objects
.
equals
(
engineerCode
,
that
.
engineerCode
)
&&
Objects
.
equals
(
capTotal
,
that
.
capTotal
)
&&
Objects
.
equals
(
capUsed
,
that
.
capUsed
)
&&
Objects
.
equals
(
capUsedTravel
,
that
.
capUsedTravel
)
&&
Objects
.
equals
(
capLeft
,
that
.
capLeft
)
&&
Objects
.
equals
(
maxDuration
,
that
.
maxDuration
)
&&
Objects
.
equals
(
durationTime
,
that
.
durationTime
)
&&
Objects
.
equals
(
maxDurationType
,
that
.
maxDurationType
)
&&
Objects
.
equals
(
memo
,
that
.
memo
)
&&
Objects
.
equals
(
createTime
,
that
.
createTime
)
&&
Objects
.
equals
(
updateTime
,
that
.
updateTime
);
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
id
,
timmeSlice
,
workday
,
engineerCode
,
capTotal
,
capUsed
,
capUsedTravel
,
capLeft
,
orderCount
,
maxDuration
,
maxDurationType
,
memo
,
createTime
,
updateTime
);
return
Objects
.
hash
(
id
,
timmeSlice
,
workday
,
engineerCode
,
capTotal
,
capUsed
,
capUsedTravel
,
capLeft
,
maxDuration
,
durationTime
,
maxDurationType
,
memo
,
createTime
,
updateTime
);
}
}
project-order/src/main/java/com/dituhui/pea/order/scheduler/CalcEngineerCapacityScheduler.java
View file @
22db7b1
...
...
@@ -3,6 +3,7 @@ package com.dituhui.pea.order.scheduler;
import
com.dituhui.pea.order.common.CapacityUtils
;
import
com.dituhui.pea.order.common.DateUtils
;
import
com.dituhui.pea.order.common.OccupyInfo
;
import
com.dituhui.pea.order.common.OccupyInfoDetail
;
import
com.dituhui.pea.order.common.jackson.DateTimeUtil
;
import
com.dituhui.pea.order.common.jackson.DateUtil
;
import
com.dituhui.pea.order.dao.CapacityEngineerCalendarDao
;
...
...
@@ -140,11 +141,14 @@ public class CalcEngineerCapacityScheduler {
//已用容量
long
totalUseTime
=
occupyInfo
.
stream
().
mapToLong
(
t
->
Duration
.
between
(
t
.
getEndTime
(),
t
.
getBeginTime
()).
abs
().
toMinutes
()).
sum
();
//最大连续时长
Long
maxRemainBlock
=
CapacityUtils
.
getMaxRemainBlock
(
startTime
,
endTime
,
occupyInfo
);
List
<
OccupyInfoDetail
>
durationTime
=
CapacityUtils
.
getMaxRemainBlock
(
startTime
,
endTime
,
occupyInfo
);
long
maxRemainBlock
=
durationTime
.
stream
().
mapToLong
(
OccupyInfoDetail:
:
getDuration
).
max
().
orElse
(
Duration
.
between
(
startTime
,
endTime
).
abs
().
toMinutes
());
//剩余连续时间段
sliceCap
.
setDurationTime
(
durationTime
);
sliceCap
.
setCapLeft
(
sliceCap
.
getCapTotal
()
-
totalUseTime
);
sliceCap
.
setCapUsed
(
totalUseTime
);
sliceCap
.
setOrderCount
((
long
)
orders
.
size
());
//计算时 存储时间差级(剩余时间段)
sliceCap
.
setMaxDuration
(
maxRemainBlock
);
sliceCap
.
setUpdateTime
(
LocalDateTime
.
now
(
ZoneId
.
of
(
"+8"
)));
}
...
...
project-order/src/main/java/com/dituhui/pea/order/service/impl/CapacityQueryServiceImpl.java
View file @
22db7b1
package
com
.
dituhui
.
pea
.
order
.
service
.
impl
;
import
com.dituhui.pea.common.BusinessException
;
import
com.dituhui.pea.common.Result
;
import
com.dituhui.pea.enums.StatusCodeEnum
;
import
com.dituhui.pea.order.common.CapacityUtils
;
...
...
@@ -135,6 +136,10 @@ public class CapacityQueryServiceImpl implements CapacityQueryService {
allFulfillEngineer
.
addAll
(
engineerInfoEntities
);
}
log
.
info
(
"[matchCapacityData]【符合技能要求的工程师总数为:{} 个】"
,
allFulfillEngineer
.
size
());
if
(
CollectionUtils
.
isEmpty
(
querySkillGroup
))
{
throw
new
BusinessException
(
"查询不到对应的技能组信息"
);
}
//计算所有查询技能的所需耗时 (querySkillGroup)
final
int
totalTakeTime
=
querySkillGroup
.
stream
()
.
mapToInt
(
SkillInfoEntity:
:
getTakeTime
)
...
...
@@ -194,6 +199,14 @@ public class CapacityQueryServiceImpl implements CapacityQueryService {
//查询对应的技能信息
SkillInfoEntity
skillInfo
=
skillInfoDao
.
getByBrandAndTypeAndSkill
(
service
.
getBrand
(),
service
.
getProductType
(),
service
.
getServiceType
());
// 查询不到技能组 直接返不可用
if
(
Objects
.
isNull
(
skillInfo
))
{
CapacityQueryDTO
.
Segment
segment
=
new
CapacityQueryDTO
.
Segment
();
segment
.
setMaxDuration
(
0
);
segment
.
setRemain
(
0
);
segment
.
setStatus
(
0
);
return
segment
;
}
List
<
CapacityEngineerSliceUsedEntity
>
allEngineerTimeSlice
=
new
CopyOnWriteArrayList
<>();
for
(
EngineerInfoEntity
engineerInfo
:
engineerInfoEntities
)
{
...
...
@@ -236,7 +249,14 @@ public class CapacityQueryServiceImpl implements CapacityQueryService {
//查询对应的技能信息
SkillInfoEntity
skillInfo
=
skillInfoDao
.
getByBrandAndTypeAndSkill
(
service
.
getBrand
(),
service
.
getProductType
(),
service
.
getServiceType
());
// 查询不到技能组 直接返不可用
if
(
Objects
.
isNull
(
skillInfo
))
{
CapacityQueryDTO
.
Segment
segment
=
new
CapacityQueryDTO
.
Segment
();
segment
.
setMaxDuration
(
0
);
segment
.
setRemain
(
0
);
segment
.
setStatus
(
0
);
return
segment
;
}
return
CapacityUtils
.
caculateTargetTimeSlice
(
skillInfo
.
getTakeTime
(),
"时间段"
,
new
CopyOnWriteArrayList
<>(
engineerTimeSlice
),
startTime
,
endTime
,
date
);
}
...
...
@@ -353,23 +373,23 @@ public class CapacityQueryServiceImpl implements CapacityQueryService {
.
findByWorkdayAndEngineerCode
(
DateTimeUtil
.
formatDate
(
currentDate
),
engineerInfo
.
getEngineerCode
());
allEngineerTimeSlice
.
addAll
(
engineerTimeSlice
);
}
//计算所有工程师半天类型容量
List
<
CapacityQueryDTO
.
Segment
>
objects
=
new
ArrayList
<>();
if
(
CollectionUtils
.
isNotEmpty
(
halfDayTypeTimeSlice
))
{
List
<
CapacityQueryDTO
.
Segment
>
engineerHalfDay
=
CapacityUtils
.
getEngineerTypeDay
(
halfDayTypeTimeSlice
,
allEngineerTimeSlice
,
currentDate
,
totalTakeTime
);
objects
.
addAll
(
engineerHalfDay
);
}
//计算所有工程师全天天类型容量
if
(
CollectionUtils
.
isNotEmpty
(
allDayTypeTimeSlice
))
{
List
<
CapacityQueryDTO
.
Segment
>
engineerAllDay
=
CapacityUtils
.
getEngineerTypeDay
(
allDayTypeTimeSlice
,
allEngineerTimeSlice
,
currentDate
,
totalTakeTime
);
objects
.
addAll
(
engineerAllDay
);
}
//计算所有工程师半天类型容量
if
(
CollectionUtils
.
isNotEmpty
(
halfDayTypeTimeSlice
))
{
List
<
CapacityQueryDTO
.
Segment
>
engineerHalfDay
=
CapacityUtils
.
getEngineerTypeDay
(
halfDayTypeTimeSlice
,
allEngineerTimeSlice
,
currentDate
,
totalTakeTime
);
objects
.
addAll
(
engineerHalfDay
);
}
//计算所有工程师时间段类型容量
/*
List<CapacityQueryDTO.Segment> timeSliceTwoHour = CapacityUtils.getEngineerTypeDay(timeSliceEntities,
allEngineerTimeSlice, currentDate, totalTakeTime);
*/
/*objects.addAll(timeSliceTwoHour);*/
List
<
CapacityQueryDTO
.
Segment
>
timeSliceTwoHour
=
CapacityUtils
.
getEngineerTypeDay
(
timeSliceEntities
,
allEngineerTimeSlice
,
currentDate
,
totalTakeTime
);
objects
.
addAll
(
timeSliceTwoHour
);
CapacityQueryDTO
.
Data
data
=
new
CapacityQueryDTO
.
Data
();
data
.
setDate
(
DateUtil
.
toDate
(
currentDate
));
data
.
setSegments
(
objects
);
...
...
project-order/src/test/java/com/dituhui/pea/order/common/CapacityUtilsTest.java
0 → 100644
View file @
22db7b1
package
com
.
dituhui
.
pea
.
order
.
common
;
import
org.junit.jupiter.api.Assertions
;
import
org.junit.jupiter.api.Test
;
import
org.junit.jupiter.api.extension.ExtendWith
;
import
org.mockito.junit.jupiter.MockitoExtension
;
import
java.time.Duration
;
import
java.time.LocalDate
;
import
java.time.LocalDateTime
;
import
java.time.LocalTime
;
import
java.util.ArrayList
;
import
java.util.List
;
@ExtendWith
(
MockitoExtension
.
class
)
public
class
CapacityUtilsTest
{
@Test
public
void
testMaxRemainBlock
()
{
LocalDateTime
sliceStart
=
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
8
,
0
));
LocalDateTime
sliceEnd
=
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
9
,
0
));
OccupyInfo
occupyInfo
=
new
OccupyInfo
()
.
setBeginTime
(
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
8
,
0
)))
.
setEndTime
(
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
8
,
25
)));
ArrayList
<
OccupyInfo
>
occupyInfos
=
new
ArrayList
<>();
occupyInfos
.
add
(
occupyInfo
);
List
<
OccupyInfoDetail
>
remainBlock
=
CapacityUtils
.
getMaxRemainBlock
(
sliceStart
,
sliceEnd
,
occupyInfos
);
Assertions
.
assertEquals
(
35
,
remainBlock
.
stream
().
mapToLong
(
OccupyInfoDetail:
:
getDuration
).
max
().
orElse
(
Duration
.
between
(
sliceStart
,
sliceEnd
).
abs
().
toMinutes
()));
occupyInfos
.
clear
();
occupyInfos
.
add
(
new
OccupyInfo
()
.
setBeginTime
(
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
8
,
10
)))
.
setEndTime
(
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
8
,
25
))));
remainBlock
=
CapacityUtils
.
getMaxRemainBlock
(
sliceStart
,
sliceEnd
,
occupyInfos
);
Assertions
.
assertEquals
(
35
,
remainBlock
.
stream
().
mapToLong
(
OccupyInfoDetail:
:
getDuration
).
max
().
orElse
(
Duration
.
between
(
sliceStart
,
sliceEnd
).
abs
().
toMinutes
()));
occupyInfos
.
clear
();
occupyInfos
.
add
(
new
OccupyInfo
()
.
setBeginTime
(
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
8
,
20
)))
.
setEndTime
(
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
8
,
40
))));
remainBlock
=
CapacityUtils
.
getMaxRemainBlock
(
sliceStart
,
sliceEnd
,
occupyInfos
);
Assertions
.
assertEquals
(
20
,
remainBlock
.
stream
().
mapToLong
(
OccupyInfoDetail:
:
getDuration
).
max
().
orElse
(
Duration
.
between
(
sliceStart
,
sliceEnd
).
abs
().
toMinutes
()));
}
@Test
public
void
calculateUnionTest
()
{
//三个时间片[9:00, 10:00],[9:30, 11:00]和[10:30, 12:00],那么它们的并集计算结果是[9:00, 12:00]
List
<
OccupyInfoDetail
>
occupyInfoDetails
=
new
ArrayList
<>();
occupyInfoDetails
.
add
(
new
OccupyInfoDetail
(
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
9
,
0
)
),
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
10
,
0
))));
occupyInfoDetails
.
add
(
new
OccupyInfoDetail
(
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
9
,
30
)
),
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
11
,
0
))));
occupyInfoDetails
.
add
(
new
OccupyInfoDetail
(
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
10
,
30
)
),
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
12
,
0
))));
List
<
OccupyInfoDetail
>
occupyInfoDetails1
=
CapacityUtils
.
calculateUnion
(
occupyInfoDetails
);
Assertions
.
assertEquals
(
1
,
occupyInfoDetails1
.
size
());
OccupyInfoDetail
unionOccupyInfo
=
occupyInfoDetails1
.
get
(
0
);
Assertions
.
assertEquals
(
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
12
,
0
)),
unionOccupyInfo
.
getEndTime
());
Assertions
.
assertEquals
(
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
9
,
0
)),
unionOccupyInfo
.
getBeginTime
());
occupyInfoDetails
.
clear
();
occupyInfoDetails
.
add
(
new
OccupyInfoDetail
(
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
9
,
0
)
),
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
10
,
0
))));
occupyInfoDetails
.
add
(
new
OccupyInfoDetail
(
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
9
,
30
)
),
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
11
,
0
))));
occupyInfoDetails
.
add
(
new
OccupyInfoDetail
(
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
11
,
30
)
),
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
12
,
0
))));
occupyInfoDetails1
=
CapacityUtils
.
calculateUnion
(
occupyInfoDetails
);
Assertions
.
assertEquals
(
2
,
occupyInfoDetails1
.
size
());
}
}
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