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
92314ee9
authored
Nov 06, 2024
by
GoldenZqqq
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 自定义选择审批人逻辑TODO,选择用户弹窗绘制与选择交互逻辑处理
parent
0fbd9829
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
228 additions
and
26 deletions
+228
-26
src/components/UserSelectForm/index.vue
+92
-0
src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue
+26
-24
src/views/bpm/processInstance/create/mock.ts
+86
-0
src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue
+24
-2
No files found.
src/components/UserSelectForm/index.vue
0 → 100644
View file @
92314ee9
<
template
>
<Dialog
v-model=
"dialogVisible"
title=
"人员选择"
width=
"900"
>
<el-row>
<el-col
:span=
"6"
>
<el-tree
ref=
"treeRef"
:data=
"deptList"
:expand-on-click-node=
"false"
:props=
"defaultProps"
default-expand-all
highlight-current
node-key=
"id"
@
node-click=
"handleNodeClick"
/>
</el-col>
<el-col
:span=
"17"
:offset=
"1"
>
<el-transfer
v-model=
"selectedUserList"
filterable
filter-placeholder=
"搜索成员"
:data=
"userList"
:props=
"
{ label: 'nickname', key: 'id' }"
/>
</el-col>
</el-row>
<template
#
footer
>
<el-button
:disabled=
"formLoading"
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'
import
*
as
UserApi
from
'@/api/system/user'
defineOptions
({
name
:
'UserSelectForm'
})
const
emit
=
defineEmits
<
{
confirm
:
[
userList
:
any
[]]
}
>
()
const
{
t
}
=
useI18n
()
// 国际
const
deptList
=
ref
<
Tree
[]
>
([])
// 部门树形结构化
const
userList
:
any
=
ref
([])
// 用户列表
const
message
=
useMessage
()
// 消息弹窗
const
selectedUserList
:
any
=
ref
([])
// 选中的用户列表
const
dialogVisible
=
ref
(
false
)
// 弹窗的是否展示
const
formLoading
=
ref
(
false
)
// 表单的加载中
/** 打开弹窗 */
const
open
=
async
()
=>
{
resetForm
()
deptList
.
value
=
handleTree
(
await
DeptApi
.
getSimpleDeptList
())
await
getUserList
()
// 修改时,设置数据
dialogVisible
.
value
=
true
}
/* 获取用户列表 */
const
getUserList
=
async
(
deptId
?)
=>
{
try
{
// @ts-ignore
const
data
=
await
UserApi
.
getUserPage
({
pageSize
:
100
,
pageNo
:
1
,
deptId
})
userList
.
value
=
data
.
list
}
finally
{
}
}
const
submitForm
=
async
()
=>
{
// 提交请求
formLoading
.
value
=
true
try
{
message
.
success
(
t
(
'common.updateSuccess'
))
dialogVisible
.
value
=
false
// 发送操作成功的事件
emit
(
'confirm'
,
selectedUserList
.
value
)
}
finally
{
formLoading
.
value
=
false
}
}
const
resetForm
=
()
=>
{
deptList
.
value
=
[]
userList
.
value
=
[]
selectedUserList
.
value
=
[]
}
/** 处理部门被点击 */
const
handleNodeClick
=
async
(
row
:
{
[
key
:
string
]:
any
})
=>
{
getUserList
(
row
.
id
)
}
defineExpose
({
open
})
// 提供 open 方法,用于打开弹窗
</
script
>
src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue
View file @
92314ee9
...
@@ -20,7 +20,7 @@
...
@@ -20,7 +20,7 @@
:option=
"detailForm.option"
:option=
"detailForm.option"
@
submit=
"submitForm"
@
submit=
"submitForm"
>
>
<template
#
type-startUserSelect
>
<
!--
<
template
#
type-startUserSelect
>
<el-col
:span=
"24"
>
<el-col
:span=
"24"
>
<el-card
class=
"mb-10px"
>
<el-card
class=
"mb-10px"
>
<template
#
header
>
指定审批人
</
template
>
<template
#
header
>
指定审批人
</
template
>
...
@@ -51,7 +51,7 @@
...
@@ -51,7 +51,7 @@
</el-form>
</el-form>
</el-card>
</el-card>
</el-col>
</el-col>
</template>
</template>
-->
</form-create>
</form-create>
</el-col>
</el-col>
...
@@ -61,7 +61,7 @@
...
@@ -61,7 +61,7 @@
ref=
"timelineRef"
ref=
"timelineRef"
:activity-nodes=
"activityNodes"
:activity-nodes=
"activityNodes"
:show-status-icon=
"false"
:show-status-icon=
"false"
candidateField=
"candidateUserList
"
:startUserSelectTasks=
"startUserSelectTasks
"
/>
/>
</el-col>
</el-col>
</el-row>
</el-row>
...
@@ -104,7 +104,8 @@ import type { ApiAttrs } from '@form-create/element-ui/types/config'
...
@@ -104,7 +104,8 @@ import type { ApiAttrs } from '@form-create/element-ui/types/config'
import
{
useTagsViewStore
}
from
'@/store/modules/tagsView'
import
{
useTagsViewStore
}
from
'@/store/modules/tagsView'
import
*
as
ProcessInstanceApi
from
'@/api/bpm/processInstance'
import
*
as
ProcessInstanceApi
from
'@/api/bpm/processInstance'
import
*
as
DefinitionApi
from
'@/api/bpm/definition'
import
*
as
DefinitionApi
from
'@/api/bpm/definition'
import
*
as
UserApi
from
'@/api/system/user'
// import * as UserApi from '@/api/system/user'
import
{
activityNodes
as
aN
,
startUserSelectTasks
as
sUs
}
from
'./mock'
defineOptions
({
name
:
'ProcessDefinitionDetail'
})
defineOptions
({
name
:
'ProcessDefinitionDetail'
})
const
props
=
defineProps
<
{
const
props
=
defineProps
<
{
...
@@ -125,7 +126,7 @@ const startUserSelectAssigneesFormRef = ref() // 发起人选择审批人的表
...
@@ -125,7 +126,7 @@ const startUserSelectAssigneesFormRef = ref() // 发起人选择审批人的表
const
startUserSelectTasks
:
any
=
ref
([])
// 发起人需要选择审批人的用户任务列表
const
startUserSelectTasks
:
any
=
ref
([])
// 发起人需要选择审批人的用户任务列表
const
startUserSelectAssignees
=
ref
({})
// 发起人选择审批人的数据
const
startUserSelectAssignees
=
ref
({})
// 发起人选择审批人的数据
const
startUserSelectAssigneesFormRules
=
ref
({})
// 发起人选择审批人的表单 Rules
const
startUserSelectAssigneesFormRules
=
ref
({})
// 发起人选择审批人的表单 Rules
const
userList
=
ref
<
any
[]
>
([])
// 用户列表
//
const userList = ref
<
any
[]
>
([])
// 用户列表
const
bpmnXML
:
any
=
ref
(
null
)
// BPMN 数据
const
bpmnXML
:
any
=
ref
(
null
)
// BPMN 数据
/** 当前的Tab */
/** 当前的Tab */
const
activeTab
=
ref
(
'form'
)
const
activeTab
=
ref
(
'form'
)
...
@@ -163,25 +164,25 @@ const initProcessInfo = async (row: any, formVariables?: any) => {
...
@@ -163,25 +164,25 @@ const initProcessInfo = async (row: any, formVariables?: any) => {
if
(
processDefinitionDetail
)
{
if
(
processDefinitionDetail
)
{
bpmnXML
.
value
=
processDefinitionDetail
.
bpmnXml
bpmnXML
.
value
=
processDefinitionDetail
.
bpmnXml
startUserSelectTasks
.
value
=
processDefinitionDetail
.
startUserSelectTasks
startUserSelectTasks
.
value
=
processDefinitionDetail
.
startUserSelectTasks
startUserSelectTasks
.
value
=
sUs
// 设置指定审批人
// 设置指定审批人
if
(
startUserSelectTasks
.
value
?.
length
>
0
)
{
//
if (startUserSelectTasks.value?.length > 0) {
detailForm
.
value
.
rule
.
push
({
//
detailForm.value.rule.push({
type
:
'startUserSelect'
,
//
type: 'startUserSelect',
props
:
{
//
props: {
title
:
'指定审批人'
//
title: '指定审批人'
}
//
}
})
//
})
// 设置校验规则
//
// 设置校验规则
for
(
const
userTask
of
startUserSelectTasks
.
value
)
{
//
for (const userTask of startUserSelectTasks.value) {
startUserSelectAssignees
.
value
[
userTask
.
id
]
=
[]
//
startUserSelectAssignees.value[userTask.id] = []
startUserSelectAssigneesFormRules
.
value
[
userTask
.
id
]
=
[
//
startUserSelectAssigneesFormRules.value[userTask.id] = [
{
required
:
true
,
message
:
'请选择审批人'
,
trigger
:
'blur'
}
//
{ required: true, message: '请选择审批人', trigger: 'blur' }
]
//
]
}
//
}
// 加载用户列表
//
// 加载用户列表
userList
.
value
=
await
UserApi
.
getSimpleUserList
()
//
userList.value = await UserApi.getSimpleUserList()
}
//
}
}
}
// 情况二:业务表单
// 情况二:业务表单
}
else
if
(
row
.
formCustomCreatePath
)
{
}
else
if
(
row
.
formCustomCreatePath
)
{
...
@@ -205,6 +206,7 @@ const getApprovalDetail = async (row: any) => {
...
@@ -205,6 +206,7 @@ const getApprovalDetail = async (row: any) => {
}
}
// 获取审批节点,显示 Timeline 的数据
// 获取审批节点,显示 Timeline 的数据
activityNodes
.
value
=
data
.
activityNodes
activityNodes
.
value
=
data
.
activityNodes
activityNodes
.
value
=
aN
}
finally
{
}
finally
{
}
}
}
}
...
@@ -250,7 +252,7 @@ defineExpose({ initProcessInfo })
...
@@ -250,7 +252,7 @@ defineExpose({ initProcessInfo })
$
wrap-padding-height
:
20px
;
$
wrap-padding-height
:
20px
;
$
wrap-margin-height
:
15px
;
$
wrap-margin-height
:
15px
;
$
button-height
:
51px
;
$
button-height
:
51px
;
$
process-header-height
:
1
94
px
;
$
process-header-height
:
1
05
px
;
.processInstance-wrap-main
{
.processInstance-wrap-main
{
height
:
calc
(
height
:
calc
(
...
...
src/views/bpm/processInstance/create/mock.ts
0 → 100644
View file @
92314ee9
import
{
ProcessInstanceVO
,
User
,
ApprovalTaskInfo
,
ApprovalNodeInfo
}
from
'@/api/bpm/processInstance'
;
import
{
NodeType
}
from
'@/components/SimpleProcessDesignerV2/src/consts'
const
users
:
User
[]
=
[
{
id
:
1
,
nickname
:
'Alice'
,
avatar
:
'https://picsum.photos/200?r=1'
},
{
id
:
2
,
nickname
:
'Bob'
,
avatar
:
'https://picsum.photos/200?r=2'
},
{
id
:
3
,
nickname
:
'Charlie'
,
avatar
:
'https://picsum.photos/200?r=3'
},
{
id
:
4
,
nickname
:
'David'
,
avatar
:
'https://picsum.photos/200?r=4'
}
];
const
approvalTask1
:
ApprovalTaskInfo
=
{
id
:
1
,
ownerUser
:
users
[
0
],
// Alice is the owner (initiator)
assigneeUser
:
users
[
1
],
// Bob is the assignee
status
:
1
,
// In Progress
reason
:
'Please review and approve the request.'
};
const
approvalTask2
:
ApprovalTaskInfo
=
{
id
:
2
,
ownerUser
:
users
[
1
],
// Bob is the owner (approver)
assigneeUser
:
users
[
2
],
// Charlie is the assignee
status
:
0
,
// Pending approval
reason
:
'Awaiting Bob’s decision.'
};
const
approvalTask3
:
ApprovalTaskInfo
=
{
id
:
3
,
ownerUser
:
users
[
2
],
// Charlie is the owner (approver)
assigneeUser
:
users
[
3
],
// David is the assignee
status
:
0
,
// Pending approval
reason
:
'Awaiting Charlie’s decision.'
};
const
approvalNode1
:
ApprovalNodeInfo
=
{
id
:
101
,
name
:
'Start Review'
,
nodeType
:
NodeType
.
START_USER_NODE
,
status
:
1
,
// In Progress
startTime
:
new
Date
(
'2024-11-01T10:00:00Z'
),
tasks
:
[
approvalTask1
]
};
const
approvalNode2
:
ApprovalNodeInfo
=
{
id
:
102
,
name
:
'First Review'
,
nodeType
:
NodeType
.
USER_TASK_NODE
,
status
:
0
,
// Pending approval
startTime
:
new
Date
(
'2024-11-01T11:00:00Z'
),
tasks
:
[
approvalTask2
],
candidateUsers
:
[
users
[
2
],
users
[
3
]]
// Candidate users: Charlie and David
};
const
approvalNode3
:
ApprovalNodeInfo
=
{
id
:
103
,
name
:
'Second Review'
,
nodeType
:
NodeType
.
USER_TASK_NODE
,
status
:
0
,
// Pending approval
startTime
:
new
Date
(
'2024-11-01T12:00:00Z'
),
tasks
:
[
approvalTask3
],
candidateUsers
:
[
users
[
1
],
users
[
3
]]
// Candidate users: Bob and David
};
const
processInstance
:
ProcessInstanceVO
=
{
id
:
1001
,
name
:
'Request Approval Process'
,
processDefinitionId
:
'proc-2024-001'
,
category
:
'Approval Process'
,
result
:
0
,
// Ongoing
tasks
:
[{
id
:
'1'
,
name
:
'Start Review'
},
{
id
:
'2'
,
name
:
'First Review'
},
{
id
:
'3'
,
name
:
'Second Review'
}],
fields
:
[
'field1'
,
'field2'
],
status
:
1
,
// In Progress
remark
:
'This is a sample approval process.'
,
businessKey
:
'BUS-12345'
,
createTime
:
'2024-11-01T09:00:00Z'
,
endTime
:
''
,
processDefinition
:
undefined
// Not populated in this example
};
// 模拟的 activityNodes 数据,传递给 ProcessInstanceTimeline 组件
const
activityNodes
:
ApprovalNodeInfo
[]
=
[
approvalNode1
,
approvalNode2
,
approvalNode3
];
export
{
processInstance
,
activityNodes
,
users
};
export
const
startUserSelectTasks
=
users
.
map
(
user
=>
({
id
:
user
.
id
,
name
:
user
.
nickname
}))
src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue
View file @
92314ee9
...
@@ -36,7 +36,15 @@
...
@@ -36,7 +36,15 @@
{{ getApprovalNodeTime(activity) }}
{{ getApprovalNodeTime(activity) }}
</div>
</div>
</div>
</div>
<div
class=
"flex items-center flex-wrap mt-1 gap2"
>
<!-- 需要自定义选择审批人 -->
<div
v-if=
"startUserSelectTasks?.length > 0 && activity.nodeType === NodeType.USER_TASK_NODE"
>
<el-button
class=
"!px-8px"
@
click=
"handleSelectUser"
>
<Icon
icon=
"fa:user-plus"
/>
</el-button>
</div>
<div
v-else
class=
"flex items-center flex-wrap mt-1 gap2"
>
<!-- 情况一:遍历每个审批节点下的【进行中】task 任务 -->
<!-- 情况一:遍历每个审批节点下的【进行中】task 任务 -->
<div
v-for=
"(task, idx) in activity.tasks"
:key=
"idx"
class=
"flex flex-col pr-2 gap2"
>
<div
v-for=
"(task, idx) in activity.tasks"
:key=
"idx"
class=
"flex flex-col pr-2 gap2"
>
<div
<div
...
@@ -121,6 +129,8 @@
...
@@ -121,6 +129,8 @@
</div>
</div>
</el-timeline-item>
</el-timeline-item>
</el-timeline>
</el-timeline>
<!-- 用户选择弹窗 -->
<UserSelectForm
ref=
"userSelectFormRef"
@
confirm=
"handleUserSelectConfirm"
/>
</template>
</template>
<
script
lang=
"ts"
setup
>
<
script
lang=
"ts"
setup
>
...
@@ -141,9 +151,11 @@ withDefaults(
...
@@ -141,9 +151,11 @@ withDefaults(
defineProps
<
{
defineProps
<
{
activityNodes
:
ProcessInstanceApi
.
ApprovalNodeInfo
[]
// 审批节点信息
activityNodes
:
ProcessInstanceApi
.
ApprovalNodeInfo
[]
// 审批节点信息
showStatusIcon
?:
boolean
// 是否显示头像右下角状态图标
showStatusIcon
?:
boolean
// 是否显示头像右下角状态图标
startUserSelectTasks
?:
any
[]
// 发起人需要选择审批人的用户任务列表
}
>
(),
}
>
(),
{
{
showStatusIcon
:
true
// 默认值为 true
showStatusIcon
:
true
,
// 默认值为 true
startUserSelectTasks
:
()
=>
[]
// 默认值为空数组
}
}
)
)
...
@@ -241,4 +253,14 @@ const getApprovalNodeTime = (node: ProcessInstanceApi.ApprovalNodeInfo) => {
...
@@ -241,4 +253,14 @@ const getApprovalNodeTime = (node: ProcessInstanceApi.ApprovalNodeInfo) => {
return
`
${
formatDate
(
node
.
startTime
)}
`
return
`
${
formatDate
(
node
.
startTime
)}
`
}
}
}
}
// 选择自定义审批人
const
userSelectFormRef
=
ref
()
const
handleSelectUser
=
()
=>
{
userSelectFormRef
.
value
.
open
()
}
// 选择完成
const
handleUserSelectConfirm
=
(
userList
)
=>
{
console
.
log
(
'[ userList ] >'
,
userList
)
}
</
script
>
</
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