Merge remote-tracking branch 'origin/feature/bpm' into feature/bpm

# Conflicts:
#	src/views/bpm/processInstance/detail/index_new.vue
pull/582/head
YunaiV 2024-10-12 19:42:43 +08:00
commit 6b06f320b9
8 changed files with 515 additions and 193 deletions

View File

@ -46,7 +46,7 @@ export type ApprovalNodeInfo = {
status: number status: number
startTime?: Date startTime?: Date
endTime?: Date endTime?: Date
candidateUserList?: User[] candidateUsers?: User[]
tasks: ApprovalTaskInfo[] tasks: ApprovalTaskInfo[]
} }

View File

@ -106,6 +106,11 @@ export const signDeleteTask = async (data: any) => {
return await request.delete({ url: '/bpm/task/delete-sign', data }) return await request.delete({ url: '/bpm/task/delete-sign', data })
} }
// 抄送
export const copyTask = async (data: any) => {
return await request.put({ url: '/bpm/task/copy', data })
}
// 获取减签任务列表 // 获取减签任务列表
export const getChildrenTaskList = async (id: string) => { export const getChildrenTaskList = async (id: string) => {
return await request.get({ url: '/bpm/task/list-by-parent-task-id?parentTaskId=' + id }) return await request.get({ url: '/bpm/task/list-by-parent-task-id?parentTaskId=' + id })

View File

@ -362,7 +362,11 @@ export enum OperationButtonType {
/** /**
* 退 * 退
*/ */
RETURN = 6 RETURN = 6,
/**
*
*/
COPY = 7
} }
/** /**
@ -504,6 +508,7 @@ OPERATION_BUTTON_NAME.set(OperationButtonType.TRANSFER, '转办')
OPERATION_BUTTON_NAME.set(OperationButtonType.DELEGATE, '委派') OPERATION_BUTTON_NAME.set(OperationButtonType.DELEGATE, '委派')
OPERATION_BUTTON_NAME.set(OperationButtonType.ADD_SIGN, '加签') OPERATION_BUTTON_NAME.set(OperationButtonType.ADD_SIGN, '加签')
OPERATION_BUTTON_NAME.set(OperationButtonType.RETURN, '回退') OPERATION_BUTTON_NAME.set(OperationButtonType.RETURN, '回退')
OPERATION_BUTTON_NAME.set(OperationButtonType.COPY, '抄送')
// 默认的按钮权限设置 // 默认的按钮权限设置
export const DEFAULT_BUTTON_SETTING: ButtonSetting[] = [ export const DEFAULT_BUTTON_SETTING: ButtonSetting[] = [

View File

@ -139,7 +139,6 @@
clearable clearable
multiple multiple
style="width: 100%" style="width: 100%"
@change="changedCandidateUsers"
> >
<el-option <el-option
v-for="item in userOptions" v-for="item in userOptions"
@ -187,10 +186,6 @@
<el-radio <el-radio
:value="item.value" :value="item.value"
:label="item.value" :label="item.value"
:disabled="
item.value !== ApproveMethodType.RANDOM_SELECT_ONE_APPROVE &&
notAllowedMultiApprovers
"
> >
{{ item.label }} {{ item.label }}
</el-radio> </el-radio>
@ -537,8 +532,7 @@ const {
getShowText getShowText
} = useNodeForm(NodeType.USER_TASK_NODE) } = useNodeForm(NodeType.USER_TASK_NODE)
const configForm = tempConfigForm as Ref<UserTaskFormType> const configForm = tempConfigForm as Ref<UserTaskFormType>
//
const notAllowedMultiApprovers = ref(false)
// //
const changeCandidateStrategy = () => { const changeCandidateStrategy = () => {
configForm.value.userIds = [] configForm.value.userIds = []
@ -548,29 +542,8 @@ const changeCandidateStrategy = () => {
configForm.value.userGroups = [] configForm.value.userGroups = []
configForm.value.deptLevel = 1 configForm.value.deptLevel = 1
configForm.value.approveMethod = ApproveMethodType.SEQUENTIAL_APPROVE configForm.value.approveMethod = ApproveMethodType.SEQUENTIAL_APPROVE
if (
configForm.value.candidateStrategy === CandidateStrategy.START_USER ||
configForm.value.candidateStrategy === CandidateStrategy.USER
) {
notAllowedMultiApprovers.value = true
} else {
notAllowedMultiApprovers.value = false
}
}
//
const changedCandidateUsers = () => {
if (
configForm.value.userIds &&
configForm.value.userIds?.length <= 1 &&
configForm.value.candidateStrategy === CandidateStrategy.USER
) {
configForm.value.approveMethod = ApproveMethodType.RANDOM_SELECT_ONE_APPROVE
configForm.value.rejectHandlerType = RejectHandlerType.FINISH_PROCESS
notAllowedMultiApprovers.value = true
} else {
notAllowedMultiApprovers.value = false
}
} }
// //
const approveMethodChanged = () => { const approveMethodChanged = () => {
configForm.value.rejectHandlerType = RejectHandlerType.FINISH_PROCESS configForm.value.rejectHandlerType = RejectHandlerType.FINISH_PROCESS
@ -666,11 +639,6 @@ const showUserTaskNodeConfig = (node: SimpleFlowNode) => {
configForm.value.candidateStrategy = node.candidateStrategy! configForm.value.candidateStrategy = node.candidateStrategy!
// //
parseCandidateParam(node.candidateStrategy!, node?.candidateParam) parseCandidateParam(node.candidateStrategy!, node?.candidateParam)
if (configForm.value.userIds && configForm.value.userIds.length > 1) {
notAllowedMultiApprovers.value = true
} else {
notAllowedMultiApprovers.value = false
}
// 2.2 // 2.2
configForm.value.approveMethod = node.approveMethod! configForm.value.approveMethod = node.approveMethod!
if (node.approveMethod == ApproveMethodType.APPROVE_BY_RATIO) { if (node.approveMethod == ApproveMethodType.APPROVE_BY_RATIO) {

View File

@ -5,14 +5,14 @@
> >
<!-- 通过按钮 --> <!-- 通过按钮 -->
<el-popover <el-popover
:visible="passVisible" :visible="popOverVisible.approve"
placement="top-end" placement="top-end"
:width="500" :width="420"
trigger="click" trigger="click"
v-if="isShowButton(OperationButtonType.APPROVE)" v-if="isShowButton(OperationButtonType.APPROVE)"
> >
<template #reference> <template #reference>
<el-button plain type="success" @click="openPopover('1')"> <el-button plain type="success" @click="openPopover('approve')">
<Icon icon="ep:select" />&nbsp; {{ getButtonDisplayName(OperationButtonType.APPROVE) }} <Icon icon="ep:select" />&nbsp; {{ getButtonDisplayName(OperationButtonType.APPROVE) }}
</el-button> </el-button>
</template> </template>
@ -22,16 +22,10 @@
label-position="top" label-position="top"
class="mb-auto" class="mb-auto"
ref="formRef" ref="formRef"
:model="auditForm" :model="genericForm"
:rules="auditRule" :rules="genericRule"
label-width="100px" label-width="100px"
> >
<el-form-item v-if="processInstance && processInstance.startUser" label="流程发起人">
{{ processInstance?.startUser.nickname }}
<el-tag size="small" type="info" class="ml-8px">
{{ processInstance?.startUser.deptName }}
</el-tag>
</el-form-item>
<el-card v-if="runningTask.formId > 0" class="mb-15px !-mt-10px"> <el-card v-if="runningTask.formId > 0" class="mb-15px !-mt-10px">
<template #header> <template #header>
<span class="el-icon-picture-outline"> 填写表单{{ runningTask?.formName }} </span> <span class="el-icon-picture-outline"> 填写表单{{ runningTask?.formName }} </span>
@ -43,25 +37,14 @@
:rule="approveForm.rule" :rule="approveForm.rule"
/> />
</el-card> </el-card>
<el-form-item label="审批建议" prop="reason"> <el-form-item label="审批意见" prop="reason">
<el-input v-model="auditForm.reason" placeholder="请输入审批建议" type="textarea" /> <el-input v-model="genericForm.reason" placeholder="请输入审批意见" type="textarea" :rows="4" />
</el-form-item> </el-form-item>
<el-form-item label="抄送人" prop="copyUserIds">
<el-select v-model="auditForm.copyUserIds" multiple placeholder="请选择抄送人">
<el-option
v-for="itemx in userOptions"
:key="itemx.id"
:label="itemx.nickname"
:value="itemx.id"
/>
</el-select>
</el-form-item>
<el-form-item> <el-form-item>
<el-button :disabled="formLoading" type="success" @click="handleAudit(true)"> <el-button :disabled="formLoading" type="success" @click="handleAudit(true)">
{{ getButtonDisplayName(OperationButtonType.APPROVE) }} {{ getButtonDisplayName(OperationButtonType.APPROVE) }}
</el-button> </el-button>
<el-button @click="passVisible = false"> 取消 </el-button> <el-button @click="popOverVisible.approve = false"> 取消 </el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
@ -69,14 +52,14 @@
<!-- 拒绝按钮 --> <!-- 拒绝按钮 -->
<el-popover <el-popover
:visible="rejectVisible" :visible="popOverVisible.reject"
placement="top-end" placement="top-end"
:width="500" :width="420"
trigger="click" trigger="click"
v-if="isShowButton(OperationButtonType.REJECT)" v-if="isShowButton(OperationButtonType.REJECT)"
> >
<template #reference> <template #reference>
<el-button class="mr-20px" plain type="danger" @click="openPopover('2')"> <el-button class="mr-20px" plain type="danger" @click="openPopover('reject')">
<Icon icon="ep:close" />&nbsp; {{ getButtonDisplayName(OperationButtonType.REJECT) }} <Icon icon="ep:close" />&nbsp; {{ getButtonDisplayName(OperationButtonType.REJECT) }}
</el-button> </el-button>
</template> </template>
@ -86,16 +69,10 @@
label-position="top" label-position="top"
class="mb-auto" class="mb-auto"
ref="formRef" ref="formRef"
:model="auditForm" :model="genericForm"
:rules="auditRule" :rules="genericRule"
label-width="100px" label-width="100px"
> >
<el-form-item v-if="processInstance && processInstance.startUser" label="流程发起人">
{{ processInstance?.startUser.nickname }}
<el-tag size="small" type="info" class="ml-8px">
{{ processInstance?.startUser.deptName }}
</el-tag>
</el-form-item>
<el-card v-if="runningTask.formId > 0" class="mb-15px !-mt-10px"> <el-card v-if="runningTask.formId > 0" class="mb-15px !-mt-10px">
<template #header> <template #header>
<span class="el-icon-picture-outline"> 填写表单{{ runningTask?.formName }} </span> <span class="el-icon-picture-outline"> 填写表单{{ runningTask?.formName }} </span>
@ -107,80 +84,273 @@
:rule="approveForm.rule" :rule="approveForm.rule"
/> />
</el-card> </el-card>
<el-form-item label="审批建议" prop="reason"> <el-form-item label="审批意见" prop="reason">
<el-input v-model="auditForm.reason" placeholder="请输入审批建议" type="textarea" /> <el-input v-model="genericForm.reason" placeholder="请输入审批意见" type="textarea" :rows="4" />
</el-form-item> </el-form-item>
<el-form-item label="抄送人" prop="copyUserIds">
<el-select v-model="auditForm.copyUserIds" multiple placeholder="请选择抄送人">
<el-option
v-for="itemx in userOptions"
:key="itemx.id"
:label="itemx.nickname"
:value="itemx.id"
/>
</el-select>
</el-form-item>
<el-form-item> <el-form-item>
<el-button :disabled="formLoading" type="danger" @click="handleAudit(false)"> <el-button :disabled="formLoading" type="danger" @click="handleAudit(false)">
{{ getButtonDisplayName(OperationButtonType.REJECT) }} {{ getButtonDisplayName(OperationButtonType.REJECT) }}
</el-button> </el-button>
<el-button @click="rejectVisible = false"> 取消 </el-button> <el-button @click="popOverVisible.reject = false"> 取消 </el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
</el-popover> </el-popover>
<!-- 抄送按钮 --> <!-- 抄送按钮 -->
<div @click="handleSend"> <Icon :size="14" icon="svg-icon:send" />&nbsp;抄送 </div> <el-popover
:visible="popOverVisible.copy"
placement="top-start"
:width="420"
trigger="click"
v-if="isShowButton(OperationButtonType.COPY)"
>
<template #reference>
<div @click="openPopover('copy')" class="hover-bg-gray-100 rounded-xl p-6px" >
<Icon :size="14" icon="svg-icon:send" />&nbsp;
{{ getButtonDisplayName(OperationButtonType.COPY) }}
</div>
</template>
<div class="flex flex-col flex-1 pt-20px px-20px" v-loading="formLoading">
<el-form
label-position="top"
class="mb-auto"
ref="formRef"
:model="genericForm"
:rules="genericRule"
label-width="100px"
>
<el-form-item label="抄送人" prop="copyUserIds">
<el-select v-model="genericForm.copyUserIds" clearable style="width: 100%" multiple placeholder="请选择抄送人">
<el-option
v-for="item in userOptions"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="抄送意见" prop="copyReason">
<el-input v-model="genericForm.copyReason" clearable placeholder="请输入抄送意见" type="textarea" :rows="3" />
</el-form-item>
<el-form-item>
<el-button :disabled="formLoading" type="primary" @click="handleCopy">
{{ getButtonDisplayName(OperationButtonType.COPY) }}
</el-button>
<el-button @click="popOverVisible.copy = false"> 取消 </el-button>
</el-form-item>
</el-form>
</div>
</el-popover>
<!-- 转交按钮 --> <!-- 转交按钮 -->
<div @click="openTaskUpdateAssigneeForm" v-if="isShowButton(OperationButtonType.TRANSFER)"> <el-popover
:visible="popOverVisible.transfer"
placement="top-start"
:width="420"
trigger="click"
v-if="isShowButton(OperationButtonType.TRANSFER)"
>
<template #reference>
<div @click="openPopover('transfer')" class="hover-bg-gray-100 rounded-xl p-6px" >
<Icon :size="14" icon="fa:share-square-o" />&nbsp; <Icon :size="14" icon="fa:share-square-o" />&nbsp;
{{ getButtonDisplayName(OperationButtonType.TRANSFER) }} {{ getButtonDisplayName(OperationButtonType.TRANSFER) }}
</div> </div>
</template>
<div class="flex flex-col flex-1 pt-20px px-20px" v-loading="formLoading">
<el-form
label-position="top"
class="mb-auto"
ref="formRef"
:model="genericForm"
:rules="genericRule"
label-width="100px"
>
<!-- 委托按钮 --> <el-form-item label="新审批人" prop="assigneeUserId">
<div @click="handleDelegate" v-if="isShowButton(OperationButtonType.DELEGATE)"> <el-select v-model="genericForm.assigneeUserId" clearable style="width: 100%">
<el-option
v-for="item in userOptions"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="审批意见" prop="reason">
<el-input v-model="genericForm.reason" clearable placeholder="请输入审批意见" type="textarea" :rows="3" />
</el-form-item>
<el-form-item>
<el-button :disabled="formLoading" type="primary" @click="handleTransfer()">
{{ getButtonDisplayName(OperationButtonType.TRANSFER) }}
</el-button>
<el-button @click="popOverVisible.transfer = false"> 取消 </el-button>
</el-form-item>
</el-form>
</div>
</el-popover>
<!-- 委派按钮 -->
<el-popover
:visible="popOverVisible.delegate"
placement="top-start"
:width="420"
trigger="click"
v-if="isShowButton(OperationButtonType.DELEGATE)"
>
<template #reference>
<div @click="openPopover('delegate')" class="hover-bg-gray-100 rounded-xl p-6px" >
<Icon :size="14" icon="ep:position" />&nbsp; <Icon :size="14" icon="ep:position" />&nbsp;
{{ getButtonDisplayName(OperationButtonType.DELEGATE) }} {{ getButtonDisplayName(OperationButtonType.DELEGATE) }}
</div> </div>
</template>
<!-- 加签 --> <div class="flex flex-col flex-1 pt-20px px-20px" v-loading="formLoading">
<div @click="handleSign" v-if="isShowButton(OperationButtonType.ADD_SIGN)"> <el-form
label-position="top"
class="mb-auto"
ref="formRef"
:model="genericForm"
:rules="genericRule"
label-width="100px"
>
<el-form-item label="接收人" prop="delegateUserId">
<el-select v-model="genericForm.delegateUserId" clearable style="width: 100%">
<el-option
v-for="item in userOptions"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="审批意见" prop="reason">
<el-input v-model="genericForm.reason" clearable placeholder="请输入审批意见" type="textarea" :rows="3" />
</el-form-item>
<el-form-item>
<el-button :disabled="formLoading" type="primary" @click="handleDelegate()">
{{ getButtonDisplayName(OperationButtonType.DELEGATE) }}
</el-button>
<el-button @click="popOverVisible.delegate = false"> 取消 </el-button>
</el-form-item>
</el-form>
</div>
</el-popover>
<!-- 加签按钮 当前任务审批人为A向前加签选了一个C则需要C先审批然后再是A审批向后加签BA审批完需要B再审批完才算完成这个任务节点 -->
<el-popover
:visible="popOverVisible.addSign"
placement="top-start"
:width="420"
trigger="click"
v-if="isShowButton(OperationButtonType.ADD_SIGN)"
>
<template #reference>
<div @click="openPopover('addSign')" class="hover-bg-gray-100 rounded-xl p-6px" >
<Icon :size="14" icon="ep:plus" />&nbsp; <Icon :size="14" icon="ep:plus" />&nbsp;
{{ getButtonDisplayName(OperationButtonType.ADD_SIGN) }} {{ getButtonDisplayName(OperationButtonType.ADD_SIGN) }}
</div> </div>
<!-- TODO @jason减签 --> </template>
<div class="flex flex-col flex-1 pt-20px px-20px" v-loading="formLoading">
<el-form
label-position="top"
class="mb-auto"
ref="formRef"
:model="genericForm"
:rules="genericRule"
label-width="100px"
>
<el-form-item label="加签处理人" prop="addSignUserIds">
<el-select v-model="genericForm.addSignUserIds" multiple clearable style="width: 100%">
<el-option
v-for="item in userOptions"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="审批意见" prop="reason">
<el-input v-model="genericForm.reason" clearable placeholder="请输入审批意见" type="textarea" :rows="3" />
</el-form-item>
<el-form-item>
<el-button :disabled="formLoading" type="primary" @click="handlerAddSign('before')">
向前{{ getButtonDisplayName(OperationButtonType.ADD_SIGN) }}
</el-button>
<el-button :disabled="formLoading" type="primary" @click="handlerAddSign('after')">
向后{{ getButtonDisplayName(OperationButtonType.ADD_SIGN) }}
</el-button>
<el-button @click="popOverVisible.addSign = false"> 取消 </el-button>
</el-form-item>
</el-form>
</div>
</el-popover>
<!-- TODO @jason减签 -->
<!-- 退回按钮 --> <!-- 退回按钮 -->
<div @click="handleBack" v-if="isShowButton(OperationButtonType.RETURN)"> <el-popover
:visible="popOverVisible.return"
placement="top-start"
:width="420"
trigger="click"
v-if="isShowButton(OperationButtonType.RETURN)"
>
<template #reference>
<div @click="openReturnPopover" class="hover-bg-gray-100 rounded-xl p-6px" >
<Icon :size="14" icon="fa:mail-reply" />&nbsp; <Icon :size="14" icon="fa:mail-reply" />&nbsp;
{{ getButtonDisplayName(OperationButtonType.RETURN) }} {{ getButtonDisplayName(OperationButtonType.RETURN) }}
</div> </div>
</template>
<div class="flex flex-col flex-1 pt-20px px-20px" v-loading="formLoading">
<el-form
label-position="top"
class="mb-auto"
ref="formRef"
:model="genericForm"
:rules="genericRule"
label-width="100px"
>
<el-form-item label="退回节点" prop="targetTaskDefinitionKey">
<el-select v-model="genericForm.targetTaskDefinitionKey" clearable style="width: 100%">
<el-option
v-for="item in returnList"
:key="item.taskDefinitionKey"
:label="item.name"
:value="item.taskDefinitionKey"
/>
</el-select>
</el-form-item>
<el-form-item label="退回理由" prop="returnReason">
<el-input v-model="genericForm.returnReason" clearable placeholder="请输入退回理由" type="textarea" :rows="3" />
</el-form-item>
<el-form-item>
<el-button :disabled="formLoading" type="primary" @click="handleReturn()">
{{ getButtonDisplayName(OperationButtonType.RETURN) }}
</el-button>
<el-button @click="popOverVisible.return = false"> 取消 </el-button>
</el-form-item>
</el-form>
</div>
</el-popover>
<!--TODO @jason撤回 --> <!--TODO @jason撤回 -->
<!--TODO @jason再次发起 --> <!--TODO @jason再次发起 -->
</div> </div>
<!-- 弹窗转派审批人 -->
<TaskTransferForm ref="taskTransferFormRef" @success="getDetail" />
<!-- 弹窗回退节点 -->
<TaskReturnForm ref="taskReturnFormRef" @success="getDetail" />
<!-- 弹窗委派将任务委派给别人处理处理完成后会重新回到原审批人手中-->
<TaskDelegateForm ref="taskDelegateForm" @success="getDetail" />
<!-- 弹窗加签当前任务审批人为A向前加签选了一个C则需要C先审批然后再是A审批向后加签BA审批完需要B再审批完才算完成这个任务节点 -->
<TaskSignCreateForm ref="taskSignCreateFormRef" @success="getDetail" />
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { setConfAndFields2 } from '@/utils/formCreate' import { setConfAndFields2 } from '@/utils/formCreate'
import { useUserStore } from '@/store/modules/user' import { useUserStore } from '@/store/modules/user'
import * as TaskApi from '@/api/bpm/task' import * as TaskApi from '@/api/bpm/task'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import TaskReturnForm from './dialog/TaskReturnForm.vue'
import TaskDelegateForm from './dialog/TaskDelegateForm.vue'
import TaskTransferForm from './dialog/TaskTransferForm.vue'
import TaskSignCreateForm from './dialog/TaskSignCreateForm.vue'
import { isEmpty } from '@/utils/is' import { isEmpty } from '@/utils/is'
import { import {
OperationButtonType, OperationButtonType,
@ -197,16 +367,32 @@ defineProps({
userOptions: propTypes.any userOptions: propTypes.any
}) })
const formLoading = ref(false) // const formLoading = ref(false) //
const passVisible = ref(false) // /** 气泡卡是否展示 */
const rejectVisible = ref(false) // const popOverVisible = ref({
approve: false,
reject: false,
transfer: false,
delegate: false,
addSign: false,
return : false,
copy: false
})
/** 退回节点 */
const returnList = ref([] as any)
// ========== ========== // ========== ==========
const runningTask = ref<any>({}) // const runningTask = ref<any>({}) //
const auditForm = ref<any>({}) // const genericForm = ref<any>({}) //
const approveForm = ref<any>({}) // const approveForm = ref<any>({}) //
const approveFormFApi = ref<any>({}) // approveForms fAPi const approveFormFApi = ref<any>({}) // approveForms fAPi
const formRef = ref() const formRef = ref()
const auditRule = reactive({ /** 表单校验规则 */
reason: [{ required: true, message: '审批建议不能为空', trigger: 'blur' }] const genericRule = reactive({
reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }],
returnReason: [{ required: true, message: '退回理由不能为空', trigger: 'blur' }],
copyUserIds: [{ required: true, message: '抄送人不能为空', trigger: 'change' }],
assigneeUserId:[{ required: true, message: '新审批人不能为空', trigger: 'change' }],
delegateUserId: [{ required: true, message: '接收人不能为空', trigger: 'change' }],
addSignUserIds: [{ required: true, message: '加签处理人不能为空', trigger: 'change' }]
}) })
/** 监听 approveFormFApis实现它对应的 form-create 初始化后,隐藏掉对应的表单提交按钮 */ /** 监听 approveFormFApis实现它对应的 form-create 初始化后,隐藏掉对应的表单提交按钮 */
@ -227,7 +413,7 @@ watch(
*/ */
const loadRunningTask = (tasks: any[]) => { const loadRunningTask = (tasks: any[]) => {
runningTask.value = {} runningTask.value = {}
auditForm.value = {} genericForm.value = {}
approveForm.value = {} approveForm.value = {}
approveFormFApi.value = {} approveFormFApi.value = {}
tasks.forEach((task: any) => { tasks.forEach((task: any) => {
@ -244,7 +430,7 @@ const loadRunningTask = (tasks: any[]) => {
} }
// 2.3 // 2.3
runningTask.value = { ...task } runningTask.value = { ...task }
auditForm.value = { genericForm.value = {
reason: '', reason: '',
copyUserIds: [] copyUserIds: []
} }
@ -261,12 +447,12 @@ const loadRunningTask = (tasks: any[]) => {
} }
/** 处理审批通过和不通过的操作 */ /** 处理审批通过和不通过的操作 */
const handleAudit = async (pass: any) => { const handleAudit = async (pass: boolean) => {
formLoading.value = true formLoading.value = true
try { try {
const auditFormRef = proxy.$refs['formRef'] const genericFormRef = proxy.$refs['formRef']
// 1.2 // 1.2
const elForm = unref(auditFormRef) const elForm = unref(genericFormRef)
if (!elForm) return if (!elForm) return
const valid = await elForm.validate() const valid = await elForm.validate()
if (!valid) return if (!valid) return
@ -274,8 +460,7 @@ const handleAudit = async (pass: any) => {
// 2.1 // 2.1
const data = { const data = {
id: runningTask.value.id, id: runningTask.value.id,
reason: auditForm.value.reason, reason: genericForm.value.reason
copyUserIds: auditForm.value.copyUserIds
} }
if (pass) { if (pass) {
// approveForm + data // approveForm + data
@ -286,9 +471,11 @@ const handleAudit = async (pass: any) => {
data.variables = approveForm.value.value data.variables = approveForm.value.value
} }
await TaskApi.approveTask(data) await TaskApi.approveTask(data)
popOverVisible.value.approve = false
message.success('审批通过成功') message.success('审批通过成功')
} else { } else {
await TaskApi.rejectTask(data) await TaskApi.rejectTask(data)
popOverVisible.value.reject = false
message.success('审批不通过成功') message.success('审批不通过成功')
} }
// 2.2 // 2.2
@ -298,40 +485,160 @@ const handleAudit = async (pass: any) => {
} }
} }
/* 抄送 TODO */ /* 处理抄送 */
const handleSend = () => {} const handleCopy = async () => {
formLoading.value = true
// TODO flag approve: boolean flag 1 2 try {
const openPopover = (flag) => { const copyFormRef = proxy.$refs['formRef']
passVisible.value = false // 1.
rejectVisible.value = false const elForm = unref(copyFormRef)
formRef.value.resetFields() if (!elForm) return
flag === '1' ? (passVisible.value = true) : (rejectVisible.value = true) const valid = await elForm.validate()
if (!valid) return
// 2.
const data = {
id: runningTask.value.id,
reason: genericForm.value.copyReason,
copyUserIds: genericForm.value.copyUserIds
}
await TaskApi.copyTask(data)
popOverVisible.value.copy = false
message.success('操作成功')
} finally {
formLoading.value = false
}
} }
/** 转派审批人 */ /** 处理转交 */
const taskTransferFormRef = ref() const handleTransfer = async () => {
const openTaskUpdateAssigneeForm = () => {
taskTransferFormRef.value.open(runningTask.value.id) formLoading.value = true
try {
const transferFormRef = proxy.$refs['formRef']
// 1.1
const elForm = unref(transferFormRef)
if (!elForm) return
const valid = await elForm.validate()
if (!valid) return
// 1.2
const data = {
id: runningTask.value.id,
reason: genericForm.value.reason,
assigneeUserId: genericForm.value.assigneeUserId
}
await TaskApi.transferTask(data)
popOverVisible.value.transfer = false
message.success('操作成功')
// 2.
getDetail()
} finally {
formLoading.value = false
}
} }
/** 处理审批退回的操作 */ /** 处理委派 */
const taskDelegateForm = ref()
const handleDelegate = async () => { const handleDelegate = async () => {
taskDelegateForm.value.open(runningTask.value.id) formLoading.value = true
try {
const deletegateFormRef = proxy.$refs['formRef']
// 1.1
const elForm = unref(deletegateFormRef)
if (!elForm) return
const valid = await elForm.validate()
if (!valid) return
// 1.2
const data = {
id: runningTask.value.id,
reason: genericForm.value.reason,
delegateUserId: genericForm.value.delegateUserId
}
await TaskApi.delegateTask(data)
popOverVisible.value.delegate = false
message.success('操作成功')
// 2.
getDetail()
} finally {
formLoading.value = false
}
}
/** 处理加签 */
const handlerAddSign = async (type: string) => {
formLoading.value = true
try {
const transferFormRef = proxy.$refs['formRef']
// 1.1
const elForm = unref(transferFormRef)
if (!elForm) return
const valid = await elForm.validate()
if (!valid) return
// 1.2
const data = {
id: runningTask.value.id,
type,
reason: genericForm.value.reason,
userIds: genericForm.value.addSignUserIds
}
await TaskApi.signCreateTask(data)
message.success('操作成功')
popOverVisible.value.addSign = false
// 2
getDetail()
} finally {
formLoading.value = false
}
} }
/** 处理审批退回的操作 */ /** 处理退回 */
const taskReturnFormRef = ref() const handleReturn = async () => {
const handleBack = async () => { formLoading.value = true
taskReturnFormRef.value.open(runningTask.value.id) try {
const returnFormRef = proxy.$refs['formRef']
// 1.1
const elForm = unref(returnFormRef)
if (!elForm) return
const valid = await elForm.validate()
if (!valid) return
// 1.2 退
const data = {
id: runningTask.value.id,
reason: genericForm.value.returnReason,
targetTaskDefinitionKey: genericForm.value.targetTaskDefinitionKey
}
await TaskApi.returnTask(data)
popOverVisible.value.return = false
message.success('操作成功')
// 2
getDetail()
} finally {
formLoading.value = false
}
} }
/** 处理审批加签的操作 */ /** 弹出退回气泡卡 */
const taskSignCreateFormRef = ref() const openReturnPopover = async () => {
const handleSign = async () => { returnList.value = await TaskApi.getTaskListByReturn(runningTask.value.id)
taskSignCreateFormRef.value.open(runningTask.value.id) if (returnList.value.length === 0) {
message.warning('当前没有可退回的节点')
return
}
openPopover('return')
} }
/** 弹出气泡卡 */
const openPopover = (type: string ) => {
Object.keys(popOverVisible.value).forEach( item => {
if( item === type) {
popOverVisible.value[item] = true
} else {
popOverVisible.value[item] = false
}
})
formRef.value.resetFields()
}
/** 获得详情 */ /** 获得详情 */
const getDetail = () => { const getDetail = () => {
emit('success') emit('success')

View File

@ -14,7 +14,7 @@
<div class="flex items-center mt-1"> <div class="flex items-center mt-1">
<!-- 情况一遍历每个审批节点下的进行中task 任务 --> <!-- 情况一遍历每个审批节点下的进行中task 任务 -->
<div v-for="(task, idx) in activity.tasks" :key="idx" class="flex items-center"> <div v-for="(task, idx) in activity.tasks" :key="idx" class="flex items-center">
<div class="flex items-center flex-col pr-2"> <div class="flex flex-col pr-2">
<div class="position-relative" v-if="task.assigneeUser || task.ownerUser"> <div class="position-relative" v-if="task.assigneeUser || task.ownerUser">
<!-- 信息头像 --> <!-- 信息头像 -->
<el-avatar <el-avatar
@ -47,7 +47,7 @@
<!-- 信息昵称 --> <!-- 信息昵称 -->
<div <div
v-if="task.assigneeUser && task.assigneeUser.nickname" v-if="task.assigneeUser && task.assigneeUser.nickname"
class="text-10px text-align-center" class="text-12px text-align-center"
> >
{{ task.assigneeUser.nickname }} {{ task.assigneeUser.nickname }}
</div> </div>
@ -57,14 +57,20 @@
> >
{{ task.ownerUser.nickname }} {{ task.ownerUser.nickname }}
</div> </div>
<!-- TODO @jason审批意见要展示哈 --> <div v-if="task.reason" class="text-#a5a5a5 my-4px text-12px flex items-center w-100%">
<!-- <div v-if="task.reason" :title="task.reason" class="text-13px text-truncate w-150px mt-1"> : {{ task.reason }}</div> --> <div
:title="task.reason"
class="text-truncate w-200px border-1px border-#a5a5a5 border-dashed rounded py-5px px-15px text-#2d2d2d"
>
{{ task.reason }}
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
<!-- 情况二遍历每个审批节点下的候选的task 任务例如说1依次审批2未来的审批任务等 --> <!-- 情况二遍历每个审批节点下的候选的task 任务例如说1依次审批2未来的审批任务等 -->
<div <div
v-for="(user, idx1) in activity.candidateUserList" v-for="(user, idx1) in activity.candidateUsers"
:key="idx1" :key="idx1"
class="flex items-center" class="flex items-center"
> >
@ -91,7 +97,6 @@
<div v-if="user.nickname" class="text-10px text-align-center"> <div v-if="user.nickname" class="text-10px text-align-center">
{{ user.nickname }} {{ user.nickname }}
</div> </div>
<!-- <div v-if="task.reason" :title="task.reason" class="text-13px text-truncate w-150px mt-1"> : {{ task.reason }}</div> -->
</div> </div>
</div> </div>
</div> </div>

View File

@ -12,25 +12,37 @@
<el-divider class="!my-8px" /> <el-divider class="!my-8px" />
<div class="flex items-center gap-5 mb-10px h-40px"> <div class="flex items-center gap-5 mb-10px h-40px">
<div class="text-26px font-bold mb-5px">{{ processInstance.name }}</div> <div class="text-26px font-bold mb-5px">{{ processInstance.name }}</div>
<dict-tag :type="DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS" :value="processInstance.status" /> <dict-tag
v-if="processInstance.status"
:type="DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS"
:value="processInstance.status"
/>
</div> </div>
<div class="flex items-center gap-5 mb-10px text-13px h-35px"> <div class="flex items-center gap-5 mb-10px text-13px h-35px">
<div <div
class="bg-gray-100 h-35px rounded-3xl flex items-center p-8px gap-2 dark:color-gray-600" class="bg-gray-100 h-35px rounded-3xl flex items-center p-8px gap-2 dark:color-gray-600"
> >
<img class="rounded-full h-28px" src="@/assets/imgs/avatar.jpg" alt="" /> <!-- <img class="rounded-full h-28px" src="@/assets/imgs/avatar.jpg" alt="" /> -->
<el-avatar
:size="28"
v-if="processInstance?.startUser?.avatar"
:src="processInstance?.startUser?.avatar"
/>
<el-avatar :size="28" v-else-if="processInstance?.startUser?.nickname">
{{ processInstance?.startUser?.nickname.substring(0, 1) }}
</el-avatar>
{{ processInstance?.startUser?.nickname }} {{ processInstance?.startUser?.nickname }}
</div> </div>
<div class="text-#878c93"> {{ formatDate(processInstance.startTime) }} 提交 </div> <div class="text-#878c93"> {{ formatDate(processInstance.startTime) }} 提交 </div>
</div> </div>
<el-tabs v-model="activeTab"> <el-tabs v-model="activeTab" @tab-change="onTabChange">
<!-- 表单信息 --> <!-- 表单信息 -->
<el-tab-pane label="审批详情" name="form"> <el-tab-pane label="审批详情" name="form">
<div class="form-scroll-area"> <div class="form-scroll-area">
<el-scrollbar> <el-scrollbar>
<el-row :gutter="10"> <el-row>
<el-col :span="18" class="!flex !flex-col formCol"> <el-col :span="18" class="!flex !flex-col formCol">
<!-- 表单信息 --> <!-- 表单信息 -->
<div <div
@ -38,11 +50,7 @@
class="form-box flex flex-col mb-30px flex-1" class="form-box flex flex-col mb-30px flex-1"
> >
<!-- 情况一流程表单 --> <!-- 情况一流程表单 -->
<el-col <el-col v-if="processInstance?.processDefinition?.formType === 10">
v-if="processInstance?.processDefinition?.formType === 10"
:offset="6"
:span="16"
>
<form-create <form-create
v-model="detailForm.value" v-model="detailForm.value"
v-model:api="fApi" v-model:api="fApi"
@ -64,27 +72,36 @@
</el-scrollbar> </el-scrollbar>
</div> </div>
</el-tab-pane> </el-tab-pane>
<!-- 流程图 --> <!-- 流程图 -->
<el-tab-pane label="流程图" name="diagram"> <el-tab-pane label="流程图" name="diagram">
<div class="form-scroll-area">
<ProcessInstanceBpmnViewer :id="`${id}`" :loading="processInstanceLoading" /> <ProcessInstanceBpmnViewer :id="`${id}`" :loading="processInstanceLoading" />
</div>
</el-tab-pane> </el-tab-pane>
<!-- 流转记录 --> <!-- 流转记录 -->
<el-tab-pane label="流转记录" name="record"> <el-tab-pane label="流转记录" name="record">
<div class="form-scroll-area">
<el-scrollbar>
<ProcessInstanceTaskList <ProcessInstanceTaskList
:loading="tasksLoad" :loading="tasksLoad"
:process-instance="processInstance" :process-instance="processInstance"
:tasks="tasks" :tasks="tasks"
@refresh="getTaskList"
/> />
</el-scrollbar>
</div>
</el-tab-pane> </el-tab-pane>
<!-- 流转评论 TODO 待开发 --> <!-- 流转评论 TODO 待开发 -->
<el-tab-pane label="流转评论" name="comment"> 流转评论 </el-tab-pane> <el-tab-pane label="流转评论" name="comment">
<div class="form-scroll-area">
<el-scrollbar> 流转评论 </el-scrollbar>
</div>
</el-tab-pane>
</el-tabs> </el-tabs>
<div <div class="b-t-solid border-t-1px border-[var(--el-border-color)]">
class="b-t-solid border-t-1px border-[var(--el-border-color)]"
v-if="activeTab === 'form'"
>
<!-- 操作栏按钮 --> <!-- 操作栏按钮 -->
<ProcessInstanceOperationButton <ProcessInstanceOperationButton
ref="operationButtonRef" ref="operationButtonRef"
@ -125,6 +142,7 @@ const props = defineProps<{
const message = useMessage() // const message = useMessage() //
const processInstanceLoading = ref(false) // const processInstanceLoading = ref(false) //
const processInstance = ref<any>({}) // const processInstance = ref<any>({}) //
let processDefinitionId = undefined // Id
const operationButtonRef = ref() const operationButtonRef = ref()
const timelineRef = ref() const timelineRef = ref()
const bpmnXml = ref('') // BPMN XML const bpmnXml = ref('') // BPMN XML
@ -145,10 +163,10 @@ const detailForm = ref({
}) // }) //
/** 获得详情 */ /** 获得详情 */
const getDetail = () => { const getDetail = async () => {
// 1. // 1.
getProcessInstance() getProcessInstance()
// 2. // 2.
getTaskList() getTaskList()
} }
@ -176,12 +194,18 @@ const getProcessInstance = async () => {
activityId: props.activityId activityId: props.activityId
}) })
} }
if (detailForm.value.rule.length > 0) { // form-create
detailForm.value.value = data.formVariables
} else {
setConfAndFields2( setConfAndFields2(
detailForm, detailForm,
processDefinition.formConf, processDefinition.formConf,
processDefinition.formFields, processDefinition.formFields,
data.formVariables data.formVariables
) )
}
nextTick().then(() => { nextTick().then(() => {
fApi.value?.btn.show(false) fApi.value?.btn.show(false)
fApi.value?.resetBtn.show(false) fApi.value?.resetBtn.show(false)
@ -196,9 +220,9 @@ const getProcessInstance = async () => {
// data.processDefinition.formCustomViewPath /crm/contract/detail/index.vue // data.processDefinition.formCustomViewPath /crm/contract/detail/index.vue
BusinessFormComponent.value = registerComponent(data.processDefinition.formCustomViewPath) BusinessFormComponent.value = registerComponent(data.processDefinition.formCustomViewPath)
} }
processDefinitionId = processDefinition.id
// //
bpmnXml.value = (await DefinitionApi.getProcessDefinition(processDefinition.id))?.bpmnXml // bpmnXml.value = (await DefinitionApi.getProcessDefinition(processDefinition.id))?.bpmnXml
} finally { } finally {
processInstanceLoading.value = false processInstanceLoading.value = false
} }
@ -267,6 +291,13 @@ const refresh = () => {
/** 当前的Tab */ /** 当前的Tab */
const activeTab = ref('form') const activeTab = ref('form')
/** Tab 切换 加载流程图,直接加载显示不出来,不知道啥原因,所以切换以后在加载 */
const onTabChange = async (tabName: string) => {
if (tabName === 'diagram' && processDefinitionId && !bpmnXml.value) {
//
bpmnXml.value = (await DefinitionApi.getProcessDefinition(processDefinitionId))?.bpmnXml
}
}
/** 初始化 */ /** 初始化 */
const userOptions = ref<UserApi.UserVO[]>([]) // const userOptions = ref<UserApi.UserVO[]>([]) //
onMounted(async () => { onMounted(async () => {

View File

@ -55,6 +55,7 @@
/> />
<el-table-column align="center" label="抄送任务" prop="taskName" min-width="180" /> <el-table-column align="center" label="抄送任务" prop="taskName" min-width="180" />
<el-table-column align="center" label="抄送人" prop="creatorName" min-width="100" /> <el-table-column align="center" label="抄送人" prop="creatorName" min-width="100" />
<el-table-column align="center" label="抄送意见" prop="reason" width="150" />
<el-table-column <el-table-column
align="center" align="center"
label="抄送时间" label="抄送时间"