| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- <template>
- <div class="w-full h-full flex flex-col">
- <div
- class="h-60px shrink-0 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"
- @update:nodes:position="handleUpdateNodesPosition"
- @update:node:attrs="handleUpdateNodeProps"
- class="bg-#f5f5f5"
- />
- <RunWorkflow v-model:visible="runVisible" />
- <Setter
- :id="nodeID"
- :workflow="workflow"
- @update:node:data="hangleUpdateNodeData"
- 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>
- </template>
- <script setup lang="ts">
- import { ref, inject, type CSSProperties, onBeforeUnmount } from 'vue'
- import { startNode, endNode, httpNode, conditionNode, databaseNode, codeNode } from '@repo/nodes'
- import { Workflow, type IWorkflow, type XYPosition, type Connection } from '@repo/workflow'
- import { v4 as uuid } from 'uuid'
- import Setter from '@/components/setter/index.vue'
- import RunWorkflow from '@/components/RunWorkflow/index.vue'
- import EditorFooter from '@/features/editorFooter/index.vue'
- import { IconButton } from '@repo/ui'
- import type { SourceType } from '@repo/nodes'
- const layout = inject<{ setMainStyle: (style: CSSProperties) => void }>('layout')
- layout?.setMainStyle({
- padding: '0px'
- })
- const footerHeight = ref(32)
- const workflow = ref<IWorkflow>({
- id: uuid(),
- nodes: [startNode, endNode],
- edges: []
- })
- /**
- * Editor
- */
- const handleFooterToggle = (open: boolean) => {
- footerHeight.value = open ? 200 : 32
- }
- /**
- * Workflow
- */
- const nodeID = ref('')
- const setterVisible = ref(false)
- const runVisible = ref(false)
- const handleRunWorkflow = () => {
- runVisible.value = true
- console.log('run workflow')
- }
- const handleNodeCreate = (value: SourceType | string) => {
- const id = uuid()
- if (typeof value === 'string') {
- if (value === 'stickyNote') {
- workflow.value.nodes.push({
- id,
- type: 'canvas-node',
- zIndex: -1,
- position: { x: 600, y: 300 },
- data: {
- id,
- version: ['1.0.0'],
- inputs: [],
- outputs: [],
- renderType: 'stickyNote',
- content: '注释内容,可以使用 **Markdown** 语法进行格式化, 双击进入编辑。',
- width: 400,
- height: 200,
- color: '#fff5d6'
- }
- })
- }
- return
- }
- const nodeMap: Record<string, any> = {
- start: startNode,
- end: endNode,
- http: httpNode,
- condition: conditionNode,
- code: codeNode,
- database: databaseNode
- }
- const nodeToAdd = nodeMap[value.type]
- // 如果存在对应节点则添加
- if (nodeToAdd) {
- workflow.value.nodes.push({
- ...nodeToAdd,
- data: {
- ...nodeToAdd.data,
- id
- },
- zIndex: 1,
- id: uuid()
- })
- }
- console.log(workflow.value.nodes, 'workflow.nodes')
- }
- const handleNodeClick = (id: string, position: XYPosition) => {
- nodeID.value = id
- setterVisible.value = true
- }
- const handleDrop = (position: XYPosition, event: DragEvent) => {
- console.log('drag and drop at', position, event)
- }
- /**
- * 创建连线
- */
- const onCreateConnection = (connection: Connection) => {
- const { source, target } = connection
- if (!workflow.value.edges.some((edge) => edge.source === source && edge.target === target)) {
- workflow.value.edges.push({
- id: `edge-${source}-${target}`,
- source,
- target,
- type: 'canvas-edge',
- data: {}
- })
- }
- }
- /**
- * 移动位置
- */
- const handleUpdateNodesPosition = (events: { id: string; position: XYPosition }[]) => {
- events?.forEach(({ id, position }) => {
- const node = workflow.value.nodes.find((node) => node.id === id)
- if (node) {
- node.position = position
- }
- })
- }
- /**
- * 修改节点数据
- */
- const hangleUpdateNodeData = (id: string, data: any) => {
- const node = workflow.value.nodes.find((node) => node.id === id)
- if (node) {
- node.data = {
- ...node.data,
- ...data
- }
- }
- console.log('hangleUpdateNodeData', id, data)
- }
- /**
- * 修改节点属性
- */
- const handleUpdateNodeProps = (id: string, attrs: Record<string, unknown>) => {
- const node = workflow.value.nodes.find((node) => node.id === id)
- if (node) {
- if (node.data?.renderType === 'stickyNote') {
- Object.assign(node.data, attrs)
- } else {
- Object.assign(node, attrs)
- }
- }
- }
- onBeforeUnmount(() => {
- layout?.setMainStyle({})
- })
- </script>
|