update 优化warm-flow工作流模块

master
yinq 3 months ago
parent 1c1bc1e310
commit ea59268910

@ -47,6 +47,7 @@
"vue": "3.4.34", "vue": "3.4.34",
"vue-cropper": "1.1.1", "vue-cropper": "1.1.1",
"vue-i18n": "9.10.2", "vue-i18n": "9.10.2",
"vue-json-pretty": "2.4.0",
"vue-router": "4.3.2", "vue-router": "4.3.2",
"vue-types": "5.1.1", "vue-types": "5.1.1",
"vue3-seamless-scroll": "^3.0.2", "vue3-seamless-scroll": "^3.0.2",

@ -2,39 +2,63 @@
<div class="container"> <div class="container">
<el-dialog v-model="visible" draggable title="审批记录" :width="props.width" :height="props.height" :close-on-click-modal="false"> <el-dialog v-model="visible" draggable title="审批记录" :width="props.width" :height="props.height" :close-on-click-modal="false">
<el-tabs v-model="tabActiveName" class="demo-tabs"> <el-tabs v-model="tabActiveName" class="demo-tabs">
<el-tab-pane label="流程图" name="bpmn"> <el-tab-pane v-loading="loading" label="流程图" name="image" style="height: 68vh">
<BpmnView ref="bpmnViewRef"></BpmnView> <div
ref="imageWrapperRef"
class="image-wrapper"
@wheel="handleMouseWheel"
@mousedown="handleMouseDown"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"
@mouseleave="handleMouseLeave"
@dblclick="resetTransform"
:style="transformStyle"
>
<el-card class="box-card">
<el-image :src="imgUrl" class="scalable-image" />
</el-card>
</div>
</el-tab-pane> </el-tab-pane>
<el-tab-pane v-loading="loading" label="审批信息" name="info"> <el-tab-pane v-loading="loading" label="审批信息" name="info">
<div> <div>
<el-table :data="historyList" style="width: 100%" border fit> <el-table :data="historyList" style="width: 100%" border fit>
<el-table-column type="index" label="序号" align="center" width="60"></el-table-column> <el-table-column type="index" label="序号" align="center" width="60"></el-table-column>
<el-table-column prop="name" label="任务名称" sortable align="center"></el-table-column> <el-table-column prop="nodeName" label="任务名称" sortable align="center"></el-table-column>
<el-table-column prop="nickName" :show-overflow-tooltip="true" label="办理人" sortable align="center"> <el-table-column prop="approveName" :show-overflow-tooltip="true" label="办理人" sortable align="center">
<template #default="scope"> <template #default="scope">
<el-tag type="success">{{ scope.row.nickName || '无' }}</el-tag> <template v-if="scope.row.approveName">
<el-tag v-for="(item, index) in scope.row.approveName.split(',')" :key="index" type="success">{{ item }}</el-tag>
</template>
<template v-else> <el-tag type="success"></el-tag></template>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="状态" sortable align="center"> <el-table-column prop="flowStatus" label="状态" width="80" sortable align="center">
<template #default="scope"> <template #default="scope">
<el-tag type="success">{{ scope.row.statusName }}</el-tag> <dict-tag :options="wf_task_status" :value="scope.row.flowStatus"></dict-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="comment" label="审批意见" sortable align="center"></el-table-column> <el-table-column prop="message" label="审批意见" :show-overflow-tooltip="true" sortable align="center"></el-table-column>
<el-table-column prop="startTime" label="开始时间" sortable align="center"></el-table-column> <el-table-column prop="createTime" label="开始时间" width="160" :show-overflow-tooltip="true" sortable align="center"></el-table-column>
<el-table-column prop="endTime" label="结束时间" sortable align="center"></el-table-column> <el-table-column prop="updateTime" label="结束时间" width="160" :show-overflow-tooltip="true" sortable align="center"></el-table-column>
<el-table-column prop="runDuration" label="运行时长" sortable align="center"></el-table-column> <el-table-column
<el-table-column prop="attachmentList" label="附件" sortable align="center"> prop="runDuration"
label="运行时长"
width="140"
:show-overflow-tooltip="true"
sortable
align="center"
></el-table-column>
<el-table-column prop="attachmentList" width="120" label="附件" align="center">
<template #default="scope"> <template #default="scope">
<el-popover v-if="scope.row.attachmentList && scope.row.attachmentList.length > 0" placement="right" :width="310" trigger="click"> <el-popover v-if="scope.row.attachmentList && scope.row.attachmentList.length > 0" placement="right" :width="310" trigger="click">
<template #reference> <template #reference>
<el-button style="margin-right: 16px">附件</el-button> <el-button type="primary" style="margin-right: 16px">附件</el-button>
</template> </template>
<el-table border :data="scope.row.attachmentList"> <el-table border :data="scope.row.attachmentList">
<el-table-column prop="name" width="202" :show-overflow-tooltip="true" label="附件名称"></el-table-column> <el-table-column prop="originalName" width="202" :show-overflow-tooltip="true" label="附件名称"></el-table-column>
<el-table-column prop="name" width="80" align="center" :show-overflow-tooltip="true" label="操作"> <el-table-column prop="name" width="80" align="center" :show-overflow-tooltip="true" label="操作">
<template #default="tool"> <template #default="tool">
<el-button type="text" @click="handleDownload(tool.row.contentId)"></el-button> <el-button type="text" @click="handleDownload(tool.row.ossId)"></el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -48,43 +72,161 @@
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<script lang="ts" setup> <script setup lang="ts">
import BpmnView from '@/components/BpmnView/index.vue'; import { flowImage } from '@/api/workflow/instance';
import processApi from '@/api/flowableWorkflow/processInstance';
import { propTypes } from '@/utils/propTypes'; import { propTypes } from '@/utils/propTypes';
import { listByIds } from '@/api/system/oss';
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { wf_task_status } = toRefs<any>(proxy?.useDict('wf_task_status'));
const props = defineProps({ const props = defineProps({
width: propTypes.string.def('70%'), width: propTypes.string.def('80%'),
height: propTypes.string.def('100%') height: propTypes.string.def('100%')
}); });
const loading = ref(false); const loading = ref(false);
const visible = ref(false); const visible = ref(false);
const historyList = ref<Array<any>>([]); const historyList = ref<Array<any>>([]);
const tabActiveName = ref('bpmn'); const tabActiveName = ref('image');
const imgUrl = ref('');
const bpmnViewRef = ref<BpmnView>();
// //
const init = async (businessKey: string | number) => { const init = async (businessId: string | number) => {
visible.value = true; visible.value = true;
loading.value = true; loading.value = true;
tabActiveName.value = 'bpmn'; tabActiveName.value = 'image';
historyList.value = []; historyList.value = [];
processApi.getHistoryRecord(businessKey).then((resp) => { flowImage(businessId).then((resp) => {
historyList.value = resp.data; if (resp.data) {
historyList.value = resp.data.list;
imgUrl.value = 'data:image/gif;base64,' + resp.data.image;
if (historyList.value.length > 0) {
historyList.value.forEach((item) => {
if (item.ext) {
getIds(item.ext).then((res) => {
item.attachmentList = res.data;
});
} else {
item.attachmentList = [];
}
});
}
loading.value = false; loading.value = false;
}
}); });
await nextTick(() => { };
bpmnViewRef.value.init(businessKey); const getIds = async (ids: string | number) => {
}); const res = await listByIds(ids);
return res;
}; };
/** 下载按钮操作 */ /** 下载按钮操作 */
const handleDownload = (ossId: string) => { const handleDownload = (ossId: string) => {
proxy?.$download.oss(ossId); proxy?.$download.oss(ossId);
}; };
const imageWrapperRef = ref<HTMLElement | null>(null);
const scale = ref(1); //
const maxScale = 3; //
const minScale = 0.5; //
let isDragging = false;
let startX = 0;
let startY = 0;
let currentTranslateX = 0;
let currentTranslateY = 0;
const handleMouseWheel = (event: WheelEvent) => {
event.preventDefault();
let newScale = scale.value - event.deltaY / 1000;
newScale = Math.max(minScale, Math.min(newScale, maxScale));
if (newScale !== scale.value) {
scale.value = newScale;
resetDragPosition(); // 使
}
};
const handleMouseDown = (event: MouseEvent) => {
if (scale.value > 1) {
event.preventDefault(); //
isDragging = true;
startX = event.clientX;
startY = event.clientY;
}
};
const handleMouseMove = (event: MouseEvent) => {
if (!isDragging || !imageWrapperRef.value) return;
const deltaX = event.clientX - startX;
const deltaY = event.clientY - startY;
startX = event.clientX;
startY = event.clientY;
currentTranslateX += deltaX;
currentTranslateY += deltaY;
//
const bounds = getBounds();
if (currentTranslateX > bounds.maxTranslateX) {
currentTranslateX = bounds.maxTranslateX;
} else if (currentTranslateX < bounds.minTranslateX) {
currentTranslateX = bounds.minTranslateX;
}
if (currentTranslateY > bounds.maxTranslateY) {
currentTranslateY = bounds.maxTranslateY;
} else if (currentTranslateY < bounds.minTranslateY) {
currentTranslateY = bounds.minTranslateY;
}
applyTransform();
};
const handleMouseUp = () => {
isDragging = false;
};
const handleMouseLeave = () => {
isDragging = false;
};
const resetTransform = () => {
scale.value = 1;
currentTranslateX = 0;
currentTranslateY = 0;
applyTransform();
};
const resetDragPosition = () => {
currentTranslateX = 0;
currentTranslateY = 0;
applyTransform();
};
const applyTransform = () => {
if (imageWrapperRef.value) {
imageWrapperRef.value.style.transform = `translate(${currentTranslateX}px, ${currentTranslateY}px) scale(${scale.value})`;
}
};
const getBounds = () => {
if (!imageWrapperRef.value) return { minTranslateX: 0, maxTranslateX: 0, minTranslateY: 0, maxTranslateY: 0 };
const imgRect = imageWrapperRef.value.getBoundingClientRect();
const containerRect = imageWrapperRef.value.parentElement?.getBoundingClientRect() ?? imgRect;
const minTranslateX = (containerRect.width - imgRect.width * scale.value) / 2;
const maxTranslateX = -(containerRect.width - imgRect.width * scale.value) / 2;
const minTranslateY = (containerRect.height - imgRect.height * scale.value) / 2;
const maxTranslateY = -(containerRect.height - imgRect.height * scale.value) / 2;
return { minTranslateX, maxTranslateX, minTranslateY, maxTranslateY };
};
const transformStyle = computed(() => ({
transition: isDragging ? 'none' : 'transform 0.2s ease'
}));
/** /**
* 对外暴露子组件方法 * 对外暴露子组件方法
*/ */
@ -113,4 +255,26 @@ defineExpose({
min-height: calc(100vh - 170px) !important; min-height: calc(100vh - 170px) !important;
} }
} }
.image-wrapper {
width: 100%;
overflow: hidden;
position: relative;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
user-select: none; /* 禁用文本选择 */
cursor: grab; /* 设置初始鼠标指针为可拖动 */
}
.image-wrapper:active {
cursor: grabbing; /* 当正在拖动时改变鼠标指针 */
}
.scalable-image {
object-fit: contain;
width: 100%;
padding: 15px;
}
</style> </style>

@ -0,0 +1,211 @@
<template>
<el-dialog v-model="visible" draggable title="流程干预" :width="props.width" :height="props.height" :close-on-click-modal="false">
<el-descriptions v-loading="loading" class="margin-top" :title="`${task.flowName}(${task.flowCode})`" :column="2" border>
<el-descriptions-item label="任务名称">{{ task.nodeName }}</el-descriptions-item>
<el-descriptions-item label="节点编码">{{ task.nodeCode }}</el-descriptions-item>
<el-descriptions-item label="开始时间">{{ task.createTime }}</el-descriptions-item>
<el-descriptions-item label="流程实例ID">{{ task.instanceId }}</el-descriptions-item>
<el-descriptions-item label="版本号">{{ task.version }}.0</el-descriptions-item>
<el-descriptions-item label="业务ID">{{ task.businessId }}</el-descriptions-item>
</el-descriptions>
<template #footer>
<span class="dialog-footer">
<el-button v-if="task.flowStatus === 'waiting'" :disabled="buttonDisabled" type="primary" @click="openTransferTask"> </el-button>
<el-button
v-if="task.flowStatus === 'waiting' && Number(task.nodeRatio) > 0"
:disabled="buttonDisabled"
type="primary"
@click="openMultiInstanceUser"
>
加签
</el-button>
<el-button
v-if="task.flowStatus === 'waiting' && Number(task.nodeRatio) > 0"
:disabled="buttonDisabled"
type="primary"
@click="handleTaskUser"
>
减签
</el-button>
<el-button v-if="task.flowStatus === 'waiting'" :disabled="buttonDisabled" type="danger" @click="handleTerminationTask"> </el-button>
</span>
</template>
<!-- 转办 -->
<UserSelect ref="transferTaskRef" :multiple="false" @confirm-call-back="handleTransferTask"></UserSelect>
<!-- 加签组件 -->
<UserSelect ref="multiInstanceUserRef" :multiple="true" @confirm-call-back="addMultiInstanceUser"></UserSelect>
<el-dialog v-model="deleteSignatureVisible" draggable title="减签人员" width="700px" height="400px" append-to-body :close-on-click-modal="false"
><div>
<el-table :data="deleteUserList" border>
<el-table-column prop="nodeName" label="任务名称" />
<el-table-column prop="nickName" label="办理人" />
<el-table-column label="操作" align="center" width="160">
<template #default="scope">
<el-button type="danger" size="small" icon="Delete" @click="deleteMultiInstanceUser(scope.row)"></el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-dialog>
</el-dialog>
</template>
<script setup lang="ts">
import { propTypes } from '@/utils/propTypes';
import { FlowTaskVO, TaskOperationBo } from '@/api/workflow/task/types';
import UserSelect from '@/components/UserSelect';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
import { getTask, taskOperation, currentTaskAllUser, terminationTask } from '@/api/workflow/task';
const props = defineProps({
width: propTypes.string.def('50%'),
height: propTypes.string.def('100%')
});
const emits = defineEmits(['submitCallback']);
const transferTaskRef = ref<InstanceType<typeof UserSelect>>();
const multiInstanceUserRef = ref<InstanceType<typeof UserSelect>>();
//
const loading = ref(true);
//
const buttonDisabled = ref(true);
const visible = ref(false);
//
const deleteSignatureVisible = ref(false);
//
const deleteUserList = ref<any>([]);
//
const task = ref<FlowTaskVO>({
id: undefined,
createTime: undefined,
updateTime: undefined,
tenantId: undefined,
definitionId: undefined,
instanceId: undefined,
flowName: undefined,
businessId: undefined,
nodeCode: undefined,
nodeName: undefined,
flowCode: undefined,
flowStatus: undefined,
formCustom: undefined,
formPath: undefined,
nodeType: undefined,
nodeRatio: undefined,
version: undefined,
applyNode: undefined,
buttonList: []
});
const open = (taskId: string) => {
visible.value = true;
getTask(taskId).then((response) => {
loading.value = false;
buttonDisabled.value = false;
task.value = response.data;
});
};
//
const openTransferTask = () => {
transferTaskRef.value.open();
};
//
const handleTransferTask = async (data) => {
if (data && data.length > 0) {
const taskOperationBo = reactive<TaskOperationBo>({
userId: data[0].userId,
taskId: task.value.id,
message: ''
});
await proxy?.$modal.confirm('是否确认提交?');
loading.value = true;
buttonDisabled.value = true;
await taskOperation(taskOperationBo, 'transferTask').finally(() => {
loading.value = false;
buttonDisabled.value = false;
});
visible.value = false;
emits('submitCallback');
proxy?.$modal.msgSuccess('操作成功');
} else {
proxy?.$modal.msgWarning('请选择用户!');
}
};
//
const openMultiInstanceUser = async () => {
multiInstanceUserRef.value.open();
};
//
const addMultiInstanceUser = async (data) => {
if (data && data.length > 0) {
const taskOperationBo = reactive<TaskOperationBo>({
userIds: data.map((e) => e.userId),
taskId: task.value.id,
message: ''
});
await proxy?.$modal.confirm('是否确认提交?');
loading.value = true;
buttonDisabled.value = true;
await taskOperation(taskOperationBo, 'addSignature').finally(() => {
loading.value = false;
buttonDisabled.value = false;
});
visible.value = false;
emits('submitCallback');
proxy?.$modal.msgSuccess('操作成功');
} else {
proxy?.$modal.msgWarning('请选择用户!');
}
};
//
const deleteMultiInstanceUser = async (row) => {
await proxy?.$modal.confirm('是否确认提交?');
loading.value = true;
buttonDisabled.value = true;
const taskOperationBo = reactive<TaskOperationBo>({
userIds: [row.userId],
taskId: task.value.id,
message: ''
});
await taskOperation(taskOperationBo, 'reductionSignature').finally(() => {
loading.value = false;
buttonDisabled.value = false;
});
visible.value = false;
emits('submitCallback');
proxy?.$modal.msgSuccess('操作成功');
};
//
const handleTaskUser = async () => {
const data = await currentTaskAllUser(task.value.id);
deleteUserList.value = data.data;
if (deleteUserList.value && deleteUserList.value.length > 0) {
deleteUserList.value.forEach((e) => {
e.nodeName = task.value.nodeName;
});
}
deleteSignatureVisible.value = true;
};
//
const handleTerminationTask = async () => {
const params = {
taskId: task.value.id,
comment: ''
};
await proxy?.$modal.confirm('是否确认终止?');
loading.value = true;
buttonDisabled.value = true;
await terminationTask(params).finally(() => {
loading.value = false;
buttonDisabled.value = false;
});
visible.value = false;
emits('submitCallback');
proxy?.$modal.msgSuccess('操作成功');
};
/**
* 对外暴露子组件方法
*/
defineExpose({
open
});
</script>

@ -3,47 +3,71 @@
<el-form v-loading="loading" :model="form" label-width="120px"> <el-form v-loading="loading" :model="form" label-width="120px">
<el-form-item label="消息提醒"> <el-form-item label="消息提醒">
<el-checkbox-group v-model="form.messageType"> <el-checkbox-group v-model="form.messageType">
<el-checkbox label="1" name="type" disabled>站内信</el-checkbox> <el-checkbox value="1" name="type" disabled>站内信</el-checkbox>
<el-checkbox label="2" name="type">邮件</el-checkbox> <el-checkbox value="2" name="type">邮件</el-checkbox>
<el-checkbox label="3" name="type">短信</el-checkbox> <el-checkbox value="3" name="type">短信</el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
<el-form-item v-if="task.businessStatus === 'waiting'" label="附件"> <el-form-item v-if="task.flowStatus === 'waiting'" label="附件">
<fileUpload v-model="form.fileId" :file-type="['doc', 'xls', 'ppt', 'txt', 'pdf', 'xlsx', 'docx', 'zip']" :file-size="'20'" /> <fileUpload v-model="form.fileId" :file-type="['png', 'jpg', 'jpeg', 'doc', 'docx', 'xlsx', 'xls', 'ppt', 'txt', 'pdf']" :file-size="20" />
</el-form-item> </el-form-item>
<el-form-item label="抄送"> <el-form-item label="抄送" v-if="task.flowStatus === 'waiting' && buttonObj.copy">
<el-button type="primary" icon="Plus" circle @click="openUserSelectCopy" /> <el-button type="primary" icon="Plus" circle @click="openUserSelectCopy" />
<el-tag v-for="user in selectCopyUserList" :key="user.userId" closable style="margin: 2px" @close="handleCopyCloseTag(user)"> <el-tag v-for="user in selectCopyUserList" :key="user.userId" closable style="margin: 2px" @close="handleCopyCloseTag(user)">
{{ user.userName }} {{ user.nickName }}
</el-tag> </el-tag>
</el-form-item> </el-form-item>
<el-form-item v-if="task.businessStatus === 'waiting'" label="审批意见"> <el-form-item v-if="buttonObj.pop && nestNodeList && nestNodeList.length > 0" label="下一步审批人" prop="assigneeMap">
<div v-for="(item, index) in nestNodeList" :key="index" style="margin-bottom: 5px; width: 500px">
<span>{{ item.nodeName }}</span>
<el-input v-if="false" v-model="form.assigneeMap[item.nodeCode]" />
<el-input placeholder="请选择审批人" readonly v-model="nickName[item.nodeCode]">
<template v-slot:append>
<el-button @click="choosePeople(item)" icon="search">选择</el-button>
</template>
</el-input>
</div>
</el-form-item>
<el-form-item v-if="task.flowStatus === 'waiting'" label="审批意见">
<el-input v-model="form.message" type="textarea" resize="none" /> <el-input v-model="form.message" type="textarea" resize="none" />
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button :disabled="buttonDisabled" type="primary" @click="handleCompleteTask"> </el-button> <el-button :disabled="buttonDisabled" type="primary" @click="handleCompleteTask"> </el-button>
<el-button v-if="task.businessStatus === 'waiting'" :disabled="buttonDisabled" type="primary" @click="openDelegateTask"> </el-button> <el-button v-if="task.flowStatus === 'waiting' && buttonObj.trust" :disabled="buttonDisabled" type="primary" @click="openDelegateTask">
<el-button v-if="task.businessStatus === 'waiting'" :disabled="buttonDisabled" type="primary" @click="openTransferTask"> </el-button> 委托
</el-button>
<el-button v-if="task.flowStatus === 'waiting' && buttonObj.transfer" :disabled="buttonDisabled" type="primary" @click="openTransferTask">
转办
</el-button>
<el-button <el-button
v-if="task.businessStatus === 'waiting' && task.multiInstance" v-if="task.flowStatus === 'waiting' && Number(task.nodeRatio) > 0 && buttonObj.addSign"
:disabled="buttonDisabled" :disabled="buttonDisabled"
type="primary" type="primary"
@click="addMultiInstanceUser" @click="openMultiInstanceUser"
> >
加签 加签
</el-button> </el-button>
<el-button <el-button
v-if="task.businessStatus === 'waiting' && task.multiInstance" v-if="task.flowStatus === 'waiting' && Number(task.nodeRatio) > 0 && buttonObj.subSign"
:disabled="buttonDisabled" :disabled="buttonDisabled"
type="primary" type="primary"
@click="deleteMultiInstanceUser" @click="handleTaskUser"
> >
减签 减签
</el-button> </el-button>
<el-button v-if="task.businessStatus === 'waiting'" :disabled="buttonDisabled" type="danger" @click="handleTerminationTask"> </el-button> <el-button
<el-button v-if="task.businessStatus === 'waiting'" :disabled="buttonDisabled" type="danger" @click="handleBackProcessOpen"> 退 </el-button> v-if="task.flowStatus === 'waiting' && buttonObj.termination"
:disabled="buttonDisabled"
type="danger"
@click="handleTerminationTask"
>
终止
</el-button>
<el-button v-if="task.flowStatus === 'waiting' && buttonObj.back" :disabled="buttonDisabled" type="danger" @click="handleBackProcessOpen">
退回
</el-button>
<el-button :disabled="buttonDisabled" @click="cancel"></el-button> <el-button :disabled="buttonDisabled" @click="cancel"></el-button>
</span> </span>
</template> </template>
@ -54,14 +78,16 @@
<!-- 委托 --> <!-- 委托 -->
<UserSelect ref="delegateTaskRef" :multiple="false" @confirm-call-back="handleDelegateTask"></UserSelect> <UserSelect ref="delegateTaskRef" :multiple="false" @confirm-call-back="handleDelegateTask"></UserSelect>
<!-- 加签组件 --> <!-- 加签组件 -->
<multiInstanceUser ref="multiInstanceUserRef" :title="title" @submit-callback="closeDialog" /> <UserSelect ref="multiInstanceUserRef" :multiple="true" @confirm-call-back="addMultiInstanceUser"></UserSelect>
<!-- 弹窗选人 -->
<UserSelect ref="porUserRef" :multiple="true" :userIds="popUserIds" @confirm-call-back="handlePopUser"></UserSelect>
<!-- 驳回开始 --> <!-- 驳回开始 -->
<el-dialog v-model="backVisible" draggable title="驳回" width="40%" :close-on-click-modal="false"> <el-dialog v-model="backVisible" draggable title="驳回" width="40%" :close-on-click-modal="false">
<el-form v-if="task.businessStatus === 'waiting'" v-loading="backLoading" :model="backForm" label-width="120px"> <el-form v-if="task.flowStatus === 'waiting'" v-loading="backLoading" :model="backForm" label-width="120px">
<el-form-item label="驳回节点"> <el-form-item label="驳回节点">
<el-select v-model="backForm.targetActivityId" clearable placeholder="请选择" style="width: 300px"> <el-select v-model="backForm.nodeCode" clearable placeholder="请选择" style="width: 300px">
<el-option v-for="item in taskNodeList" :key="item.nodeId" :label="item.nodeName" :value="item.nodeId" /> <el-option v-for="item in taskNodeList" :key="item.nodeCode" :label="item.nodeName" :value="item.nodeCode" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="消息提醒"> <el-form-item label="消息提醒">
@ -71,6 +97,13 @@
<el-checkbox label="3" name="type">短信</el-checkbox> <el-checkbox label="3" name="type">短信</el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
<el-form-item v-if="task.flowStatus === 'waiting'" label="附件">
<fileUpload
v-model="backForm.fileId"
:file-type="['png', 'jpg', 'jpeg', 'doc', 'docx', 'xlsx', 'xls', 'ppt', 'txt', 'pdf']"
:file-size="20"
/>
</el-form-item>
<el-form-item label="审批意见"> <el-form-item label="审批意见">
<el-input v-model="backForm.message" type="textarea" resize="none" /> <el-input v-model="backForm.message" type="textarea" resize="none" />
</el-form-item> </el-form-item>
@ -83,25 +116,47 @@
</template> </template>
</el-dialog> </el-dialog>
<!-- 驳回结束 --> <!-- 驳回结束 -->
<el-dialog v-model="deleteSignatureVisible" draggable title="减签人员" width="700px" height="400px" append-to-body :close-on-click-modal="false">
<div>
<el-table :data="deleteUserList" border>
<el-table-column prop="nodeName" label="任务名称" />
<el-table-column prop="nickName" label="办理人" />
<el-table-column label="操作" align="center" width="160">
<template #default="scope">
<el-button type="danger" size="small" icon="Delete" @click="deleteMultiInstanceUser(scope.row)"> </el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-dialog>
</el-dialog> </el-dialog>
</template> </template>
<script lang="ts" setup> <script setup lang="ts">
import { ref } from 'vue'; import { ref } from 'vue';
import { ComponentInternalInstance } from 'vue'; import { ComponentInternalInstance } from 'vue';
import { ElForm } from 'element-plus'; import { ElForm } from 'element-plus';
import { completeTask, backProcess, getTaskById, transferTask, terminationTask, getTaskNodeList, delegateTask } from '@/api/flowableWorkflow/task'; import {
completeTask,
backProcess,
getTask,
taskOperation,
terminationTask,
getBackTaskNode,
currentTaskAllUser,
getNextNodeList
} from '@/api/workflow/task';
import UserSelect from '@/components/UserSelect'; import UserSelect from '@/components/UserSelect';
import MultiInstanceUser from '@/components/Process/multiInstanceUser.vue';
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
import { UserVO } from '@/api/system/user/types'; import { UserVO } from '@/api/system/user/types';
import { TaskVO } from '@/api/flowableWorkflow/task/types'; import { FlowTaskVO, TaskOperationBo } from '@/api/workflow/task/types';
const userSelectCopyRef = ref<InstanceType<typeof UserSelect>>(); const userSelectCopyRef = ref<InstanceType<typeof UserSelect>>();
const transferTaskRef = ref<InstanceType<typeof UserSelect>>(); const transferTaskRef = ref<InstanceType<typeof UserSelect>>();
const delegateTaskRef = ref<InstanceType<typeof UserSelect>>(); const delegateTaskRef = ref<InstanceType<typeof UserSelect>>();
const multiInstanceUserRef = ref<InstanceType<typeof UserSelect>>();
// const porUserRef = ref<InstanceType<typeof UserSelect>>();
const multiInstanceUserRef = ref<InstanceType<typeof MultiInstanceUser>>();
const props = defineProps({ const props = defineProps({
taskVariables: { taskVariables: {
@ -119,67 +174,75 @@ const taskId = ref<string>('');
const selectCopyUserList = ref<UserVO[]>([]); const selectCopyUserList = ref<UserVO[]>([]);
//id //id
const selectCopyUserIds = ref<string>(undefined); const selectCopyUserIds = ref<string>(undefined);
//
const deleteUserList = ref<any>([]);
//id
const popUserIds = ref<any>([]);
// //
const backVisible = ref(false); const backVisible = ref(false);
const backLoading = ref(true); const backLoading = ref(true);
const backButtonDisabled = ref(true); const backButtonDisabled = ref(true);
// //
const taskNodeList = ref([]); const taskNodeList = ref([]);
// const nickName = ref({});
const task = ref<TaskVO>({ //
id: undefined, const nodeCode = ref<string>('');
name: undefined, const buttonObj = ref<any>({
description: undefined, pop: false,
priority: undefined, trust: false,
owner: undefined, transfer: false,
assignee: undefined, addSign: false,
assigneeName: undefined, subSign: false,
processInstanceId: undefined, termination: false,
executionId: undefined, back: false
taskDefinitionId: undefined, });
processDefinitionId: undefined, //
endTime: undefined, const nestNodeList = ref([]);
taskDefinitionKey: undefined, //
dueDate: undefined, const task = ref<FlowTaskVO>({
category: undefined, id: undefined,
parentTaskId: undefined, createTime: undefined,
tenantId: undefined, updateTime: undefined,
claimTime: undefined, tenantId: undefined,
businessStatus: undefined, definitionId: undefined,
businessStatusName: undefined, instanceId: undefined,
processDefinitionName: undefined, flowName: undefined,
processDefinitionKey: undefined, businessId: undefined,
participantVo: undefined, nodeCode: undefined,
multiInstance: undefined, nodeName: undefined,
businessKey: undefined, flowCode: undefined,
wfNodeConfigVo: undefined flowStatus: undefined,
formCustom: undefined,
formPath: undefined,
nodeType: undefined,
nodeRatio: undefined,
applyNode: false,
buttonList: []
}); });
//
const title = ref('');
const dialog = reactive<DialogOption>({ const dialog = reactive<DialogOption>({
visible: false, visible: false,
title: '提示' title: '提示'
}); });
//
const deleteSignatureVisible = ref(false);
const form = ref<Record<string, any>>({ const form = ref<Record<string, any>>({
taskId: undefined, taskId: undefined,
message: undefined, message: undefined,
assigneeMap: {},
variables: {}, variables: {},
messageType: ['1'], messageType: ['1'],
wfCopyList: [] flowCopyList: []
}); });
const backForm = ref<Record<string, any>>({ const backForm = ref<Record<string, any>>({
taskId: undefined, taskId: undefined,
targetActivityId: undefined, nodeCode: undefined,
message: undefined, message: undefined,
variables: {}, variables: {},
messageType: ['1'] messageType: ['1']
}); });
const closeDialog = () => {
dialog.visible = false;
};
// //
const openDialog = (id?: string) => { const openDialog = async (id?: string) => {
selectCopyUserIds.value = undefined; selectCopyUserIds.value = undefined;
selectCopyUserList.value = []; selectCopyUserList.value = [];
form.value.fileId = undefined; form.value.fileId = undefined;
@ -188,13 +251,20 @@ const openDialog = (id?: string) => {
dialog.visible = true; dialog.visible = true;
loading.value = true; loading.value = true;
buttonDisabled.value = true; buttonDisabled.value = true;
nextTick(() => { const response = await getTask(taskId.value);
getTaskById(taskId.value).then((response) => {
task.value = response.data; task.value = response.data;
loading.value = false; buttonObj.value = {};
task.value.buttonList.forEach((e) => {
buttonObj.value[e.code] = e.show;
});
buttonDisabled.value = false; buttonDisabled.value = false;
}); const data = {
}); taskId: taskId.value,
variables: props.taskVariables
};
const nextData = await getNextNodeList(data);
nestNodeList.value = nextData.data;
loading.value = false;
}; };
onMounted(() => {}); onMounted(() => {});
@ -204,16 +274,35 @@ const emits = defineEmits(['submitCallback', 'cancelCallback']);
const handleCompleteTask = async () => { const handleCompleteTask = async () => {
form.value.taskId = taskId.value; form.value.taskId = taskId.value;
form.value.taskVariables = props.taskVariables; form.value.taskVariables = props.taskVariables;
let verify = false;
if (buttonObj.value.pop && nestNodeList.value && nestNodeList.value.length > 0) {
nestNodeList.value.forEach((e) => {
if (
Object.keys(form.value.assigneeMap).length === 0 ||
form.value.assigneeMap[e.nodeCode] === '' ||
form.value.assigneeMap[e.nodeCode] === null ||
form.value.assigneeMap[e.nodeCode] === undefined
) {
verify = true;
}
});
if (verify) {
proxy?.$modal.msgWarning('请选择审批人!');
return false;
}
} else {
form.value.assigneeMap = {};
}
if (selectCopyUserList.value && selectCopyUserList.value.length > 0) { if (selectCopyUserList.value && selectCopyUserList.value.length > 0) {
let wfCopyList = []; const flowCopyList = [];
selectCopyUserList.value.forEach((e) => { selectCopyUserList.value.forEach((e) => {
let copyUser = { const copyUser = {
userId: e.userId, userId: e.userId,
userName: e.nickName userName: e.nickName
}; };
wfCopyList.push(copyUser); flowCopyList.push(copyUser);
}); });
form.value.wfCopyList = wfCopyList; form.value.flowCopyList = flowCopyList;
} }
await proxy?.$modal.confirm('是否确认提交?'); await proxy?.$modal.confirm('是否确认提交?');
loading.value = true; loading.value = true;
@ -236,11 +325,11 @@ const handleBackProcessOpen = async () => {
backVisible.value = true; backVisible.value = true;
backLoading.value = true; backLoading.value = true;
backButtonDisabled.value = true; backButtonDisabled.value = true;
let data = await getTaskNodeList(task.value.processInstanceId); const data = await getBackTaskNode(task.value.definitionId, task.value.nodeCode);
taskNodeList.value = data.data; taskNodeList.value = data.data;
backLoading.value = false; backLoading.value = false;
backButtonDisabled.value = false; backButtonDisabled.value = false;
backForm.value.targetActivityId = taskNodeList.value[0].nodeId; backForm.value.nodeCode = taskNodeList.value[0].nodeCode;
}; };
/** 驳回流程 */ /** 驳回流程 */
const handleBackProcess = async () => { const handleBackProcess = async () => {
@ -249,7 +338,10 @@ const handleBackProcess = async () => {
loading.value = true; loading.value = true;
backLoading.value = true; backLoading.value = true;
backButtonDisabled.value = true; backButtonDisabled.value = true;
await backProcess(backForm.value).finally(() => (loading.value = false)); await backProcess(backForm.value).finally(() => {
loading.value = false;
buttonDisabled.value = false;
});
dialog.visible = false; dialog.visible = false;
backLoading.value = false; backLoading.value = false;
backButtonDisabled.value = false; backButtonDisabled.value = false;
@ -260,6 +352,8 @@ const handleBackProcess = async () => {
const cancel = async () => { const cancel = async () => {
dialog.visible = false; dialog.visible = false;
buttonDisabled.value = false; buttonDisabled.value = false;
nickName.value = {};
form.value.assigneeMap = {};
emits('cancelCallback'); emits('cancelCallback');
}; };
// //
@ -282,18 +376,48 @@ const handleCopyCloseTag = (user: UserVO) => {
selectCopyUserIds.value = selectCopyUserList.value.map((item) => item.userId).join(','); selectCopyUserIds.value = selectCopyUserList.value.map((item) => item.userId).join(',');
}; };
// //
const addMultiInstanceUser = () => { const openMultiInstanceUser = async () => {
if (multiInstanceUserRef.value) { multiInstanceUserRef.value.open();
title.value = '加签人员'; };
multiInstanceUserRef.value.getAddMultiInstanceList(taskId.value, []); //
const addMultiInstanceUser = async (data) => {
if (data && data.length > 0) {
const taskOperationBo = reactive<TaskOperationBo>({
userIds: data.map((e) => e.userId),
taskId: taskId.value,
message: form.value.message
});
await proxy?.$modal.confirm('是否确认提交?');
loading.value = true;
buttonDisabled.value = true;
await taskOperation(taskOperationBo, 'addSignature').finally(() => {
loading.value = false;
buttonDisabled.value = false;
});
dialog.visible = false;
emits('submitCallback');
proxy?.$modal.msgSuccess('操作成功');
} else {
proxy?.$modal.msgWarning('请选择用户!');
} }
}; };
// //
const deleteMultiInstanceUser = () => { const deleteMultiInstanceUser = async (row) => {
if (multiInstanceUserRef.value) { await proxy?.$modal.confirm('是否确认提交?');
title.value = '减签人员'; loading.value = true;
multiInstanceUserRef.value.getDeleteMultiInstanceList(taskId.value); buttonDisabled.value = true;
} const taskOperationBo = reactive<TaskOperationBo>({
userIds: [row.userId],
taskId: taskId.value,
message: form.value.message
});
await taskOperation(taskOperationBo, 'reductionSignature').finally(() => {
loading.value = false;
buttonDisabled.value = false;
});
dialog.visible = false;
emits('submitCallback');
proxy?.$modal.msgSuccess('操作成功');
}; };
// //
const openTransferTask = () => { const openTransferTask = () => {
@ -302,15 +426,18 @@ const openTransferTask = () => {
// //
const handleTransferTask = async (data) => { const handleTransferTask = async (data) => {
if (data && data.length > 0) { if (data && data.length > 0) {
let params = { const taskOperationBo = reactive<TaskOperationBo>({
taskId: taskId.value,
userId: data[0].userId, userId: data[0].userId,
comment: form.value.message taskId: taskId.value,
}; message: form.value.message
});
await proxy?.$modal.confirm('是否确认提交?'); await proxy?.$modal.confirm('是否确认提交?');
loading.value = true; loading.value = true;
buttonDisabled.value = true; buttonDisabled.value = true;
await transferTask(params).finally(() => (loading.value = false)); await taskOperation(taskOperationBo, 'transferTask').finally(() => {
loading.value = false;
buttonDisabled.value = false;
});
dialog.visible = false; dialog.visible = false;
emits('submitCallback'); emits('submitCallback');
proxy?.$modal.msgSuccess('操作成功'); proxy?.$modal.msgSuccess('操作成功');
@ -326,15 +453,18 @@ const openDelegateTask = () => {
// //
const handleDelegateTask = async (data) => { const handleDelegateTask = async (data) => {
if (data && data.length > 0) { if (data && data.length > 0) {
let params = { const taskOperationBo = reactive<TaskOperationBo>({
taskId: taskId.value,
userId: data[0].userId, userId: data[0].userId,
nickName: data[0].nickName taskId: taskId.value,
}; message: form.value.message
});
await proxy?.$modal.confirm('是否确认提交?'); await proxy?.$modal.confirm('是否确认提交?');
loading.value = true; loading.value = true;
buttonDisabled.value = true; buttonDisabled.value = true;
await delegateTask(params).finally(() => (loading.value = false)); await taskOperation(taskOperationBo, 'delegateTask').finally(() => {
loading.value = false;
buttonDisabled.value = false;
});
dialog.visible = false; dialog.visible = false;
emits('submitCallback'); emits('submitCallback');
proxy?.$modal.msgSuccess('操作成功'); proxy?.$modal.msgSuccess('操作成功');
@ -343,19 +473,52 @@ const handleDelegateTask = async (data) => {
} }
}; };
// //
const handleTerminationTask = async (data) => { const handleTerminationTask = async () => {
let params = { const params = {
taskId: taskId.value, taskId: taskId.value,
comment: form.value.message comment: form.value.message
}; };
await proxy?.$modal.confirm('是否确认终止?'); await proxy?.$modal.confirm('是否确认终止?');
loading.value = true; loading.value = true;
buttonDisabled.value = true; buttonDisabled.value = true;
await terminationTask(params).finally(() => (loading.value = false)); await terminationTask(params).finally(() => {
loading.value = false;
buttonDisabled.value = false;
});
dialog.visible = false; dialog.visible = false;
emits('submitCallback'); emits('submitCallback');
proxy?.$modal.msgSuccess('操作成功'); proxy?.$modal.msgSuccess('操作成功');
}; };
const handleTaskUser = async () => {
const data = await currentTaskAllUser(taskId.value);
deleteUserList.value = data.data;
if (deleteUserList.value && deleteUserList.value.length > 0) {
deleteUserList.value.forEach((e) => {
e.nodeName = task.value.nodeName;
});
}
deleteSignatureVisible.value = true;
};
//
const choosePeople = async (data) => {
if (!data.permissionFlag) {
proxy?.$modal.msgError('没有可选择的人员,请联系管理员!');
}
popUserIds.value = data.permissionFlag;
nodeCode.value = data.nodeCode;
porUserRef.value.open();
};
//
const handlePopUser = async (userList) => {
const userIds = userList.map((item) => {
return item.userId;
});
const nickNames = userList.map((item) => {
return item.nickName;
});
form.value.assigneeMap[nodeCode.value] = userIds.join(',');
nickName.value[nodeCode.value] = nickNames.join(',');
};
/** /**
* 对外暴露子组件方法 * 对外暴露子组件方法

Loading…
Cancel
Save