|
@@ -1,154 +1,200 @@
|
|
|
<template>
|
|
<template>
|
|
|
- <div class="w-full h-full">
|
|
|
|
|
- <Workflow
|
|
|
|
|
- :workflow="workflow"
|
|
|
|
|
- @click:node="handleNodeClick"
|
|
|
|
|
- @create:node="handleNodeCreate"
|
|
|
|
|
- @create:connection="onCreateConnection"
|
|
|
|
|
- @drop="handleDrop"
|
|
|
|
|
- @run="handleRunWorkflow"
|
|
|
|
|
- />
|
|
|
|
|
- <RunWork v-model:visible="runVisible" />
|
|
|
|
|
- <Setter :data="nodeID" v-model:visible="setterVisible" />
|
|
|
|
|
|
|
+ <div class="w-full h-full flex flex-col">
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="h-60px border-b border-b-solid border-gray-200 flex items-center justify-between px-12px"
|
|
|
|
|
+ >
|
|
|
|
|
+ <div class="left flex items-center gap-4">
|
|
|
|
|
+ <el-breadcrumb separator="/">
|
|
|
|
|
+ <el-breadcrumb-item>Workspace</el-breadcrumb-item>
|
|
|
|
|
+ <el-breadcrumb-item>workflow_1</el-breadcrumb-item>
|
|
|
|
|
+ </el-breadcrumb>
|
|
|
|
|
+ <IconButton icon="iconoir:plus" type="primary" link>标签</IconButton>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="right flex items-center gap-2">
|
|
|
|
|
+ <el-button type="default" size="small">发布</el-button>
|
|
|
|
|
+ <IconButton icon="lucide:history" type="default" link></IconButton>
|
|
|
|
|
+ <el-dropdown placement="bottom-end" popper-class="w-120px">
|
|
|
|
|
+ <IconButton icon="fluent-mdl2:more" type="default" link></IconButton>
|
|
|
|
|
+ <template #dropdown>
|
|
|
|
|
+ <el-dropdown-item>描述</el-dropdown-item>
|
|
|
|
|
+ <el-dropdown-item>复用</el-dropdown-item>
|
|
|
|
|
+ <el-dropdown-item>重命名</el-dropdown-item>
|
|
|
|
|
+ <el-dropdown-item divided>删除</el-dropdown-item>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-dropdown>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <el-splitter layout="vertical" class="flex-1">
|
|
|
|
|
+ <el-splitter-panel>
|
|
|
|
|
+ <Workflow
|
|
|
|
|
+ :workflow="workflow"
|
|
|
|
|
+ @click:node="handleNodeClick"
|
|
|
|
|
+ @create:node="handleNodeCreate"
|
|
|
|
|
+ @create:connection="onCreateConnection"
|
|
|
|
|
+ @drop="handleDrop"
|
|
|
|
|
+ @run="handleRunWorkflow"
|
|
|
|
|
+ class="bg-#f5f5f5"
|
|
|
|
|
+ />
|
|
|
|
|
+ <RunWork v-model:visible="runVisible" />
|
|
|
|
|
+ <Setter :data="nodeID" v-model:visible="setterVisible" />
|
|
|
|
|
+ </el-splitter-panel>
|
|
|
|
|
+
|
|
|
|
|
+ <el-splitter-panel v-model:size.lazy="footerHeight" :min="32">
|
|
|
|
|
+ <EditorFooter @toggle="handleFooterToggle" />
|
|
|
|
|
+ </el-splitter-panel>
|
|
|
|
|
+ </el-splitter>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
|
|
+import { ref, inject, type CSSProperties } from 'vue'
|
|
|
import { startNode, endNode, httpNode, conditionNode, databaseNode, codeNode } from '@repo/nodes'
|
|
import { startNode, endNode, httpNode, conditionNode, databaseNode, codeNode } from '@repo/nodes'
|
|
|
import { Workflow, type IWorkflow, type XYPosition, type Connection } from '@repo/workflow'
|
|
import { Workflow, type IWorkflow, type XYPosition, type Connection } from '@repo/workflow'
|
|
|
|
|
+
|
|
|
import Setter from '@/components/setter/index.vue'
|
|
import Setter from '@/components/setter/index.vue'
|
|
|
import RunWork from '@/components/RunWork.vue'
|
|
import RunWork from '@/components/RunWork.vue'
|
|
|
|
|
+import EditorFooter from '@/features/editorFooter/index.vue'
|
|
|
|
|
+
|
|
|
|
|
+import { IconButton } from '@repo/ui'
|
|
|
|
|
+
|
|
|
import type { SourceType } from '@repo/nodes'
|
|
import type { SourceType } from '@repo/nodes'
|
|
|
-import { ref } from 'vue'
|
|
|
|
|
|
|
+
|
|
|
|
|
+const layout = inject<{ setMainStyle: (style: CSSProperties) => void }>('layout')
|
|
|
|
|
+
|
|
|
|
|
+layout?.setMainStyle({
|
|
|
|
|
+ padding: '0px'
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const footerHeight = ref(32)
|
|
|
|
|
|
|
|
const workflow = ref<IWorkflow>({
|
|
const workflow = ref<IWorkflow>({
|
|
|
id: '1',
|
|
id: '1',
|
|
|
nodes: [
|
|
nodes: [
|
|
|
- startNode, // 初始化节点,
|
|
|
|
|
- endNode, // 初始化节点,
|
|
|
|
|
- // httpNode,
|
|
|
|
|
- // conditionNode,
|
|
|
|
|
- // databaseNode,
|
|
|
|
|
- // codeNode
|
|
|
|
|
- {
|
|
|
|
|
- id: 'node-1',
|
|
|
|
|
- type: 'canvas-node',
|
|
|
|
|
- position: { x: 100, y: 100 },
|
|
|
|
|
- data: {
|
|
|
|
|
- version: ['1.0.0'],
|
|
|
|
|
- displayName: '用户输入',
|
|
|
|
|
- name: 'chart',
|
|
|
|
|
- description: '通过用户输入开启流程处理',
|
|
|
|
|
- icon: 'fluent:comment-multiple-28-regular',
|
|
|
|
|
- iconColor: '#296dff',
|
|
|
|
|
- inputs: [],
|
|
|
|
|
- outputs: [
|
|
|
|
|
- {
|
|
|
|
|
- index: 0,
|
|
|
|
|
- type: 'main'
|
|
|
|
|
- }
|
|
|
|
|
- ]
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 'node-2',
|
|
|
|
|
- type: 'canvas-node',
|
|
|
|
|
- position: { x: 400, y: 100 },
|
|
|
|
|
- data: {
|
|
|
|
|
- version: ['1.0.0'],
|
|
|
|
|
- displayName: '条件判断',
|
|
|
|
|
- name: 'if',
|
|
|
|
|
- description: '通过条件判断拆分多个流程分支',
|
|
|
|
|
- icon: 'roentgen:guidepost',
|
|
|
|
|
- iconColor: '#108e49',
|
|
|
|
|
- inputs: [
|
|
|
|
|
- {
|
|
|
|
|
- index: 0,
|
|
|
|
|
- type: 'main'
|
|
|
|
|
- }
|
|
|
|
|
- ],
|
|
|
|
|
- outputs: [
|
|
|
|
|
- {
|
|
|
|
|
- index: 0,
|
|
|
|
|
- type: 'main',
|
|
|
|
|
- label: 'true'
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- index: 1,
|
|
|
|
|
- type: 'main',
|
|
|
|
|
- label: 'false'
|
|
|
|
|
- }
|
|
|
|
|
- ],
|
|
|
|
|
- outputNames: ['true', 'false']
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 'node-3',
|
|
|
|
|
- type: 'canvas-node',
|
|
|
|
|
- width: 96,
|
|
|
|
|
- height: 96,
|
|
|
|
|
- position: { x: 600, y: 300 },
|
|
|
|
|
- data: {
|
|
|
|
|
- version: ['1.0.0'],
|
|
|
|
|
- displayName: '条件判断',
|
|
|
|
|
- name: 'if',
|
|
|
|
|
- description: '通过条件判断拆分多个流程分支',
|
|
|
|
|
- icon: 'roentgen:guidepost',
|
|
|
|
|
- iconColor: '#108e49',
|
|
|
|
|
- inputs: [
|
|
|
|
|
- {
|
|
|
|
|
- index: 0,
|
|
|
|
|
- type: 'main'
|
|
|
|
|
- }
|
|
|
|
|
- ],
|
|
|
|
|
- outputs: [
|
|
|
|
|
- {
|
|
|
|
|
- index: 0,
|
|
|
|
|
- type: 'main',
|
|
|
|
|
- label: 'true'
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- index: 1,
|
|
|
|
|
- type: 'main',
|
|
|
|
|
- label: 'false'
|
|
|
|
|
- }
|
|
|
|
|
- ],
|
|
|
|
|
- outputNames: ['true', 'false']
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 'node-note',
|
|
|
|
|
- type: 'canvas-node',
|
|
|
|
|
- position: { x: 600, y: 300 },
|
|
|
|
|
- data: {
|
|
|
|
|
- version: ['1.0.0'],
|
|
|
|
|
- displayName: '条件判断',
|
|
|
|
|
- name: 'if',
|
|
|
|
|
- description: '通过条件判断拆分多个流程分支',
|
|
|
|
|
- icon: 'roentgen:guidepost',
|
|
|
|
|
- iconColor: '#108e49',
|
|
|
|
|
- inputs: [],
|
|
|
|
|
- outputs: [],
|
|
|
|
|
- // 便签数据
|
|
|
|
|
- renderType: 'stickyNote',
|
|
|
|
|
- content:
|
|
|
|
|
- '# 标题\n\n这是一些便签内容,可以使用 **Markdown** 语法进行格式化。\n\n- 列表项 1\n- 列表项 2\n\n[链接](https://example.com)',
|
|
|
|
|
- width: 400,
|
|
|
|
|
- height: 200,
|
|
|
|
|
- color: '#d6f5e3'
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // startNode, // 初始化节点,
|
|
|
|
|
+ // endNode, // 初始化节点,
|
|
|
|
|
+ // // httpNode,
|
|
|
|
|
+ // // conditionNode,
|
|
|
|
|
+ // // databaseNode,
|
|
|
|
|
+ // // codeNode
|
|
|
|
|
+ // {
|
|
|
|
|
+ // id: 'node-1',
|
|
|
|
|
+ // type: 'canvas-node',
|
|
|
|
|
+ // position: { x: 100, y: 100 },
|
|
|
|
|
+ // data: {
|
|
|
|
|
+ // version: ['1.0.0'],
|
|
|
|
|
+ // displayName: '用户输入',
|
|
|
|
|
+ // name: 'chart',
|
|
|
|
|
+ // description: '通过用户输入开启流程处理',
|
|
|
|
|
+ // icon: 'fluent:comment-multiple-28-regular',
|
|
|
|
|
+ // iconColor: '#296dff',
|
|
|
|
|
+ // inputs: [],
|
|
|
|
|
+ // outputs: [
|
|
|
|
|
+ // {
|
|
|
|
|
+ // index: 0,
|
|
|
|
|
+ // type: 'main'
|
|
|
|
|
+ // }
|
|
|
|
|
+ // ]
|
|
|
|
|
+ // }
|
|
|
|
|
+ // },
|
|
|
|
|
+ // {
|
|
|
|
|
+ // id: 'node-2',
|
|
|
|
|
+ // type: 'canvas-node',
|
|
|
|
|
+ // position: { x: 400, y: 100 },
|
|
|
|
|
+ // data: {
|
|
|
|
|
+ // version: ['1.0.0'],
|
|
|
|
|
+ // displayName: '条件判断',
|
|
|
|
|
+ // name: 'if',
|
|
|
|
|
+ // description: '通过条件判断拆分多个流程分支',
|
|
|
|
|
+ // icon: 'roentgen:guidepost',
|
|
|
|
|
+ // iconColor: '#108e49',
|
|
|
|
|
+ // inputs: [
|
|
|
|
|
+ // {
|
|
|
|
|
+ // index: 0,
|
|
|
|
|
+ // type: 'main'
|
|
|
|
|
+ // }
|
|
|
|
|
+ // ],
|
|
|
|
|
+ // outputs: [
|
|
|
|
|
+ // {
|
|
|
|
|
+ // index: 0,
|
|
|
|
|
+ // type: 'main',
|
|
|
|
|
+ // label: 'true'
|
|
|
|
|
+ // },
|
|
|
|
|
+ // {
|
|
|
|
|
+ // index: 1,
|
|
|
|
|
+ // type: 'main',
|
|
|
|
|
+ // label: 'false'
|
|
|
|
|
+ // }
|
|
|
|
|
+ // ],
|
|
|
|
|
+ // outputNames: ['true', 'false']
|
|
|
|
|
+ // }
|
|
|
|
|
+ // },
|
|
|
|
|
+ // {
|
|
|
|
|
+ // id: 'node-3',
|
|
|
|
|
+ // type: 'canvas-node',
|
|
|
|
|
+ // width: 96,
|
|
|
|
|
+ // height: 96,
|
|
|
|
|
+ // position: { x: 600, y: 300 },
|
|
|
|
|
+ // data: {
|
|
|
|
|
+ // version: ['1.0.0'],
|
|
|
|
|
+ // displayName: '条件判断',
|
|
|
|
|
+ // name: 'if',
|
|
|
|
|
+ // description: '通过条件判断拆分多个流程分支',
|
|
|
|
|
+ // icon: 'roentgen:guidepost',
|
|
|
|
|
+ // iconColor: '#108e49',
|
|
|
|
|
+ // inputs: [
|
|
|
|
|
+ // {
|
|
|
|
|
+ // index: 0,
|
|
|
|
|
+ // type: 'main'
|
|
|
|
|
+ // }
|
|
|
|
|
+ // ],
|
|
|
|
|
+ // outputs: [
|
|
|
|
|
+ // {
|
|
|
|
|
+ // index: 0,
|
|
|
|
|
+ // type: 'main',
|
|
|
|
|
+ // label: 'true'
|
|
|
|
|
+ // },
|
|
|
|
|
+ // {
|
|
|
|
|
+ // index: 1,
|
|
|
|
|
+ // type: 'main',
|
|
|
|
|
+ // label: 'false'
|
|
|
|
|
+ // }
|
|
|
|
|
+ // ],
|
|
|
|
|
+ // outputNames: ['true', 'false']
|
|
|
|
|
+ // }
|
|
|
|
|
+ // },
|
|
|
|
|
+ // {
|
|
|
|
|
+ // id: 'node-note',
|
|
|
|
|
+ // type: 'canvas-node',
|
|
|
|
|
+ // position: { x: 600, y: 300 },
|
|
|
|
|
+ // data: {
|
|
|
|
|
+ // version: ['1.0.0'],
|
|
|
|
|
+ // displayName: '条件判断',
|
|
|
|
|
+ // name: 'if',
|
|
|
|
|
+ // description: '通过条件判断拆分多个流程分支',
|
|
|
|
|
+ // icon: 'roentgen:guidepost',
|
|
|
|
|
+ // iconColor: '#108e49',
|
|
|
|
|
+ // inputs: [],
|
|
|
|
|
+ // outputs: [],
|
|
|
|
|
+ // // 便签数据
|
|
|
|
|
+ // renderType: 'stickyNote',
|
|
|
|
|
+ // content:
|
|
|
|
|
+ // '# 标题\n\n这是一些便签内容,可以使用 **Markdown** 语法进行格式化。\n\n- 列表项 1\n- 列表项 2\n\n[链接](https://example.com)',
|
|
|
|
|
+ // width: 400,
|
|
|
|
|
+ // height: 200,
|
|
|
|
|
+ // color: '#d6f5e3'
|
|
|
|
|
+ // }
|
|
|
|
|
+ // }
|
|
|
],
|
|
],
|
|
|
edges: [
|
|
edges: [
|
|
|
- {
|
|
|
|
|
- id: 'edge-1-2',
|
|
|
|
|
- source: 'node-1',
|
|
|
|
|
- target: 'node-2',
|
|
|
|
|
- type: 'canvas-edge',
|
|
|
|
|
- data: {
|
|
|
|
|
- label: 'Edge 1-2'
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // {
|
|
|
|
|
+ // id: 'edge-1-2',
|
|
|
|
|
+ // source: 'node-1',
|
|
|
|
|
+ // target: 'node-2',
|
|
|
|
|
+ // type: 'canvas-edge',
|
|
|
|
|
+ // data: {
|
|
|
|
|
+ // label: 'Edge 1-2'
|
|
|
|
|
+ // }
|
|
|
|
|
+ // }
|
|
|
// {
|
|
// {
|
|
|
// id: 'edge-1-2',
|
|
// id: 'edge-1-2',
|
|
|
// source: 'start-node',
|
|
// source: 'start-node',
|
|
@@ -185,7 +231,6 @@ const workflow = ref<IWorkflow>({
|
|
|
// label: 'Edge 1-2'
|
|
// label: 'Edge 1-2'
|
|
|
// }
|
|
// }
|
|
|
// },
|
|
// },
|
|
|
-
|
|
|
|
|
// {
|
|
// {
|
|
|
// id: 'edge-1-4',
|
|
// id: 'edge-1-4',
|
|
|
// source: 'code-node',
|
|
// source: 'code-node',
|
|
@@ -196,77 +241,18 @@ const workflow = ref<IWorkflow>({
|
|
|
// }
|
|
// }
|
|
|
// }
|
|
// }
|
|
|
]
|
|
]
|
|
|
- // id: '1',
|
|
|
|
|
- // nodes: [
|
|
|
|
|
- // {
|
|
|
|
|
- // id: 'node-1',
|
|
|
|
|
- // type: 'canvas-node',
|
|
|
|
|
- // position: { x: 100, y: 100 },
|
|
|
|
|
- // width: 96,
|
|
|
|
|
- // height: 96,
|
|
|
|
|
- // data: {
|
|
|
|
|
- // version: ['1.0.0'],
|
|
|
|
|
- // displayName: '用户输入',
|
|
|
|
|
- // name: 'chart',
|
|
|
|
|
- // description: '通过用户输入开启流程处理',
|
|
|
|
|
- // icon: 'fluent:comment-multiple-28-regular',
|
|
|
|
|
- // iconColor: '#296dff',
|
|
|
|
|
- // inputs: [],
|
|
|
|
|
- // outputs: [
|
|
|
|
|
- // {
|
|
|
|
|
- // index: 0,
|
|
|
|
|
- // type: 'main'
|
|
|
|
|
- // }
|
|
|
|
|
- // ]
|
|
|
|
|
- // }
|
|
|
|
|
- // },
|
|
|
|
|
- // {
|
|
|
|
|
- // id: 'node-2',
|
|
|
|
|
- // type: 'canvas-node',
|
|
|
|
|
- // width: 96,
|
|
|
|
|
- // height: 96,
|
|
|
|
|
- // position: { x: 400, y: 100 },
|
|
|
|
|
- // data: {
|
|
|
|
|
- // version: ['1.0.0'],
|
|
|
|
|
- // displayName: '条件判断',
|
|
|
|
|
- // name: 'if',
|
|
|
|
|
- // description: '通过条件判断拆分多个流程分支',
|
|
|
|
|
- // icon: 'roentgen:guidepost',
|
|
|
|
|
- // iconColor: '#108e49',
|
|
|
|
|
- // inputs: [
|
|
|
|
|
- // {
|
|
|
|
|
- // index: 0,
|
|
|
|
|
- // type: 'main'
|
|
|
|
|
- // }
|
|
|
|
|
- // ],
|
|
|
|
|
- // outputs: [
|
|
|
|
|
- // {
|
|
|
|
|
- // index: 0,
|
|
|
|
|
- // type: 'main',
|
|
|
|
|
- // label: 'true'
|
|
|
|
|
- // },
|
|
|
|
|
- // {
|
|
|
|
|
- // index: 1,
|
|
|
|
|
- // type: 'main',
|
|
|
|
|
- // label: 'false'
|
|
|
|
|
- // }
|
|
|
|
|
- // ],
|
|
|
|
|
- // outputNames: ['true', 'false']
|
|
|
|
|
- // }
|
|
|
|
|
- // }
|
|
|
|
|
- // ],
|
|
|
|
|
- // edges: [
|
|
|
|
|
- // {
|
|
|
|
|
- // id: 'edge-1-2',
|
|
|
|
|
- // source: 'node-1',
|
|
|
|
|
- // target: 'node-2',
|
|
|
|
|
- // type: 'canvas-edge',
|
|
|
|
|
- // data: {
|
|
|
|
|
- // label: 'Edge 1-2'
|
|
|
|
|
- // }
|
|
|
|
|
- // }
|
|
|
|
|
- // ]
|
|
|
|
|
})
|
|
})
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * Editor
|
|
|
|
|
+ */
|
|
|
|
|
+const handleFooterToggle = (open: boolean) => {
|
|
|
|
|
+ footerHeight.value = open ? 200 : 32
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * Workflow
|
|
|
|
|
+ */
|
|
|
const nodeID = ref('')
|
|
const nodeID = ref('')
|
|
|
const setterVisible = ref(false)
|
|
const setterVisible = ref(false)
|
|
|
const runVisible = ref(false)
|
|
const runVisible = ref(false)
|
|
@@ -274,10 +260,33 @@ const handleRunWorkflow = () => {
|
|
|
runVisible.value = true
|
|
runVisible.value = true
|
|
|
console.log('run workflow')
|
|
console.log('run workflow')
|
|
|
}
|
|
}
|
|
|
-const handleNodeCreate = (value: SourceType) => {
|
|
|
|
|
|
|
+const handleNodeCreate = (value: SourceType | string) => {
|
|
|
console.log(value)
|
|
console.log(value)
|
|
|
|
|
|
|
|
|
|
+ if (typeof value === 'string') {
|
|
|
|
|
+ if (value === 'stickyNote') {
|
|
|
|
|
+ workflow.value.nodes.push({
|
|
|
|
|
+ id: 'node-note',
|
|
|
|
|
+ type: 'canvas-node',
|
|
|
|
|
+ position: { x: 600, y: 300 },
|
|
|
|
|
+ data: {
|
|
|
|
|
+ version: ['1.0.0'],
|
|
|
|
|
+ inputs: [],
|
|
|
|
|
+ outputs: [],
|
|
|
|
|
+ renderType: 'stickyNote',
|
|
|
|
|
+ content: '注释内容,可以使用 **Markdown** 语法进行格式化。',
|
|
|
|
|
+ width: 400,
|
|
|
|
|
+ height: 200,
|
|
|
|
|
+ color: '#fff5d6'
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
const nodeMap: Record<string, any> = {
|
|
const nodeMap: Record<string, any> = {
|
|
|
|
|
+ start: startNode,
|
|
|
|
|
+ end: endNode,
|
|
|
http: httpNode,
|
|
http: httpNode,
|
|
|
condition: conditionNode,
|
|
condition: conditionNode,
|
|
|
code: codeNode,
|
|
code: codeNode,
|