From d2da078b40578cf72901442c7a2b878dfc34cae5 Mon Sep 17 00:00:00 2001 From: wujingjing <gersonwu@qq.com> Date: 星期五, 13 十二月 2024 12:10:00 +0800 Subject: [PATCH] feat(flow): 新增执行功能节点并优化流程画布 --- customer_list/common/static/fonts/ywiconfont/iconfont.ttf | 0 src/components/vue-flow/ui/nodes/FuncNode.vue | 112 ++++++++++++ src/components/vue-flow/ui/nodes/EndNode.vue | 14 + tailwind.config.js | 3 package-lock.json | 14 + src/components/vue-flow/ui/nodes/OutputNode.vue | 14 + src/api/workflow/index.ts | 18 + src/views/project/yw/systemManage/flowApp/components/Sidebar.vue | 48 ---- src/components/vue-flow/vueFlowEnum.ts | 19 + customer_list/common/static/fonts/ywiconfont/iconfont.woff2 | 0 src/main.ts | 5 customer_list/common/static/fonts/ywiconfont/iconfont.woff | 0 src/components/vue-flow/ui/nodes/AgentNode.vue | 14 + src/components/icon/index.vue | 25 ++ src/components/vue-flow/VueFlowHelper.ts | 24 ++ package.json | 6 src/components/vue-flow/ui/nodes/ConditionNode.vue | 23 + src/utils/setIconfont.ts | 2 src/components/vue-flow/ui/VueFlowConfig.ts | 78 ++++++++ src/components/vue-flow/MainCanvas.vue | 13 + src/views/project/yw/systemManage/flowApp/FlowApp.vue | 14 + customer_list/common/static/fonts/ywiconfont/iconfont.css | 14 + src/components/vue-flow/ui/nodes/LLMNode.vue | 12 + src/components/vue-flow/ui/nodes/StartNode.vue | 15 + 24 files changed, 390 insertions(+), 97 deletions(-) diff --git a/customer_list/common/static/fonts/ywiconfont/iconfont.css b/customer_list/common/static/fonts/ywiconfont/iconfont.css index d046c76..7db4c1a 100644 --- a/customer_list/common/static/fonts/ywiconfont/iconfont.css +++ b/customer_list/common/static/fonts/ywiconfont/iconfont.css @@ -1,8 +1,8 @@ @font-face { font-family: "ywifont"; /* Project id 4655417 */ - src: url('iconfont.woff2?t=1733970308986') format('woff2'), - url('iconfont.woff?t=1733970308986') format('woff'), - url('iconfont.ttf?t=1733970308986') format('truetype'); + src: url('iconfont.woff2?t=1734055372679') format('woff2'), + url('iconfont.woff?t=1734055372679') format('woff'), + url('iconfont.ttf?t=1734055372679') format('truetype'); } .ywifont { @@ -13,6 +13,14 @@ -moz-osx-font-smoothing: grayscale; } +.ywicon-jianpan:before { + content: "\eac2"; +} + +.ywicon-llm:before { + content: "\e611"; +} + .ywicon-jiegousheji:before { content: "\e63b"; } diff --git a/customer_list/common/static/fonts/ywiconfont/iconfont.ttf b/customer_list/common/static/fonts/ywiconfont/iconfont.ttf index 1245eb9..b188d10 100644 --- a/customer_list/common/static/fonts/ywiconfont/iconfont.ttf +++ b/customer_list/common/static/fonts/ywiconfont/iconfont.ttf Binary files differ diff --git a/customer_list/common/static/fonts/ywiconfont/iconfont.woff b/customer_list/common/static/fonts/ywiconfont/iconfont.woff index f414a2b..768508c 100644 --- a/customer_list/common/static/fonts/ywiconfont/iconfont.woff +++ b/customer_list/common/static/fonts/ywiconfont/iconfont.woff Binary files differ diff --git a/customer_list/common/static/fonts/ywiconfont/iconfont.woff2 b/customer_list/common/static/fonts/ywiconfont/iconfont.woff2 index 5760f8a..d9b4781 100644 --- a/customer_list/common/static/fonts/ywiconfont/iconfont.woff2 +++ b/customer_list/common/static/fonts/ywiconfont/iconfont.woff2 Binary files differ diff --git a/package-lock.json b/package-lock.json index ddcf26f..04088ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "@vue-flow/background": "^1.3.2", "@vue-flow/controls": "^1.1.2", "@vue-flow/core": "^1.41.6", + "@vue-flow/minimap": "^1.5.0", "@vueuse/core": "^11.0.3", "@wangeditor/editor": "^5.1.23", "@wangeditor/editor-for-vue": "^5.1.12", @@ -2376,6 +2377,19 @@ } } }, + "node_modules/@vue-flow/minimap": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/@vue-flow/minimap/-/minimap-1.5.0.tgz", + "integrity": "sha512-JhxXDF+8uTc7sgkZHDIvFpHqSl4wsK9xp8Kz5OHwNcXlgGcwqj4yad6jcc1B6bGxm+huESpNmoPotQbpMn6rVw==", + "dependencies": { + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0" + }, + "peerDependencies": { + "@vue-flow/core": "^1.23.0", + "vue": "^3.3.0" + } + }, "node_modules/@vue/compiler-core": { "version": "3.4.38", "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.4.38.tgz", diff --git a/package.json b/package.json index 1ae1441..0716b16 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "@vue-flow/background": "^1.3.2", "@vue-flow/controls": "^1.1.2", "@vue-flow/core": "^1.41.6", + "@vue-flow/minimap": "^1.5.0", "@vueuse/core": "^11.0.3", "@wangeditor/editor": "^5.1.23", "@wangeditor/editor-for-vue": "^5.1.12", @@ -88,6 +89,7 @@ "@vitejs/plugin-vue": "^5.0.4", "@vue/compiler-sfc": "^3.4.15", "autoprefixer": "^10.4.19", + "code-inspector-plugin": "^0.17.7", "eslint": "^8.35.0", "eslint-plugin-vue": "^9.9.0", "ncp": "^2.0.0", @@ -101,9 +103,7 @@ "vite-plugin-compression": "^0.5.1", "vite-plugin-vue-setup-extend-plus": "^0.1.0", "vue-eslint-parser": "^9.1.0", - "yw-deploy-cli": "latest", - "code-inspector-plugin": "^0.17.7" - + "yw-deploy-cli": "latest" }, "browserslist": [ "> 1%", diff --git a/src/api/workflow/index.ts b/src/api/workflow/index.ts index 336c696..bcb75de 100644 --- a/src/api/workflow/index.ts +++ b/src/api/workflow/index.ts @@ -68,13 +68,23 @@ ...extraData, }); +/** + * @description 鑾峰彇 agent_names 鍒楄〃 + **/ +export const get_agent_names = (extraData: ExtraConfig = {}) => + request({ + url: `/admin/workflow/get_agent_names`, + method: 'post', + ...extraData, + }); + /** - * @description 娴嬭瘯宸ヤ綔娴乤gent + * @description 鑾峰彇 func_names 鍒楄〃 **/ -export const get_agent_names = ( extraData: ExtraConfig = {}) => +export const get_flow_func_names = (extraData: ExtraConfig = {}) => request({ - url: `/admin/workflow/get_agent_names`, + url: `/admin/workflow/get_flow_func_names`, method: 'post', ...extraData, -}); +}); \ No newline at end of file diff --git a/src/components/icon/index.vue b/src/components/icon/index.vue new file mode 100644 index 0000000..cae8fc7 --- /dev/null +++ b/src/components/icon/index.vue @@ -0,0 +1,25 @@ +<template> + <span + :class="['ywifont', `ywicon-${name}`]" + :style="{ + fontSize: Number(fontSize) + 'px', + color: color, + }" + ></span> +</template> + +<script setup lang="ts" name="YWIcon"> +defineProps({ + name: { + type: String, + required: true, + }, + fontSize: { + type: String, + }, + color: { + type: String, + }, +}); +</script> +<style scoped lang="scss"></style> diff --git a/src/components/vue-flow/MainCanvas.vue b/src/components/vue-flow/MainCanvas.vue index c961f12..d24f53e 100644 --- a/src/components/vue-flow/MainCanvas.vue +++ b/src/components/vue-flow/MainCanvas.vue @@ -1,6 +1,6 @@ <template> <div class="relative h-full w-full" id="main-canvas" @drop="handleOnDrop" @dragover="handleOnDragOver"> - <VueFlow v-model="elements" :node-types="nodeTypes" :connection-mode="ConnectionMode.Loose"> + <VueFlow v-model="elements" :node-types="nodeTypes" :connection-mode="ConnectionMode.Strict"> <template #edge-custom="customEdgeProps"> <CustomEdge v-bind="customEdgeProps" /> </template> @@ -8,8 +8,12 @@ <template #node-agent="agentNodeProps"> <AgentNode v-bind="agentNodeProps" :agentNames="agentNames" /> </template> + <template #node-func="funcNodeProps"> + <FuncNode v-bind="funcNodeProps" :funcNames="funcNames" /> + </template> <Controls /> <Background /> + <MiniMap pannable zoomable /> </VueFlow> </div> </template> @@ -17,6 +21,8 @@ <script setup lang="ts"> import { Background } from '@vue-flow/background'; import { Controls } from '@vue-flow/controls'; +import { MiniMap } from '@vue-flow/minimap'; + import { Dimensions, Elements, useVueFlow, VueFlow, ConnectionMode, MarkerType } from '@vue-flow/core'; import { markRaw, nextTick, ref, watch } from 'vue'; import { Test_data } from './testData'; @@ -28,11 +34,12 @@ import LLMNode from './ui/nodes/LLMNode.vue'; import OutputNode from './ui/nodes/OutputNode.vue'; import AgentNode from './ui/nodes/AgentNode.vue'; +import FuncNode from './ui/nodes/FuncNode.vue'; import CustomEdge from './ui/edges/CustomEdge.vue'; import { onMounted } from 'vue'; -const props = defineProps(['flowJson', 'agentNames']); +const props = defineProps(['flowJson', 'agentNames','funcNames']); const nodeTypes = { start: markRaw(StartNode), @@ -147,6 +154,8 @@ @import '@vue-flow/core/dist/style.css'; @import '@vue-flow/core/dist/theme-default.css'; @import '@vue-flow/controls/dist/style.css'; +@import '@vue-flow/minimap/dist/style.css'; + #main-canvas { --vf-handle: #2563eb; diff --git a/src/components/vue-flow/VueFlowHelper.ts b/src/components/vue-flow/VueFlowHelper.ts index 6eaef88..d63c9f2 100644 --- a/src/components/vue-flow/VueFlowHelper.ts +++ b/src/components/vue-flow/VueFlowHelper.ts @@ -40,7 +40,7 @@ key: 'condition', label: '', type: 'condition', - value: [ConditionHelper.getDefaultConditionGroup(),ConditionHelper.getDefaultConditionGroup(true)], + value: [ConditionHelper.getDefaultConditionGroup(), ConditionHelper.getDefaultConditionGroup(true)], }, ], }, @@ -82,6 +82,24 @@ // value_label:'', required: true, placeholder: '浠g悊', + }, + ], + }, + ]; + break; + + case NodeType.Func: + data[VueFlowConstant.GROUP_PARAMS_KEY] = [ + { + [VueFlowConstant.PARAMS_KEY]: [ + { + key: 'func_name', + label: '鍑芥暟鍚嶇О', + type: 'func_name_select', + value: '', + // value_label:'', + required: true, + placeholder: '鍑芥暟鍚嶇О', }, ], }, @@ -212,9 +230,7 @@ : { id: VueFlowHelper.genId(), operator: ConditionOperator.And, - conditions: [ - ConditionHelper.getConditionItem() - ], + conditions: [ConditionHelper.getConditionItem()], }; }; } diff --git a/src/components/vue-flow/ui/VueFlowConfig.ts b/src/components/vue-flow/ui/VueFlowConfig.ts new file mode 100644 index 0000000..1c5b126 --- /dev/null +++ b/src/components/vue-flow/ui/VueFlowConfig.ts @@ -0,0 +1,78 @@ +import { NodeType, nodeTypeMap } from '../vueFlowEnum'; + +export class VueFlowConfig { + static nodeStyleMap = new Map([ + [ + NodeType.Start, + { + type: NodeType.Start, + title: nodeTypeMap[NodeType.Start], + icon: 'xiangxiajiantou -rotate-90', + fontSize: '13', + color: 'white', + class: '!bg-primary ', + }, + ], + [ + NodeType.End, + { + type: NodeType.End, + title: nodeTypeMap[NodeType.End], + icon: 'jieshu', + fontSize: '13', + color: 'white', + class: '!bg-primary ', + }, + ], + [ + NodeType.Condition, + { + type: NodeType.Condition, + title: nodeTypeMap[NodeType.Condition], + icon: 'jiegousheji', + fontSize: '14', + class: 'bg-[#edc9e9] ', + }, + ], + [ + NodeType.LLM, + { + type: NodeType.LLM, + title: nodeTypeMap[NodeType.LLM], + icon: 'llm', + fontSize: '14', + class: 'bg-[#d9d7ff] ', + }, + ], + [ + NodeType.Output, + { + type: NodeType.Output, + title: nodeTypeMap[NodeType.Output], + icon: 'xiaoxi1', + fontSize: '14', + class: 'bg-[#9ce4f4] ', + }, + ], + [ + NodeType.Agent, + { + type: NodeType.Agent, + title: nodeTypeMap[NodeType.Agent], + icon: 'wode', + fontSize: '14', + class: 'bg-[#ffd89a] ', + }, + ], + [ + NodeType.Func, + { + type: NodeType.Func, + title: nodeTypeMap[NodeType.Func], + icon: 'kaishi', + fontSize: '14', + class: 'bg-[#bbdbff] ', + }, + ], + ]); +} diff --git a/src/components/vue-flow/ui/nodes/AgentNode.vue b/src/components/vue-flow/ui/nodes/AgentNode.vue index afc8fd2..e223c35 100644 --- a/src/components/vue-flow/ui/nodes/AgentNode.vue +++ b/src/components/vue-flow/ui/nodes/AgentNode.vue @@ -2,7 +2,7 @@ <div class="w-max-[520px] border-2 rounded-lg border-solid border-gray-100 bg-white p-3 shadow-md relative hover:border-blue-500 group" > - <Handle :id="targetHandleId" type="source" :position="Position.Left" /> + <Handle :id="targetHandleId" type="target" :position="Position.Left" /> <div class="group-hover:visible invisible flex absolute divide-y-[1.5px] divide-solid divide-gray-100 rounded-lg right-0 -top-0.5 translate-y-[-100%]" style="box-shadow: 0 0 15px #dbdee6" @@ -27,7 +27,13 @@ <div class="flex flex-col gap-y-2"> <div class="flex justify-between flex-0"> <div class="flex items-center gap-x-2"> - <img src="/@/components/vue-flow/ui/assets/images/icon_Start.png" class="h-4 w-4" alt="Start icon" /> + <YWIcon + :name="VueFlowConfig.nodeStyleMap.get(NodeType.Agent).icon" + :fontSize="VueFlowConfig.nodeStyleMap.get(NodeType.Agent).fontSize" + :color="VueFlowConfig.nodeStyleMap.get(NodeType.Agent).color" + class="rounded-lg p-1.5" + :class="VueFlowConfig.nodeStyleMap.get(NodeType.Agent).class" + /> <div class="flex flex-col gap-y-1"> <p v-if="!titleIsEdit" class="text-xl font-bold text-gray-500" @click="titleIsEdit = true">{{ data.title }}</p> <el-input v-elInputFocus="false" v-else v-model="data.title" @blur="() => (titleIsEdit = false)"></el-input> @@ -62,9 +68,9 @@ import { Handle, Position, useNode, useVueFlow } from '@vue-flow/core'; import { ref } from 'vue'; -import type { NodeProps } from '@vue-flow/core'; import { VueFlowHelper } from '../../VueFlowHelper'; -import { LLMNodeData, LLMNodeEvents } from './index'; +import { NodeType } from '../../vueFlowEnum'; +import { VueFlowConfig } from '../VueFlowConfig'; import { deepClone } from '/@/utils/other'; // defineProps<NodeProps<LLMNodeData, LLMNodeEvents>>(); diff --git a/src/components/vue-flow/ui/nodes/ConditionNode.vue b/src/components/vue-flow/ui/nodes/ConditionNode.vue index aeecf58..eeb4c1d 100644 --- a/src/components/vue-flow/ui/nodes/ConditionNode.vue +++ b/src/components/vue-flow/ui/nodes/ConditionNode.vue @@ -27,7 +27,13 @@ <div class="flex flex-col gap-y-2 min-w-[400px]"> <div class="flex justify-between flex-0"> <div class="flex items-center gap-x-2"> - <img src="/@/components/vue-flow/ui/assets/images/icon_Start.png" class="h-4 w-4" alt="Start icon" /> + <YWIcon + :name="VueFlowConfig.nodeStyleMap.get(NodeType.Condition).icon" + :fontSize="VueFlowConfig.nodeStyleMap.get(NodeType.Condition).fontSize" + :color="VueFlowConfig.nodeStyleMap.get(NodeType.Condition).color" + class="rounded-lg p-1.5" + :class="VueFlowConfig.nodeStyleMap.get(NodeType.Condition).class" + /> <div class="flex flex-col gap-y-1"> <p v-if="!titleIsEdit" class="text-xl font-bold text-gray-500" @click="titleIsEdit = true">{{ data.title }}</p> <el-input v-elInputFocus="false" v-else v-model="data.title" @blur="() => (titleIsEdit = false)"></el-input> @@ -60,7 +66,7 @@ <div class="flex flex-col gap-y-2" v-if="item.conditions"> <div v-for="(subItem, subIndex) in item.conditions" class="ml-5 flex-items-center gap-x-2 group/conditionItem pr-8"> <el-input filterable class="w-[120px] flex-0" v-model="subItem.left_value" placeholder="杈撳叆鍙橀噺"> </el-input> - <el-select v-model="subItem.comparison_operation" class="flex-0 w-[120px]" placeholder="閫夋嫨鏉′欢"> + <el-select filterable v-model="subItem.comparison_operation" class="flex-0 w-[120px]" placeholder="閫夋嫨鏉′欢"> <el-option v-for="item in Object.keys(compareOperationMap)" :key="item" @@ -114,16 +120,17 @@ </template> <script lang="ts" setup> -import { Handle, Position, useNode, useVueFlow } from '@vue-flow/core'; -import { ref, watchEffect } from 'vue'; - import type { NodeProps } from '@vue-flow/core'; -import { computed } from 'vue'; +import { Handle, Position, useNode, useVueFlow } from '@vue-flow/core'; +import { computed, ref, watchEffect } from 'vue'; import { VueFlowConstant } from '../../VueFlowConstant'; import { ConditionHelper, VueFlowHelper } from '../../VueFlowHelper'; -import { CompareOperation, VarType, compareOperationMap, conditionOperatorMap, varTypeMap } from '../../vueFlowEnum'; +import { CompareOperation, VarType, compareOperationMap, conditionOperatorMap } from '../../vueFlowEnum'; import { LLMNodeData, LLMNodeEvents } from './index'; import { deepClone } from '/@/utils/other'; +import { VueFlowConfig } from '../VueFlowConfig'; +import { NodeType } from '../../vueFlowEnum'; + defineProps<NodeProps<LLMNodeData, LLMNodeEvents>>(); const node = useNode(); @@ -133,7 +140,7 @@ const otherHandleId = VueFlowHelper.genId(); const isShowRight = (item) => { - const yes = ![CompareOperation.empty, CompareOperation.notEmpty].includes(item.comparison_operation); + const yes = ![CompareOperation.empty, CompareOperation.notEmpty].includes(item.comparison_operation); return yes; }; diff --git a/src/components/vue-flow/ui/nodes/EndNode.vue b/src/components/vue-flow/ui/nodes/EndNode.vue index c3ee5cb..7d5e3d5 100644 --- a/src/components/vue-flow/ui/nodes/EndNode.vue +++ b/src/components/vue-flow/ui/nodes/EndNode.vue @@ -28,7 +28,13 @@ <div class="flex flex-col gap-y-2"> <div class="flex justify-between flex-0"> <div class="flex items-center gap-x-2"> - <img src="/@/components/vue-flow/ui/assets/images/icon_End.png" class="h-4 w-4" alt="Start icon" /> + <YWIcon + :name="VueFlowConfig.nodeStyleMap.get(NodeType.End).icon" + :fontSize="VueFlowConfig.nodeStyleMap.get(NodeType.End).fontSize" + :color="VueFlowConfig.nodeStyleMap.get(NodeType.End).color" + class="rounded-lg p-1.5" + :class="VueFlowConfig.nodeStyleMap.get(NodeType.End).class" + /> <div class="flex flex-col gap-y-1"> <p v-if="!titleIsEdit" class="text-xl font-bold text-gray-500" @click="titleIsEdit = true">{{ data.title }}</p> <el-input v-elInputFocus="false" v-else v-model="data.title" @blur="() => (titleIsEdit = false)"></el-input> @@ -52,11 +58,13 @@ import { computed, ref } from 'vue'; import { VueFlowConstant } from '../../VueFlowConstant'; import { VueFlowHelper } from '../../VueFlowHelper'; +import { VueFlowConfig } from '../VueFlowConfig'; +import { NodeType } from '../../vueFlowEnum'; + import { LLMNodeData, LLMNodeEvents } from './index'; import { deepClone } from '/@/utils/other'; - defineProps<NodeProps<LLMNodeData, LLMNodeEvents>>(); - + const node = useNode(); const handleId = ref(VueFlowHelper.getHandleId(node.node, 'target')); diff --git a/src/components/vue-flow/ui/nodes/FuncNode.vue b/src/components/vue-flow/ui/nodes/FuncNode.vue new file mode 100644 index 0000000..37c0d4d --- /dev/null +++ b/src/components/vue-flow/ui/nodes/FuncNode.vue @@ -0,0 +1,112 @@ +<template> + <div + class="w-max-[520px] border-2 rounded-lg border-solid border-gray-100 bg-white p-3 shadow-md relative hover:border-blue-500 group" + > + <Handle :id="targetHandleId" type="target" :position="Position.Left" /> + <div + class="group-hover:visible invisible flex absolute divide-y-[1.5px] divide-solid divide-gray-100 rounded-lg right-0 -top-0.5 translate-y-[-100%]" + style="box-shadow: 0 0 15px #dbdee6" + > + <el-tooltip effect="dark" content="澶嶅埗" placement="top"> + <div + class="flex content-center items-center border-x-0 p-1 hover:bg-gray-200 active:bg-gray-300 cursor-pointer" + @click="handleClickDuplicateBtn" + > + <span class="ywifont !text-[20px] mb-1 p-1.5 ywicon-copy"></span> + </div> + </el-tooltip> + <el-tooltip effect="dark" content="鍒犻櫎" placement="top"> + <div + @click="clickDeleteBtn" + class="flex content-center items-center border-x-0 p-1 hover:bg-gray-200 active:bg-gray-300 hover:text-red-400 cursor-pointer" + > + <span class="ywifont !text-[20px] mb-1 p-1.5 ywicon-shanchu"></span> + </div> + </el-tooltip> + </div> + <div class="flex flex-col gap-y-2"> + <div class="flex justify-between flex-0"> + <div class="flex items-center gap-x-2"> + <YWIcon + :name="VueFlowConfig.nodeStyleMap.get(NodeType.Agent).icon" + :fontSize="VueFlowConfig.nodeStyleMap.get(NodeType.Agent).fontSize" + :color="VueFlowConfig.nodeStyleMap.get(NodeType.Agent).color" + class="rounded-lg p-1.5" + :class="VueFlowConfig.nodeStyleMap.get(NodeType.Agent).class" + /> + <div class="flex flex-col gap-y-1"> + <p v-if="!titleIsEdit" class="text-xl font-bold text-gray-500" @click="titleIsEdit = true">{{ data.title }}</p> + <el-input v-elInputFocus="false" v-else v-model="data.title" @blur="() => (titleIsEdit = false)"></el-input> + </div> + </div> + </div> + + <div class="flex-auto gap-y-2 flex-col flex nodrag"> + <div class="text-lg font-bold">鍑芥暟鍚嶇О</div> + + <div class="min-w-[340px] flex-items-center gap-x-2"> + <div class="flex-column gap-y-1.5"> + <!-- <span class="text-gray-500">妯″瀷</span> --> + <el-select filterable placeholder="璇烽�夋嫨鍑芥暟鍚嶇О" v-model="funcNameParams.value" @change="agentParamsValueChange"> + <el-option v-for="item in funcNames" :key="item.id" :value="item.id" :label="item.title"></el-option> + </el-select> + </div> + </div> + </div> + </div> + <Handle :id="sourceHandleId" type="source" :position="Position.Right" /> + </div> + + <!-- <div> + <span>璧峰</span> + + <Handle type="source" :position="Position.Right" /> + </div> --> +</template> + +<script lang="ts" setup> +import { Handle, Position, useNode, useVueFlow } from '@vue-flow/core'; +import { ref } from 'vue'; + +import { VueFlowHelper } from '../../VueFlowHelper'; +import { NodeType } from '../../vueFlowEnum'; +import { VueFlowConfig } from '../VueFlowConfig'; +import { deepClone } from '/@/utils/other'; + +// defineProps<NodeProps<LLMNodeData, LLMNodeEvents>>(); + +const props = defineProps(['funcNames']) +const agentParamsValueChange = () => { + // const foundNames = props.agentNames.find(item=>item.id == agentParams.value); + // agentParams.value.value_label = foundNames?.title ??''; +}; +const node = useNode(); +const sourceHandleId = ref(VueFlowHelper.getHandleId(node.node, 'source')); +const targetHandleId = ref(VueFlowHelper.getHandleId(node.node, 'target')); + +const data = ref(node.node.data); + +const varList = ref(VueFlowHelper.getFieldValue(data.value, 'var_list')); +const titleIsEdit = ref(false); + +const funcNameParams = ref(VueFlowHelper.getParams(VueFlowHelper.getGroupParam(data.value), 'func_name')); + +const { removeNodes, nodes, addNodes } = useVueFlow(); + +function handleClickDuplicateBtn() { + const { type, position, data } = node.node; + const newNode = { + id: VueFlowHelper.genGeometryId(), + type, + position: { + x: position.x + 100, + y: position.y + 100, + }, + data: deepClone(data), + }; + addNodes(newNode); +} +const clickDeleteBtn = () => { + removeNodes(node.id); +}; +</script> diff --git a/src/components/vue-flow/ui/nodes/LLMNode.vue b/src/components/vue-flow/ui/nodes/LLMNode.vue index 69eb5b6..c90e462 100644 --- a/src/components/vue-flow/ui/nodes/LLMNode.vue +++ b/src/components/vue-flow/ui/nodes/LLMNode.vue @@ -2,7 +2,7 @@ <div class="w-max-[520px] border-2 rounded-lg border-solid border-gray-100 bg-white p-3 shadow-md relative hover:border-blue-500 group" > - <Handle :id="targetHandleId" type="source" :position="Position.Left" /> + <Handle :id="targetHandleId" type="target" :position="Position.Left" /> <div class="group-hover:visible invisible flex absolute divide-y-[1.5px] divide-solid divide-gray-100 rounded-lg right-0 -top-0.5 translate-y-[-100%]" style="box-shadow: 0 0 15px #dbdee6" @@ -27,7 +27,13 @@ <div class="flex flex-col gap-y-2"> <div class="flex justify-between flex-0"> <div class="flex items-center gap-x-2"> - <img src="/@/components/vue-flow/ui/assets/images/icon_Start.png" class="h-4 w-4" alt="Start icon" /> + <YWIcon + :name="VueFlowConfig.nodeStyleMap.get(NodeType.LLM).icon" + :fontSize="VueFlowConfig.nodeStyleMap.get(NodeType.LLM).fontSize" + :color="VueFlowConfig.nodeStyleMap.get(NodeType.LLM).color" + class="rounded-lg p-1.5" + :class="VueFlowConfig.nodeStyleMap.get(NodeType.LLM).class" + /> <div class="flex flex-col gap-y-1"> <p v-if="!titleIsEdit" class="text-xl font-bold text-gray-500" @click="titleIsEdit = true">{{ data.title }}</p> <el-input v-else v-elInputFocus="false" v-model="data.title" @blur="() => (titleIsEdit = false)"></el-input> @@ -85,6 +91,8 @@ import { VueFlowHelper } from '../../VueFlowHelper'; import { LLMNodeData, LLMNodeEvents } from './index'; import { deepClone } from '/@/utils/other'; +import { NodeType } from '../../vueFlowEnum'; +import { VueFlowConfig } from '../VueFlowConfig'; defineProps<NodeProps<LLMNodeData, LLMNodeEvents>>(); diff --git a/src/components/vue-flow/ui/nodes/OutputNode.vue b/src/components/vue-flow/ui/nodes/OutputNode.vue index a62d7ec..2d45c89 100644 --- a/src/components/vue-flow/ui/nodes/OutputNode.vue +++ b/src/components/vue-flow/ui/nodes/OutputNode.vue @@ -2,7 +2,7 @@ <div class="min-w-[320px] w-max-[520px] border-2 rounded-lg border-solid border-gray-100 bg-white p-3 shadow-md relative hover:border-blue-500 group" > - <Handle :id="targetHandleId" type="source" :position="Position.Left" /> + <Handle :id="targetHandleId" type="target" :position="Position.Left" /> <div class="group-hover:visible invisible flex absolute divide-y-[1.5px] divide-solid divide-gray-100 rounded-lg right-0 -top-0.5 translate-y-[-100%]" style="box-shadow: 0 0 15px #dbdee6" @@ -27,7 +27,13 @@ <div class="flex flex-col gap-y-2"> <div class="flex justify-between flex-0"> <div class="flex items-center gap-x-2"> - <img src="/@/components/vue-flow/ui/assets/images/icon_Start.png" class="h-4 w-4" alt="Start icon" /> + <YWIcon + :name="VueFlowConfig.nodeStyleMap.get(NodeType.Output).icon" + :fontSize="VueFlowConfig.nodeStyleMap.get(NodeType.Output).fontSize" + :color="VueFlowConfig.nodeStyleMap.get(NodeType.Output).color" + class="rounded-lg p-1.5" + :class="VueFlowConfig.nodeStyleMap.get(NodeType.Output).class" + /> <div class="flex flex-col gap-y-1"> <p v-if="!titleIsEdit" class="text-xl font-bold text-gray-500" @click="titleIsEdit = true">{{ data.title }}</p> <el-input v-elInputFocus="false" v-else v-model="data.title" @blur="() => (titleIsEdit = false)"></el-input> @@ -121,8 +127,8 @@ import { InteractionType, interactionTypeMap } from '../../vueFlowEnum'; import { LLMNodeData, LLMNodeEvents } from './index'; import { deepClone } from '/@/utils/other'; -import { remove } from 'nprogress'; -defineProps<NodeProps<LLMNodeData, LLMNodeEvents>>(); +import { VueFlowConfig } from '../VueFlowConfig'; +import { NodeType } from '../../vueFlowEnum';defineProps<NodeProps<LLMNodeData, LLMNodeEvents>>(); const node = useNode(); const sourceHandleId = ref(VueFlowHelper.getHandleId(node.node, 'source')); diff --git a/src/components/vue-flow/ui/nodes/StartNode.vue b/src/components/vue-flow/ui/nodes/StartNode.vue index 582b0b5..9f2ebe2 100644 --- a/src/components/vue-flow/ui/nodes/StartNode.vue +++ b/src/components/vue-flow/ui/nodes/StartNode.vue @@ -26,7 +26,14 @@ <div class="flex flex-col gap-y-2"> <div class="flex justify-between flex-0"> <div class="flex items-center gap-x-2"> - <img src="/@/components/vue-flow/ui/assets/images/icon_Start.png" class="h-4 w-4" alt="Start icon" /> + <YWIcon + :name="VueFlowConfig.nodeStyleMap.get(NodeType.Start).icon" + :fontSize="VueFlowConfig.nodeStyleMap.get(NodeType.Start).fontSize" + :color="VueFlowConfig.nodeStyleMap.get(NodeType.Start).color" + class="rounded-lg p-1.5 " + :class="VueFlowConfig.nodeStyleMap.get(NodeType.Start).class" + + /> <div class="flex flex-col gap-y-1"> <p v-if="!titleIsEdit" class="text-xl font-bold text-gray-500" @click="titleIsEdit = true">{{ data.title }}</p> <el-input v-elInputFocus="false" v-else v-model="data.title" @blur="() => (titleIsEdit = false)"></el-input> @@ -96,17 +103,15 @@ import type { NodeProps } from '@vue-flow/core'; import { VueFlowConstant } from '../../VueFlowConstant'; import { VueFlowHelper } from '../../VueFlowHelper'; -import { parameterTypeMap } from '../../vueFlowEnum'; +import { NodeType, parameterTypeMap } from '../../vueFlowEnum'; +import { VueFlowConfig } from '../VueFlowConfig'; import { LLMNodeData, LLMNodeEvents } from './index'; import { deepClone } from '/@/utils/other'; - defineProps<NodeProps<LLMNodeData, LLMNodeEvents>>(); - const node = useNode(); const handleId = ref(VueFlowHelper.getHandleId(node.node, 'source')); const data = ref(node.node.data); - const getVarList = () => { const varList = data.value[VueFlowConstant.GROUP_PARAMS_KEY][0][VueFlowConstant.PARAMS_KEY].find( (item) => item.key === 'condition' diff --git a/src/components/vue-flow/vueFlowEnum.ts b/src/components/vue-flow/vueFlowEnum.ts index e7c1022..a0c03c8 100644 --- a/src/components/vue-flow/vueFlowEnum.ts +++ b/src/components/vue-flow/vueFlowEnum.ts @@ -5,9 +5,9 @@ } export const parameterTypeMap = { - [ParameterType.String]: 'string', - [ParameterType.Number]: 'number', - [ParameterType.Boolean]: 'boolean', + [ParameterType.String]: '瀛楃涓�', + [ParameterType.Number]: '鏁板瓧', + [ParameterType.Boolean]: '甯冨皵鍊�', }; export const enum NodeType { @@ -17,7 +17,8 @@ Condition = 'condition', Knowledge = 'knowledge', Output = 'output_msg', - Agent='agent' + Agent='agent', + Func='func', } export const nodeTypeMap = { @@ -26,8 +27,9 @@ [NodeType.End]: '缁撴潫', [NodeType.Condition]: '鏉′欢鍒ゆ柇', [NodeType.Knowledge]: '鐭ヨ瘑搴�', - [NodeType.Output]: '杈撳嚭', + [NodeType.Output]: '瀵硅瘽', [NodeType.Agent]: '浠g悊', + [NodeType.Func]: '鎵ц鍔熻兘', }; @@ -44,6 +46,11 @@ startWith = 'startWith', /** @description 缁撴潫涓� */ endWith = 'endWith', + + /** @description 闈炲紑濮嬩负 */ + notStartWith = 'notStartWith', + /** @description 闈炵粨鏉熶负 */ + notEndWith = 'notEndWith', /** @description 绛変簬 */ eq = 'eq', @@ -71,6 +78,8 @@ [CompareOperation.notEmpty]: '涓嶄负绌�', [CompareOperation.startWith]: '寮�濮嬩负', [CompareOperation.endWith]: '缁撴潫涓�', + [CompareOperation.notStartWith]: '闈炲紑濮嬩负', + [CompareOperation.notEndWith]: '闈炵粨鏉熶负', }; export const enum VarType { diff --git a/src/main.ts b/src/main.ts index f2a3365..620b129 100644 --- a/src/main.ts +++ b/src/main.ts @@ -5,14 +5,14 @@ import { directive } from '/@/directive/index'; import { i18n } from '/@/i18n/index'; import other from '/@/utils/other'; -import "@amap/amap-jsapi-types"; +import '@amap/amap-jsapi-types'; import '/@/extend'; +import YWIcon from '/@/components/icon/index.vue'; import ElementPlus from 'element-plus'; import '/@/theme/index.scss'; import * as ElementPlusIconsVue from '@element-plus/icons-vue'; import { gotoRoute } from '/@/utils/route'; - const app = createApp(App); for (const [key, component] of Object.entries(ElementPlusIconsVue)) { @@ -20,6 +20,7 @@ } directive(app); other.elSvg(app); +app.component('YWIcon', YWIcon); app.use(pinia).use(router).use(ElementPlus).use(i18n).mount('#app'); window.openPage = (name, siteId) => { diff --git a/src/utils/setIconfont.ts b/src/utils/setIconfont.ts index 0887ad2..e678257 100644 --- a/src/utils/setIconfont.ts +++ b/src/utils/setIconfont.ts @@ -1,7 +1,7 @@ // 瀛椾綋鍥炬爣 url const cssCdnUrlList: Array<string> = [ './static/fonts/iconfont/iconfont.css', - './static/fonts/ywiconfont/iconfont.css?v=2112', + './static/fonts/ywiconfont/iconfont.css?v=21122', './static/fonts/fontawesome/fontawesome.min.css', ]; diff --git a/src/views/project/yw/systemManage/flowApp/FlowApp.vue b/src/views/project/yw/systemManage/flowApp/FlowApp.vue index bacc18a..4a1c654 100644 --- a/src/views/project/yw/systemManage/flowApp/FlowApp.vue +++ b/src/views/project/yw/systemManage/flowApp/FlowApp.vue @@ -1,11 +1,11 @@ <template> - <div class="absolute bottom-0 left-0 right-0 top-0 bg-gray text-base"> + <div class="absolute bottom-0 left-0 right-0 top-0 bg-page text-base"> <div class="relative flex h-full w-full flex-col"> <Header v-if="flowAgent" :flowAgent="flowAgent" :queryId="queryId" /> <main class="relative flex h-full w-full flex-1"> - <Sidebar @dragstart="handleOnDragStart" /> + <Sidebar class="w-52" @dragstart="handleOnDragStart" /> <div class="relative h-full flex-1 overflow-hidden" v-if="flowJson"> - <MainCanvas :flowJson="flowJson" :agentNames="agentNames" /> + <MainCanvas :flowJson="flowJson" :agentNames="agentNames" :funcNames="funcNames"/> </div> </main> </div> @@ -20,7 +20,7 @@ import { computed, onMounted, ref } from 'vue'; import Header from './components/Header.vue'; import Sidebar from './components/Sidebar.vue'; -import { get_agent_names, get_workflow_agent_list, get_workflow_json_flow } from '/@/api/workflow'; +import { get_agent_names, get_flow_func_names, get_workflow_agent_list, get_workflow_json_flow } from '/@/api/workflow'; import MainCanvas from '/@/components/vue-flow/MainCanvas.vue'; import router from '/@/router'; @@ -62,11 +62,17 @@ const res = await get_agent_names(); agentNames.value = res.agents ?? []; }; +const funcNames = ref([]); +const getFuncNames = async () => { + const res = await get_flow_func_names(); + funcNames.value = res.funcs ?? []; +}; onMounted(() => { if (!queryId.value) return; handleGetJSON(queryId.value); getFlowAgent(); getAgentNames(); + getFuncNames(); }); </script> diff --git a/src/views/project/yw/systemManage/flowApp/components/Sidebar.vue b/src/views/project/yw/systemManage/flowApp/components/Sidebar.vue index e5c1ec9..bd07db3 100644 --- a/src/views/project/yw/systemManage/flowApp/components/Sidebar.vue +++ b/src/views/project/yw/systemManage/flowApp/components/Sidebar.vue @@ -1,16 +1,16 @@ <template> - <div class="w-44 bg-white rounded-lg mt-2 py-2 px-2"> + <div class="bg-white rounded-lg mt-2 py-2 px-2"> <div - v-for="item in sidebarList" + v-for="item in VueFlowConfig.nodeStyleMap.values()" class="cursor-grab rounded-md bg-white py-3 px-2 hover:bg-gray-100" :draggable="true" @dragstart="handleOnDragStart($event, item.type)" > <div class="flex items-center justify-between"> - <h3 class="flex items-center gap-x-2"> - <img :src="item.img" class="h-4 w-4" alt="LLM icon" /> + <span class="flex items-center gap-x-2"> + <YWIcon :name="item.icon" :fontSize="item.fontSize" :color="item.color" class="rounded-lg p-1.5" :class="item.class" /> {{ item.title }} - </h3> + </span> <!-- <plus-icon class="text-primary" /> --> </div> </div> @@ -18,9 +18,8 @@ </template> <script setup lang="ts"> -import llmImg from '/@/components/vue-flow/ui/assets/images/icon_LLM.png'; -import startImg from '/@/components/vue-flow/ui/assets/images/icon_Start.png'; -import endImg from '/@/components/vue-flow/ui/assets/images/icon_End.png'; +import YWIcon from '/@/components/icon/index.vue'; +import { VueFlowConfig } from '/@/components/vue-flow/ui/VueFlowConfig'; import { NodeType, nodeTypeMap } from '/@/components/vue-flow/vueFlowEnum'; const emit = defineEmits(['dragstart']); @@ -29,38 +28,5 @@ emit('dragstart', e, type); }; -const sidebarList = [ - { - type: NodeType.Start, - title: nodeTypeMap[NodeType.Start], - img: startImg, - }, - { - type: NodeType.End, - title: nodeTypeMap[NodeType.End], - img: endImg, - }, - { - type: NodeType.Condition, - title: nodeTypeMap[NodeType.Condition], - img: llmImg, - }, - { - type: NodeType.LLM, - title: nodeTypeMap[NodeType.LLM], - img: llmImg, - }, - { - type: NodeType.Output, - title: nodeTypeMap[NodeType.Output], - img: llmImg, - }, - { - type: NodeType.Agent, - title: nodeTypeMap[NodeType.Agent], - img: llmImg, - }, - -]; </script> <style scoped lang="scss"></style> diff --git a/tailwind.config.js b/tailwind.config.js index 847ed5a..63336e3 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -7,7 +7,7 @@ 'light-7': `var(--${namespace}-color-${branchName}-light-7)`, 'light-8': `var(--${namespace}-color-${branchName}-light-8)`, 'light-9': `var(--${namespace}-color-${branchName}-light-9)`, - main: `var(--${namespace}-color-${branchName})`, + DEFAULT: `var(--${namespace}-color-${branchName})`, 'dark-2': `var(--${namespace}-color-${branchName}-dark-2)`, }; } @@ -36,7 +36,6 @@ page: `var(--${namespace}-bg-color-page)`, overlay: `var(--${namespace}-bg-color-overlay)`, disabled: `var(--${namespace}-disabled-bg-color)`, - gray: `#f4f5f8`, }, textColor: { -- Gitblit v1.9.3