mirror of
https://gitee.com/cai_xiao_feng/lowflow-design.git
synced 2025-12-06 16:18:22 +08:00
修改为next、分支修改为branches、新增ServiceNode节点
This commit is contained in:
parent
48cbcf35ed
commit
3fe2c36607
@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import TreeNode from './nodes/TreeNode.vue'
|
||||
import Panel from './panels/index.vue'
|
||||
import type { ErrorInfo, FlowNode, TimerNode } from './nodes/type'
|
||||
import type { ErrorInfo, FlowNode, ServiceNode, TimerNode } from './nodes/type'
|
||||
import type {
|
||||
ApprovalNode,
|
||||
BranchNode,
|
||||
@ -73,13 +73,13 @@ const nextId = (): string => {
|
||||
if (node.id === id) {
|
||||
return true
|
||||
}
|
||||
if (node.child) {
|
||||
return findId(node.child, id)
|
||||
if (node.next) {
|
||||
return findId(node.next, id)
|
||||
}
|
||||
if ('children' in node) {
|
||||
if ('branches' in node) {
|
||||
const branchNode = node as BranchNode
|
||||
if (branchNode.children && branchNode.children.length > 0) {
|
||||
return branchNode.children.some((item) => {
|
||||
if (branchNode.branches && branchNode.branches.length > 0) {
|
||||
return branchNode.branches.some((item) => {
|
||||
return findId(item, id)
|
||||
})
|
||||
}
|
||||
@ -92,53 +92,53 @@ const nextId = (): string => {
|
||||
return id
|
||||
}
|
||||
const addExclusive = (node: FlowNode) => {
|
||||
const child = node.child
|
||||
const next = node.next
|
||||
const id = nextId()
|
||||
const exclusiveNode = {
|
||||
id: id,
|
||||
pid: node.id,
|
||||
type: 'exclusive',
|
||||
name: '独占网关',
|
||||
child: child,
|
||||
children: []
|
||||
next: next,
|
||||
branches: []
|
||||
} as ExclusiveNode
|
||||
if (child) {
|
||||
child.pid = id
|
||||
if (next) {
|
||||
next.pid = id
|
||||
}
|
||||
addCondition(exclusiveNode)
|
||||
addCondition(exclusiveNode)
|
||||
node.child = exclusiveNode
|
||||
if (exclusiveNode.children.length > 0) {
|
||||
const condition = exclusiveNode.children[exclusiveNode.children.length - 1] as ConditionNode
|
||||
node.next = exclusiveNode
|
||||
if (exclusiveNode.branches.length > 0) {
|
||||
const condition = exclusiveNode.branches[exclusiveNode.branches.length - 1] as ConditionNode
|
||||
condition.def = true
|
||||
condition.name = '默认条件'
|
||||
}
|
||||
}
|
||||
const addCondition = (node: FlowNode) => {
|
||||
const exclusive = node as ExclusiveNode
|
||||
exclusive.children.splice(exclusive.children.length - 1, 0, {
|
||||
exclusive.branches.splice(exclusive.branches.length - 1, 0, {
|
||||
id: nextId(),
|
||||
pid: exclusive.id,
|
||||
type: 'condition',
|
||||
def: false,
|
||||
name: `条件${exclusive.children.length + 1}`,
|
||||
name: `条件${exclusive.branches.length + 1}`,
|
||||
conditions: {
|
||||
operator: 'and',
|
||||
conditions: [],
|
||||
groups: []
|
||||
} as FilterRules,
|
||||
child: undefined
|
||||
next: undefined
|
||||
})
|
||||
}
|
||||
const addCc = (node: FlowNode) => {
|
||||
const child = node.child
|
||||
const next = node.next
|
||||
const id = nextId()
|
||||
node.child = {
|
||||
node.next = {
|
||||
id: id,
|
||||
pid: node.id,
|
||||
type: 'cc',
|
||||
name: '抄送人',
|
||||
child: child,
|
||||
next: next,
|
||||
assigneeType: 'user',
|
||||
formUser: '',
|
||||
formRole: '',
|
||||
@ -150,38 +150,38 @@ const addCc = (node: FlowNode) => {
|
||||
self: false,
|
||||
formProperties: []
|
||||
} as CcNode
|
||||
if (child) {
|
||||
child.pid = id
|
||||
if (next) {
|
||||
next.pid = id
|
||||
}
|
||||
}
|
||||
const addTimer = (node: FlowNode) => {
|
||||
const child = node.child
|
||||
const next = node.next
|
||||
const id = nextId()
|
||||
node.child = {
|
||||
node.next = {
|
||||
id: id,
|
||||
pid: node.id,
|
||||
name: '计时等待',
|
||||
type: 'timer',
|
||||
child: child,
|
||||
next: next,
|
||||
waitType: 'duration',
|
||||
unit: 'PT%sS',
|
||||
duration: 0,
|
||||
timeDate: undefined
|
||||
} as TimerNode
|
||||
if (child) {
|
||||
child.pid = id
|
||||
if (next) {
|
||||
next.pid = id
|
||||
}
|
||||
}
|
||||
|
||||
const addNotify = (node: FlowNode) => {
|
||||
const child = node.child
|
||||
const next = node.next
|
||||
const id = nextId()
|
||||
node.child = {
|
||||
node.next = {
|
||||
id: id,
|
||||
pid: node.id,
|
||||
name: '消息通知',
|
||||
type: 'notify',
|
||||
child: child,
|
||||
next: next,
|
||||
assigneeType: 'user',
|
||||
formUser: '',
|
||||
formRole: '',
|
||||
@ -195,20 +195,36 @@ const addNotify = (node: FlowNode) => {
|
||||
subject: '',
|
||||
content: ''
|
||||
} as NotifyNode
|
||||
if (child) {
|
||||
child.pid = id
|
||||
if (next) {
|
||||
next.pid = id
|
||||
}
|
||||
}
|
||||
const addService = (node: FlowNode) => {
|
||||
const next = node.next
|
||||
const id = nextId()
|
||||
node.next = {
|
||||
id: id,
|
||||
pid: node.id,
|
||||
type: 'service',
|
||||
name: '服务节点',
|
||||
next: next,
|
||||
implementationType: '',
|
||||
implementation: '',
|
||||
} as ServiceNode
|
||||
if (next) {
|
||||
next.pid = id
|
||||
}
|
||||
}
|
||||
const addApproval = (node: FlowNode) => {
|
||||
const child = node.child
|
||||
const next = node.next
|
||||
const id = nextId()
|
||||
node.child = {
|
||||
node.next = {
|
||||
id: id,
|
||||
pid: node.id,
|
||||
type: 'approval',
|
||||
name: '审批人',
|
||||
executionListeners: [],
|
||||
child: child,
|
||||
next: next,
|
||||
// 属性
|
||||
assigneeType: 'user',
|
||||
formUser: '',
|
||||
@ -234,8 +250,8 @@ const addApproval = (node: FlowNode) => {
|
||||
minusMulti: false
|
||||
}
|
||||
} as ApprovalNode
|
||||
if (child) {
|
||||
child.pid = id
|
||||
if (next) {
|
||||
next.pid = id
|
||||
}
|
||||
}
|
||||
const addNode = (type: NodeType, node: FlowNode) => {
|
||||
@ -245,6 +261,7 @@ const addNode = (type: NodeType, node: FlowNode) => {
|
||||
cc: addCc,
|
||||
timer: addTimer,
|
||||
notify: addNotify,
|
||||
service: addService,
|
||||
approval: addApproval
|
||||
}
|
||||
const fun = addMap[type]
|
||||
@ -257,32 +274,32 @@ const delNode = (del: FlowNode) => {
|
||||
const delNodeNext = (next: FlowNode, del: FlowNode) => {
|
||||
delete nodesError.value[del.id]
|
||||
if (next.id === del.pid) {
|
||||
if ('children' in next && next.child?.id !== del.id) {
|
||||
if ('branches' in next && next.next?.id !== del.id) {
|
||||
const branchNode = next as BranchNode
|
||||
const index = branchNode.children.findIndex((item) => item.id === del.id)
|
||||
const index = branchNode.branches.findIndex((item) => item.id === del.id)
|
||||
if (index !== -1) {
|
||||
if (branchNode.children.length <= 2) {
|
||||
if (branchNode.branches.length <= 2) {
|
||||
delError(branchNode)
|
||||
delNode(branchNode)
|
||||
} else {
|
||||
delError(del)
|
||||
branchNode.children.splice(index, 1)
|
||||
branchNode.branches.splice(index, 1)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (del.child && del.child.pid) {
|
||||
del.child.pid = next.id
|
||||
if (del.next && del.next.pid) {
|
||||
del.next.pid = next.id
|
||||
}
|
||||
next.child = del.child
|
||||
next.next = del.next
|
||||
}
|
||||
} else {
|
||||
if (next.child) {
|
||||
delNodeNext(next.child, del)
|
||||
if (next.next) {
|
||||
delNodeNext(next.next, del)
|
||||
}
|
||||
if ('children' in next) {
|
||||
if ('branches' in next) {
|
||||
const nextBranch = next as BranchNode
|
||||
if (nextBranch.children && nextBranch.children.length > 0) {
|
||||
nextBranch.children.forEach((item) => {
|
||||
if (nextBranch.branches && nextBranch.branches.length > 0) {
|
||||
nextBranch.branches.forEach((item) => {
|
||||
delNodeNext(item, del)
|
||||
})
|
||||
}
|
||||
@ -291,13 +308,13 @@ const delNodeNext = (next: FlowNode, del: FlowNode) => {
|
||||
}
|
||||
const delError = (node: FlowNode) => {
|
||||
delete nodesError.value[node.id]
|
||||
if (node.child) {
|
||||
delError(node.child)
|
||||
if (node.next) {
|
||||
delError(node.next)
|
||||
}
|
||||
if ('children' in node) {
|
||||
if ('branches' in node) {
|
||||
const branchNode = node as BranchNode
|
||||
if (branchNode.children && branchNode.children.length > 0) {
|
||||
branchNode.children.forEach((item) => {
|
||||
if (branchNode.branches && branchNode.branches.length > 0) {
|
||||
branchNode.branches.forEach((item) => {
|
||||
delError(item)
|
||||
})
|
||||
}
|
||||
|
||||
@ -30,6 +30,10 @@ const addNotifyNode = () => {
|
||||
$emits('addNode', 'notify')
|
||||
popoverRef.value?.hide()
|
||||
}
|
||||
const addServiceNode = () => {
|
||||
$emits('addNode', 'service')
|
||||
popoverRef.value?.hide()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -62,6 +66,10 @@ const addNotifyNode = () => {
|
||||
<svg-icon name="el:BellFilled" />
|
||||
<el-text>消息通知</el-text>
|
||||
</div>
|
||||
<div class="node-select" @click="addServiceNode">
|
||||
<svg-icon name="el:Tools" />
|
||||
<el-text>服务节点</el-text>
|
||||
</div>
|
||||
</el-space>
|
||||
<template #reference>
|
||||
<el-button
|
||||
@ -117,6 +125,10 @@ const addNotifyNode = () => {
|
||||
&.BellFilled {
|
||||
background-color: #95d475;
|
||||
}
|
||||
|
||||
&.Tools {
|
||||
background-color: #ffc107;
|
||||
}
|
||||
}
|
||||
|
||||
.el-text {
|
||||
|
||||
@ -13,13 +13,13 @@ const { nodesError } = inject<{
|
||||
const content = ref<string>('')
|
||||
watchEffect(() => {
|
||||
const errors: ErrorInfo[] = []
|
||||
const { id, name, def, conditions, child } = props.node
|
||||
const { id, name, def, conditions, next } = props.node
|
||||
if (def) {
|
||||
content.value = '不满足其他条件,进入此分支'
|
||||
} else if (conditions.conditions.length > 0 || (conditions.groups?.length || 0) > 0) {
|
||||
const count = conditions.conditions.length + (conditions.groups?.length || 0)
|
||||
content.value = `已设置(${count})个条件`
|
||||
if (!child) {
|
||||
if (!next) {
|
||||
errors.push({ id: id, name: name, message: '分支下节点为空' })
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -17,14 +17,14 @@ const addNode = (type: NodeType, node?: FlowNode) => {
|
||||
$emits('addNode', type, node || props.node)
|
||||
}
|
||||
const moveRight = (index: number) => {
|
||||
const node = props.node.children[index]
|
||||
props.node.children.splice(index, 1)
|
||||
props.node.children.splice(index + 1, 0, node)
|
||||
const node = props.node.branches[index]
|
||||
props.node.branches.splice(index, 1)
|
||||
props.node.branches.splice(index + 1, 0, node)
|
||||
}
|
||||
const moveLeft = (index: number) => {
|
||||
const node = props.node.children[index]
|
||||
props.node.children.splice(index, 1)
|
||||
props.node.children.splice(index - 1, 0, node)
|
||||
const node = props.node.branches[index]
|
||||
props.node.branches.splice(index, 1)
|
||||
props.node.branches.splice(index - 1, 0, node)
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -33,12 +33,12 @@ const moveLeft = (index: number) => {
|
||||
<div class="add-branch">
|
||||
<slot :addNode="addNode" :readOnly="readOnly"></slot>
|
||||
</div>
|
||||
<div v-for="(item, index) in node.children" :key="item.id" class="col-box">
|
||||
<div v-for="(item, index) in node.branches" :key="item.id" class="col-box">
|
||||
<template v-if="index === 0">
|
||||
<div class="top-left-border"></div>
|
||||
<div class="bottom-left-border" />
|
||||
</template>
|
||||
<template v-else-if="node.children.length === index + 1">
|
||||
<template v-else-if="node.branches.length === index + 1">
|
||||
<div class="top-right-border"></div>
|
||||
<div class="bottom-right-border" />
|
||||
</template>
|
||||
@ -47,14 +47,14 @@ const moveLeft = (index: number) => {
|
||||
<div
|
||||
class="move-left"
|
||||
@click.stop="moveLeft(index)"
|
||||
v-show="index !== 0 && node.children.length !== index + 1 && !readOnly"
|
||||
v-show="index !== 0 && node.branches.length !== index + 1 && !readOnly"
|
||||
>
|
||||
<svg-icon name="el:ArrowLeft" />
|
||||
</div>
|
||||
<div
|
||||
class="move-right"
|
||||
@click.stop="moveRight(index)"
|
||||
v-show="![index + 1, index + 2].includes(node.children.length) && !readOnly"
|
||||
v-show="![index + 1, index + 2].includes(node.branches.length) && !readOnly"
|
||||
>
|
||||
<svg-icon name="el:ArrowRight" />
|
||||
</div>
|
||||
|
||||
40
src/views/flowDesign/nodes/ServiceNode.vue
Normal file
40
src/views/flowDesign/nodes/ServiceNode.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<script setup lang="ts">
|
||||
import Node from './Node.vue'
|
||||
import type { ErrorInfo, ServiceNode } from './type'
|
||||
import type { Ref } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
node: ServiceNode
|
||||
}>()
|
||||
const { nodesError } = inject<{
|
||||
nodesError: Ref<Recordable<ErrorInfo[]>>
|
||||
}>('flowDesign', { nodesError: ref({}) })
|
||||
const content = ref<string>('')
|
||||
watchEffect(() => {
|
||||
const errors: ErrorInfo[] = []
|
||||
const { id, name, implementationType, implementation } = props.node
|
||||
if (!implementationType) {
|
||||
errors.push({ id: id, name: name, message: '执行类型为空' })
|
||||
content.value = '执行类型为空'
|
||||
} else if (!implementation) {
|
||||
errors.push({ id: id, name: name, message: '执行值为空' })
|
||||
content.value = '执行值为空'
|
||||
} else {
|
||||
content.value = `执行服务`
|
||||
}
|
||||
// 记录错误
|
||||
if (errors.length > 0) {
|
||||
nodesError.value[id] = errors
|
||||
} else {
|
||||
delete nodesError.value[id]
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Node v-bind="$attrs" icon="el:Tools" color="#ffc107" :node="node">
|
||||
<el-text>{{ content }}</el-text>
|
||||
</Node>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
@ -12,8 +12,8 @@ const { nodesError } = inject<{
|
||||
}>('flowDesign', { nodesError: ref({}) })
|
||||
watchEffect(() => {
|
||||
const errors: ErrorInfo[] = []
|
||||
const { id, name, child } = props.node
|
||||
if (child?.type === 'end') {
|
||||
const { id, name, next } = props.node
|
||||
if (next?.type === 'end') {
|
||||
errors.push({ id: id, name: name, message: '发起下节点为空' })
|
||||
}
|
||||
// 记录错误
|
||||
|
||||
@ -7,6 +7,7 @@ import Approval from './ApprovalNode.vue'
|
||||
import Cc from './CcNode.vue'
|
||||
import Timer from './TimerNode.vue'
|
||||
import Notify from './NotifyNode.vue'
|
||||
import Service from './ServiceNode.vue'
|
||||
import Exclusive from './ExclusiveNode.vue'
|
||||
import Condition from './ConditionNode.vue'
|
||||
|
||||
@ -19,6 +20,7 @@ const nodes: Recordable<Component> = {
|
||||
cc: Cc,
|
||||
timer: Timer,
|
||||
notify: Notify,
|
||||
service: Service,
|
||||
exclusive: Exclusive,
|
||||
condition: Condition,
|
||||
end: End
|
||||
@ -32,7 +34,7 @@ const nodes: Recordable<Component> = {
|
||||
<slot :name="name" v-bind="scope || {}"></slot>
|
||||
</template>
|
||||
</component>
|
||||
<TreeNode v-if="node.child" :node="node.child" v-bind="$attrs" />
|
||||
<TreeNode v-if="node.next" :node="node.next" v-bind="$attrs" />
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
@ -7,6 +7,7 @@ export type NodeType =
|
||||
| 'exclusive'
|
||||
| 'timer'
|
||||
| 'notify'
|
||||
| 'service'
|
||||
| 'condition'
|
||||
| 'end'
|
||||
|
||||
@ -16,7 +17,7 @@ export interface FlowNode {
|
||||
name: string
|
||||
type: NodeType
|
||||
executionListeners?: NodeListener[]
|
||||
child?: FlowNode
|
||||
next?: FlowNode
|
||||
}
|
||||
|
||||
export interface NodeListener {
|
||||
@ -88,6 +89,11 @@ export interface ApprovalNode extends AssigneeNode {
|
||||
taskListeners?: NodeListener[]
|
||||
}
|
||||
|
||||
export interface ServiceNode extends FlowNode {
|
||||
implementationType: string
|
||||
implementation: string
|
||||
}
|
||||
|
||||
export interface TimerNode extends FlowNode {
|
||||
waitType: 'duration' | 'date'
|
||||
unit: 'PT%sS' | 'PT%sM' | 'PT%sH' | 'P%sD' | 'P%sW' | 'P%sM'
|
||||
@ -101,11 +107,11 @@ export interface ConditionNode extends FlowNode {
|
||||
}
|
||||
|
||||
export interface BranchNode extends FlowNode {
|
||||
children: FlowNode[]
|
||||
branches: FlowNode[]
|
||||
}
|
||||
|
||||
export interface ExclusiveNode extends BranchNode {
|
||||
children: ConditionNode[]
|
||||
branches: ConditionNode[]
|
||||
}
|
||||
|
||||
export interface ErrorInfo {
|
||||
|
||||
40
src/views/flowDesign/panels/ServicePanel.vue
Normal file
40
src/views/flowDesign/panels/ServicePanel.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<script setup lang="ts">
|
||||
import type { ServiceNode } from '../nodes/type'
|
||||
|
||||
defineProps<{
|
||||
activeData: ServiceNode
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-form label-position="top">
|
||||
<el-form-item prop="implementationType" label="执行类型">
|
||||
<el-select v-model="activeData.implementationType" placeholder="请选择执行类型">
|
||||
<el-option label="类" value="class" />
|
||||
<el-option label="表达式" value="expression" />
|
||||
<el-option label="委托表达式" value="delegateExpression" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item prop="implementation" label="执行值">
|
||||
<template #label>
|
||||
<div class="flex-items-center gap3px">
|
||||
<span>执行值</span>
|
||||
<el-tooltip placement="top-start">
|
||||
<template #content>
|
||||
实现 JavaDelegate 接口 <br />
|
||||
类:${com.example.delegate.MyServiceDelegate} <br />
|
||||
表达式: ${myServiceDelegate.execute(execution)} <br />
|
||||
委托表达式:${myServiceDelegate}
|
||||
</template>
|
||||
<el-icon>
|
||||
<QuestionFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input v-model="activeData.implementation" placeholder="请输入执行值" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
@ -6,6 +6,7 @@ import Approval from './ApprovalPanel.vue'
|
||||
import Cc from './CcPanel.vue'
|
||||
import Timer from './TimerPanel.vue'
|
||||
import Notify from './NotifyPanel.vue'
|
||||
import Service from './ServicePanel.vue'
|
||||
import Condition from './ConditionPanel.vue'
|
||||
import End from './EndPanel.vue'
|
||||
import type { FlowNode } from '../nodes/type'
|
||||
@ -20,6 +21,7 @@ const panels: Recordable<Component> = {
|
||||
cc: Cc,
|
||||
timer: Timer,
|
||||
notify: Notify,
|
||||
service: Service,
|
||||
condition: Condition,
|
||||
end: End
|
||||
}
|
||||
|
||||
@ -12,13 +12,13 @@ const process = ref<FlowNode>({
|
||||
name: '发起人',
|
||||
executionListeners: [],
|
||||
formProperties: [],
|
||||
child: {
|
||||
next: {
|
||||
id: 'end',
|
||||
pid: 'root',
|
||||
type: 'end',
|
||||
name: '流程结束',
|
||||
executionListeners: [],
|
||||
child: undefined
|
||||
next: undefined
|
||||
} as EndNode
|
||||
} as StartNode)
|
||||
// 表单字段
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user