diff --git a/src/components/custom/user-select-modal.vue b/src/components/custom/user-select-modal.vue index e7f80cc3..feda03f5 100644 --- a/src/components/custom/user-select-modal.vue +++ b/src/components/custom/user-select-modal.vue @@ -192,6 +192,10 @@ function closeModal() { } function handleConfirm() { + if (checkedRowKeys.value.length === 0) { + window.$message?.error('请选择用户'); + return; + } // 获取选中行对应的用户对象(从所有页面数据中筛选) const selectedUsers = allPagesData.value.filter(item => checkedRowKeys.value.includes(item.userId.toString())); emit('confirm', checkedRowKeys.value, selectedUsers); diff --git a/src/components/custom/workflow/back-task-modal.vue b/src/components/custom/workflow/back-task-modal.vue new file mode 100644 index 00000000..79103228 --- /dev/null +++ b/src/components/custom/workflow/back-task-modal.vue @@ -0,0 +1,142 @@ + + + diff --git a/src/components/custom/workflow/flow-intervene-modal.vue b/src/components/custom/workflow/flow-intervene-modal.vue index c878ace5..37f3b401 100644 --- a/src/components/custom/workflow/flow-intervene-modal.vue +++ b/src/components/custom/workflow/flow-intervene-modal.vue @@ -2,6 +2,7 @@ import { computed, reactive, ref, watch } from 'vue'; import { useBoolean, useLoading } from '@sa/hooks'; import { fetchGetTask, fetchTaskOperate, fetchTerminateTask } from '@/service/api/workflow/task'; +import ReduceSignatureModal from './reduce-signature-modal.vue'; defineOptions({ name: 'FlowInterveneModal' @@ -59,10 +60,6 @@ function createDefaultTerminateModel(): TerminateModel { } function handleTransferConfirm(ids: CommonType.IdType[]) { - if (ids.length === 0) { - window.$message?.error('请选择转办用户'); - return; - } model.userId = ids[0]; model.taskId = props.taskId; window.$dialog?.warning({ @@ -84,10 +81,6 @@ function handleTransferConfirm(ids: CommonType.IdType[]) { } function handleAddSignatureConfirm(ids: CommonType.IdType[]) { - if (ids.length === 0) { - window.$message?.error('请选择加签用户'); - return; - } model.userIds = ids; window.$dialog?.warning({ title: '提示', @@ -111,7 +104,7 @@ function handleTerminate() { terminateModel.taskId = props.taskId; window.$dialog?.warning({ title: '提示', - content: '是否确认中止?', + content: '是否确认终止?', positiveText: '确认', positiveButtonProps: { type: 'primary' @@ -120,7 +113,7 @@ function handleTerminate() { onPositiveClick: async () => { const { error } = await fetchTerminateTask(terminateModel); if (error) return; - window.$message?.success('中止成功'); + window.$message?.success('终止成功'); visible.value = false; emit('refresh'); } @@ -189,7 +182,7 @@ watch(visible, () => { 减签 - 中止 + 终止 @@ -202,7 +195,7 @@ watch(visible, () => { @confirm="handleAddSignatureConfirm" /> - -import { reactive, ref, watch } from 'vue'; +import { computed, reactive, ref, watch } from 'vue'; import type { UploadFileInfo } from 'naive-ui'; import { useBoolean, useLoading } from '@sa/hooks'; import { messageTypeOptions } from '@/constants/workflow'; -import { fetchCompleteTask, fetchGetTask, fetchGetkNextNode } from '@/service/api/workflow'; +import { + fetchCompleteTask, + fetchGetTask, + fetchGetkNextNode, + fetchTaskOperate, + fetchTerminateTask +} from '@/service/api/workflow'; import FileUpload from '@/components/custom/file-upload.vue'; +import ReduceSignatureModal from './reduce-signature-modal.vue'; +import BackTaskModal from './back-task-modal.vue'; defineOptions({ name: 'FlowTaskApprovalModal' }); interface Props { - /** the task id */ + /** 任务id */ taskId: CommonType.IdType; - /** the task variables */ + /** 任务变量 */ taskVariables: { [key: string]: any }; } @@ -32,6 +40,11 @@ const { loading: baseFormLoading, startLoading: startBaseFormLoading, endLoading const { loading: btnLoading, startLoading: startBtnLoading, endLoading: endBtnLoading } = useLoading(); const { bool: copyVisible, setTrue: openCopyModal } = useBoolean(); const { bool: assigneeVisible, setTrue: openAssigneeModal } = useBoolean(); +const { bool: delegateVisible, setTrue: openDelegateModal, setFalse: closeDelegateModal } = useBoolean(); +const { bool: transferVisible, setTrue: openTransferModal, setFalse: closeTransferModal } = useBoolean(); +const { bool: addSignatureVisible, setTrue: openAddSignatureModal, setFalse: closeAddSignatureModal } = useBoolean(); +const { bool: reduceSignatureVisible, setTrue: openReduceSignatureModal } = useBoolean(); +const { bool: backVisible, setTrue: openBackModal } = useBoolean(); const title = defineModel('title', { default: '流程发起' }); @@ -42,6 +55,8 @@ type Model = Api.Workflow.CompleteTaskOperateParams; const task = ref(); +const isWaiting = computed(() => task.value?.flowStatus === 'waiting'); + const model: Model = reactive(createDefaultModel()); function createDefaultModel(): Model { @@ -119,19 +134,18 @@ async function getTask() { } task.value = data; task.value.buttonList.forEach(item => { - buttonPerm[item.code as keyof ButtonPerm] = !item.show; + buttonPerm[item.code as keyof ButtonPerm] = item.show!; }); endBtnLoading(); const { error: nextNodeError, data: nextNodeData } = await fetchGetkNextNode({ taskId: props.taskId, taskVariables: props.taskVariables }); + endBaseFormLoading(); if (nextNodeError) { - endBaseFormLoading(); return; } nestNodeList.value = nextNodeData; - endBaseFormLoading(); } async function handleSubmit() { @@ -231,6 +245,118 @@ function handleAssigneeTagClose(code: string, index?: number) { } } +interface TaskOperationOptions { + userIds: CommonType.IdType[]; + operation: 'delegateTask' | 'transferTask' | 'addSignature'; + confirmText: string; + successMessage: string; + closeModal: () => void; +} + +function handleTaskOperationConfirm(options: TaskOperationOptions) { + const { userIds, operation, confirmText, successMessage, closeModal } = options; + + const taskModel = { + taskId: props.taskId, + userId: userIds[0], + message: model.message + }; + + window.$dialog?.warning({ + title: '提示', + content: `是否确认${confirmText}?`, + positiveText: `确认${confirmText}`, + positiveButtonProps: { + type: 'primary' + }, + negativeText: '取消', + onPositiveClick: async () => { + startBtnLoading(); + startBaseFormLoading(); + const { error } = await fetchTaskOperate(taskModel, operation); + endBtnLoading(); + endBaseFormLoading(); + if (error) return; + window.$message?.success(successMessage); + closeModal(); + visible.value = false; + emit('finished'); + } + }); +} + +// 委托 +function handleDelegateConfirm(userIds: CommonType.IdType[]) { + handleTaskOperationConfirm({ + userIds, + operation: 'delegateTask', + confirmText: '委托', + successMessage: '委托成功', + closeModal: closeDelegateModal + }); +} + +// 转办 +function handleTransferConfirm(userIds: CommonType.IdType[]) { + handleTaskOperationConfirm({ + userIds, + operation: 'transferTask', + confirmText: '转办', + successMessage: '转办成功', + closeModal: closeTransferModal + }); +} + +// 加签 +function handleAddSignatureConfirm(userIds: CommonType.IdType[]) { + handleTaskOperationConfirm({ + userIds, + operation: 'addSignature', + confirmText: '加签', + successMessage: '加签成功', + closeModal: closeAddSignatureModal + }); +} + +// 减签 +function handleReduceSubmit() { + visible.value = false; + emit('finished'); +} + +// 终止 +function handleTerminate() { + const terminateModel = { + taskId: props.taskId, + comment: model.message + }; + window.$dialog?.warning({ + title: '提示', + content: '是否确认终止?', + positiveText: '确认', + positiveButtonProps: { + type: 'primary' + }, + negativeText: '取消', + onPositiveClick: async () => { + startBtnLoading(); + startBaseFormLoading(); + const { error } = await fetchTerminateTask(terminateModel); + endBtnLoading(); + endBaseFormLoading(); + if (error) return; + window.$message?.success('终止成功'); + visible.value = false; + emit('finished'); + } + }); +} + +function handleBackSubmit() { + visible.value = false; + emit('finished'); +} + watch(visible, () => { if (visible.value) { initDefault(); @@ -291,22 +417,80 @@ watch(visible, () => { - + -
- 取消 - 提交 -
+ + + + + + + + + + + + + + + - - diff --git a/src/components/custom/workflow/reduce-signature-drawer.vue b/src/components/custom/workflow/reduce-signature-modal.vue similarity index 96% rename from src/components/custom/workflow/reduce-signature-drawer.vue rename to src/components/custom/workflow/reduce-signature-modal.vue index 51fd064b..233f0699 100644 --- a/src/components/custom/workflow/reduce-signature-drawer.vue +++ b/src/components/custom/workflow/reduce-signature-modal.vue @@ -72,8 +72,8 @@ const columns = ref[]>([ text type="error" icon="material-symbols:delete-outline" - tooltipContent={$t('common.delete')} - popconfirmContent={$t('common.confirmDelete')} + tooltipContent={'减签'} + popconfirmContent={'是否确认减签?'} onPositiveClick={() => handleReduceSignature([row.userId])} /> ); @@ -128,7 +128,7 @@ watch(visible, async () => { - 删除 + 批量减签 ({ + return request({ url: '/workflow/task/completeTask', method: 'post', data @@ -55,7 +55,7 @@ export function fetchGetAllFinishedTask(data: Api.Workflow.TaskSearchParams) { /** 任务操作 */ export function fetchTaskOperate(data: Api.Workflow.TaskOperateParams, operateType: Api.Workflow.TaskOperateType) { - return request({ + return request({ url: `/workflow/task/taskOperation/${operateType}`, method: 'post', data @@ -87,3 +87,18 @@ export function fetchGetTaskWaitList(data: Api.Workflow.TaskSearchParams) { params: data }); } +/** 获取可驳回节点 */ +export function fetchGetBackNode(definitionId: CommonType.IdType, nodeCode: string) { + return request({ + url: `/workflow/task/getBackTaskNode/${definitionId}/${nodeCode}`, + method: 'get' + }); +} +/** 驳回任务 */ +export function fetchBackTask(data: Api.Workflow.BackOperateParams) { + return request({ + url: '/workflow/task/backProcess', + method: 'post', + data + }); +} diff --git a/src/typings/api/workflow.api.d.ts b/src/typings/api/workflow.api.d.ts index b7c60886..fa8f1c06 100644 --- a/src/typings/api/workflow.api.d.ts +++ b/src/typings/api/workflow.api.d.ts @@ -461,7 +461,7 @@ declare namespace Api { }>; /** 工作流节点 */ - type FlowNode = Common.CommonRecord<{ + type FlowNode = Common.CommonTenantRecord<{ /** 节点ID */ id: CommonType.IdType; /** 删除标志 */ @@ -502,5 +502,16 @@ declare namespace Api { /** 工作流节点列表 */ type FlowNodeList = FlowNode[]; + + /** 驳回操作参数 */ + type BackOperateParams = CommonType.RecordNullable<{ + taskId: CommonType.IdType; + fileId: CommonType.IdType; + messageType: string[]; + nodeCode: string; + message: string; + notice: string; + variables: { [key: string]: any }; + }>; } } diff --git a/src/typings/components.d.ts b/src/typings/components.d.ts index 3e48ee87..ddc0b483 100644 --- a/src/typings/components.d.ts +++ b/src/typings/components.d.ts @@ -10,6 +10,7 @@ declare module 'vue' { export interface GlobalComponents { AppProvider: typeof import('./../components/common/app-provider.vue')['default'] ApprovalInfoPanel: typeof import('./../components/custom/workflow/approval-info-panel.vue')['default'] + BackTaskModal: typeof import('./../components/custom/workflow/back-task-modal.vue')['default'] BetterScroll: typeof import('./../components/custom/better-scroll.vue')['default'] BooleanTag: typeof import('./../components/custom/boolean-tag.vue')['default'] ButtonIcon: typeof import('./../components/custom/button-icon.vue')['default'] @@ -145,7 +146,7 @@ declare module 'vue' { OssUpload: typeof import('./../components/custom/oss-upload.vue')['default'] PinToggler: typeof import('./../components/common/pin-toggler.vue')['default'] PostSelect: typeof import('./../components/custom/post-select.vue')['default'] - ReduceSignatureDrawer: typeof import('./../components/custom/workflow/reduce-signature-drawer.vue')['default'] + ReduceSignatureModal: typeof import('./../components/custom/workflow/reduce-signature-modal.vue')['default'] ReloadButton: typeof import('./../components/common/reload-button.vue')['default'] RoleSelect: typeof import('./../components/custom/role-select.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink']