!267 【工作流】加签和减签

Merge pull request !267 from Youkehai/feature/addSignAndSubSign
This commit is contained in:
芋道源码 2023-10-17 11:01:18 +00:00 committed by Gitee
commit 0242c84196
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
8 changed files with 380 additions and 17 deletions

View File

@ -58,3 +58,24 @@ export const returnTask = 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 getChildrenTaskList = async (id: string) => {
return await request.get({ url: '/bpm/task/get-children-task-list?taskId=' + id })
}
/**
*
*/
export const taskSubSign = async (data) => {
return await request.put({ url: '/bpm/task/sub-sign', data })
}

View File

@ -250,6 +250,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 +368,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

@ -0,0 +1,99 @@
<template>
<el-drawer v-model="drawerVisible" title="子任务" size="70%">
<template #header>
<h4>{{ baseTask.name }} 审批人{{ baseTask.assigneeUser?.nickname }}</h4>
<el-button style="margin-left: 5px" v-if="showSubSignButton(baseTask)" 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="showSubSignButton(scope.row)"
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)
}
/**
* 显示减签按钮
* @param task
*/
const showSubSignButton = (task:any) => {
if(!isEmpty(task.children)){
//
const subTask = task.children.find((item) => item.result === 1 || item.result === 9)
return !isEmpty(subTask)
}
return false
}
</script>

View File

@ -12,7 +12,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 }}
@ -42,11 +53,16 @@
</el-timeline> </el-timeline>
</div> </div>
</el-col> </el-col>
<!-- 子任务 -->
<ProcessInstanceChildrenTaskList ref="processInstanceChildrenTaskList" />
</el-card> </el-card>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { formatDate, formatPast2 } from '@/utils/formatTime' import { formatDate, formatPast2 } from '@/utils/formatTime'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { DICT_TYPE } from '@/utils/dict'
import { isEmpty } from '@/utils/is'
import ProcessInstanceChildrenTaskList from './ProcessInstanceChildrenTaskList.vue'
defineOptions({ name: 'BpmProcessInstanceTaskList' }) defineOptions({ name: 'BpmProcessInstanceTaskList' })
@ -95,6 +111,18 @@ 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)
}
</script> </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.getChildrenTaskList(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>

View File

@ -49,6 +49,10 @@
<Icon icon="ep:position" /> <Icon icon="ep:position" />
委派 委派
</el-button> </el-button>
<el-button type="primary" @click="handleSign(item)">
<Icon icon="ep:plus" />
加签
</el-button>
<el-button type="warning" @click="handleBack(item)"> <el-button type="warning" @click="handleBack(item)">
<Icon icon="ep:back" /> <Icon icon="ep:back" />
回退 回退
@ -95,6 +99,8 @@
<TaskReturnDialog ref="taskReturnDialogRef" @success="getDetail" /> <TaskReturnDialog 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" />
</ContentWrap> </ContentWrap>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -109,7 +115,9 @@ import ProcessInstanceBpmnViewer from './ProcessInstanceBpmnViewer.vue'
import ProcessInstanceTaskList from './ProcessInstanceTaskList.vue' import ProcessInstanceTaskList from './ProcessInstanceTaskList.vue'
import TaskReturnDialog from './TaskReturnDialogForm.vue' import TaskReturnDialog from './TaskReturnDialogForm.vue'
import TaskDelegateForm from './taskDelegateForm.vue' import TaskDelegateForm from './taskDelegateForm.vue'
import TaskAddSignDialogForm from './TaskAddSignDialogForm.vue'
import { registerComponent } from '@/utils/routerHelper' import { registerComponent } from '@/utils/routerHelper'
import { isEmpty } from '@/utils/is'
defineOptions({ name: 'BpmProcessInstanceDetail' }) defineOptions({ name: 'BpmProcessInstanceDetail' })
@ -185,6 +193,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 getDetail = () => { const getDetail = () => {
// 1. // 1.
@ -261,26 +275,36 @@ const getTaskList = async () => {
// //
runningTasks.value = [] runningTasks.value = []
auditForms.value = [] auditForms.value = []
tasks.value.forEach((task) => { loadRunningTask(tasks.value)
// 2.1
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: ''
})
})
} finally { } finally {
tasksLoad.value = false tasksLoad.value = false
} }
} }
/**
* 设置 runningTasks 中的任务
*/
const loadRunningTask = (tasks) => {
tasks.forEach((task) => {
if (!isEmpty(task.children)) {
loadRunningTask(task.children)
}
// 2.1
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: ''
})
})
}
/** 初始化 */ /** 初始化 */
onMounted(() => { onMounted(() => {
getDetail() getDetail()