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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,11 +8,12 @@ import { cloneDeep, buildShortUUID as generateUUID } from '@vben/utils';
import { Button, Input } from 'ant-design-vue'; import { Button, Input } from 'ant-design-vue';
import { BpmNodeTypeEnum } from '#/utils';
import { import {
ConditionType, ConditionType,
DEFAULT_CONDITION_GROUP_VALUE, DEFAULT_CONDITION_GROUP_VALUE,
NODE_DEFAULT_TEXT, NODE_DEFAULT_TEXT,
NodeType,
} from '../../consts'; } from '../../consts';
import { getDefaultConditionNodeName, useTaskStatusClass } from '../../helpers'; import { getDefaultConditionNodeName, useTaskStatusClass } from '../../helpers';
import ConditionNodeConfig from '../nodes-config/condition-node-config.vue'; import ConditionNodeConfig from '../nodes-config/condition-node-config.vue';
@ -90,7 +91,7 @@ function addCondition() {
id: `Flow_${generateUUID()}`, id: `Flow_${generateUUID()}`,
name: `条件${len}`, name: `条件${len}`,
showText: '', showText: '',
type: NodeType.CONDITION_NODE, type: BpmNodeTypeEnum.CONDITION_NODE,
childNode: undefined, childNode: undefined,
conditionNodes: [], conditionNodes: [],
conditionSetting: { conditionSetting: {
@ -138,7 +139,7 @@ function recursiveFindParentNode(
node: SimpleFlowNode, node: SimpleFlowNode,
nodeType: number, nodeType: number,
) { ) {
if (!node || node.type === NodeType.START_USER_NODE) { if (!node || node.type === BpmNodeTypeEnum.START_USER_NODE) {
return; return;
} }
if (node.type === nodeType) { if (node.type === nodeType) {
@ -210,7 +211,7 @@ function recursiveFindParentNode(
{{ item.showText }} {{ item.showText }}
</div> </div>
<div class="branch-node-text" v-else> <div class="branch-node-text" v-else>
{{ NODE_DEFAULT_TEXT.get(NodeType.CONDITION_NODE) }} {{ NODE_DEFAULT_TEXT.get(BpmNodeTypeEnum.CONDITION_NODE) }}
</div> </div>
</div> </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 { Button, Input } from 'ant-design-vue';
import { BpmNodeTypeEnum } from '#/utils';
import { import {
ConditionType, ConditionType,
DEFAULT_CONDITION_GROUP_VALUE, DEFAULT_CONDITION_GROUP_VALUE,
NODE_DEFAULT_TEXT, NODE_DEFAULT_TEXT,
NodeType,
} from '../../consts'; } from '../../consts';
import { import {
getDefaultInclusiveConditionNodeName, getDefaultInclusiveConditionNodeName,
@ -95,7 +96,7 @@ function addCondition() {
id: `Flow_${generateUUID()}`, id: `Flow_${generateUUID()}`,
name: `包容条件${len}`, name: `包容条件${len}`,
showText: '', showText: '',
type: NodeType.CONDITION_NODE, type: BpmNodeTypeEnum.CONDITION_NODE,
childNode: undefined, childNode: undefined,
conditionNodes: [], conditionNodes: [],
conditionSetting: { conditionSetting: {
@ -143,7 +144,7 @@ function recursiveFindParentNode(
node: SimpleFlowNode, node: SimpleFlowNode,
nodeType: number, nodeType: number,
) { ) {
if (!node || node.type === NodeType.START_USER_NODE) { if (!node || node.type === BpmNodeTypeEnum.START_USER_NODE) {
return; return;
} }
if (node.type === nodeType) { if (node.type === nodeType) {
@ -213,7 +214,7 @@ function recursiveFindParentNode(
{{ item.showText }} {{ item.showText }}
</div> </div>
<div class="branch-node-text" v-else> <div class="branch-node-text" v-else>
{{ NODE_DEFAULT_TEXT.get(NodeType.CONDITION_NODE) }} {{ NODE_DEFAULT_TEXT.get(BpmNodeTypeEnum.CONDITION_NODE) }}
</div> </div>
</div> </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 { message, Popover } from 'ant-design-vue';
import { BpmNodeTypeEnum } from '#/utils';
import { import {
ApproveMethodType, ApproveMethodType,
AssignEmptyHandlerType, AssignEmptyHandlerType,
@ -15,7 +17,6 @@ import {
ConditionType, ConditionType,
DEFAULT_CONDITION_GROUP_VALUE, DEFAULT_CONDITION_GROUP_VALUE,
NODE_DEFAULT_NAME, NODE_DEFAULT_NAME,
NodeType,
RejectHandlerType, RejectHandlerType,
} from '../../consts'; } from '../../consts';
@ -41,17 +42,21 @@ const readonly = inject<Boolean>('readonly'); // 是否只读
function addNode(type: number) { function addNode(type: number) {
// //
if ( if (
type === NodeType.PARALLEL_BRANCH_NODE && type === BpmNodeTypeEnum.PARALLEL_BRANCH_NODE &&
[NodeType.CONDITION_BRANCH_NODE, NodeType.INCLUSIVE_BRANCH_NODE].includes( [
props.currentNode?.type, BpmNodeTypeEnum.CONDITION_BRANCH_NODE,
) BpmNodeTypeEnum.INCLUSIVE_BRANCH_NODE,
].includes(props.currentNode?.type)
) { ) {
message.error('条件分支、包容分支后面,不允许直接添加并行分支'); message.error('条件分支、包容分支后面,不允许直接添加并行分支');
return; return;
} }
popoverShow.value = false; 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 id = `Activity_${generateUUID()}`;
const data: SimpleFlowNode = { const data: SimpleFlowNode = {
id, id,
@ -83,20 +88,20 @@ function addNode(type: number) {
}; };
emits('update:childNode', data); emits('update:childNode', data);
} }
if (type === NodeType.COPY_TASK_NODE) { if (type === BpmNodeTypeEnum.COPY_TASK_NODE) {
const data: SimpleFlowNode = { const data: SimpleFlowNode = {
id: `Activity_${generateUUID()}`, 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: '', showText: '',
type: NodeType.COPY_TASK_NODE, type: BpmNodeTypeEnum.COPY_TASK_NODE,
childNode: props.childNode, childNode: props.childNode,
}; };
emits('update:childNode', data); emits('update:childNode', data);
} }
if (type === NodeType.CONDITION_BRANCH_NODE) { if (type === BpmNodeTypeEnum.CONDITION_BRANCH_NODE) {
const data: SimpleFlowNode = { const data: SimpleFlowNode = {
name: '条件分支', name: '条件分支',
type: NodeType.CONDITION_BRANCH_NODE, type: BpmNodeTypeEnum.CONDITION_BRANCH_NODE,
id: `GateWay_${generateUUID()}`, id: `GateWay_${generateUUID()}`,
childNode: props.childNode, childNode: props.childNode,
conditionNodes: [ conditionNodes: [
@ -104,7 +109,7 @@ function addNode(type: number) {
id: `Flow_${generateUUID()}`, id: `Flow_${generateUUID()}`,
name: '条件1', name: '条件1',
showText: '', showText: '',
type: NodeType.CONDITION_NODE, type: BpmNodeTypeEnum.CONDITION_NODE,
childNode: undefined, childNode: undefined,
conditionSetting: { conditionSetting: {
defaultFlow: false, defaultFlow: false,
@ -116,7 +121,7 @@ function addNode(type: number) {
id: `Flow_${generateUUID()}`, id: `Flow_${generateUUID()}`,
name: '其它情况', name: '其它情况',
showText: '未满足其它条件时,将进入此分支', showText: '未满足其它条件时,将进入此分支',
type: NodeType.CONDITION_NODE, type: BpmNodeTypeEnum.CONDITION_NODE,
childNode: undefined, childNode: undefined,
conditionSetting: { conditionSetting: {
defaultFlow: true, defaultFlow: true,
@ -126,10 +131,10 @@ function addNode(type: number) {
}; };
emits('update:childNode', data); emits('update:childNode', data);
} }
if (type === NodeType.PARALLEL_BRANCH_NODE) { if (type === BpmNodeTypeEnum.PARALLEL_BRANCH_NODE) {
const data: SimpleFlowNode = { const data: SimpleFlowNode = {
name: '并行分支', name: '并行分支',
type: NodeType.PARALLEL_BRANCH_NODE, type: BpmNodeTypeEnum.PARALLEL_BRANCH_NODE,
id: `GateWay_${generateUUID()}`, id: `GateWay_${generateUUID()}`,
childNode: props.childNode, childNode: props.childNode,
conditionNodes: [ conditionNodes: [
@ -137,24 +142,24 @@ function addNode(type: number) {
id: `Flow_${generateUUID()}`, id: `Flow_${generateUUID()}`,
name: '并行1', name: '并行1',
showText: '无需配置条件同时执行', showText: '无需配置条件同时执行',
type: NodeType.CONDITION_NODE, type: BpmNodeTypeEnum.CONDITION_NODE,
childNode: undefined, childNode: undefined,
}, },
{ {
id: `Flow_${generateUUID()}`, id: `Flow_${generateUUID()}`,
name: '并行2', name: '并行2',
showText: '无需配置条件同时执行', showText: '无需配置条件同时执行',
type: NodeType.CONDITION_NODE, type: BpmNodeTypeEnum.CONDITION_NODE,
childNode: undefined, childNode: undefined,
}, },
], ],
}; };
emits('update:childNode', data); emits('update:childNode', data);
} }
if (type === NodeType.INCLUSIVE_BRANCH_NODE) { if (type === BpmNodeTypeEnum.INCLUSIVE_BRANCH_NODE) {
const data: SimpleFlowNode = { const data: SimpleFlowNode = {
name: '包容分支', name: '包容分支',
type: NodeType.INCLUSIVE_BRANCH_NODE, type: BpmNodeTypeEnum.INCLUSIVE_BRANCH_NODE,
id: `GateWay_${generateUUID()}`, id: `GateWay_${generateUUID()}`,
childNode: props.childNode, childNode: props.childNode,
conditionNodes: [ conditionNodes: [
@ -162,7 +167,7 @@ function addNode(type: number) {
id: `Flow_${generateUUID()}`, id: `Flow_${generateUUID()}`,
name: '包容条件1', name: '包容条件1',
showText: '', showText: '',
type: NodeType.CONDITION_NODE, type: BpmNodeTypeEnum.CONDITION_NODE,
childNode: undefined, childNode: undefined,
conditionSetting: { conditionSetting: {
defaultFlow: false, defaultFlow: false,
@ -174,7 +179,7 @@ function addNode(type: number) {
id: `Flow_${generateUUID()}`, id: `Flow_${generateUUID()}`,
name: '其它情况', name: '其它情况',
showText: '未满足其它条件时,将进入此分支', showText: '未满足其它条件时,将进入此分支',
type: NodeType.CONDITION_NODE, type: BpmNodeTypeEnum.CONDITION_NODE,
childNode: undefined, childNode: undefined,
conditionSetting: { conditionSetting: {
defaultFlow: true, defaultFlow: true,
@ -184,42 +189,42 @@ function addNode(type: number) {
}; };
emits('update:childNode', data); emits('update:childNode', data);
} }
if (type === NodeType.DELAY_TIMER_NODE) { if (type === BpmNodeTypeEnum.DELAY_TIMER_NODE) {
const data: SimpleFlowNode = { const data: SimpleFlowNode = {
id: `Activity_${generateUUID()}`, 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: '', showText: '',
type: NodeType.DELAY_TIMER_NODE, type: BpmNodeTypeEnum.DELAY_TIMER_NODE,
childNode: props.childNode, childNode: props.childNode,
}; };
emits('update:childNode', data); emits('update:childNode', data);
} }
if (type === NodeType.ROUTER_BRANCH_NODE) { if (type === BpmNodeTypeEnum.ROUTER_BRANCH_NODE) {
const data: SimpleFlowNode = { const data: SimpleFlowNode = {
id: `GateWay_${generateUUID()}`, 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: '', showText: '',
type: NodeType.ROUTER_BRANCH_NODE, type: BpmNodeTypeEnum.ROUTER_BRANCH_NODE,
childNode: props.childNode, childNode: props.childNode,
}; };
emits('update:childNode', data); emits('update:childNode', data);
} }
if (type === NodeType.TRIGGER_NODE) { if (type === BpmNodeTypeEnum.TRIGGER_NODE) {
const data: SimpleFlowNode = { const data: SimpleFlowNode = {
id: `Activity_${generateUUID()}`, id: `Activity_${generateUUID()}`,
name: NODE_DEFAULT_NAME.get(NodeType.TRIGGER_NODE) as string, name: NODE_DEFAULT_NAME.get(BpmNodeTypeEnum.TRIGGER_NODE) as string,
showText: '', showText: '',
type: NodeType.TRIGGER_NODE, type: BpmNodeTypeEnum.TRIGGER_NODE,
childNode: props.childNode, childNode: props.childNode,
}; };
emits('update:childNode', data); emits('update:childNode', data);
} }
if (type === NodeType.CHILD_PROCESS_NODE) { if (type === BpmNodeTypeEnum.CHILD_PROCESS_NODE) {
const data: SimpleFlowNode = { const data: SimpleFlowNode = {
id: `Activity_${generateUUID()}`, 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: '', showText: '',
type: NodeType.CHILD_PROCESS_NODE, type: BpmNodeTypeEnum.CHILD_PROCESS_NODE,
childNode: props.childNode, childNode: props.childNode,
childProcessSetting: { childProcessSetting: {
calledProcessDefinitionKey: '', calledProcessDefinitionKey: '',
@ -247,7 +252,10 @@ function addNode(type: number) {
<Popover trigger="hover" placement="right" width="auto" v-if="!readonly"> <Popover trigger="hover" placement="right" width="auto" v-if="!readonly">
<template #content> <template #content>
<div class="handler-item-wrapper"> <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"> <div class="approve handler-item-icon">
<span class="iconfont icon-approve icon-size"></span> <span class="iconfont icon-approve icon-size"></span>
</div> </div>
@ -255,14 +263,17 @@ function addNode(type: number) {
</div> </div>
<div <div
class="handler-item" class="handler-item"
@click="addNode(NodeType.TRANSACTOR_NODE)" @click="addNode(BpmNodeTypeEnum.TRANSACTOR_NODE)"
> >
<div class="transactor handler-item-icon"> <div class="transactor handler-item-icon">
<span class="iconfont icon-transactor icon-size"></span> <span class="iconfont icon-transactor icon-size"></span>
</div> </div>
<div class="handler-item-text">办理人</div> <div class="handler-item-text">办理人</div>
</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"> <div class="handler-item-icon copy">
<span class="iconfont icon-size icon-copy"></span> <span class="iconfont icon-size icon-copy"></span>
</div> </div>
@ -270,7 +281,7 @@ function addNode(type: number) {
</div> </div>
<div <div
class="handler-item" class="handler-item"
@click="addNode(NodeType.CONDITION_BRANCH_NODE)" @click="addNode(BpmNodeTypeEnum.CONDITION_BRANCH_NODE)"
> >
<div class="handler-item-icon condition"> <div class="handler-item-icon condition">
<span class="iconfont icon-size icon-exclusive"></span> <span class="iconfont icon-size icon-exclusive"></span>
@ -279,7 +290,7 @@ function addNode(type: number) {
</div> </div>
<div <div
class="handler-item" class="handler-item"
@click="addNode(NodeType.PARALLEL_BRANCH_NODE)" @click="addNode(BpmNodeTypeEnum.PARALLEL_BRANCH_NODE)"
> >
<div class="handler-item-icon parallel"> <div class="handler-item-icon parallel">
<span class="iconfont icon-size icon-parallel"></span> <span class="iconfont icon-size icon-parallel"></span>
@ -288,7 +299,7 @@ function addNode(type: number) {
</div> </div>
<div <div
class="handler-item" class="handler-item"
@click="addNode(NodeType.INCLUSIVE_BRANCH_NODE)" @click="addNode(BpmNodeTypeEnum.INCLUSIVE_BRANCH_NODE)"
> >
<div class="handler-item-icon inclusive"> <div class="handler-item-icon inclusive">
<span class="iconfont icon-size icon-inclusive"></span> <span class="iconfont icon-size icon-inclusive"></span>
@ -297,7 +308,7 @@ function addNode(type: number) {
</div> </div>
<div <div
class="handler-item" class="handler-item"
@click="addNode(NodeType.DELAY_TIMER_NODE)" @click="addNode(BpmNodeTypeEnum.DELAY_TIMER_NODE)"
> >
<div class="handler-item-icon delay"> <div class="handler-item-icon delay">
<span class="iconfont icon-size icon-delay"></span> <span class="iconfont icon-size icon-delay"></span>
@ -306,14 +317,17 @@ function addNode(type: number) {
</div> </div>
<div <div
class="handler-item" class="handler-item"
@click="addNode(NodeType.ROUTER_BRANCH_NODE)" @click="addNode(BpmNodeTypeEnum.ROUTER_BRANCH_NODE)"
> >
<div class="handler-item-icon router"> <div class="handler-item-icon router">
<span class="iconfont icon-size icon-router"></span> <span class="iconfont icon-size icon-router"></span>
</div> </div>
<div class="handler-item-text">路由分支</div> <div class="handler-item-text">路由分支</div>
</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"> <div class="handler-item-icon trigger">
<span class="iconfont icon-size icon-trigger"></span> <span class="iconfont icon-size icon-trigger"></span>
</div> </div>
@ -321,7 +335,7 @@ function addNode(type: number) {
</div> </div>
<div <div
class="handler-item" class="handler-item"
@click="addNode(NodeType.CHILD_PROCESS_NODE)" @click="addNode(BpmNodeTypeEnum.CHILD_PROCESS_NODE)"
> >
<div class="handler-item-icon child-process"> <div class="handler-item-icon child-process">
<span class="iconfont icon-size icon-child-process"></span> <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 { 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 { useTaskStatusClass } from '../../helpers';
import ProcessNodeTree from '../process-node-tree.vue'; import ProcessNodeTree from '../process-node-tree.vue';
import NodeHandler from './node-handler.vue'; import NodeHandler from './node-handler.vue';
@ -70,7 +72,7 @@ function addCondition() {
id: `Flow_${generateUUID()}`, id: `Flow_${generateUUID()}`,
name: `并行${len}`, name: `并行${len}`,
showText: '无需配置条件同时执行', showText: '无需配置条件同时执行',
type: NodeType.CONDITION_NODE, type: BpmNodeTypeEnum.CONDITION_NODE,
childNode: undefined, childNode: undefined,
conditionNodes: [], conditionNodes: [],
}; };
@ -97,7 +99,7 @@ function recursiveFindParentNode(
node: SimpleFlowNode, node: SimpleFlowNode,
nodeType: number, nodeType: number,
) { ) {
if (!node || node.type === NodeType.START_USER_NODE) { if (!node || node.type === BpmNodeTypeEnum.START_USER_NODE) {
return; return;
} }
if (node.type === nodeType) { if (node.type === nodeType) {
@ -168,7 +170,7 @@ function recursiveFindParentNode(
{{ item.showText }} {{ item.showText }}
</div> </div>
<div class="branch-node-text" v-else> <div class="branch-node-text" v-else>
{{ NODE_DEFAULT_TEXT.get(NodeType.CONDITION_NODE) }} {{ NODE_DEFAULT_TEXT.get(BpmNodeTypeEnum.CONDITION_NODE) }}
</div> </div>
</div> </div>
<div v-if="!readonly" class="node-toolbar"> <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 { 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 { useNodeName2, useTaskStatusClass, useWatchNode } from '../../helpers';
import RouterNodeConfig from '../nodes-config/router-node-config.vue'; import RouterNodeConfig from '../nodes-config/router-node-config.vue';
import NodeHandler from './node-handler.vue'; import NodeHandler from './node-handler.vue';
@ -33,7 +35,7 @@ const currentNode = useWatchNode(props);
// //
const { showInput, blurEvent, clickTitle } = useNodeName2( const { showInput, blurEvent, clickTitle } = useNodeName2(
currentNode, currentNode,
NodeType.ROUTER_BRANCH_NODE, BpmNodeTypeEnum.ROUTER_BRANCH_NODE,
); );
const nodeSetting = ref(); const nodeSetting = ref();
@ -85,7 +87,7 @@ function deleteNode() {
{{ currentNode.showText }} {{ currentNode.showText }}
</div> </div>
<div class="node-text" v-else> <div class="node-text" v-else>
{{ NODE_DEFAULT_TEXT.get(NodeType.ROUTER_BRANCH_NODE) }} {{ NODE_DEFAULT_TEXT.get(BpmNodeTypeEnum.ROUTER_BRANCH_NODE) }}
</div> </div>
<IconifyIcon v-if="!readonly" icon="ep:arrow-right-bold" /> <IconifyIcon v-if="!readonly" icon="ep:arrow-right-bold" />
</div> </div>

View File

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

View File

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

View File

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

View File

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

View File

@ -22,9 +22,9 @@ import { getSimpleDeptList } from '#/api/system/dept';
import { getSimplePostList } from '#/api/system/post'; import { getSimplePostList } from '#/api/system/post';
import { getSimpleRoleList } from '#/api/system/role'; import { getSimpleRoleList } from '#/api/system/role';
import { getSimpleUserList } from '#/api/system/user'; 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'; import SimpleProcessModel from './simple-process-model.vue';
defineOptions({ defineOptions({
@ -124,13 +124,13 @@ function updateModel() {
if (!processNodeTree.value) { if (!processNodeTree.value) {
processNodeTree.value = { processNodeTree.value = {
name: '发起人', name: '发起人',
type: NodeType.START_USER_NODE, type: BpmNodeTypeEnum.START_USER_NODE,
id: NodeId.START_USER_NODE_ID, id: NodeId.START_USER_NODE_ID,
showText: '默认配置', showText: '默认配置',
childNode: { childNode: {
id: NodeId.END_EVENT_NODE_ID, id: NodeId.END_EVENT_NODE_ID,
name: '结束', name: '结束',
type: NodeType.END_EVENT_NODE, type: BpmNodeTypeEnum.END_EVENT_NODE,
}, },
}; };
// //
@ -162,14 +162,14 @@ function validateNode(
) { ) {
if (node) { if (node) {
const { type, showText, conditionNodes } = node; const { type, showText, conditionNodes } = node;
if (type === NodeType.END_EVENT_NODE) { if (type === BpmNodeTypeEnum.END_EVENT_NODE) {
return; return;
} }
if ( if (
type === NodeType.CONDITION_BRANCH_NODE || type === BpmNodeTypeEnum.CONDITION_BRANCH_NODE ||
type === NodeType.PARALLEL_BRANCH_NODE || type === BpmNodeTypeEnum.PARALLEL_BRANCH_NODE ||
type === NodeType.INCLUSIVE_BRANCH_NODE type === BpmNodeTypeEnum.INCLUSIVE_BRANCH_NODE
) { ) {
// 1. , // 1. ,
conditionNodes?.forEach((item) => { 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 { 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 { useWatchNode } from '../helpers';
import ProcessNodeTree from './process-node-tree.vue'; import ProcessNodeTree from './process-node-tree.vue';
@ -113,18 +115,18 @@ function validateNode(
) { ) {
if (node) { if (node) {
const { type, showText, conditionNodes } = node; const { type, showText, conditionNodes } = node;
if (type === NodeType.END_EVENT_NODE) { if (type === BpmNodeTypeEnum.END_EVENT_NODE) {
return; return;
} }
if (type === NodeType.START_USER_NODE) { if (type === BpmNodeTypeEnum.START_USER_NODE) {
// //
validateNode(node.childNode, errorNodes); validateNode(node.childNode, errorNodes);
} }
if ( if (
type === NodeType.USER_TASK_NODE || type === BpmNodeTypeEnum.USER_TASK_NODE ||
type === NodeType.COPY_TASK_NODE || type === BpmNodeTypeEnum.COPY_TASK_NODE ||
type === NodeType.CONDITION_NODE type === BpmNodeTypeEnum.CONDITION_NODE
) { ) {
if (!showText) { if (!showText) {
errorNodes.push(node); errorNodes.push(node);
@ -133,9 +135,9 @@ function validateNode(
} }
if ( if (
type === NodeType.CONDITION_BRANCH_NODE || type === BpmNodeTypeEnum.CONDITION_BRANCH_NODE ||
type === NodeType.PARALLEL_BRANCH_NODE || type === BpmNodeTypeEnum.PARALLEL_BRANCH_NODE ||
type === NodeType.INCLUSIVE_BRANCH_NODE type === BpmNodeTypeEnum.INCLUSIVE_BRANCH_NODE
) { ) {
// //
// 1. // 1.

View File

@ -1,4 +1,4 @@
// TODO 芋艿 这些 常量是不是可以共享 import { BpmNodeTypeEnum, BpmTaskStatusEnum } from '#/utils';
interface DictDataType { interface DictDataType {
label: string; label: string;
@ -43,112 +43,6 @@ export enum ApproveMethodType {
SEQUENTIAL_APPROVE = 4, 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 { export enum NodeId {
/** /**
* Id * Id
@ -660,7 +554,7 @@ export type ChildProcessSetting = {
*/ */
export interface SimpleFlowNode { export interface SimpleFlowNode {
id: string; id: string;
type: NodeType; type: BpmNodeTypeEnum;
name: string; name: string;
showText?: string; showText?: string;
// 孩子节点 // 孩子节点
@ -698,7 +592,7 @@ export interface SimpleFlowNode {
// 条件设置 // 条件设置
conditionSetting?: ConditionSetting; conditionSetting?: ConditionSetting;
// 活动的状态,用于前端节点状态展示 // 活动的状态,用于前端节点状态展示
activityStatus?: TaskStatusEnum; activityStatus?: BpmTaskStatusEnum;
// 延迟设置 // 延迟设置
delaySetting?: DelaySetting; delaySetting?: DelaySetting;
// 路由分支 // 路由分支
@ -734,26 +628,26 @@ export const DEFAULT_CONDITION_GROUP_VALUE = {
}; };
export const NODE_DEFAULT_TEXT = new Map<number, string>(); export const NODE_DEFAULT_TEXT = new Map<number, string>();
NODE_DEFAULT_TEXT.set(NodeType.USER_TASK_NODE, '请配置审批人'); NODE_DEFAULT_TEXT.set(BpmNodeTypeEnum.USER_TASK_NODE, '请配置审批人');
NODE_DEFAULT_TEXT.set(NodeType.COPY_TASK_NODE, '请配置抄送人'); NODE_DEFAULT_TEXT.set(BpmNodeTypeEnum.COPY_TASK_NODE, '请配置抄送人');
NODE_DEFAULT_TEXT.set(NodeType.CONDITION_NODE, '请设置条件'); NODE_DEFAULT_TEXT.set(BpmNodeTypeEnum.CONDITION_NODE, '请设置条件');
NODE_DEFAULT_TEXT.set(NodeType.START_USER_NODE, '请设置发起人'); NODE_DEFAULT_TEXT.set(BpmNodeTypeEnum.START_USER_NODE, '请设置发起人');
NODE_DEFAULT_TEXT.set(NodeType.DELAY_TIMER_NODE, '请设置延迟器'); NODE_DEFAULT_TEXT.set(BpmNodeTypeEnum.DELAY_TIMER_NODE, '请设置延迟器');
NODE_DEFAULT_TEXT.set(NodeType.ROUTER_BRANCH_NODE, '请设置路由节点'); NODE_DEFAULT_TEXT.set(BpmNodeTypeEnum.ROUTER_BRANCH_NODE, '请设置路由节点');
NODE_DEFAULT_TEXT.set(NodeType.TRIGGER_NODE, '请设置触发器'); NODE_DEFAULT_TEXT.set(BpmNodeTypeEnum.TRIGGER_NODE, '请设置触发器');
NODE_DEFAULT_TEXT.set(NodeType.TRANSACTOR_NODE, '请设置办理人'); NODE_DEFAULT_TEXT.set(BpmNodeTypeEnum.TRANSACTOR_NODE, '请设置办理人');
NODE_DEFAULT_TEXT.set(NodeType.CHILD_PROCESS_NODE, '请设置子流程'); NODE_DEFAULT_TEXT.set(BpmNodeTypeEnum.CHILD_PROCESS_NODE, '请设置子流程');
export const NODE_DEFAULT_NAME = new Map<number, string>(); export const NODE_DEFAULT_NAME = new Map<number, string>();
NODE_DEFAULT_NAME.set(NodeType.USER_TASK_NODE, '审批人'); NODE_DEFAULT_NAME.set(BpmNodeTypeEnum.USER_TASK_NODE, '审批人');
NODE_DEFAULT_NAME.set(NodeType.COPY_TASK_NODE, '抄送人'); NODE_DEFAULT_NAME.set(BpmNodeTypeEnum.COPY_TASK_NODE, '抄送人');
NODE_DEFAULT_NAME.set(NodeType.CONDITION_NODE, '条件'); NODE_DEFAULT_NAME.set(BpmNodeTypeEnum.CONDITION_NODE, '条件');
NODE_DEFAULT_NAME.set(NodeType.START_USER_NODE, '发起人'); NODE_DEFAULT_NAME.set(BpmNodeTypeEnum.START_USER_NODE, '发起人');
NODE_DEFAULT_NAME.set(NodeType.DELAY_TIMER_NODE, '延迟器'); NODE_DEFAULT_NAME.set(BpmNodeTypeEnum.DELAY_TIMER_NODE, '延迟器');
NODE_DEFAULT_NAME.set(NodeType.ROUTER_BRANCH_NODE, '路由分支'); NODE_DEFAULT_NAME.set(BpmNodeTypeEnum.ROUTER_BRANCH_NODE, '路由分支');
NODE_DEFAULT_NAME.set(NodeType.TRIGGER_NODE, '触发器'); NODE_DEFAULT_NAME.set(BpmNodeTypeEnum.TRIGGER_NODE, '触发器');
NODE_DEFAULT_NAME.set(NodeType.TRANSACTOR_NODE, '办理人'); NODE_DEFAULT_NAME.set(BpmNodeTypeEnum.TRANSACTOR_NODE, '办理人');
NODE_DEFAULT_NAME.set(NodeType.CHILD_PROCESS_NODE, '子流程'); NODE_DEFAULT_NAME.set(BpmNodeTypeEnum.CHILD_PROCESS_NODE, '子流程');
// 候选人策略。暂时不从字典中取。 后续可能调整。控制显示顺序 // 候选人策略。暂时不从字典中取。 后续可能调整。控制显示顺序
export const CANDIDATE_STRATEGY: DictDataType[] = [ export const CANDIDATE_STRATEGY: DictDataType[] = [
@ -930,24 +824,6 @@ export const MULTI_LEVEL_DEPT: DictDataType[] = [
{ label: '第 15 级部门', value: 15 }, { 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 = [ export const DELAY_TYPE = [
{ label: '固定时长', value: DelayTypeEnum.FIXED_TIME_DURATION }, { label: '固定时长', value: DelayTypeEnum.FIXED_TIME_DURATION },
{ label: '固定日期', value: DelayTypeEnum.FIXED_DATE_TIME }, { 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 { inject, ref, toRaw, unref, watch } from 'vue';
import {
BpmNodeTypeEnum,
BpmTaskStatusEnum,
ProcessVariableEnum,
} from '#/utils';
import { import {
ApproveMethodType, ApproveMethodType,
AssignEmptyHandlerType, AssignEmptyHandlerType,
@ -23,10 +29,7 @@ import {
ConditionType, ConditionType,
FieldPermissionType, FieldPermissionType,
NODE_DEFAULT_NAME, NODE_DEFAULT_NAME,
NodeType,
ProcessVariableEnum,
RejectHandlerType, RejectHandlerType,
TaskStatusEnum,
} from './consts'; } from './consts';
export function useWatchNode(props: { export function useWatchNode(props: {
@ -252,7 +255,7 @@ export type CopyTaskFormType = {
/** /**
* @description * @description
*/ */
export function useNodeForm(nodeType: NodeType) { export function useNodeForm(nodeType: BpmNodeTypeEnum) {
const roleOptions = inject<Ref<SystemRoleApi.Role[]>>('roleList', ref([])); // 角色列表 const roleOptions = inject<Ref<SystemRoleApi.Role[]>>('roleList', ref([])); // 角色列表
const postOptions = inject<Ref<SystemPostApi.Post[]>>('postList', ref([])); // 岗位列表 const postOptions = inject<Ref<SystemPostApi.Post[]>>('postList', ref([])); // 岗位列表
const userOptions = inject<Ref<SystemUserApi.User[]>>('userList', ref([])); // 用户列表 const userOptions = inject<Ref<SystemUserApi.User[]>>('userList', ref([])); // 用户列表
@ -269,8 +272,8 @@ export function useNodeForm(nodeType: NodeType) {
const configForm = ref<any | CopyTaskFormType | UserTaskFormType>(); const configForm = ref<any | CopyTaskFormType | UserTaskFormType>();
if ( if (
nodeType === NodeType.USER_TASK_NODE || nodeType === BpmNodeTypeEnum.USER_TASK_NODE ||
nodeType === NodeType.TRANSACTOR_NODE nodeType === BpmNodeTypeEnum.TRANSACTOR_NODE
) { ) {
configForm.value = { configForm.value = {
candidateStrategy: CandidateStrategy.USER, candidateStrategy: CandidateStrategy.USER,
@ -614,7 +617,7 @@ export function useDrawer() {
/** /**
* @description * @description
*/ */
export function useNodeName(nodeType: NodeType) { export function useNodeName(nodeType: BpmNodeTypeEnum) {
// 节点名称 // 节点名称
const nodeName = ref<string>(); 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); const showInput = ref(false);
// 节点名称输入框失去焦点 // 节点名称输入框失去焦点
@ -661,21 +667,21 @@ export function useNodeName2(node: Ref<SimpleFlowNode>, nodeType: NodeType) {
* @description * @description
*/ */
export function useTaskStatusClass( export function useTaskStatusClass(
taskStatus: TaskStatusEnum | undefined, taskStatus: BpmTaskStatusEnum | undefined,
): string { ): string {
if (!taskStatus) { if (!taskStatus) {
return ''; return '';
} }
if (taskStatus === TaskStatusEnum.APPROVE) { if (taskStatus === BpmTaskStatusEnum.APPROVE) {
return 'status-pass'; return 'status-pass';
} }
if (taskStatus === TaskStatusEnum.RUNNING) { if (taskStatus === BpmTaskStatusEnum.RUNNING) {
return 'status-running'; return 'status-running';
} }
if (taskStatus === TaskStatusEnum.REJECT) { if (taskStatus === BpmTaskStatusEnum.REJECT) {
return 'status-reject'; return 'status-reject';
} }
if (taskStatus === TaskStatusEnum.CANCEL) { if (taskStatus === BpmTaskStatusEnum.CANCEL) {
return 'status-cancel'; return 'status-cancel';
} }
return ''; return '';

View File

@ -1,3 +1,7 @@
import './styles/simple-process-designer.scss'; 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 { 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.ADD_SIGN, '加签');
OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.RETURN, '退回'); OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.RETURN, '退回');
OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.COPY, '抄送'); 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 { BpmAutoApproveType, BpmModelFormType, BpmModelType } from '#/utils';
import BasicInfo from './modules/basic-info.vue'; import BasicInfo from './modules/basic-info.vue';
import ExtraSetting from './modules/extra-setting.vue';
import FormDesign from './modules/form-design.vue'; import FormDesign from './modules/form-design.vue';
import ProcessDesign from './modules/process-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 formDesignRef = ref<InstanceType<typeof FormDesign>>();
// //
const processDesignRef = ref<InstanceType<typeof ProcessDesign>>(); const processDesignRef = ref<InstanceType<typeof ProcessDesign>>();
//
const extraSettingRef = ref<InstanceType<typeof ExtraSetting>>();
/** 步骤校验函数 */ /** 步骤校验函数 */
const validateBasic = async () => { const validateBasic = async () => {
@ -71,13 +74,18 @@ const validateProcess = async () => {
await processDesignRef.value?.validate(); await processDesignRef.value?.validate();
}; };
/** 更多设置校验 */
const validateExtra = async () => {
await extraSettingRef.value?.validate();
};
const currentStep = ref(-1); // -1 const currentStep = ref(-1); // -1
const steps = [ const steps = [
{ title: '基本信息', validator: validateBasic }, { title: '基本信息', validator: validateBasic },
{ title: '表单设计', validator: validateForm }, { title: '表单设计', validator: validateForm },
{ title: '流程设计', validator: validateProcess }, { title: '流程设计', validator: validateProcess },
{ title: '更多设置', validator: null }, { title: '更多设置', validator: validateExtra },
]; ];
// //
@ -190,8 +198,8 @@ const initData = async () => {
// currentStep // currentStep
currentStep.value = 0; currentStep.value = 0;
// TODO //
// extraSettingsRef.value.initData() extraSettingRef.value?.initData();
}; };
/** 根据类型切换流程数据 */ /** 根据类型切换流程数据 */
@ -237,7 +245,13 @@ const validateAllSteps = async () => {
return false; return false;
} }
// TODO //
try {
await validateExtra();
} catch {
currentStep.value = 3;
return false;
}
return true; return true;
}; };
@ -345,6 +359,9 @@ const handleStepClick = async (index: number) => {
if (index !== 2) { if (index !== 2) {
await validateProcess(); await validateProcess();
} }
if (index !== 3) {
await validateExtra();
}
// //
currentStep.value = index; currentStep.value = index;
} catch (error) { } catch (error) {
@ -475,8 +492,10 @@ onBeforeUnmount(() => {
ref="processDesignRef" 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> </div>
</Card> </Card>
</div> </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>