BPM:增加「发起人自选」的任务审批人的分配策略

This commit is contained in:
YunaiV
2024-03-23 00:54:33 +08:00
parent 48f6624737
commit 728cf15c45
7 changed files with 182 additions and 29 deletions

View File

@@ -1,8 +1,9 @@
import request from '@/config/axios' import request from '@/config/axios'
export const getProcessDefinitionBpmnXML = async (id: number) => { export const getProcessDefinition = async (id: number, key: string) => {
return await request.get({ return await request.get({
url: '/bpm/process-definition/get-bpmn-xml?id=' + id url: '/bpm/process-definition/get',
params: { id, key }
}) })
} }

View File

@@ -65,11 +65,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
v-if=" v-if="userTaskForm.candidateStrategy == 30"
userTaskForm.candidateStrategy == 30 ||
userTaskForm.candidateStrategy == 31 ||
userTaskForm.candidateStrategy == 32
"
label="指定用户" label="指定用户"
prop="candidateParam" prop="candidateParam"
span="24" span="24"

View File

@@ -72,8 +72,8 @@
<Dialog title="流程图" v-model="bpmnDetailVisible" width="800"> <Dialog title="流程图" v-model="bpmnDetailVisible" width="800">
<MyProcessViewer <MyProcessViewer
key="designer" key="designer"
v-model="bpmnXML" v-model="bpmnXml"
:value="bpmnXML as any" :value="bpmnXml as any"
v-bind="bpmnControlForm" v-bind="bpmnControlForm"
:prefix="bpmnControlForm.prefix" :prefix="bpmnControlForm.prefix"
/> />
@@ -133,12 +133,12 @@ const handleFormDetail = async (row) => {
/** 流程图的详情按钮操作 */ /** 流程图的详情按钮操作 */
const bpmnDetailVisible = ref(false) const bpmnDetailVisible = ref(false)
const bpmnXML = ref(null) const bpmnXml = ref(null)
const bpmnControlForm = ref({ const bpmnControlForm = ref({
prefix: 'flowable' prefix: 'flowable'
}) })
const handleBpmnDetail = async (row) => { const handleBpmnDetail = async (row) => {
bpmnXML.value = await DefinitionApi.getProcessDefinitionBpmnXML(row.id) bpmnXml.value = (await DefinitionApi.getProcessDefinition(row.id))?.bpmnXml
bpmnDetailVisible.value = true bpmnDetailVisible.value = true
} }

View File

@@ -37,6 +37,36 @@
<el-form-item label="原因" prop="reason"> <el-form-item label="原因" prop="reason">
<el-input v-model="formData.reason" placeholder="请输请假原因" type="textarea" /> <el-input v-model="formData.reason" placeholder="请输请假原因" type="textarea" />
</el-form-item> </el-form-item>
<el-col v-if="startUserSelectTasks.length > 0">
<el-card class="mb-10px">
<template #header>指定审批人</template>
<el-form
:model="startUserSelectAssignees"
:rules="startUserSelectAssigneesFormRules"
ref="startUserSelectAssigneesFormRef"
>
<el-form-item
v-for="userTask in startUserSelectTasks"
:key="userTask.id"
:label="`任务【${userTask.name}】`"
:prop="userTask.id"
>
<el-select
v-model="startUserSelectAssignees[userTask.id]"
multiple
placeholder="请选择审批人"
>
<el-option
v-for="user in userList"
:key="user.id"
:label="user.nickname"
:value="user.id"
/>
</el-select>
</el-form-item>
</el-form>
</el-card>
</el-col>
<el-form-item> <el-form-item>
<el-button :disabled="formLoading" type="primary" @click="submitForm"> </el-button> <el-button :disabled="formLoading" type="primary" @click="submitForm"> </el-button>
</el-form-item> </el-form-item>
@@ -46,10 +76,15 @@
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 * as DefinitionApi from '@/api/bpm/definition'
import * as UserApi from '@/api/system/user'
defineOptions({ name: 'BpmOALeaveCreate' }) defineOptions({ name: 'BpmOALeaveCreate' })
const message = useMessage() // 消息弹窗 const message = useMessage() // 消息弹窗
const { delView } = useTagsViewStore() // 视图操作
const { push, currentRoute } = useRouter() // 路由
const formLoading = ref(false) // 表单的加载中1修改时的数据加载2提交的按钮禁用 const formLoading = ref(false) // 表单的加载中1修改时的数据加载2提交的按钮禁用
const formData = ref({ const formData = ref({
type: undefined, type: undefined,
@@ -64,18 +99,34 @@ const formRules = reactive({
endTime: [{ required: true, message: '请假结束时间不能为空', trigger: 'change' }] endTime: [{ required: true, message: '请假结束时间不能为空', trigger: 'change' }]
}) })
const formRef = ref() // 表单 Ref const formRef = ref() // 表单 Ref
const { delView } = useTagsViewStore() // 视图操作
const { push, currentRoute } = useRouter() // 路由 // 指定审批人
const processDefineKey = 'oa_leave' // 流程定义 Key
const startUserSelectTasks = ref([]) // 发起人需要选择审批人的用户任务列表
const startUserSelectAssignees = ref({}) // 发起人选择审批人的数据
const startUserSelectAssigneesFormRef = ref() // 发起人选择审批人的表单 Ref
const startUserSelectAssigneesFormRules = ref({}) // 发起人选择审批人的表单 Rules
const userList = ref<any[]>([]) // 用户列表
/** 提交表单 */ /** 提交表单 */
const submitForm = async () => { const submitForm = async () => {
// 校验表单 // 校验表单
if (!formRef) return if (!formRef) return
const valid = await formRef.value.validate() const valid = await formRef.value.validate()
if (!valid) return if (!valid) return
// 校验指定审批人
if (startUserSelectTasks.value?.length > 0) {
await startUserSelectAssigneesFormRef.value.validate()
}
// 提交请求 // 提交请求
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) {
data.startUserSelectAssignees = startUserSelectAssignees.value
}
await LeaveApi.createLeave(data) await LeaveApi.createLeave(data)
message.success('发起成功') message.success('发起成功')
// 关闭当前 Tab // 关闭当前 Tab
@@ -85,4 +136,29 @@ const submitForm = async () => {
formLoading.value = false formLoading.value = false
} }
} }
/** 初始化 */
onMounted(async () => {
const processDefinitionDetail = await DefinitionApi.getProcessDefinition(
undefined,
processDefineKey
)
if (!processDefinitionDetail) {
message.error('OA 请假的流程模型未配置,请检查!')
return
}
startUserSelectTasks.value = processDefinitionDetail.startUserSelectTasks
// 设置指定审批人
if (startUserSelectTasks.value?.length > 0) {
// 设置校验规则
for (const userTask of startUserSelectTasks.value) {
startUserSelectAssignees.value[userTask.id] = []
startUserSelectAssigneesFormRules.value[userTask.id] = [
{ required: true, message: '请选择审批人', trigger: 'blur' }
]
}
// 加载用户列表
userList.value = await UserApi.getSimpleUserList()
}
})
</script> </script>

View File

@@ -54,7 +54,40 @@
v-model="detailForm.value" v-model="detailForm.value"
:option="detailForm.option" :option="detailForm.option"
@submit="submitForm" @submit="submitForm"
>
<template #type-startUserSelect>
<el-col :span="24">
<el-card class="mb-10px">
<template #header>指定审批人</template>
<el-form
:model="startUserSelectAssignees"
:rules="startUserSelectAssigneesFormRules"
ref="startUserSelectAssigneesFormRef"
>
<el-form-item
v-for="userTask in startUserSelectTasks"
:key="userTask.id"
:label="`任务【${userTask.name}】`"
:prop="userTask.id"
>
<el-select
v-model="startUserSelectAssignees[userTask.id]"
multiple
placeholder="请选择审批人"
>
<el-option
v-for="user in userList"
:key="user.id"
:label="user.nickname"
:value="user.id"
/> />
</el-select>
</el-form-item>
</el-form>
</el-card>
</el-col>
</template>
</form-create>
</el-col> </el-col>
</el-card> </el-card>
<!-- 流程图预览 --> <!-- 流程图预览 -->
@@ -69,6 +102,7 @@ import type { ApiAttrs } from '@form-create/element-ui/types/config'
import ProcessInstanceBpmnViewer from '../detail/ProcessInstanceBpmnViewer.vue' import ProcessInstanceBpmnViewer from '../detail/ProcessInstanceBpmnViewer.vue'
import { CategoryApi } from '@/api/bpm/category' import { CategoryApi } from '@/api/bpm/category'
import { useTagsViewStore } from '@/store/modules/tagsView' import { useTagsViewStore } from '@/store/modules/tagsView'
import * as UserApi from '@/api/system/user'
defineOptions({ name: 'BpmProcessInstanceCreate' }) defineOptions({ name: 'BpmProcessInstanceCreate' })
@@ -124,7 +158,6 @@ const categoryProcessDefinitionList = computed(() => {
}) })
// ========== 表单相关 ========== // ========== 表单相关 ==========
const bpmnXML = ref(null) // BPMN 数据
const fApi = ref<ApiAttrs>() const fApi = ref<ApiAttrs>()
const detailForm = ref({ const detailForm = ref({
rule: [], rule: [],
@@ -133,17 +166,53 @@ const detailForm = ref({
}) // 流程表单详情 }) // 流程表单详情
const selectProcessDefinition = ref() // 选择的流程定义 const selectProcessDefinition = ref() // 选择的流程定义
// 指定审批人
const bpmnXML = ref(null) // BPMN 数据
const startUserSelectTasks = ref([]) // 发起人需要选择审批人的用户任务列表
const startUserSelectAssignees = ref({}) // 发起人选择审批人的数据
const startUserSelectAssigneesFormRef = ref() // 发起人选择审批人的表单 Ref
const startUserSelectAssigneesFormRules = ref({}) // 发起人选择审批人的表单 Rules
const userList = ref<any[]>([]) // 用户列表
/** 处理选择流程的按钮操作 **/ /** 处理选择流程的按钮操作 **/
const handleSelect = async (row, formVariables) => { const handleSelect = async (row, formVariables) => {
// 设置选择的流程 // 设置选择的流程
selectProcessDefinition.value = row selectProcessDefinition.value = row
// 重置指定审批人
startUserSelectTasks.value = []
startUserSelectAssignees.value = {}
startUserSelectAssigneesFormRules.value = {}
// 情况一:流程表单 // 情况一:流程表单
if (row.formType == 10) { if (row.formType == 10) {
// 设置表单 // 设置表单
setConfAndFields2(detailForm, row.formConf, row.formFields, formVariables) setConfAndFields2(detailForm, row.formConf, row.formFields, formVariables)
// 加载流程图 // 加载流程图
bpmnXML.value = await DefinitionApi.getProcessDefinitionBpmnXML(row.id) const processDefinitionDetail = await DefinitionApi.getProcessDefinition(row.id)
if (processDefinitionDetail) {
bpmnXML.value = processDefinitionDetail.bpmnXml
startUserSelectTasks.value = processDefinitionDetail.startUserSelectTasks
// 设置指定审批人
if (startUserSelectTasks.value?.length > 0) {
detailForm.value.rule.push({
type: 'startUserSelect',
props: {
title: '指定审批人'
}
})
// 设置校验规则
for (const userTask of startUserSelectTasks.value) {
startUserSelectAssignees.value[userTask.id] = []
startUserSelectAssigneesFormRules.value[userTask.id] = [
{ required: true, message: '请选择审批人', trigger: 'blur' }
]
}
// 加载用户列表
userList.value = await UserApi.getSimpleUserList()
}
}
// 情况二:业务表单 // 情况二:业务表单
} else if (row.formCustomCreatePath) { } else if (row.formCustomCreatePath) {
await push({ await push({
@@ -158,19 +227,25 @@ const submitForm = async (formData) => {
if (!fApi.value || !selectProcessDefinition.value) { if (!fApi.value || !selectProcessDefinition.value) {
return return
} }
// 如果有指定审批人,需要校验
if (startUserSelectTasks.value?.length > 0) {
await startUserSelectAssigneesFormRef.value.validate()
}
// 提交请求 // 提交请求
fApi.value.btn.loading(true) fApi.value.btn.loading(true)
try { try {
await ProcessInstanceApi.createProcessInstance({ await ProcessInstanceApi.createProcessInstance({
processDefinitionId: selectProcessDefinition.value.id, processDefinitionId: selectProcessDefinition.value.id,
variables: formData variables: formData,
startUserSelectAssignees: startUserSelectAssignees.value
}) })
// 提示 // 提示
message.success('发起流程成功') message.success('发起流程成功')
// 跳转回去 // 跳转回去
delView(unref(currentRoute)) delView(unref(currentRoute))
await push({ await push({
name: 'BpmProcessInstance' name: 'BpmProcessInstanceMy'
}) })
} finally { } finally {
fApi.value.btn.loading(false) fApi.value.btn.loading(false)

View File

@@ -34,14 +34,17 @@ const bpmnControlForm = ref({
}) })
const activityList = ref([]) // 任务列表 const activityList = ref([]) // 任务列表
/** 初始化 */ /** 只有 loading 完成时,才去加载流程列表 */
onMounted(async () => { watch(
if (props.id) { () => props.loading,
async (value) => {
if (value && props.id) {
activityList.value = await ActivityApi.getActivityList({ activityList.value = await ActivityApi.getActivityList({
processInstanceId: props.id processInstanceId: props.id
}) })
} }
}) }
)
</script> </script>
<style> <style>
.box-card { .box-card {

View File

@@ -115,7 +115,7 @@
<!-- 高亮流程图 --> <!-- 高亮流程图 -->
<ProcessInstanceBpmnViewer <ProcessInstanceBpmnViewer
:id="`${id}`" :id="`${id}`"
:bpmn-xml="bpmnXML" :bpmn-xml="bpmnXml"
:loading="processInstanceLoading" :loading="processInstanceLoading"
:process-instance="processInstance" :process-instance="processInstance"
:tasks="tasks" :tasks="tasks"
@@ -158,7 +158,7 @@ const userId = useUserStore().getUser.id // 当前登录的编号
const id = query.id as unknown as string // 流程实例的编号 const id = query.id as unknown as string // 流程实例的编号
const processInstanceLoading = ref(false) // 流程实例的加载中 const processInstanceLoading = ref(false) // 流程实例的加载中
const processInstance = ref<any>({}) // 流程实例 const processInstance = ref<any>({}) // 流程实例
const bpmnXML = ref('') // BPMN XML const bpmnXml = ref('') // BPMN XML
const tasksLoad = ref(true) // 任务的加载中 const tasksLoad = ref(true) // 任务的加载中
const tasks = ref<any[]>([]) // 任务列表 const tasks = ref<any[]>([]) // 任务列表
// ========== 审批信息 ========== // ========== 审批信息 ==========
@@ -290,7 +290,9 @@ const getProcessInstance = async () => {
} }
// 加载流程图 // 加载流程图
bpmnXML.value = await DefinitionApi.getProcessDefinitionBpmnXML(processDefinition.id as number) bpmnXml.value = (
await DefinitionApi.getProcessDefinition(processDefinition.id as number)
)?.bpmnXml
} finally { } finally {
processInstanceLoading.value = false processInstanceLoading.value = false
} }