Files
geg-gas-web/src/views/secondDev/approveFlowPage.vue
2026-02-03 17:59:05 +08:00

816 lines
30 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<a-spin :spinning="spinning" tip="请稍后...">
<div class="page-bg-wrap">
<div class="geg-flow-page">
<div class="top-toolbar">
<a-space :size="10" wrap>
<a-button style="margin-right: 10px" @click="close">
<slot name="icon">
<close-outlined />
</slot>
关闭
</a-button>
<template v-for="(btn, index) in buttonMap.normal">
<a-button @click="onClickBtn(btn)" :type="btn.buttonCode === ApproveCode.AGREE ? 'primary' : ''">
<slot name="icon" v-if="btn.buttonCode === ApproveCode.AGREE">
<check-circle-outlined />
</slot>
<slot name="icon" v-if="btn.buttonCode === ApproveCode.REJECT">
<stop-outlined />
</slot>
{{ btn.buttonName }}
</a-button>
</template>
<template v-for="(btnGroup, btnGroupKey) in buttonMap">
<a-dropdown v-if="btnGroupKey !== 'normal' && btnGroup.length">
<template #overlay>
<a-menu>
<a-menu-item v-for="(btn, index) in btnGroup" :key="btn.buttonCode" @click="onClickBtn(btn)">
{{ btn.buttonName }}
</a-menu-item>
</a-menu>
</template>
<a-button>
{{ btnGroupKey }}
<down-outlined />
</a-button>
</a-dropdown>
</template>
</a-space>
</div>
<component v-if="customFormConfig.codeList.includes(curPageCode)" :is="componentName" ref="formInformation" :disabled="(rQuery.status=='COMPLETED'?false : true)" />
<FormInformation
v-else
:key="renderKey"
ref="formInformation"
:disabled="readonly"
:formAssignmentData="data.formAssignmentData"
:formInfos="data.formInfos"
:opinions="data.opinions"
:opinionsComponents="data.opinionsComponents"
@get-form-configs="(config) => (formConfigs = config)"
/>
<div class="formViewStyle">
<Card title="流转信息" :bordered="false" >
<!-- <Title :font-size="18" default-value="流转信息"></Title> -->
<flow-history :items="getTaskRecords()"></flow-history>
</Card>
</div>
<opinion-dialog ref="opinionDlg" />
<transfer-dialog ref="transferDlg" />
<a-modal :closable="false" v-if="showFlowChart" visible="true" centered class="geg" title="流程图" width="1200px" @cancel="closeFlowChart">
<process-information :process-id="processId" :xml="data.xml" :currentTaskInfo="data.currentTaskInfo" :currentTaskAssigneeNames="data.currentTaskAssigneeNames" :currentTaskAssignees="data.currentTaskAssignees" />
<template #footer>
<a-button type="primary" @click="closeFlowChart">关闭</a-button>
</template>
</a-modal>
<a-modal :closable="false" v-if="showRecord" visible="true" centered class="geg" title="流程记录" width="1200px" @cancel="closeFlowRecord">
<div class="flow-record-box">
<FlowRecord :list="data.taskRecords" :processId="processId" />
</div>
<template #footer>
<a-button type="primary" @click="closeFlowRecord">关闭</a-button>
</template>
</a-modal>
<SelectUserV2 ref="selectUser" v-model:value="addStepUser" @change="changeAddStepUser" just-dialog title="加签减签" />
</div>
</div>
</a-spin>
</template>
<script setup>
import { Card } from 'ant-design-vue';
import { useRouter } from 'vue-router';
import { onMounted, reactive, ref, unref, createVNode, provide,computed,defineAsyncComponent } from 'vue';
import FormInformation from '/@/views/secondDev/FormInformation.vue';
import userTaskItem from '/@/views/workflow/task/hooks/userTaskItem';
import { getApprovalProcess, postApproval, postGetNextTaskMaybeArrival, postTransfer, getDrawNode, withdraw } from '/@/api/workflow/task';
import { ApproveCode, ApproveType, ButtonType } from '/@/enums/workflowEnum';
import { CheckCircleOutlined, StopOutlined, CloseOutlined, DownOutlined, ExclamationCircleOutlined } from '@ant-design/icons-vue';
import OpinionDialog from '/@/components/SecondDev/OpinionDialog.vue';
import TransferDialog from '/@/components/SecondDev/TransferDialog.vue';
import SelectUserV2 from '/@/components/Form/src/components/SelectUserV2.vue';
import { separator } from '/@bpmn/config/info';
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
import Title from '/@/components/Title/src/Title.vue';
import FlowHistory from '/@/components/SecondDev/FlowHistory.vue';
import { message, Modal } from 'ant-design-vue';
import useEventBus from '/@/hooks/event/useEventBus';
import ProcessInformation from '/@/views/workflow/task/components/flow/ProcessInformation.vue';
import { useI18n } from '/@/hooks/web/useI18n';
import { useMessage } from '/@/hooks/web/useMessage';
import { useUserStore } from '/@/store/modules/user';
import { deleteDraft, postDraft, putDraft, getDraftInfo } from '/@/api/workflow/process';
import { TaskTypeUrl } from '/@/enums/workflowEnum';
import { postSetSign, postSetSignV2 } from '/@/api/workflow/task';
import FlowRecord from '/@/views/workflow/task/components/flow/FlowRecord.vue';
import {customFormConfig} from './customFormConfig'
const spinning = ref(false);
const userStore = useUserStore();
const { t } = useI18n();
const { notification } = useMessage();
const { data, approveUserData, initProcessData, notificationError, notificationSuccess } = userTaskItem();
const { bus, FLOW_PROCESSED } = useEventBus();
const tabStore = useMultipleTabStore();
const router = useRouter();
const currentRoute = router.currentRoute.value;
const fullPath = currentRoute.fullPath;
const rQuery = currentRoute.query;
const rParams = currentRoute.params;
const schemaId = ref(rParams.arg1);
const taskId = ref(rQuery.taskId);
const processId = ref(rParams.arg2);
const readonly = ref(!!rQuery.readonly); // 查看流程会触发只读模式
const rDraftsId = ref(rQuery.draftId || '');
const renderKey = ref('');
const formConfigs = ref();
const opinionDlg = ref();
const transferDlg = ref();
const validateSuccess = ref(false);
const formInformation = ref();
const selectUser = ref();
const addStepUser = ref('');
const lastAddStepUser = ref('');
const hasBtnAddStep = ref(false);
const hasBtnTransfer = ref(false);
const showFlowChart = ref(false);
const showRecord = ref(false);
const hasBtnApprove = ref(false);
const hasBtnDisagree = ref(false);
const hasBtnReject = ref(false);
const hasBtnFinish = ref(false);
const hasBtnDraft = ref(false);
const approveBtnName = ref('同意');
const transferBtnName = ref('转办');
const addStepBtnName = ref('会签');
const finishBtnName = ref('终止');
const rejectBtnName = ref('拒绝');
const drawBackBtnName = ref('撤回');
const draftBtnName = ref('暂存');
const disagreeBtnName = ref('不同意');
const buttonMap = ref({
normal: []
});
let draftData = {};
const drawNode = ref('');
const props = defineProps({
rowKeyData: {
type: String
}
});
const processInfo = ref();
provide('processInfo', processInfo);
let approvalData = reactive({
isCountersign: false,
isAddOrSubSign: false,
isEnd: false,
stampInfo: {
stampId: '',
password: ''
},
buttonConfigs: [],
approvedType: ApproveType.AGREE,
approvedResult: ApproveCode.AGREE,
approvedContent: '',
rejectNodeActivityId: '',
rejectNodeActivityIds: [],
circulateConfigs: [],
nextTaskUser: {} // 格式为taskKey: 用户id逗号分隔
});
let approvedType = ref(ApproveType.AGREE);
const componentName = computed(() => {
if (!data.formInfos.length) {
return defineAsyncComponent({
loader: () => import('/@/views/secondDev/Empty.vue')
});
}
return defineAsyncComponent({
loader: () => import(`../../views/${data.formInfos[0]?.functionalModule}/${data.formInfos[0]?.functionName}/components/createForm.vue`)
});
});
function showButton(btn) {
// 撤回有drawNode才显示流程图任何情况下都显示
let show =
(btn.checked && ((!readonly.value && btn.buttonCode !== ApproveCode.DRAWBACK) || (readonly.value && btn.buttonCode === ApproveCode.DRAWBACK && drawNode.value))) ||
btn.buttonCode === ApproveCode.FLOWBPMN ||
btn.buttonCode === ApproveCode.FLOWRECORD;
if (rQuery.status=='COMPLETED' && btn.buttonCode=='draft'){
show = true
}
if (readonly.value && btn.buttonCode=='drawBack'){
show = false
}
return show;
}
function onClickBtn(btn) {
const key = btn.buttonCode;
if (btn.buttonType === ButtonType.DEFAULT) {
let funName = `handle${key}`;
methods[funName](btn);
} else if (btn.buttonType === ButtonType.SCRIPT) {
handleFunction(btn);
}
}
function onMoreClick(e) {
const key = e.key;
if (btn.buttonType === ButtonType.DEFAULT) {
let funName = `handle${key}`;
methods[funName](btn);
} else if (btn.buttonType === ButtonType.SCRIPT) {
handleFunction(btn);
}
}
function handleFunction(btn) {
// eval(script)
if (btn.handleFuncName) {
formInformation.value?.handleInnerFun(btn.handleFuncName);
}
}
const methods = {
handlesetDraft() {
setDraft();
},
handledraft() {
saveDraft();
},
handleaddStep() {
selectUser.value.show();
},
handledrawBack() {
Modal.confirm({
title: t('提示'),
icon: createVNode(ExclamationCircleOutlined),
content: t('请确认是否撤回该流程?'),
okText: t('确定'),
okType: 'danger',
cancelText: t('取消'),
onOk() {
openSpinning();
withdraw(processId.value, drawNode.value)
.then((res) => {
if (res) {
notification.open({
type: 'success',
message: t('撤回'),
description: t('撤回成功')
});
setTimeout(() => {
bus.emit(FLOW_PROCESSED);
close();
}, 500);
} else {
notification.open({
type: 'error',
message: t('撤回'),
description: t('撤回失败')
});
}
})
.finally(() => {
closeSpinning();
});
},
onCancel() {}
});
},
handlefinish(btn) {
Modal.confirm({
title: () => '提示',
content: () => `确定${btn.buttonName}吗?`,
onOk: () => {
onFinishClick();
}
});
},
handleflowBpmn() {
showFlowChart.value = true;
},
handletransfer() {
onTransferClick();
},
handleagree() {
onApproveClick();
},
handledisagree() {
onDisagreeClick();
},
handlereject() {
onDenyClick();
},
handleflowRecord() {
showRecord.value = true;
}
};
function closeFlowChart() {
showFlowChart.value = false;
}
function closeFlowRecord() {
showRecord.value = false;
}
function close() {
tabStore.closeTab(currentRoute, router);
if (window?.isOnlyShowContent == 'Y') {
window.close();
}
}
async function setDraft(needModal = true) {
let formData = [];
let params = {
taskId: taskId.value,
userId: userStore.getUserInfo.id
};
let res = await getDraftInfo('', taskId.value, userStore.getUserInfo.id);
if (res) {
draftData = JSON.parse(res.formData);
rDraftsId.value = res.id;
if (!needModal) return;
Modal.confirm({
title: () => '提示',
content: () => '确认使用草稿覆盖当前数据?',
onOk: async () => {
data.formInfos.forEach((item) => {
if (draftData && item.formConfig && item.formConfig.key && draftData[item.formConfig.key]) {
formData.push(item.formConfig.key ? draftData[item.formConfig.key] : {});
}
});
await formInformation.value.setFormData(formData);
}
});
}
}
async function saveDraft() {
if (customFormConfig.codeList.includes(curPageCode.value)) {
let value = await formInformation.value.handleSubmit();
if (value) {
setTimeout(() => {
bus.emit(FLOW_PROCESSED)
close();
}, 500);
}
return
}
try {
spinning.value = true;
let formModels = await formInformation.value.saveDraftData();
if (rDraftsId.value) {
let res = await putDraft(schemaId.value, formModels, rDraftsId.value, props.rowKeyData, processId.value, taskId.value);
showResult(res, '保存草稿');
} else {
let res = await postDraft(schemaId.value, formModels, props.rowKeyData, processId.value, taskId.value);
showResult(res, '保存草稿');
}
setDraft(false);
spinning.value = false;
} catch (error) {
spinning.value = false;
notificationError('保存草稿');
}
}
function showResult(res, title) {
if (res) {
notificationSuccess(title);
} else {
notificationError(title);
}
}
async function changeAddStepUser(ids, memberList) {
try {
spinning.value = true;
let idList = memberList.map((item) => {
return item.id;
});
let lastIdList = lastAddStepUser.value.split(',');
let addUserIds = idList.filter((item) => {
return lastIdList.indexOf(item) == -1;
});
let subUserIds = lastIdList.filter((item) => {
return idList.indexOf(item) == -1;
});
let data = {
addUserIds,
subUserIds,
schemaId: schemaId.value,
taskId: taskId.value
};
await postSetSignV2(data);
let res = await getApprovalProcess(unref(taskId), unref(processId));
initProcessData(res);
spinning.value = false;
message.success('操作成功');
} catch (e) {
message.error(e);
spinning.value = false;
message.error('操作失败,请稍后再试');
}
}
async function onApproveClick(isAutoAgreeBreak = false) {
try {
openSpinning();
if (!customFormConfig.codeList.includes(curPageCode.value)) {
if (!isAutoAgreeBreak) {
await submit();
}
if (!validateSuccess.value) {
closeSpinning();
return;
}
} else {
// await formInformation.value.handleSubmit(true);
validateSuccess.value = true
}
const params = await getApproveParams();
const nextNodes = await postGetNextTaskMaybeArrival(params);
approvalData.approvedType = ApproveType.AGREE;
approvalData.approvedResult = ApproveCode.AGREE;
//如果是自动同意触发的关闭弹层的loading
if (isAutoAgreeBreak) {
opinionDlg.value.stopLoading();
}
closeSpinning();
opinionDlg.value.toggleDialog({
action: 'agree',
nextNodes,
callback: (args) => {
approvalData.approvedContent = args.opinion;
approvalData.nextTaskUser = args.nextTaskUser;
approvalData.isEnd = args.isEnd;
onFinish('approve');
}
});
} catch (e) {
console.error(e);
closeSpinning();
throw new Error(e);
}
}
async function onDisagreeClick() {
try {
openSpinning();
if (!customFormConfig.codeList.includes(curPageCode.value)) {
await submit();
if (!validateSuccess.value) {
closeSpinning();
return;
}
} else {
// await formInformation.value.handleSubmit(true);
validateSuccess.value = true
}
const params = await getApproveParams();
const nextNodes = await postGetNextTaskMaybeArrival(params);
approvalData.approvedType = ApproveType.DISAGREE;
approvalData.approvedResult = ApproveCode.DISAGREE;
closeSpinning();
opinionDlg.value.toggleDialog({
action: 'disagree',
nextNodes,
callback: (args) => {
approvalData.approvedContent = args.opinion;
onFinish('disagree');
}
});
} catch (e) {
console.error(e);
closeSpinning();
throw new Error(e);
}
}
async function onDenyClick() {
approvalData.approvedType = ApproveType.REJECT;
approvalData.approvedResult = ApproveCode.REJECT;
opinionDlg.value.toggleDialog({
action: 'reject',
processId: processId.value,
taskId: taskId.value,
callback: (args) => {
approvalData.approvedContent = args.opinion;
approvalData.rejectNodeActivityId = args.rejectNodeId;
approvalData.nextTaskUser = args.nextTaskUser;
onFinish('reject');
}
});
}
function onTransferClick() {
transferDlg.value.toggleDialog({
taskId: taskId.value,
callback: (args) => {
onTransfer(args);
}
});
}
function onTransfer({ taskId, userId }) {
transferDlg.value.validate().then(() => {
transferDlg.value.startLoading();
postTransfer(taskId, userId)
.then((res) => {
transferDlg.value.toggleDialog({
isClose: true
});
message.success('转办成功');
setTimeout(() => {
bus.emit(FLOW_PROCESSED);
close();
}, 500);
})
.catch((err) => {
message.error('转办失败');
transferDlg.value.toggleDialog({
isClose: true
});
});
});
}
function onTransferFlowFail() {
transferDlg.value.stopLoading();
}
async function onFinishClick() {
approvalData.approvedType = ApproveType.FINISH;
approvalData.approvedResult = ApproveCode.FINISH;
onFinish('finish');
}
function flowSuccess() {
opinionDlg.value.toggleDialog({
isClose: true
});
message.success('操作成功');
setTimeout(() => {
bus.emit(FLOW_PROCESSED);
close();
}, 500);
}
function flowFail() {
opinionDlg.value.stopLoading();
}
function reset() {
approvalData.isAddOrSubSign = false;
approvalData.stampInfo = {
stampId: '',
password: ''
};
approvalData.buttonConfigs = [];
approvalData.approvedType = ApproveType.AGREE;
approvalData.approvedContent = '';
approvalData.rejectNodeActivityId = '';
approvalData.rejectNodeActivityIds = [];
approvalData.circulateConfigs = [];
}
function setBtnStatus() {
let btnConfigs = approvalData.buttonConfigs;
let draftBtn = btnConfigs.find((item) => item.buttonCode === ApproveCode.DRAFT);
if (draftBtn && rDraftsId.value) {
btnConfigs.push({
...draftBtn,
buttonName: t('从草稿导入'),
buttonCode: 'setDraft',
approveType: ApproveType.DRAFT,
index: 1
});
}
// 如果审批已完成,且没有保存按钮
if (rQuery.status=='COMPLETED') {
btnConfigs =[{
buttonName: t('保存'),
buttonCode: 'draft',
approveType: ApproveType.DRAFT,
buttonType: 0
}];
}
btnConfigs.forEach((btn) => {
const index = btn.index;
const buttonGroup = btn?.buttonGroup;
if (buttonGroup) {
if (!buttonMap.value[buttonGroup]) {
buttonMap.value[buttonGroup] = [];
}
if (showButton(btn)) {
buttonMap.value[buttonGroup].push(btn);
}
} else {
if (showButton(btn)) {
buttonMap.value['normal'].push(btn);
}
}
for (let key in buttonMap.value) {
buttonMap.value[key].sort((a, b) => {
let aIndex = a?.index || 0;
let bIndex = b?.index || 0;
return aIndex - bIndex;
});
}
});
}
function getTaskRecords() {
if (data?.taskApproveOpinions?.length) {
return data.taskApproveOpinions || [];
}
}
const curPageCode = ref()
onMounted(async () => {
try {
let res = await getApprovalProcess(unref(taskId), unref(processId));
curPageCode.value = res?.schemaInfo?.code
initProcessData(res);
await getBackNode();
processInfo.value = res;
const title = res?.schemaInfo?.name;
if (title) {
const tabPrefix = readonly.value ? '查看' : '审批';
tabStore.changeTitle(fullPath, `${tabPrefix}${title}`);
}
if (taskId.value) {
let ids = '';
res.currentTaskAssignees[res.taskInfo.taskDefinitionKey].forEach((item, index) => {
ids = `${ids}${index == 0 ? '' : ','}${item.assigneeIdStr}`;
});
addStepUser.value = ids;
lastAddStepUser.value = ids;
}
if (res.buttonConfigs) {
approvalData.buttonConfigs = res.buttonConfigs;
setBtnStatus();
}
if (!readonly.value) {
if (res.relationTasks) {
data.predecessorTasks = res.relationTasks;
}
if (res.isAddOrSubSign) {
approvalData.isAddOrSubSign = res.isAddOrSubSign;
}
approvalData.approvedType = ApproveType.AGREE;
approvedType.value = ApproveType.AGREE;
approvalData.approvedContent = '';
approvalData.rejectNodeActivityId = '';
approvalData.rejectNodeActivityIds = [];
approvalData.circulateConfigs = [];
}
renderKey.value = Math.random() + '';
setDraft();
} catch (error) {}
});
async function getBackNode() {
await getDrawNode(processId.value).then((res) => {
if (res.length) {
drawNode.value = res[0].activityId;
} else {
drawNode.value = '';
}
});
}
async function submit() {
data.submitLoading = true;
validateSuccess.value = false;
try {
let validateForms = await formInformation.value.validateForm();
if (validateForms.length > 0) {
let successValidate = validateForms.filter((ele) => {
return ele.validate;
});
if (successValidate.length == validateForms.length) {
validateSuccess.value = true;
data.submitLoading = false;
} else {
data.submitLoading = false;
notificationError(t('审批流程'), t('表单校验未通过'));
}
}
} catch (error) {
data.submitLoading = false;
notificationError(t('审批流程'), t('审批流程失败'));
}
}
function getUploadFileFolderIds(formModels) {
let fileFolderIds = [];
let uploadComponentIds = formInformation.value.getUploadComponentIds();
uploadComponentIds.forEach((ids) => {
if (ids.includes(separator)) {
let arr = ids.split(separator);
if (arr.length == 2 && formModels[arr[0]][arr[1]]) {
fileFolderIds.push(formModels[arr[0]][arr[1]]);
} else if (arr.length == 3 && formModels[arr[0]][arr[1]] && Array.isArray(formModels[arr[0]][arr[1]])) {
formModels[arr[0]][arr[1]].forEach((o) => {
fileFolderIds.push(o[arr[2]]);
});
}
}
});
return fileFolderIds;
}
async function getApproveParams() {
try {
let formModels = {}
let system = {}
let fileFolderIds = []
if (!customFormConfig.codeList.includes(curPageCode.value)) {
let formModels = await formInformation.value.getFormModels();
let system = formInformation.value.getSystemType();
let fileFolderIds = getUploadFileFolderIds(formModels);
} else {
let value = await formInformation.value.getFormValue();
let key = data.formInfos[0]?.formConfig?.key
formModels[key] = value
system[key] = false
fileFolderIds = []
}
return {
approvedType: approvalData.approvedType,
approvedResult: approvalData.approvedResult, // approvalData.approvedType 审批结果 如果为 4 就需要传buttonCode
approvedContent: approvalData.approvedContent,
formData: formModels,
rejectNodeActivityId: approvalData.rejectNodeActivityId,
taskId: taskId.value,
fileFolderIds,
circulateConfigs: approvalData.circulateConfigs,
/*stampId: values.stampId,
stampPassword: values.password,*/
isOldSystem: system,
isEnd: approvalData.isEnd,
nextTaskUser: approvalData.nextTaskUser
};
} catch (e) {
console.error(e);
}
}
async function onFinish(values) {
try {
if (validateSuccess.value || values === 'reject' || values === 'finish' || values === 'disagree') {
let params = await getApproveParams();
openSpinning()
let response = await postApproval(params);
closeSpinning()
// 判断返回值是否带有isAutoAgree 来判断中间是否有自动审批的业务如有再执行判断待审人员是否包含自己不包含就直接flowSuccess
if (checkIsAutoAgree(response)) return;
flowSuccess();
data.submitLoading = false;
}
} catch (error) {
closeSpinning()
flowFail();
throw new Error(error);
}
}
/**
* 判断该次审核是否触发自动同意事务并且检验返回得task 是否是自身作为被审需要弹框再次审核
* @param response
*/
function checkIsAutoAgree(response) {
if (
response != null &&
response.length != 0 &&
response[0].isAutoAgree == true && //
response[0].approveUserIds.includes(userStore.getUserInfo.id)
) {
// 注入新得taskId
taskId.value = response[0].taskId;
data.submitLoading = false;
onApproveClick(true);
return true;
} else {
return false;
}
}
function openSpinning() {
spinning.value = true;
}
function closeSpinning() {
spinning.value = false;
}
</script>
<style lang="less" scoped>
.flow-record-box {
height: 500px;
overflow: auto;
}
</style>