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
ffc569e6
Commit
ffc569e6
authored
Dec 11, 2025
by
王志超
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 行动工单提交变更执行,变更工单自动提交
parent
42a2aa4a
Pipeline
#86794
passed with stages
in 1 minute 30 seconds
Changes
2
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
216 additions
and
93 deletions
+216
-93
ChangeFlowBiz.java
...om/netease/mail/yanxuan/change/biz/biz/ChangeFlowBiz.java
+0
-87
ChangeSubFlowBiz.java
...netease/mail/yanxuan/change/biz/biz/ChangeSubFlowBiz.java
+216
-6
No files found.
yanxuan-qc-change-system-biz/src/main/java/com/netease/mail/yanxuan/change/biz/biz/ChangeFlowBiz.java
View file @
ffc569e6
...
...
@@ -1707,93 +1707,6 @@ public class ChangeFlowBiz {
return
nextNodeId
;
}
void
submitMainFlowAfterAllSubFlowsApproved
(
Long
changeRecordId
)
{
// 查询主工单
ChangeRecord
changeRecord
=
changeRecordMapper
.
selectByPrimaryKey
(
changeRecordId
);
if
(
changeRecord
==
null
)
{
log
.
error
(
"[submitMainFlowAfterAllSubFlowsApproved] 主工单不存在,changeRecordId:{}"
,
changeRecordId
);
throw
ExceptionFactory
.
createBiz
(
ResponseCode
.
BAD_REQUEST
,
"主工单不存在"
);
}
// 验证主工单当前节点
String
currentNode
=
changeRecord
.
getFlowNode
();
if
(!
ChangeFlowEnum
.
NEW_CHANGE_FLOW_CONFIRM_EXEC_PLAN
.
getNodeId
().
equals
(
currentNode
))
{
throw
ExceptionFactory
.
createBiz
(
ResponseCode
.
NODE_ERROR
,
String
.
format
(
"主工单当前节点不是确认变更方案节点,无法流转。当前节点:%s"
,
currentNode
));
}
try
{
Long
flowId
=
changeRecord
.
getFlowId
();
String
uid
=
RequestLocalBean
.
getUid
();
// 获取工单详情
FlowDataDTO
flowDataDTO
=
flowService
.
flowDetail
(
flowId
.
toString
());
if
(
flowDataDTO
==
null
)
{
throw
ExceptionFactory
.
createBiz
(
ResponseCode
.
DETAIL_FLOW_ERROR
,
"工单查询错误,不存在"
);
}
// 构建提交内容
Map
<
String
,
Object
>
content
=
new
HashMap
<>(
CommonConstants
.
INIT_HASH_MAP_SIZE
);
content
.
put
(
"updateTime"
,
System
.
currentTimeMillis
());
content
.
put
(
CommonConstants
.
FLOW_OPERATION_KEY
,
FlowOperationTypeEnum
.
PASS
.
getValue
());
// 使用paramMap控制流转方向(所有子单审批通过)
Map
<
String
,
Object
>
paramMap
=
new
HashMap
<>();
paramMap
.
put
(
"type"
,
FlowTransitionType
.
TYPE_APPROVED
);
// 流转主工单到部门负责人审批节点
String
ownerApproveNodeId
=
flowService
.
submitFlowWithParamMap
(
flowId
.
toString
(),
flowDataDTO
,
uid
,
ChangeFlowEnum
.
NEW_CHANGE_FLOW
.
getTopoId
(),
JSON
.
toJSONString
(
content
),
paramMap
,
FlowxOperationEnum
.
SUBMIT
.
getName
(),
"所有子单审批通过,主工单流转"
,
changeRecord
.
getCreateTime
());
changeRecord
.
setFlowNode
(
ownerApproveNodeId
);
changeRecord
.
setState
(
ChangeStatusEnum
.
WAIT_DEPT_LEADER_APPROVE
.
getStatus
());
changeRecord
.
setUpdateTime
(
DateUtils
.
getCurrentTime
());
// 获取变更负责人的上级领导并设置为审批人
String
changeCommander
=
changeRecord
.
getChangeCommander
();
if
(
StringUtils
.
isBlank
(
changeCommander
))
{
throw
ExceptionFactory
.
createBiz
(
ResponseCode
.
BAD_REQUEST
,
"变更负责人邮箱不能为空"
);
}
String
leaderEmail
=
departmentLeaderBiz
.
getDepartmentLeader
(
changeCommander
);
if
(
StringUtils
.
isBlank
(
leaderEmail
))
{
throw
ExceptionFactory
.
createBiz
(
ResponseCode
.
BAD_REQUEST
,
String
.
format
(
"变更负责人[%s]的部门上级领导不存在"
,
changeCommander
));
}
// 设置审批人为上级领导(JSON 数组格式)
changeRecord
.
setApprover
(
JSON
.
toJSONString
(
Collections
.
singletonList
(
leaderEmail
)));
changeFlowService
.
updateRecord
(
changeRecord
);
log
.
info
(
"[submitMainFlowAfterAllSubFlowsApproved] 主工单流转成功,flowId:{}, nextNodeId:{}, approver:{}"
,
flowId
,
ownerApproveNodeId
,
leaderEmail
);
}
catch
(
Exception
e
)
{
log
.
error
(
"[submitMainFlowAfterAllSubFlowsApproved] 主工单流转失败,changeRecordId:{}"
,
changeRecordId
,
e
);
throw
ExceptionFactory
.
createBiz
(
ResponseCode
.
BAD_REQUEST
,
String
.
format
(
"主工单流转失败:%s"
,
e
.
getMessage
()));
}
}
/**
* 检查主工单下所有子单是否都已完成(供主工单流转时调用)
* 条件:status = FINISHED 或 CANCELLED
*
* @param changeRecordId 主工单ID
* @return true 表示所有子单都已完成
*/
public
boolean
checkAllSubFlowsFinishedForMainFlow
(
Long
changeRecordId
)
{
// 查询该主工单下所有子单
List
<
ChangeSubFlowRecord
>
allSubFlows
=
changeSubFlowRecordMapper
.
selectByChangeRecordId
(
changeRecordId
);
if
(
CollectionUtils
.
isEmpty
(
allSubFlows
))
{
return
false
;
}
// 检查是否所有子单都满足条件:状态是 FINISHED 或 CANCELLED
return
allSubFlows
.
stream
().
allMatch
(
subFlow
->
ChangeSubFlowStatusEnum
.
FINISHED
.
getStatus
().
equals
(
subFlow
.
getStatus
())
||
ChangeSubFlowStatusEnum
.
CANCELLED
.
getStatus
().
equals
(
subFlow
.
getStatus
())
);
}
/**
* 验证子单归属于主工单(查询一次,返回所有子单供后续复用)
*
...
...
yanxuan-qc-change-system-biz/src/main/java/com/netease/mail/yanxuan/change/biz/biz/ChangeSubFlowBiz.java
View file @
ffc569e6
...
...
@@ -19,6 +19,7 @@ import com.netease.mail.yanxuan.change.common.bean.ResponseCode;
import
com.netease.mail.yanxuan.change.common.constants.FlowTransitionType
;
import
com.netease.mail.yanxuan.change.common.enums.ChangeFlowEnum
;
import
com.netease.mail.yanxuan.change.common.enums.ChangeResultEnum
;
import
com.netease.mail.yanxuan.change.common.enums.ChangeStatusEnum
;
import
com.netease.mail.yanxuan.change.common.enums.ChangeSubFlowStatusEnum
;
import
com.netease.mail.yanxuan.change.common.enums.ChangeSubjectEnum
;
import
com.netease.mail.yanxuan.change.common.enums.CreateSourceEnum
;
...
...
@@ -175,9 +176,7 @@ public class ChangeSubFlowBiz {
log
.
debug
(
"[checkUpdateAndSubmit] 提交参数:{}"
,
JSON
.
toJSONString
(
changeSubFlowSubmitReq
));
// 构建工单内容
Map
<
String
,
Object
>
content
=
new
HashMap
<>(
CommonConstants
.
INIT_HASH_MAP_SIZE
);
content
.
put
(
"updateTime"
,
System
.
currentTimeMillis
());
content
.
put
(
CommonConstants
.
FLOW_OPERATION_KEY
,
FlowOperationTypeEnum
.
PASS
.
getValue
());
Map
<
String
,
Object
>
content
=
buildFlowContent
();
switch
(
node
)
{
case
CHANGE_SUB_FLOW_START:
...
...
@@ -347,7 +346,7 @@ public class ChangeSubFlowBiz {
// 检查所有子单是否都已到达提交执行结果节点,如果是则流转主工单
if
(
checkAllSubFlowsApproved
(
subFlowRecord
.
getChangeRecordId
()))
{
changeFlowBiz
.
submitMainFlowAfterAllSubFlowsApproved
(
subFlowRecord
.
getChangeRecordId
());
submitMainFlowAfterAllSubFlowsApproved
(
subFlowRecord
.
getChangeRecordId
());
log
.
info
(
"[CHANGE_SUB_FLOW_EXE] 所有子单均已到达提交执行结果节点,主工单已流转"
);
}
}
else
{
...
...
@@ -495,7 +494,11 @@ public class ChangeSubFlowBiz {
// 发送邮件
sendSubFlowFinishEmail
(
subFlowRecord
);
// todo: 检查所有子单是否都已完成,如果是则流转主工单
// 检查所有子单是否都已完成,如果是则流转主工单
if
(
checkAllSubFlowsFinishedForMainFlow
(
subFlowRecord
.
getChangeRecordId
()))
{
submitMainFlowAfterAllSubFlowsFinished
(
subFlowRecord
.
getChangeRecordId
());
log
.
info
(
"[handleSubFlowFinish] 所有子单均已完成,主工单已流转"
);
}
return
endNodeId
;
}
...
...
@@ -532,7 +535,11 @@ public class ChangeSubFlowBiz {
// 发送邮件
sendSubFlowFinishEmail
(
subFlowRecord
);
// todo: 检查所有子单是否都已完成,如果是则流转主工单
// 检查所有子单是否都已完成,如果是则流转主工单
if
(
checkAllSubFlowsFinishedForMainFlow
(
subFlowRecord
.
getChangeRecordId
()))
{
submitMainFlowAfterAllSubFlowsFinished
(
subFlowRecord
.
getChangeRecordId
());
log
.
info
(
"[handleSubFlowCancel] 所有子单均已完成,主工单已流转"
);
}
return
cancelNodeId
;
}
...
...
@@ -607,6 +614,188 @@ public class ChangeSubFlowBiz {
}
/**
* 构建工单提交内容(包含 updateTime 和 FLOW_OPERATION_KEY)
*
* @return 工单提交内容 Map
*/
private
Map
<
String
,
Object
>
buildFlowContent
()
{
Map
<
String
,
Object
>
content
=
new
HashMap
<>(
CommonConstants
.
INIT_HASH_MAP_SIZE
);
content
.
put
(
"updateTime"
,
System
.
currentTimeMillis
());
content
.
put
(
CommonConstants
.
FLOW_OPERATION_KEY
,
FlowOperationTypeEnum
.
PASS
.
getValue
());
return
content
;
}
/**
* 所有子单审批变更方案通过后,流转主工单到部门负责人审批节点
*
* @param changeRecordId 主工单ID
*/
private
void
submitMainFlowAfterAllSubFlowsApproved
(
Long
changeRecordId
)
{
// 查询主工单
ChangeRecord
changeRecord
=
changeRecordMapper
.
selectByPrimaryKey
(
changeRecordId
);
if
(
changeRecord
==
null
)
{
log
.
error
(
"[submitMainFlowAfterAllSubFlowsApproved] 主工单不存在,changeRecordId:{}"
,
changeRecordId
);
throw
ExceptionFactory
.
createBiz
(
ResponseCode
.
BAD_REQUEST
,
"主工单不存在"
);
}
// 验证主工单当前节点
String
currentNode
=
changeRecord
.
getFlowNode
();
if
(!
ChangeFlowEnum
.
NEW_CHANGE_FLOW_CONFIRM_EXEC_PLAN
.
getNodeId
().
equals
(
currentNode
))
{
throw
ExceptionFactory
.
createBiz
(
ResponseCode
.
NODE_ERROR
,
String
.
format
(
"主工单当前节点不是确认变更方案节点,无法流转。当前节点:%s"
,
currentNode
));
}
try
{
Long
flowId
=
changeRecord
.
getFlowId
();
String
uid
=
RequestLocalBean
.
getUid
();
if
(
StringUtils
.
isBlank
(
uid
))
{
uid
=
"system"
;
}
// 获取工单详情
FlowDataDTO
flowDataDTO
=
flowService
.
flowDetail
(
flowId
.
toString
());
if
(
flowDataDTO
==
null
)
{
throw
ExceptionFactory
.
createBiz
(
ResponseCode
.
DETAIL_FLOW_ERROR
,
"工单查询错误,不存在"
);
}
// 构建提交内容
Map
<
String
,
Object
>
content
=
buildFlowContent
();
// 使用paramMap控制流转方向(所有子单审批通过)
Map
<
String
,
Object
>
paramMap
=
new
HashMap
<>();
paramMap
.
put
(
"type"
,
FlowTransitionType
.
TYPE_APPROVED
);
// 流转主工单到部门负责人审批节点
String
ownerApproveNodeId
=
flowService
.
submitFlowWithParamMap
(
flowId
.
toString
(),
flowDataDTO
,
uid
,
ChangeFlowEnum
.
NEW_CHANGE_FLOW
.
getTopoId
(),
JSON
.
toJSONString
(
content
),
paramMap
,
FlowxOperationEnum
.
SUBMIT
.
getName
(),
"所有子单审批通过,主工单流转"
,
changeRecord
.
getCreateTime
());
changeRecord
.
setFlowNode
(
ownerApproveNodeId
);
changeRecord
.
setState
(
ChangeStatusEnum
.
WAIT_DEPT_LEADER_APPROVE
.
getStatus
());
changeRecord
.
setUpdateTime
(
DateUtils
.
getCurrentTime
());
// 获取变更负责人的上级领导并设置为审批人
String
changeCommander
=
changeRecord
.
getChangeCommander
();
if
(
StringUtils
.
isBlank
(
changeCommander
))
{
throw
ExceptionFactory
.
createBiz
(
ResponseCode
.
BAD_REQUEST
,
"变更负责人邮箱不能为空"
);
}
String
leaderEmail
=
departmentLeaderBiz
.
getDepartmentLeader
(
changeCommander
);
if
(
StringUtils
.
isBlank
(
leaderEmail
))
{
throw
ExceptionFactory
.
createBiz
(
ResponseCode
.
BAD_REQUEST
,
String
.
format
(
"变更负责人[%s]的部门上级领导不存在"
,
changeCommander
));
}
// 设置审批人为上级领导(JSON 数组格式)
changeRecord
.
setApprover
(
JSON
.
toJSONString
(
Collections
.
singletonList
(
leaderEmail
)));
changeFlowService
.
updateRecord
(
changeRecord
);
log
.
info
(
"[submitMainFlowAfterAllSubFlowsApproved] 主工单流转成功,flowId:{}, nextNodeId:{}, approver:{}"
,
flowId
,
ownerApproveNodeId
,
leaderEmail
);
}
catch
(
Exception
e
)
{
log
.
error
(
"[submitMainFlowAfterAllSubFlowsApproved] 主工单流转失败,changeRecordId:{}"
,
changeRecordId
,
e
);
throw
ExceptionFactory
.
createBiz
(
ResponseCode
.
BAD_REQUEST
,
String
.
format
(
"主工单流转失败:%s"
,
e
.
getMessage
()));
}
}
/**
* 所有子单执行完成后,流转主工单到确认执行结果节点
*
* @param changeRecordId 主工单ID
*/
private
void
submitMainFlowAfterAllSubFlowsFinished
(
Long
changeRecordId
)
{
// 查询主工单
ChangeRecord
changeRecord
=
changeRecordMapper
.
selectByPrimaryKey
(
changeRecordId
);
if
(
changeRecord
==
null
)
{
log
.
error
(
"[submitMainFlowAfterAllSubFlowsFinished] 主工单不存在,changeRecordId:{}"
,
changeRecordId
);
throw
ExceptionFactory
.
createBiz
(
ResponseCode
.
BAD_REQUEST
,
"主工单不存在"
);
}
// 验证主工单当前节点
String
currentNode
=
changeRecord
.
getFlowNode
();
if
(!
ChangeFlowEnum
.
NEW_CHANGE_FLOW_EXE
.
getNodeId
().
equals
(
currentNode
))
{
log
.
warn
(
"[submitMainFlowAfterAllSubFlowsFinished] 主工单当前节点不是执行变更方案节点,无法流转。当前节点:{}"
,
currentNode
);
return
;
}
try
{
Long
flowId
=
changeRecord
.
getFlowId
();
String
uid
=
RequestLocalBean
.
getUid
();
if
(
StringUtils
.
isBlank
(
uid
))
{
uid
=
"system"
;
}
String
name
=
RequestLocalBean
.
getName
();
if
(
StringUtils
.
isBlank
(
name
))
{
name
=
"系统"
;
}
// 获取工单详情
FlowDataDTO
flowDataDTO
=
flowService
.
flowDetail
(
flowId
.
toString
());
if
(
flowDataDTO
==
null
)
{
throw
ExceptionFactory
.
createBiz
(
ResponseCode
.
DETAIL_FLOW_ERROR
,
"工单查询错误,不存在"
);
}
// 构建提交内容
Map
<
String
,
Object
>
content
=
buildFlowContent
();
// 使用paramMap控制流转方向(所有子单执行结果完成)
Map
<
String
,
Object
>
paramMap
=
new
HashMap
<>();
paramMap
.
put
(
"type"
,
FlowTransitionType
.
TYPE_APPROVED
);
// 流转主工单到确认变更结果节点
String
confirmNodeId
=
flowService
.
submitFlowWithParamMap
(
flowId
.
toString
(),
flowDataDTO
,
uid
,
ChangeFlowEnum
.
NEW_CHANGE_FLOW
.
getTopoId
(),
JSON
.
toJSONString
(
content
),
paramMap
,
FlowxOperationEnum
.
SUBMIT
.
getName
(),
"所有子单执行结果完成,主工单流转"
,
changeRecord
.
getCreateTime
());
changeRecord
.
setFlowNode
(
confirmNodeId
);
changeRecord
.
setState
(
ChangeStatusEnum
.
WAIT_CONFIRM_EXEC_RESULT
.
getStatus
());
changeRecord
.
setUpdateTime
(
DateUtils
.
getCurrentTime
());
changeFlowService
.
updateRecord
(
changeRecord
);
log
.
info
(
"[submitMainFlowAfterAllSubFlowsFinished] 主工单流转成功,flowId:{}, nextNodeId:{}, state:{}"
,
flowId
,
confirmNodeId
,
ChangeStatusEnum
.
WAIT_CONFIRM_EXEC_RESULT
.
getStatus
());
}
catch
(
Exception
e
)
{
log
.
error
(
"[submitMainFlowAfterAllSubFlowsFinished] 主工单流转失败,changeRecordId:{}"
,
changeRecordId
,
e
);
throw
ExceptionFactory
.
createBiz
(
ResponseCode
.
BAD_REQUEST
,
String
.
format
(
"主工单流转失败:%s"
,
e
.
getMessage
()));
}
}
/**
* 检查主工单下所有子单是否都已完成
* 以节点为准:如果节点是结束节点(9999),则认为已完成,允许主工单流转
*
* @param changeRecordId 主工单ID
* @return true 表示所有子单都已完成
*/
private
boolean
checkAllSubFlowsFinishedForMainFlow
(
Long
changeRecordId
)
{
// 查询该主工单下所有子单
List
<
ChangeSubFlowRecord
>
allSubFlows
=
changeSubFlowRecordMapper
.
selectByChangeRecordId
(
changeRecordId
);
if
(
CollectionUtils
.
isEmpty
(
allSubFlows
))
{
return
false
;
}
// 检查是否所有子单都满足条件:以节点为准,节点是结束节点则认为已完成
return
allSubFlows
.
stream
().
allMatch
(
subFlow
->
{
// 判断节点是否为结束节点(9999),节点是最准确的
boolean
isEndNode
=
ChangeFlowEnum
.
SUB_FLOW_END
.
getNodeId
().
equals
(
subFlow
.
getSubFlowNode
());
if
(
isEndNode
)
{
// 节点是结束节点,认为已完成,允许流转
// 如果状态不对,打印日志提醒
Integer
status
=
subFlow
.
getStatus
();
if
(!
ChangeSubFlowStatusEnum
.
FINISHED
.
getStatus
().
equals
(
status
)
&&
!
ChangeSubFlowStatusEnum
.
CANCELLED
.
getStatus
().
equals
(
status
))
{
log
.
warn
(
"[checkAllSubFlowsFinishedForMainFlow] 子单节点已是结束节点,但状态不正确,subFlowId:{}, status:{}, 期望状态:{}或{}"
,
subFlow
.
getSubFlowId
(),
status
,
ChangeSubFlowStatusEnum
.
FINISHED
.
getStatus
(),
ChangeSubFlowStatusEnum
.
CANCELLED
.
getStatus
());
}
return
true
;
}
return
false
;
});
}
/**
* 发送子单完成/取消邮件
*
* @param subFlowRecord 子单记录
...
...
@@ -701,6 +890,27 @@ public class ChangeSubFlowBiz {
// mainFlowNode:设置主单的节点,用于前端判断是否允许提交执行结果
changeFlowVO
.
setMainFlowNode
(
mainRecord
.
getFlowNode
());
// 子单特有字段:从子单记录中获取并设置到VO中
changeFlowVO
.
setChangeResult
(
subFlowRecord
.
getChangeResult
());
changeFlowVO
.
setRemark
(
subFlowRecord
.
getRemark
());
changeFlowVO
.
setCancelReason
(
subFlowRecord
.
getCancelReason
());
changeFlowVO
.
setChangeConfirmResultTime
(
subFlowRecord
.
getChangeConfirmResultTime
());
// 查询子单的文件(替换主单的文件)
List
<
ChangeSubFlowFile
>
subFlowFiles
=
changeSubFlowFileService
.
getFileList
(
subFlowRecordId
);
if
(
CollectionUtils
.
isNotEmpty
(
subFlowFiles
))
{
List
<
ChangeFlowFile
>
fileList
=
subFlowFiles
.
stream
().
map
(
f
->
{
ChangeFlowFile
file
=
new
ChangeFlowFile
();
file
.
setFileName
(
f
.
getFileName
());
file
.
setFileUrl
(
f
.
getFileUrl
());
file
.
setFileType
(
f
.
getFileType
());
return
file
;
}).
collect
(
Collectors
.
toList
());
changeFlowVO
.
setFiles
(
fileList
);
}
else
{
changeFlowVO
.
setFiles
(
new
ArrayList
<>());
}
// 只保留该变更行动工单下绑定的行动项
List
<
ChangeExecRecord
>
execRecords
=
changeFlowExecService
.
getBySubFlowRecordId
(
subFlowRecordId
);
if
(
CollectionUtils
.
isNotEmpty
(
execRecords
))
{
...
...
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