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) // 12 const formLoading = ref(false) // 12
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
} }