Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion ui/src/workflow-canvas/config/node-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,20 @@ export const loopNode = {
y: 200,
id: 'loop-start-node',
type: 'loop-start-node',
properties: { config: { fields: [], globalFields: [] }, fields: [], showNode: true, stepName: '开始', globalFields: [] },
properties: {
config: {
// 循环引擎内置的输出参数(index/item),只读展示,用户不可增删改
fields: [
{ label: '下标', value: 'index' },
{ label: '循环元素', value: 'item' },
],
globalFields: [],
},
fields: [],
showNode: true,
stepName: '开始',
globalFields: [],
},
},
],
},
Expand All @@ -410,6 +423,7 @@ export const loopStartNode = {
properties: {
stepName: '循环开始',
config: {
// 循环引擎内置的输出参数(index/item),只读展示,用户不可增删改
fields: [
{ label: '下标', value: 'index' },
{ label: '循环元素', value: 'item' },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import { reactive, ref } from 'vue'
import { cloneDeep } from 'lodash'
import type { FormInstance } from 'element-plus'
import { isLoopBuiltinField } from '../constant'

defineOptions({ name: 'LoopFieldDialog' })
const emit = defineEmits<{ refresh: [data: { field: string; label: string }, index?: number] }>()
Expand All @@ -42,6 +43,16 @@ const rules = reactive({
field: [
{ required: true, message: '请输入变量名', trigger: 'blur' },
{ pattern: /^[a-zA-Z0-9_]+$/, message: '变量名只能包含英文字母、数字、下划线', trigger: 'blur' },
{
validator: (_rule: unknown, value: string, callback: (error?: Error) => void) => {
if (isLoopBuiltinField(value)) {
callback(new Error('此变量名为循环引擎内置,不可使用'))
} else {
callback()
}
},
trigger: 'blur',
},
],
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,14 @@ import { cloneDeep, set } from 'lodash'
import type { BaseNodeModel } from '@logicflow/core'
import LoopFieldDialog from './LoopFieldDialog.vue'
import { MsgError } from '@/utils/message'
import { isLoopBuiltinField } from '../constant'

defineOptions({ name: 'LoopFieldTable' })
const props = defineProps<{ nodeModel: BaseNodeModel }>()

type WorkflowGraphModel = BaseNodeModel['graphModel'] & { refresh_loop_fields?: (fields: Array<{ label: string; value: string }>) => void }
type LoopInputField = { field: string; label: string }

const DEFAULT_FIELDS: LoopInputField[] = [
{ field: 'index', label: '下标' },
{ field: 'item', label: '循环元素' },
]

const fieldDialogRef = ref<InstanceType<typeof LoopFieldDialog>>()
const loopInputFieldList = ref<LoopInputField[]>([])

Expand Down Expand Up @@ -85,11 +81,10 @@ function sync() {

onMounted(() => {
const properties = props.nodeModel.properties as { loop_input_field_list?: LoopInputField[] }
if (Array.isArray(properties.loop_input_field_list)) {
loopInputFieldList.value = cloneDeep(properties.loop_input_field_list)
} else {
loopInputFieldList.value = cloneDeep(DEFAULT_FIELDS)
}
// 内置参数(index/item)由循环引擎提供,作为只读输出参数展示,不进入用户可配置的循环变量列表
loopInputFieldList.value = (Array.isArray(properties.loop_input_field_list) ? cloneDeep(properties.loop_input_field_list) : []).filter(
(item) => !isLoopBuiltinField(item.field),
)
sync()
})
</script>
8 changes: 8 additions & 0 deletions ui/src/workflow-canvas/nodes/loop-start-node/constant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// 循环引擎自带的输出参数(内置,界面上不展示、不可被用户修改)
export const LOOP_BUILTIN_FIELDS = [
{ field: 'index', label: '下标' },
{ field: 'item', label: '循环元素' },
] as const

export const isLoopBuiltinField = (value?: string) =>
!!value && LOOP_BUILTIN_FIELDS.some((item) => item.field === value)
22 changes: 17 additions & 5 deletions ui/src/workflow-canvas/nodes/loop-start-node/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import LoopStartNodeVue from './index.vue'
import { WorkflowNodeModel, WorkflowNodeView } from '@/workflow-canvas/core/workflow-node'
import { WorkflowNodeType, type WorkflowNodeField } from '@/workflow-canvas/types'
import { isLoopBuiltinField, LOOP_BUILTIN_FIELDS } from './constant'

interface LoopStartNodeProperties {
config?: { fields?: Array<{ label: string; value: string }>; globalFields?: unknown[] }
Expand All @@ -9,13 +10,24 @@ interface LoopStartNodeProperties {
}

class LoopStartNodeModel extends WorkflowNodeModel {
override setAttributes() {
super.setAttributes()
// 循环引擎内置的 index/item 作为只读输出参数,始终保留在节点自身配置里,保证输出区一定展示
const config = (this.properties.config ?? {}) as { fields?: unknown[]; globalFields?: unknown[] }
this.properties.config = {
...config,
fields: LOOP_BUILTIN_FIELDS.map((item) => ({ label: item.label, value: item.field })),
}
}

override getNodeFieldList(): WorkflowNodeField[] {
const properties = this.properties as LoopStartNodeProperties
const inputFields =
properties.loop_input_field_list && properties.loop_input_field_list.length
? properties.loop_input_field_list.map((item) => ({ field: item.field ?? item.variable ?? '', label: item.label ?? '' }))
: (properties.config?.fields ?? []).map((field) => ({ field: field.value, label: field.label }))
const loopFields = inputFields.map((item) => ({ label: item.label, value: item.field })).filter((field) => Boolean(field.value))
const inputFields = properties.loop_input_field_list
? properties.loop_input_field_list
: (properties.config?.fields ?? []).map((field) => ({ field: field.value, label: field.label, variable: undefined }))
const loopFields = inputFields
.map((item) => ({ label: item.label ?? '', value: item.field ?? item.variable ?? '' }))
.filter((field) => Boolean(field.value) && !isLoopBuiltinField(field.value))
return [{ value: 'loop', label: '循环变量', type: 'loop', children: loopFields }, ...super.getNodeFieldList()]
}
}
Expand Down
3 changes: 2 additions & 1 deletion ui/src/workflow-canvas/nodes/loop-start-node/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import type { BaseNodeModel } from '@logicflow/core'
import NodeContainer from '@/workflow-canvas/core/node-container/index.vue'
import LoopFieldTable from './component/LoopFieldTable.vue'
import { copyText } from '@/utils/clipboard'
import { isLoopBuiltinField } from './constant'

defineOptions({ name: 'WorkflowLoopStartNode' })
const getModel = inject('getModel') as () => BaseNodeModel
Expand All @@ -40,6 +41,6 @@ const loopInputFields = computed(() => {
const list = (model.properties as { loop_input_field_list?: LoopInputField[] }).loop_input_field_list ?? []
return list
.map((item) => ({ label: item.label ?? item.field ?? '', value: item.field ?? item.variable ?? '' }))
.filter((field) => Boolean(field.value))
.filter((field) => Boolean(field.value) && !isLoopBuiltinField(field.value))
})
</script>
Loading