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 c5885899
authored
Oct 30, 2023
by
chamberone
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop' of
https://zhangguoping@gitlab.dituhui.com/bsh/project/pr…
…oject.git into develop
2 parents
334fab9e
e9d01980
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
864 additions
and
49 deletions
project-order/src/main/java/com/dituhui/pea/order/common/DateSplit.java
project-order/src/main/java/com/dituhui/pea/order/common/jackson/DateTimeUtil.java
project-order/src/main/java/com/dituhui/pea/order/common/jackson/DateUtil.java
project-order/src/main/java/com/dituhui/pea/order/controller/PeaApiController.java
project-order/src/main/java/com/dituhui/pea/order/dao/EngineerInfoDao.java
project-order/src/main/java/com/dituhui/pea/order/dao/EngineerSliceUsedCapacityDao.java
project-order/src/main/java/com/dituhui/pea/order/dao/TableCodeCheckDao.java
project-order/src/main/java/com/dituhui/pea/order/dao/TimeSliceDao.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/OrderConfirmParam.java
project-order/src/main/java/com/dituhui/pea/order/entity/CapacityEngineerSliceUsedEntity.java
project-order/src/main/java/com/dituhui/pea/order/entity/EngineerInfoEntity.java
project-order/src/main/java/com/dituhui/pea/order/entity/OrderInfoEntity.java
project-order/src/main/java/com/dituhui/pea/order/entity/TimeSliceEntity.java
project-order/src/main/java/com/dituhui/pea/order/entity/TypeCodeCheckTableEntity.java
project-order/src/main/java/com/dituhui/pea/order/scheduler/CalcEngineerCapacityScheduler.java
project-order/src/main/java/com/dituhui/pea/order/scheduler/InitEngineerCapacityScheduler.java
project-order/src/main/java/com/dituhui/pea/order/service/CapacityQueryService.java
project-order/src/main/java/com/dituhui/pea/order/service/impl/CapacityQueryServiceImpl.java
project-order/src/main/java/com/dituhui/pea/order/common/DateSplit.java
0 → 100644
View file @
c588589
package
com
.
dituhui
.
pea
.
order
.
common
;
import
com.dituhui.pea.order.common.jackson.DateUtil
;
import
lombok.AllArgsConstructor
;
import
lombok.Getter
;
import
lombok.RequiredArgsConstructor
;
import
java.time.LocalDateTime
;
import
java.time.LocalTime
;
import
java.util.Date
;
@Getter
@RequiredArgsConstructor
@AllArgsConstructor
public
class
DateSplit
{
private
Date
startDateTime
;
private
Date
endDateTime
;
public
void
setStartDateTime
(
Date
startDateTime
)
{
this
.
startDateTime
=
startDateTime
;
}
public
void
setEndDateTime
(
Date
endDateTime
)
{
this
.
endDateTime
=
endDateTime
;
}
public
LocalDateTime
getStartLocalDateTime
()
{
return
DateUtil
.
fromDate
(
this
.
startDateTime
);
}
public
LocalDateTime
getLocalEndDateTime
()
{
return
DateUtil
.
fromDate
(
this
.
startDateTime
);
}
/**
* 获取开始时间片
*
* @return 开始时间
*/
public
LocalTime
getStartTime
()
{
return
this
.
getStartLocalDateTime
().
toLocalTime
();
}
/**
* 获取结束时间片
*
* @return 结束时间
*/
public
LocalTime
getEndTime
()
{
return
this
.
getLocalEndDateTime
().
toLocalTime
();
}
}
\ No newline at end of file
project-order/src/main/java/com/dituhui/pea/order/common/jackson/DateTimeUtil.java
View file @
c588589
...
...
@@ -4,11 +4,14 @@ import lombok.experimental.UtilityClass;
import
java.time.Duration
;
import
java.time.Instant
;
import
java.time.LocalDate
;
import
java.time.LocalDateTime
;
import
java.time.LocalTime
;
import
java.time.ZoneId
;
import
java.time.format.DateTimeFormatter
;
import
java.time.temporal.Temporal
;
import
java.time.temporal.TemporalAccessor
;
import
java.util.Objects
;
import
java.util.concurrent.TimeUnit
;
/**
...
...
@@ -29,7 +32,7 @@ public class DateTimeUtil {
/**
* 时间格式 HH:mm:ss
*/
public
static
final
DateTimeFormatter
TIME_FORMAT
=
DateTimeFormatter
.
ofPattern
(
DateUtil
.
PATTERN_TIME
);
public
static
final
DateTimeFormatter
TIME_FORMAT
=
DateTimeFormatter
.
ofPattern
(
DateUtil
.
PATTERN_TIME
);
/**
* 日期时间格式化
...
...
@@ -161,4 +164,22 @@ public class DateTimeUtil {
return
result
;
}
/**
* 当前时间是否在时间指定范围内, 包含起始时间<br>
*
* @param time 被检查的时间
* @param beginTime 起始时间
* @param endTime 结束时间
* @return 是否在范围内
* @since 3.0.8
*/
public
static
boolean
isIn
(
LocalTime
time
,
LocalTime
beginTime
,
LocalTime
endTime
)
{
if
((
Objects
.
equals
(
beginTime
,
time
)
||
beginTime
.
isBefore
(
time
))
&&
(
endTime
.
isAfter
(
time
)
||
Objects
.
equals
(
endTime
,
time
)))
{
return
true
;
}
return
false
;
}
}
project-order/src/main/java/com/dituhui/pea/order/common/jackson/DateUtil.java
View file @
c588589
package
com
.
dituhui
.
pea
.
order
.
common
.
jackson
;
import
com.dituhui.pea.order.common.DateSplit
;
import
lombok.experimental.UtilityClass
;
import
org.springframework.util.Assert
;
...
...
@@ -8,6 +9,7 @@ import java.time.Duration;
import
java.time.Instant
;
import
java.time.LocalDate
;
import
java.time.LocalDateTime
;
import
java.time.LocalTime
;
import
java.time.Period
;
import
java.time.ZoneId
;
import
java.time.ZonedDateTime
;
...
...
@@ -15,9 +17,12 @@ import java.time.format.DateTimeFormatter;
import
java.time.temporal.Temporal
;
import
java.time.temporal.TemporalAmount
;
import
java.time.temporal.TemporalQuery
;
import
java.util.ArrayList
;
import
java.util.Calendar
;
import
java.util.Collections
;
import
java.util.Date
;
import
java.util.GregorianCalendar
;
import
java.util.List
;
import
java.util.TimeZone
;
/**
...
...
@@ -495,4 +500,95 @@ public class DateUtil {
}
//CHECKSTYLE:ON
/**
* 按照分钟切割时间区间
*/
public
static
List
<
DateSplit
>
splitByMinute
(
Date
startTime
,
Date
endTime
,
int
intervalMinutes
)
{
if
(
endTime
.
getTime
()
<=
startTime
.
getTime
())
{
return
null
;
}
List
<
DateSplit
>
dateSplits
=
new
ArrayList
<>(
50
);
DateSplit
param
=
new
DateSplit
();
param
.
setStartDateTime
(
startTime
);
param
.
setEndDateTime
(
endTime
);
param
.
setEndDateTime
(
addMinute
(
startTime
,
intervalMinutes
));
while
(
true
)
{
param
.
setStartDateTime
(
startTime
);
Date
tempEndTime
=
addMinute
(
startTime
,
intervalMinutes
);
if
(
tempEndTime
.
getTime
()
>=
endTime
.
getTime
())
{
tempEndTime
=
endTime
;
}
param
.
setEndDateTime
(
tempEndTime
);
dateSplits
.
add
(
new
DateSplit
(
param
.
getStartDateTime
(),
param
.
getEndDateTime
()));
startTime
=
addMinute
(
startTime
,
intervalMinutes
);
if
(
startTime
.
getTime
()
>=
endTime
.
getTime
())
{
break
;
}
if
(
param
.
getEndDateTime
().
getTime
()
>=
endTime
.
getTime
())
{
break
;
}
}
return
dateSplits
;
}
/**
* 按照小时切割时间区间
*
* @param startTime 开始时间
* @param endTime 结束时间
* @param intervalHours 时间片大小 (小时)
* @param splitAdjacency 相邻时间片间隔(小时),此值必须小于等于 'intervalHours' 值且大于等于0
* @return 返回对应的时间片
*/
public
static
List
<
DateSplit
>
splitByHour
(
Date
startTime
,
Date
endTime
,
int
intervalHours
,
int
splitAdjacency
)
{
if
(
endTime
.
getTime
()
<=
startTime
.
getTime
())
{
return
Collections
.
emptyList
();
}
List
<
DateSplit
>
dateSplits
=
new
ArrayList
<>(
60
);
DateSplit
param
=
new
DateSplit
();
param
.
setStartDateTime
(
startTime
);
param
.
setEndDateTime
(
endTime
);
param
.
setEndDateTime
(
addHours
(
startTime
,
intervalHours
));
while
(
true
)
{
param
.
setStartDateTime
(
startTime
);
Date
tempEndTime
=
addHours
(
startTime
,
intervalHours
);
if
(
tempEndTime
.
getTime
()
>=
endTime
.
getTime
())
{
tempEndTime
=
endTime
;
}
param
.
setEndDateTime
(
tempEndTime
);
dateSplits
.
add
(
new
DateSplit
(
param
.
getStartDateTime
(),
param
.
getEndDateTime
()));
startTime
=
addHours
(
startTime
,
splitAdjacency
);
if
(
startTime
.
getTime
()
>=
endTime
.
getTime
())
{
break
;
}
if
(
param
.
getEndDateTime
().
getTime
()
>=
endTime
.
getTime
())
{
break
;
}
}
return
dateSplits
;
}
private
static
Date
addMinute
(
Date
date
,
int
minute
)
{
return
add
(
date
,
Calendar
.
MINUTE
,
minute
);
}
private
static
Date
addHours
(
Date
date
,
int
hours
)
{
return
add
(
date
,
Calendar
.
HOUR_OF_DAY
,
hours
);
}
private
static
Date
add
(
final
Date
date
,
final
int
calendarField
,
final
int
amount
)
{
final
Calendar
c
=
Calendar
.
getInstance
();
c
.
setTime
(
date
);
c
.
add
(
calendarField
,
amount
);
return
c
.
getTime
();
}
}
project-order/src/main/java/com/dituhui/pea/order/controller/PeaApiController.java
View file @
c588589
...
...
@@ -3,23 +3,45 @@ package com.dituhui.pea.order.controller;
import
com.dituhui.pea.common.Result
;
import
com.dituhui.pea.order.common.jackson.DateUtil
;
import
com.dituhui.pea.order.common.jackson.JsonUtil
;
import
com.dituhui.pea.order.dto.param.*
;
import
com.dituhui.pea.order.dao.TableCodeCheckDao
;
import
com.dituhui.pea.order.dto.param.BaseDistance
;
import
com.dituhui.pea.order.dto.param.BaseDistanceParam
;
import
com.dituhui.pea.order.dto.param.CapacityQueryDTO
;
import
com.dituhui.pea.order.dto.param.EngineerCalendarResultDTO
;
import
com.dituhui.pea.order.dto.param.EngineerOrderParam
;
import
com.dituhui.pea.order.dto.param.EstimateDTO
;
import
com.dituhui.pea.order.dto.param.Order
;
import
com.dituhui.pea.order.dto.param.OrderConfirmParam
;
import
com.dituhui.pea.order.dto.param.OrderConfirmResult
;
import
com.dituhui.pea.order.dto.param.OrderDTO
;
import
com.dituhui.pea.order.entity.TypeCodeCheckTableEntity
;
import
com.dituhui.pea.order.service.CapacityQueryService
;
import
com.dituhui.pea.order.service.EngineerCalendarService
;
import
com.dituhui.pea.order.service.OrderCreateService
;
import
com.dituhui.pea.order.service.PeaOuterAPIService
;
import
com.fasterxml.jackson.annotation.JsonFormat
;
import
lombok.RequiredArgsConstructor
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.format.annotation.DateTimeFormat
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestParam
;
import
org.springframework.web.bind.annotation.RestController
;
import
javax.validation.constraints.NotBlank
;
import
javax.validation.constraints.NotNull
;
import
java.io.IOException
;
import
java.time.LocalDate
;
import
java.time.ZoneId
;
import
java.util.*
;
import
java.util.ArrayList
;
import
java.util.Date
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Random
;
import
java.util.stream.Collectors
;
/**
* PEA 对外接口
...
...
@@ -32,8 +54,9 @@ public class PeaApiController {
private
final
EngineerCalendarService
engineerCalendarService
;
private
final
PeaOuterAPIService
peaOuterAPIService
;
@Autowired
private
OrderCreateService
orderCreateService
;
private
final
CapacityQueryService
capacityQueryService
;
private
final
OrderCreateService
orderCreateService
;
private
final
TableCodeCheckDao
tableCodeCheckDao
;
private
static
final
String
capacity
=
"{\"groupId\": \"G100038\", \"params\": {\"beginDate\": \"2023-07-21\", \"endDate\": \"2023-07-27\", \"services\": [{\"brand\": \"博世\", \"productType\": \"多门冰箱\", \"serviceType\": \"商场样机安装\"}], \"location\": {\"addressId\":\"21231231\", \"latitude\": 120.608463, \"longitude\": 31.318442, \"name\": \"江苏省苏州市姑苏区蒋庙前\", \"address\": \"江苏省苏州市姑苏区解放大街123号\"}}, \"takeTime\": 720, \"datas\": [{\"date\": \"2023-07-21\", \"segments\": [{\"maxDuration\": 90, \"name\": \"全天\", \"beginTime\": \"2023-07-21 08:00:00\", \"endTime\": \"2023-07-21 17:59:59\", \"status\": 1, \"remain\": 3500}, {\"maxDuration\": 45, \"name\": \"上午\", \"beginTime\": \"2023-07-21 08:00:00\", \"endTime\": \"2023-07-21 11:59:59\", \"status\": 1, \"remain\": 2500}, {\"maxDuration\": 60, \"name\": \"下午\", \"beginTime\": \"2023-07-21 13:00:00\", \"endTime\": \"2023-07-21 17:59:59\", \"status\": 0, \"remain\": 1000}, {\"maxDuration\": 60, \"name\": \"时间段\", \"beginTime\": \"2023-07-21 13:00:00\", \"endTime\": \"2023-07-21 15:00:00\", \"status\": 1, \"remain\": 480}]}]}"
;
...
...
@@ -83,23 +106,34 @@ public class PeaApiController {
* @return 容量列表
*/
@PostMapping
(
"/capacity/query"
)
public
Result
<
CapacityQueryDTO
.
Result
>
capacityQuery
(
@Validated
@RequestBody
CapacityQueryDTO
.
Request
reqDTO
)
throws
IOException
{
public
Result
<
CapacityQueryDTO
.
Result
>
capacityQuery
(
@Validated
@RequestBody
CapacityQueryDTO
.
Request
reqDTO
)
{
//查询日期起止参数限制为一月
ArrayList
<
String
>
strings
=
new
ArrayList
<>();
strings
.
add
(
half_capacity
);
strings
.
add
(
day_capacity
);
strings
.
add
(
half_capacity2
);
strings
.
add
(
date_capacity
);
Random
random
=
new
Random
();
int
i
=
random
.
nextInt
(
4
);
CapacityQueryDTO
.
Result
result
=
JsonUtil
.
parse
(
strings
.
get
(
i
),
CapacityQueryDTO
.
Result
.
class
).
get
();
result
.
setParams
(
reqDTO
);
return
Result
.
success
(
result
);
LocalDate
startDate
=
reqDTO
.
getBeginDate
().
toInstant
().
atZone
(
ZoneId
.
of
(
"+8"
)).
toLocalDate
();
LocalDate
endDate
=
reqDTO
.
getEndDate
().
toInstant
().
atZone
(
ZoneId
.
of
(
"+8"
)).
toLocalDate
();
List
<
CapacityQueryDTO
.
Service
>
services
=
reqDTO
.
getServices
();
List
<
CapacityQueryDTO
.
Service
>
convertService
=
services
.
stream
()
.
map
(
source
->
{
TypeCodeCheckTableEntity
brand
=
tableCodeCheckDao
.
findByTypeAndCode
(
"BRAND"
,
source
.
getBrand
());
TypeCodeCheckTableEntity
type
=
tableCodeCheckDao
.
findByTypeAndCode
(
"TYPE"
,
source
.
getProductType
());
TypeCodeCheckTableEntity
skill
=
tableCodeCheckDao
.
findByTypeAndCode
(
"SKILL"
,
source
.
getServiceType
());
CapacityQueryDTO
.
Service
service
=
new
CapacityQueryDTO
.
Service
();
service
.
setBrand
(
fixBrand
(
brand
.
getName
()));
service
.
setProductType
(
type
.
getName
());
service
.
setServiceType
(
skill
.
getName
());
return
service
;
}).
collect
(
Collectors
.
toList
());
return
capacityQueryService
.
matchCapacityData
(
convertService
,
reqDTO
.
getLocation
(),
startDate
,
endDate
);
}
private
String
fixBrand
(
String
brand
)
{
if
(!
brand
.
equals
(
"嘉格纳"
))
{
return
"博世/西门子以及其他品牌"
;
}
else
{
return
brand
;
}
}
/**
* 4.2 改派到人容量看板查询
...
...
@@ -117,7 +151,7 @@ public class PeaApiController {
@RequestParam
(
"beginDate"
)
Date
beginDate
,
@DateTimeFormat
(
pattern
=
"yyyy-MM-dd"
)
@JsonFormat
(
pattern
=
"yyyy-MM-dd"
,
timezone
=
"GMT+8"
)
Date
endDate
)
throws
IOException
{
Date
endDate
)
throws
IOException
{
ArrayList
<
String
>
strings
=
new
ArrayList
<>();
strings
.
add
(
half_capacity
);
...
...
project-order/src/main/java/com/dituhui/pea/order/dao/EngineerInfoDao.java
View file @
c588589
...
...
@@ -12,6 +12,7 @@ import org.springframework.data.jpa.repository.Query;
import
org.springframework.stereotype.Repository
;
import
java.util.List
;
import
java.util.Set
;
@Repository
public
interface
EngineerInfoDao
extends
JpaRepository
<
EngineerInfoEntity
,
Integer
>,
JpaSpecificationExecutor
<
EngineerInfoEntity
>
{
...
...
@@ -37,13 +38,48 @@ public interface EngineerInfoDao extends JpaRepository<EngineerInfoEntity, Integ
return
(
root
,
query
,
criteriaBuilder
)
->
root
.
get
(
"engineerCode"
).
in
(
engineerCodes
);
}
/**
* 根据技能、产品、产品类型 分站ID获取分站下用户对应技能的技术员
*
* @param brand 产品
* @param productType 产品类型
* @param skill 技能
* @param groupId 分站ID
* @return 工程师信息
*/
@Query
(
value
=
"SELECT ei.* FROM skill_info si LEFT JOIN skill_group sg ON sg.skill_group_code =si.skill_group_code "
+
" LEFT JOIN engineer_skill_group esg ON sg.skill_group_code = esg.skill_group_code "
+
" LEFT JOIN engineer_info ei ON esg.engineer_code = ei.engineer_code "
+
" WHERE si.brand = :brand AND si.type= :productType AND si.skill = :skill "
+
" AND group_id = :groupId "
,
nativeQuery
=
true
)
Set
<
EngineerInfoEntity
>
listByBrandAndTypeAndSkillAndGroupId
(
@Param
(
"brand"
)
String
brand
,
@Param
(
"productType"
)
String
productType
,
@Param
(
"skill"
)
String
skill
,
@Param
(
"groupId"
)
String
groupId
);
/**
* 根据技能、产品、产品类型 工作队获取分站下用户对应技能的技术员
*
* @param brand 产品
* @param productType 产品类型
* @param skill 技能
* @param teamId 工作队ID
* @return 工程师信息
*/
@Query
(
value
=
"SELECT ei.* FROM skill_info si LEFT JOIN skill_group sg ON sg.skill_group_code =si.skill_group_code \n"
+
" LEFT JOIN engineer_skill_group esg ON sg.skill_group_code = esg.skill_group_code \n"
+
" LEFT JOIN engineer_info ei ON esg.engineer_code = ei.engineer_code\n"
+
" LEFT JOIN org_team_engineer ote ON ote.engineer_code = ei.engineer_code \n"
+
" WHERE si.brand = :brand AND si.type= :productType AND si.skill = :skill \n"
+
" AND ote.team_id = :teamId "
,
nativeQuery
=
true
)
Set
<
EngineerInfoEntity
>
listByBrandAndTypeAndSkillAndTeamId
(
@Param
(
"brand"
)
String
brand
,
@Param
(
"productType"
)
String
productType
,
@Param
(
"skill"
)
String
skill
,
@Param
(
"teamId"
)
String
teamId
);
@Query
(
value
=
"SELECT ei.* from engineer_info ei left join engineer_skill_group esg on ei.engineer_code = esg.engineer_code "
+
"left join skill_info si on si.skill_group_code = esg.skill_group_code left join map_layer_customize mlc on mlc.layer_id = si.layer_id "
+
" WHERE si.brand = :brand and si.`type` = :productType and si.skill_code = :skillCode and ei.group_id in ( :teamIds ) "
+
" order by mlc.priority "
,
nativeQuery
=
true
)
List
<
EngineerInfoEntity
>
listBrandAndSkillCodeAndTeamIdIn
(
@Param
(
"brand"
)
String
brand
,
@Param
(
"productType"
)
String
productType
,
@Param
(
"skillCode"
)
String
skillCode
,
@Param
(
"teamIds"
)
List
<
String
>
teamIds
);
@Param
(
"skillCode"
)
String
skillCode
,
@Param
(
"teamIds"
)
List
<
String
>
teamIds
);
@Query
(
value
=
"SELECT ei.* from engineer_info ei left join engineer_skill_group esg on ei.engineer_code = esg.engineer_code "
+
...
...
@@ -51,7 +87,7 @@ public interface EngineerInfoDao extends JpaRepository<EngineerInfoEntity, Integ
" WHERE si.brand = :brand and si.`type` = :productType and si.skill = :skill and ei.group_id in ( :teamIds ) "
+
" order by mlc.priority "
,
nativeQuery
=
true
)
List
<
EngineerInfoEntity
>
listBrandAndSkillAndTeamIdIn
(
@Param
(
"brand"
)
String
brand
,
@Param
(
"productType"
)
String
productType
,
@Param
(
"skill"
)
String
skill
,
@Param
(
"teamIds"
)
List
<
String
>
teamIds
);
@Param
(
"skill"
)
String
skill
,
@Param
(
"teamIds"
)
List
<
String
>
teamIds
);
@Query
(
value
=
"SELECT ei.* from engineer_info ei left join engineer_skill_group esg on ei.engineer_code = esg.engineer_code "
+
...
...
@@ -59,5 +95,5 @@ public interface EngineerInfoDao extends JpaRepository<EngineerInfoEntity, Integ
" WHERE si.brand = :brand and si.`type` = :productType and si.skill = :skill and ei.engineer_code in ( :engineerCodes ) "
+
" order by mlc.priority "
,
nativeQuery
=
true
)
List
<
EngineerInfoEntity
>
listBrandAndSkillAndEngineerCodes
(
@Param
(
"brand"
)
String
brand
,
@Param
(
"productType"
)
String
productType
,
@Param
(
"skill"
)
String
skill
,
@Param
(
"engineerCodes"
)
List
<
String
>
engineerCodes
);
@Param
(
"skill"
)
String
skill
,
@Param
(
"engineerCodes"
)
List
<
String
>
engineerCodes
);
}
project-order/src/main/java/com/dituhui/pea/order/dao/EngineerSliceUsedCapacityDao.java
0 → 100644
View file @
c588589
package
com
.
dituhui
.
pea
.
order
.
dao
;
import
com.dituhui.pea.order.entity.CapacityEngineerSliceUsedEntity
;
import
org.springframework.data.jpa.repository.JpaRepository
;
import
java.util.List
;
public
interface
EngineerSliceUsedCapacityDao
extends
JpaRepository
<
CapacityEngineerSliceUsedEntity
,
Long
>
{
List
<
CapacityEngineerSliceUsedEntity
>
findByWorkdayAndEngineerCode
(
String
workDay
,
String
engineerCode
);
}
project-order/src/main/java/com/dituhui/pea/order/dao/TableCodeCheckDao.java
0 → 100644
View file @
c588589
package
com
.
dituhui
.
pea
.
order
.
dao
;
import
com.dituhui.pea.order.entity.TypeCodeCheckTableEntity
;
import
org.springframework.data.jpa.repository.JpaRepository
;
public
interface
TableCodeCheckDao
extends
JpaRepository
<
TypeCodeCheckTableEntity
,
Integer
>
{
TypeCodeCheckTableEntity
findByTypeAndCode
(
String
type
,
String
code
);
}
project-order/src/main/java/com/dituhui/pea/order/dao/TimeSliceDao.java
0 → 100644
View file @
c588589
package
com
.
dituhui
.
pea
.
order
.
dao
;
import
com.dituhui.pea.order.entity.TimeSliceEntity
;
import
org.springframework.data.jpa.repository.JpaRepository
;
import
java.util.List
;
public
interface
TimeSliceDao
extends
JpaRepository
<
TimeSliceEntity
,
Long
>
{
List
<
TimeSliceEntity
>
findByType
(
String
type
);
}
project-order/src/main/java/com/dituhui/pea/order/dto/param/CapacityQueryDTO.java
View file @
c588589
...
...
@@ -9,7 +9,6 @@ import org.springframework.validation.annotation.Validated;
import
javax.validation.Valid
;
import
javax.validation.constraints.NotBlank
;
import
javax.validation.constraints.NotNull
;
import
java.time.LocalDateTime
;
import
java.util.Date
;
import
java.util.List
;
...
...
@@ -136,7 +135,7 @@ public class CapacityQueryDTO {
/**
* 最大可用时长, 单位: 分钟
*/
private
int
maxDuration
;
private
long
maxDuration
;
/**
* 容量名称 全天/上午/下午/时间段
...
...
@@ -165,7 +164,7 @@ public class CapacityQueryDTO {
/**
* 剩余容量
*/
private
int
remain
;
private
long
remain
;
}
...
...
project-order/src/main/java/com/dituhui/pea/order/dto/param/OrderConfirmParam.java
View file @
c588589
...
...
@@ -26,4 +26,13 @@ public class OrderConfirmParam extends OrderConfirmBaseParam{
@JsonFormat
(
pattern
=
"yyyy-MM-dd HH:mm:ss"
,
timezone
=
"GMT+8"
)
@DateTimeFormat
(
pattern
=
"yyyy-MM-dd HH:mm:ss"
)
private
Date
appointmentTime
;
/**
* 预约加单状态, 预约失败时传递
*
* CONFIRMED 预约成功
* REFUED 客户拒绝
* CANNOT_BE_REACHED 客户联系不上
*/
private
String
reasonForFailure
;
}
project-order/src/main/java/com/dituhui/pea/order/entity/CapacityEngineerSliceUsedEntity.java
0 → 100644
View file @
c588589
package
com
.
dituhui
.
pea
.
order
.
entity
;
import
lombok.Getter
;
import
org.hibernate.annotations.GenericGenerator
;
import
javax.persistence.Basic
;
import
javax.persistence.CascadeType
;
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.Objects
;
@Getter
@Entity
@Table
(
name
=
"capacity_engineer_slice_used"
)
public
class
CapacityEngineerSliceUsedEntity
{
@Id
@Column
(
name
=
"id"
)
@GeneratedValue
(
generator
=
"uuid"
)
@GenericGenerator
(
name
=
"uuid"
,
strategy
=
"uuid"
)
private
String
id
;
@OneToOne
(
targetEntity
=
TimeSliceEntity
.
class
,
cascade
=
{
CascadeType
.
DETACH
},
fetch
=
FetchType
.
EAGER
)
@JoinColumn
(
name
=
"timme_slice"
,
referencedColumnName
=
"id"
)
private
TimeSliceEntity
timmeSlice
;
@Basic
@Column
(
name
=
"workday"
)
private
String
workday
;
@Basic
@Column
(
name
=
"engineer_code"
)
private
String
engineerCode
;
@Basic
@Column
(
name
=
"cap_total"
)
private
Long
capTotal
;
@Basic
@Column
(
name
=
"cap_used"
)
private
Long
capUsed
;
@Basic
@Column
(
name
=
"cap_used_travel"
)
private
Long
capUsedTravel
;
@Basic
@Column
(
name
=
"cap_left"
)
private
Long
capLeft
;
@Basic
@Column
(
name
=
"order_count"
)
private
Long
orderCount
;
@Basic
@Column
(
name
=
"max_duration"
)
private
Long
maxDuration
;
@Basic
@Column
(
name
=
"max_duration_type"
)
private
String
maxDurationType
;
@Basic
@Column
(
name
=
"memo"
)
private
String
memo
;
@Basic
@Column
(
name
=
"create_time"
)
private
LocalDateTime
createTime
;
@Basic
@Column
(
name
=
"update_time"
)
private
LocalDateTime
updateTime
;
public
void
setId
(
String
id
)
{
this
.
id
=
id
;
}
public
void
setTimmeSlice
(
TimeSliceEntity
timmeSlice
)
{
this
.
timmeSlice
=
timmeSlice
;
}
public
void
setWorkday
(
String
workday
)
{
this
.
workday
=
workday
;
}
public
void
setEngineerCode
(
String
engineerCode
)
{
this
.
engineerCode
=
engineerCode
;
}
public
void
setCapTotal
(
Long
capTotal
)
{
this
.
capTotal
=
capTotal
;
}
public
void
setCapUsed
(
Long
capUsed
)
{
this
.
capUsed
=
capUsed
;
}
public
void
setCapUsedTravel
(
Long
capUsedTravel
)
{
this
.
capUsedTravel
=
capUsedTravel
;
}
public
void
setCapLeft
(
Long
capLeft
)
{
this
.
capLeft
=
capLeft
;
}
public
void
setOrderCount
(
Long
orderCount
)
{
this
.
orderCount
=
orderCount
;
}
public
void
setMaxDuration
(
Long
maxDuration
)
{
this
.
maxDuration
=
maxDuration
;
}
public
void
setMaxDurationType
(
String
maxDurationType
)
{
this
.
maxDurationType
=
maxDurationType
;
}
public
void
setMemo
(
String
memo
)
{
this
.
memo
=
memo
;
}
public
void
setCreateTime
(
LocalDateTime
createTime
)
{
this
.
createTime
=
createTime
;
}
public
void
setUpdateTime
(
LocalDateTime
updateTime
)
{
this
.
updateTime
=
updateTime
;
}
@Override
public
boolean
equals
(
Object
o
)
{
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
);
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
id
,
timmeSlice
,
workday
,
engineerCode
,
capTotal
,
capUsed
,
capUsedTravel
,
capLeft
,
orderCount
,
maxDuration
,
maxDurationType
,
memo
,
createTime
,
updateTime
);
}
}
project-order/src/main/java/com/dituhui/pea/order/entity/EngineerInfoEntity.java
View file @
c588589
package
com
.
dituhui
.
pea
.
order
.
entity
;
import
lombok.Data
;
import
lombok.EqualsAndHashCode
;
import
javax.persistence.*
;
import
java.time.LocalDateTime
;
import
java.util.Date
;
@Data
@Entity
@Table
(
name
=
"engineer_info"
)
@Table
(
name
=
"engineer_info"
)
@EqualsAndHashCode
public
class
EngineerInfoEntity
{
/**
* 工程师id
...
...
@@ -112,5 +113,6 @@ public class EngineerInfoEntity {
*/
private
LocalDateTime
updateTime
=
LocalDateTime
.
now
();
public
EngineerInfoEntity
()
{}
public
EngineerInfoEntity
()
{
}
}
project-order/src/main/java/com/dituhui/pea/order/entity/OrderInfoEntity.java
View file @
c588589
...
...
@@ -226,4 +226,12 @@ public class OrderInfoEntity {
*/
@Column
(
name
=
"is_special_time"
)
private
Integer
isSpecialTime
=
0
;
/**
* 申请加单状态,CONFIRMED 预约成功
* REFUSED 客户拒绝
* CANNOT_BE_REACHED 客户联系不上
*/
@Column
(
name
=
"reason_for_failure"
)
private
String
reasonForFailure
;
}
project-order/src/main/java/com/dituhui/pea/order/entity/TimeSliceEntity.java
0 → 100644
View file @
c588589
package
com
.
dituhui
.
pea
.
order
.
entity
;
import
lombok.Getter
;
import
javax.persistence.Basic
;
import
javax.persistence.Column
;
import
javax.persistence.Entity
;
import
javax.persistence.GeneratedValue
;
import
javax.persistence.GenerationType
;
import
javax.persistence.Id
;
import
javax.persistence.Table
;
import
java.time.LocalDateTime
;
import
java.util.Objects
;
@Getter
@Entity
@Table
(
name
=
"time_slice"
)
public
class
TimeSliceEntity
{
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
@Id
@Column
(
name
=
"id"
)
private
Long
id
;
@Basic
@Column
(
name
=
"type"
)
private
String
type
;
@Basic
@Column
(
name
=
"name"
)
private
String
name
;
@Basic
@Column
(
name
=
"start"
)
private
String
start
;
@Basic
@Column
(
name
=
"end"
)
private
String
end
;
@Basic
@Column
(
name
=
"create_time"
)
private
LocalDateTime
createTime
;
@Basic
@Column
(
name
=
"update_time"
)
private
LocalDateTime
updateTime
;
public
void
setId
(
Long
id
)
{
this
.
id
=
id
;
}
public
void
setType
(
String
type
)
{
this
.
type
=
type
;
}
public
void
setName
(
String
name
)
{
this
.
name
=
name
;
}
public
void
setStart
(
String
start
)
{
this
.
start
=
start
;
}
public
void
setEnd
(
String
end
)
{
this
.
end
=
end
;
}
public
void
setCreateTime
(
LocalDateTime
createTime
)
{
this
.
createTime
=
createTime
;
}
public
void
setUpdateTime
(
LocalDateTime
updateTime
)
{
this
.
updateTime
=
updateTime
;
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
return
true
;
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
())
return
false
;
TimeSliceEntity
that
=
(
TimeSliceEntity
)
o
;
return
id
==
that
.
id
&&
Objects
.
equals
(
type
,
that
.
type
)
&&
Objects
.
equals
(
name
,
that
.
name
)
&&
Objects
.
equals
(
start
,
that
.
start
)
&&
Objects
.
equals
(
end
,
that
.
end
)
&&
Objects
.
equals
(
createTime
,
that
.
createTime
)
&&
Objects
.
equals
(
updateTime
,
that
.
updateTime
);
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
id
,
type
,
name
,
start
,
end
,
createTime
,
updateTime
);
}
}
project-order/src/main/java/com/dituhui/pea/order/entity/TypeCodeCheckTableEntity.java
0 → 100644
View file @
c588589
package
com
.
dituhui
.
pea
.
order
.
entity
;
import
lombok.Getter
;
import
javax.persistence.Basic
;
import
javax.persistence.Column
;
import
javax.persistence.Entity
;
import
javax.persistence.GeneratedValue
;
import
javax.persistence.GenerationType
;
import
javax.persistence.Id
;
import
javax.persistence.Table
;
import
java.sql.Timestamp
;
import
java.util.Objects
;
@Getter
@Entity
@Table
(
name
=
"type_code_check_table"
)
public
class
TypeCodeCheckTableEntity
{
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
@Id
@Column
(
name
=
"id"
)
private
Integer
id
;
@Basic
@Column
(
name
=
"type"
)
private
String
type
;
@Basic
@Column
(
name
=
"name"
)
private
String
name
;
@Basic
@Column
(
name
=
"code"
)
private
String
code
;
@Basic
@Column
(
name
=
"create_time"
)
private
Timestamp
createTime
;
@Basic
@Column
(
name
=
"update_time"
)
private
Timestamp
updateTime
;
public
void
setId
(
int
id
)
{
this
.
id
=
id
;
}
public
void
setType
(
String
type
)
{
this
.
type
=
type
;
}
public
void
setName
(
String
name
)
{
this
.
name
=
name
;
}
public
void
setCode
(
String
code
)
{
this
.
code
=
code
;
}
public
void
setCreateTime
(
Timestamp
createTime
)
{
this
.
createTime
=
createTime
;
}
public
void
setUpdateTime
(
Timestamp
updateTime
)
{
this
.
updateTime
=
updateTime
;
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
return
true
;
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
())
return
false
;
TypeCodeCheckTableEntity
that
=
(
TypeCodeCheckTableEntity
)
o
;
return
id
==
that
.
id
&&
Objects
.
equals
(
type
,
that
.
type
)
&&
Objects
.
equals
(
name
,
that
.
name
)
&&
Objects
.
equals
(
code
,
that
.
code
)
&&
Objects
.
equals
(
createTime
,
that
.
createTime
)
&&
Objects
.
equals
(
updateTime
,
that
.
updateTime
);
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
id
,
type
,
name
,
code
,
createTime
,
updateTime
);
}
}
project-order/src/main/java/com/dituhui/pea/order/scheduler/CalcEngineerCapacityScheduler.java
View file @
c588589
package
com
.
dituhui
.
pea
.
order
.
scheduler
;
import
com.dituhui.pea.order.common.DateUtils
;
import
com.dituhui.pea.order.dao.*
;
import
com.dituhui.pea.order.entity.*
;
import
com.dituhui.pea.order.common.jackson.DateTimeUtil
;
import
com.dituhui.pea.order.common.jackson.DateUtil
;
import
com.dituhui.pea.order.dao.CapacityEngineerCalendarDao
;
import
com.dituhui.pea.order.dao.CapacityEngineerStatDao
;
import
com.dituhui.pea.order.dao.EngineerBusinessDao
;
import
com.dituhui.pea.order.dao.EngineerInfoDao
;
import
com.dituhui.pea.order.dao.EngineerSliceUsedCapacityDao
;
import
com.dituhui.pea.order.dao.OrderInfoDao
;
import
com.dituhui.pea.order.dao.TimeSliceDao
;
import
com.dituhui.pea.order.entity.CapacityEngineerCalendarEntity
;
import
com.dituhui.pea.order.entity.CapacityEngineerSliceUsedEntity
;
import
com.dituhui.pea.order.entity.CapacityEngineerStatEntity
;
import
com.dituhui.pea.order.entity.EngineerBusinessEntity
;
import
com.dituhui.pea.order.entity.EngineerInfoEntity
;
import
com.dituhui.pea.order.entity.OrderInfoEntity
;
import
com.dituhui.pea.order.entity.TimeSliceEntity
;
import
lombok.Data
;
import
lombok.experimental.Accessors
;
import
lombok.extern.slf4j.Slf4j
;
...
...
@@ -14,7 +28,13 @@ import org.springframework.stereotype.Component;
import
java.time.Duration
;
import
java.time.LocalDate
;
import
java.time.LocalDateTime
;
import
java.util.*
;
import
java.time.LocalTime
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.Comparator
;
import
java.util.List
;
import
java.util.Set
;
import
java.util.concurrent.TimeUnit
;
import
java.util.stream.Collectors
;
@Slf4j
...
...
@@ -36,6 +56,10 @@ public class CalcEngineerCapacityScheduler {
private
EngineerBusinessDao
engineerBusinessDao
;
@Autowired
private
EngineerInfoDao
engineerInfoDao
;
@Autowired
private
TimeSliceDao
timeSliceDao
;
@Autowired
private
EngineerSliceUsedCapacityDao
engineerSliceUsedCapacityDao
;
@Scheduled
(
cron
=
"${scheduler.calc-engineer-capacity.cron-expr}"
)
public
void
run
()
{
...
...
@@ -58,8 +82,20 @@ public class CalcEngineerCapacityScheduler {
}
private
void
calcOneEngineer
(
String
date
,
String
engineerCode
)
{
CapacityEngineerStatEntity
statEntity
=
capacityEngineerStatDao
.
getByWorkdayAndEngineerCode
(
date
,
engineerCode
);
if
(
statEntity
==
null
)
{
log
.
error
(
"错误:日期[{}]技术员[{}]容量尚未初始化,忽略退出!"
,
date
,
engineerCode
);
return
;
}
Set
<
String
>
ss
=
Set
.
of
(
"CANCELED"
,
"RESCHEDULED"
);
List
<
OrderInfoEntity
>
orders
=
orderInfoDao
.
findByDtAndEngineerCode
(
DateUtils
.
localDateFromStr
(
date
),
engineerCode
);
// 根据capacity_engineer_calendar和order_info,来确定当天剩下的最大连续时间区块;
EngineerBusinessEntity
businessEntity
=
engineerBusinessDao
.
getByEngineerCode
(
engineerCode
);
// 就算单小时时间段工程师技能已用容量存储至时间切片工程师时间表内
extracted
(
date
,
engineerCode
,
orders
,
ss
);
int
used
=
orders
.
stream
().
map
(
e
->
{
if
(
ss
.
contains
(
e
.
getOrderStatus
()))
{
return
0
;
...
...
@@ -70,13 +106,8 @@ public class CalcEngineerCapacityScheduler {
long
cnt
=
orders
.
stream
()
.
filter
(
e
->
!
ss
.
contains
(
e
.
getOrderStatus
()))
.
count
();
long
max
=
getMaxRemainBlock
(
date
,
engineerCode
,
orders
);
long
max
=
getMaxRemainBlock
(
date
,
engineerCode
,
orders
,
businessEntity
);
log
.
info
(
"正在处理: 日期[{}]技术员[{}]容量相关信息 ==> used:{}, orderCnt:{}, maxDuration:{}"
,
date
,
engineerCode
,
used
,
cnt
,
max
);
CapacityEngineerStatEntity
statEntity
=
capacityEngineerStatDao
.
getByWorkdayAndEngineerCode
(
date
,
engineerCode
);
if
(
statEntity
==
null
)
{
log
.
error
(
"错误:日期[{}]技术员[{}]容量尚未初始化,忽略退出!"
,
date
,
engineerCode
);
return
;
}
statEntity
.
setOrderCount
((
int
)
cnt
);
statEntity
.
setCapUsed
(
used
);
statEntity
.
setCapLeft
(
statEntity
.
getCapTotal
()
-
used
);
...
...
@@ -85,9 +116,47 @@ public class CalcEngineerCapacityScheduler {
capacityEngineerStatDao
.
save
(
statEntity
);
}
private
long
getMaxRemainBlock
(
String
date
,
String
engineerCode
,
List
<
OrderInfoEntity
>
orders
)
{
private
void
extracted
(
String
date
,
String
engineerCode
,
List
<
OrderInfoEntity
>
orders
,
Set
<
String
>
ss
)
{
//查询时间片容量
List
<
CapacityEngineerSliceUsedEntity
>
engineerTimeSlice
=
engineerSliceUsedCapacityDao
.
findByWorkdayAndEngineerCode
(
date
,
engineerCode
);
for
(
CapacityEngineerSliceUsedEntity
sliceCap
:
engineerTimeSlice
)
{
final
TimeSliceEntity
timeSlice
=
sliceCap
.
getTimmeSlice
();
LocalTime
sliceStartLocalTime
=
LocalTime
.
parse
(
timeSlice
.
getStart
(),
DateUtil
.
TIME_FORMATTER
);
LocalTime
sliceEndLocalTime
=
LocalTime
.
parse
(
timeSlice
.
getEnd
(),
DateUtil
.
TIME_FORMATTER
);
long
lengthOfLeave
=
sliceCap
.
getCapTotal
();
for
(
OrderInfoEntity
order
:
orders
)
{
LocalTime
planStartTime
=
order
.
getPlanStartTime
().
toLocalTime
();
LocalTime
planEndTime
=
order
.
getPlanEndTime
().
toLocalTime
();
boolean
startIn
=
DateTimeUtil
.
isIn
(
planStartTime
,
sliceStartLocalTime
,
sliceEndLocalTime
);
boolean
endAfter
=
planEndTime
.
isAfter
(
sliceEndLocalTime
);
//8:00- 8:30 8:00 - 10:30
boolean
contains
=
ss
.
contains
(
order
.
getOrderStatus
());
//请假时间仅落在当前时间段内, 当前时间段请假时长为 请假结束时间- 请假开始时间
if
(
startIn
&&
DateTimeUtil
.
isIn
(
planEndTime
,
sliceStartLocalTime
,
sliceEndLocalTime
))
{
lengthOfLeave
=
contains
?
lengthOfLeave
-
DateTimeUtil
.
betweenTwoTime
(
planStartTime
,
planEndTime
,
TimeUnit
.
MINUTES
)
:
lengthOfLeave
+
DateTimeUtil
.
betweenTwoTime
(
planStartTime
,
planEndTime
,
TimeUnit
.
MINUTES
);
}
else
if
(
startIn
&&
endAfter
)
{
//落在当前时间段和下一个时间段
lengthOfLeave
=
contains
?
lengthOfLeave
-
DateTimeUtil
.
betweenTwoTime
(
planStartTime
,
sliceEndLocalTime
,
TimeUnit
.
MINUTES
)
:
lengthOfLeave
+
DateTimeUtil
.
betweenTwoTime
(
planStartTime
,
sliceEndLocalTime
,
TimeUnit
.
MINUTES
);
}
else
if
(
planStartTime
.
isBefore
(
sliceStartLocalTime
)
&&
endAfter
)
{
lengthOfLeave
=
contains
?
lengthOfLeave
-
DateTimeUtil
.
betweenTwoTime
(
sliceStartLocalTime
,
sliceEndLocalTime
,
TimeUnit
.
MINUTES
):
lengthOfLeave
+
DateTimeUtil
.
betweenTwoTime
(
sliceStartLocalTime
,
sliceEndLocalTime
,
TimeUnit
.
MINUTES
);
}
}
sliceCap
.
setCapLeft
(
lengthOfLeave
);
}
engineerSliceUsedCapacityDao
.
saveAll
(
engineerTimeSlice
);
}
private
long
getMaxRemainBlock
(
String
date
,
String
engineerCode
,
List
<
OrderInfoEntity
>
orders
,
EngineerBusinessEntity
businessEntity
)
{
// 根据capacity_engineer_calendar和order_info,来确定当天剩下的最大连续时间区块;
EngineerBusinessEntity
businessEntity
=
engineerBusinessDao
.
getByEngineerCode
(
engineerCode
);
LocalDateTime
startTime
=
DateUtils
.
localDateTimeFromStr
(
String
.
format
(
"%s %s:00"
,
date
,
businessEntity
.
getWorkOn
()));
LocalDateTime
endTime
=
DateUtils
.
localDateTimeFromStr
(
String
.
format
(
"%s %s:00"
,
date
,
businessEntity
.
getWorkOff
()));
...
...
project-order/src/main/java/com/dituhui/pea/order/scheduler/InitEngineerCapacityScheduler.java
View file @
c588589
package
com
.
dituhui
.
pea
.
order
.
scheduler
;
import
cn.hutool.core.collection.CollectionUtil
;
import
com.dituhui.pea.order.common.DateUtils
;
import
com.dituhui.pea.order.common.jackson.DateTimeUtil
;
import
com.dituhui.pea.order.common.jackson.DateUtil
;
import
com.dituhui.pea.order.dao.CapacityEngineerCalendarDao
;
import
com.dituhui.pea.order.dao.CapacityEngineerStatDao
;
import
com.dituhui.pea.order.dao.EngineerBusinessDao
;
import
com.dituhui.pea.order.dao.EngineerInfoDao
;
import
com.dituhui.pea.order.dao.EngineerSliceUsedCapacityDao
;
import
com.dituhui.pea.order.dao.TimeSliceDao
;
import
com.dituhui.pea.order.entity.CapacityEngineerCalendarEntity
;
import
com.dituhui.pea.order.entity.CapacityEngineerSliceUsedEntity
;
import
com.dituhui.pea.order.entity.CapacityEngineerStatEntity
;
import
com.dituhui.pea.order.entity.EngineerBusinessEntity
;
import
com.dituhui.pea.order.entity.EngineerInfoEntity
;
import
com.dituhui.pea.order.entity.TimeSliceEntity
;
import
lombok.Data
;
import
lombok.experimental.Accessors
;
import
lombok.extern.slf4j.Slf4j
;
...
...
@@ -20,8 +27,11 @@ import org.springframework.stereotype.Component;
import
java.time.Duration
;
import
java.time.LocalDate
;
import
java.time.LocalDateTime
;
import
java.time.LocalTime
;
import
java.util.ArrayList
;
import
java.util.Comparator
;
import
java.util.List
;
import
java.util.concurrent.TimeUnit
;
import
java.util.stream.Collectors
;
@Slf4j
...
...
@@ -45,6 +55,10 @@ public class InitEngineerCapacityScheduler {
private
CapacityEngineerStatDao
capacityEngineerStatDao
;
@Autowired
private
EngineerInfoDao
engineerInfoDao
;
@Autowired
private
TimeSliceDao
timeSliceDao
;
@Autowired
private
EngineerSliceUsedCapacityDao
engineerSliceUsedCapacityDao
;
private
boolean
verifyCalendar
(
List
<
CapacityEngineerCalendarEntity
>
configs
)
{
// 检查多条请假配置是否有交叉行为; configs已经根据startTime排序
...
...
@@ -84,19 +98,99 @@ public class InitEngineerCapacityScheduler {
return
new
CapacityStats
().
setTotal
(
totalWorkTime
).
setUsed
(
totalLeaveTime
).
setRemain
(
totalWorkTime
-
totalLeaveTime
);
}
private
void
initOneEngineer
(
String
date
,
String
engineerCode
)
{
log
.
info
(
"正在处理日期[{}] 技术员[{}]"
,
date
,
engineerCode
);
//
初始化一个工程师、一天的
容量
CapacityEngineerStatEntity
statEntity
=
capacityEngineerStatDao
.
get
ByWorkdayAndEngineerCode
(
date
,
engineerCode
);
if
(
statEntity
!=
null
&&
!
rewriteForce
)
{
log
.
error
(
"技术员容量信息记录已存在, 直接返回"
);
private
void
initOneEngineer
Slice
(
String
date
,
String
engineerCode
,
List
<
CapacityEngineerCalendarEntity
>
configs
,
List
<
TimeSliceEntity
>
commonTimeSliceList
)
{
//
查询时间片
容量
List
<
CapacityEngineerSliceUsedEntity
>
engineerTimeSlice
=
engineerSliceUsedCapacityDao
.
find
ByWorkdayAndEngineerCode
(
date
,
engineerCode
);
if
(
!
CollectionUtil
.
isEmpty
(
engineerTimeSlice
)
&&
!
rewriteForce
)
{
log
.
warn
(
"工程师:{}存在日期:{}时间切片记录, 无需初始化"
,
engineerCode
,
date
);
return
;
}
// 查询工程师正常的工作时间 并按小时切片:
EngineerBusinessEntity
businessEntity
=
engineerBusinessDao
.
getByEngineerCode
(
engineerCode
);
LocalDateTime
workStartTime
=
DateUtils
.
localDateTimeFromStr
(
String
.
format
(
"%s %s:00"
,
date
,
businessEntity
.
getWorkOn
()));
LocalDateTime
workEndTime
=
DateUtils
.
localDateTimeFromStr
(
String
.
format
(
"%s %s:00"
,
date
,
businessEntity
.
getWorkOff
()));
List
<
TimeSliceEntity
>
timeCorridor
=
getTimeSliceEntities
(
workStartTime
,
workEndTime
,
commonTimeSliceList
);
ArrayList
<
CapacityEngineerSliceUsedEntity
>
resultList
=
new
ArrayList
<>(
timeCorridor
.
size
());
for
(
TimeSliceEntity
timeSlice
:
timeCorridor
)
{
CapacityEngineerSliceUsedEntity
r
=
new
CapacityEngineerSliceUsedEntity
();
r
.
setTimmeSlice
(
timeSlice
);
r
.
setEngineerCode
(
engineerCode
);
r
.
setWorkday
(
date
);
LocalTime
sliceStartLocalTime
=
LocalTime
.
parse
(
timeSlice
.
getStart
(),
DateUtil
.
TIME_FORMATTER
);
LocalTime
sliceEndLocalTime
=
LocalTime
.
parse
(
timeSlice
.
getEnd
(),
DateUtil
.
TIME_FORMATTER
);
r
.
setCapTotal
(
DateTimeUtil
.
betweenTwoTime
(
sliceStartLocalTime
,
sliceEndLocalTime
,
TimeUnit
.
MINUTES
));
//校验是否有在当前时间段的请假时间
//已用容量
long
lengthOfLeave
=
0L
;
for
(
int
i
=
0
;
i
<
configs
.
size
();
i
++)
{
CapacityEngineerCalendarEntity
leave
=
configs
.
get
(
i
);
LocalTime
leaveStartTime
=
leave
.
getStartTime
().
toLocalTime
();
LocalTime
leaveEndTime
=
leave
.
getEndTime
().
toLocalTime
();
boolean
startIn
=
DateTimeUtil
.
isIn
(
leaveStartTime
,
sliceStartLocalTime
,
sliceEndLocalTime
);
boolean
endAfter
=
leaveEndTime
.
isAfter
(
sliceEndLocalTime
);
//8:00- 8:30 8:00 - 10:30
//请假时间仅落在当前时间段内, 当前时间段请假时长为 请假结束时间- 请假开始时间
if
(
startIn
&&
DateTimeUtil
.
isIn
(
leaveEndTime
,
sliceStartLocalTime
,
sliceEndLocalTime
))
{
lengthOfLeave
+=
DateTimeUtil
.
betweenTwoTime
(
leaveStartTime
,
leaveEndTime
,
TimeUnit
.
MINUTES
);
}
else
if
(
startIn
&&
endAfter
)
{
//落在当前时间段和下一个时间段
lengthOfLeave
+=
DateTimeUtil
.
betweenTwoTime
(
leaveStartTime
,
sliceEndLocalTime
,
TimeUnit
.
MINUTES
);
}
else
if
(
leaveStartTime
.
isBefore
(
sliceStartLocalTime
)
&&
leaveEndTime
.
isAfter
(
sliceEndLocalTime
))
{
lengthOfLeave
+=
DateTimeUtil
.
betweenTwoTime
(
sliceStartLocalTime
,
sliceEndLocalTime
,
TimeUnit
.
MINUTES
);
}
}
// 剩余可约容量
long
leftUseTime
=
60
-
lengthOfLeave
;
r
.
setCapLeft
(
leftUseTime
);
r
.
setCapUsed
(
lengthOfLeave
);
r
.
setCreateTime
(
LocalDateTime
.
now
());
r
.
setUpdateTime
(
LocalDateTime
.
now
());
resultList
.
add
(
r
);
}
engineerSliceUsedCapacityDao
.
saveAll
(
resultList
);
}
private
List
<
TimeSliceEntity
>
getTimeSliceEntities
(
LocalDateTime
workStartTime
,
LocalDateTime
workEndTime
,
List
<
TimeSliceEntity
>
commonTimeSliceList
)
{
//切片开始时间
LocalTime
sliceStartHour
=
LocalTime
.
of
(
workStartTime
.
getHour
(),
0
);
//切片结束时间
LocalTime
sliceEndHour
=
LocalTime
.
of
(
workEndTime
.
getHour
(),
0
);
List
<
TimeSliceEntity
>
timeCorridor
=
commonTimeSliceList
.
stream
()
.
filter
(
slice
->
{
LocalTime
startLocalTime
=
LocalTime
.
parse
(
slice
.
getStart
(),
DateUtil
.
TIME_FORMATTER
);
LocalTime
endLocalTime
=
LocalTime
.
parse
(
slice
.
getEnd
(),
DateUtil
.
TIME_FORMATTER
);
return
(
startLocalTime
.
isAfter
(
sliceStartHour
)
&&
endLocalTime
.
isBefore
(
sliceEndHour
))
||
(
startLocalTime
.
equals
(
sliceStartHour
)
||
endLocalTime
.
equals
(
sliceEndHour
));
}).
sorted
(
Comparator
.
comparing
(
TimeSliceEntity:
:
getId
)).
collect
(
Collectors
.
toList
());
return
timeCorridor
;
}
private
void
initOneEngineer
(
String
date
,
String
engineerCode
)
{
log
.
info
(
"正在处理日期[{}] 技术员[{}]"
,
date
,
engineerCode
);
List
<
CapacityEngineerCalendarEntity
>
configs
=
capacityEngineerCalendarDao
.
findCalendarByWorkdayAndEngineerCode
(
date
,
engineerCode
)
.
stream
().
sorted
(
Comparator
.
comparing
(
CapacityEngineerCalendarEntity:
:
getStartTime
)).
collect
(
Collectors
.
toList
());
if
(!
configs
.
isEmpty
()
&&
!
verifyCalendar
(
configs
))
{
log
.
error
(
"配置检查失败,忽略退出"
);
log
.
error
(
"日期[{}]技术员[{}]请假配置检查失败,忽略退出"
,
date
,
engineerCode
);
return
;
}
List
<
TimeSliceEntity
>
commonTimeSliceList
=
timeSliceDao
.
findByType
(
"HOURS"
);
//初始化一个工程师时间切片容量
initOneEngineerSlice
(
date
,
engineerCode
,
configs
,
commonTimeSliceList
);
// 初始化一个工程师、一天的容量
CapacityEngineerStatEntity
statEntity
=
capacityEngineerStatDao
.
getByWorkdayAndEngineerCode
(
date
,
engineerCode
);
if
(
statEntity
!=
null
&&
!
rewriteForce
)
{
log
.
error
(
"技术员容量信息记录已存在, 直接返回"
);
return
;
}
String
memo
=
configs
.
stream
().
map
(
CapacityEngineerCalendarEntity:
:
getType
).
collect
(
Collectors
.
joining
(
"/"
));
...
...
project-order/src/main/java/com/dituhui/pea/order/service/CapacityQueryService.java
View file @
c588589
...
...
@@ -2,7 +2,70 @@ package com.dituhui.pea.order.service;
import
com.dituhui.pea.common.Result
;
import
com.dituhui.pea.order.dto.CapacityOrderQueryDTO
;
import
com.dituhui.pea.order.dto.param.CapacityQueryDTO
;
import
com.dituhui.pea.order.dto.param.Location
;
import
java.time.LocalDate
;
import
java.time.LocalTime
;
import
java.util.List
;
public
interface
CapacityQueryService
{
Result
<?>
queryMatchCapacityData
(
CapacityOrderQueryDTO
.
Request
capacityQueryReqDTO
);
/**
* 对外创单可用容量查询
*
* @param services 服务技能信息, 包含品牌, 产品类型, 服务技能
* @param location 需要查询容量的地址
* @param beginDate 开始日期
* @param endDate 结束日期
* @return 满足对应技能工作队的容量(三种类型与分站绑定)
*/
Result
<
CapacityQueryDTO
.
Result
>
matchCapacityData
(
List
<
CapacityQueryDTO
.
Service
>
services
,
Location
location
,
LocalDate
beginDate
,
LocalDate
endDate
);
/**
* 根据工作队,时间段,技能、品牌,服务类型查容量
*
* @param teamId 工作队
* @param service 服务技能信息, 包含品牌, 产品类型, 服务技能--汉字
* @param targetDate 时间段对应的日期
* @param startTime 开始时间
* @param endTime 结束时间
* @return 日期对应时间段工作队容量
*/
CapacityQueryDTO
.
Segment
queryCapacityByTeam
(
String
teamId
,
CapacityQueryDTO
.
Service
service
,
LocalDate
targetDate
,
LocalTime
startTime
,
LocalTime
endTime
);
/**
* 根据工作队,日期,技能、品牌,服务类型查容量
*
* @param teamId 工作队
* @param service 服务技能信息, 包含品牌, 产品类型, 服务技能--汉字
* @param targetDate 查询容量的日期
* @return 工作队指定日期的容量
*/
CapacityQueryDTO
.
Segment
queryCapacityByTeam
(
String
teamId
,
CapacityQueryDTO
.
Service
service
,
LocalDate
targetDate
);
/**
* 查询单个工程师指定日期的容量状态
*
* @param engineerCode 工程师编码
* @param date 需要查询的日期
* @return 返回单个工程师容量结果
*/
CapacityQueryDTO
.
Segment
queryEngineerCapacity
(
String
engineerCode
,
LocalDate
date
);
/**
* 查询单个工程师指定日期时间段内的的容量状态
*
* @param engineerCode 工程师编码
* @param date 需要查询的日期
* @param startTime 开始时间
* @param endTime 结束时间
* @return 返回单个工程师容量结果
*/
CapacityQueryDTO
.
Segment
queryEngineerCapacity
(
String
engineerCode
,
CapacityQueryDTO
.
Service
service
,
LocalDate
date
,
LocalTime
startTime
,
LocalTime
endTime
);
}
project-order/src/main/java/com/dituhui/pea/order/service/impl/CapacityQueryServiceImpl.java
View file @
c588589
This diff is collapsed.
Click to expand it.
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