Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
admin
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
8465f8fa
authored
Oct 29, 2024
by
jason
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
【功能完善】仿钉钉流程模型浏览,增加弹窗显示用户任务信息
parent
7044bcee
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
282 additions
and
601 deletions
+282
-601
src/components/SimpleProcessDesignerV2/src/SimpleProcessViewer.vue
+26
-3
src/components/SimpleProcessDesignerV2/src/nodes/EndEventNode.vue
+79
-2
src/components/SimpleProcessDesignerV2/src/nodes/StartUserNode.vue
+84
-5
src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue
+85
-7
src/components/SimpleProcessDesignerV2/theme/simple-process-designer.scss
+1
-571
src/views/bpm/processInstance/detail/ProcessInstanceSimpleViewer.vue
+7
-13
No files found.
src/components/SimpleProcessDesignerV2/src/SimpleProcessViewer.vue
View file @
8465f8fa
<
template
>
<SimpleProcessModel
:flow-node=
"simpleModel"
:readonly=
"true"
/>
<SimpleProcessModel
:flow-node=
"simpleModel"
:readonly=
"true"
/>
</
template
>
<
script
setup
lang=
"ts"
>
...
...
@@ -16,10 +16,33 @@ const props = defineProps({
required
:
true
},
// 流程任务
tasks
:
{
type
:
Array
,
tasks
:
{
type
:
Array
,
default
:
()
=>
[]
as
any
[]
},
// 流程实例
processInstance
:
{
type
:
Object
,
default
:
()
=>
undefined
}
})
const
approveTasks
=
ref
<
any
[]
>
(
props
.
tasks
)
const
currentProcessInstance
=
ref
(
props
.
processInstance
)
const
simpleModel
=
useWatchNode
(
props
)
watch
(
()
=>
props
.
tasks
,
(
newValue
)
=>
{
approveTasks
.
value
=
newValue
}
)
watch
(
()
=>
props
.
processInstance
,
(
newValue
)
=>
{
currentProcessInstance
.
value
=
newValue
}
)
provide
(
'tasks'
,
approveTasks
)
provide
(
'processInstance'
,
currentProcessInstance
)
</
script
>
p
src/components/SimpleProcessDesignerV2/src/nodes/EndEventNode.vue
View file @
8465f8fa
<
template
>
<div
class=
"end-node-wrapper"
>
<div
class=
"end-node-box
"
:class=
"`$
{useTaskStatusClass(currentNode?.activityStatus)}`
">
<div
class=
"end-node-box
cursor-pointer"
:class=
"`$
{useTaskStatusClass(currentNode?.activityStatus)}`" @click="nodeClick
">
<span
class=
"node-fixed-name"
title=
"结束"
>
结束
</span>
</div>
</div>
<el-dialog
title=
"审批信息"
v-model=
"dialogVisible"
width=
"1000px"
append-to-body
>
<el-row>
<el-table
:data=
"processInstanceInfos"
size=
"small"
border
header-cell-class-name=
"table-header-gray"
>
<el-table-column
label=
"序号"
header-align=
"center"
align=
"center"
type=
"index"
width=
"50"
/>
<el-table-column
label=
"发起人"
prop=
"assigneeUser.nickname"
min-width=
"100"
align=
"center"
/>
<el-table-column
label=
"部门"
min-width=
"100"
align=
"center"
>
<template
#
default=
"scope"
>
{{
scope
.
row
.
assigneeUser
?.
deptName
||
scope
.
row
.
ownerUser
?.
deptName
}}
</
template
>
</el-table-column>
<el-table-column
:formatter=
"dateFormatter"
align=
"center"
label=
"开始时间"
prop=
"createTime"
min-width=
"140"
/>
<el-table-column
:formatter=
"dateFormatter"
align=
"center"
label=
"结束时间"
prop=
"endTime"
min-width=
"140"
/>
<el-table-column
align=
"center"
label=
"审批状态"
prop=
"status"
min-width=
"90"
>
<
template
#
default=
"scope"
>
<dict-tag
:type=
"DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS"
:value=
"scope.row.status"
/>
</
template
>
</el-table-column>
<el-table-column
align=
"center"
label=
"耗时"
prop=
"durationInMillis"
width=
"100"
>
<
template
#
default=
"scope"
>
{{
formatPast2
(
scope
.
row
.
durationInMillis
)
}}
</
template
>
</el-table-column>
</el-table>
</el-row>
</el-dialog>
</template>
<
script
setup
lang=
"ts"
>
import
{
SimpleFlowNode
}
from
'../consts'
import
{
useWatchNode
,
useTaskStatusClass
}
from
'../node'
import
{
dateFormatter
,
formatPast2
}
from
'@/utils/formatTime'
import
{
DICT_TYPE
}
from
'@/utils/dict'
defineOptions
({
name
:
'EndEventNode'
})
...
...
@@ -20,6 +75,28 @@ const props = defineProps({
})
// 监控节点变化
const
currentNode
=
useWatchNode
(
props
)
// 是否只读
const
readonly
=
inject
<
Boolean
>
(
'readonly'
)
const
processInstance
=
inject
<
Ref
<
any
>>
(
'processInstance'
)
// 审批信息的弹窗显示,用于只读模式
const
dialogVisible
=
ref
(
false
)
// 弹窗可见性
const
processInstanceInfos
=
ref
<
any
[]
>
([])
// 流程的审批信息
const
nodeClick
=
()
=>
{
if
(
readonly
)
{
if
(
processInstance
&&
processInstance
.
value
){
processInstanceInfos
.
value
=
[
{
assigneeUser
:
processInstance
.
value
.
startUser
,
createTime
:
processInstance
.
value
.
startTime
,
endTime
:
processInstance
.
value
.
endTime
,
status
:
processInstance
.
value
.
status
,
durationInMillis
:
processInstance
.
value
.
durationInMillis
}
]
dialogVisible
.
value
=
true
}
}
}
</
script
>
<
style
lang=
"scss"
scoped
></
style
>
src/components/SimpleProcessDesignerV2/src/nodes/StartUserNode.vue
View file @
8465f8fa
...
...
@@ -22,7 +22,7 @@
{{
currentNode
.
name
}}
</div>
</div>
<div
class=
"node-content"
@
click=
"
openNodeConfig
"
>
<div
class=
"node-content"
@
click=
"
nodeClick
"
>
<div
class=
"node-text"
:title=
"currentNode.showText"
v-if=
"currentNode.showText"
>
{{
currentNode
.
showText
}}
</div>
...
...
@@ -37,12 +37,78 @@
</div>
</div>
<StartUserNodeConfig
v-if=
"!readonly && currentNode"
ref=
"nodeSetting"
:flow-node=
"currentNode"
/>
<!-- 审批记录 -->
<el-dialog
:title=
"dialogTitle || '审批记录'"
v-model=
"dialogVisible"
width=
"1000px"
append-to-body
>
<el-row>
<el-table
:data=
"selectTasks"
size=
"small"
border
header-cell-class-name=
"table-header-gray"
>
<el-table-column
label=
"序号"
header-align=
"center"
align=
"center"
type=
"index"
width=
"50"
/>
<el-table-column
label=
"审批人"
min-width=
"100"
align=
"center"
>
<template
#
default=
"scope"
>
{{
scope
.
row
.
assigneeUser
?.
nickname
||
scope
.
row
.
ownerUser
?.
nickname
}}
</
template
>
</el-table-column>
<el-table-column
label=
"部门"
min-width=
"100"
align=
"center"
>
<
template
#
default=
"scope"
>
{{
scope
.
row
.
assigneeUser
?.
deptName
||
scope
.
row
.
ownerUser
?.
deptName
}}
</
template
>
</el-table-column>
<el-table-column
:formatter=
"dateFormatter"
align=
"center"
label=
"开始时间"
prop=
"createTime"
min-width=
"140"
/>
<el-table-column
:formatter=
"dateFormatter"
align=
"center"
label=
"结束时间"
prop=
"endTime"
min-width=
"140"
/>
<el-table-column
align=
"center"
label=
"审批状态"
prop=
"status"
min-width=
"90"
>
<
template
#
default=
"scope"
>
<dict-tag
:type=
"DICT_TYPE.BPM_TASK_STATUS"
:value=
"scope.row.status"
/>
</
template
>
</el-table-column>
<el-table-column
align=
"center"
label=
"审批建议"
prop=
"reason"
min-width=
"120"
/>
<el-table-column
align=
"center"
label=
"耗时"
prop=
"durationInMillis"
width=
"100"
>
<
template
#
default=
"scope"
>
{{
formatPast2
(
scope
.
row
.
durationInMillis
)
}}
</
template
>
</el-table-column>
</el-table>
</el-row>
</el-dialog>
</template>
<
script
setup
lang=
"ts"
>
import
NodeHandler
from
'../NodeHandler.vue'
import
{
useWatchNode
,
useNodeName2
,
useTaskStatusClass
}
from
'../node'
import
{
SimpleFlowNode
,
NODE_DEFAULT_TEXT
,
NodeType
}
from
'../consts'
import
StartUserNodeConfig
from
'../nodes-config/StartUserNodeConfig.vue'
import
{
dateFormatter
,
formatPast2
}
from
'@/utils/formatTime'
import
{
DICT_TYPE
}
from
'@/utils/dict'
defineOptions
({
name
:
'StartEventNode'
})
...
...
@@ -53,6 +119,7 @@ const props = defineProps({
}
})
const
readonly
=
inject
<
Boolean
>
(
'readonly'
)
// 是否只读
const
tasks
=
inject
<
Ref
<
any
[]
>>
(
'tasks'
)
// 定义事件,更新父组件。
const
emits
=
defineEmits
<
{
'update:modelValue'
:
[
node
:
SimpleFlowNode
|
undefined
]
...
...
@@ -63,15 +130,27 @@ const currentNode = useWatchNode(props)
const
{
showInput
,
blurEvent
,
clickTitle
}
=
useNodeName2
(
currentNode
,
NodeType
.
START_USER_NODE
)
const
nodeSetting
=
ref
()
//
打开节点配置
const
openNodeConfig
=
()
=>
{
//
const
nodeClick
=
()
=>
{
if
(
readonly
)
{
return
// 只读模式,弹窗显示任务信息
if
(
tasks
&&
tasks
.
value
){
dialogTitle
.
value
=
currentNode
.
value
.
name
selectTasks
.
value
=
tasks
.
value
.
filter
((
item
:
any
)
=>
item
?.
taskDefinitionKey
===
currentNode
.
value
.
id
)
dialogVisible
.
value
=
true
}
// 把当前节点传递给配置组件
}
else
{
// 编辑模式,打开节点配置、把当前节点传递给配置组件
nodeSetting
.
value
.
showStartUserNodeConfig
(
currentNode
.
value
)
nodeSetting
.
value
.
openDrawer
()
}
}
// 任务的弹窗显示,用于只读模式
const
dialogVisible
=
ref
(
false
)
// 弹窗可见性
const
dialogTitle
=
ref
<
string
|
undefined
>
(
undefined
)
// 弹窗标题
const
selectTasks
=
ref
<
any
[]
|
undefined
>
([])
// 选中的任务数组
</
script
>
<
style
lang=
"scss"
scoped
></
style
>
src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue
View file @
8465f8fa
...
...
@@ -20,7 +20,7 @@
{{
currentNode
.
name
}}
</div>
</div>
<div
class=
"node-content"
@
click=
"
openNodeConfig
"
>
<div
class=
"node-content"
@
click=
"
nodeClick
"
>
<div
class=
"node-text"
:title=
"currentNode.showText"
v-if=
"currentNode.showText"
>
{{
currentNode
.
showText
}}
</div>
...
...
@@ -45,12 +45,78 @@
:flow-node=
"currentNode"
@
find:return-task-nodes=
"findReturnTaskNodes"
/>
<!-- 审批记录 -->
<el-dialog
:title=
"dialogTitle || '审批记录'"
v-model=
"dialogVisible"
width=
"1000px"
append-to-body
>
<el-row>
<el-table
:data=
"selectTasks"
size=
"small"
border
header-cell-class-name=
"table-header-gray"
>
<el-table-column
label=
"序号"
header-align=
"center"
align=
"center"
type=
"index"
width=
"50"
/>
<el-table-column
label=
"审批人"
min-width=
"100"
align=
"center"
>
<template
#
default=
"scope"
>
{{
scope
.
row
.
assigneeUser
?.
nickname
||
scope
.
row
.
ownerUser
?.
nickname
}}
</
template
>
</el-table-column>
<el-table-column
label=
"部门"
min-width=
"100"
align=
"center"
>
<
template
#
default=
"scope"
>
{{
scope
.
row
.
assigneeUser
?.
deptName
||
scope
.
row
.
ownerUser
?.
deptName
}}
</
template
>
</el-table-column>
<el-table-column
:formatter=
"dateFormatter"
align=
"center"
label=
"开始时间"
prop=
"createTime"
min-width=
"140"
/>
<el-table-column
:formatter=
"dateFormatter"
align=
"center"
label=
"结束时间"
prop=
"endTime"
min-width=
"140"
/>
<el-table-column
align=
"center"
label=
"审批状态"
prop=
"status"
min-width=
"90"
>
<
template
#
default=
"scope"
>
<dict-tag
:type=
"DICT_TYPE.BPM_TASK_STATUS"
:value=
"scope.row.status"
/>
</
template
>
</el-table-column>
<el-table-column
align=
"center"
label=
"审批建议"
prop=
"reason"
min-width=
"120"
/>
<el-table-column
align=
"center"
label=
"耗时"
prop=
"durationInMillis"
width=
"100"
>
<
template
#
default=
"scope"
>
{{
formatPast2
(
scope
.
row
.
durationInMillis
)
}}
</
template
>
</el-table-column>
</el-table>
</el-row>
</el-dialog>
</template>
<
script
setup
lang=
"ts"
>
import
{
SimpleFlowNode
,
NodeType
,
NODE_DEFAULT_TEXT
}
from
'../consts'
import
{
useWatchNode
,
useNodeName2
,
useTaskStatusClass
}
from
'../node'
import
NodeHandler
from
'../NodeHandler.vue'
import
UserTaskNodeConfig
from
'../nodes-config/UserTaskNodeConfig.vue'
import
{
dateFormatter
,
formatPast2
}
from
'@/utils/formatTime'
import
{
DICT_TYPE
}
from
'@/utils/dict'
defineOptions
({
name
:
'UserTaskNode'
})
...
...
@@ -67,26 +133,32 @@ const emits = defineEmits<{
// 是否只读
const
readonly
=
inject
<
Boolean
>
(
'readonly'
)
const
tasks
=
inject
<
Ref
<
any
[]
>>
(
'tasks'
)
// 监控节点变化
const
currentNode
=
useWatchNode
(
props
)
// 节点名称编辑
const
{
showInput
,
blurEvent
,
clickTitle
}
=
useNodeName2
(
currentNode
,
NodeType
.
START_USER_NODE
)
const
nodeSetting
=
ref
()
// 打开节点配置
const
openNodeConfig
=
()
=>
{
const
nodeClick
=
()
=>
{
if
(
readonly
)
{
return
if
(
tasks
&&
tasks
.
value
){
dialogTitle
.
value
=
currentNode
.
value
.
name
// 只读模式,弹窗显示任务信息
selectTasks
.
value
=
tasks
.
value
.
filter
((
item
:
any
)
=>
item
?.
taskDefinitionKey
===
currentNode
.
value
.
id
)
dialogVisible
.
value
=
true
}
// 把当前节点传递给配置组件
}
else
{
// 编辑模式,打开节点配置、把当前节点传递给配置组件
nodeSetting
.
value
.
showUserTaskNodeConfig
(
currentNode
.
value
)
nodeSetting
.
value
.
openDrawer
()
}
}
const
deleteNode
=
()
=>
{
emits
(
'update:flowNode'
,
currentNode
.
value
.
childNode
)
}
// 查找可以驳回用户节点
const
findReturnTaskNodes
=
(
matchNodeList
:
SimpleFlowNode
[]
// 匹配的节点
...
...
@@ -94,5 +166,11 @@ const findReturnTaskNodes = (
// 从父节点查找
emits
(
'find:parentNode'
,
matchNodeList
,
NodeType
.
USER_TASK_NODE
)
}
// 任务的弹窗显示,用于只读模式
const
dialogVisible
=
ref
(
false
)
// 弹窗可见性
const
dialogTitle
=
ref
<
string
|
undefined
>
(
undefined
)
// 弹窗标题
const
selectTasks
=
ref
<
any
[]
|
undefined
>
([])
// 选中的任务数组
</
script
>
<
style
lang=
"scss"
scoped
></
style
>
src/components/SimpleProcessDesignerV2/theme/simple-process-designer.scss
View file @
8465f8fa
// .simple-flow-canvas {
// z-index: 1;
// overflow: auto;
// background-color: #fafafa;
// // user-select: none;
// .simple-flow-container {
// position: relative;
// display: flex;
// flex-direction: column;
// justify-content: center;
// align-items: center;
// .top-area-container {
// position: sticky;
// inset: 0;
// display: flex;
// width: 100%;
// height: 42px;
// z-index: 1;
// // padding: 4px 0;
// background-color: #fff;
// justify-content: flex-end;
// align-items: center;
// .top-actions {
// display: flex;
// margin: 4px;
// margin-right: 8px;
// align-items: center;
// .canvas-control {
// font-size: 16px;
// .control-scale-group {
// display: inline-flex;
// align-items: center;
// margin-right: 8px;
// .control-scale-button {
// display: inline-flex;
// width: 28px;
// height: 28px;
// padding: 2px;
// text-align: center;
// cursor: pointer;
// justify-content: center;
// align-items: center;
// }
// .control-scale-label {
// margin: 0 4px;
// font-size: 14px;
// }
// }
// }
// }
// }
// .scale-container {
// display: flex;
// flex-direction: column;
// justify-content: center;
// align-items: center;
// margin-top: 16px;
// background-color: #fafafa;
// transform-origin: 50% 0 0;
// transform: scale(1);
// transition: transform 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
// // 节点容器 定义节点宽度
// .node-container {
// width: 200px;
// }
// // 节点
// .node-box {
// position: relative;
// display: flex;
// min-height: 70px;
// padding: 5px 10px 8px;
// cursor: pointer;
// background-color: #fff;
// flex-direction: column;
// border: 2px solid transparent;
// border-radius: 8px;
// box-shadow: 0 1px 4px 0 rgba(10, 30, 65, 0.16);
// transition: all 0.1s cubic-bezier(0.645, 0.045, 0.355, 1);
// &.status-pass {
// border-color: #67c23a;
// background-color: #a9da90;
// }
// &.status-pass:hover {
// border-color: #67c23a;
// }
// &.status-running {
// border-color: #5a9cf8;
// background-color: #e7f0fe;
// }
// &.status-running:hover {
// border-color: #5a9cf8;
// }
// &.status-reject {
// border-color: #e47470;
// background-color: #f6e5e5;
// }
// &.status-reject:hover {
// border-color: #e47470;
// }
// &:hover {
// border-color: #0089ff;
// .node-toolbar {
// opacity: 1;
// }
// .branch-node-move {
// display: flex;
// }
// }
// // 普通节点标题
// .node-title-container {
// display: flex;
// padding: 4px;
// cursor: pointer;
// border-radius: 4px 4px 0 0;
// align-items: center;
// .node-title-icon {
// display: flex;
// align-items: center;
// &.user-task {
// color: #ff943e;
// }
// &.copy-task {
// color: #3296fa;
// }
// &.start-user {
// color: #676565;
// }
// }
// .node-title {
// margin-left: 4px;
// font-size: 14px;
// font-weight: 600;
// white-space: nowrap;
// overflow: hidden;
// text-overflow: ellipsis;
// color: #1f1f1f;
// line-height: 18px;
// &:hover {
// border-bottom: 1px dashed #f60;
// }
// }
// }
// // 条件节点标题
// .branch-node-title-container {
// display: flex;
// padding: 4px 0;
// cursor: pointer;
// border-radius: 4px 4px 0 0;
// align-items: center;
// justify-content: space-between;
// .input-max-width {
// max-width: 115px !important;
// }
// .branch-title {
// font-size: 13px;
// font-weight: 600;
// white-space: nowrap;
// overflow: hidden;
// text-overflow: ellipsis;
// color: #f60;
// &:hover {
// border-bottom: 1px dashed #000;
// }
// }
// .branch-priority {
// min-width: 50px;
// font-size: 12px;
// }
// }
// .node-content {
// display: flex;
// min-height: 32px;
// padding: 4px 8px;
// margin-top: 4px;
// line-height: 32px;
// justify-content: space-between;
// align-items: center;
// color: #111f2c;
// background: rgba(0, 0, 0, 0.03);
// border-radius: 4px;
// .node-text {
// display: -webkit-box;
// overflow: hidden;
// font-size: 14px;
// line-height: 24px;
// text-overflow: ellipsis;
// word-break: break-all;
// -webkit-line-clamp: 2; /* 这将限制文本显示为两行 */
// -webkit-box-orient: vertical;
// }
// }
// //条件节点内容
// .branch-node-content {
// display: flex;
// min-height: 32px;
// padding: 4px 0;
// margin-top: 4px;
// line-height: 32px;
// align-items: center;
// color: #111f2c;
// border-radius: 4px;
// .branch-node-text {
// overflow: hidden;
// font-size: 12px;
// line-height: 24px;
// text-overflow: ellipsis;
// word-break: break-all;
// -webkit-line-clamp: 2; /* 这将限制文本显示为两行 */
// -webkit-box-orient: vertical;
// }
// }
// // 节点操作 :删除
// .node-toolbar {
// opacity: 0;
// position: absolute;
// top: -20px;
// right: 0px;
// display: flex;
// .toolbar-icon {
// text-align: center;
// vertical-align: middle;
// }
// }
// // 条件节点左右移动
// .branch-node-move {
// position: absolute;
// width: 10px;
// cursor: pointer;
// display: none;
// align-items: center;
// height: 100%;
// justify-content: center;
// }
// .move-node-left {
// left: -2px;
// top: 0px;
// background: rgba(126, 134, 142, 0.08);
// border-top-left-radius: 8px;
// border-bottom-left-radius: 8px;
// }
// .move-node-right {
// right: -2px;
// top: 0px;
// background: rgba(126, 134, 142, 0.08);
// border-top-right-radius: 6px;
// border-bottom-right-radius: 6px;
// }
// }
// .node-config-error {
// border-color: #ff5219 !important;
// }
// // 普通节点包装
// .node-wrapper {
// display: flex;
// flex-direction: column;
// justify-content: center;
// align-items: center;
// }
// // 节点连线处理
// .node-handler-wrapper {
// position: relative;
// display: flex;
// height: 70px;
// align-items: center;
// user-select: none;
// justify-content: center;
// flex-direction: column;
// &::before {
// position: absolute;
// top: 0;
// z-index: 0;
// width: 2px;
// height: 100%;
// margin: auto;
// background-color: #dedede;
// content: '';
// }
// .node-handler {
// .add-icon {
// position: relative;
// top: -5px;
// display: flex;
// align-items: center;
// justify-content: center;
// cursor: pointer;
// width: 25px;
// height: 25px;
// color: #fff;
// background-color: #0089ff;
// border-radius: 50%;
// &:hover {
// transform: scale(1.1);
// }
// }
// }
// .node-handler-arrow {
// position: absolute;
// bottom: 0;
// left: 50%;
// display: flex;
// transform: translateX(-50%);
// }
// }
// // 条件节点包装
// .branch-node-wrapper {
// position: relative;
// display: flex;
// flex-direction: column;
// justify-content: center;
// align-items: center;
// margin-top: 16px;
// .branch-node-container {
// position: relative;
// display: flex;
// &::before {
// position: absolute;
// height: 100%;
// width: 4px;
// background-color: #fafafa;
// content: '';
// left: 50%;
// transform: translate(-50%);
// }
// .branch-node-add {
// position: absolute;
// top: -18px;
// left: 50%;
// z-index: 1;
// height: 36px;
// padding: 0 10px;
// font-size: 12px;
// line-height: 36px;
// border: 2px solid #dedede;
// border-radius: 18px;
// transform: translateX(-50%);
// transform-origin: center center;
// }
// .branch-node-readonly {
// position: absolute;
// top: -18px;
// left: 50%;
// z-index: 1;
// width: 36px;
// height: 36px;
// display: flex;
// align-items: center;
// justify-content: center;
// border: 2px solid #dedede;
// background-color: #fff;
// border-radius: 50%;
// transform: translateX(-50%);
// transform-origin: center center;
// &.status-pass {
// border-color: #6bb63c;
// background-color: #e9f4e2;
// }
// &.status-pass:hover {
// border-color: #6bb63c;
// }
// .icon-size {
// font-size: 22px;
// color: #67c23a;
// }
// }
// .branch-node-item {
// position: relative;
// display: flex;
// flex-direction: column;
// align-items: center;
// min-width: 280px;
// padding: 40px 40px 0;
// background: transparent;
// border-top: 2px solid #dedede;
// border-bottom: 2px solid #dedede;
// &::before {
// position: absolute;
// width: 2px;
// height: 100%;
// margin: auto;
// inset: 0;
// background-color: #dedede;
// content: '';
// }
// }
// // 覆盖条件节点第一个节点左上角的线
// .branch-line-first-top {
// position: absolute;
// top: -5px;
// left: -1px;
// width: 50%;
// height: 7px;
// background-color: #fafafa;
// content: '';
// }
// // 覆盖条件节点第一个节点左下角的线
// .branch-line-first-bottom {
// position: absolute;
// bottom: -5px;
// left: -1px;
// width: 50%;
// height: 7px;
// background-color: #fafafa;
// content: '';
// }
// // 覆盖条件节点最后一个节点右上角的线
// .branch-line-last-top {
// position: absolute;
// top: -5px;
// right: -1px;
// width: 50%;
// height: 7px;
// background-color: #fafafa;
// content: '';
// }
// // 覆盖条件节点最后一个节点右下角的线
// .branch-line-last-bottom {
// position: absolute;
// right: -1px;
// bottom: -5px;
// width: 50%;
// height: 7px;
// background-color: #fafafa;
// content: '';
// }
// }
// }
// .node-fixed-name {
// display: inline-block;
// width: auto;
// padding: 0 4px;
// overflow: hidden;
// text-align: center;
// text-overflow: ellipsis;
// white-space: nowrap;
// }
// // 开始节点包装
// .start-node-wrapper {
// position: relative;
// margin-top: 16px;
// .start-node-container {
// display: flex;
// flex-direction: column;
// justify-content: center;
// align-items: center;
// .start-node-box {
// display: flex;
// justify-content: center;
// align-items: center;
// width: 90px;
// height: 36px;
// padding: 3px 4px;
// color: #212121;
// cursor: pointer;
// background: #fafafa;
// border-radius: 30px;
// box-shadow: 0 1px 5px 0 rgba(10, 30, 65, 0.08);
// box-sizing: border-box;
// }
// }
// }
// // 结束节点包装
// .end-node-wrapper {
// margin-bottom: 16px;
// .end-node-box {
// display: flex;
// justify-content: center;
// align-items: center;
// width: 80px;
// height: 36px;
// border: 2px solid #fafafa;
// color: #212121;
// border-radius: 30px;
// box-shadow: 0 1px 5px 0 rgba(10, 30, 65, 0.08);
// box-sizing: border-box;
// &.status-pass {
// border-color: #6bb63c;
// background-color: #a9da90;
// }
// &.status-pass:hover {
// border-color: #6bb63c;
// }
// &.status-reject {
// border-color: #e47470;
// background-color: #f6e5e5;
// }
// &.status-reject:hover {
// border-color: #e47470;
// }
// &.status-cancel {
// border-color: #919398;
// background-color: #eaeaeb;
// }
// &.status-cancel:hover {
// border-color: #919398;
// }
// }
// }
// // 可编辑的 title 输入框
// .editable-title-input {
// height: 20px;
// max-width: 145px;
// line-height: 20px;
// font-size: 12px;
// margin-left: 4px;
// border: 1px solid #d9d9d9;
// border-radius: 4px;
// transition: all 0.3s;
// &:focus {
// border-color: #40a9ff;
// outline: 0;
// box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
// }
// }
// }
// }
// }
// 配置节点头部
.config-header
{
...
...
@@ -739,7 +169,7 @@
font-size
:
13px
;
}
}
// Simple 流程模型样式
.simple-process-model-container
{
height
:
100%
;
overflow
:
auto
;
...
...
src/views/bpm/processInstance/detail/ProcessInstanceSimpleViewer.vue
View file @
8465f8fa
<
template
>
<div
v-loading=
"loading"
class=
"mb-20px"
>
<SimpleProcessViewer
:flow-node=
"simpleModel"
:tasks=
"tasks"
/>
<SimpleProcessViewer
:flow-node=
"simpleModel"
:tasks=
"tasks"
:process-instance=
"processInstance"
/>
</div>
</
template
>
<
script
lang=
"ts"
setup
>
...
...
@@ -16,10 +16,11 @@ const props = defineProps({
loading
:
propTypes
.
bool
.
def
(
false
),
// 是否加载中
id
:
propTypes
.
string
// 流程实例的编号
})
const
tasks
=
ref
([])
const
simpleModel
=
ref
()
// 用户任务
const
tasks
=
ref
([])
// 流程实例
const
processInstance
=
ref
()
/** 只有 loading 完成时,才去加载流程列表 */
watch
(
()
=>
props
.
loading
,
...
...
@@ -27,7 +28,8 @@ watch(
if
(
value
&&
props
.
id
)
{
const
modelView
=
await
ProcessInstanceApi
.
getProcessInstanceBpmnModelView
(
props
.
id
)
if
(
modelView
)
{
tasks
.
value
=
modelView
.
tasks
;
tasks
.
value
=
modelView
.
tasks
processInstance
.
value
=
modelView
.
processInstance
// 已经拒绝的活动节点编号集合,只包括 UserTask
const
rejectedTaskActivityIds
:
string
[]
=
modelView
.
rejectedTaskActivityIds
// 进行中的活动节点编号集合, 只包括 UserTask
...
...
@@ -44,7 +46,6 @@ watch(
finishedActivityIds
,
finishedSequenceFlowActivityIds
)
console
.
log
(
'modelView.simpleModel==>'
,
modelView
.
simpleModel
)
simpleModel
.
value
=
modelView
.
simpleModel
}
}
...
...
@@ -140,11 +141,4 @@ const setSimpleModelNodeTaskStatus = (
finishedSequenceFlowActivityIds
)
}
/** 监听 bpmnXml */
// watch(
// () => props.bpmnXml,
// (value) => {
// view.value.bpmnXml = value
// }
// )
</
script
>
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