fix: 【工作流】--加签减签

This commit is contained in:
shizhong 2024-03-05 16:31:04 +08:00
parent a2c4cb22f4
commit f0cdee8e9a
7 changed files with 370 additions and 21 deletions

View File

@ -58,3 +58,24 @@ export const okRollback = async (data) => {
export const delegateTask = async (data) => { export const delegateTask = async (data) => {
return await request.put({ url: '/bpm/task/delegate', data }) return await request.put({ url: '/bpm/task/delegate', data })
} }
/**
*
*/
export const taskAddSign = async (data) => {
return await request.put({ url: '/bpm/task/add-sign', data })
}
/**
*
*/
export const getSubSignTaskList = async (id: string) => {
return await request.get({ url: '/bpm/task/get-sub-sign?taskId=' + id })
}
/**
*
*/
export const taskSubSign = async (data) => {
return await request.put({ url: '/bpm/task/sub-sign', data })
}

View File

@ -1,3 +1,4 @@
<template>
<template> <template>
<div class="my-process-designer"> <div class="my-process-designer">
<div class="my-process-designer__container"> <div class="my-process-designer__container">
@ -250,6 +251,12 @@ const getResultCss = (result) => {
} else if (result === 5) { } else if (result === 5) {
// 退 // 退
return 'highlight-return' return 'highlight-return'
} else if (result === 6) {
//
return 'highlight-return'
} else if (result === 7 || result === 8 || result === 9) {
// //
return 'highlight-return'
} }
return '' return ''
} }
@ -362,7 +369,7 @@ const elementHover = (element) => {
} }
} }
console.log(html, 'html111111111111111') console.log(html, 'html111111111111111')
elementOverlayIds.value[element.value.id] = toRaw(overlays.value).add(element.value, { elementOverlayIds.value[element.value.id] = toRaw(overlays.value)?.add(element.value, {
position: { left: 0, bottom: 0 }, position: { left: 0, bottom: 0 },
html: `<div class="element-overlays">${html}</div>` html: `<div class="element-overlays">${html}</div>`
}) })

View File

@ -19,6 +19,9 @@ export const isObject = (val: any): val is Record<any, any> => {
} }
export const isEmpty = <T = unknown>(val: T): val is T => { export const isEmpty = <T = unknown>(val: T): val is T => {
if (val === null) {
return true
}
if (isArray(val) || isString(val)) { if (isArray(val) || isString(val)) {
return val.length === 0 return val.length === 0
} }

View File

@ -57,6 +57,7 @@
title="委派" title="委派"
@click="handleDelegate(item)" @click="handleDelegate(item)"
/> />
<XButton pre-icon="ep:plus" type="warning" title="加签" @click="handleSign(item)" />
<XButton pre-icon="ep:back" type="warning" title="退回" @click="handleBack(item)" /> <XButton pre-icon="ep:back" type="warning" title="退回" @click="handleBack(item)" />
</div> </div>
</el-col> </el-col>
@ -104,7 +105,18 @@
:icon="getTimelineItemIcon(item)" :icon="getTimelineItemIcon(item)"
:type="getTimelineItemType(item)" :type="getTimelineItemType(item)"
> >
<p style="font-weight: 700">任务{{ item.name }}</p> <p style="font-weight: 700">
任务{{ item.name }}
<dict-tag :type="DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT" :value="item.result" />
<el-button
style="margin-left: 5px"
v-if="!isEmpty(item.children)"
@click="openChildrenTask(item)"
>
<Icon icon="ep:memo" />
子任务
</el-button>
</p>
<el-card :body-style="{ padding: '10px' }"> <el-card :body-style="{ padding: '10px' }">
<label v-if="item.assigneeUser" style="margin-right: 30px; font-weight: normal"> <label v-if="item.assigneeUser" style="margin-right: 30px; font-weight: normal">
审批人{{ item.assigneeUser.nickname }} 审批人{{ item.assigneeUser.nickname }}
@ -194,6 +206,10 @@
<TaskReturnDialogForm ref="taskReturnDialogRef" @success="getDetail" /> <TaskReturnDialogForm ref="taskReturnDialogRef" @success="getDetail" />
<!-- 委派将任务委派给别人处理处理完成后会重新回到原审批人手中--> <!-- 委派将任务委派给别人处理处理完成后会重新回到原审批人手中-->
<TaskDelegateForm ref="taskDelegateForm" @success="getDetail" /> <TaskDelegateForm ref="taskDelegateForm" @success="getDetail" />
<!-- 加签当前任务审批人为A向前加签选了一个C则需要C先审批然后再是A审批向后加签BA审批完需要B再审批完才算完成这个任务节点 -->
<TaskAddSignDialogForm ref="taskAddSignDialogForm" @success="getDetail" />
<!-- 子任务 -->
<ProcessInstanceChildrenTaskList ref="processInstanceChildrenTaskList" />
</ContentWrap> </ContentWrap>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -211,6 +227,11 @@ import { useUserStore } from '@/store/modules/user'
import { MyProcessViewer } from '@/components/bpmnProcessDesigner/package' import { MyProcessViewer } from '@/components/bpmnProcessDesigner/package'
import TaskReturnDialogForm from './detail/TaskReturnDialogForm.vue' import TaskReturnDialogForm from './detail/TaskReturnDialogForm.vue'
import TaskDelegateForm from './detail/TaskDelegateForm.vue' import TaskDelegateForm from './detail/TaskDelegateForm.vue'
import TaskAddSignDialogForm from './TaskAddSignDialogForm.vue'
import { isEmpty } from '@/utils/is'
import { DICT_TYPE } from '@/utils/dict'
import { isEmpty } from '@/utils/is'
import ProcessInstanceChildrenTaskList from './ProcessInstanceChildrenTaskList.vue'
defineOptions({ name: 'BpmProcessInstanceDetail' }) defineOptions({ name: 'BpmProcessInstanceDetail' })
@ -309,9 +330,21 @@ const getTimelineItemType = (item) => {
if (item.result === 6) { if (item.result === 6) {
return 'default' return 'default'
} }
if (item.result === 7 || item.result === 8) {
return 'warning'
}
return '' return ''
} }
/**
* 子任务
*/
const processInstanceChildrenTaskList = ref()
const openChildrenTask = (item) => {
processInstanceChildrenTaskList.value.open(item)
}
// ========== ========== // ========== ==========
const updateAssigneeVisible = ref(false) const updateAssigneeVisible = ref(false)
const updateAssigneeLoading = ref(false) const updateAssigneeLoading = ref(false)
@ -377,6 +410,12 @@ const handleBack = async (task) => {
taskReturnDialogRef.value.open(task.id) taskReturnDialogRef.value.open(task.id)
} }
const taskAddSignDialogForm = ref()
/** 处理审批加签的操作 */
const handleSign = async (task) => {
taskAddSignDialogForm.value.open(task.id)
}
// ========== ========== // ========== ==========
const bpmnXML = ref(null) const bpmnXML = ref(null)
const bpmnControlForm = ref({ const bpmnControlForm = ref({
@ -466,26 +505,37 @@ const getDetail = () => {
} }
}) })
// //
tasks.value.forEach((task) => { runningTasks.value = []
// 1.1 auditForms.value = []
if (task.result !== 1 && task.result !== 6) { loadRunningTask(tasks.value)
return } finally {
} tasksLoad.value = false
// 1.2 }
if (!task.assigneeUser || task.assigneeUser.id !== userId) { }
return
} /**
// 2. * 设置 runningTasks 中的任务
runningTasks.value.push({ ...task }) */
auditForms.value.push({ const loadRunningTask = (tasks) => {
reason: '' tasks.forEach((task) => {
}) if (!isEmpty(task.children)) {
}) loadRunningTask(task.children)
}) }
.finally(() => { // 2.1
tasksLoad.value = false if (task.result !== 1 && task.result !== 6) {
return
}
// 2.2
if (!task.assigneeUser || task.assigneeUser.id !== userId) {
return
}
// 2.3
runningTasks.value.push({ ...task })
auditForms.value.push({
reason: ''
}) })
})
} }
</script> </script>

View File

@ -0,0 +1,86 @@
<template>
<el-drawer v-model="drawerVisible" title="子任务" size="70%">
<template #header>
<h4>{{ baseTask.name }} 审批人{{ baseTask.assigneeUser?.nickname }}</h4>
<el-button style="margin-left: 5px" type="danger" plain @click="handleSubSign(baseTask)">
<Icon icon="ep:remove" />
减签
</el-button>
</template>
<el-table :data="tableData" style="width: 100%" row-key="id" border>
<el-table-column prop="assigneeUser.nickname" label="审批人" />
<el-table-column prop="assigneeUser.deptName" label="所在部门" />
<el-table-column label="审批状态" prop="result">
<template #default="scope">
<dict-tag :type="DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT" :value="scope.row.result" />
</template>
</el-table-column>
<el-table-column
label="提交时间"
align="center"
prop="createTime"
width="180"
:formatter="dateFormatter"
/>
<el-table-column
label="结束时间"
align="center"
prop="endTime"
width="180"
:formatter="dateFormatter"
/>
<el-table-column label="操作" prop="operation">
<template #default="scope">
<el-button
v-if="!isEmpty(scope.row.children)"
type="danger"
plain
@click="handleSubSign(scope.row)"
>
<Icon icon="ep:remove" />
减签
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 减签 -->
<TaskSubSignDialogForm ref="taskSubSignDialogForm" />
</el-drawer>
</template>
<script lang="ts" setup>
import { isEmpty } from '@/utils/is'
import { DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import TaskSubSignDialogForm from './TaskSubSignDialogForm.vue'
const message = useMessage() //
defineOptions({ name: 'ProcessInstancechildrenList' })
const drawerVisible = ref(false) //
const tableData = ref<any[]>([]) //
const baseTask = ref<object>({})
/** 打开弹窗 */
const open = async (task: any) => {
if (isEmpty(task.children)) {
message.warning('该任务没有子任务')
return
}
baseTask.value = task
//
tableData.value = task.children
//
drawerVisible.value = true
}
defineExpose({ open }) // openModal
const emit = defineEmits(['success']) // success
/**
* 减签
*/
const taskSubSignDialogForm = ref()
const handleSubSign = (item) => {
taskSubSignDialogForm.value.open(item.id)
}
</script>

View File

@ -0,0 +1,97 @@
<template>
<Dialog v-model="dialogVisible" title="加签" width="500">
<el-form
ref="formRef"
v-loading="formLoading"
:model="formData"
:rules="formRules"
label-width="110px"
>
<el-form-item label="加签处理人" prop="userIdList">
<el-select v-model="formData.userIdList" multiple clearable style="width: 100%">
<el-option
v-for="item in userList"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="加签理由" prop="reason">
<el-input v-model="formData.reason" clearable placeholder="请输入加签理由" />
</el-form-item>
</el-form>
<template #footer>
<el-button :disabled="formLoading" type="primary" @click="submitForm('before')"
>向前加签</el-button
>
<el-button :disabled="formLoading" type="primary" @click="submitForm('after')"
>向后加签</el-button
>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</template>
<script lang="ts" setup>
import * as TaskApi from '@/api/bpm/task'
import * as UserApi from '@/api/system/user'
const message = useMessage() //
defineOptions({ name: 'BpmTaskUpdateAssigneeForm' })
const dialogVisible = ref(false) //
const formLoading = ref(false) //
const formData = ref({
id: '',
userIdList: [],
type: ''
})
const formRules = ref({
userIdList: [{ required: true, message: '加签处理人不能为空', trigger: 'change' }],
reason: [{ required: true, message: '加签理由不能为空', trigger: 'change' }]
})
const formRef = ref() // Ref
const userList = ref<any[]>([]) //
/** 打开弹窗 */
const open = async (id: string) => {
dialogVisible.value = true
resetForm()
formData.value.id = id
//
userList.value = await UserApi.getSimpleUserList()
}
defineExpose({ open }) // openModal
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async (type: string) => {
//
if (!formRef) return
const valid = await formRef.value.validate()
if (!valid) return
//
formLoading.value = true
formData.value.type = type
try {
await TaskApi.taskAddSign(formData.value)
message.success('加签成功')
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: '',
userIdList: [],
type: ''
}
formRef.value?.resetFields()
}
</script>

View File

@ -0,0 +1,85 @@
<template>
<Dialog v-model="dialogVisible" title="减签" width="500">
<el-form
ref="formRef"
v-loading="formLoading"
:model="formData"
:rules="formRules"
label-width="110px"
>
<el-form-item label="减签任务" prop="id">
<el-radio-group v-model="formData.id">
<el-radio-button v-for="item in subTaskList" :key="item.id" :label="item.id">
{{ item.name }}({{ item.assigneeUser.deptName }}{{ item.assigneeUser.nickname }}--审批)
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="减签理由" prop="reason">
<el-input v-model="formData.reason" clearable placeholder="请输入减签理由" />
</el-form-item>
</el-form>
<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" name="TaskRollbackDialogForm" setup>
import * as TaskApi from '@/api/bpm/task'
import { isEmpty } from '@/utils/is'
const message = useMessage() //
const dialogVisible = ref(false) //
const formLoading = ref(false) //
const formData = ref({
id: '',
reason: ''
})
const formRules = ref({
id: [{ required: true, message: '必须选择减签任务', trigger: 'change' }],
reason: [{ required: true, message: '减签理由不能为空', trigger: 'blur' }]
})
const formRef = ref() // Ref
const subTaskList = ref([])
/** 打开弹窗 */
const open = async (id: string) => {
subTaskList.value = await TaskApi.getSubSignTaskList(id)
if (isEmpty(subTaskList.value)) {
message.warning('当前没有可减签的任务')
return false
}
dialogVisible.value = true
resetForm()
}
defineExpose({ open }) // openModal
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
if (!formRef) return
const valid = await formRef.value.validate()
if (!valid) return
//
formLoading.value = true
try {
await TaskApi.taskSubSign(formData.value)
message.success('减签成功')
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: '',
reason: ''
}
formRef.value?.resetFields()
}
</script>