diff --git a/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue b/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue
index cdb540322d8d3ddf90e778fed665dcd3efa61d9b..70de02b9ced9d5f2ab6d5c61cf42cdacc59bfa3b 100644
--- a/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue
+++ b/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue
@@ -75,6 +75,7 @@
/>
diff --git a/src/components/SimpleProcessDesignerV2/src/consts.ts b/src/components/SimpleProcessDesignerV2/src/consts.ts
index 7270b104e820c0bf747f19725c99c49ced29a411..34c4cbfbfccb6dac7e336cf6bf09740b2a06ecdc 100644
--- a/src/components/SimpleProcessDesignerV2/src/consts.ts
+++ b/src/components/SimpleProcessDesignerV2/src/consts.ts
@@ -233,6 +233,8 @@ export type TimeoutHandler = {
timeDuration?: string
// 执行动作是自动提醒, 最大提醒次数
maxRemindCount?: number
+ // 执行动作是自动跳转时,跳转的节点ID
+ returnNodeId?: string
}
/**
@@ -291,6 +293,16 @@ export enum RejectHandlerType {
*/
RETURN_USER_TASK = 2
}
+export enum DelaySettingType {
+ /**
+ * 默认开启
+ */
+ FINISH_PROCESS = 1,
+ /**
+ * 延迟器指定节点
+ */
+ RETURN_USER_TASK = 2
+}
// 用户任务超时处理类型枚举
export enum TimeoutHandlerType {
/**
@@ -304,7 +316,11 @@ export enum TimeoutHandlerType {
/**
* 自动拒绝
*/
- REJECT = 3
+ REJECT = 3,
+ /**
+ * 自动跳转
+ */
+ AUTO_JUMP = 4
}
// 用户任务的审批人为空时,处理类型枚举
export enum AssignEmptyHandlerType {
@@ -570,7 +586,8 @@ export const TIME_UNIT_TYPES: DictDataVO[] = [
export const TIMEOUT_HANDLER_TYPES: DictDataVO[] = [
{ label: '自动提醒', value: 1 },
{ label: '自动同意', value: 2 },
- { label: '自动拒绝', value: 3 }
+ { label: '自动拒绝', value: 3 },
+ { label: '自动跳转', value: 4 }
]
export const REJECT_HANDLER_TYPES: DictDataVO[] = [
{ label: '终止流程', value: RejectHandlerType.FINISH_PROCESS },
@@ -700,6 +717,8 @@ export type DelaySetting = {
delayType: number
// 延迟时间表达式
delayTime: string
+ autoJumpEnable?: boolean
+ returnNodeId?: string
}
/**
* 延迟类型
diff --git a/src/components/SimpleProcessDesignerV2/src/node.ts b/src/components/SimpleProcessDesignerV2/src/node.ts
index e3ac7c263d4a0ef31a4027b2753ef7b283b09bce..bbbca9855895d83a807695cdba1b5c2be9dc42a2 100644
--- a/src/components/SimpleProcessDesignerV2/src/node.ts
+++ b/src/components/SimpleProcessDesignerV2/src/node.ts
@@ -156,6 +156,7 @@ export type UserTaskFormType = {
assignStartUserHandlerType?: AssignStartUserHandlerType
timeDuration?: number
maxRemindCount?: number
+ timeoutReturnNodeId?: string
buttonsSetting: any[]
taskCreateListenerEnable?: boolean
taskCreateListenerPath?: string
diff --git a/src/components/SimpleProcessDesignerV2/src/nodes-config/ConditionNodeConfig.vue b/src/components/SimpleProcessDesignerV2/src/nodes-config/ConditionNodeConfig.vue
index 6efed26046780c619b8e51470d89a1de3c722f6a..9871aa9531e5088b58eaab6f369a925ab440f3e3 100644
--- a/src/components/SimpleProcessDesignerV2/src/nodes-config/ConditionNodeConfig.vue
+++ b/src/components/SimpleProcessDesignerV2/src/nodes-config/ConditionNodeConfig.vue
@@ -63,9 +63,43 @@ const props = defineProps({
})
const settingVisible = ref(false)
const currentNode = ref(props.conditionNode)
-const condition = ref()
+const condition = ref({
+ conditionType: ConditionType.RULE, // 设置默认值
+ conditionExpression: '',
+ conditionGroups: {
+ and: true,
+ conditions: [{
+ and: true,
+ rules: [{
+ opCode: '==',
+ leftSide: '',
+ rightSide: ''
+ }]
+ }]
+ }
+})
const open = () => {
- condition.value = currentNode.value.conditionSetting
+ // 如果有已存在的配置则使用,否则使用默认值
+ if (currentNode.value.conditionSetting) {
+ condition.value = JSON.parse(JSON.stringify(currentNode.value.conditionSetting))
+ } else {
+ // 重置为默认值
+ condition.value = {
+ conditionType: ConditionType.RULE,
+ conditionExpression: '',
+ conditionGroups: {
+ and: true,
+ conditions: [{
+ and: true,
+ rules: [{
+ opCode: '==',
+ leftSide: '',
+ rightSide: ''
+ }]
+ }]
+ }
+ }
+ }
settingVisible.value = true
}
@@ -123,15 +157,13 @@ const saveConfig = async () => {
return false
}
currentNode.value.showText = showText
- currentNode.value.conditionSetting!.conditionType = condition.value?.conditionType
- if (currentNode.value.conditionSetting?.conditionType === ConditionType.EXPRESSION) {
- currentNode.value.conditionSetting.conditionGroups = undefined
- currentNode.value.conditionSetting.conditionExpression = condition.value?.conditionExpression
- }
- if (currentNode.value.conditionSetting!.conditionType === ConditionType.RULE) {
- currentNode.value.conditionSetting!.conditionExpression = undefined
- currentNode.value.conditionSetting!.conditionGroups = condition.value?.conditionGroups
- }
+ // 深拷贝保存的条件设置,避免引用问题
+ currentNode.value.conditionSetting = JSON.parse(JSON.stringify({
+ ...currentNode.value.conditionSetting,
+ conditionType: condition.value?.conditionType,
+ conditionExpression: condition.value?.conditionType === ConditionType.EXPRESSION ? condition.value?.conditionExpression : undefined,
+ conditionGroups: condition.value?.conditionType === ConditionType.RULE ? condition.value?.conditionGroups : undefined
+ }))
}
settingVisible.value = false
return true
diff --git a/src/components/SimpleProcessDesignerV2/src/nodes-config/DelayTimerNodeConfig.vue b/src/components/SimpleProcessDesignerV2/src/nodes-config/DelayTimerNodeConfig.vue
index 741796d3a76080ff5e73dfbbf4c18aea7698cea1..6517f84c30106e3f8e6b9b4b9797e4a5905e9108 100644
--- a/src/components/SimpleProcessDesignerV2/src/nodes-config/DelayTimerNodeConfig.vue
+++ b/src/components/SimpleProcessDesignerV2/src/nodes-config/DelayTimerNodeConfig.vue
@@ -65,6 +65,36 @@
/>
后进入下一节点
+
+ 延迟结束后
+
+
+
+
+
+
+
+
+
@@ -104,19 +134,44 @@ const currentNode = useWatchNode(props)
const { nodeName, showInput, clickIcon, blurEvent } = useNodeName(NodeType.DELAY_TIMER_NODE)
// 抄送人表单配置
const formRef = ref() // 表单 Ref
+
+const emits = defineEmits<{
+ 'find:return-task-nodes': [nodeList: SimpleFlowNode[]]
+}>()
+
// 表单校验规则
const formRules = reactive({
delayType: [{ required: true, message: '延迟时间不能为空', trigger: 'change' }],
timeDuration: [{ required: true, message: '延迟时间不能为空', trigger: 'change' }],
- dateTime: [{ required: true, message: '延迟时间不能为空', trigger: 'change' }]
+ dateTime: [{ required: true, message: '延迟时间不能为空', trigger: 'change' }],
+ returnNodeId: [{ required: true, message: '跳转节点不能为空', trigger: 'change' }]
})
// 配置表单数据
const configForm = ref({
delayType: DelayTypeEnum.FIXED_TIME_DURATION,
timeDuration: 1,
timeUnit: TimeUnitType.HOUR,
- dateTime: ''
+ dateTime: '',
+ autoJumpEnable: true, // 默认开启自动跳转
+ returnNodeId: undefined as string | undefined // Change type to string | undefined
})
+
+// 可选的跳转节点列表
+const returnTaskList = ref([])
+
+// 自动跳转开关改变
+const autoJumpChange = () => {
+ if (!configForm.value.autoJumpEnable) {
+ // 当关闭自动跳转时,获取可跳转的节点列表
+ const matchNodeList: SimpleFlowNode[] = []
+ emits('find:return-task-nodes', matchNodeList)
+ returnTaskList.value = matchNodeList
+ } else {
+ // 当开启自动跳转时,清空跳转节点
+ configForm.value.returnNodeId = undefined
+ }
+}
+
// 保存配置
const saveConfig = async () => {
if (!formRef) return false
@@ -129,13 +184,17 @@ const saveConfig = async () => {
if (configForm.value.delayType === DelayTypeEnum.FIXED_TIME_DURATION) {
currentNode.value.delaySetting = {
delayType: configForm.value.delayType,
- delayTime: getIsoTimeDuration()
+ delayTime: getIsoTimeDuration(),
+ autoJumpEnable: configForm.value.autoJumpEnable,
+ returnNodeId: !configForm.value.autoJumpEnable ? configForm.value.returnNodeId || undefined : undefined
}
}
if (configForm.value.delayType === DelayTypeEnum.FIXED_DATE_TIME) {
currentNode.value.delaySetting = {
delayType: configForm.value.delayType,
- delayTime: configForm.value.dateTime
+ delayTime: configForm.value.dateTime,
+ autoJumpEnable: configForm.value.autoJumpEnable,
+ returnNodeId: !configForm.value.autoJumpEnable ? configForm.value.returnNodeId || undefined : undefined
}
}
settingVisible.value = false
@@ -169,6 +228,16 @@ const showDelayTimerNodeConfig = (node: SimpleFlowNode) => {
nodeName.value = node.name
if (node.delaySetting) {
configForm.value.delayType = node.delaySetting.delayType
+ configForm.value.autoJumpEnable = node.delaySetting.autoJumpEnable ?? true
+
+ // 先获取可跳转节点列表
+ const matchNodeList: SimpleFlowNode[] = []
+ emits('find:return-task-nodes', matchNodeList)
+ returnTaskList.value = matchNodeList
+
+ // 再设置选中的节点
+ configForm.value.returnNodeId = node.delaySetting.returnNodeId
+
// 固定时长
if (configForm.value.delayType === DelayTypeEnum.FIXED_TIME_DURATION) {
const strTimeDuration = node.delaySetting.delayTime
diff --git a/src/components/SimpleProcessDesignerV2/src/nodes-config/UserTaskNodeConfig.vue b/src/components/SimpleProcessDesignerV2/src/nodes-config/UserTaskNodeConfig.vue
index 433864b02d2ea9bb2c7b198c20cb646f8ae48911..02ae42120bf4a44aaf0df326bfa986f82a9f779e 100644
--- a/src/components/SimpleProcessDesignerV2/src/nodes-config/UserTaskNodeConfig.vue
+++ b/src/components/SimpleProcessDesignerV2/src/nodes-config/UserTaskNodeConfig.vue
@@ -347,6 +347,25 @@
>
+
+
+
+
+
{{ nodeTypeName }}人为空时
@@ -729,7 +748,9 @@ const saveConfig = async () => {
enable: configForm.value.timeoutHandlerEnable!,
type: cTimeoutType.value,
timeDuration: isoTimeDuration.value,
- maxRemindCount: cTimeoutMaxRemindCount.value
+ maxRemindCount: cTimeoutMaxRemindCount.value,
+ returnNodeId: configForm.value.timeoutHandlerType === TimeoutHandlerType.AUTO_JUMP ?
+ configForm.value.timeoutReturnNodeId : undefined
}
// 设置审批人为空时
currentNode.value.assignEmptyHandler = {
@@ -803,15 +824,24 @@ const showUserTaskNodeConfig = (node: SimpleFlowNode) => {
returnTaskList.value = matchNodeList
// 2.4 设置审批超时处理
configForm.value.timeoutHandlerEnable = node.timeoutHandler?.enable
- if (node.timeoutHandler?.enable && node.timeoutHandler?.timeDuration) {
- const strTimeDuration = node.timeoutHandler.timeDuration
- let parseTime = strTimeDuration.slice(2, strTimeDuration.length - 1)
- let parseTimeUnit = strTimeDuration.slice(strTimeDuration.length - 1)
- configForm.value.timeDuration = parseInt(parseTime)
- timeUnit.value = convertTimeUnit(parseTimeUnit)
+ if (node.timeoutHandler?.enable) {
+ configForm.value.timeoutHandlerType = node.timeoutHandler.type
+ configForm.value.timeoutReturnNodeId = node.timeoutHandler.returnNodeId
+
+ if (node.timeoutHandler.timeDuration) {
+ const strTimeDuration = node.timeoutHandler.timeDuration
+ let parseTime = strTimeDuration.slice(2, strTimeDuration.length - 1)
+ let parseTimeUnit = strTimeDuration.slice(strTimeDuration.length - 1)
+ configForm.value.timeDuration = parseInt(parseTime)
+ timeUnit.value = convertTimeUnit(parseTimeUnit)
+ }
+
+ if (node.timeoutHandler.type === TimeoutHandlerType.AUTO_JUMP) {
+ const matchNodeList: SimpleFlowNode[] = []
+ emits('find:returnTaskNodes', matchNodeList)
+ returnTaskList.value = matchNodeList
+ }
}
- configForm.value.timeoutHandlerType = node.timeoutHandler?.type
- configForm.value.maxRemindCount = node.timeoutHandler?.maxRemindCount
// 2.5 设置审批人为空时
configForm.value.assignEmptyHandlerType = node.assignEmptyHandler?.type
configForm.value.assignEmptyHandlerUserIds = node.assignEmptyHandler?.userIds
@@ -902,6 +932,11 @@ function useTimeoutHandler() {
const timeoutHandlerTypeChanged = () => {
if (configForm.value.timeoutHandlerType === TimeoutHandlerType.REMINDER) {
configForm.value.maxRemindCount = 1 // 超时提醒次数,默认为1
+ } else if (configForm.value.timeoutHandlerType === TimeoutHandlerType.AUTO_JUMP) {
+ // 获取可跳转节点列表
+ const matchNodeList: SimpleFlowNode[] = []
+ emits('find:returnTaskNodes', matchNodeList)
+ returnTaskList.value = matchNodeList
}
}
diff --git a/src/components/SimpleProcessDesignerV2/src/nodes/DelayTimerNode.vue b/src/components/SimpleProcessDesignerV2/src/nodes/DelayTimerNode.vue
index ad6795aa6909ded9991bc6abb9ab31674be9483c..29046c0d74f159cc136b6fdf2dda257e26f307e9 100644
--- a/src/components/SimpleProcessDesignerV2/src/nodes/DelayTimerNode.vue
+++ b/src/components/SimpleProcessDesignerV2/src/nodes/DelayTimerNode.vue
@@ -50,6 +50,7 @@
v-if="!readonly && currentNode"
ref="nodeSetting"
:flow-node="currentNode"
+ @find:return-task-nodes="findReturnTaskNodes"
/>
@@ -65,11 +66,16 @@ const props = defineProps({
flowNode: {
type: Object as () => SimpleFlowNode,
required: true
+ },
+ parentNode: {
+ type: Object as () => SimpleFlowNode,
+ default: null
}
})
// 定义事件,更新父组件。
const emits = defineEmits<{
'update:flowNode': [node: SimpleFlowNode | undefined]
+ 'find:parentNode': [nodeList: SimpleFlowNode[], nodeType: NodeType]
}>()
// 是否只读
const readonly = inject('readonly')
@@ -92,6 +98,76 @@ const openNodeConfig = () => {
const deleteNode = () => {
emits('update:flowNode', currentNode.value.childNode)
}
+
+// 查找可跳转节点
+const findReturnTaskNodes = (matchNodeList: SimpleFlowNode[]) => {
+ // 从父节点查找所有用户任务节点(向上查找)
+ emits('find:parentNode', matchNodeList, NodeType.USER_TASK_NODE)
+
+ // 从根节点开始查找所有用户任务节点(向下查找)
+ const rootNode = findRootNode(currentNode.value)
+ if (rootNode.type === NodeType.USER_TASK_NODE) {
+ // 如果找到了起始节点,从它的子节点开始查找
+ if (rootNode.childNode) {
+ findAllUserTaskNodes(rootNode.childNode, matchNodeList)
+ }
+ } else {
+ // 否则从当前找到的最上层节点开始查找
+ findAllUserTaskNodes(rootNode, matchNodeList)
+ }
+
+ // 过滤掉当前节点
+ const currentNodeId = currentNode.value.id
+ const filteredList = matchNodeList.filter(node => node.id !== currentNodeId)
+ matchNodeList.length = 0
+ matchNodeList.push(...filteredList)
+}
+
+// 查找根节点
+const findRootNode = (node: SimpleFlowNode): SimpleFlowNode => {
+ let parent: SimpleFlowNode | null = props.parentNode
+ let current: SimpleFlowNode = node
+
+ while (parent !== null) {
+ current = parent
+ parent = findParentNode(current)
+ }
+
+ return current
+}
+
+// 查找父节点
+const findParentNode = (node: SimpleFlowNode): SimpleFlowNode | null => {
+ if (!props.parentNode) return null
+ if (props.parentNode.childNode === node) return props.parentNode
+ return null
+}
+
+// 递归查找所有用户任务节点
+const findAllUserTaskNodes = (node: SimpleFlowNode, matchNodeList: SimpleFlowNode[]) => {
+ if (!node) return
+
+ // 检查当前节点
+ if (node.type === NodeType.USER_TASK_NODE) {
+ if (!matchNodeList.some(n => n.id === node.id)) {
+ matchNodeList.push(node)
+ }
+ }
+
+ // 检查子节点
+ if (node.childNode) {
+ findAllUserTaskNodes(node.childNode, matchNodeList)
+ }
+
+ // 检查条件分支节点的子节点
+ if (node.type === NodeType.CONDITION_BRANCH_NODE && node.conditionNodes) {
+ node.conditionNodes.forEach(conditionNode => {
+ if (conditionNode.childNode) {
+ findAllUserTaskNodes(conditionNode.childNode, matchNodeList)
+ }
+ })
+ }
+}
diff --git a/src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue b/src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue
index ae1af6c287957627fcdc5b0febe729ad618593be..2ec34bedd38e9a48c05e7cc8f8e435d242f4aafa 100644
--- a/src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue
+++ b/src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue
@@ -169,8 +169,42 @@ const deleteNode = () => {
const findReturnTaskNodes = (
matchNodeList: SimpleFlowNode[] // 匹配的节点
) => {
- // 从父节点查找
+ // 从父节点查找所有用户任务节点
emits('find:parentNode', matchNodeList, NodeType.USER_TASK_NODE)
+
+ // 递归查找当前节点的子节点
+ findChildUserTaskNodes(currentNode.value, matchNodeList)
+
+ // 过滤掉当前节点
+ const currentNodeId = currentNode.value.id
+ const filteredList = matchNodeList.filter(node => node.id !== currentNodeId)
+ matchNodeList.length = 0 // 清空原数组
+ matchNodeList.push(...filteredList) // 将过滤后的节点重新加入数组
+}
+
+// 递归查找子节点中的用户任务节点
+const findChildUserTaskNodes = (node: SimpleFlowNode, matchNodeList: SimpleFlowNode[]) => {
+ if (!node) return
+
+ // 检查子节点
+ if (node.childNode) {
+ if (node.childNode.type === NodeType.USER_TASK_NODE) {
+ matchNodeList.push(node.childNode)
+ }
+ findChildUserTaskNodes(node.childNode, matchNodeList)
+ }
+
+ // 检查条件分支节点的子节点
+ if (node.type === NodeType.CONDITION_BRANCH_NODE && node.conditionNodes) {
+ node.conditionNodes.forEach(conditionNode => {
+ if (conditionNode.childNode && conditionNode.childNode.type === NodeType.USER_TASK_NODE) {
+ matchNodeList.push(conditionNode.childNode)
+ }
+ if (conditionNode.childNode) {
+ findChildUserTaskNodes(conditionNode.childNode, matchNodeList)
+ }
+ })
+ }
}
// 任务的弹窗显示,用于只读模式