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
16a98e5a
authored
Mar 30, 2025
by
YunaiV
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feature/bpm' of
https://gitee.com/yudaocode/yudao-ui-admin-vue3
parents
8d9d9e76
e75dbd67
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
574 additions
and
126 deletions
+574
-126
src/components/DeptSelectForm/index.vue
+122
-0
src/components/SimpleProcessDesignerV2/src/NodeHandler.vue
+3
-2
src/components/SimpleProcessDesignerV2/src/SimpleProcessDesigner.vue
+6
-0
src/components/SimpleProcessDesignerV2/src/nodes-config/StartUserNodeConfig.vue
+57
-14
src/components/SimpleProcessDesignerV2/src/nodes-config/TriggerNodeConfig.vue
+6
-5
src/components/SimpleProcessDesignerV2/src/nodes-config/components/Condition.vue
+2
-1
src/components/SimpleProcessDesignerV2/src/nodes-config/components/ConditionDialog.vue
+4
-3
src/components/SimpleProcessDesignerV2/src/nodes/ExclusiveNode.vue
+11
-3
src/components/SimpleProcessDesignerV2/src/nodes/InclusiveNode.vue
+11
-3
src/views/bpm/model/CategoryDraggableModel.vue
+14
-1
src/views/bpm/model/form/BasicInfo.vue
+73
-1
src/views/bpm/model/form/ExtraSettings.vue
+81
-5
src/views/bpm/model/form/ProcessDesign.vue
+1
-0
src/views/bpm/model/form/index.vue
+12
-3
src/views/bpm/oa/leave/create.vue
+152
-85
src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue
+17
-0
src/views/bpm/simple/SimpleModelDesign.vue
+2
-0
No files found.
src/components/DeptSelectForm/index.vue
0 → 100644
View file @
16a98e5a
<
template
>
<Dialog
v-model=
"dialogVisible"
title=
"部门选择"
width=
"600"
>
<el-row
v-loading=
"formLoading"
>
<el-col
:span=
"24"
>
<ContentWrap
class=
"h-1/1"
>
<el-tree
ref=
"treeRef"
:data=
"deptTree"
:props=
"defaultProps"
show-checkbox
:check-strictly=
"checkStrictly"
check-on-click-node
default-expand-all
highlight-current
node-key=
"id"
@
check=
"handleCheck"
/>
</ContentWrap>
</el-col>
</el-row>
<template
#
footer
>
<el-button
:disabled=
"formLoading || !selectedDeptIds?.length"
type=
"primary"
@
click=
"submitForm"
>
确 定
</el-button>
<el-button
@
click=
"dialogVisible = false"
>
取 消
</el-button>
</
template
>
</Dialog>
</template>
<
script
lang=
"ts"
setup
>
import
{
defaultProps
,
handleTree
}
from
'@/utils/tree'
import
*
as
DeptApi
from
'@/api/system/dept'
defineOptions
({
name
:
'DeptSelectForm'
})
const
emit
=
defineEmits
<
{
confirm
:
[
deptList
:
any
[]]
}
>
()
const
{
t
}
=
useI18n
()
// 国际化
const
message
=
useMessage
()
// 消息弹窗
const
props
=
defineProps
({
// 是否严格的遵循父子不互相关联
checkStrictly
:
{
type
:
Boolean
,
default
:
false
},
// 是否支持多选
multiple
:
{
type
:
Boolean
,
default
:
true
}
})
const
treeRef
=
ref
()
const
deptTree
=
ref
<
Tree
[]
>
([])
// 部门树形结构
const
selectedDeptIds
=
ref
<
number
[]
>
([])
// 选中的部门 ID 列表
const
dialogVisible
=
ref
(
false
)
// 弹窗的是否展示
const
formLoading
=
ref
(
false
)
// 表单的加载中
/** 打开弹窗 */
const
open
=
async
(
selectedList
?:
DeptApi
.
DeptVO
[])
=>
{
resetForm
()
formLoading
.
value
=
true
try
{
// 加载部门列表
const
deptData
=
await
DeptApi
.
getSimpleDeptList
()
deptTree
.
value
=
handleTree
(
deptData
)
}
finally
{
formLoading
.
value
=
false
}
dialogVisible
.
value
=
true
// 设置已选择的部门
if
(
selectedList
?.
length
)
{
await
nextTick
()
const
selectedIds
=
selectedList
.
map
((
dept
)
=>
dept
.
id
)
.
filter
((
id
):
id
is
number
=>
id
!==
undefined
)
selectedDeptIds
.
value
=
selectedIds
treeRef
.
value
?.
setCheckedKeys
(
selectedIds
)
}
}
/** 处理选中状态变化 */
const
handleCheck
=
(
data
:
any
,
checked
:
any
)
=>
{
selectedDeptIds
.
value
=
treeRef
.
value
.
getCheckedKeys
()
if
(
!
props
.
multiple
&&
selectedDeptIds
.
value
.
length
>
1
)
{
// 单选模式下,只保留最后选择的节点
const
lastSelectedId
=
selectedDeptIds
.
value
[
selectedDeptIds
.
value
.
length
-
1
]
selectedDeptIds
.
value
=
[
lastSelectedId
]
treeRef
.
value
.
setCheckedKeys
([
lastSelectedId
])
}
}
/** 提交选择 */
const
submitForm
=
async
()
=>
{
try
{
// 获取选中的完整部门数据
const
checkedNodes
=
treeRef
.
value
.
getCheckedNodes
()
message
.
success
(
t
(
'common.updateSuccess'
))
dialogVisible
.
value
=
false
emit
(
'confirm'
,
checkedNodes
)
}
finally
{
}
}
/** 重置表单 */
const
resetForm
=
()
=>
{
deptTree
.
value
=
[]
selectedDeptIds
.
value
=
[]
if
(
treeRef
.
value
)
{
treeRef
.
value
.
setCheckedKeys
([])
}
}
defineExpose
({
open
})
// 提供 open 方法,用于打开弹窗
</
script
>
src/components/SimpleProcessDesignerV2/src/NodeHandler.vue
View file @
16a98e5a
...
@@ -91,6 +91,7 @@ import {
...
@@ -91,6 +91,7 @@ import {
DEFAULT_CONDITION_GROUP_VALUE
DEFAULT_CONDITION_GROUP_VALUE
}
from
'./consts'
}
from
'./consts'
import
{
generateUUID
}
from
'@/utils'
import
{
generateUUID
}
from
'@/utils'
import
{
cloneDeep
}
from
'lodash-es'
defineOptions
({
defineOptions
({
name
:
'NodeHandler'
name
:
'NodeHandler'
...
@@ -184,7 +185,7 @@ const addNode = (type: number) => {
...
@@ -184,7 +185,7 @@ const addNode = (type: number) => {
conditionSetting
:
{
conditionSetting
:
{
defaultFlow
:
false
,
defaultFlow
:
false
,
conditionType
:
ConditionType
.
RULE
,
conditionType
:
ConditionType
.
RULE
,
conditionGroups
:
DEFAULT_CONDITION_GROUP_VALUE
conditionGroups
:
cloneDeep
(
DEFAULT_CONDITION_GROUP_VALUE
)
}
}
},
},
{
{
...
@@ -242,7 +243,7 @@ const addNode = (type: number) => {
...
@@ -242,7 +243,7 @@ const addNode = (type: number) => {
conditionSetting
:
{
conditionSetting
:
{
defaultFlow
:
false
,
defaultFlow
:
false
,
conditionType
:
ConditionType
.
RULE
,
conditionType
:
ConditionType
.
RULE
,
conditionGroups
:
DEFAULT_CONDITION_GROUP_VALUE
conditionGroups
:
cloneDeep
(
DEFAULT_CONDITION_GROUP_VALUE
)
}
}
},
},
{
{
...
...
src/components/SimpleProcessDesignerV2/src/SimpleProcessDesigner.vue
View file @
16a98e5a
...
@@ -59,6 +59,11 @@ const props = defineProps({
...
@@ -59,6 +59,11 @@ const props = defineProps({
startUserIds
:
{
startUserIds
:
{
type
:
Array
,
type
:
Array
,
required
:
false
required
:
false
},
// 可发起流程的部门编号
startDeptIds
:
{
type
:
Array
,
required
:
false
}
}
})
})
...
@@ -82,6 +87,7 @@ provide('deptList', deptOptions)
...
@@ -82,6 +87,7 @@ provide('deptList', deptOptions)
provide
(
'userGroupList'
,
userGroupOptions
)
provide
(
'userGroupList'
,
userGroupOptions
)
provide
(
'deptTree'
,
deptTreeOptions
)
provide
(
'deptTree'
,
deptTreeOptions
)
provide
(
'startUserIds'
,
props
.
startUserIds
)
provide
(
'startUserIds'
,
props
.
startUserIds
)
provide
(
'startDeptIds'
,
props
.
startDeptIds
)
provide
(
'tasks'
,
[])
provide
(
'tasks'
,
[])
provide
(
'processInstance'
,
{})
provide
(
'processInstance'
,
{})
const
message
=
useMessage
()
// 国际化
const
message
=
useMessage
()
// 国际化
...
...
src/components/SimpleProcessDesignerV2/src/nodes-config/StartUserNodeConfig.vue
View file @
16a98e5a
...
@@ -25,21 +25,46 @@
...
@@ -25,21 +25,46 @@
</
template
>
</
template
>
<el-tabs
type=
"border-card"
v-model=
"activeTabName"
>
<el-tabs
type=
"border-card"
v-model=
"activeTabName"
>
<el-tab-pane
label=
"权限"
name=
"user"
>
<el-tab-pane
label=
"权限"
name=
"user"
>
<el-text
v-if=
"!startUserIds || startUserIds.length === 0"
>
全部成员可以发起流程
</el-text>
<el-text
<el-text
v-else-if=
"startUserIds.length == 1"
>
v-if=
"
{{ getUserNicknames(startUserIds) }} 可发起流程
(!startUserIds || startUserIds.length === 0) &&
</el-text>
(!startDeptIds || startDeptIds.length === 0)
<el-text
v-else
>
"
<el-tooltip
>
class=
"box-item"
全部成员可以发起流程
effect=
"dark"
placement=
"top"
:content=
"getUserNicknames(startUserIds)"
>
{{ getUserNicknames(startUserIds.slice(0, 2)) }} 等
{{ startUserIds.length }} 人可发起流程
</el-tooltip>
</el-text>
</el-text>
<div
v-else-if=
"startUserIds && startUserIds.length > 0"
>
<el-text
v-if=
"startUserIds.length == 1"
>
{{ getUserNicknames(startUserIds) }} 可发起流程
</el-text>
<el-text
v-else
>
<el-tooltip
class=
"box-item"
effect=
"dark"
placement=
"top"
:content=
"getUserNicknames(startUserIds)"
>
{{ getUserNicknames(startUserIds.slice(0, 2)) }} 等
{{ startUserIds.length }} 人可发起流程
</el-tooltip>
</el-text>
</div>
<div
v-else-if=
"startDeptIds && startDeptIds.length > 0"
>
<el-text
v-if=
"startDeptIds.length == 1"
>
{{ getDeptNames(startDeptIds) }} 可发起流程
</el-text>
<el-text
v-else
>
<el-tooltip
class=
"box-item"
effect=
"dark"
placement=
"top"
:content=
"getDeptNames(startDeptIds)"
>
{{ getDeptNames(startDeptIds.slice(0, 2)) }} 等
{{ startDeptIds.length }} 个部门可发起流程
</el-tooltip>
</el-text>
</div>
</el-tab-pane>
</el-tab-pane>
<el-tab-pane
label=
"表单字段权限"
name=
"fields"
v-if=
"formType === 10"
>
<el-tab-pane
label=
"表单字段权限"
name=
"fields"
v-if=
"formType === 10"
>
<div
class=
"field-setting-pane"
>
<div
class=
"field-setting-pane"
>
...
@@ -107,6 +132,7 @@
...
@@ -107,6 +132,7 @@
import
{
SimpleFlowNode
,
NodeType
,
FieldPermissionType
,
START_USER_BUTTON_SETTING
}
from
'../consts'
import
{
SimpleFlowNode
,
NodeType
,
FieldPermissionType
,
START_USER_BUTTON_SETTING
}
from
'../consts'
import
{
useWatchNode
,
useDrawer
,
useNodeName
,
useFormFieldsPermission
}
from
'../node'
import
{
useWatchNode
,
useDrawer
,
useNodeName
,
useFormFieldsPermission
}
from
'../node'
import
*
as
UserApi
from
'@/api/system/user'
import
*
as
UserApi
from
'@/api/system/user'
import
*
as
DeptApi
from
'@/api/system/dept'
defineOptions
({
defineOptions
({
name
:
'StartUserNodeConfig'
name
:
'StartUserNodeConfig'
})
})
...
@@ -118,8 +144,12 @@ const props = defineProps({
...
@@ -118,8 +144,12 @@ const props = defineProps({
})
})
// 可发起流程的用户编号
// 可发起流程的用户编号
const
startUserIds
=
inject
<
Ref
<
any
[]
>>
(
'startUserIds'
)
const
startUserIds
=
inject
<
Ref
<
any
[]
>>
(
'startUserIds'
)
// 可发起流程的部门编号
const
startDeptIds
=
inject
<
Ref
<
any
[]
>>
(
'startDeptIds'
)
// 用户列表
// 用户列表
const
userOptions
=
inject
<
Ref
<
UserApi
.
UserVO
[]
>>
(
'userList'
)
const
userOptions
=
inject
<
Ref
<
UserApi
.
UserVO
[]
>>
(
'userList'
)
// 部门列表
const
deptOptions
=
inject
<
Ref
<
DeptApi
.
DeptVO
[]
>>
(
'deptList'
)
// 抽屉配置
// 抽屉配置
const
{
settingVisible
,
closeDrawer
,
openDrawer
}
=
useDrawer
()
const
{
settingVisible
,
closeDrawer
,
openDrawer
}
=
useDrawer
()
// 当前节点
// 当前节点
...
@@ -145,6 +175,19 @@ const getUserNicknames = (userIds: number[]): string => {
...
@@ -145,6 +175,19 @@ const getUserNicknames = (userIds: number[]): string => {
})
})
return
nicknames
.
join
(
','
)
return
nicknames
.
join
(
','
)
}
}
const
getDeptNames
=
(
deptIds
:
number
[]):
string
=>
{
if
(
!
deptIds
||
deptIds
.
length
===
0
)
{
return
''
}
const
deptNames
:
string
[]
=
[]
deptIds
.
forEach
((
deptId
)
=>
{
const
found
=
deptOptions
?.
value
.
find
((
item
)
=>
item
.
id
===
deptId
)
if
(
found
&&
found
.
name
)
{
deptNames
.
push
(
found
.
name
)
}
})
return
deptNames
.
join
(
','
)
}
// 保存配置
// 保存配置
const
saveConfig
=
async
()
=>
{
const
saveConfig
=
async
()
=>
{
activeTabName
.
value
=
'user'
activeTabName
.
value
=
'user'
...
...
src/components/SimpleProcessDesignerV2/src/nodes-config/TriggerNodeConfig.vue
View file @
16a98e5a
...
@@ -254,6 +254,7 @@ import {
...
@@ -254,6 +254,7 @@ import {
import
{
useWatchNode
,
useDrawer
,
useNodeName
,
useFormFields
,
getConditionShowText
}
from
'../node'
import
{
useWatchNode
,
useDrawer
,
useNodeName
,
useFormFields
,
getConditionShowText
}
from
'../node'
import
HttpRequestSetting
from
'./components/HttpRequestSetting.vue'
import
HttpRequestSetting
from
'./components/HttpRequestSetting.vue'
import
ConditionDialog
from
'./components/ConditionDialog.vue'
import
ConditionDialog
from
'./components/ConditionDialog.vue'
import
{
cloneDeep
}
from
'lodash-es'
const
{
proxy
}
=
getCurrentInstance
()
as
any
const
{
proxy
}
=
getCurrentInstance
()
as
any
defineOptions
({
defineOptions
({
...
@@ -290,7 +291,7 @@ const configForm = ref<TriggerSetting>({
...
@@ -290,7 +291,7 @@ const configForm = ref<TriggerSetting>({
},
},
formSettings
:
[
formSettings
:
[
{
{
conditionGroups
:
DEFAULT_CONDITION_GROUP_VALUE
,
conditionGroups
:
cloneDeep
(
DEFAULT_CONDITION_GROUP_VALUE
)
,
updateFormFields
:
{},
updateFormFields
:
{},
deleteFields
:
[]
deleteFields
:
[]
}
}
...
@@ -346,7 +347,7 @@ const changeTriggerType = () => {
...
@@ -346,7 +347,7 @@ const changeTriggerType = () => {
?
originalSetting
.
formSettings
?
originalSetting
.
formSettings
:
[
:
[
{
{
conditionGroups
:
DEFAULT_CONDITION_GROUP_VALUE
,
conditionGroups
:
cloneDeep
(
DEFAULT_CONDITION_GROUP_VALUE
)
,
updateFormFields
:
{},
updateFormFields
:
{},
deleteFields
:
[]
deleteFields
:
[]
}
}
...
@@ -361,7 +362,7 @@ const changeTriggerType = () => {
...
@@ -361,7 +362,7 @@ const changeTriggerType = () => {
?
originalSetting
.
formSettings
?
originalSetting
.
formSettings
:
[
:
[
{
{
conditionGroups
:
DEFAULT_CONDITION_GROUP_VALUE
,
conditionGroups
:
cloneDeep
(
DEFAULT_CONDITION_GROUP_VALUE
)
,
updateFormFields
:
undefined
,
updateFormFields
:
undefined
,
deleteFields
:
[]
deleteFields
:
[]
}
}
...
@@ -374,7 +375,7 @@ const changeTriggerType = () => {
...
@@ -374,7 +375,7 @@ const changeTriggerType = () => {
/** 添加新的修改表单设置 */
/** 添加新的修改表单设置 */
const
addFormSetting
=
()
=>
{
const
addFormSetting
=
()
=>
{
configForm
.
value
.
formSettings
!
.
push
({
configForm
.
value
.
formSettings
!
.
push
({
conditionGroups
:
DEFAULT_CONDITION_GROUP_VALUE
,
conditionGroups
:
cloneDeep
(
DEFAULT_CONDITION_GROUP_VALUE
)
,
updateFormFields
:
{},
updateFormFields
:
{},
deleteFields
:
[]
deleteFields
:
[]
})
})
...
@@ -509,7 +510,7 @@ const showTriggerNodeConfig = (node: SimpleFlowNode) => {
...
@@ -509,7 +510,7 @@ const showTriggerNodeConfig = (node: SimpleFlowNode) => {
},
},
formSettings: node.triggerSetting.formSettings || [
formSettings: node.triggerSetting.formSettings || [
{
{
conditionGroups:
DEFAULT_CONDITION_GROUP_VALUE
,
conditionGroups:
cloneDeep(DEFAULT_CONDITION_GROUP_VALUE)
,
updateFormFields: {},
updateFormFields: {},
deleteFields: []
deleteFields: []
}
}
...
...
src/components/SimpleProcessDesignerV2/src/nodes-config/components/Condition.vue
View file @
16a98e5a
...
@@ -154,6 +154,7 @@ import {
...
@@ -154,6 +154,7 @@ import {
}
from
'../../consts'
}
from
'../../consts'
import
{
BpmModelFormType
}
from
'@/utils/constants'
import
{
BpmModelFormType
}
from
'@/utils/constants'
import
{
useFormFieldsAndStartUser
}
from
'../../node'
import
{
useFormFieldsAndStartUser
}
from
'../../node'
import
{
cloneDeep
}
from
'lodash-es'
const
props
=
defineProps
({
const
props
=
defineProps
({
modelValue
:
{
modelValue
:
{
...
@@ -196,7 +197,7 @@ const formRef = ref() // 表单 Ref
...
@@ -196,7 +197,7 @@ const formRef = ref() // 表单 Ref
const
changeConditionType
=
()
=>
{
const
changeConditionType
=
()
=>
{
if
(
condition
.
value
.
conditionType
===
ConditionType
.
RULE
)
{
if
(
condition
.
value
.
conditionType
===
ConditionType
.
RULE
)
{
if
(
!
condition
.
value
.
conditionGroups
)
{
if
(
!
condition
.
value
.
conditionGroups
)
{
condition
.
value
.
conditionGroups
=
DEFAULT_CONDITION_GROUP_VALUE
condition
.
value
.
conditionGroups
=
cloneDeep
(
DEFAULT_CONDITION_GROUP_VALUE
)
}
}
}
}
}
}
...
...
src/components/SimpleProcessDesignerV2/src/nodes-config/components/ConditionDialog.vue
View file @
16a98e5a
<!-- TODO @jason:有可能,它里面套 Condition 么? -->
<!-- TODO @jason:有可能,它里面套 Condition 么? -->
<!-- TODO 怕影响其它节点功能,后面看看如何如何复用 Condtion -->
<!-- TODO 怕影响其它节点功能,后面看看如何如何复用 Condtion -->
<
template
>
<
template
>
<Dialog
v-model=
"dialogVisible"
title=
"条件配置"
width=
"600px"
:fullscreen=
"false"
>
<Dialog
v-model=
"dialogVisible"
title=
"条件配置"
width=
"600px"
:fullscreen=
"false"
>
<div
class=
"h-410px"
>
<div
class=
"h-410px"
>
...
@@ -165,6 +165,7 @@ import {
...
@@ -165,6 +165,7 @@ import {
}
from
'../../consts'
}
from
'../../consts'
import
{
BpmModelFormType
}
from
'@/utils/constants'
import
{
BpmModelFormType
}
from
'@/utils/constants'
import
{
useFormFieldsAndStartUser
}
from
'../../node'
import
{
useFormFieldsAndStartUser
}
from
'../../node'
import
{
cloneDeep
}
from
'lodash-es'
defineOptions
({
defineOptions
({
name
:
'ConditionDialog'
name
:
'ConditionDialog'
})
})
...
@@ -175,7 +176,7 @@ const condition = ref<{
...
@@ -175,7 +176,7 @@ const condition = ref<{
conditionGroups
?:
ConditionGroup
conditionGroups
?:
ConditionGroup
}
>
({
}
>
({
conditionType
:
ConditionType
.
RULE
,
conditionType
:
ConditionType
.
RULE
,
conditionGroups
:
DEFAULT_CONDITION_GROUP_VALUE
conditionGroups
:
cloneDeep
(
DEFAULT_CONDITION_GROUP_VALUE
)
})
})
const
emit
=
defineEmits
<
{
const
emit
=
defineEmits
<
{
...
@@ -210,7 +211,7 @@ const formRef = ref() // 表单 Ref
...
@@ -210,7 +211,7 @@ const formRef = ref() // 表单 Ref
const
changeConditionType
=
()
=>
{
const
changeConditionType
=
()
=>
{
if
(
condition
.
value
.
conditionType
===
ConditionType
.
RULE
)
{
if
(
condition
.
value
.
conditionType
===
ConditionType
.
RULE
)
{
if
(
!
condition
.
value
.
conditionGroups
)
{
if
(
!
condition
.
value
.
conditionGroups
)
{
condition
.
value
.
conditionGroups
=
DEFAULT_CONDITION_GROUP_VALUE
condition
.
value
.
conditionGroups
=
cloneDeep
(
DEFAULT_CONDITION_GROUP_VALUE
)
}
}
}
}
}
}
...
...
src/components/SimpleProcessDesignerV2/src/nodes/ExclusiveNode.vue
View file @
16a98e5a
...
@@ -108,11 +108,18 @@
...
@@ -108,11 +108,18 @@
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
NodeHandler
from
'../NodeHandler.vue'
import
NodeHandler
from
'../NodeHandler.vue'
import
ProcessNodeTree
from
'../ProcessNodeTree.vue'
import
ProcessNodeTree
from
'../ProcessNodeTree.vue'
import
{
SimpleFlowNode
,
NodeType
,
ConditionType
,
DEFAULT_CONDITION_GROUP_VALUE
,
NODE_DEFAULT_TEXT
}
from
'../consts'
import
{
SimpleFlowNode
,
NodeType
,
ConditionType
,
DEFAULT_CONDITION_GROUP_VALUE
,
NODE_DEFAULT_TEXT
}
from
'../consts'
import
{
getDefaultConditionNodeName
}
from
'../utils'
import
{
getDefaultConditionNodeName
}
from
'../utils'
import
{
useTaskStatusClass
}
from
'../node'
import
{
useTaskStatusClass
}
from
'../node'
import
{
generateUUID
}
from
'@/utils'
import
{
generateUUID
}
from
'@/utils'
import
ConditionNodeConfig
from
'../nodes-config/ConditionNodeConfig.vue'
import
ConditionNodeConfig
from
'../nodes-config/ConditionNodeConfig.vue'
import
{
cloneDeep
}
from
'lodash-es'
const
{
proxy
}
=
getCurrentInstance
()
as
any
const
{
proxy
}
=
getCurrentInstance
()
as
any
defineOptions
({
defineOptions
({
name
:
'ExclusiveNode'
name
:
'ExclusiveNode'
...
@@ -149,7 +156,8 @@ const blurEvent = (index: number) => {
...
@@ -149,7 +156,8 @@ const blurEvent = (index: number) => {
showInputs
.
value
[
index
]
=
false
showInputs
.
value
[
index
]
=
false
const
conditionNode
=
currentNode
.
value
.
conditionNodes
?.
at
(
index
)
as
SimpleFlowNode
const
conditionNode
=
currentNode
.
value
.
conditionNodes
?.
at
(
index
)
as
SimpleFlowNode
conditionNode
.
name
=
conditionNode
.
name
=
conditionNode
.
name
||
getDefaultConditionNodeName
(
index
,
conditionNode
.
conditionSetting
?.
defaultFlow
)
conditionNode
.
name
||
getDefaultConditionNodeName
(
index
,
conditionNode
.
conditionSetting
?.
defaultFlow
)
}
}
// 点击条件名称
// 点击条件名称
...
@@ -181,7 +189,7 @@ const addCondition = () => {
...
@@ -181,7 +189,7 @@ const addCondition = () => {
conditionSetting
:
{
conditionSetting
:
{
defaultFlow
:
false
,
defaultFlow
:
false
,
conditionType
:
ConditionType
.
RULE
,
conditionType
:
ConditionType
.
RULE
,
conditionGroups
:
DEFAULT_CONDITION_GROUP_VALUE
conditionGroups
:
cloneDeep
(
DEFAULT_CONDITION_GROUP_VALUE
)
}
}
}
}
conditionNodes
.
splice
(
lastIndex
,
0
,
conditionData
)
conditionNodes
.
splice
(
lastIndex
,
0
,
conditionData
)
...
...
src/components/SimpleProcessDesignerV2/src/nodes/InclusiveNode.vue
View file @
16a98e5a
...
@@ -110,11 +110,18 @@
...
@@ -110,11 +110,18 @@
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
NodeHandler
from
'../NodeHandler.vue'
import
NodeHandler
from
'../NodeHandler.vue'
import
ProcessNodeTree
from
'../ProcessNodeTree.vue'
import
ProcessNodeTree
from
'../ProcessNodeTree.vue'
import
{
SimpleFlowNode
,
NodeType
,
ConditionType
,
DEFAULT_CONDITION_GROUP_VALUE
,
NODE_DEFAULT_TEXT
}
from
'../consts'
import
{
SimpleFlowNode
,
NodeType
,
ConditionType
,
DEFAULT_CONDITION_GROUP_VALUE
,
NODE_DEFAULT_TEXT
}
from
'../consts'
import
{
useTaskStatusClass
}
from
'../node'
import
{
useTaskStatusClass
}
from
'../node'
import
{
getDefaultInclusiveConditionNodeName
}
from
'../utils'
import
{
getDefaultInclusiveConditionNodeName
}
from
'../utils'
import
{
generateUUID
}
from
'@/utils'
import
{
generateUUID
}
from
'@/utils'
import
ConditionNodeConfig
from
'../nodes-config/ConditionNodeConfig.vue'
import
ConditionNodeConfig
from
'../nodes-config/ConditionNodeConfig.vue'
import
{
cloneDeep
}
from
'lodash-es'
const
{
proxy
}
=
getCurrentInstance
()
as
any
const
{
proxy
}
=
getCurrentInstance
()
as
any
defineOptions
({
defineOptions
({
name
:
'InclusiveNode'
name
:
'InclusiveNode'
...
@@ -153,7 +160,8 @@ const blurEvent = (index: number) => {
...
@@ -153,7 +160,8 @@ const blurEvent = (index: number) => {
showInputs
.
value
[
index
]
=
false
showInputs
.
value
[
index
]
=
false
const
conditionNode
=
currentNode
.
value
.
conditionNodes
?.
at
(
index
)
as
SimpleFlowNode
const
conditionNode
=
currentNode
.
value
.
conditionNodes
?.
at
(
index
)
as
SimpleFlowNode
conditionNode
.
name
=
conditionNode
.
name
=
conditionNode
.
name
||
getDefaultInclusiveConditionNodeName
(
index
,
conditionNode
.
conditionSetting
?.
defaultFlow
)
conditionNode
.
name
||
getDefaultInclusiveConditionNodeName
(
index
,
conditionNode
.
conditionSetting
?.
defaultFlow
)
}
}
// 点击条件名称
// 点击条件名称
...
@@ -185,7 +193,7 @@ const addCondition = () => {
...
@@ -185,7 +193,7 @@ const addCondition = () => {
conditionSetting
:
{
conditionSetting
:
{
defaultFlow
:
false
,
defaultFlow
:
false
,
conditionType
:
ConditionType
.
RULE
,
conditionType
:
ConditionType
.
RULE
,
conditionGroups
:
DEFAULT_CONDITION_GROUP_VALUE
conditionGroups
:
cloneDeep
(
DEFAULT_CONDITION_GROUP_VALUE
)
}
}
}
}
conditionNodes
.
splice
(
lastIndex
,
0
,
conditionData
)
conditionNodes
.
splice
(
lastIndex
,
0
,
conditionData
)
...
...
src/views/bpm/model/CategoryDraggableModel.vue
View file @
16a98e5a
...
@@ -97,10 +97,23 @@
...
@@ -97,10 +97,23 @@
</el-table-column>
</el-table-column>
<el-table-column
label=
"可见范围"
prop=
"startUserIds"
min-width=
"150"
>
<el-table-column
label=
"可见范围"
prop=
"startUserIds"
min-width=
"150"
>
<
template
#
default=
"{ row }"
>
<
template
#
default=
"{ row }"
>
<el-text
v-if=
"!row.startUsers?.length"
>
全部可见
</el-text>
<el-text
v-if=
"!row.startUsers?.length
&& !row.startDepts?.length
"
>
全部可见
</el-text>
<el-text
v-else-if=
"row.startUsers.length === 1"
>
<el-text
v-else-if=
"row.startUsers.length === 1"
>
{{
row
.
startUsers
[
0
].
nickname
}}
{{
row
.
startUsers
[
0
].
nickname
}}
</el-text>
</el-text>
<el-text
v-else-if=
"row.startDepts?.length === 1"
>
{{
row
.
startDepts
[
0
].
name
}}
</el-text>
<el-text
v-else-if=
"row.startDepts?.length > 1"
>
<el-tooltip
class=
"box-item"
effect=
"dark"
placement=
"top"
:content=
"row.startDepts.map((dept: any) => dept.name).join('、')"
>
{{
row
.
startDepts
[
0
].
name
}}
等
{{
row
.
startDepts
.
length
}}
个部门可见
</el-tooltip>
</el-text>
<el-text
v-else
>
<el-text
v-else
>
<el-tooltip
<el-tooltip
class=
"box-item"
class=
"box-item"
...
...
src/views/bpm/model/form/BasicInfo.vue
View file @
16a98e5a
...
@@ -77,6 +77,7 @@
...
@@ -77,6 +77,7 @@
>
>
<el-option
label=
"全员"
:value=
"0"
/>
<el-option
label=
"全员"
:value=
"0"
/>
<el-option
label=
"指定人员"
:value=
"1"
/>
<el-option
label=
"指定人员"
:value=
"1"
/>
<el-option
label=
"指定部门"
:value=
"2"
/>
</el-select>
</el-select>
<div
v-if=
"modelData.startUserType === 1"
class=
"mt-2 flex flex-wrap gap-2"
>
<div
v-if=
"modelData.startUserType === 1"
class=
"mt-2 flex flex-wrap gap-2"
>
<div
<div
...
@@ -99,6 +100,24 @@
...
@@ -99,6 +100,24 @@
<Icon
icon=
"ep:plus"
/>
选择人员
<Icon
icon=
"ep:plus"
/>
选择人员
</el-button>
</el-button>
</div>
</div>
<div
v-if=
"modelData.startUserType === 2"
class=
"mt-2 flex flex-wrap gap-2"
>
<div
v-for=
"dept in selectedStartDepts"
:key=
"dept.id"
class=
"bg-gray-100 h-35px rounded-3xl flex items-center pr-8px dark:color-gray-600 position-relative"
>
<Icon
icon=
"ep:office-building"
class=
"!m-5px text-20px"
/>
{{
dept
.
name
}}
<Icon
icon=
"ep:close"
class=
"ml-2 cursor-pointer hover:text-red-500"
@
click=
"handleRemoveStartDept(dept)"
/>
</div>
<el-button
type=
"primary"
link
@
click=
"openStartDeptSelect"
>
<Icon
icon=
"ep:plus"
/>
选择部门
</el-button>
</div>
</el-form-item>
</el-form-item>
<el-form-item
label=
"流程管理员"
prop=
"managerUserIds"
class=
"mb-20px"
>
<el-form-item
label=
"流程管理员"
prop=
"managerUserIds"
class=
"mb-20px"
>
<div
class=
"flex flex-wrap gap-2"
>
<div
class=
"flex flex-wrap gap-2"
>
...
@@ -127,11 +146,19 @@
...
@@ -127,11 +146,19 @@
<!-- 用户选择弹窗 -->
<!-- 用户选择弹窗 -->
<UserSelectForm
ref=
"userSelectFormRef"
@
confirm=
"handleUserSelectConfirm"
/>
<UserSelectForm
ref=
"userSelectFormRef"
@
confirm=
"handleUserSelectConfirm"
/>
<!-- 部门选择弹窗 -->
<DeptSelectForm
ref=
"deptSelectFormRef"
:multiple=
"true"
:check-strictly=
"true"
@
confirm=
"handleDeptSelectConfirm"
/>
</
template
>
</
template
>
<
script
lang=
"ts"
setup
>
<
script
lang=
"ts"
setup
>
import
{
DICT_TYPE
,
getBoolDictOptions
,
getIntDictOptions
}
from
'@/utils/dict'
import
{
DICT_TYPE
,
getBoolDictOptions
,
getIntDictOptions
}
from
'@/utils/dict'
import
{
UserVO
}
from
'@/api/system/user'
import
{
UserVO
}
from
'@/api/system/user'
import
{
DeptVO
}
from
'@/api/system/dept'
import
{
CategoryVO
}
from
'@/api/bpm/category'
import
{
CategoryVO
}
from
'@/api/bpm/category'
const
props
=
defineProps
({
const
props
=
defineProps
({
...
@@ -142,13 +169,19 @@ const props = defineProps({
...
@@ -142,13 +169,19 @@ const props = defineProps({
userList
:
{
userList
:
{
type
:
Array
,
type
:
Array
,
required
:
true
required
:
true
},
deptList
:
{
type
:
Array
,
required
:
true
}
}
})
})
const
formRef
=
ref
()
const
formRef
=
ref
()
const
selectedStartUsers
=
ref
<
UserVO
[]
>
([])
const
selectedStartUsers
=
ref
<
UserVO
[]
>
([])
const
selectedStartDepts
=
ref
<
DeptVO
[]
>
([])
const
selectedManagerUsers
=
ref
<
UserVO
[]
>
([])
const
selectedManagerUsers
=
ref
<
UserVO
[]
>
([])
const
userSelectFormRef
=
ref
()
const
userSelectFormRef
=
ref
()
const
deptSelectFormRef
=
ref
()
const
currentSelectType
=
ref
<
'start'
|
'manager'
>
(
'start'
)
const
currentSelectType
=
ref
<
'start'
|
'manager'
>
(
'start'
)
const
rules
=
{
const
rules
=
{
...
@@ -174,6 +207,13 @@ watch(
...
@@ -174,6 +207,13 @@ watch(
}
else
{
}
else
{
selectedStartUsers
.
value
=
[]
selectedStartUsers
.
value
=
[]
}
}
if
(
newVal
.
startDeptIds
?.
length
)
{
selectedStartDepts
.
value
=
props
.
deptList
.
filter
((
dept
:
DeptVO
)
=>
newVal
.
startDeptIds
.
includes
(
dept
.
id
)
)
as
DeptVO
[]
}
else
{
selectedStartDepts
.
value
=
[]
}
if
(
newVal
.
managerUserIds
?.
length
)
{
if
(
newVal
.
managerUserIds
?.
length
)
{
selectedManagerUsers
.
value
=
props
.
userList
.
filter
((
user
:
UserVO
)
=>
selectedManagerUsers
.
value
=
props
.
userList
.
filter
((
user
:
UserVO
)
=>
newVal
.
managerUserIds
.
includes
(
user
.
id
)
newVal
.
managerUserIds
.
includes
(
user
.
id
)
...
@@ -193,6 +233,11 @@ const openStartUserSelect = () => {
...
@@ -193,6 +233,11 @@ const openStartUserSelect = () => {
userSelectFormRef
.
value
.
open
(
0
,
selectedStartUsers
.
value
)
userSelectFormRef
.
value
.
open
(
0
,
selectedStartUsers
.
value
)
}
}
/** 打开部门选择 */
const
openStartDeptSelect
=
()
=>
{
deptSelectFormRef
.
value
.
open
(
selectedStartDepts
.
value
)
}
/** 打开管理员选择 */
/** 打开管理员选择 */
const
openManagerUserSelect
=
()
=>
{
const
openManagerUserSelect
=
()
=>
{
currentSelectType
.
value
=
'manager'
currentSelectType
.
value
=
'manager'
...
@@ -214,9 +259,28 @@ const handleUserSelectConfirm = (_, users: UserVO[]) => {
...
@@ -214,9 +259,28 @@ const handleUserSelectConfirm = (_, users: UserVO[]) => {
}
}
}
}
/** 处理部门选择确认 */
const
handleDeptSelectConfirm
=
(
depts
:
DeptVO
[])
=>
{
modelData
.
value
=
{
...
modelData
.
value
,
startDeptIds
:
depts
.
map
((
d
)
=>
d
.
id
)
}
}
/** 处理发起人类型变化 */
/** 处理发起人类型变化 */
const
handleStartUserTypeChange
=
(
value
:
number
)
=>
{
const
handleStartUserTypeChange
=
(
value
:
number
)
=>
{
if
(
value
!==
1
)
{
if
(
value
===
0
)
{
modelData
.
value
=
{
...
modelData
.
value
,
startUserIds
:
[],
startDeptIds
:
[]
}
}
else
if
(
value
===
1
)
{
modelData
.
value
=
{
...
modelData
.
value
,
startDeptIds
:
[]
}
}
else
if
(
value
===
2
)
{
modelData
.
value
=
{
modelData
.
value
=
{
...
modelData
.
value
,
...
modelData
.
value
,
startUserIds
:
[]
startUserIds
:
[]
...
@@ -232,6 +296,14 @@ const handleRemoveStartUser = (user: UserVO) => {
...
@@ -232,6 +296,14 @@ const handleRemoveStartUser = (user: UserVO) => {
}
}
}
}
/** 移除部门 */
const
handleRemoveStartDept
=
(
dept
:
DeptVO
)
=>
{
modelData
.
value
=
{
...
modelData
.
value
,
startDeptIds
:
modelData
.
value
.
startDeptIds
.
filter
((
id
:
number
)
=>
id
!==
dept
.
id
)
}
}
/** 移除管理员 */
/** 移除管理员 */
const
handleRemoveManagerUser
=
(
user
:
UserVO
)
=>
{
const
handleRemoveManagerUser
=
(
user
:
UserVO
)
=>
{
modelData
.
value
=
{
modelData
.
value
=
{
...
...
src/views/bpm/model/form/ExtraSettings.vue
View file @
16a98e5a
...
@@ -148,7 +148,7 @@
...
@@ -148,7 +148,7 @@
<div
class=
"flex"
>
<div
class=
"flex"
>
<el-switch
<el-switch
v-model=
"processBeforeTriggerEnable"
v-model=
"processBeforeTriggerEnable"
@
change=
"handlePr
eProcessNotify
EnableChange"
@
change=
"handlePr
ocessBeforeTrigger
EnableChange"
/>
/>
<div
class=
"ml-80px"
>
流程启动后通知
</div>
<div
class=
"ml-80px"
>
流程启动后通知
</div>
</div>
</div>
...
@@ -168,9 +168,9 @@
...
@@ -168,9 +168,9 @@
<div
class=
"flex"
>
<div
class=
"flex"
>
<el-switch
<el-switch
v-model=
"processAfterTriggerEnable"
v-model=
"processAfterTriggerEnable"
@
change=
"handleP
ostProcessNotify
EnableChange"
@
change=
"handleP
rocessAfterTrigger
EnableChange"
/>
/>
<div
class=
"ml-80px"
>
流程
启动
后通知
</div>
<div
class=
"ml-80px"
>
流程
结束
后通知
</div>
</div>
</div>
<HttpRequestSetting
<HttpRequestSetting
v-if=
"processAfterTriggerEnable"
v-if=
"processAfterTriggerEnable"
...
@@ -180,6 +180,46 @@
...
@@ -180,6 +180,46 @@
/>
/>
</div>
</div>
</el-form-item>
</el-form-item>
<el-form-item
class=
"mb-20px"
>
<
template
#
label
>
<el-text
size=
"large"
tag=
"b"
>
任务前置通知
</el-text>
</
template
>
<div
class=
"flex flex-col w-100%"
>
<div
class=
"flex"
>
<el-switch
v-model=
"taskBeforeTriggerEnable"
@
change=
"handleTaskBeforeTriggerEnableChange"
/>
<div
class=
"ml-80px"
>
任务执行时通知
</div>
</div>
<HttpRequestSetting
v-if=
"taskBeforeTriggerEnable"
v-model:setting=
"modelData.taskBeforeTriggerSetting"
:responseEnable=
"true"
:formItemPrefix=
"'taskBeforeTriggerSetting'"
/>
</div>
</el-form-item>
<el-form-item
class=
"mb-20px"
>
<
template
#
label
>
<el-text
size=
"large"
tag=
"b"
>
任务后置通知
</el-text>
</
template
>
<div
class=
"flex flex-col w-100%"
>
<div
class=
"flex"
>
<el-switch
v-model=
"taskAfterTriggerEnable"
@
change=
"handleTaskAfterTriggerEnableChange"
/>
<div
class=
"ml-80px"
>
任务结束后通知
</div>
</div>
<HttpRequestSetting
v-if=
"taskAfterTriggerEnable"
v-model:setting=
"modelData.taskAfterTriggerSetting"
:responseEnable=
"true"
:formItemPrefix=
"'taskAfterTriggerSetting'"
/>
</div>
</el-form-item>
</el-form>
</el-form>
</template>
</template>
...
@@ -248,7 +288,7 @@ const numberExample = computed(() => {
...
@@ -248,7 +288,7 @@ const numberExample = computed(() => {
/** 是否开启流程前置通知 */
/** 是否开启流程前置通知 */
const
processBeforeTriggerEnable
=
ref
(
false
)
const
processBeforeTriggerEnable
=
ref
(
false
)
const
handlePr
eProcessNotify
EnableChange
=
(
val
:
boolean
|
string
|
number
)
=>
{
const
handlePr
ocessBeforeTrigger
EnableChange
=
(
val
:
boolean
|
string
|
number
)
=>
{
if
(
val
)
{
if
(
val
)
{
modelData
.
value
.
processBeforeTriggerSetting
=
{
modelData
.
value
.
processBeforeTriggerSetting
=
{
url
:
''
,
url
:
''
,
...
@@ -263,7 +303,7 @@ const handlePreProcessNotifyEnableChange = (val: boolean | string | number) => {
...
@@ -263,7 +303,7 @@ const handlePreProcessNotifyEnableChange = (val: boolean | string | number) => {
/** 是否开启流程后置通知 */
/** 是否开启流程后置通知 */
const
processAfterTriggerEnable
=
ref
(
false
)
const
processAfterTriggerEnable
=
ref
(
false
)
const
handleP
ostProcessNotify
EnableChange
=
(
val
:
boolean
|
string
|
number
)
=>
{
const
handleP
rocessAfterTrigger
EnableChange
=
(
val
:
boolean
|
string
|
number
)
=>
{
if
(
val
)
{
if
(
val
)
{
modelData
.
value
.
processAfterTriggerSetting
=
{
modelData
.
value
.
processAfterTriggerSetting
=
{
url
:
''
,
url
:
''
,
...
@@ -276,6 +316,36 @@ const handlePostProcessNotifyEnableChange = (val: boolean | string | number) =>
...
@@ -276,6 +316,36 @@ const handlePostProcessNotifyEnableChange = (val: boolean | string | number) =>
}
}
}
}
/** 是否开启任务前置通知 */
const
taskBeforeTriggerEnable
=
ref
(
false
)
const
handleTaskBeforeTriggerEnableChange
=
(
val
:
boolean
|
string
|
number
)
=>
{
if
(
val
)
{
modelData
.
value
.
taskBeforeTriggerSetting
=
{
url
:
''
,
header
:
[],
body
:
[],
response
:
[]
}
}
else
{
modelData
.
value
.
taskBeforeTriggerSetting
=
null
}
}
/** 是否开启任务后置通知 */
const
taskAfterTriggerEnable
=
ref
(
false
)
const
handleTaskAfterTriggerEnableChange
=
(
val
:
boolean
|
string
|
number
)
=>
{
if
(
val
)
{
modelData
.
value
.
taskAfterTriggerSetting
=
{
url
:
''
,
header
:
[],
body
:
[],
response
:
[]
}
}
else
{
modelData
.
value
.
taskAfterTriggerSetting
=
null
}
}
/** 表单选项 */
/** 表单选项 */
const
formField
=
ref
<
Array
<
{
field
:
string
;
title
:
string
}
>>
([])
const
formField
=
ref
<
Array
<
{
field
:
string
;
title
:
string
}
>>
([])
const
formFieldOptions4Title
=
computed
(()
=>
{
const
formFieldOptions4Title
=
computed
(()
=>
{
...
@@ -341,6 +411,12 @@ const initData = () => {
...
@@ -341,6 +411,12 @@ const initData = () => {
if
(
modelData
.
value
.
processAfterTriggerSetting
)
{
if
(
modelData
.
value
.
processAfterTriggerSetting
)
{
processAfterTriggerEnable
.
value
=
true
processAfterTriggerEnable
.
value
=
true
}
}
if
(
modelData
.
value
.
taskBeforeTriggerSetting
)
{
taskBeforeTriggerEnable
.
value
=
true
}
if
(
modelData
.
value
.
taskAfterTriggerSetting
)
{
taskAfterTriggerEnable
.
value
=
true
}
}
}
defineExpose
({
initData
})
defineExpose
({
initData
})
...
...
src/views/bpm/model/form/ProcessDesign.vue
View file @
16a98e5a
...
@@ -18,6 +18,7 @@
...
@@ -18,6 +18,7 @@
:model-key=
"modelData.key"
:model-key=
"modelData.key"
:model-name=
"modelData.name"
:model-name=
"modelData.name"
:start-user-ids=
"modelData.startUserIds"
:start-user-ids=
"modelData.startUserIds"
:start-dept-ids=
"modelData.startDeptIds"
@
success=
"handleDesignSuccess"
@
success=
"handleDesignSuccess"
/>
/>
</
template
>
</
template
>
...
...
src/views/bpm/model/form/index.vue
View file @
16a98e5a
...
@@ -62,6 +62,7 @@
...
@@ -62,6 +62,7 @@
v-model=
"formData"
v-model=
"formData"
:categoryList=
"categoryList"
:categoryList=
"categoryList"
:userList=
"userList"
:userList=
"userList"
:deptList=
"deptList"
ref=
"basicInfoRef"
ref=
"basicInfoRef"
/>
/>
</div>
</div>
...
@@ -92,6 +93,7 @@ import * as ModelApi from '@/api/bpm/model'
...
@@ -92,6 +93,7 @@ import * as ModelApi from '@/api/bpm/model'
import
*
as
FormApi
from
'@/api/bpm/form'
import
*
as
FormApi
from
'@/api/bpm/form'
import
{
CategoryApi
,
CategoryVO
}
from
'@/api/bpm/category'
import
{
CategoryApi
,
CategoryVO
}
from
'@/api/bpm/category'
import
*
as
UserApi
from
'@/api/system/user'
import
*
as
UserApi
from
'@/api/system/user'
import
*
as
DeptApi
from
'@/api/system/dept'
import
*
as
DefinitionApi
from
'@/api/bpm/definition'
import
*
as
DefinitionApi
from
'@/api/bpm/definition'
import
{
BpmModelFormType
,
BpmModelType
,
BpmAutoApproveType
}
from
'@/utils/constants'
import
{
BpmModelFormType
,
BpmModelType
,
BpmAutoApproveType
}
from
'@/utils/constants'
import
BasicInfo
from
'./BasicInfo.vue'
import
BasicInfo
from
'./BasicInfo.vue'
...
@@ -153,6 +155,7 @@ const formData: any = ref({
...
@@ -153,6 +155,7 @@ const formData: any = ref({
visible
:
true
,
visible
:
true
,
startUserType
:
undefined
,
startUserType
:
undefined
,
startUserIds
:
[],
startUserIds
:
[],
startDeptIds
:
[],
managerUserIds
:
[],
managerUserIds
:
[],
allowCancelRunningProcess
:
true
,
allowCancelRunningProcess
:
true
,
processIdRule
:
{
processIdRule
:
{
...
@@ -183,6 +186,7 @@ provide('modelData', formData)
...
@@ -183,6 +186,7 @@ provide('modelData', formData)
const
formList
=
ref
([])
const
formList
=
ref
([])
const
categoryList
=
ref
<
CategoryVO
[]
>
([])
const
categoryList
=
ref
<
CategoryVO
[]
>
([])
const
userList
=
ref
<
UserApi
.
UserVO
[]
>
([])
const
userList
=
ref
<
UserApi
.
UserVO
[]
>
([])
const
deptList
=
ref
<
DeptApi
.
DeptVO
[]
>
([])
/** 初始化数据 */
/** 初始化数据 */
const
actionType
=
route
.
params
.
type
as
string
const
actionType
=
route
.
params
.
type
as
string
...
@@ -200,14 +204,17 @@ const initData = async () => {
...
@@ -200,14 +204,17 @@ const initData = async () => {
data
.
simpleModel
=
JSON
.
parse
(
data
.
simpleModel
)
data
.
simpleModel
=
JSON
.
parse
(
data
.
simpleModel
)
}
}
formData
.
value
=
data
formData
.
value
=
data
formData
.
value
.
startUserType
=
formData
.
value
.
startUserIds
?.
length
>
0
?
1
:
0
formData
.
value
.
startUserType
=
formData
.
value
.
startUserIds
?.
length
>
0
?
1
:
formData
.
value
?.
startDeptIds
?.
length
>
0
?
2
:
0
}
else
if
([
'update'
,
'copy'
].
includes
(
actionType
))
{
}
else
if
([
'update'
,
'copy'
].
includes
(
actionType
))
{
// 情况二:修改场景/复制场景
// 情况二:修改场景/复制场景
const
modelId
=
route
.
params
.
id
as
string
const
modelId
=
route
.
params
.
id
as
string
formData
.
value
=
await
ModelApi
.
getModel
(
modelId
)
formData
.
value
=
await
ModelApi
.
getModel
(
modelId
)
formData
.
value
.
startUserType
=
formData
.
value
.
startUserIds
?.
length
>
0
?
1
:
0
formData
.
value
.
startUserType
=
formData
.
value
.
startUserIds
?.
length
>
0
?
1
:
formData
.
value
?.
startDeptIds
?.
length
>
0
?
2
:
0
// 特殊:复制场景
// 特殊:复制场景
if
(
actionT
ype
===
'copy'
)
{
if
(
route
.
params
.
t
ype
===
'copy'
)
{
delete
formData
.
value
.
id
delete
formData
.
value
.
id
formData
.
value
.
name
+=
'副本'
formData
.
value
.
name
+=
'副本'
formData
.
value
.
key
+=
'_copy'
formData
.
value
.
key
+=
'_copy'
...
@@ -225,6 +232,8 @@ const initData = async () => {
...
@@ -225,6 +232,8 @@ const initData = async () => {
categoryList
.
value
=
await
CategoryApi
.
getCategorySimpleList
()
categoryList
.
value
=
await
CategoryApi
.
getCategorySimpleList
()
// 获取用户列表
// 获取用户列表
userList
.
value
=
await
UserApi
.
getSimpleUserList
()
userList
.
value
=
await
UserApi
.
getSimpleUserList
()
// 获取部门列表
deptList
.
value
=
await
DeptApi
.
getSimpleDeptList
()
// 最终,设置 currentStep 切换到第一步
// 最终,设置 currentStep 切换到第一步
currentStep
.
value
=
0
currentStep
.
value
=
0
...
...
src/views/bpm/oa/leave/create.vue
View file @
16a98e5a
<
template
>
<
template
>
<el-form
<el-row
:gutter=
"20"
>
ref=
"formRef"
<el-col
:span=
"16"
>
v-loading=
"formLoading"
<ContentWrap
title=
"申请信息"
>
:model=
"formData"
:rules=
"formRules"
label-width=
"80px"
>
<el-form-item
label=
"请假类型"
prop=
"type"
>
<el-select
v-model=
"formData.type"
clearable
placeholder=
"请选择请假类型"
>
<el-option
v-for=
"dict in getIntDictOptions(DICT_TYPE.BPM_OA_LEAVE_TYPE)"
:key=
"dict.value"
:label=
"dict.label"
:value=
"dict.value"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"开始时间"
prop=
"startTime"
>
<el-date-picker
v-model=
"formData.startTime"
clearable
placeholder=
"请选择开始时间"
type=
"datetime"
value-format=
"x"
/>
</el-form-item>
<el-form-item
label=
"结束时间"
prop=
"endTime"
>
<el-date-picker
v-model=
"formData.endTime"
clearable
placeholder=
"请选择结束时间"
type=
"datetime"
value-format=
"x"
/>
</el-form-item>
<el-form-item
label=
"原因"
prop=
"reason"
>
<el-input
v-model=
"formData.reason"
placeholder=
"请输请假原因"
type=
"textarea"
/>
</el-form-item>
<el-col
v-if=
"startUserSelectTasks.length > 0"
>
<el-card
class=
"mb-10px"
>
<template
#
header
>
指定审批人
</
template
>
<el-form
<el-form
:model=
"startUserSelectAssignees"
ref=
"formRef"
:rules=
"startUserSelectAssigneesFormRules"
v-loading=
"formLoading"
ref=
"startUserSelectAssigneesFormRef"
:model=
"formData"
:rules=
"formRules"
label-width=
"80px"
>
>
<el-form-item
<el-form-item
label=
"请假类型"
prop=
"type"
>
v-for=
"userTask in startUserSelectTasks"
<el-select
v-model=
"formData.type"
clearable
placeholder=
"请选择请假类型"
>
:key=
"userTask.id"
:label=
"`任务【${userTask.name}】`"
:prop=
"userTask.id"
>
<el-select
v-model=
"startUserSelectAssignees[userTask.id]"
multiple
placeholder=
"请选择审批人"
>
<el-option
<el-option
v-for=
"
user in userList
"
v-for=
"
dict in getIntDictOptions(DICT_TYPE.BPM_OA_LEAVE_TYPE)
"
:key=
"
user.id
"
:key=
"
dict.value
"
:label=
"
user.nickname
"
:label=
"
dict.label
"
:value=
"
user.id
"
:value=
"
dict.value
"
/>
/>
</el-select>
</el-select>
</el-form-item>
</el-form-item>
<el-form-item
label=
"开始时间"
prop=
"startTime"
>
<el-date-picker
v-model=
"formData.startTime"
clearable
placeholder=
"请选择开始时间"
type=
"datetime"
value-format=
"x"
/>
</el-form-item>
<el-form-item
label=
"结束时间"
prop=
"endTime"
>
<el-date-picker
v-model=
"formData.endTime"
clearable
placeholder=
"请选择结束时间"
type=
"datetime"
value-format=
"x"
/>
</el-form-item>
<el-form-item
label=
"原因"
prop=
"reason"
>
<el-input
v-model=
"formData.reason"
placeholder=
"请输入请假原因"
type=
"textarea"
/>
</el-form-item>
<el-form-item>
<el-button
:disabled=
"formLoading"
type=
"primary"
@
click=
"submitForm"
>
确 定
</el-button>
</el-form-item>
</el-form>
</el-form>
</
el-card
>
</
ContentWrap
>
</el-col>
</el-col>
<el-form-item>
<el-button
:disabled=
"formLoading"
type=
"primary"
@
click=
"submitForm"
>
确 定
</el-button>
<!-- 审批相关:流程信息 -->
</el-form-item>
<el-col
:span=
"8"
>
</el-form>
<ContentWrap
title=
"审批流程"
:bodyStyle=
"
{ padding: '0 20px 0' }">
<ProcessInstanceTimeline
ref=
"timelineRef"
:activity-nodes=
"activityNodes"
:show-status-icon=
"false"
@
select-user-confirm=
"selectUserConfirm"
/>
</ContentWrap>
</el-col>
</el-row>
</
template
>
</
template
>
<
script
lang=
"ts"
setup
>
<
script
lang=
"ts"
setup
>
import
{
DICT_TYPE
,
getIntDictOptions
}
from
'@/utils/dict'
import
{
DICT_TYPE
,
getIntDictOptions
}
from
'@/utils/dict'
import
*
as
LeaveApi
from
'@/api/bpm/leave'
import
*
as
LeaveApi
from
'@/api/bpm/leave'
import
{
useTagsViewStore
}
from
'@/store/modules/tagsView'
import
{
useTagsViewStore
}
from
'@/store/modules/tagsView'
// 审批相关:import
import
*
as
DefinitionApi
from
'@/api/bpm/definition'
import
*
as
DefinitionApi
from
'@/api/bpm/definition'
import
*
as
UserApi
from
'@/api/system/user'
import
ProcessInstanceTimeline
from
'@/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue'
import
*
as
ProcessInstanceApi
from
'@/api/bpm/processInstance'
import
{
CandidateStrategy
,
NodeId
}
from
'@/components/SimpleProcessDesignerV2/src/consts'
import
{
ApprovalNodeInfo
}
from
'@/api/bpm/processInstance'
defineOptions
({
name
:
'BpmOALeaveCreate'
})
defineOptions
({
name
:
'BpmOALeaveCreate'
})
...
@@ -100,30 +95,37 @@ const formRules = reactive({
...
@@ -100,30 +95,37 @@ const formRules = reactive({
})
})
const
formRef
=
ref
()
// 表单 Ref
const
formRef
=
ref
()
// 表单 Ref
//
指定审批人
//
审批相关:变量
const
processDefineKey
=
'oa_leave'
// 流程定义 Key
const
processDefineKey
=
'oa_leave'
// 流程定义 Key
const
startUserSelectTasks
=
ref
([])
// 发起人需要选择审批人的用户任务列表
const
startUserSelectTasks
=
ref
([])
// 发起人需要选择审批人的用户任务列表
const
startUserSelectAssignees
=
ref
({})
// 发起人选择审批人的数据
const
startUserSelectAssignees
=
ref
({})
// 发起人选择审批人的数据
const
startUserSelectAssigneesFormRef
=
ref
()
// 发起人选择审批人的表单 Ref
const
tempStartUserSelectAssignees
=
ref
({})
// 历史发起人选择审批人的数据,用于每次表单变更时,临时保存
const
startUserSelectAssigneesFormRules
=
ref
({})
// 发起人选择审批人的表单 Rules
const
activityNodes
=
ref
<
ProcessInstanceApi
.
ApprovalNodeInfo
[]
>
([])
// 审批节点信息
const
userList
=
ref
<
any
[]
>
([])
// 用户列表
const
processDefinitionId
=
ref
(
''
)
/** 提交表单 */
/** 提交表单 */
const
submitForm
=
async
()
=>
{
const
submitForm
=
async
()
=>
{
// 校验表单
//
1.1
校验表单
if
(
!
formRef
)
return
if
(
!
formRef
)
return
const
valid
=
await
formRef
.
value
.
validate
()
const
valid
=
await
formRef
.
value
.
validate
()
if
(
!
valid
)
return
if
(
!
valid
)
return
// 校验指定审批人
//
1.2 审批相关:
校验指定审批人
if
(
startUserSelectTasks
.
value
?.
length
>
0
)
{
if
(
startUserSelectTasks
.
value
?.
length
>
0
)
{
await
startUserSelectAssigneesFormRef
.
value
.
validate
()
for
(
const
userTask
of
startUserSelectTasks
.
value
)
{
if
(
Array
.
isArray
(
startUserSelectAssignees
.
value
[
userTask
.
id
])
&&
startUserSelectAssignees
.
value
[
userTask
.
id
].
length
===
0
)
{
return
message
.
warning
(
`请选择
${
userTask
.
name
}
的审批人`
)
}
}
}
}
// 提交请求
//
2.
提交请求
formLoading
.
value
=
true
formLoading
.
value
=
true
try
{
try
{
const
data
=
{
...
formData
.
value
}
as
unknown
as
LeaveApi
.
LeaveVO
const
data
=
{
...
formData
.
value
}
as
unknown
as
LeaveApi
.
LeaveVO
// 设置指定审批人
//
审批相关:
设置指定审批人
if
(
startUserSelectTasks
.
value
?.
length
>
0
)
{
if
(
startUserSelectTasks
.
value
?.
length
>
0
)
{
data
.
startUserSelectAssignees
=
startUserSelectAssignees
.
value
data
.
startUserSelectAssignees
=
startUserSelectAssignees
.
value
}
}
...
@@ -137,28 +139,93 @@ const submitForm = async () => {
...
@@ -137,28 +139,93 @@ const submitForm = async () => {
}
}
}
}
/** 审批相关:获取审批详情 */
const
getApprovalDetail
=
async
()
=>
{
try
{
const
data
=
await
ProcessInstanceApi
.
getApprovalDetail
({
processDefinitionId
:
processDefinitionId
.
value
,
// TODO 小北:可以支持 processDefinitionKey 查询
activityId
:
NodeId
.
START_USER_NODE_ID
,
processVariablesStr
:
JSON
.
stringify
({
day
:
daysDifference
()
})
// 解决 GET 无法传递对象的问题,后端 String 再转 JSON
})
if
(
!
data
)
{
message
.
error
(
'查询不到审批详情信息!'
)
return
}
// 获取审批节点,显示 Timeline 的数据
activityNodes
.
value
=
data
.
activityNodes
// 获取发起人自选的任务
startUserSelectTasks
.
value
=
data
.
activityNodes
?.
filter
(
(
node
:
ApprovalNodeInfo
)
=>
CandidateStrategy
.
START_USER_SELECT
===
node
.
candidateStrategy
)
// 恢复之前的选择审批人
if
(
startUserSelectTasks
.
value
?.
length
>
0
)
{
for
(
const
node
of
startUserSelectTasks
.
value
)
{
if
(
tempStartUserSelectAssignees
.
value
[
node
.
id
]
&&
tempStartUserSelectAssignees
.
value
[
node
.
id
].
length
>
0
)
{
startUserSelectAssignees
.
value
[
node
.
id
]
=
tempStartUserSelectAssignees
.
value
[
node
.
id
]
}
else
{
startUserSelectAssignees
.
value
[
node
.
id
]
=
[]
}
}
}
}
finally
{
}
}
/** 审批相关:选择发起人 */
const
selectUserConfirm
=
(
id
:
string
,
userList
:
any
[])
=>
{
startUserSelectAssignees
.
value
[
id
]
=
userList
?.
map
((
item
:
any
)
=>
item
.
id
)
}
// 计算天数差
// TODO @小北:可以搞到 formatTime 里面去,然后看看 dayjs 里面有没有现成的方法,或者辅助计算的方法。
const
daysDifference
=
()
=>
{
const
oneDay
=
24
*
60
*
60
*
1000
// 一天的毫秒数
const
diffTime
=
Math
.
abs
(
Number
(
formData
.
value
.
endTime
)
-
Number
(
formData
.
value
.
startTime
))
return
Math
.
floor
(
diffTime
/
oneDay
)
}
/** 初始化 */
/** 初始化 */
onMounted
(
async
()
=>
{
onMounted
(
async
()
=>
{
// TODO @小北:这里可以简化,统一通过 getApprovalDetail 处理么?
const
processDefinitionDetail
=
await
DefinitionApi
.
getProcessDefinition
(
const
processDefinitionDetail
=
await
DefinitionApi
.
getProcessDefinition
(
undefined
,
undefined
,
processDefineKey
processDefineKey
)
)
if
(
!
processDefinitionDetail
)
{
if
(
!
processDefinitionDetail
)
{
message
.
error
(
'OA 请假的流程模型未配置,请检查!'
)
message
.
error
(
'OA 请假的流程模型未配置,请检查!'
)
return
return
}
}
processDefinitionId
.
value
=
processDefinitionDetail
.
id
startUserSelectTasks
.
value
=
processDefinitionDetail
.
startUserSelectTasks
startUserSelectTasks
.
value
=
processDefinitionDetail
.
startUserSelectTasks
// 设置指定审批人
if
(
startUserSelectTasks
.
value
?.
length
>
0
)
{
// 审批相关:加载最新的审批详情,主要用于节点预测
// 设置校验规则
await
getApprovalDetail
()
for
(
const
userTask
of
startUserSelectTasks
.
value
)
{
})
startUserSelectAssignees
.
value
[
userTask
.
id
]
=
[]
startUserSelectAssigneesFormRules
.
value
[
userTask
.
id
]
=
[
/** 审批相关:预测流程节点会因为输入的参数值而产生新的预测结果值,所以需重新预测一次, formData.value可改成实际业务中的特定字段 */
{
required
:
true
,
message
:
'请选择审批人'
,
trigger
:
'blur'
}
watch
(
]
formData
.
value
,
(
newValue
,
oldValue
)
=>
{
if
(
!
oldValue
)
{
return
}
}
// 加载用户列表
if
(
newValue
&&
Object
.
keys
(
newValue
).
length
>
0
)
{
userList
.
value
=
await
UserApi
.
getSimpleUserList
()
// 记录之前的节点审批人
tempStartUserSelectAssignees
.
value
=
startUserSelectAssignees
.
value
startUserSelectAssignees
.
value
=
{}
// 加载最新的审批详情,主要用于节点预测
getApprovalDetail
()
}
},
{
immediate
:
true
}
}
}
)
)
</
script
>
</
script
>
src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue
View file @
16a98e5a
...
@@ -37,6 +37,11 @@
...
@@ -37,6 +37,11 @@
{{ getApprovalNodeTime(activity) }}
{{ getApprovalNodeTime(activity) }}
</div>
</div>
</div>
</div>
<div
v-if=
"activity.nodeType === NodeType.CHILD_PROCESS_NODE"
>
<el-button
type=
"primary"
plain
size=
"small"
@
click=
"handleChildProcess(activity)"
>
查看子流程
</el-button>
</div>
<!-- 需要自定义选择审批人 -->
<!-- 需要自定义选择审批人 -->
<div
<div
class=
"flex flex-wrap gap2 items-center"
class=
"flex flex-wrap gap2 items-center"
...
@@ -194,6 +199,7 @@ withDefaults(
...
@@ -194,6 +199,7 @@ withDefaults(
showStatusIcon
:
true
// 默认值为 true
showStatusIcon
:
true
// 默认值为 true
}
}
)
)
const
{
push
}
=
useRouter
()
// 路由
// 审批节点
// 审批节点
const
statusIconMap2
=
{
const
statusIconMap2
=
{
...
@@ -310,4 +316,15 @@ const handleUserSelectConfirm = (activityId: string, userList: any[]) => {
...
@@ -310,4 +316,15 @@ const handleUserSelectConfirm = (activityId: string, userList: any[]) => {
customApproveUsers
.
value
[
activityId
]
=
userList
||
[]
customApproveUsers
.
value
[
activityId
]
=
userList
||
[]
emit
(
'selectUserConfirm'
,
activityId
,
userList
)
emit
(
'selectUserConfirm'
,
activityId
,
userList
)
}
}
/** 跳转子流程 */
const
handleChildProcess
=
(
activity
:
any
)
=>
{
// TODO @lesan:貌似跳不过去?!
push
({
name
:
'BpmProcessInstanceDetail'
,
query
:
{
id
:
activity
.
processInstanceId
}
})
}
</
script
>
</
script
>
src/views/bpm/simple/SimpleModelDesign.vue
View file @
16a98e5a
...
@@ -6,6 +6,7 @@
...
@@ -6,6 +6,7 @@
:model-name=
"modelName"
:model-name=
"modelName"
@
success=
"handleSuccess"
@
success=
"handleSuccess"
:start-user-ids=
"startUserIds"
:start-user-ids=
"startUserIds"
:start-dept-ids=
"startDeptIds"
ref=
"designerRef"
ref=
"designerRef"
/>
/>
</ContentWrap>
</ContentWrap>
...
@@ -22,6 +23,7 @@ defineProps<{
...
@@ -22,6 +23,7 @@ defineProps<{
modelKey
?:
string
modelKey
?:
string
modelName
?:
string
modelName
?:
string
startUserIds
?:
number
[]
startUserIds
?:
number
[]
startDeptIds
?:
number
[]
}
>
()
}
>
()
const
emit
=
defineEmits
([
'success'
])
const
emit
=
defineEmits
([
'success'
])
...
...
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