feat: [BPM 工作流] Simple 模型 - 流程设计校验
parent
9ceb1cc63c
commit
db10830bbb
|
@ -11,9 +11,10 @@ import type { SystemUserApi } from '#/api/system/user';
|
||||||
|
|
||||||
import { inject, onMounted, provide, ref, watch } from 'vue';
|
import { inject, onMounted, provide, ref, watch } from 'vue';
|
||||||
|
|
||||||
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
import { handleTree } from '@vben/utils';
|
import { handleTree } from '@vben/utils';
|
||||||
|
|
||||||
import { Button, Modal } from 'ant-design-vue';
|
import { Button } from 'ant-design-vue';
|
||||||
|
|
||||||
import { getFormDetail } from '#/api/bpm/form';
|
import { getFormDetail } from '#/api/bpm/form';
|
||||||
import { getUserGroupSimpleList } from '#/api/bpm/userGroup';
|
import { getUserGroupSimpleList } from '#/api/bpm/userGroup';
|
||||||
|
@ -112,8 +113,11 @@ provide('tasks', []);
|
||||||
provide('processInstance', {});
|
provide('processInstance', {});
|
||||||
const processNodeTree = ref<SimpleFlowNode | undefined>();
|
const processNodeTree = ref<SimpleFlowNode | undefined>();
|
||||||
provide('processNodeTree', processNodeTree);
|
provide('processNodeTree', processNodeTree);
|
||||||
const errorDialogVisible = ref(false);
|
|
||||||
const errorNodes: SimpleFlowNode[] = [];
|
// 创建错误提示弹窗
|
||||||
|
const [ErrorModal, errorModalApi] = useVbenModal({
|
||||||
|
fullscreenButton: false,
|
||||||
|
});
|
||||||
|
|
||||||
// 添加更新模型的方法
|
// 添加更新模型的方法
|
||||||
const updateModel = () => {
|
const updateModel = () => {
|
||||||
|
@ -122,6 +126,7 @@ const updateModel = () => {
|
||||||
name: '发起人',
|
name: '发起人',
|
||||||
type: NodeType.START_USER_NODE,
|
type: NodeType.START_USER_NODE,
|
||||||
id: NodeId.START_USER_NODE_ID,
|
id: NodeId.START_USER_NODE_ID,
|
||||||
|
showText: '默认配置',
|
||||||
childNode: {
|
childNode: {
|
||||||
id: NodeId.END_EVENT_NODE_ID,
|
id: NodeId.END_EVENT_NODE_ID,
|
||||||
name: '结束',
|
name: '结束',
|
||||||
|
@ -151,7 +156,7 @@ const saveSimpleFlowModel = async (
|
||||||
/**
|
/**
|
||||||
* 校验节点设置。 暂时以 showText 为空 未节点错误配置
|
* 校验节点设置。 暂时以 showText 为空 未节点错误配置
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line unused-imports/no-unused-vars, no-unused-vars
|
|
||||||
const validateNode = (
|
const validateNode = (
|
||||||
node: SimpleFlowNode | undefined,
|
node: SimpleFlowNode | undefined,
|
||||||
errorNodes: SimpleFlowNode[],
|
errorNodes: SimpleFlowNode[],
|
||||||
|
@ -161,34 +166,23 @@ const validateNode = (
|
||||||
if (type === NodeType.END_EVENT_NODE) {
|
if (type === NodeType.END_EVENT_NODE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type === NodeType.START_USER_NODE) {
|
|
||||||
// 发起人节点暂时不用校验,直接校验孩子节点
|
|
||||||
validateNode(node.childNode, errorNodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
type === NodeType.USER_TASK_NODE ||
|
|
||||||
type === NodeType.COPY_TASK_NODE ||
|
|
||||||
type === NodeType.CONDITION_NODE
|
|
||||||
) {
|
|
||||||
if (!showText) {
|
|
||||||
errorNodes.push(node);
|
|
||||||
}
|
|
||||||
validateNode(node.childNode, errorNodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
type === NodeType.CONDITION_BRANCH_NODE ||
|
type === NodeType.CONDITION_BRANCH_NODE ||
|
||||||
type === NodeType.PARALLEL_BRANCH_NODE ||
|
type === NodeType.PARALLEL_BRANCH_NODE ||
|
||||||
type === NodeType.INCLUSIVE_BRANCH_NODE
|
type === NodeType.INCLUSIVE_BRANCH_NODE
|
||||||
) {
|
) {
|
||||||
// 分支节点
|
// 1. 分支节点, 先校验各个分支
|
||||||
// 1. 先校验各个分支
|
|
||||||
conditionNodes?.forEach((item) => {
|
conditionNodes?.forEach((item) => {
|
||||||
validateNode(item, errorNodes);
|
validateNode(item, errorNodes);
|
||||||
});
|
});
|
||||||
// 2. 校验孩子节点
|
// 2. 校验孩子节点
|
||||||
validateNode(node.childNode, errorNodes);
|
validateNode(node.childNode, errorNodes);
|
||||||
|
} else {
|
||||||
|
if (!showText) {
|
||||||
|
errorNodes.push(node);
|
||||||
|
}
|
||||||
|
validateNode(node.childNode, errorNodes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -220,38 +214,40 @@ onMounted(async () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const simpleProcessModelRef = ref();
|
const validate = async () => {
|
||||||
|
const errorNodes: SimpleFlowNode[] = [];
|
||||||
defineExpose({});
|
validateNode(processNodeTree.value, errorNodes);
|
||||||
|
if (errorNodes.length === 0) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// 设置错误节点数据并打开弹窗
|
||||||
|
errorModalApi.setData(errorNodes);
|
||||||
|
errorModalApi.open();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
defineExpose({ validate });
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div v-loading="loading">
|
<div v-loading="loading">
|
||||||
<SimpleProcessModel
|
<SimpleProcessModel
|
||||||
ref="simpleProcessModelRef"
|
|
||||||
v-if="processNodeTree"
|
v-if="processNodeTree"
|
||||||
:flow-node="processNodeTree"
|
:flow-node="processNodeTree"
|
||||||
:readonly="false"
|
:readonly="false"
|
||||||
@save="saveSimpleFlowModel"
|
@save="saveSimpleFlowModel"
|
||||||
/>
|
/>
|
||||||
<Modal
|
<ErrorModal title="流程设计校验不通过" class="w-[600px]">
|
||||||
v-model="errorDialogVisible"
|
<div class="mb-2 text-base">以下节点配置不完善,请修改相关配置</div>
|
||||||
title="保存失败"
|
|
||||||
width="400"
|
|
||||||
:fullscreen="false"
|
|
||||||
>
|
|
||||||
<div class="mb-2">以下节点内容不完善,请修改后保存</div>
|
|
||||||
<div
|
<div
|
||||||
class="b-rounded-1 line-height-normal mb-3 bg-gray-100 p-2"
|
class="mb-3 rounded-md bg-gray-100 p-2 text-sm"
|
||||||
v-for="(item, index) in errorNodes"
|
v-for="(item, index) in errorModalApi.getData()"
|
||||||
:key="index"
|
:key="index"
|
||||||
>
|
>
|
||||||
{{ item.name }} : {{ NODE_DEFAULT_TEXT.get(item.type) }}
|
{{ item.name }} : {{ NODE_DEFAULT_TEXT.get(item.type) }}
|
||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<Button type="primary" @click="errorDialogVisible = false">
|
<Button type="primary" @click="errorModalApi.close()">知道了</Button>
|
||||||
知道了
|
|
||||||
</Button>
|
|
||||||
</template>
|
</template>
|
||||||
</Modal>
|
</ErrorModal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -648,7 +648,8 @@
|
||||||
width: 80px;
|
width: 80px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
color: #212121;
|
color: #212121;
|
||||||
border: 2px solid #fafafa;
|
background-color: #fff;
|
||||||
|
border: 2px solid transparent;
|
||||||
border-radius: 30px;
|
border-radius: 30px;
|
||||||
box-shadow: 0 1px 5px 0 rgb(10 30 65 / 8%);
|
box-shadow: 0 1px 5px 0 rgb(10 30 65 / 8%);
|
||||||
|
|
||||||
|
|
|
@ -216,7 +216,8 @@ const validateAllSteps = async () => {
|
||||||
await validateBasic();
|
await validateBasic();
|
||||||
} catch {
|
} catch {
|
||||||
currentStep.value = 0;
|
currentStep.value = 0;
|
||||||
throw new Error('请完善基本信息');
|
message.warning('请完善基本信息');
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 表单设计校验
|
// 表单设计校验
|
||||||
|
@ -224,25 +225,19 @@ const validateAllSteps = async () => {
|
||||||
await validateForm();
|
await validateForm();
|
||||||
} catch {
|
} catch {
|
||||||
currentStep.value = 1;
|
currentStep.value = 1;
|
||||||
throw new Error('请完善自定义表单信息');
|
message.warning('请完善自定义表单信息');
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 流程设计校验 TODO
|
// 流程设计校验
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await validateProcess();
|
await validateProcess();
|
||||||
} catch {
|
} catch {
|
||||||
currentStep.value = 2;
|
currentStep.value = 2;
|
||||||
throw new Error('请设计流程');
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 表单设计校验
|
// TODO 更多设置校验
|
||||||
try {
|
|
||||||
await validateProcess();
|
|
||||||
} catch {
|
|
||||||
currentStep.value = 2;
|
|
||||||
throw new Error('请设计流程');
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
@ -251,7 +246,10 @@ const validateAllSteps = async () => {
|
||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
try {
|
try {
|
||||||
// 保存前校验所有步骤的数据
|
// 保存前校验所有步骤的数据
|
||||||
await validateAllSteps();
|
const result = await validateAllSteps();
|
||||||
|
if (!result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 更新表单数据
|
// 更新表单数据
|
||||||
const modelData = {
|
const modelData = {
|
||||||
|
@ -297,7 +295,7 @@ const handleSave = async () => {
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error('保存失败:', error);
|
console.error('保存失败:', error);
|
||||||
message.warning(error.message || '请完善所有步骤的必填信息');
|
// message.warning(error.msg || '请完善所有步骤的必填信息');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -347,23 +345,13 @@ const handleStepClick = async (index: number) => {
|
||||||
if (index !== 2) {
|
if (index !== 2) {
|
||||||
await validateProcess();
|
await validateProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 切换步骤
|
// 切换步骤
|
||||||
currentStep.value = index;
|
currentStep.value = index;
|
||||||
|
|
||||||
// 如果切换到流程设计步骤,等待组件渲染完成后刷新设计器
|
|
||||||
if (index === 2) {
|
|
||||||
// TODO 后续加
|
|
||||||
// await nextTick();
|
|
||||||
// // 等待更长时间确保组件完全初始化
|
|
||||||
// await new Promise((resolve) => setTimeout(resolve, 200));
|
|
||||||
// if (processDesignRef.value?.refresh) {
|
|
||||||
// await processDesignRef.value.refresh();
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('步骤切换失败:', error);
|
console.error('步骤切换失败:', error);
|
||||||
message.warning('请先完善当前步骤必填信息');
|
if (currentStep.value !== 2) {
|
||||||
|
message.warning('请先完善当前步骤必填信息');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
|
|
||||||
import { computed, inject, nextTick } from 'vue';
|
import { computed, inject, nextTick, ref } from 'vue';
|
||||||
|
|
||||||
import { BpmModelType } from '#/utils';
|
import { BpmModelType } from '#/utils';
|
||||||
|
|
||||||
|
@ -13,12 +13,21 @@ const modelData = defineModel<any>();
|
||||||
|
|
||||||
const processData = inject('processData') as Ref;
|
const processData = inject('processData') as Ref;
|
||||||
|
|
||||||
|
const simpleDesign = ref();
|
||||||
|
|
||||||
/** 表单校验 */
|
/** 表单校验 */
|
||||||
const validate = async () => {
|
const validate = async () => {
|
||||||
// 获取最新的流程数据
|
// 获取最新的流程数据
|
||||||
if (!processData.value) {
|
if (!processData.value) {
|
||||||
throw new Error('请设计流程');
|
throw new Error('请设计流程');
|
||||||
}
|
}
|
||||||
|
if (modelData.value.type === BpmModelType.SIMPLE) {
|
||||||
|
// 简易设计器校验
|
||||||
|
const validateResult = await simpleDesign.value?.validateConfig();
|
||||||
|
if (!validateResult) {
|
||||||
|
throw new Error('请完善设计配置');
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
/** 处理设计器保存成功 */
|
/** 处理设计器保存成功 */
|
||||||
|
@ -41,9 +50,7 @@ const handleDesignSuccess = async (data?: any) => {
|
||||||
const showDesigner = computed(() => {
|
const showDesigner = computed(() => {
|
||||||
return Boolean(modelData.value?.key && modelData.value?.name);
|
return Boolean(modelData.value?.key && modelData.value?.name);
|
||||||
});
|
});
|
||||||
defineExpose({
|
defineExpose({ validate });
|
||||||
validate,
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="h-full">
|
<div class="h-full">
|
||||||
|
@ -61,6 +68,7 @@ defineExpose({
|
||||||
:start-user-ids="modelData.startUserIds"
|
:start-user-ids="modelData.startUserIds"
|
||||||
:start-dept-ids="modelData.startDeptIds"
|
:start-dept-ids="modelData.startDeptIds"
|
||||||
@success="handleDesignSuccess"
|
@success="handleDesignSuccess"
|
||||||
|
ref="simpleDesign"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -17,12 +17,17 @@ defineProps<{
|
||||||
const emit = defineEmits(['success']);
|
const emit = defineEmits(['success']);
|
||||||
const designerRef = ref();
|
const designerRef = ref();
|
||||||
|
|
||||||
// 修改成功回调
|
/** 保存成功回调 */
|
||||||
const handleSuccess = (data?: any) => {
|
const handleSuccess = (data?: any) => {
|
||||||
if (data) {
|
if (data) {
|
||||||
emit('success', data);
|
emit('success', data);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
/** 设计器配置校验 */
|
||||||
|
const validateConfig = async () => {
|
||||||
|
return await designerRef.value.validate();
|
||||||
|
};
|
||||||
|
defineExpose({ validateConfig });
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<ContentWrap :body-style="{ padding: '20px 16px' }">
|
<ContentWrap :body-style="{ padding: '20px 16px' }">
|
||||||
|
|
Loading…
Reference in New Issue