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 c9ea6eb7
authored
Nov 02, 2023
by
刘鑫
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix(容量): 时间片最大容量计算
1 parent
4fb7e617
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
186 additions
and
12 deletions
project-order/src/main/java/com/dituhui/pea/order/common/CapacityUtils.java
project-order/src/main/java/com/dituhui/pea/order/common/OccupyInfoDetail.java
project-order/src/test/java/com/dituhui/pea/order/common/CapacityUtilsTest.java
project-order/src/main/java/com/dituhui/pea/order/common/CapacityUtils.java
View file @
c9ea6eb
...
@@ -19,14 +19,15 @@ import java.time.Duration;
...
@@ -19,14 +19,15 @@ import java.time.Duration;
import
java.time.LocalDate
;
import
java.time.LocalDate
;
import
java.time.LocalDateTime
;
import
java.time.LocalDateTime
;
import
java.time.LocalTime
;
import
java.time.LocalTime
;
import
java.util.AbstractMap
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.Collection
;
import
java.util.Collections
;
import
java.util.Collections
;
import
java.util.Comparator
;
import
java.util.Comparator
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Objects
;
import
java.util.Objects
;
import
java.util.Optional
;
import
java.util.Optional
;
import
java.util.OptionalLong
;
import
java.util.concurrent.ExecutionException
;
import
java.util.concurrent.ExecutionException
;
import
java.util.concurrent.ForkJoinPool
;
import
java.util.concurrent.ForkJoinPool
;
import
java.util.concurrent.ForkJoinTask
;
import
java.util.concurrent.ForkJoinTask
;
...
@@ -101,7 +102,7 @@ public class CapacityUtils {
...
@@ -101,7 +102,7 @@ public class CapacityUtils {
}
}
public
static
List
<
OccupyInfoDetail
>
getMaxRemainBlock
(
LocalDateTime
startTime
,
LocalDateTime
endTime
,
List
<
OccupyInfo
>
occupyInfos
)
{
public
static
List
<
OccupyInfoDetail
>
getMaxRemainBlock
(
LocalDateTime
startTime
,
LocalDateTime
endTime
,
List
<
OccupyInfo
>
occupyInfos
)
{
//存储空闲时间段
//存储空闲时间段
List
<
OccupyInfoDetail
>
leisureTime
=
new
ArrayList
<>();
List
<
OccupyInfoDetail
>
leisureTime
=
new
ArrayList
<>();
if
(
CollectionUtils
.
isEmpty
(
occupyInfos
))
{
if
(
CollectionUtils
.
isEmpty
(
occupyInfos
))
{
...
@@ -121,7 +122,7 @@ public class CapacityUtils {
...
@@ -121,7 +122,7 @@ public class CapacityUtils {
}
}
if
(
preLast
.
isBefore
(
endTime
))
{
if
(
preLast
.
isBefore
(
endTime
))
{
long
duraionMiu
=
Duration
.
between
(
preLast
,
endTime
).
abs
().
toMinutes
();
long
duraionMiu
=
Duration
.
between
(
preLast
,
endTime
).
abs
().
toMinutes
();
leisureTime
.
add
(
new
OccupyInfoDetail
(
preLast
,
endTime
,
duraionMiu
));
leisureTime
.
add
(
new
OccupyInfoDetail
(
preLast
,
endTime
,
duraionMiu
));
}
}
return
leisureTime
;
return
leisureTime
;
}
}
...
@@ -150,6 +151,59 @@ public class CapacityUtils {
...
@@ -150,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
,
public
static
CapacityQueryDTO
.
Segment
caculateTargetTimeSlice
(
int
totalTakeTime
,
String
timeSliceName
,
List
<
CapacityEngineerSliceUsedEntity
>
engineerTimeSlice
,
List
<
CapacityEngineerSliceUsedEntity
>
engineerTimeSlice
,
LocalTime
targetStartTime
,
LocalTime
targetStartTime
,
...
@@ -159,20 +213,29 @@ public class CapacityUtils {
...
@@ -159,20 +213,29 @@ public class CapacityUtils {
TimeSliceEntity
timeSlice
=
t
.
getTimmeSlice
();
TimeSliceEntity
timeSlice
=
t
.
getTimmeSlice
();
LocalTime
sliceStartHour
=
LocalTime
.
parse
(
timeSlice
.
getStart
(),
DateUtil
.
TIME_FORMATTER
);
LocalTime
sliceStartHour
=
LocalTime
.
parse
(
timeSlice
.
getStart
(),
DateUtil
.
TIME_FORMATTER
);
LocalTime
sliceEndHour
=
LocalTime
.
parse
(
timeSlice
.
getEnd
(),
DateUtil
.
TIME_FORMATTER
);
LocalTime
sliceEndHour
=
LocalTime
.
parse
(
timeSlice
.
getEnd
(),
DateUtil
.
TIME_FORMATTER
);
return
(
targetStartTime
.
isAfter
(
sliceStartHour
)
&&
targetEndTime
.
isBefore
(
sliceEndHour
))
||
return
!(
targetStartTime
.
isAfter
(
sliceEndHour
)
||
targetEndTime
.
isBefore
(
sliceStartHour
));
(
targetStartTime
.
equals
(
sliceStartHour
)
||
targetEndTime
.
equals
(
sliceEndHour
));
}).
collect
(
Collectors
.
toList
());
}).
collect
(
Collectors
.
toList
());
CapacityQueryDTO
.
Segment
segment
=
new
CapacityQueryDTO
.
Segment
();
CapacityQueryDTO
.
Segment
segment
=
new
CapacityQueryDTO
.
Segment
();
segment
.
setName
(
timeSliceName
);
segment
.
setName
(
timeSliceName
);
segment
.
setEndTime
(
DateUtil
.
toDate
(
LocalDateTime
.
of
(
targetDate
,
targetEndTime
)));
segment
.
setEndTime
(
DateUtil
.
toDate
(
LocalDateTime
.
of
(
targetDate
,
targetEndTime
)));
segment
.
setBeginTime
(
DateUtil
.
toDate
(
LocalDateTime
.
of
(
targetDate
,
targetStartTime
)));
segment
.
setBeginTime
(
DateUtil
.
toDate
(
LocalDateTime
.
of
(
targetDate
,
targetStartTime
)));
if
(!
org
.
apache
.
commons
.
collections4
.
CollectionUtils
.
isEmpty
(
collect
))
{
if
(!
CollectionUtils
.
isEmpty
(
collect
))
{
OptionalLong
optionalLong
=
collect
.
stream
().
mapToLong
(
t
->
{
//时间区间范围空闲时间段
Long
maxDuration
=
t
.
getMaxDuration
();
//按人分组
return
Objects
.
isNull
(
maxDuration
)
?
0L
:
maxDuration
;
Map
<
String
,
List
<
CapacityEngineerSliceUsedEntity
>>
engineerSliceMap
=
collect
.
stream
()
}).
max
();
.
collect
(
Collectors
.
groupingBy
(
CapacityEngineerSliceUsedEntity:
:
getEngineerCode
));
long
maxDuration
=
optionalLong
.
isEmpty
()
?
0
:
optionalLong
.
getAsLong
();
//计算最大空闲时间
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
);
segment
.
setMaxDuration
(
maxDuration
);
long
remain
=
collect
.
stream
().
mapToLong
(
CapacityEngineerSliceUsedEntity:
:
getCapLeft
).
sum
();
long
remain
=
collect
.
stream
().
mapToLong
(
CapacityEngineerSliceUsedEntity:
:
getCapLeft
).
sum
();
segment
.
setRemain
(
remain
);
segment
.
setRemain
(
remain
);
...
...
project-order/src/main/java/com/dituhui/pea/order/common/OccupyInfoDetail.java
View file @
c9ea6eb
...
@@ -6,12 +6,14 @@ import lombok.NoArgsConstructor;
...
@@ -6,12 +6,14 @@ import lombok.NoArgsConstructor;
import
lombok.experimental.Accessors
;
import
lombok.experimental.Accessors
;
import
java.time.LocalDateTime
;
import
java.time.LocalDateTime
;
import
java.util.ArrayList
;
import
java.util.List
;
@EqualsAndHashCode
(
callSuper
=
true
)
@EqualsAndHashCode
(
callSuper
=
true
)
@Data
@Data
@Accessors
(
chain
=
true
)
@Accessors
(
chain
=
true
)
@NoArgsConstructor
@NoArgsConstructor
public
class
OccupyInfoDetail
extends
OccupyInfo
{
public
class
OccupyInfoDetail
extends
OccupyInfo
implements
Comparable
<
OccupyInfoDetail
>
{
/**
/**
* 时间片时长(分钟)
* 时间片时长(分钟)
*/
*/
...
@@ -21,4 +23,28 @@ public class OccupyInfoDetail extends OccupyInfo {
...
@@ -21,4 +23,28 @@ public class OccupyInfoDetail extends OccupyInfo {
super
(
beginTime
,
endTime
);
super
(
beginTime
,
endTime
);
this
.
duration
=
duration
;
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/test/java/com/dituhui/pea/order/common/CapacityUtilsTest.java
0 → 100644
View file @
c9ea6eb
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