From b9ddd1eaa68c94dc2aa57ccaa27b5cb99e6b51eb Mon Sep 17 00:00:00 2001
From: Lemon <1599456917@qq.com>
Date: Fri, 21 Feb 2025 18:59:46 +0800
Subject: [PATCH 1/2] =?UTF-8?q?=E5=AE=A1=E6=89=B9=E8=B6=85=E6=97=B6?=
=?UTF-8?q?=E5=BB=B6=E8=BF=9F=E5=99=A8=E5=BB=B6=E8=BF=9F=E8=B7=B3=E8=BD=AC?=
=?UTF-8?q?=E4=BB=BB=E6=84=8F=E6=8C=87=E5=AE=9A=E7=9A=84=E8=8A=82=E7=82=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/ProcessNodeTree.vue | 34 ++++++--
.../SimpleProcessDesignerV2/src/consts.ts | 23 +++++-
.../SimpleProcessDesignerV2/src/node.ts | 1 +
.../src/nodes-config/DelayTimerNodeConfig.vue | 77 ++++++++++++++++++-
.../src/nodes-config/UserTaskNodeConfig.vue | 53 ++++++++++---
.../src/nodes/DelayTimerNode.vue | 76 ++++++++++++++++++
.../src/nodes/UserTaskNode.vue | 36 ++++++++-
7 files changed, 277 insertions(+), 23 deletions(-)
diff --git a/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue b/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue
index cdb540322..70de02b9c 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 7270b104e..34c4cbfbf 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 e3ac7c263..bbbca9855 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/DelayTimerNodeConfig.vue b/src/components/SimpleProcessDesignerV2/src/nodes-config/DelayTimerNodeConfig.vue
index 741796d3a..6517f84c3 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 433864b02..02ae42120 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 ad6795aa6..29046c0d7 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 ae1af6c28..2ec34bedd 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)
+ }
+ })
+ }
}
// 任务的弹窗显示,用于只读模式
--
Gitee
From 16c35012c1327a993c48b7127bfede7506ee1941 Mon Sep 17 00:00:00 2001
From: Lemon <1599456917@qq.com>
Date: Sat, 22 Feb 2025 09:48:04 +0800
Subject: [PATCH 2/2] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81=20?=
=?UTF-8?q?=E5=88=87=E6=8D=A2=E7=82=B9=E5=87=BB=E6=9D=A1=E4=BB=B6=E5=88=86?=
=?UTF-8?q?=E6=94=AF=E5=90=8E=E5=B8=A6=E6=9D=A5=E7=9A=84=20=E6=9D=A1?=
=?UTF-8?q?=E4=BB=B6=E5=88=87=E6=8D=A2=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/nodes-config/ConditionNodeConfig.vue | 54 +++++++++++++++----
1 file changed, 43 insertions(+), 11 deletions(-)
diff --git a/src/components/SimpleProcessDesignerV2/src/nodes-config/ConditionNodeConfig.vue b/src/components/SimpleProcessDesignerV2/src/nodes-config/ConditionNodeConfig.vue
index 6efed2604..9871aa953 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
--
Gitee