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
6cf69f04
authored
May 13, 2024
by
jason
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
仿钉钉流程设计器- 条件节点,新增条件规则配置
parent
672db903
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
351 additions
and
20 deletions
+351
-20
src/components/SimpleProcessDesignerV2/src/consts.ts
+71
-2
src/components/SimpleProcessDesignerV2/src/nodes-config/ConditionNodeConfig.vue
+280
-18
No files found.
src/components/SimpleProcessDesignerV2/src/consts.ts
View file @
6cf69f04
...
@@ -47,7 +47,21 @@ export enum NodeType {
...
@@ -47,7 +47,21 @@ export enum NodeType {
INCLUSIVE_NODE_JOIN
=
8
INCLUSIVE_NODE_JOIN
=
8
}
}
// 候选人策略 (用于审批节点。抄送节点
// 条件配置类型 ( 用于条件节点配置 )
export
enum
ConditionConfigType
{
/**
* 条件表达式
*/
EXPRESSION
=
1
,
/**
* 条件规则
*/
RULE
=
2
}
// 候选人策略 ( 用于审批节点。抄送节点 )
export
enum
CandidateStrategy
{
export
enum
CandidateStrategy
{
/**
/**
* 指定角色
* 指定角色
...
@@ -96,6 +110,31 @@ export type SimpleFlowNode = {
...
@@ -96,6 +110,31 @@ export type SimpleFlowNode = {
conditionNodes
?:
SimpleFlowNode
[]
conditionNodes
?:
SimpleFlowNode
[]
}
}
// 条件组
export
type
ConditionGroup
=
{
// 条件组的逻辑关系是否为且
and
:
boolean
,
// 条件数组
conditions
:
Condition
[]
}
// 条件
export
type
Condition
=
{
// 条件规则的逻辑关系是否为且
and
:
boolean
,
rules
:
ConditionRule
[]
}
// 条件规则
export
type
ConditionRule
=
{
type
:
number
,
opName
:
string
,
opCode
:
string
,
leftSide
:
string
,
rightSide
:
string
}
export
const
NODE_DEFAULT_TEXT
=
new
Map
<
number
,
string
>
()
export
const
NODE_DEFAULT_TEXT
=
new
Map
<
number
,
string
>
()
NODE_DEFAULT_TEXT
.
set
(
NodeType
.
USER_TASK_NODE
,
'请配置审批人'
)
NODE_DEFAULT_TEXT
.
set
(
NodeType
.
USER_TASK_NODE
,
'请配置审批人'
)
NODE_DEFAULT_TEXT
.
set
(
NodeType
.
COPY_TASK_NODE
,
'请配置抄送人'
)
NODE_DEFAULT_TEXT
.
set
(
NodeType
.
COPY_TASK_NODE
,
'请配置抄送人'
)
...
@@ -115,5 +154,35 @@ export const APPROVE_METHODS: DictDataVO [] = [
...
@@ -115,5 +154,35 @@ export const APPROVE_METHODS: DictDataVO [] = [
]
]
export
const
CONDITION_CONFIG_TYPES
:
DictDataVO
[]
=
[
export
const
CONDITION_CONFIG_TYPES
:
DictDataVO
[]
=
[
{
label
:
'自定义条件表达式'
,
value
:
1
}
{
label
:
'条件表达式'
,
value
:
1
},
{
label
:
'条件规则'
,
value
:
2
}
]
// 比较运算符
export
const
COMPARISON_OPERATORS
:
DictDataVO
=
[
{
value
:
'=='
,
label
:
'等于'
,
},
{
value
:
'!='
,
label
:
'不等于'
,
}
// 待完善
// {
// value: '>',
// label: '大于',
// },
// {
// value: '>=',
// label: '大于等于',
// },
// {
// value: '<',
// label: '小于',
// },
// {
// value: '<=',
// label: '小于等于',
// }
]
]
src/components/SimpleProcessDesignerV2/src/nodes-config/ConditionNodeConfig.vue
View file @
6cf69f04
...
@@ -3,8 +3,8 @@
...
@@ -3,8 +3,8 @@
:append-to-body=
"true"
:append-to-body=
"true"
v-model=
"settingVisible"
v-model=
"settingVisible"
:show-close=
"false"
:show-close=
"false"
:size=
"5
50
"
:size=
"5
88
"
:before-close=
"
saveConfig
"
:before-close=
"
handleClose
"
>
>
<template
#
header
>
<template
#
header
>
<div
class=
"config-header"
>
<div
class=
"config-header"
>
...
@@ -25,14 +25,18 @@
...
@@ -25,14 +25,18 @@
<div>
<div>
<div
class=
"mb-3 text-size-sm"
v-if=
"currentNode.attributes.defaultFlow"
>
其它条件不满足进入此分支(该分支不可编辑和删除)
</div>
<div
class=
"mb-3 text-size-sm"
v-if=
"currentNode.attributes.defaultFlow"
>
其它条件不满足进入此分支(该分支不可编辑和删除)
</div>
<div
v-else
>
<div
v-else
>
<el-form
label-position=
"top"
>
<el-form
<el-form-item
label=
"条件类型"
prop=
"conditionType"
>
ref=
"formRef"
:model=
"currentNode.attributes"
:rules=
"formRules"
label-position=
"top"
>
<el-form-item
label=
"配置方式"
prop=
"conditionType"
>
<el-radio-group
<el-radio-group
v-model=
"currentNode.attributes.conditionType"
v-model=
"currentNode.attributes.conditionType"
@
change=
"changeConditionType"
@
change=
"changeConditionType"
>
>
<el-radio
<el-radio
v-for=
"(dict, index) in
CONDITION_CONFIG_TYPES
"
v-for=
"(dict, index) in
conditionConfigTypes
"
:key=
"index"
:key=
"index"
:value=
"dict.value"
:value=
"dict.value"
:label=
"dict.value"
:label=
"dict.value"
...
@@ -54,13 +58,85 @@
...
@@ -54,13 +58,85 @@
style=
"width: 100%"
style=
"width: 100%"
/>
/>
</el-form-item>
</el-form-item>
<!--
<el-form-item
<el-form-item
v-if="currentNode.attributes.conditionType ===
1
"
v-if=
"currentNode.attributes.conditionType ===
2
"
label=
"条件规则"
label=
"条件规则"
prop="conditionExpression"
>
>
<span class="text-red-400">待实现</span>
<div
class=
"condition-group-tool"
>
</el-form-item> -->
<div
class=
"flex items-center"
>
<div
class=
"mr-4"
>
条件组关系
</div>
<el-switch
v-model=
"conditionGroups.and"
inline-prompt
active-text=
"且"
inactive-text=
"或"
/>
</div>
<!-- <div class="flex items-center">
<el-button size="small" type="primary">添加条件组</el-button>
</div> -->
</div>
<el-space
direction=
"vertical"
:spacer=
"conditionGroups.and ? '且' : '或' "
>
<el-card
class=
"condition-group"
style=
"width: 530px"
v-for=
"(condition, cIdx) in conditionGroups.conditions"
:key=
"cIdx"
>
<div
class=
"condition-group-delete"
v-if=
"conditionGroups.conditions.length > 1"
>
<Icon
color=
"#0089ff"
icon=
"ep:circle-close-filled"
:size=
"18"
@
click=
"deleteConditionGroup(cIdx)"
/>
</div>
<
template
#
header
>
<div
class=
"flex items-center justify-between"
>
<div>
条件组
</div>
<div
class=
"flex"
>
<div
class=
"mr-4"
>
规则关系
</div>
<el-switch
v-model=
"condition.and"
inline-prompt
active-text=
"且"
inactive-text=
"或"
/>
</div>
</div>
</
template
>
<div
class=
"flex pt-2"
v-for=
"(rule, rIdx) in condition.rules"
:key=
"rIdx"
>
<div
class=
"mr-2"
>
<el-select
style=
"width: 160px"
v-model=
"rule.leftSide"
>
<el-option
v-for=
"(item, index) in fieldsInfo"
:key=
"index"
:label=
"item.title"
:value=
"item.field"
/>
</el-select>
</div>
<div
class=
"mr-2"
>
<el-select
v-model=
"rule.opCode"
style=
"width: 100px"
>
<el-option
v-for=
"item in COMPARISON_OPERATORS"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</div>
<div
class=
"mr-2"
>
<el-input
v-model=
"rule.rightSide"
style=
"width: 160px"
/>
</div>
<div
class=
"mr-1 flex items-center"
v-if=
"condition.rules.length > 1"
>
<Icon
icon=
"ep:delete"
:size=
"18"
@
click=
"deleteConditionRule(condition,rIdx)"
/>
</div>
<div
class=
"flex items-center"
>
<Icon
icon=
"ep:plus"
:size=
"18"
@
click=
"addConditionRule(condition,rIdx)"
/>
</div>
</div>
</el-card>
</el-space>
<div
title=
"添加条件组"
class=
"mt-4 cursor-pointer"
>
<Icon
color=
"#0089ff"
icon=
"ep:plus"
:size=
"24"
@
click=
"addConditionGroup"
/>
</div>
</el-form-item>
</el-form>
</el-form>
</div>
</div>
</div>
</div>
...
@@ -74,11 +150,27 @@
...
@@ -74,11 +150,27 @@
</el-drawer>
</el-drawer>
</template>
</template>
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
SimpleFlowNode
,
CONDITION_CONFIG_TYPES
}
from
'../consts'
import
{
SimpleFlowNode
,
CONDITION_CONFIG_TYPES
,
ConditionConfigType
}
from
'../consts'
import
{
getDefaultConditionNodeName
}
from
'../utils'
;
import
{
getDefaultConditionNodeName
}
from
'../utils'
;
import
{
COMPARISON_OPERATORS
,
ConditionGroup
,
Condition
,
ConditionRule
}
from
'../consts'
;
const
message
=
useMessage
()
// 消息弹窗
defineOptions
({
defineOptions
({
name
:
'ConditionNode'
name
:
'ConditionNodeConfig'
})
const
formFields
=
inject
<
Ref
<
string
[]
>>
(
'formFields'
)
const
formType
=
inject
<
Ref
<
number
>>
(
'formType'
)
// 表单类型
const
conditionConfigTypes
=
computed
(
()
=>
{
return
CONDITION_CONFIG_TYPES
.
filter
(
item
=>
{
// 业务表单暂时去掉条件规则 选项
if
(
formType
?.
value
!==
10
){
return
item
.
value
===
1
}
else
{
return
true
;
}
});
})
})
const
props
=
defineProps
({
const
props
=
defineProps
({
conditionNode
:
{
conditionNode
:
{
type
:
Object
as
()
=>
SimpleFlowNode
,
type
:
Object
as
()
=>
SimpleFlowNode
,
...
@@ -91,6 +183,12 @@ const props = defineProps({
...
@@ -91,6 +183,12 @@ const props = defineProps({
})
})
const
settingVisible
=
ref
(
false
)
const
settingVisible
=
ref
(
false
)
const
open
=
()
=>
{
const
open
=
()
=>
{
getFieldsInfo
()
if
(
currentNode
.
value
.
attributes
.
conditionType
===
ConditionConfigType
.
RULE
)
{
if
(
currentNode
.
value
.
attributes
.
conditionGroups
)
{
conditionGroups
.
value
=
currentNode
.
value
.
attributes
.
conditionGroups
}
}
settingVisible
.
value
=
true
settingVisible
.
value
=
true
}
}
...
@@ -117,31 +215,195 @@ defineExpose({ open }) // 提供 open 方法,用于打开弹窗
...
@@ -117,31 +215,195 @@ defineExpose({ open }) // 提供 open 方法,用于打开弹窗
const
closeDrawer
=
()
=>
{
const
closeDrawer
=
()
=>
{
settingVisible
.
value
=
false
settingVisible
.
value
=
false
}
}
const
handleClose
=
async
(
done
:
(
cancel
?:
boolean
)
=>
void
)
=>
{
if
(
await
saveConfig
()){
done
(
false
);
// 传入 false 阻止关闭
}
else
{
done
();
}
}
// 表单校验规则
const
formRules
=
reactive
({
conditionType
:
[{
required
:
true
,
message
:
'配置方式不能为空'
,
trigger
:
'blur'
}],
conditionExpression
:
[{
required
:
true
,
message
:
'条件表达式不能为空'
,
trigger
:
'blur'
}]
})
const
formRef
=
ref
()
// 表单 Ref
// 保存配置
// 保存配置
const
saveConfig
=
()
=>
{
const
saveConfig
=
async
()
=>
{
if
(
!
currentNode
.
value
.
attributes
.
defaultFlow
)
{
if
(
!
currentNode
.
value
.
attributes
.
defaultFlow
)
{
currentNode
.
value
.
showText
=
getShowText
();
// 校验表单
if
(
!
formRef
)
return
false
const
valid
=
await
formRef
.
value
.
validate
()
if
(
!
valid
)
return
false
const
showText
=
getShowText
();
if
(
!
showText
){
return
false
;
}
currentNode
.
value
.
showText
=
showText
if
(
currentNode
.
value
.
attributes
.
conditionType
===
ConditionConfigType
.
EXPRESSION
){
currentNode
.
value
.
attributes
.
conditionGroups
=
undefined
}
if
(
currentNode
.
value
.
attributes
.
conditionType
===
ConditionConfigType
.
RULE
){
currentNode
.
value
.
attributes
.
conditionExpression
=
undefined
currentNode
.
value
.
attributes
.
conditionGroups
=
conditionGroups
.
value
}
}
}
settingVisible
.
value
=
false
settingVisible
.
value
=
false
return
true
;
}
}
const
getShowText
=
()
:
string
=>
{
const
getShowText
=
()
:
string
=>
{
let
showText
=
''
;
let
showText
=
''
;
// if (currentNode.value.attributes.conditionType === 1) {
if
(
currentNode
.
value
.
attributes
.
conditionType
===
ConditionConfigType
.
EXPRESSION
)
{
// showText = '待实现'
// }
if
(
currentNode
.
value
.
attributes
.
conditionType
===
1
)
{
if
(
currentNode
.
value
.
attributes
.
conditionExpression
)
{
if
(
currentNode
.
value
.
attributes
.
conditionExpression
)
{
showText
=
`表达式:
${
currentNode
.
value
.
attributes
.
conditionExpression
}
`
showText
=
`表达式:
${
currentNode
.
value
.
attributes
.
conditionExpression
}
`
}
}
}
}
if
(
currentNode
.
value
.
attributes
.
conditionType
===
ConditionConfigType
.
RULE
)
{
// 条件组是否为与关系
const
groupAnd
=
conditionGroups
.
value
.
and
;
let
warningMesg
:
undefined
|
string
=
undefined
const
conditionGroup
=
conditionGroups
.
value
.
conditions
.
map
(
item
=>
{
return
'('
+
item
.
rules
.
map
(
rule
=>
{
if
(
rule
.
leftSide
&&
rule
.
rightSide
)
{
return
getFieldTitle
(
rule
.
leftSide
)
+
" "
+
rule
.
opName
+
" "
+
rule
.
rightSide
}
else
{
// 又一条规则不完善。提示错误
warningMesg
=
'请完善条件规则'
return
''
}
}).
join
(
item
.
and
?
' 且 '
:
' 或 '
)
+
' ) '
}
)
if
(
warningMesg
)
{
message
.
warning
(
warningMesg
);
showText
=
''
;
}
else
{
showText
=
conditionGroup
.
join
(
groupAnd
?
' 且 '
:
' 或 '
);
}
}
return
showText
return
showText
}
}
// 改变条件配置方式
// 改变条件配置方式
const
changeConditionType
=
()
=>
{
const
changeConditionType
=
()
=>
{
}
}
const
conditionGroups
=
ref
<
ConditionGroup
>
({
and
:
true
,
conditions
:
[
{
and
:
true
,
rules
:
[
{
type
:
1
,
opName
:
"等于"
,
opCode
:
"=="
,
leftSide
:
""
,
rightSide
:
""
}
]
}
]
})
// 添加条件组
const
addConditionGroup
=
()
=>
{
const
condition
=
{
and
:
true
,
rules
:
[
{
type
:
1
,
opName
:
"等于"
,
opCode
:
"=="
,
leftSide
:
""
,
rightSide
:
""
}
]
}
conditionGroups
.
value
.
conditions
.
push
(
condition
)
}
// 删除条件组
const
deleteConditionGroup
=
(
idx
:
number
)
=>
{
conditionGroups
.
value
.
conditions
.
splice
(
idx
,
1
)
}
// 添加条件规则
const
addConditionRule
=
(
condition
:
Condition
,
idx
:
number
)
=>
{
const
rule
:
ConditionRule
=
{
type
:
1
,
opName
:
"等于"
,
opCode
:
"=="
,
leftSide
:
""
,
rightSide
:
""
}
condition
.
rules
.
splice
(
idx
+
1
,
0
,
rule
)
}
const
deleteConditionRule
=
(
condition
:
Condition
,
idx
:
number
)
=>
{
condition
.
rules
.
splice
(
idx
,
1
)
}
const
fieldsInfo
:
any
[]
=
[];
const
getFieldsInfo
=
()
=>
{
if
(
formFields
){
formFields
.
value
.
forEach
((
fieldStr
:
string
)
=>
{
const
{
field
,
title
,
type
}
=
JSON
.
parse
(
fieldStr
)
fieldsInfo
.
push
({
field
,
title
,
type
})
})
}
}
const
getFieldTitle
=
(
field
:
string
)
:
string
=>
{
const
item
=
fieldsInfo
.
find
(
item
=>
item
.
field
===
field
)
return
item
?.
title
;
}
</
script
>
</
script
>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
.condition-group-tool
{
display
:
flex
;
justify-content
:
space-between
;
width
:
500px
;
margin-bottom
:
20px
;
}
.condition-group
{
position
:
relative
;
&:hover
{
border-color
:
#0089ff
;
.condition-group-delete
{
opacity
:
1
;
}
}
.condition-group-delete
{
position
:
absolute
;
top
:
0
;
left
:
0
;
display
:
flex
;
cursor
:
pointer
;
opacity
:
0
;
}
}
::v-deep
(
.el-card__header
)
{
padding
:
8px
var
(
--el-card-padding
);
border-bottom
:
1px
solid
var
(
--el-card-border-color
);
box-sizing
:
border-box
;
}
</
style
>
</
style
>
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