Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yanxuan-qc-change-system
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
yx-qc-change-flow
yanxuan-qc-change-system
Commits
c1a3588c
Commit
c1a3588c
authored
Dec 12, 2025
by
王志超
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 变更工单完结时间和超期处理
parent
f93efe87
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
190 additions
and
13 deletions
+190
-13
ChangeFlowBiz.java
...om/netease/mail/yanxuan/change/biz/biz/ChangeFlowBiz.java
+146
-9
ChangeFlowExportCallback.java
...yanxuan/change/biz/callback/ChangeFlowExportCallback.java
+28
-3
ChangeFlowVO.java
...e/mail/yanxuan/change/dal/meta/model/vo/ChangeFlowVO.java
+16
-1
No files found.
yanxuan-qc-change-system-biz/src/main/java/com/netease/mail/yanxuan/change/biz/biz/ChangeFlowBiz.java
View file @
c1a3588c
...
@@ -58,6 +58,7 @@ import com.netease.mail.yanxuan.change.dal.entity.ChangeFile;
...
@@ -58,6 +58,7 @@ import com.netease.mail.yanxuan.change.dal.entity.ChangeFile;
import
com.netease.mail.yanxuan.change.dal.entity.ChangeRecord
;
import
com.netease.mail.yanxuan.change.dal.entity.ChangeRecord
;
import
com.netease.mail.yanxuan.change.dal.entity.ChangeSubFlowRecord
;
import
com.netease.mail.yanxuan.change.dal.entity.ChangeSubFlowRecord
;
import
com.netease.mail.yanxuan.change.dal.entity.ChangeType
;
import
com.netease.mail.yanxuan.change.dal.entity.ChangeType
;
import
com.netease.mail.yanxuan.change.dal.mapper.ChangeExecRecordMapper
;
import
com.netease.mail.yanxuan.change.dal.mapper.ChangeRecordMapper
;
import
com.netease.mail.yanxuan.change.dal.mapper.ChangeRecordMapper
;
import
com.netease.mail.yanxuan.change.dal.mapper.ChangeSubFlowRecordMapper
;
import
com.netease.mail.yanxuan.change.dal.mapper.ChangeSubFlowRecordMapper
;
import
com.netease.mail.yanxuan.change.dal.meta.model.po.ChangeCommanderPO
;
import
com.netease.mail.yanxuan.change.dal.meta.model.po.ChangeCommanderPO
;
...
@@ -133,6 +134,9 @@ public class ChangeFlowBiz {
...
@@ -133,6 +134,9 @@ public class ChangeFlowBiz {
private
ChangeRecordMapper
changeRecordMapper
;
private
ChangeRecordMapper
changeRecordMapper
;
@Autowired
@Autowired
private
ChangeExecRecordMapper
changeExecRecordMapper
;
@Autowired
private
ChangeSubFlowRecordMapper
changeSubFlowRecordMapper
;
private
ChangeSubFlowRecordMapper
changeSubFlowRecordMapper
;
@Autowired
@Autowired
...
@@ -1301,19 +1305,20 @@ public class ChangeFlowBiz {
...
@@ -1301,19 +1305,20 @@ public class ChangeFlowBiz {
if
(
CollectionUtils
.
isNotEmpty
(
changeRecords
))
{
if
(
CollectionUtils
.
isNotEmpty
(
changeRecords
))
{
// 批量查询所有变更行动工单,构建 Map<changeRecordId, List<subFlowId>>,提升性能
// 批量查询所有变更行动工单,构建 Map<changeRecordId, List<subFlowId>>,提升性能
final
Map
<
Long
,
List
<
String
>>
subFlowIdsMap
;
final
Map
<
Long
,
List
<
String
>>
subFlowIdsMap
;
List
<
Long
>
changeRecordIds
=
changeRecords
.
stream
()
// 批量查询所有行动工单,构建 Map<changeRecordId, List<ChangeSubFlowRecord>>,用于后续过滤和超期判断
.
map
(
ChangeRecord:
:
getId
)
final
Map
<
Long
,
List
<
ChangeSubFlowRecord
>>
subFlowRecordsMap
;
.
collect
(
Collectors
.
toList
());
List
<
Long
>
changeRecordIds
=
changeRecords
.
stream
().
map
(
ChangeRecord:
:
getId
)
.
collect
(
Collectors
.
toList
());
List
<
ChangeSubFlowRecord
>
subFlowRecords
=
changeSubFlowRecordService
.
getByChangeRecordIds
(
changeRecordIds
);
List
<
ChangeSubFlowRecord
>
subFlowRecords
=
changeSubFlowRecordService
.
getByChangeRecordIds
(
changeRecordIds
);
if
(
CollectionUtils
.
isNotEmpty
(
subFlowRecords
))
{
if
(
CollectionUtils
.
isNotEmpty
(
subFlowRecords
))
{
subFlowIdsMap
=
subFlowRecords
.
stream
()
subFlowIdsMap
=
subFlowRecords
.
stream
()
.
filter
(
record
->
StringUtils
.
isNotBlank
(
record
.
getSubFlowId
()))
.
filter
(
record
->
StringUtils
.
isNotBlank
(
record
.
getSubFlowId
()))
.
collect
(
Collectors
.
groupingBy
(
ChangeSubFlowRecord:
:
getChangeRecordId
,
.
collect
(
Collectors
.
groupingBy
(
Collectors
.
mapping
(
ChangeSubFlowRecord:
:
getSubFlowId
,
Collectors
.
toList
())));
ChangeSubFlowRecord:
:
getChangeRecordId
,
// 按 changeRecordId 分组,不过滤状态,后续在内部方法中根据业务需求过滤
Collectors
.
mapping
(
ChangeSubFlowRecord:
:
getSubFlowId
,
Collectors
.
toList
()
)
subFlowRecordsMap
=
subFlowRecords
.
stream
(
)
));
.
collect
(
Collectors
.
groupingBy
(
ChangeSubFlowRecord:
:
getChangeRecordId
));
}
else
{
}
else
{
subFlowIdsMap
=
new
HashMap
<>();
subFlowIdsMap
=
new
HashMap
<>();
subFlowRecordsMap
=
new
HashMap
<>();
}
}
list
=
changeRecords
.
stream
().
map
(
c
->
{
list
=
changeRecords
.
stream
().
map
(
c
->
{
ChangeFlowVO
changeFlowVO
=
new
ChangeFlowVO
();
ChangeFlowVO
changeFlowVO
=
new
ChangeFlowVO
();
...
@@ -1382,6 +1387,9 @@ public class ChangeFlowBiz {
...
@@ -1382,6 +1387,9 @@ public class ChangeFlowBiz {
changeFlowVO
.
setFlowOwnership
(
flowOwnership
);
changeFlowVO
.
setFlowOwnership
(
flowOwnership
);
}
}
// 设置变更完结时间和是否超期标识
buildChangeEndTime
(
c
,
changeFlowVO
,
subFlowRecordsMap
);
return
changeFlowVO
;
return
changeFlowVO
;
}).
collect
(
Collectors
.
toList
());
}).
collect
(
Collectors
.
toList
());
...
@@ -2055,4 +2063,133 @@ public class ChangeFlowBiz {
...
@@ -2055,4 +2063,133 @@ public class ChangeFlowBiz {
return
resetCount
;
return
resetCount
;
}
}
/**
* 构建变更完结时间和是否超期标识
*
* 时间展示逻辑:
* - 未完成的工单:展示预期完成时间(changeConfirmResultTime)
* - 已完成工单(END):展示实际完成时间(updateTime)
* - 取消的工单(CANCEL):展示取消时间(updateTime)
*
* 超期判断逻辑(仅针对非完结/取消的变更单):
* - 变更单的 changeConfirmResultTime 超过两个工作日未处理
* - 或者工单下属的执行项里的 changeExecFinishTime 超过两个工作日未处理(仅判断未完结或未取消的行动工单对应的行动项)
*
* @param changeRecord 变更记录
* @param changeFlowVO 变更工单视图对象
* @param subFlowRecordsMap 所有行动工单Map,key为changeRecordId,value为该主单下所有行动工单列表
*/
private
void
buildChangeEndTime
(
ChangeRecord
changeRecord
,
ChangeFlowVO
changeFlowVO
,
Map
<
Long
,
List
<
ChangeSubFlowRecord
>>
subFlowRecordsMap
)
{
Integer
state
=
changeRecord
.
getState
();
Long
changeConfirmResultTime
=
changeRecord
.
getChangeConfirmResultTime
();
Long
updateTime
=
changeRecord
.
getUpdateTime
();
if
(
ChangeStatusEnum
.
END
.
getStatus
().
equals
(
state
))
{
// 已完成工单:展示实际完成时间(updateTime)
changeFlowVO
.
setChangeEndTime
(
updateTime
);
changeFlowVO
.
setIsOverdue
(
false
);
}
else
if
(
ChangeStatusEnum
.
CANCEL
.
getStatus
().
equals
(
state
))
{
// 取消的工单:展示取消时间(updateTime)
changeFlowVO
.
setChangeEndTime
(
updateTime
);
changeFlowVO
.
setIsOverdue
(
false
);
}
else
{
// 未完成的工单:展示预期完成时间(changeConfirmResultTime)
changeFlowVO
.
setChangeEndTime
(
changeConfirmResultTime
);
// 超期判断:非完结/取消的变更单,判断是否超过两个工作日未处理
boolean
isOverdue
=
false
;
Long
currentTime
=
DateUtils
.
getCurrentTime
();
// 判断变更单的 changeConfirmResultTime 是否超过两个工作日
if
(
isOverdueByWorkdays
(
changeConfirmResultTime
,
currentTime
,
2
))
{
isOverdue
=
true
;
}
// 判断执行项的 changeExecFinishTime 是否超过两个工作日
// 注意:只判断未完结或未取消的行动工单对应的行动项
if
(!
isOverdue
)
{
// 从Map中获取该主单下所有行动工单
List
<
ChangeSubFlowRecord
>
allSubFlows
=
subFlowRecordsMap
.
getOrDefault
(
changeRecord
.
getId
(),
new
ArrayList
<>());
// 内部过滤:只保留未完结或未取消的行动工单
List
<
ChangeSubFlowRecord
>
activeSubFlows
=
allSubFlows
.
stream
()
.
filter
(
subFlow
->
{
Integer
status
=
subFlow
.
getStatus
();
return
status
!=
null
&&
!
ChangeSubFlowStatusEnum
.
FINISHED
.
getStatus
().
equals
(
status
)
&&
!
ChangeSubFlowStatusEnum
.
CANCELLED
.
getStatus
().
equals
(
status
);
})
.
collect
(
Collectors
.
toList
());
if
(
CollectionUtils
.
isNotEmpty
(
activeSubFlows
))
{
// 提取未完结或未取消的行动工单的ID
Set
<
Long
>
activeSubFlowRecordIds
=
activeSubFlows
.
stream
()
.
map
(
ChangeSubFlowRecord:
:
getId
)
.
collect
(
Collectors
.
toSet
());
// 批量查询这些行动工单对应的行动项
List
<
ChangeExecRecord
>
execRecords
=
changeExecRecordMapper
.
selectBySubFlowRecordIds
(
new
ArrayList
<>(
activeSubFlowRecordIds
));
if
(
CollectionUtils
.
isNotEmpty
(
execRecords
))
{
for
(
ChangeExecRecord
execRecord
:
execRecords
)
{
Long
changeExecFinishTime
=
execRecord
.
getChangeExecFinishTime
();
if
(
changeExecFinishTime
!=
null
&&
isOverdueByWorkdays
(
changeExecFinishTime
,
currentTime
,
2
))
{
isOverdue
=
true
;
break
;
}
}
}
}
}
changeFlowVO
.
setIsOverdue
(
isOverdue
);
}
}
/**
* 判断指定时间是否超过指定工作日数未处理
*
* @param targetTime 目标时间(需要判断的时间)
* @param currentTime 当前时间
* @param workdays 工作日数
* @return true: 超过指定工作日数未处理;false: 未超过
*/
private
boolean
isOverdueByWorkdays
(
Long
targetTime
,
Long
currentTime
,
int
workdays
)
{
if
(
targetTime
==
null
||
currentTime
==
null
)
{
return
false
;
}
// 计算目标时间加上指定工作日数后的时间
Long
deadlineTime
=
addWorkdays
(
targetTime
,
workdays
);
// 如果当前时间超过截止时间,则超期
return
currentTime
>
deadlineTime
;
}
/**
* 在指定时间基础上增加指定工作日数(排除周末)
*
* @param time 起始时间
* @param workdays 工作日数
* @return 增加工作日数后的时间
*/
private
Long
addWorkdays
(
Long
time
,
int
workdays
)
{
if
(
time
==
null
||
workdays
<=
0
)
{
return
time
;
}
java
.
util
.
Calendar
calendar
=
java
.
util
.
Calendar
.
getInstance
();
calendar
.
setTimeInMillis
(
time
);
int
addedDays
=
0
;
while
(
addedDays
<
workdays
)
{
calendar
.
add
(
java
.
util
.
Calendar
.
DAY_OF_MONTH
,
1
);
int
dayOfWeek
=
calendar
.
get
(
java
.
util
.
Calendar
.
DAY_OF_WEEK
);
// 排除周六(7)和周日(1)
if
(
dayOfWeek
!=
java
.
util
.
Calendar
.
SATURDAY
&&
dayOfWeek
!=
java
.
util
.
Calendar
.
SUNDAY
)
{
addedDays
++;
}
}
return
calendar
.
getTimeInMillis
();
}
}
}
yanxuan-qc-change-system-biz/src/main/java/com/netease/mail/yanxuan/change/biz/callback/ChangeFlowExportCallback.java
View file @
c1a3588c
...
@@ -356,12 +356,37 @@ public class ChangeFlowExportCallback implements DesCallbackService {
...
@@ -356,12 +356,37 @@ public class ChangeFlowExportCallback implements DesCallbackService {
ChangeResultEnum
resultEnum
=
ChangeResultEnum
.
getByValue
(
record
.
getChangeResult
());
ChangeResultEnum
resultEnum
=
ChangeResultEnum
.
getByValue
(
record
.
getChangeResult
());
log
.
debug
(
"[obtainOther] record:{}, resultEnum:{}"
,
JSON
.
toJSONString
(
record
),
resultEnum
);
log
.
debug
(
"[obtainOther] record:{}, resultEnum:{}"
,
JSON
.
toJSONString
(
record
),
resultEnum
);
changeFlowExcelDTO
.
setChangeResult
(
resultEnum
==
null
?
"/"
:
resultEnum
.
getDesc
());
changeFlowExcelDTO
.
setChangeResult
(
resultEnum
==
null
?
"/"
:
resultEnum
.
getDesc
());
if
(
record
.
getState
().
equals
(
ChangeStatusEnum
.
CANCEL
.
getStatus
())
||
record
.
getState
().
equals
(
ChangeStatusEnum
.
END
.
getStatus
()))
{
// 时间展示逻辑:
changeFlowExcelDTO
.
setChangeEndTime
(
DateUtils
.
parseLongToString
(
record
.
getUpdateTime
(),
DateUtils
.
DATE_TIME_FORMAT
));
// - 未完成的工单:展示预期完成时间(changeConfirmResultTime)
// - 已完成工单(END):展示实际完成时间(updateTime)
// - 取消的工单(CANCEL):展示取消时间(updateTime)
Integer
state
=
record
.
getState
();
Long
changeConfirmResultTime
=
record
.
getChangeConfirmResultTime
();
Long
updateTime
=
record
.
getUpdateTime
();
if
(
ChangeStatusEnum
.
END
.
getStatus
().
equals
(
state
))
{
// 已完成工单:展示实际完成时间(updateTime)
if
(
updateTime
!=
null
)
{
changeFlowExcelDTO
.
setChangeEndTime
(
DateUtils
.
parseLongToString
(
updateTime
,
DateUtils
.
DATE_TIME_FORMAT
));
}
else
{
changeFlowExcelDTO
.
setChangeEndTime
(
"/"
);
}
}
else
if
(
ChangeStatusEnum
.
CANCEL
.
getStatus
().
equals
(
state
))
{
// 取消的工单:展示取消时间(updateTime)
if
(
updateTime
!=
null
)
{
changeFlowExcelDTO
.
setChangeEndTime
(
DateUtils
.
parseLongToString
(
updateTime
,
DateUtils
.
DATE_TIME_FORMAT
));
}
else
{
}
else
{
changeFlowExcelDTO
.
setChangeEndTime
(
"/"
);
changeFlowExcelDTO
.
setChangeEndTime
(
"/"
);
}
}
}
else
{
// 未完成的工单:展示预期完成时间(changeConfirmResultTime)
if
(
changeConfirmResultTime
!=
null
)
{
changeFlowExcelDTO
.
setChangeEndTime
(
DateUtils
.
parseLongToString
(
changeConfirmResultTime
,
DateUtils
.
DATE_TIME_FORMAT
));
}
else
{
changeFlowExcelDTO
.
setChangeEndTime
(
"/"
);
}
}
}
}
private
void
buildGoodsPrincipal
(
ChangeGoodsPrincipalPO
changeGoodsPrincipalPO
,
ChangeFlowExcelDTO
changeFlowExcelDTO
)
{
private
void
buildGoodsPrincipal
(
ChangeGoodsPrincipalPO
changeGoodsPrincipalPO
,
ChangeFlowExcelDTO
changeFlowExcelDTO
)
{
...
...
yanxuan-qc-change-system-dal/src/main/java/com/netease/mail/yanxuan/change/dal/meta/model/vo/ChangeFlowVO.java
View file @
c1a3588c
...
@@ -162,11 +162,26 @@ public class ChangeFlowVO {
...
@@ -162,11 +162,26 @@ public class ChangeFlowVO {
private
Long
createTime
;
private
Long
createTime
;
/**
/**
* 变更结果确认时间
* 变更结果确认时间
(预期完成时间)
*/
*/
private
Long
changeConfirmResultTime
;
private
Long
changeConfirmResultTime
;
/**
/**
* 变更完结时间(实际完成时间/取消时间)
* 未完成的工单:展示预期完成时间(changeConfirmResultTime)
* 已完成工单:展示实际完成时间(updateTime)
* 取消的工单:展示取消时间(updateTime)
*/
private
Long
changeEndTime
;
/**
* 是否超出预计完成时间(用于前端标红展示)
* true: 已完成工单的实际完成时间超出预期完成时间
* false: 其他情况
*/
private
Boolean
isOverdue
;
/**
* 取消原因
* 取消原因
*/
*/
private
String
cancelReason
;
private
String
cancelReason
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
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 comment