Pārlūkot izejas kodu

feat:新增添加节点功能及节点规范

lj1559651600@163.com 1 nedēļu atpakaļ
vecāks
revīzija
903bfa1fb7

+ 1 - 1
apps/web/package.json

@@ -9,6 +9,7 @@
     "preview": "vite preview"
   },
   "dependencies": {
+    "@repo/nodes": "workspace:^",
     "element-plus": "^2.13.1",
     "normalize.css": "^8.0.1",
     "vue": "^3.5.24",
@@ -16,7 +17,6 @@
   },
   "devDependencies": {
     "@repo/workflow": "workspace:*",
-    "@types/node": "^24.10.1",
     "@vitejs/plugin-vue": "^6.0.1",
     "@vue/tsconfig": "^0.8.1",
     "less": "^4.5.1",

+ 48 - 0
apps/web/src/components/RunWork.vue

@@ -0,0 +1,48 @@
+<!--
+ * @Author: liuJie
+ * @Date: 2026-01-24 21:25:04
+ * @LastEditors: liuJie
+ * @LastEditTime: 2026-01-24 22:01:08
+ * @Describe: 运行工作流
+-->
+<script lang="ts" setup>
+import { ElDrawer, ElButton } from 'element-plus';
+import { Icon } from '@iconify/vue';
+const props = withDefaults(
+    defineProps<{
+        visible: boolean,
+    }>(),
+    {
+        visible: false,
+    }
+);
+const emit = defineEmits<{
+    'update:visible': [value: boolean]
+}>()
+</script>
+<template>
+    <div class='content'>
+        <ElDrawer :model-value="visible" :show-close="false" size="25%" @close="emit('update:visible', false)">
+
+            <template #header>
+                <h4>运行工作流</h4>
+                <Icon icon="lucide:x" height="24" width="24"></Icon>
+            </template>
+
+            <!-- Drawer content -->
+            This is drawer content.
+
+            <template #footer>
+                <ElButton type="success" size="large" class="w-full" @click="emit('update:visible', false)">
+                    运行
+                </ElButton>
+            </template>
+
+        </ElDrawer>
+    </div>
+</template>
+<style lang="less" scoped>
+.pt-0 {
+    padding-top: 0px;
+}
+</style>

+ 46 - 0
apps/web/src/components/setter/CodeSetter.vue

@@ -0,0 +1,46 @@
+<!--
+ * @Author: liuJie
+ * @Date: 2026-01-25 22:08:04
+ * @LastEditors: liuJie
+ * @LastEditTime: 2026-01-25 23:04:14
+ * @Describe: code设置器
+-->
+<script lang="ts" setup>
+import { ElDrawer, ElButton } from 'element-plus';
+import { Icon } from '@iconify/vue';
+const props = withDefaults(
+    defineProps<{
+        data: any,
+        visible: boolean,
+    }>(),
+    {
+        visible: false,
+        data: {}
+    }
+);
+const emit = defineEmits<{
+    'update:visible': [value: boolean]
+}>()
+</script>
+<template>
+    <div class='content'>
+        <ElDrawer :model-value="visible" :show-close="false" size="25%" @close="emit('update:visible', false)">
+
+            <template #header>
+                <h4>代码执行</h4>
+                <Icon icon="lucide:x" height="24" width="24"></Icon>
+            </template>
+
+            <!-- Drawer content -->
+            This is drawer content.
+
+            <!-- <template #footer>
+                <ElButton type="success" size="large" class="w-full" @click="emit('update:visible', false)">
+                    运行
+                </ElButton>
+            </template> -->
+
+        </ElDrawer>
+    </div>
+</template>
+<style lang="scss" scoped></style>

+ 46 - 0
apps/web/src/components/setter/ConditionSetter.vue

@@ -0,0 +1,46 @@
+<!--
+ * @Author: liuJie
+ * @Date: 2026-01-25 22:08:04
+ * @LastEditors: liuJie
+ * @LastEditTime: 2026-01-25 23:04:45
+ * @Describe: 条件设置器
+-->
+<script lang="ts" setup>
+import { ElDrawer, ElButton } from 'element-plus';
+import { Icon } from '@iconify/vue';
+const props = withDefaults(
+    defineProps<{
+        data: any,
+        visible: boolean,
+    }>(),
+    {
+        visible: false,
+        data: {}
+    }
+);
+const emit = defineEmits<{
+    'update:visible': [value: boolean]
+}>()
+</script>
+<template>
+    <div class='content'>
+        <ElDrawer :model-value="visible" :show-close="false" size="25%" @close="emit('update:visible', false)">
+
+            <template #header>
+                <h4>条件</h4>
+                <Icon icon="lucide:x" height="24" width="24"></Icon>
+            </template>
+
+            <!-- Drawer content -->
+            This is drawer content.
+
+            <!-- <template #footer>
+                <ElButton type="success" size="large" class="w-full" @click="emit('update:visible', false)">
+                    运行
+                </ElButton>
+            </template> -->
+
+        </ElDrawer>
+    </div>
+</template>
+<style lang="scss" scoped></style>

+ 46 - 0
apps/web/src/components/setter/DatabaseSetter.vue

@@ -0,0 +1,46 @@
+<!--
+ * @Author: liuJie
+ * @Date: 2026-01-25 22:08:04
+ * @LastEditors: liuJie
+ * @LastEditTime: 2026-01-25 23:05:13
+ * @Describe: 数据设置器
+-->
+<script lang="ts" setup>
+import { ElDrawer, ElButton } from 'element-plus';
+import { Icon } from '@iconify/vue';
+const props = withDefaults(
+    defineProps<{
+        data: any,
+        visible: boolean,
+    }>(),
+    {
+        visible: false,
+        data: {}
+    }
+);
+const emit = defineEmits<{
+    'update:visible': [value: boolean]
+}>()
+</script>
+<template>
+    <div class='content'>
+        <ElDrawer :model-value="visible" :show-close="false" size="25%" @close="emit('update:visible', false)">
+
+            <template #header>
+                <h4>数据查询</h4>
+                <Icon icon="lucide:x" height="24" width="24"></Icon>
+            </template>
+
+            <!-- Drawer content -->
+            This is drawer content.
+
+            <!-- <template #footer>
+                <ElButton type="success" size="large" class="w-full" @click="emit('update:visible', false)">
+                    运行
+                </ElButton>
+            </template> -->
+
+        </ElDrawer>
+    </div>
+</template>
+<style lang="scss" scoped></style>

+ 46 - 0
apps/web/src/components/setter/HttpSetter.vue

@@ -0,0 +1,46 @@
+<!--
+ * @Author: liuJie
+ * @Date: 2026-01-25 22:08:04
+ * @LastEditors: liuJie
+ * @LastEditTime: 2026-01-25 22:24:34
+ * @Describe: http设置器
+-->
+<script lang="ts" setup>
+import { ElDrawer, ElButton } from 'element-plus';
+import { Icon } from '@iconify/vue';
+const props = withDefaults(
+    defineProps<{
+        data: any,
+        visible: boolean,
+    }>(),
+    {
+        visible: false,
+        data: {}
+    }
+);
+const emit = defineEmits<{
+    'update:visible': [value: boolean]
+}>()
+</script>
+<template>
+    <div class='content'>
+        <ElDrawer :model-value="visible" :show-close="false" size="25%" @close="emit('update:visible', false)">
+
+            <template #header>
+                <h4>HTTP请求</h4>
+                <Icon icon="lucide:x" height="24" width="24"></Icon>
+            </template>
+
+            <!-- Drawer content -->
+            This is drawer content.
+
+            <!-- <template #footer>
+                <ElButton type="success" size="large" class="w-full" @click="emit('update:visible', false)">
+                    运行
+                </ElButton>
+            </template> -->
+
+        </ElDrawer>
+    </div>
+</template>
+<style lang="scss" scoped></style>

+ 27 - 0
apps/web/src/components/setter/index.vue

@@ -0,0 +1,27 @@
+<!--
+ * @Author: liuJie
+ * @Date: 2026-01-25 22:13:06
+ * @LastEditors: liuJie
+ * @LastEditTime: 2026-01-25 22:26:30
+ * @Describe: file describe
+-->
+<script lang="ts" setup>
+import HttpSetter from './HttpSetter.vue';
+interface Props {
+    data: any, // 暂时定义
+    visible: boolean
+}
+const props = withDefaults(defineProps<Props>(), {
+    id: '',
+    visible: false
+})
+const emit = defineEmits<{
+    'update:visible': [value: boolean]
+}>()
+</script>
+<template>
+    <div class='setter'>
+        <HttpSetter :data="data" v-model:visible="props.visible" />
+    </div>
+</template>
+<style lang="less" scoped></style>

+ 95 - 36
apps/web/src/views/Editor.vue

@@ -1,51 +1,110 @@
 <template>
-	<div class="w-full h-full">
-		<Workflow :workflow="workflow" @click:node="handleNodeClick" @drop="handleDrop" />
-	</div>
+    <div class="w-full h-full">
+        <Workflow :workflow="workflow" @click:node="handleNodeClick" @create:node="handleNodeCreate" @drop="handleDrop"
+            @run="handleRunWorkflow" />
+        <RunWork v-model:visible="runVisible" />
+        <Setter :data="nodeID" v-model:visible="setterVisible" />
+    </div>
 </template>
 
 <script setup lang="ts">
-import { ref } from 'vue'
+import { startNode, endNode, httpNode, conditionNode, databaseNode, codeNode, } from '@repo/nodes'
 import { Workflow, type IWorkflow, type XYPosition } from '@repo/workflow'
+import Setter from "@/components/setter/index.vue"
+import RunWork from '@/components/RunWork.vue'
+import type { SourceType } from '@repo/nodes'
+import { ref } from 'vue'
 
 const workflow = ref<IWorkflow>({
-	id: '1',
-	nodes: [
-		{
-			id: 'node-1',
-			type: 'canvas-node',
-			position: { x: 100, y: 100 },
-			width: 100,
-			height: 100,
-			data: { label: 'Node 1', inputs: [], outputs: [] }
-		},
-		{
-			id: 'node-2',
-			type: 'canvas-node',
-			width: 100,
-			height: 100,
-			position: { x: 400, y: 100 },
-			data: { label: 'Node 1', inputs: [], outputs: [] }
-		}
-	],
-	edges: [
-		{
-			id: 'edge-1-2',
-			source: 'node-1',
-			target: 'node-2',
-			type: 'canvas-edge',
-			data: {
-				label: 'Edge 1-2'
-			}
-		}
-	]
+    id: '1',
+    nodes: [
+        startNode, // 初始化节点,
+        endNode, // 初始化节点,
+        // httpNode,
+        // conditionNode,
+        // databaseNode,
+        // codeNode
+    ],
+    edges: [
+        // {
+        //     id: 'edge-1-2',
+        //     source: 'start-node',
+        //     target: 'http-node',
+        //     type: 'canvas-edge',
+        //     data: {
+        //         label: 'Edge 1-2'
+        //     }
+        // },
+        // {
+        //     id: 'edge-1-6',
+        //     source: 'http-node',
+        //     target: 'condition-node',
+        //     type: 'canvas-edge',
+        //     data: {
+        //         label: 'Edge 1-2'
+        //     }
+        // },
+        // {
+        //     id: 'edge-1-5',
+        //     source: 'condition-node',
+        //     target: 'data-node',
+        //     type: 'canvas-edge',
+        //     data: {
+        //         label: 'Edge 1-2'
+        //     }
+        // },
+        // {
+        //     id: 'edge-1-3',
+        //     source: 'database-node',
+        //     target: 'code-node',
+        //     type: 'canvas-edge',
+        //     data: {
+        //         label: 'Edge 1-2'
+        //     }
+        // },
+
+        // {
+        //     id: 'edge-1-4',
+        //     source: 'code-node',
+        //     target: 'end-node',
+        //     type: 'canvas-edge',
+        //     data: {
+        //         label: 'Edge 1-2'
+        //     }
+        // }
+    ]
 })
+const nodeID = ref('')
+const setterVisible = ref(false)
+const runVisible = ref(false)
+const handleRunWorkflow = () => {
+    runVisible.value = true
+    console.log('run workflow')
+}
+const handleNodeCreate = (value: SourceType) => {
+    console.log(value)
+
+    const nodeMap: Record<string, any> = {
+        'http': httpNode,
+        'condition': conditionNode,
+        'code': codeNode,
+        'database': databaseNode
+    }
+    const nodeToAdd = nodeMap[value.type]
 
+    // 如果存在对应节点则添加
+    if (nodeToAdd) {
+        workflow.value.nodes.push(nodeToAdd)
+    }
+    console.log(workflow.value.nodes, 'workflow.nodes')
+}
 const handleNodeClick = (id: string, position: XYPosition) => {
-	console.log('click node', id, position)
+    console.log('click node', id, position)
+    nodeID.value = id
+    setterVisible.value = true
 }
 
 const handleDrop = (position: XYPosition, event: DragEvent) => {
-	console.log('drag and drop at', position, event)
+    console.log('drag and drop at', position, event)
 }
 </script>