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
22af2dc2
authored
May 07, 2024
by
jason
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
仿钉钉流程设计器- 优化节点配置
parent
e8193a0a
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
155 additions
and
63 deletions
+155
-63
src/components/SimpleProcessDesignerV2/src/nodes-config/ConditionNodeConfig.vue
+33
-12
src/components/SimpleProcessDesignerV2/src/nodes-config/CopyTaskNodeConfig.vue
+31
-10
src/components/SimpleProcessDesignerV2/src/nodes-config/UserTaskNodeConfig.vue
+25
-21
src/components/SimpleProcessDesignerV2/src/nodes/CopyTaskNode.vue
+1
-2
src/components/SimpleProcessDesignerV2/src/nodes/ExclusiveNode.vue
+12
-13
src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue
+1
-2
src/components/SimpleProcessDesignerV2/src/utils.ts
+7
-0
src/components/SimpleProcessDesignerV2/theme/simple-process-designer.scss
+45
-3
No files found.
src/components/SimpleProcessDesignerV2/src/nodes-config/ConditionNodeConfig.vue
View file @
22af2dc2
...
...
@@ -7,9 +7,19 @@
:before-close=
"saveConfig"
>
<template
#
header
>
<div
class=
"w-full flex flex-col"
>
<div
class=
"mb-2 text-size-2xl"
>
{{
currentNode
.
name
}}
</div>
<el-divider
/>
<div
class=
"config-header"
>
<input
v-if=
"showInput"
type=
"text"
class=
"config-editable-input"
@
blur=
"blurEvent()"
v-mountedFocus
v-model=
"currentNode.name"
:placeholder=
"currentNode.name"
/>
<div
v-else
class=
"node-name"
>
{{
currentNode
.
name
}}
<Icon
class=
"ml-1"
icon=
"ep:edit-pen"
:size=
"16"
@
click=
"clickIcon()"
/></div>
<div
class=
"divide-line"
></div>
</div>
</
template
>
<div>
...
...
@@ -65,6 +75,7 @@
</template>
<
script
setup
lang=
"ts"
>
import
{
SimpleFlowNode
,
CONDITION_CONFIG_TYPES
}
from
'../consts'
import
{
getDefaultConditionNodeName
}
from
'../utils'
;
defineOptions
({
name
:
'ConditionNode'
})
...
...
@@ -72,6 +83,10 @@ const props = defineProps({
conditionNode
:
{
type
:
Object
as
()
=>
SimpleFlowNode
,
required
:
true
},
nodeIndex
:
{
type
:
Number
,
required
:
true
}
})
const
settingVisible
=
ref
(
false
)
...
...
@@ -81,11 +96,22 @@ const open = () => {
watch
(()
=>
props
.
conditionNode
,
(
newValue
)
=>
{
currentNode
.
value
=
newValue
;
});
});
// 显示名称输入框
const
showInput
=
ref
(
false
)
const
clickIcon
=
()
=>
{
showInput
.
value
=
true
;
}
// 输入框失去焦点
const
blurEvent
=
()
=>
{
showInput
.
value
=
false
currentNode
.
value
.
name
=
currentNode
.
value
.
name
||
getDefaultConditionNodeName
(
props
.
nodeIndex
,
currentNode
.
value
.
attributes
?.
defaultFlow
)
}
const
currentNode
=
ref
<
SimpleFlowNode
>
(
props
.
conditionNode
)
// TODO nodeInfo 测试
defineExpose
({
open
,
nodeInfo
:
currentNode
})
// 提供 open 方法,用于打开弹窗
defineExpose
({
open
})
// 提供 open 方法,用于打开弹窗
// 关闭
const
closeDrawer
=
()
=>
{
...
...
@@ -117,10 +143,5 @@ const changeConditionType = () => {
</
script
>
<
style
lang=
"scss"
scoped
>
::v-deep
(
.el-divider--horizontal
)
{
display
:
block
;
height
:
1px
;
margin
:
0
;
border-top
:
1px
var
(
--el-border-color
)
var
(
--el-border-style
);
}
</
style
>
src/components/SimpleProcessDesignerV2/src/nodes-config/CopyTaskNodeConfig.vue
View file @
22af2dc2
...
...
@@ -7,9 +7,19 @@
:before-close=
"saveConfig"
>
<template
#
header
>
<div
class=
"w-full flex flex-col"
>
<div
class=
"mb-2 text-size-2xl"
>
{{
currentNode
.
name
}}
</div>
<el-divider
/>
<div
class=
"config-header"
>
<input
v-if=
"showInput"
type=
"text"
class=
"config-editable-input"
@
blur=
"blurEvent()"
v-mountedFocus
v-model=
"currentNode.name"
:placeholder=
"currentNode.name"
/>
<div
v-else
class=
"node-name"
>
{{
currentNode
.
name
}}
<Icon
class=
"ml-1"
icon=
"ep:edit-pen"
:size=
"16"
@
click=
"clickIcon()"
/></div>
<div
class=
"divide-line"
></div>
</div>
</
template
>
<el-tabs
type=
"border-card"
>
...
...
@@ -144,7 +154,7 @@
</el-drawer>
</template>
<
script
setup
lang=
'ts'
>
import
{
SimpleFlowNode
,
CandidateStrategy
}
from
'../consts'
import
{
SimpleFlowNode
,
CandidateStrategy
,
NodeType
,
NODE_DEFAULT_NAME
}
from
'../consts'
import
{
DICT_TYPE
,
getIntDictOptions
}
from
'@/utils/dict'
import
*
as
RoleApi
from
'@/api/system/role'
import
*
as
DeptApi
from
'@/api/system/dept'
...
...
@@ -282,6 +292,17 @@ const getShowText = () : string => {
}
return
showText
}
// 显示名称输入框
const
showInput
=
ref
(
false
)
const
clickIcon
=
()
=>
{
showInput
.
value
=
true
;
}
// 输入框失去焦点
const
blurEvent
=
()
=>
{
showInput
.
value
=
false
currentNode
.
value
.
name
=
currentNode
.
value
.
name
||
NODE_DEFAULT_NAME
.
get
(
NodeType
.
COPY_TASK_NODE
)
as
string
}
onMounted
(
async
()
=>
{
console
.
log
(
'candidateParam'
,
currentNode
.
value
.
attributes
?.
candidateParam
)
...
...
@@ -291,10 +312,10 @@ onMounted(async () => {
</
script
>
<
style
lang=
"scss"
scoped
>
::v-deep
(
.el-divider--horizontal
)
{
display
:
block
;
height
:
1px
;
margin
:
0
;
border-top
:
1px
var
(
--el-border-color
)
var
(
--el-border-style
);
}
//
::v-deep
(
.el-divider--horizontal
)
{
//
display
:
block
;
//
height
:
1px
;
//
margin
:
0
;
//
border-top
:
1px
var
(
--el-border-color
)
var
(
--el-border-style
);
//
}
</
style
>
src/components/SimpleProcessDesignerV2/src/nodes-config/UserTaskNodeConfig.vue
View file @
22af2dc2
...
...
@@ -8,9 +8,19 @@
class=
"justify-start"
>
<template
#
header
>
<div
class=
"w-full flex flex-col"
>
<div
class=
"mb-2 text-size-2xl"
>
{{
currentNode
.
name
}}
</div>
<el-divider
/>
<div
class=
"config-header"
>
<input
v-if=
"showInput"
type=
"text"
class=
"config-editable-input"
@
blur=
"blurEvent()"
v-mountedFocus
v-model=
"currentNode.name"
:placeholder=
"currentNode.name"
/>
<div
v-else
class=
"node-name"
>
{{
currentNode
.
name
}}
<Icon
class=
"ml-1"
icon=
"ep:edit-pen"
:size=
"16"
@
click=
"clickIcon()"
/></div>
<div
class=
"divide-line"
></div>
</div>
</
template
>
<el-tabs
type=
"border-card"
>
...
...
@@ -162,7 +172,7 @@
</template>
<
script
setup
lang=
"ts"
>
import
{
SimpleFlowNode
,
APPROVE_METHODS
,
CandidateStrategy
}
from
'../consts'
import
{
SimpleFlowNode
,
APPROVE_METHODS
,
CandidateStrategy
,
NodeType
,
NODE_DEFAULT_NAME
}
from
'../consts'
import
{
DICT_TYPE
,
getIntDictOptions
}
from
'@/utils/dict'
import
{
defaultProps
}
from
'@/utils/tree'
import
*
as
RoleApi
from
'@/api/system/role'
...
...
@@ -309,18 +319,18 @@ const changedCandidateUsers = () => {
notAllowedMultiApprovers
.
value
=
false
}
}
// 显示名称输入框
const
showInput
=
ref
(
false
)
const
clickIcon
=
()
=>
{
showInput
.
value
=
true
;
}
// 节点名称输入框失去焦点
const
blurEvent
=
()
=>
{
showInput
.
value
=
false
currentNode
.
value
.
name
=
currentNode
.
value
.
name
||
NODE_DEFAULT_NAME
.
get
(
NodeType
.
USER_TASK_NODE
)
as
string
}
onMounted
(
async
()
=>
{
// 获得角色列表
// roleOptions.value = await RoleApi.getSimpleRoleList()
// postOptions.value = await PostApi.getSimplePostList()
// // 获得用户列表
// userOptions.value = await UserApi.getSimpleUserList()
// // 获得部门列表
// deptOptions = await DeptApi.getSimpleDeptList()
// deptTreeOptions.value = handleTree(deptOptions, 'id')
// // 获得用户组列表
// userGroupOptions.value = await UserGroupApi.getUserGroupSimpleList()
console
.
log
(
'candidateParam'
,
currentNode
.
value
.
attributes
?.
candidateParam
)
candidateParamArray
.
value
=
currentNode
.
value
.
attributes
?.
candidateParam
?.
split
(
','
).
map
(
item
=>
+
item
)
console
.
log
(
'candidateParamArray.value'
,
candidateParamArray
.
value
)
if
(
currentNode
.
value
.
attributes
?.
candidateStrategy
===
CandidateStrategy
.
USER
&&
candidateParamArray
.
value
?.
length
<=
1
)
{
...
...
@@ -332,10 +342,4 @@ onMounted(async () => {
</
script
>
<
style
lang=
"scss"
scoped
>
::v-deep
(
.el-divider--horizontal
)
{
display
:
block
;
height
:
1px
;
margin
:
0
;
border-top
:
1px
var
(
--el-border-color
)
var
(
--el-border-style
);
}
</
style
>
src/components/SimpleProcessDesignerV2/src/nodes/CopyTaskNode.vue
View file @
22af2dc2
...
...
@@ -27,8 +27,7 @@
<Icon
icon=
"ep:arrow-right-bold"
/>
</div>
<div
class=
"node-toolbar"
>
<!--
<div
class=
"toolbar-icon"
><Icon
icon=
"ep:document-copy"
@
click=
"copyNode"
/></div>
-->
<div
class=
"toolbar-icon"
><Icon
icon=
"ep:delete"
:size=
"16"
@
click=
"deleteNode"
/></div>
<div
class=
"toolbar-icon"
><Icon
color=
"#0089ff"
icon=
"ep:circle-close-filled"
:size=
"18"
@
click=
"deleteNode"
/></div>
</div>
</div>
...
...
src/components/SimpleProcessDesignerV2/src/nodes/ExclusiveNode.vue
View file @
22af2dc2
...
...
@@ -15,10 +15,13 @@
<div
class=
"node-container"
>
<div
class=
"node-box"
:class=
"{ 'node-config-error': !item.showText }"
>
<div
class=
"branch-node-title-container"
>
<div
class=
"branch-title"
v-if=
"showInputs[index]"
>
<div
v-if=
"showInputs[index]"
>
<input
type=
"text"
class=
"input-max-width editable-title-input"
@
blur=
"blurEvent(index)"
v-mountedFocus
v-model=
"item.name"
/>
type=
"text"
class=
"input-max-width editable-title-input"
@
blur=
"blurEvent(index)"
v-mountedFocus
v-model=
"item.name"
/>
</div>
<div
v-else
class=
"branch-title"
@
click=
"clickEvent(index)"
>
{{ item.name }}
</div>
<div
class=
"branch-priority"
>
优先级{{ index + 1 }}
</div>
...
...
@@ -33,7 +36,7 @@ type="text" class="input-max-width editable-title-input" @blur="blurEvent(index)
</div>
<div
class=
"node-toolbar"
v-if=
"index + 1 !== currentNode.conditionNodes?.length"
>
<div
class=
"toolbar-icon"
>
<Icon
icon=
"ep:delete"
:size=
"16"
@
click=
"deleteCondition(index)"
/>
<Icon
color=
"#0089ff"
icon=
"ep:circle-close-filled"
:size=
"18"
@
click=
"deleteCondition(index)"
/>
</div>
</div>
<div
...
...
@@ -52,7 +55,7 @@ type="text" class="input-max-width editable-title-input" @blur="blurEvent(index)
<NodeHandler
v-model:child-node=
"item.childNode"
/>
</div>
</div>
<ConditionNodeConfig
:condition-node=
"item"
:ref=
"item.id"
/>
<ConditionNodeConfig
:
node-index=
"index"
:
condition-node=
"item"
:ref=
"item.id"
/>
<!-- 递归显示子节点 -->
<ProcessNodeTree
v-if=
"item && item.childNode"
v-model:flow-node=
"item.childNode"
/>
</div>
...
...
@@ -65,6 +68,7 @@ type="text" class="input-max-width editable-title-input" @blur="blurEvent(index)
import
NodeHandler
from
'../NodeHandler.vue'
import
ProcessNodeTree
from
'../ProcessNodeTree.vue'
import
{
SimpleFlowNode
,
NodeType
,
NODE_DEFAULT_TEXT
}
from
'../consts'
import
{
getDefaultConditionNodeName
}
from
'../utils'
import
{
generateUUID
}
from
'@/utils'
import
ConditionNodeConfig
from
'../nodes-config/ConditionNodeConfig.vue'
const
{
proxy
}
=
getCurrentInstance
()
as
any
...
...
@@ -88,29 +92,24 @@ const currentNode = ref<SimpleFlowNode>(props.flowNode)
watch
(()
=>
props
.
flowNode
,
(
newValue
)
=>
{
currentNode
.
value
=
newValue
;
});
// TODO 测试后续去掉
// watch(() => conditionNodes, (newValue) => {
// console.log('new conditionNodes is ', newValue);
// },{ deep: true });
const
showInputs
=
ref
<
boolean
[]
>
([])
// 失去焦点
const
blurEvent
=
(
index
:
number
)
=>
{
showInputs
.
value
[
index
]
=
false
const
conditionNode
=
currentNode
.
value
.
conditionNodes
?.
at
(
index
)
as
SimpleFlowNode
;
conditionNode
.
name
=
conditionNode
.
name
||
'条件'
+
index
conditionNode
.
name
=
conditionNode
.
name
||
getDefaultConditionNodeName
(
index
,
conditionNode
.
attributes
?.
defaultFlow
)
}
// 点击条件名称
const
clickEvent
=
(
index
:
number
)
=>
{
showInputs
.
value
[
index
]
=
true
}
const
conditionNodeConfig
=
(
nodeId
:
string
)
=>
{
console
.
log
(
'nodeId'
,
nodeId
);
console
.
log
(
"proxy.$refs"
,
proxy
.
$refs
);
// TODO 测试后续去掉
const
conditionNode
=
proxy
.
$refs
[
nodeId
][
0
];
console
.
log
(
"node inf is "
,
conditionNode
.
nodeInfo
);
conditionNode
.
open
()
}
...
...
src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue
View file @
22af2dc2
...
...
@@ -27,8 +27,7 @@
<Icon
icon=
"ep:arrow-right-bold"
/>
</div>
<div
class=
"node-toolbar"
>
<!--
<div
class=
"toolbar-icon"
><Icon
icon=
"ep:document-copy"
@
click=
"copyNode"
/></div>
-->
<div
class=
"toolbar-icon"
><Icon
icon=
"ep:delete"
:size=
"18"
@
click=
"deleteNode"
/></div>
<div
class=
"toolbar-icon"
><Icon
color=
"#0089ff"
icon=
"ep:circle-close-filled"
:size=
"18"
@
click=
"deleteNode"
/></div>
</div>
</div>
<!-- 传递子节点给添加节点组件。会在子节点前面添加节点 -->
...
...
src/components/SimpleProcessDesignerV2/src/utils.ts
0 → 100644
View file @
22af2dc2
// 获取条件节点默认的名称
export
const
getDefaultConditionNodeName
=
(
index
:
number
,
defaultFlow
:
boolean
)
:
string
=>
{
if
(
defaultFlow
){
return
"其它情况"
}
return
'条件'
+
(
index
+
1
)
}
src/components/SimpleProcessDesignerV2/theme/simple-process-designer.scss
View file @
22af2dc2
...
...
@@ -91,7 +91,7 @@
transition
:
all
0
.1s
cubic-bezier
(
0
.645
,
0
.045
,
0
.355
,
1
);
&
:hover
{
//
border-color: #0089ff;
border-color
:
#0089ff
;
.node-toolbar
{
opacity
:
1
;
}
...
...
@@ -130,6 +130,9 @@
text-overflow
:
ellipsis
;
color
:
#1f1f1f
;
line-height
:
18px
;
&
:hover
{
border-bottom
:
1px
dashed
#f60
;
}
}
}
...
...
@@ -153,6 +156,9 @@
overflow
:
hidden
;
text-overflow
:
ellipsis
;
color
:
#f60
;
&
:hover
{
border-bottom
:
1px
dashed
#000
;
}
}
.branch-priority
{
...
...
@@ -211,14 +217,13 @@
.node-toolbar
{
opacity
:
0
;
position
:
absolute
;
top
:
-2
5
px
;
top
:
-2
0
px
;
right
:
0px
;
display
:
flex
;
.toolbar-icon
{
text-align
:
center
;
vertical-align
:
middle
;
color
:
#000
;
}
}
...
...
@@ -501,10 +506,47 @@
}
}
}
}
// 配置节点头部
.config-header
{
display
:
flex
;
flex-direction
:
column
;
.node-name
{
display
:
flex
;
height
:
24px
;
line-height
:
24px
;
cursor
:
pointer
;
align-items
:
center
;
}
.divide-line
{
width
:
100%
;
height
:
1px
;
margin-top
:
16px
;
background
:
#eee
;
}
.config-editable-input
{
height
:
24px
;
max-width
:
510px
;
font-size
:
16px
;
line-height
:
24px
;
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
,
.2
)
}
}
}
// 节点连线气泡卡片样式
.handler-item-wrapper
{
display
:
flex
;
...
...
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