!130 Merge remote-tracking branch 'yudao/dev' into dev

Merge pull request !130 from Jason/dev
pull/131/head
xingyu 2025-06-06 02:35:55 +00:00 committed by Gitee
commit 28807fa61b
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
25 changed files with 767 additions and 302 deletions

View File

@ -27,14 +27,13 @@ import {
TreeSelect,
} from 'ant-design-vue';
import { BpmModelFormType } from '#/utils';
import { BpmModelFormType, BpmNodeTypeEnum } from '#/utils';
import {
CANDIDATE_STRATEGY,
CandidateStrategy,
FieldPermissionType,
MULTI_LEVEL_DEPT,
NodeType,
} from '../../consts';
import {
useFormFieldsPermission,
@ -77,7 +76,7 @@ const currentNode = useWatchNode(props);
//
const { nodeName, showInput, clickIcon, blurEvent } = useNodeName(
NodeType.COPY_TASK_NODE,
BpmNodeTypeEnum.COPY_TASK_NODE,
);
// Tab
@ -137,7 +136,7 @@ const {
getShowText,
handleCandidateParam,
parseCandidateParam,
} = useNodeForm(NodeType.COPY_TASK_NODE);
} = useNodeForm(BpmNodeTypeEnum.COPY_TASK_NODE);
const configForm = tempConfigForm as Ref<CopyTaskFormType>;
//

View File

@ -22,10 +22,11 @@ import {
SelectOption,
} from 'ant-design-vue';
import { BpmNodeTypeEnum } from '#/utils';
import {
DELAY_TYPE,
DelayTypeEnum,
NodeType,
TIME_UNIT_TYPES,
TimeUnitType,
} from '../../consts';
@ -45,7 +46,7 @@ const props = defineProps({
const currentNode = useWatchNode(props);
//
const { nodeName, showInput, clickIcon, blurEvent } = useNodeName(
NodeType.DELAY_TIMER_NODE,
BpmNodeTypeEnum.DELAY_TIMER_NODE,
);
//
const formRef = ref(); // Ref

View File

@ -21,7 +21,9 @@ import {
SelectOption,
} from 'ant-design-vue';
import { ConditionType, NodeType } from '../../consts';
import { BpmNodeTypeEnum } from '#/utils';
import { ConditionType } from '../../consts';
import { useNodeName, useWatchNode } from '../../helpers';
import Condition from './modules/condition.vue';
@ -40,7 +42,7 @@ const processNodeTree = inject<Ref<SimpleFlowNode>>('processNodeTree');
const currentNode = useWatchNode(props);
/** 节点名称 */
const { nodeName, showInput, clickIcon, blurEvent } = useNodeName(
NodeType.ROUTER_BRANCH_NODE,
BpmNodeTypeEnum.ROUTER_BRANCH_NODE,
);
const routerGroups = ref<RouterSetting[]>([]);
const nodeOptions = ref<any[]>([]);
@ -176,15 +178,15 @@ function getRouterNode(node: any) {
while (true) {
if (!node) break;
if (
node.type !== NodeType.ROUTER_BRANCH_NODE &&
node.type !== NodeType.CONDITION_NODE
node.type !== BpmNodeTypeEnum.ROUTER_BRANCH_NODE &&
node.type !== BpmNodeTypeEnum.CONDITION_NODE
) {
nodeOptions.value.push({
label: node.name,
value: node.id,
});
}
if (!node.childNode || node.type === NodeType.END_EVENT_NODE) {
if (!node.childNode || node.type === BpmNodeTypeEnum.END_EVENT_NODE) {
break;
}
if (node.conditionNodes && node.conditionNodes.length > 0) {

View File

@ -23,13 +23,9 @@ import {
TypographyText,
} from 'ant-design-vue';
import { BpmModelFormType } from '#/utils';
import { BpmModelFormType, BpmNodeTypeEnum } from '#/utils';
import {
FieldPermissionType,
NodeType,
START_USER_BUTTON_SETTING,
} from '../../consts';
import { FieldPermissionType, START_USER_BUTTON_SETTING } from '../../consts';
import {
useFormFieldsPermission,
useNodeName,
@ -57,7 +53,7 @@ const deptOptions = inject<Ref<SystemDeptApi.Dept[]>>('deptList');
const currentNode = useWatchNode(props);
//
const { nodeName, showInput, clickIcon, blurEvent } = useNodeName(
NodeType.COPY_TASK_NODE,
BpmNodeTypeEnum.START_USER_NODE,
);
// Tab
const activeTabName = ref('user');

View File

@ -29,9 +29,10 @@ import {
Tag,
} from 'ant-design-vue';
import { BpmNodeTypeEnum } from '#/utils';
import {
DEFAULT_CONDITION_GROUP_VALUE,
NodeType,
TRIGGER_TYPES,
TriggerTypeEnum,
} from '../../consts';
@ -72,7 +73,7 @@ const [Drawer, drawerApi] = useVbenDrawer({
const currentNode = useWatchNode(props);
//
const { nodeName, showInput, clickIcon, blurEvent } = useNodeName(
NodeType.TRIGGER_NODE,
BpmNodeTypeEnum.TRIGGER_NODE,
);
//
const formRef = ref(); // Ref

View File

@ -34,7 +34,11 @@ import {
TypographyText,
} from 'ant-design-vue';
import { BpmModelFormType } from '#/utils';
import {
BpmModelFormType,
BpmNodeTypeEnum,
ProcessVariableEnum,
} from '#/utils';
import {
APPROVE_METHODS,
@ -49,9 +53,7 @@ import {
DEFAULT_BUTTON_SETTING,
FieldPermissionType,
MULTI_LEVEL_DEPT,
NodeType,
OPERATION_BUTTON_NAME,
ProcessVariableEnum,
REJECT_HANDLER_TYPES,
RejectHandlerType,
TIME_UNIT_TYPES,
@ -113,7 +115,7 @@ const [Drawer, drawerApi] = useVbenDrawer({
//
const { nodeName, showInput, clickIcon, blurEvent } = useNodeName(
NodeType.USER_TASK_NODE,
BpmNodeTypeEnum.USER_TASK_NODE,
);
// Tab
@ -245,7 +247,9 @@ const userTaskListenerRef = ref();
/** 节点类型名称 */
const nodeTypeName = computed(() => {
return currentNode.value.type === NodeType.TRANSACTOR_NODE ? '办理' : '审批';
return currentNode.value.type === BpmNodeTypeEnum.TRANSACTOR_NODE
? '办理'
: '审批';
});
/** 校验节点配置 */
@ -407,7 +411,7 @@ function showUserTaskNodeConfig(node: SimpleFlowNode) {
// 3.
buttonsSetting.value =
cloneDeep(node.buttonsSetting) ||
(node.type === NodeType.TRANSACTOR_NODE
(node.type === BpmNodeTypeEnum.TRANSACTOR_NODE
? TRANSACTOR_DEFAULT_BUTTON_SETTING
: DEFAULT_BUTTON_SETTING);
// 4.
@ -595,7 +599,7 @@ onMounted(() => {
</div>
</template>
<div
v-if="currentNode.type === NodeType.USER_TASK_NODE"
v-if="currentNode.type === BpmNodeTypeEnum.USER_TASK_NODE"
class="mb-3 flex items-center"
>
<span class="mr-3 text-[16px]">审批类型 :</span>
@ -860,7 +864,7 @@ onMounted(() => {
</RadioGroup>
</FormItem>
<div v-if="currentNode.type === NodeType.USER_TASK_NODE">
<div v-if="currentNode.type === BpmNodeTypeEnum.USER_TASK_NODE">
<Divider content-position="left">审批人拒绝时</Divider>
<FormItem name="rejectHandlerType">
<RadioGroup
@ -902,7 +906,7 @@ onMounted(() => {
</FormItem>
</div>
<div v-if="currentNode.type === NodeType.USER_TASK_NODE">
<div v-if="currentNode.type === BpmNodeTypeEnum.USER_TASK_NODE">
<Divider content-position="left">审批人超时未处理时</Divider>
<FormItem
label="启用开关"
@ -1047,7 +1051,7 @@ onMounted(() => {
</Select>
</FormItem>
<div v-if="currentNode.type === NodeType.USER_TASK_NODE">
<div v-if="currentNode.type === BpmNodeTypeEnum.USER_TASK_NODE">
<Divider content-position="left">
审批人与提交人为同一人时
</Divider>
@ -1081,7 +1085,7 @@ onMounted(() => {
</FormItem>
</div>
<div v-if="currentNode.type === NodeType.USER_TASK_NODE">
<div v-if="currentNode.type === BpmNodeTypeEnum.USER_TASK_NODE">
<Divider content-position="left">审批意见</Divider>
<FormItem name="reasonRequire">
<Switch
@ -1096,7 +1100,7 @@ onMounted(() => {
</TabPane>
<TabPane
tab="操作按钮设置"
v-if="currentNode.type === NodeType.USER_TASK_NODE"
v-if="currentNode.type === BpmNodeTypeEnum.USER_TASK_NODE"
key="buttons"
>
<div class="p-1">

View File

@ -7,7 +7,9 @@ import { IconifyIcon } from '@vben/icons';
import { Input } from 'ant-design-vue';
import { NODE_DEFAULT_TEXT, NodeType } from '../../consts';
import { BpmNodeTypeEnum } from '#/utils';
import { NODE_DEFAULT_TEXT } from '../../consts';
import { useNodeName2, useTaskStatusClass, useWatchNode } from '../../helpers';
import CopyTaskNodeConfig from '../nodes-config/copy-task-node-config.vue';
import NodeHandler from './node-handler.vue';
@ -32,7 +34,7 @@ const currentNode = useWatchNode(props);
//
const { showInput, blurEvent, clickTitle } = useNodeName2(
currentNode,
NodeType.COPY_TASK_NODE,
BpmNodeTypeEnum.COPY_TASK_NODE,
);
const nodeSetting = ref();
@ -85,7 +87,7 @@ function deleteNode() {
{{ currentNode.showText }}
</div>
<div class="node-text" v-else>
{{ NODE_DEFAULT_TEXT.get(NodeType.COPY_TASK_NODE) }}
{{ NODE_DEFAULT_TEXT.get(BpmNodeTypeEnum.COPY_TASK_NODE) }}
</div>
<IconifyIcon v-if="!readonly" icon="ep:arrow-right-bold" />
</div>

View File

@ -7,7 +7,9 @@ import { IconifyIcon } from '@vben/icons';
import { Input } from 'ant-design-vue';
import { NODE_DEFAULT_TEXT, NodeType } from '../../consts';
import { BpmNodeTypeEnum } from '#/utils';
import { NODE_DEFAULT_TEXT } from '../../consts';
import { useNodeName2, useTaskStatusClass, useWatchNode } from '../../helpers';
import DelayTimerNodeConfig from '../nodes-config/delay-timer-node-config.vue';
import NodeHandler from './node-handler.vue';
@ -30,7 +32,7 @@ const currentNode = useWatchNode(props);
//
const { showInput, blurEvent, clickTitle } = useNodeName2(
currentNode,
NodeType.DELAY_TIMER_NODE,
BpmNodeTypeEnum.DELAY_TIMER_NODE,
);
const nodeSetting = ref();
@ -82,7 +84,7 @@ function deleteNode() {
{{ currentNode.showText }}
</div>
<div class="node-text" v-else>
{{ NODE_DEFAULT_TEXT.get(NodeType.DELAY_TIMER_NODE) }}
{{ NODE_DEFAULT_TEXT.get(BpmNodeTypeEnum.DELAY_TIMER_NODE) }}
</div>
<IconifyIcon v-if="!readonly" icon="ep:arrow-right-bold" />
</div>

View File

@ -8,11 +8,12 @@ import { cloneDeep, buildShortUUID as generateUUID } from '@vben/utils';
import { Button, Input } from 'ant-design-vue';
import { BpmNodeTypeEnum } from '#/utils';
import {
ConditionType,
DEFAULT_CONDITION_GROUP_VALUE,
NODE_DEFAULT_TEXT,
NodeType,
} from '../../consts';
import { getDefaultConditionNodeName, useTaskStatusClass } from '../../helpers';
import ConditionNodeConfig from '../nodes-config/condition-node-config.vue';
@ -90,7 +91,7 @@ function addCondition() {
id: `Flow_${generateUUID()}`,
name: `条件${len}`,
showText: '',
type: NodeType.CONDITION_NODE,
type: BpmNodeTypeEnum.CONDITION_NODE,
childNode: undefined,
conditionNodes: [],
conditionSetting: {
@ -138,7 +139,7 @@ function recursiveFindParentNode(
node: SimpleFlowNode,
nodeType: number,
) {
if (!node || node.type === NodeType.START_USER_NODE) {
if (!node || node.type === BpmNodeTypeEnum.START_USER_NODE) {
return;
}
if (node.type === nodeType) {
@ -210,7 +211,7 @@ function recursiveFindParentNode(
{{ item.showText }}
</div>
<div class="branch-node-text" v-else>
{{ NODE_DEFAULT_TEXT.get(NodeType.CONDITION_NODE) }}
{{ NODE_DEFAULT_TEXT.get(BpmNodeTypeEnum.CONDITION_NODE) }}
</div>
</div>
<div

View File

@ -8,11 +8,12 @@ import { cloneDeep, buildShortUUID as generateUUID } from '@vben/utils';
import { Button, Input } from 'ant-design-vue';
import { BpmNodeTypeEnum } from '#/utils';
import {
ConditionType,
DEFAULT_CONDITION_GROUP_VALUE,
NODE_DEFAULT_TEXT,
NodeType,
} from '../../consts';
import {
getDefaultInclusiveConditionNodeName,
@ -95,7 +96,7 @@ function addCondition() {
id: `Flow_${generateUUID()}`,
name: `包容条件${len}`,
showText: '',
type: NodeType.CONDITION_NODE,
type: BpmNodeTypeEnum.CONDITION_NODE,
childNode: undefined,
conditionNodes: [],
conditionSetting: {
@ -143,7 +144,7 @@ function recursiveFindParentNode(
node: SimpleFlowNode,
nodeType: number,
) {
if (!node || node.type === NodeType.START_USER_NODE) {
if (!node || node.type === BpmNodeTypeEnum.START_USER_NODE) {
return;
}
if (node.type === nodeType) {
@ -213,7 +214,7 @@ function recursiveFindParentNode(
{{ item.showText }}
</div>
<div class="branch-node-text" v-else>
{{ NODE_DEFAULT_TEXT.get(NodeType.CONDITION_NODE) }}
{{ NODE_DEFAULT_TEXT.get(BpmNodeTypeEnum.CONDITION_NODE) }}
</div>
</div>
<div

View File

@ -8,6 +8,8 @@ import { cloneDeep, buildShortUUID as generateUUID } from '@vben/utils';
import { message, Popover } from 'ant-design-vue';
import { BpmNodeTypeEnum } from '#/utils';
import {
ApproveMethodType,
AssignEmptyHandlerType,
@ -15,7 +17,6 @@ import {
ConditionType,
DEFAULT_CONDITION_GROUP_VALUE,
NODE_DEFAULT_NAME,
NodeType,
RejectHandlerType,
} from '../../consts';
@ -41,17 +42,21 @@ const readonly = inject<Boolean>('readonly'); // 是否只读
function addNode(type: number) {
//
if (
type === NodeType.PARALLEL_BRANCH_NODE &&
[NodeType.CONDITION_BRANCH_NODE, NodeType.INCLUSIVE_BRANCH_NODE].includes(
props.currentNode?.type,
)
type === BpmNodeTypeEnum.PARALLEL_BRANCH_NODE &&
[
BpmNodeTypeEnum.CONDITION_BRANCH_NODE,
BpmNodeTypeEnum.INCLUSIVE_BRANCH_NODE,
].includes(props.currentNode?.type)
) {
message.error('条件分支、包容分支后面,不允许直接添加并行分支');
return;
}
popoverShow.value = false;
if (type === NodeType.USER_TASK_NODE || type === NodeType.TRANSACTOR_NODE) {
if (
type === BpmNodeTypeEnum.USER_TASK_NODE ||
type === BpmNodeTypeEnum.TRANSACTOR_NODE
) {
const id = `Activity_${generateUUID()}`;
const data: SimpleFlowNode = {
id,
@ -83,20 +88,20 @@ function addNode(type: number) {
};
emits('update:childNode', data);
}
if (type === NodeType.COPY_TASK_NODE) {
if (type === BpmNodeTypeEnum.COPY_TASK_NODE) {
const data: SimpleFlowNode = {
id: `Activity_${generateUUID()}`,
name: NODE_DEFAULT_NAME.get(NodeType.COPY_TASK_NODE) as string,
name: NODE_DEFAULT_NAME.get(BpmNodeTypeEnum.COPY_TASK_NODE) as string,
showText: '',
type: NodeType.COPY_TASK_NODE,
type: BpmNodeTypeEnum.COPY_TASK_NODE,
childNode: props.childNode,
};
emits('update:childNode', data);
}
if (type === NodeType.CONDITION_BRANCH_NODE) {
if (type === BpmNodeTypeEnum.CONDITION_BRANCH_NODE) {
const data: SimpleFlowNode = {
name: '条件分支',
type: NodeType.CONDITION_BRANCH_NODE,
type: BpmNodeTypeEnum.CONDITION_BRANCH_NODE,
id: `GateWay_${generateUUID()}`,
childNode: props.childNode,
conditionNodes: [
@ -104,7 +109,7 @@ function addNode(type: number) {
id: `Flow_${generateUUID()}`,
name: '条件1',
showText: '',
type: NodeType.CONDITION_NODE,
type: BpmNodeTypeEnum.CONDITION_NODE,
childNode: undefined,
conditionSetting: {
defaultFlow: false,
@ -116,7 +121,7 @@ function addNode(type: number) {
id: `Flow_${generateUUID()}`,
name: '其它情况',
showText: '未满足其它条件时,将进入此分支',
type: NodeType.CONDITION_NODE,
type: BpmNodeTypeEnum.CONDITION_NODE,
childNode: undefined,
conditionSetting: {
defaultFlow: true,
@ -126,10 +131,10 @@ function addNode(type: number) {
};
emits('update:childNode', data);
}
if (type === NodeType.PARALLEL_BRANCH_NODE) {
if (type === BpmNodeTypeEnum.PARALLEL_BRANCH_NODE) {
const data: SimpleFlowNode = {
name: '并行分支',
type: NodeType.PARALLEL_BRANCH_NODE,
type: BpmNodeTypeEnum.PARALLEL_BRANCH_NODE,
id: `GateWay_${generateUUID()}`,
childNode: props.childNode,
conditionNodes: [
@ -137,24 +142,24 @@ function addNode(type: number) {
id: `Flow_${generateUUID()}`,
name: '并行1',
showText: '无需配置条件同时执行',
type: NodeType.CONDITION_NODE,
type: BpmNodeTypeEnum.CONDITION_NODE,
childNode: undefined,
},
{
id: `Flow_${generateUUID()}`,
name: '并行2',
showText: '无需配置条件同时执行',
type: NodeType.CONDITION_NODE,
type: BpmNodeTypeEnum.CONDITION_NODE,
childNode: undefined,
},
],
};
emits('update:childNode', data);
}
if (type === NodeType.INCLUSIVE_BRANCH_NODE) {
if (type === BpmNodeTypeEnum.INCLUSIVE_BRANCH_NODE) {
const data: SimpleFlowNode = {
name: '包容分支',
type: NodeType.INCLUSIVE_BRANCH_NODE,
type: BpmNodeTypeEnum.INCLUSIVE_BRANCH_NODE,
id: `GateWay_${generateUUID()}`,
childNode: props.childNode,
conditionNodes: [
@ -162,7 +167,7 @@ function addNode(type: number) {
id: `Flow_${generateUUID()}`,
name: '包容条件1',
showText: '',
type: NodeType.CONDITION_NODE,
type: BpmNodeTypeEnum.CONDITION_NODE,
childNode: undefined,
conditionSetting: {
defaultFlow: false,
@ -174,7 +179,7 @@ function addNode(type: number) {
id: `Flow_${generateUUID()}`,
name: '其它情况',
showText: '未满足其它条件时,将进入此分支',
type: NodeType.CONDITION_NODE,
type: BpmNodeTypeEnum.CONDITION_NODE,
childNode: undefined,
conditionSetting: {
defaultFlow: true,
@ -184,42 +189,42 @@ function addNode(type: number) {
};
emits('update:childNode', data);
}
if (type === NodeType.DELAY_TIMER_NODE) {
if (type === BpmNodeTypeEnum.DELAY_TIMER_NODE) {
const data: SimpleFlowNode = {
id: `Activity_${generateUUID()}`,
name: NODE_DEFAULT_NAME.get(NodeType.DELAY_TIMER_NODE) as string,
name: NODE_DEFAULT_NAME.get(BpmNodeTypeEnum.DELAY_TIMER_NODE) as string,
showText: '',
type: NodeType.DELAY_TIMER_NODE,
type: BpmNodeTypeEnum.DELAY_TIMER_NODE,
childNode: props.childNode,
};
emits('update:childNode', data);
}
if (type === NodeType.ROUTER_BRANCH_NODE) {
if (type === BpmNodeTypeEnum.ROUTER_BRANCH_NODE) {
const data: SimpleFlowNode = {
id: `GateWay_${generateUUID()}`,
name: NODE_DEFAULT_NAME.get(NodeType.ROUTER_BRANCH_NODE) as string,
name: NODE_DEFAULT_NAME.get(BpmNodeTypeEnum.ROUTER_BRANCH_NODE) as string,
showText: '',
type: NodeType.ROUTER_BRANCH_NODE,
type: BpmNodeTypeEnum.ROUTER_BRANCH_NODE,
childNode: props.childNode,
};
emits('update:childNode', data);
}
if (type === NodeType.TRIGGER_NODE) {
if (type === BpmNodeTypeEnum.TRIGGER_NODE) {
const data: SimpleFlowNode = {
id: `Activity_${generateUUID()}`,
name: NODE_DEFAULT_NAME.get(NodeType.TRIGGER_NODE) as string,
name: NODE_DEFAULT_NAME.get(BpmNodeTypeEnum.TRIGGER_NODE) as string,
showText: '',
type: NodeType.TRIGGER_NODE,
type: BpmNodeTypeEnum.TRIGGER_NODE,
childNode: props.childNode,
};
emits('update:childNode', data);
}
if (type === NodeType.CHILD_PROCESS_NODE) {
if (type === BpmNodeTypeEnum.CHILD_PROCESS_NODE) {
const data: SimpleFlowNode = {
id: `Activity_${generateUUID()}`,
name: NODE_DEFAULT_NAME.get(NodeType.CHILD_PROCESS_NODE) as string,
name: NODE_DEFAULT_NAME.get(BpmNodeTypeEnum.CHILD_PROCESS_NODE) as string,
showText: '',
type: NodeType.CHILD_PROCESS_NODE,
type: BpmNodeTypeEnum.CHILD_PROCESS_NODE,
childNode: props.childNode,
childProcessSetting: {
calledProcessDefinitionKey: '',
@ -247,7 +252,10 @@ function addNode(type: number) {
<Popover trigger="hover" placement="right" width="auto" v-if="!readonly">
<template #content>
<div class="handler-item-wrapper">
<div class="handler-item" @click="addNode(NodeType.USER_TASK_NODE)">
<div
class="handler-item"
@click="addNode(BpmNodeTypeEnum.USER_TASK_NODE)"
>
<div class="approve handler-item-icon">
<span class="iconfont icon-approve icon-size"></span>
</div>
@ -255,14 +263,17 @@ function addNode(type: number) {
</div>
<div
class="handler-item"
@click="addNode(NodeType.TRANSACTOR_NODE)"
@click="addNode(BpmNodeTypeEnum.TRANSACTOR_NODE)"
>
<div class="transactor handler-item-icon">
<span class="iconfont icon-transactor icon-size"></span>
</div>
<div class="handler-item-text">办理人</div>
</div>
<div class="handler-item" @click="addNode(NodeType.COPY_TASK_NODE)">
<div
class="handler-item"
@click="addNode(BpmNodeTypeEnum.COPY_TASK_NODE)"
>
<div class="handler-item-icon copy">
<span class="iconfont icon-size icon-copy"></span>
</div>
@ -270,7 +281,7 @@ function addNode(type: number) {
</div>
<div
class="handler-item"
@click="addNode(NodeType.CONDITION_BRANCH_NODE)"
@click="addNode(BpmNodeTypeEnum.CONDITION_BRANCH_NODE)"
>
<div class="handler-item-icon condition">
<span class="iconfont icon-size icon-exclusive"></span>
@ -279,7 +290,7 @@ function addNode(type: number) {
</div>
<div
class="handler-item"
@click="addNode(NodeType.PARALLEL_BRANCH_NODE)"
@click="addNode(BpmNodeTypeEnum.PARALLEL_BRANCH_NODE)"
>
<div class="handler-item-icon parallel">
<span class="iconfont icon-size icon-parallel"></span>
@ -288,7 +299,7 @@ function addNode(type: number) {
</div>
<div
class="handler-item"
@click="addNode(NodeType.INCLUSIVE_BRANCH_NODE)"
@click="addNode(BpmNodeTypeEnum.INCLUSIVE_BRANCH_NODE)"
>
<div class="handler-item-icon inclusive">
<span class="iconfont icon-size icon-inclusive"></span>
@ -297,7 +308,7 @@ function addNode(type: number) {
</div>
<div
class="handler-item"
@click="addNode(NodeType.DELAY_TIMER_NODE)"
@click="addNode(BpmNodeTypeEnum.DELAY_TIMER_NODE)"
>
<div class="handler-item-icon delay">
<span class="iconfont icon-size icon-delay"></span>
@ -306,14 +317,17 @@ function addNode(type: number) {
</div>
<div
class="handler-item"
@click="addNode(NodeType.ROUTER_BRANCH_NODE)"
@click="addNode(BpmNodeTypeEnum.ROUTER_BRANCH_NODE)"
>
<div class="handler-item-icon router">
<span class="iconfont icon-size icon-router"></span>
</div>
<div class="handler-item-text">路由分支</div>
</div>
<div class="handler-item" @click="addNode(NodeType.TRIGGER_NODE)">
<div
class="handler-item"
@click="addNode(BpmNodeTypeEnum.TRIGGER_NODE)"
>
<div class="handler-item-icon trigger">
<span class="iconfont icon-size icon-trigger"></span>
</div>
@ -321,7 +335,7 @@ function addNode(type: number) {
</div>
<div
class="handler-item"
@click="addNode(NodeType.CHILD_PROCESS_NODE)"
@click="addNode(BpmNodeTypeEnum.CHILD_PROCESS_NODE)"
>
<div class="handler-item-icon child-process">
<span class="iconfont icon-size icon-child-process"></span>

View File

@ -8,7 +8,9 @@ import { buildShortUUID as generateUUID } from '@vben/utils';
import { Button, Input } from 'ant-design-vue';
import { NODE_DEFAULT_TEXT, NodeType } from '../../consts';
import { BpmNodeTypeEnum } from '#/utils';
import { NODE_DEFAULT_TEXT } from '../../consts';
import { useTaskStatusClass } from '../../helpers';
import ProcessNodeTree from '../process-node-tree.vue';
import NodeHandler from './node-handler.vue';
@ -70,7 +72,7 @@ function addCondition() {
id: `Flow_${generateUUID()}`,
name: `并行${len}`,
showText: '无需配置条件同时执行',
type: NodeType.CONDITION_NODE,
type: BpmNodeTypeEnum.CONDITION_NODE,
childNode: undefined,
conditionNodes: [],
};
@ -97,7 +99,7 @@ function recursiveFindParentNode(
node: SimpleFlowNode,
nodeType: number,
) {
if (!node || node.type === NodeType.START_USER_NODE) {
if (!node || node.type === BpmNodeTypeEnum.START_USER_NODE) {
return;
}
if (node.type === nodeType) {
@ -168,7 +170,7 @@ function recursiveFindParentNode(
{{ item.showText }}
</div>
<div class="branch-node-text" v-else>
{{ NODE_DEFAULT_TEXT.get(NodeType.CONDITION_NODE) }}
{{ NODE_DEFAULT_TEXT.get(BpmNodeTypeEnum.CONDITION_NODE) }}
</div>
</div>
<div v-if="!readonly" class="node-toolbar">

View File

@ -7,7 +7,9 @@ import { IconifyIcon } from '@vben/icons';
import { Input } from 'ant-design-vue';
import { NODE_DEFAULT_TEXT, NodeType } from '../../consts';
import { BpmNodeTypeEnum } from '#/utils';
import { NODE_DEFAULT_TEXT } from '../../consts';
import { useNodeName2, useTaskStatusClass, useWatchNode } from '../../helpers';
import RouterNodeConfig from '../nodes-config/router-node-config.vue';
import NodeHandler from './node-handler.vue';
@ -33,7 +35,7 @@ const currentNode = useWatchNode(props);
//
const { showInput, blurEvent, clickTitle } = useNodeName2(
currentNode,
NodeType.ROUTER_BRANCH_NODE,
BpmNodeTypeEnum.ROUTER_BRANCH_NODE,
);
const nodeSetting = ref();
@ -85,7 +87,7 @@ function deleteNode() {
{{ currentNode.showText }}
</div>
<div class="node-text" v-else>
{{ NODE_DEFAULT_TEXT.get(NodeType.ROUTER_BRANCH_NODE) }}
{{ NODE_DEFAULT_TEXT.get(BpmNodeTypeEnum.ROUTER_BRANCH_NODE) }}
</div>
<IconifyIcon v-if="!readonly" icon="ep:arrow-right-bold" />
</div>

View File

@ -9,7 +9,9 @@ import { IconifyIcon } from '@vben/icons';
import { Input } from 'ant-design-vue';
import { NODE_DEFAULT_TEXT, NodeType } from '../../consts';
import { BpmNodeTypeEnum } from '#/utils';
import { NODE_DEFAULT_TEXT } from '../../consts';
import { useNodeName2, useTaskStatusClass, useWatchNode } from '../../helpers';
import StartUserNodeConfig from '../nodes-config/start-user-node-config.vue';
import NodeHandler from './node-handler.vue';
@ -36,7 +38,7 @@ const currentNode = useWatchNode(props);
//
const { showInput, blurEvent, clickTitle } = useNodeName2(
currentNode,
NodeType.START_USER_NODE,
BpmNodeTypeEnum.START_USER_NODE,
);
const nodeSetting = ref();
@ -98,7 +100,7 @@ function nodeClick() {
{{ currentNode.showText }}
</div>
<div class="node-text" v-else>
{{ NODE_DEFAULT_TEXT.get(NodeType.START_USER_NODE) }}
{{ NODE_DEFAULT_TEXT.get(BpmNodeTypeEnum.START_USER_NODE) }}
</div>
<IconifyIcon icon="ep:arrow-right-bold" v-if="!readonly" />
</div>

View File

@ -7,7 +7,9 @@ import { IconifyIcon } from '@vben/icons';
import { Input } from 'ant-design-vue';
import { NODE_DEFAULT_TEXT, NodeType } from '../../consts';
import { BpmNodeTypeEnum } from '#/utils';
import { NODE_DEFAULT_TEXT } from '../../consts';
import { useNodeName2, useTaskStatusClass, useWatchNode } from '../../helpers';
import TriggerNodeConfig from '../nodes-config/trigger-node-config.vue';
import NodeHandler from './node-handler.vue';
@ -35,7 +37,7 @@ const currentNode = useWatchNode(props);
//
const { showInput, blurEvent, clickTitle } = useNodeName2(
currentNode,
NodeType.TRIGGER_NODE,
BpmNodeTypeEnum.TRIGGER_NODE,
);
const nodeSetting = ref();
@ -87,7 +89,7 @@ function deleteNode() {
{{ currentNode.showText }}
</div>
<div class="node-text" v-else>
{{ NODE_DEFAULT_TEXT.get(NodeType.TRIGGER_NODE) }}
{{ NODE_DEFAULT_TEXT.get(BpmNodeTypeEnum.TRIGGER_NODE) }}
</div>
<IconifyIcon v-if="!readonly" icon="ep:arrow-right-bold" />
</div>

View File

@ -9,7 +9,9 @@ import { IconifyIcon } from '@vben/icons';
import { Input } from 'ant-design-vue';
import { NODE_DEFAULT_TEXT, NodeType } from '../../consts';
import { BpmNodeTypeEnum } from '#/utils';
import { NODE_DEFAULT_TEXT } from '../../consts';
import { useNodeName2, useTaskStatusClass, useWatchNode } from '../../helpers';
import UserTaskNodeConfig from '../nodes-config/user-task-node-config.vue';
import NodeHandler from './node-handler.vue';
@ -24,7 +26,7 @@ const props = defineProps({
});
const emits = defineEmits<{
findParentNode: [nodeList: SimpleFlowNode[], nodeType: NodeType];
findParentNode: [nodeList: SimpleFlowNode[], nodeType: BpmNodeTypeEnum];
'update:flowNode': [node: SimpleFlowNode | undefined];
}>();
@ -36,7 +38,7 @@ const currentNode = useWatchNode(props);
//
const { showInput, blurEvent, clickTitle } = useNodeName2(
currentNode,
NodeType.START_USER_NODE,
BpmNodeTypeEnum.USER_TASK_NODE,
);
const nodeSetting = ref();
@ -60,7 +62,7 @@ function findReturnTaskNodes(
matchNodeList: SimpleFlowNode[], //
) {
//
emits('findParentNode', matchNodeList, NodeType.USER_TASK_NODE);
emits('findParentNode', matchNodeList, BpmNodeTypeEnum.USER_TASK_NODE);
}
// const selectTasks = ref<any[] | undefined>([]); //
@ -77,10 +79,10 @@ function findReturnTaskNodes(
>
<div class="node-title-container">
<div
:class="`node-title-icon ${currentNode.type === NodeType.TRANSACTOR_NODE ? 'transactor-task' : 'user-task'}`"
:class="`node-title-icon ${currentNode.type === BpmNodeTypeEnum.TRANSACTOR_NODE ? 'transactor-task' : 'user-task'}`"
>
<span
:class="`iconfont ${currentNode.type === NodeType.TRANSACTOR_NODE ? 'icon-transactor' : 'icon-approve'}`"
:class="`iconfont ${currentNode.type === BpmNodeTypeEnum.TRANSACTOR_NODE ? 'icon-transactor' : 'icon-approve'}`"
>
</span>
</div>

View File

@ -1,7 +1,8 @@
<script setup lang="ts">
import type { SimpleFlowNode } from '../consts';
import { NodeType } from '../consts';
import { BpmNodeTypeEnum } from '#/utils';
import { useWatchNode } from '../helpers';
import CopyTaskNode from './nodes/copy-task-node.vue';
import DelayTimerNode from './nodes/delay-timer-node.vue';
@ -57,7 +58,7 @@ function recursiveFindParentNode(
if (!findNode) {
return;
}
if (findNode.type === NodeType.START_USER_NODE) {
if (findNode.type === BpmNodeTypeEnum.START_USER_NODE) {
nodeList.push(findNode);
return;
}
@ -71,15 +72,15 @@ function recursiveFindParentNode(
<template>
<!-- 发起人节点 -->
<StartUserNode
v-if="currentNode && currentNode.type === NodeType.START_USER_NODE"
v-if="currentNode && currentNode.type === BpmNodeTypeEnum.START_USER_NODE"
:flow-node="currentNode"
/>
<!-- 审批节点 -->
<UserTaskNode
v-if="
currentNode &&
(currentNode.type === NodeType.USER_TASK_NODE ||
currentNode.type === NodeType.TRANSACTOR_NODE)
(currentNode.type === BpmNodeTypeEnum.USER_TASK_NODE ||
currentNode.type === BpmNodeTypeEnum.TRANSACTOR_NODE)
"
:flow-node="currentNode"
@update:flow-node="handleModelValueUpdate"
@ -87,46 +88,54 @@ function recursiveFindParentNode(
/>
<!-- 抄送节点 -->
<CopyTaskNode
v-if="currentNode && currentNode.type === NodeType.COPY_TASK_NODE"
v-if="currentNode && currentNode.type === BpmNodeTypeEnum.COPY_TASK_NODE"
:flow-node="currentNode"
@update:flow-node="handleModelValueUpdate"
/>
<!-- 条件节点 -->
<ExclusiveNode
v-if="currentNode && currentNode.type === NodeType.CONDITION_BRANCH_NODE"
v-if="
currentNode && currentNode.type === BpmNodeTypeEnum.CONDITION_BRANCH_NODE
"
:flow-node="currentNode"
@update:model-value="handleModelValueUpdate"
@find-parent-node="findParentNode"
/>
<!-- 并行节点 -->
<ParallelNode
v-if="currentNode && currentNode.type === NodeType.PARALLEL_BRANCH_NODE"
v-if="
currentNode && currentNode.type === BpmNodeTypeEnum.PARALLEL_BRANCH_NODE
"
:flow-node="currentNode"
@update:model-value="handleModelValueUpdate"
@find-parent-node="findParentNode"
/>
<!-- 包容分支节点 -->
<InclusiveNode
v-if="currentNode && currentNode.type === NodeType.INCLUSIVE_BRANCH_NODE"
v-if="
currentNode && currentNode.type === BpmNodeTypeEnum.INCLUSIVE_BRANCH_NODE
"
:flow-node="currentNode"
@update:model-value="handleModelValueUpdate"
@find-parent-node="findParentNode"
/>
<!-- 延迟器节点 -->
<DelayTimerNode
v-if="currentNode && currentNode.type === NodeType.DELAY_TIMER_NODE"
v-if="currentNode && currentNode.type === BpmNodeTypeEnum.DELAY_TIMER_NODE"
:flow-node="currentNode"
@update:flow-node="handleModelValueUpdate"
/>
<!-- 路由分支节点 -->
<RouterNode
v-if="currentNode && currentNode.type === NodeType.ROUTER_BRANCH_NODE"
v-if="
currentNode && currentNode.type === BpmNodeTypeEnum.ROUTER_BRANCH_NODE
"
:flow-node="currentNode"
@update:flow-node="handleModelValueUpdate"
/>
<!-- 触发器节点 -->
<TriggerNode
v-if="currentNode && currentNode.type === NodeType.TRIGGER_NODE"
v-if="currentNode && currentNode.type === BpmNodeTypeEnum.TRIGGER_NODE"
:flow-node="currentNode"
@update:flow-node="handleModelValueUpdate"
/>
@ -146,7 +155,7 @@ function recursiveFindParentNode(
<!-- 结束节点 -->
<EndEventNode
v-if="currentNode && currentNode.type === NodeType.END_EVENT_NODE"
v-if="currentNode && currentNode.type === BpmNodeTypeEnum.END_EVENT_NODE"
:flow-node="currentNode"
/>
</template>

View File

@ -22,9 +22,9 @@ import { getSimpleDeptList } from '#/api/system/dept';
import { getSimplePostList } from '#/api/system/post';
import { getSimpleRoleList } from '#/api/system/role';
import { getSimpleUserList } from '#/api/system/user';
import { BpmModelFormType } from '#/utils/constants';
import { BpmModelFormType, BpmNodeTypeEnum } from '#/utils';
import { NODE_DEFAULT_TEXT, NodeId, NodeType } from '../consts';
import { NODE_DEFAULT_TEXT, NodeId } from '../consts';
import SimpleProcessModel from './simple-process-model.vue';
defineOptions({
@ -124,13 +124,13 @@ function updateModel() {
if (!processNodeTree.value) {
processNodeTree.value = {
name: '发起人',
type: NodeType.START_USER_NODE,
type: BpmNodeTypeEnum.START_USER_NODE,
id: NodeId.START_USER_NODE_ID,
showText: '默认配置',
childNode: {
id: NodeId.END_EVENT_NODE_ID,
name: '结束',
type: NodeType.END_EVENT_NODE,
type: BpmNodeTypeEnum.END_EVENT_NODE,
},
};
//
@ -162,14 +162,14 @@ function validateNode(
) {
if (node) {
const { type, showText, conditionNodes } = node;
if (type === NodeType.END_EVENT_NODE) {
if (type === BpmNodeTypeEnum.END_EVENT_NODE) {
return;
}
if (
type === NodeType.CONDITION_BRANCH_NODE ||
type === NodeType.PARALLEL_BRANCH_NODE ||
type === NodeType.INCLUSIVE_BRANCH_NODE
type === BpmNodeTypeEnum.CONDITION_BRANCH_NODE ||
type === BpmNodeTypeEnum.PARALLEL_BRANCH_NODE ||
type === BpmNodeTypeEnum.INCLUSIVE_BRANCH_NODE
) {
// 1. ,
conditionNodes?.forEach((item) => {

View File

@ -8,7 +8,9 @@ import { downloadFileFromBlob, isString } from '@vben/utils';
import { Button, ButtonGroup, Modal, Row } from 'ant-design-vue';
import { NODE_DEFAULT_TEXT, NodeType } from '../consts';
import { BpmNodeTypeEnum } from '#/utils';
import { NODE_DEFAULT_TEXT } from '../consts';
import { useWatchNode } from '../helpers';
import ProcessNodeTree from './process-node-tree.vue';
@ -113,18 +115,18 @@ function validateNode(
) {
if (node) {
const { type, showText, conditionNodes } = node;
if (type === NodeType.END_EVENT_NODE) {
if (type === BpmNodeTypeEnum.END_EVENT_NODE) {
return;
}
if (type === NodeType.START_USER_NODE) {
if (type === BpmNodeTypeEnum.START_USER_NODE) {
//
validateNode(node.childNode, errorNodes);
}
if (
type === NodeType.USER_TASK_NODE ||
type === NodeType.COPY_TASK_NODE ||
type === NodeType.CONDITION_NODE
type === BpmNodeTypeEnum.USER_TASK_NODE ||
type === BpmNodeTypeEnum.COPY_TASK_NODE ||
type === BpmNodeTypeEnum.CONDITION_NODE
) {
if (!showText) {
errorNodes.push(node);
@ -133,9 +135,9 @@ function validateNode(
}
if (
type === NodeType.CONDITION_BRANCH_NODE ||
type === NodeType.PARALLEL_BRANCH_NODE ||
type === NodeType.INCLUSIVE_BRANCH_NODE
type === BpmNodeTypeEnum.CONDITION_BRANCH_NODE ||
type === BpmNodeTypeEnum.PARALLEL_BRANCH_NODE ||
type === BpmNodeTypeEnum.INCLUSIVE_BRANCH_NODE
) {
//
// 1.

View File

@ -1,4 +1,4 @@
// TODO 芋艿 这些 常量是不是可以共享
import { BpmNodeTypeEnum, BpmTaskStatusEnum } from '#/utils';
interface DictDataType {
label: string;
@ -43,112 +43,6 @@ export enum ApproveMethodType {
SEQUENTIAL_APPROVE = 4,
}
/**
*
*/
export enum TaskStatusEnum {
/**
*
*/
APPROVE = 2,
/**
*
*/
APPROVING = 7,
/**
*
*/
CANCEL = 4,
/**
*
*/
NOT_START = -1,
/**
*
*/
REJECT = 3,
/**
* 退
*/
RETURN = 5,
/**
*
*/
RUNNING = 1,
/**
*
*/
WAIT = 0,
}
/**
*
*/
export enum NodeType {
/**
*
*/
CHILD_PROCESS_NODE = 20,
/**
* ()
*/
CONDITION_BRANCH_NODE = 51,
/**
*
*/
CONDITION_NODE = 50,
/**
*
*/
COPY_TASK_NODE = 12,
/**
*
*/
DELAY_TIMER_NODE = 14,
/**
*
*/
END_EVENT_NODE = 1,
/**
* ()
*/
INCLUSIVE_BRANCH_NODE = 53,
/**
* ()
*/
PARALLEL_BRANCH_NODE = 52,
/**
*
*/
ROUTER_BRANCH_NODE = 54,
/**
*
*/
START_USER_NODE = 10,
/**
*
*/
TRANSACTOR_NODE = 13,
/**
*
*/
TRIGGER_NODE = 15,
/**
*
*/
USER_TASK_NODE = 11,
}
export enum NodeId {
/**
* Id
@ -660,7 +554,7 @@ export type ChildProcessSetting = {
*/
export interface SimpleFlowNode {
id: string;
type: NodeType;
type: BpmNodeTypeEnum;
name: string;
showText?: string;
// 孩子节点
@ -698,7 +592,7 @@ export interface SimpleFlowNode {
// 条件设置
conditionSetting?: ConditionSetting;
// 活动的状态,用于前端节点状态展示
activityStatus?: TaskStatusEnum;
activityStatus?: BpmTaskStatusEnum;
// 延迟设置
delaySetting?: DelaySetting;
// 路由分支
@ -734,26 +628,26 @@ export const DEFAULT_CONDITION_GROUP_VALUE = {
};
export const NODE_DEFAULT_TEXT = new Map<number, string>();
NODE_DEFAULT_TEXT.set(NodeType.USER_TASK_NODE, '请配置审批人');
NODE_DEFAULT_TEXT.set(NodeType.COPY_TASK_NODE, '请配置抄送人');
NODE_DEFAULT_TEXT.set(NodeType.CONDITION_NODE, '请设置条件');
NODE_DEFAULT_TEXT.set(NodeType.START_USER_NODE, '请设置发起人');
NODE_DEFAULT_TEXT.set(NodeType.DELAY_TIMER_NODE, '请设置延迟器');
NODE_DEFAULT_TEXT.set(NodeType.ROUTER_BRANCH_NODE, '请设置路由节点');
NODE_DEFAULT_TEXT.set(NodeType.TRIGGER_NODE, '请设置触发器');
NODE_DEFAULT_TEXT.set(NodeType.TRANSACTOR_NODE, '请设置办理人');
NODE_DEFAULT_TEXT.set(NodeType.CHILD_PROCESS_NODE, '请设置子流程');
NODE_DEFAULT_TEXT.set(BpmNodeTypeEnum.USER_TASK_NODE, '请配置审批人');
NODE_DEFAULT_TEXT.set(BpmNodeTypeEnum.COPY_TASK_NODE, '请配置抄送人');
NODE_DEFAULT_TEXT.set(BpmNodeTypeEnum.CONDITION_NODE, '请设置条件');
NODE_DEFAULT_TEXT.set(BpmNodeTypeEnum.START_USER_NODE, '请设置发起人');
NODE_DEFAULT_TEXT.set(BpmNodeTypeEnum.DELAY_TIMER_NODE, '请设置延迟器');
NODE_DEFAULT_TEXT.set(BpmNodeTypeEnum.ROUTER_BRANCH_NODE, '请设置路由节点');
NODE_DEFAULT_TEXT.set(BpmNodeTypeEnum.TRIGGER_NODE, '请设置触发器');
NODE_DEFAULT_TEXT.set(BpmNodeTypeEnum.TRANSACTOR_NODE, '请设置办理人');
NODE_DEFAULT_TEXT.set(BpmNodeTypeEnum.CHILD_PROCESS_NODE, '请设置子流程');
export const NODE_DEFAULT_NAME = new Map<number, string>();
NODE_DEFAULT_NAME.set(NodeType.USER_TASK_NODE, '审批人');
NODE_DEFAULT_NAME.set(NodeType.COPY_TASK_NODE, '抄送人');
NODE_DEFAULT_NAME.set(NodeType.CONDITION_NODE, '条件');
NODE_DEFAULT_NAME.set(NodeType.START_USER_NODE, '发起人');
NODE_DEFAULT_NAME.set(NodeType.DELAY_TIMER_NODE, '延迟器');
NODE_DEFAULT_NAME.set(NodeType.ROUTER_BRANCH_NODE, '路由分支');
NODE_DEFAULT_NAME.set(NodeType.TRIGGER_NODE, '触发器');
NODE_DEFAULT_NAME.set(NodeType.TRANSACTOR_NODE, '办理人');
NODE_DEFAULT_NAME.set(NodeType.CHILD_PROCESS_NODE, '子流程');
NODE_DEFAULT_NAME.set(BpmNodeTypeEnum.USER_TASK_NODE, '审批人');
NODE_DEFAULT_NAME.set(BpmNodeTypeEnum.COPY_TASK_NODE, '抄送人');
NODE_DEFAULT_NAME.set(BpmNodeTypeEnum.CONDITION_NODE, '条件');
NODE_DEFAULT_NAME.set(BpmNodeTypeEnum.START_USER_NODE, '发起人');
NODE_DEFAULT_NAME.set(BpmNodeTypeEnum.DELAY_TIMER_NODE, '延迟器');
NODE_DEFAULT_NAME.set(BpmNodeTypeEnum.ROUTER_BRANCH_NODE, '路由分支');
NODE_DEFAULT_NAME.set(BpmNodeTypeEnum.TRIGGER_NODE, '触发器');
NODE_DEFAULT_NAME.set(BpmNodeTypeEnum.TRANSACTOR_NODE, '办理人');
NODE_DEFAULT_NAME.set(BpmNodeTypeEnum.CHILD_PROCESS_NODE, '子流程');
// 候选人策略。暂时不从字典中取。 后续可能调整。控制显示顺序
export const CANDIDATE_STRATEGY: DictDataType[] = [
@ -930,24 +824,6 @@ export const MULTI_LEVEL_DEPT: DictDataType[] = [
{ label: '第 15 级部门', value: 15 },
];
/**
*
*/
export enum ProcessVariableEnum {
/**
*
*/
PROCESS_DEFINITION_NAME = 'PROCESS_DEFINITION_NAME',
/**
*
*/
START_TIME = 'PROCESS_START_TIME',
/**
* ID
*/
START_USER_ID = 'PROCESS_START_USER_ID',
}
export const DELAY_TYPE = [
{ label: '固定时长', value: DelayTypeEnum.FIXED_TIME_DURATION },
{ label: '固定日期', value: DelayTypeEnum.FIXED_DATE_TIME },

View File

@ -14,6 +14,12 @@ import type { SystemUserApi } from '#/api/system/user';
import { inject, ref, toRaw, unref, watch } from 'vue';
import {
BpmNodeTypeEnum,
BpmTaskStatusEnum,
ProcessVariableEnum,
} from '#/utils';
import {
ApproveMethodType,
AssignEmptyHandlerType,
@ -23,10 +29,7 @@ import {
ConditionType,
FieldPermissionType,
NODE_DEFAULT_NAME,
NodeType,
ProcessVariableEnum,
RejectHandlerType,
TaskStatusEnum,
} from './consts';
export function useWatchNode(props: {
@ -252,7 +255,7 @@ export type CopyTaskFormType = {
/**
* @description
*/
export function useNodeForm(nodeType: NodeType) {
export function useNodeForm(nodeType: BpmNodeTypeEnum) {
const roleOptions = inject<Ref<SystemRoleApi.Role[]>>('roleList', ref([])); // 角色列表
const postOptions = inject<Ref<SystemPostApi.Post[]>>('postList', ref([])); // 岗位列表
const userOptions = inject<Ref<SystemUserApi.User[]>>('userList', ref([])); // 用户列表
@ -269,8 +272,8 @@ export function useNodeForm(nodeType: NodeType) {
const configForm = ref<any | CopyTaskFormType | UserTaskFormType>();
if (
nodeType === NodeType.USER_TASK_NODE ||
nodeType === NodeType.TRANSACTOR_NODE
nodeType === BpmNodeTypeEnum.USER_TASK_NODE ||
nodeType === BpmNodeTypeEnum.TRANSACTOR_NODE
) {
configForm.value = {
candidateStrategy: CandidateStrategy.USER,
@ -614,7 +617,7 @@ export function useDrawer() {
/**
* @description
*/
export function useNodeName(nodeType: NodeType) {
export function useNodeName(nodeType: BpmNodeTypeEnum) {
// 节点名称
const nodeName = ref<string>();
// 节点名称输入框
@ -637,7 +640,10 @@ export function useNodeName(nodeType: NodeType) {
};
}
export function useNodeName2(node: Ref<SimpleFlowNode>, nodeType: NodeType) {
export function useNodeName2(
node: Ref<SimpleFlowNode>,
nodeType: BpmNodeTypeEnum,
) {
// 显示节点名称输入框
const showInput = ref(false);
// 节点名称输入框失去焦点
@ -661,21 +667,21 @@ export function useNodeName2(node: Ref<SimpleFlowNode>, nodeType: NodeType) {
* @description
*/
export function useTaskStatusClass(
taskStatus: TaskStatusEnum | undefined,
taskStatus: BpmTaskStatusEnum | undefined,
): string {
if (!taskStatus) {
return '';
}
if (taskStatus === TaskStatusEnum.APPROVE) {
if (taskStatus === BpmTaskStatusEnum.APPROVE) {
return 'status-pass';
}
if (taskStatus === TaskStatusEnum.RUNNING) {
if (taskStatus === BpmTaskStatusEnum.RUNNING) {
return 'status-running';
}
if (taskStatus === TaskStatusEnum.REJECT) {
if (taskStatus === BpmTaskStatusEnum.REJECT) {
return 'status-reject';
}
if (taskStatus === TaskStatusEnum.CANCEL) {
if (taskStatus === BpmTaskStatusEnum.CANCEL) {
return 'status-cancel';
}
return '';

View File

@ -1,3 +1,7 @@
import './styles/simple-process-designer.scss';
export { default as HttpRequestSetting } from './components/nodes-config/modules/http-request-setting.vue';
export { default as SimpleProcessDesigner } from './components/simple-process-designer.vue';
export { parseFormFields } from './helpers';

View File

@ -725,3 +725,21 @@ OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.DELEGATE, '委派');
OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.ADD_SIGN, '加签');
OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.RETURN, '退回');
OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.COPY, '抄送');
/**
*
*/
export enum ProcessVariableEnum {
/**
*
*/
PROCESS_DEFINITION_NAME = 'PROCESS_DEFINITION_NAME',
/**
*
*/
START_TIME = 'PROCESS_START_TIME',
/**
* ID
*/
START_USER_ID = 'PROCESS_START_USER_ID',
}

View File

@ -29,6 +29,7 @@ import { getSimpleUserList } from '#/api/system/user';
import { BpmAutoApproveType, BpmModelFormType, BpmModelType } from '#/utils';
import BasicInfo from './modules/basic-info.vue';
import ExtraSetting from './modules/extra-setting.vue';
import FormDesign from './modules/form-design.vue';
import ProcessDesign from './modules/process-design.vue';
@ -55,6 +56,8 @@ const basicInfoRef = ref<InstanceType<typeof BasicInfo>>();
const formDesignRef = ref<InstanceType<typeof FormDesign>>();
//
const processDesignRef = ref<InstanceType<typeof ProcessDesign>>();
//
const extraSettingRef = ref<InstanceType<typeof ExtraSetting>>();
/** 步骤校验函数 */
const validateBasic = async () => {
@ -71,13 +74,18 @@ const validateProcess = async () => {
await processDesignRef.value?.validate();
};
/** 更多设置校验 */
const validateExtra = async () => {
await extraSettingRef.value?.validate();
};
const currentStep = ref(-1); // -1
const steps = [
{ title: '基本信息', validator: validateBasic },
{ title: '表单设计', validator: validateForm },
{ title: '流程设计', validator: validateProcess },
{ title: '更多设置', validator: null },
{ title: '更多设置', validator: validateExtra },
];
//
@ -190,8 +198,8 @@ const initData = async () => {
// currentStep
currentStep.value = 0;
// TODO
// extraSettingsRef.value.initData()
//
extraSettingRef.value?.initData();
};
/** 根据类型切换流程数据 */
@ -237,7 +245,13 @@ const validateAllSteps = async () => {
return false;
}
// TODO
//
try {
await validateExtra();
} catch {
currentStep.value = 3;
return false;
}
return true;
};
@ -345,6 +359,9 @@ const handleStepClick = async (index: number) => {
if (index !== 2) {
await validateProcess();
}
if (index !== 3) {
await validateExtra();
}
//
currentStep.value = index;
} catch (error) {
@ -475,8 +492,10 @@ onBeforeUnmount(() => {
ref="processDesignRef"
/>
<!-- 第四步更多设置 TODO -->
<div v-if="currentStep === 3" class="mx-auto w-4/6"></div>
<!-- 第四步更多设置 -->
<div v-if="currentStep === 3" class="mx-auto w-4/6">
<ExtraSetting v-model="formData" ref="extraSettingRef" />
</div>
</div>
</Card>
</div>

View File

@ -0,0 +1,498 @@
<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import { CircleHelp } from '@vben/icons';
import {
Checkbox,
Col,
Form,
FormItem,
Input,
InputNumber,
Mentions,
Radio,
RadioGroup,
Row,
Select,
Switch,
Tooltip,
TypographyText,
} from 'ant-design-vue';
import dayjs from 'dayjs';
import * as FormApi from '#/api/bpm/form';
import {
HttpRequestSetting,
parseFormFields,
} from '#/components/simple-process-design';
import { ProcessVariableEnum } from '#/utils';
import { BpmAutoApproveType, BpmModelFormType } from '#/utils/constants';
const modelData = defineModel<any>();
/** 自定义 ID 流程编码 */
const timeOptions = ref([
{
value: '',
label: '无',
},
{
value: 'DAY',
label: '精确到日',
},
{
value: 'HOUR',
label: '精确到时',
},
{
value: 'MINUTE',
label: '精确到分',
},
{
value: 'SECOND',
label: '精确到秒',
},
]);
const numberExample = computed(() => {
if (modelData.value.processIdRule.enable) {
let infix = '';
switch (modelData.value.processIdRule.infix) {
case 'DAY': {
infix = dayjs().format('YYYYMMDD');
break;
}
case 'HOUR': {
infix = dayjs().format('YYYYMMDDHH');
break;
}
case 'MINUTE': {
infix = dayjs().format('YYYYMMDDHHmm');
break;
}
case 'SECOND': {
infix = dayjs().format('YYYYMMDDHHmmss');
break;
}
default: {
break;
}
}
return (
modelData.value.processIdRule.prefix +
infix +
modelData.value.processIdRule.postfix +
'1'.padStart(modelData.value.processIdRule.length - 1, '0')
);
} else {
return '';
}
});
/** 是否开启流程前置通知 */
const processBeforeTriggerEnable = ref(false);
const handleProcessBeforeTriggerEnableChange = (
val: boolean | number | string,
) => {
modelData.value.processBeforeTriggerSetting = val
? {
url: '',
header: [],
body: [],
response: [],
}
: null;
};
/** 是否开启流程后置通知 */
const processAfterTriggerEnable = ref(false);
const handleProcessAfterTriggerEnableChange = (
val: boolean | number | string,
) => {
modelData.value.processAfterTriggerSetting = val
? {
url: '',
header: [],
body: [],
response: [],
}
: null;
};
/** 是否开启任务前置通知 */
const taskBeforeTriggerEnable = ref(false);
const handleTaskBeforeTriggerEnableChange = (
val: boolean | number | string,
) => {
modelData.value.taskBeforeTriggerSetting = val
? {
url: '',
header: [],
body: [],
response: [],
}
: null;
};
/** 是否开启任务后置通知 */
const taskAfterTriggerEnable = ref(false);
const handleTaskAfterTriggerEnableChange = (val: boolean | number | string) => {
modelData.value.taskAfterTriggerSetting = val
? {
url: '',
header: [],
body: [],
response: [],
}
: null;
};
/** 表单选项 */
const formField = ref<Array<{ field: string; title: string }>>([]);
const formFieldOptions4Title = computed(() => {
const cloneFormField = formField.value.map((item) => {
return {
label: item.title,
value: item.field,
};
});
// ID
cloneFormField.unshift({
label: '流程名称',
value: ProcessVariableEnum.PROCESS_DEFINITION_NAME,
});
cloneFormField.unshift({
label: '发起时间',
value: ProcessVariableEnum.START_TIME,
});
cloneFormField.unshift({
label: '发起人',
value: ProcessVariableEnum.START_USER_ID,
});
return cloneFormField;
});
const formFieldOptions4Summary = computed(() => {
return formField.value.map((item) => {
return {
label: item.title,
value: item.field,
};
});
});
/** 兼容以前未配置更多设置的流程 */
const initData = () => {
if (!modelData.value.processIdRule) {
modelData.value.processIdRule = {
enable: false,
prefix: '',
infix: '',
postfix: '',
length: 5,
};
}
if (!modelData.value.autoApprovalType) {
modelData.value.autoApprovalType = BpmAutoApproveType.NONE;
}
if (!modelData.value.titleSetting) {
modelData.value.titleSetting = {
enable: false,
title: '',
};
}
if (!modelData.value.summarySetting) {
modelData.value.summarySetting = {
enable: false,
summary: [],
};
}
if (modelData.value.processBeforeTriggerSetting) {
processBeforeTriggerEnable.value = true;
}
if (modelData.value.processAfterTriggerSetting) {
processAfterTriggerEnable.value = true;
}
if (modelData.value.taskBeforeTriggerSetting) {
taskBeforeTriggerEnable.value = true;
}
if (modelData.value.taskAfterTriggerSetting) {
taskAfterTriggerEnable.value = true;
}
};
/** 监听表单 ID 变化,加载表单数据 */
watch(
() => modelData.value.formId,
async (newFormId) => {
if (newFormId && modelData.value.formType === BpmModelFormType.NORMAL) {
const data = await FormApi.getFormDetail(newFormId);
const result: Array<{ field: string; title: string }> = [];
if (data.fields) {
data.fields.forEach((fieldStr: string) => {
parseFormFields(JSON.parse(fieldStr), result);
});
}
formField.value = result;
} else {
formField.value = [];
}
},
{ immediate: true },
);
//
const formRef = ref();
/** 表单校验 */
const validate = async () => {
await formRef.value?.validate();
};
defineExpose({ initData, validate });
</script>
<template>
<Form
ref="formRef"
:model="modelData"
:label-col="{ span: 4 }"
:wrapper-col="{ span: 20 }"
class="mt-5 px-5"
>
<FormItem class="mb-5" label="提交人权限">
<div class="mt-1 flex flex-col">
<Checkbox v-model:checked="modelData.allowCancelRunningProcess">
允许撤销审批中的申请
</Checkbox>
<div class="ml-6">
<TypographyText type="warning">
第一个审批节点通过后提交人仍可撤销申请
</TypographyText>
</div>
</div>
</FormItem>
<FormItem v-if="modelData.processIdRule" class="mb-5" label="流程编码">
<Row :gutter="8" align="middle">
<Col :span="1">
<Checkbox v-model:checked="modelData.processIdRule.enable" />
</Col>
<Col :span="5">
<Input
v-model:value="modelData.processIdRule.prefix"
placeholder="前缀"
:disabled="!modelData.processIdRule.enable"
/>
</Col>
<Col :span="6">
<Select
v-model:value="modelData.processIdRule.infix"
allow-clear
placeholder="中缀"
:disabled="!modelData.processIdRule.enable"
:options="timeOptions"
/>
</Col>
<Col :span="4">
<Input
v-model:value="modelData.processIdRule.postfix"
placeholder="后缀"
:disabled="!modelData.processIdRule.enable"
/>
</Col>
<Col :span="4">
<InputNumber
v-model:value="modelData.processIdRule.length"
:min="5"
:disabled="!modelData.processIdRule.enable"
/>
</Col>
</Row>
<div class="ml-6 mt-2" v-if="modelData.processIdRule.enable">
<TypographyText type="success">
编码示例{{ numberExample }}
</TypographyText>
</div>
</FormItem>
<FormItem class="mb-5" label="自动去重">
<div class="mt-1">
<TypographyText class="mb-2 block">
同一审批人在流程中重复出现时
</TypographyText>
<RadioGroup v-model:value="modelData.autoApprovalType">
<Row :gutter="[0, 8]">
<Col :span="24">
<Radio :value="0">不自动通过</Radio>
</Col>
<Col :span="24">
<Radio :value="1">
仅审批一次后续重复的审批节点均自动通过
</Radio>
</Col>
<Col :span="24">
<Radio :value="2">仅针对连续审批的节点自动通过</Radio>
</Col>
</Row>
</RadioGroup>
</div>
</FormItem>
<FormItem v-if="modelData.titleSetting" class="mb-5" label="标题设置">
<div class="mt-1">
<RadioGroup v-model:value="modelData.titleSetting.enable">
<Row :gutter="[0, 8]">
<Col :span="24">
<Radio :value="false">
系统默认
<TypographyText type="success"> 展示流程名称 </TypographyText>
</Radio>
</Col>
<Col :span="24">
<Radio :value="true">
<div class="inline-flex items-center">
自定义标题
<Tooltip
title="输入字符 '{' 即可插入表单字段"
placement="top"
>
<CircleHelp class="ml-1 size-4 text-gray-500" />
</Tooltip>
</div>
</Radio>
</Col>
</Row>
</RadioGroup>
<div class="mt-2">
<Mentions
v-if="modelData.titleSetting.enable"
v-model:value="modelData.titleSetting.title"
style="width: 100%; max-width: 600px"
type="textarea"
prefix="{"
split="}"
:options="formFieldOptions4Title"
placeholder="请插入表单字段(输入 '{' 可以选择表单字段)或输入文本"
/>
</div>
</div>
</FormItem>
<FormItem
v-if="
modelData.summarySetting &&
modelData.formType === BpmModelFormType.NORMAL
"
class="mb-5"
label="摘要设置"
>
<div class="mt-1">
<RadioGroup v-model:value="modelData.summarySetting.enable">
<Row :gutter="[0, 8]">
<Col :span="24">
<Radio :value="false">
系统默认
<TypographyText type="secondary">
展示表单前 3 个字段
</TypographyText>
</Radio>
</Col>
<Col :span="24">
<Radio :value="true"> 自定义摘要 </Radio>
</Col>
</Row>
</RadioGroup>
<div class="mt-2">
<Select
v-if="modelData.summarySetting.enable"
v-model:value="modelData.summarySetting.summary"
mode="multiple"
placeholder="请选择要展示的表单字段"
:options="formFieldOptions4Summary"
/>
</div>
</div>
</FormItem>
<FormItem class="mb-5" label="流程前置通知">
<Row class="mt-1">
<Col :span="24">
<div class="flex items-center">
<Switch
v-model:checked="processBeforeTriggerEnable"
@change="handleProcessBeforeTriggerEnableChange"
/>
<span class="ml-4">流程启动后通知</span>
</div>
</Col>
</Row>
<Row v-if="processBeforeTriggerEnable">
<Col :span="24" class="mt-6">
<HttpRequestSetting
v-model:setting="modelData.processBeforeTriggerSetting"
:response-enable="true"
form-item-prefix="processBeforeTriggerSetting"
/>
</Col>
</Row>
</FormItem>
<FormItem class="mb-5" label="流程后置通知">
<Row class="mt-1">
<Col :span="24">
<div class="flex items-center">
<Switch
v-model:checked="processAfterTriggerEnable"
@change="handleProcessAfterTriggerEnableChange"
/>
<span class="ml-4">流程结束后通知</span>
</div>
</Col>
</Row>
<Row v-if="processAfterTriggerEnable" class="mt-2">
<Col :span="24">
<HttpRequestSetting
v-model:setting="modelData.processAfterTriggerSetting"
:response-enable="true"
form-item-prefix="processAfterTriggerSetting"
/>
</Col>
</Row>
</FormItem>
<FormItem class="mb-5" label="任务前置通知">
<Row class="mt-1">
<Col :span="24">
<div class="flex items-center">
<Switch
v-model:checked="taskBeforeTriggerEnable"
@change="handleTaskBeforeTriggerEnableChange"
/>
<span class="ml-4">任务执行时通知</span>
</div>
</Col>
</Row>
<Row v-if="taskBeforeTriggerEnable" class="mt-2">
<Col :span="24">
<HttpRequestSetting
v-model:setting="modelData.taskBeforeTriggerSetting"
:response-enable="true"
form-item-prefix="taskBeforeTriggerSetting"
/>
</Col>
</Row>
</FormItem>
<FormItem class="mb-5" label="任务后置通知">
<Row class="mt-1">
<Col :span="24">
<div class="flex items-center">
<Switch
v-model:checked="taskAfterTriggerEnable"
@change="handleTaskAfterTriggerEnableChange"
/>
<span class="ml-4">任务结束后通知</span>
</div>
</Col>
</Row>
<Row v-if="taskAfterTriggerEnable" class="mt-2">
<Col :span="24">
<HttpRequestSetting
v-model:setting="modelData.taskAfterTriggerSetting"
:response-enable="true"
form-item-prefix="taskAfterTriggerSetting"
/>
</Col>
</Row>
</FormItem>
</Form>
</template>