From 130ee1dcecd7eacaf4197a531b7d1a49a90c078a Mon Sep 17 00:00:00 2001
From: AN <1983933789@qq.com>
Date: Mon, 14 Jul 2025 22:29:59 +0800
Subject: [PATCH] =?UTF-8?q?feat(projects):=20=E6=96=B0=E5=A2=9E=E6=88=91?=
=?UTF-8?q?=E7=9A=84=E5=BE=85=E5=8A=9E=E5=8A=9F=E8=83=BD,=E6=96=B0?=
=?UTF-8?q?=E5=A2=9E=E5=AE=A1=E6=89=B9,=E9=A9=B3=E5=9B=9E=E7=BB=84?=
=?UTF-8?q?=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/components/custom/user-select-modal.vue | 4 +
.../custom/workflow/back-task-modal.vue | 142 +++++++++++
.../custom/workflow/flow-intervene-modal.vue | 17 +-
.../workflow/flow-task-approval-modal.vue | 224 ++++++++++++++++--
...-drawer.vue => reduce-signature-modal.vue} | 6 +-
src/service/api/workflow/task.ts | 19 +-
src/typings/api/workflow.api.d.ts | 13 +-
src/typings/components.d.ts | 3 +-
8 files changed, 389 insertions(+), 39 deletions(-)
create mode 100644 src/components/custom/workflow/back-task-modal.vue
rename src/components/custom/workflow/{reduce-signature-drawer.vue => reduce-signature-modal.vue} (96%)
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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('common.cancel') }}
+ {{ $t('common.confirm') }}
+
+
+
+
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, () => {
-
+
-
- 取消
- 提交
-
+
+
+ {{ $t('common.cancel') }}
+
+
+ 委托
+
+
+
+ 转办
+
+
+
+ 加签
+
+
+
+ 减签
+
+
+
+ 终止
+
+
+
+ 驳回
+
+ 提交
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
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']