Explorar o código

fix: 调整优化节点内容

jiaxing.liao hai 1 mes
pai
achega
f42adf1ed2

+ 1 - 0
apps/web/.gitignore

@@ -9,6 +9,7 @@ lerna-debug.log*
 
 node_modules
 dist
+dist.zip
 dist-ssr
 *.local
 

+ 0 - 8
apps/web/components.d.ts

@@ -12,7 +12,6 @@ export {}
 /* prettier-ignore */
 declare module 'vue' {
   export interface GlobalComponents {
-    AutoFocusPlugin: typeof import('./src/components/PromptEditor/plugins/AutoFocusPlugin.vue')['default']
     ElAside: typeof import('element-plus/es')['ElAside']
     ElAvatar: typeof import('element-plus/es')['ElAvatar']
     ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
@@ -59,7 +58,6 @@ declare module 'vue' {
     ElTag: typeof import('element-plus/es')['ElTag']
     ElTooltip: typeof import('element-plus/es')['ElTooltip']
     ExecutionChart: typeof import('./src/components/Chart/ExecutionChart.vue')['default']
-    PromptEditor: typeof import('./src/components/PromptEditor/index.vue')['default']
     RouterLink: typeof import('vue-router')['RouterLink']
     RouterView: typeof import('vue-router')['RouterView']
     RunWorkflow: typeof import('./src/components/RunWorkflow/index.vue')['default']
@@ -68,8 +66,6 @@ declare module 'vue' {
     SvgIcon: typeof import('./src/components/SvgIcon/index.vue')['default']
     TemplateModal: typeof import('./src/components/TemplateModal/index.vue')['default']
     VarLabel: typeof import('./src/components/VarLabel/index.vue')['default']
-    VarLabelBlock: typeof import('./src/components/PromptEditor/plugins/VarLabelBlock.vue')['default']
-    VarLaberPickerPlugin: typeof import('./src/components/PromptEditor/plugins/VarLaberPickerPlugin.vue')['default']
   }
   export interface GlobalDirectives {
     vLoading: typeof import('element-plus/es')['ElLoadingDirective']
@@ -78,7 +74,6 @@ declare module 'vue' {
 
 // For TSX support
 declare global {
-  const AutoFocusPlugin: typeof import('./src/components/PromptEditor/plugins/AutoFocusPlugin.vue')['default']
   const ElAside: typeof import('element-plus/es')['ElAside']
   const ElAvatar: typeof import('element-plus/es')['ElAvatar']
   const ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
@@ -125,7 +120,6 @@ declare global {
   const ElTag: typeof import('element-plus/es')['ElTag']
   const ElTooltip: typeof import('element-plus/es')['ElTooltip']
   const ExecutionChart: typeof import('./src/components/Chart/ExecutionChart.vue')['default']
-  const PromptEditor: typeof import('./src/components/PromptEditor/index.vue')['default']
   const RouterLink: typeof import('vue-router')['RouterLink']
   const RouterView: typeof import('vue-router')['RouterView']
   const RunWorkflow: typeof import('./src/components/RunWorkflow/index.vue')['default']
@@ -134,6 +128,4 @@ declare global {
   const SvgIcon: typeof import('./src/components/SvgIcon/index.vue')['default']
   const TemplateModal: typeof import('./src/components/TemplateModal/index.vue')['default']
   const VarLabel: typeof import('./src/components/VarLabel/index.vue')['default']
-  const VarLabelBlock: typeof import('./src/components/PromptEditor/plugins/VarLabelBlock.vue')['default']
-  const VarLaberPickerPlugin: typeof import('./src/components/PromptEditor/plugins/VarLaberPickerPlugin.vue')['default']
 }

+ 1 - 1
apps/web/src/features/nodeLibary/index.vue

@@ -34,7 +34,7 @@ const materials = computed<NodeGroup[]>(() => {
 	const groupMap = new Map<string, NodeGroup>()
 
 	nodes
-		.filter((node) => !node.name?.includes('custom-'))
+		.filter((node) => !node.hideInLibary) // 过滤掉 hideInLibary 的节点
 		.forEach((node) => {
 			const groupName = node.group || '其他'
 

+ 4 - 4
apps/web/src/features/setter/index.vue

@@ -83,11 +83,11 @@ const remark = computed({
 const nodeVars = ref<NodeVar[]>([])
 
 watch(
-	() => props.id,
-	async (id) => {
-		if (id) {
+	() => [props.id, props.visible],
+	async () => {
+		if (props.id && props.visible) {
 			const response = await agent.postAgentGetPrevNodeOutVariableList({
-				node_id: id,
+				node_id: props.id,
 				varTypeList: []
 			})
 			nodeVars.value = (response.result as NodeVar[]) || []

+ 4 - 0
apps/web/src/nodes/Interface.ts

@@ -33,6 +33,10 @@ export interface ConfigSchema {
 	input?: boolean
 	// 节点标签,可选
 	label?: string
+	/**
+	 * 是否在物料库中隐藏
+	 */
+	hideInLibary?: boolean
 	/**
 	 * 标签配置
 	 */

+ 16 - 13
apps/web/src/nodes/_base/VarSelect.vue

@@ -85,9 +85,7 @@
 						</div>
 					</div>
 
-					<div v-if="!filteredVars.length && !filteredVars.length" class="var-select__empty">
-						暂无匹配的变量
-					</div>
+					<div v-if="!filteredVars.length" class="var-select__empty">暂无匹配的变量</div>
 				</div>
 			</div>
 		</el-popover>
@@ -107,6 +105,10 @@ interface Props {
 	 * 选中的变量,格式 #{xxx.var}
 	 */
 	modelValue: string
+	/**
+	 * 过滤方法
+	 */
+	filterFn?: (list: NodeVar[]) => NodeVar[]
 }
 
 const props = withDefaults(defineProps<Props>(), {
@@ -174,14 +176,14 @@ const valueInfo = computed(() => {
 		// 环境变量
 		return {
 			type: 'env',
-			name: varName,
+			name: 'env',
 			value: varName
 		}
 	} else if (prefix.startsWith('sys')) {
 		// 系统变量
 		return {
-			type: 'system',
-			name: innerValue.value,
+			type: 'sys',
+			name: 'sys',
 			value: varName
 		}
 	} else {
@@ -206,7 +208,6 @@ const valueInfo = computed(() => {
 		}
 	}
 })
-
 const normalizeTypeLabel = (type?: VarType) => {
 	if (!type) return ''
 	return VARIABLE_TYPE_OPTIONS.find((item) => item.value === type)?.label || ''
@@ -218,17 +219,19 @@ const normalizeTypeLabel = (type?: VarType) => {
 const filteredVars = computed(() => {
 	const kw = keyword.value.trim().toLowerCase()
 
-	const options = nodeVars?.value?.filter((item) =>
-		item.variableList.find((i) => i.name.includes(kw))
-	)
+	let list = nodeVars?.value || []
+	// 先根据 filterFn 过滤一遍
+	if (props.filterFn) {
+		list = props.filterFn(list)
+	}
+
+	const options = list?.filter((item) => item.variableList.find((i) => i.name.includes(kw)))
 
 	return options || []
 })
 
 const handleSelect = (variable: { value: string; type: string }) => {
-	// 选择后只保留一个值,并包装成 #{xxx.var} 格式
-	const wrapped = `#{${variable.value}}`
-	innerValue.value = wrapped
+	innerValue.value = variable.value
 	visible.value = false
 	keyword.value = ''
 	emit('change', variable)

+ 8 - 6
apps/web/src/nodes/src/index.ts

@@ -18,25 +18,27 @@ import type { INodeType } from '../Interface'
 
 const loopStartNode = {
 	...startNode,
-	name: 'custom-loop-start',
-	nodeType: 'custom-loop-start',
+	name: 'loop-start',
+	nodeType: 'loop-start',
 	displayName: '循环开始',
 	hideToolBar: true,
+	hideInLibary: true, // 不在物料库中展示
 	schema: {
 		...startNode.schema,
-		nodeType: 'custom-loop-start'
+		nodeType: 'loop-start'
 	}
 }
 
 const iterationStartNode = {
 	...startNode,
-	name: 'custom-iteration-start',
-	nodeType: 'custom-iteration-start',
+	name: 'iteration-start',
+	nodeType: 'iteration-start',
 	displayName: '迭代开始',
 	hideToolBar: true,
+	hideInLibary: true, // 不在物料库中展示
 	schema: {
 		...startNode.schema,
-		nodeType: 'custom-iteration-start'
+		nodeType: 'iteration-start'
 	}
 }
 

+ 1 - 1
apps/web/src/nodes/src/iteration/setter.vue

@@ -144,7 +144,7 @@ const handleOutputIterationVariableChange = (val: { value: string; type: string
 				tooltip="最大并行度用于控制单次迭代中同时执行的任务数量。"
 				label-position="top"
 			>
-				<div class="w-full flex gap-12px">
+				<div class="w-full flex gap-12px pr-12px">
 					<el-input-number v-model="formData.parallel_nums" :min="1" :max="10" />
 					<div class="flex-2/3">
 						<el-slider v-model="formData.parallel_nums" :min="1" :max="10" />

+ 22 - 2
apps/web/src/nodes/src/list/setter.vue

@@ -5,6 +5,7 @@ import VarInput from '@/nodes/_base/VarInput.vue'
 
 import type { ListData } from './index'
 import type { NodeVariableType } from '@/nodes/Interface'
+import type { NodeVar } from '@/types/var'
 
 const props = defineProps<{
 	data: ListData
@@ -74,6 +75,21 @@ const handleInputVarChange = (val: { value: string; type: string }) => {
 	}
 }
 
+const isDataVarType = (type?: string) => {
+	if (!type) return false
+
+	return ['string', 'number', 'boolean', 'object'].includes(type) || /^array\[[^\]]+\]$/.test(type)
+}
+
+const filterVarFn = (list: NodeVar[]) => {
+	return list
+		.map((group) => ({
+			...group,
+			variableList: group.variableList.filter((item) => isDataVarType(item.type))
+		}))
+		.filter((group) => group.variableList.length)
+}
+
 const handleChangeFilterCondition = (val: { value: string; type: string }) => {
 	if (conditions.value) {
 		conditions.value.right_value = val.value
@@ -94,9 +110,9 @@ const handleChangeFilterCondition = (val: { value: string; type: string }) => {
 				<div class="w-full flex items-center justify-between beautify">
 					<label class="text-14px font-bold text-gray-700">输入</label>
 				</div>
-				<!--TODO: 输入变量类型选择-->
 				<VarSelect
 					:model-value="inputVar?.value"
+					:filter-fn="filterVarFn"
 					@change="handleInputVarChange"
 					placeholder="请选择输入变量"
 				/>
@@ -108,7 +124,11 @@ const handleChangeFilterCondition = (val: { value: string; type: string }) => {
 					<el-switch v-model="formData.filter_by.enabled" />
 				</div>
 				<div class="w-full flex items-center gap-12px">
-					<el-select :model-value="conditions?.comparison_operator" :options="[]" />
+					<el-select
+						:model-value="conditions?.comparison_operator"
+						:options="[]"
+						style="width: 120px"
+					/>
 					<VarInput :model-value="conditions?.right_value!" @change="handleChangeFilterCondition" />
 				</div>
 			</el-form-item>

+ 1 - 1
apps/web/src/views/Dashboard.vue

@@ -97,7 +97,7 @@
 			<div class="content-panel">
 				<div class="panel-header">
 					<h3>最近工作流</h3>
-					<el-button text @click="$router.push('/orchestration')">查看全部 →</el-button>
+					<el-button text @click="$router.push('/management')">查看全部 →</el-button>
 				</div>
 				<div class="workflow-list">
 					<div

+ 27 - 9
apps/web/src/views/Editor.vue

@@ -194,6 +194,10 @@ const handleApiResult = (response: any, successMessage?: string, errorMessage?:
 		}
 		return true
 	}
+	if (response?.code === 0 && response?.error) {
+		ElMessage.error(response.error)
+		return false
+	}
 	if (errorMessage) {
 		ElMessage.error(errorMessage)
 	}
@@ -454,6 +458,7 @@ const handleRunSelectedNode = async () => {
 			appAgentId: workflow.value.id,
 			start_node_id: nodeID.value,
 			is_debugger: true,
+			responseType: 'ws',
 			params: {}
 		})
 		const agentRunnerKey = response?.result
@@ -461,7 +466,7 @@ const handleRunSelectedNode = async () => {
 			runnerStore.startRunner(agentRunnerKey)
 		}
 		runVisible.value = false
-		handleApiResult(response, '已提交节点测试', '节点测试失败')
+		// handleApiResult(response, '已提交节点测试', '节点测试失败')
 	} catch (error) {
 		console.error('postDoTestNodeRunner error', error)
 		ElMessage.error('节点测试失败')
@@ -479,13 +484,14 @@ const handleRunNode = async (id: string) => {
 			appAgentId: workflow.value.id,
 			start_node_id: id,
 			is_debugger: true,
+			responseType: 'ws',
 			params: {}
 		})
 		const agentRunnerKey = response?.result
 		if (agentRunnerKey) {
 			runnerStore.startRunner(agentRunnerKey)
 		}
-		handleApiResult(response, '已提交运行节点', '运行节点失败')
+		// handleApiResult(response, '已提交运行节点', '运行节点失败')
 	} catch (error) {
 		console.error('postDoTestNodeRunner error', error)
 		ElMessage.error('运行节点失败')
@@ -638,7 +644,7 @@ const onCreateConnection = async (connection: Connection) => {
 	if (!workflow.value?.edges.some((edge) => edge.source === source && edge.target === target)) {
 		const response = await agent.postAgentDoNewEdge(params)
 
-		if (handleApiResult(response, '节点已添加', '新增节点失败')) {
+		if (handleApiResult(response, '连线已创建', '连线创建失败')) {
 			await loadAgentWorkflow(workflow.value.id)
 		}
 	}
@@ -750,10 +756,16 @@ const handleUpdateNodeProps = (id: string, attrs: Record<string, unknown>) => {
 const handleDeleteNode = async (id: string) => {
 	const index = workflow.value.nodes.findIndex((node) => node.id === id)
 	if (index != -1) {
-		await agent.postAgentDoDeleteAgentNode({
-			id: id
+		ElMessageBox.confirm('确定要删除吗?', '提示', {
+			confirmButtonText: '确定',
+			cancelButtonText: '取消',
+			type: 'warning'
+		}).then(async () => {
+			await agent.postAgentDoDeleteAgentNode({
+				id: id
+			})
+			await loadAgentWorkflow(workflow.value.id)
 		})
-		await loadAgentWorkflow(workflow.value.id)
 	}
 }
 
@@ -762,10 +774,16 @@ const handleDeleteNode = async (id: string) => {
  */
 const handleDeleteEdge = async (connection: Connection) => {
 	if (connection.id) {
-		await agent.postAgentDoDeleteEdge({
-			id: connection.id
+		ElMessageBox.confirm('确定要删除吗?', '提示', {
+			confirmButtonText: '确定',
+			cancelButtonText: '取消',
+			type: 'warning'
+		}).then(async () => {
+			await agent.postAgentDoDeleteEdge({
+				id: connection.id
+			})
+			await loadAgentWorkflow(workflow.value.id)
 		})
-		await loadAgentWorkflow(workflow.value.id)
 	}
 }
 

+ 2 - 0
packages/workflow/src/components/Canvas.vue

@@ -281,6 +281,7 @@ function onUpdateNodesPosition(events: CanvasNodeMoveEvent[]) {
 
 function onUpdateNodePosition(id: string, position: XYPosition) {
 	emit('update:node:position', id, position)
+	emit('update:nodes:position', [{ id, position }])
 }
 
 function onNodeDragStop(event: NodeDragEvent) {
@@ -426,6 +427,7 @@ defineExpose({
 					"
 					@delete="onDeleteNode"
 					@run="onRunNode"
+					@update:nodes:position="onUpdateNodesPosition"
 				/>
 			</slot>
 		</template>

+ 6 - 3
packages/workflow/src/components/elements/nodes/render-types/NodeLoop.vue

@@ -6,7 +6,7 @@ import type { OnResize } from '@vue-flow/node-resizer'
 import Canvas from '../../../Canvas.vue'
 
 import type { XYPosition, Connection } from '@vue-flow/core'
-import type { ConnectStartEvent } from '../../../../Interface'
+import type { CanvasNodeMoveEvent, ConnectStartEvent } from '../../../../Interface'
 import { useCanvasNodeContext } from '../../../../hooks/useCanvasNodeContext'
 import { useVueFlowContext } from '../../../../hooks/useVueFlowContext'
 
@@ -30,13 +30,14 @@ const childrenEdges = computed(() =>
 	)
 )
 const emit = defineEmits<{
-	update: [parameters: Record<string, unknown>]
+	update: [id: string, attrs: Record<string, unknown>]
 	move: [position: XYPosition]
 	'click:node:add': [
 		payload: { nodeId: string; handle: string; position: XYPosition; event?: MouseEvent }
 	]
 	'add-inner-node': [parentId: string]
 	'add-inner-edge': [connection: Connection]
+	'update:nodes:position': [events: CanvasNodeMoveEvent[]]
 	'create:connection:cancelled': [
 		payload: { handle: ConnectStartEvent; position: XYPosition; event?: MouseEvent }
 	]
@@ -65,7 +66,7 @@ function onResize(event: OnResize) {
 		x: event.params.x,
 		y: event.params.y
 	})
-	emit('update', {
+	emit('update', node.props.value.id, {
 		...(event.params.width != null ? { width: event.params.width } : {}),
 		...(event.params.height != null ? { height: event.params.height } : {})
 	})
@@ -132,6 +133,8 @@ function onAddEdge(connection: Connection) {
 					@create:node="onAddNode"
 					@create:connection:end="onAddEdge"
 					@create:connection:cancelled="emit('create:connection:cancelled', $event)"
+					@update:node:attrs="(id, attrs) => emit('update', id, attrs)"
+					@update:nodes:position="emit('update:nodes:position', $event)"
 				/>
 			</div>
 		</div>