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
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<template>
<el-avatar class="ai-avatar-gradient" shape="square">
<img src="@/assets/workflow/icon_ai_chat.svg" style="width: 75%" alt="" />
</el-avatar>
</template>
<script setup lang="ts"></script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<template>
<MkDialog
v-model="dialogVisible"
:title="isEdit ? '编辑参数' : '添加参数'"
width="520px"
append-to-body
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<el-form ref="fieldFormRef" label-position="top" require-asterisk-position="right" :rules="rules" :model="form">
<el-form-item label="参数" prop="field" :rules="rules.field">
<el-input v-model="form.field" :maxlength="64" placeholder="请输入参数" show-word-limit />
</el-form-item>
<el-form-item label="显示名称" prop="label" :rules="rules.label">
<el-input v-model="form.label" :maxlength="64" placeholder="请输入显示名称" show-word-limit />
</el-form-item>
<el-form-item label="参数类型" prop="parameter_type" :rules="rules.parameter_type">
<el-select :teleported="false" v-model="form.parameter_type" placeholder="请选择参数类型" style="width: 100%">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="描述" prop="desc">
<el-input v-model="form.desc" type="textarea" :rows="2" placeholder="请输入描述" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="close">取消</el-button>
<el-button type="primary" @click="submit(fieldFormRef)"> 保存 </el-button>
</span>
</template>
</MkDialog>
</template>
<script setup lang="ts">
import { reactive, ref, useTemplateRef } from 'vue'
import { cloneDeep } from 'lodash'
import type { FormInstance } from 'element-plus'

defineOptions({ name: 'ParameterExtractionFieldDialog' })

const emit = defineEmits<{ refresh: [data: Record<string, unknown>, index?: number] }>()

const options = [
{ value: 'string', label: 'string' },
{ value: 'number', label: 'number' },
{ value: 'object', label: 'object' },
{ value: 'boolean', label: 'boolean' },
{ value: 'array', label: 'array' },
]

const fieldFormRef = useTemplateRef<FormInstance>('fieldFormRef')
const dialogVisible = ref(false)
const isEdit = ref(false)
const currentIndex = ref<number | undefined>(undefined)
const form = ref<{ field: string; label: string; parameter_type: string; desc: string }>({
field: '',
label: '',
parameter_type: '',
desc: '',
})

const rules = reactive({
field: [
{ required: true, message: '请输入参数', trigger: 'blur' },
{ pattern: /^[a-zA-Z0-9_]+$/, message: '参数可由字母、数字、下划线组成', trigger: 'blur' },
],
label: [{ required: true, message: '请输入显示名称', trigger: 'blur' }],
parameter_type: [{ required: true, message: '请选择参数类型', trigger: 'change' }],
})

function resetForm() {
form.value = { field: '', label: '', parameter_type: '', desc: '' }
}

function open(row?: Record<string, unknown>, index?: number) {
resetForm()
if (row) {
form.value = cloneDeep(row as typeof form.value)
isEdit.value = true
currentIndex.value = index
}
dialogVisible.value = true
}

function close() {
dialogVisible.value = false
isEdit.value = false
currentIndex.value = undefined
resetForm()
}

const submit = async (formEl: FormInstance | null) => {
if (!formEl) return
await formEl.validate((valid) => {
if (valid) {
emit('refresh', cloneDeep(form.value), currentIndex.value)
}
})
}

defineExpose({ open, close })
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<template>
<div class="w-full">
<div class="flex w-full items-center justify-between">
<h6 class="font-medium">
提取参数
<span class="text-danger">*</span>
</h6>
<el-button link type="primary" @click="openAddDialog()">
<MkIcon name="icon_add_outlined" class="mr-1" />
添加
</el-button>
</div>

<el-table v-if="inputFieldList.length > 0" :data="inputFieldList" row-key="field" class="border">
<el-table-column prop="field" label="参数" width="100" show-overflow-tooltip>
<template #default="{ row }">
<span :title="row.field" class="ellipsis-1">{{ row.field }}</span>
</template>
</el-table-column>
<el-table-column prop="label" label="显示名称">
<template #default="{ row }">
<span :title="row.label" class="ellipsis-1">{{ row.label }}</span>
</template>
</el-table-column>
<el-table-column label="参数类型">
<template #default="{ row }">
<el-tag size="small" type="info" class="info-tag">{{ row.parameter_type }}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="90">
<template #default="{ row, $index }">
<el-button link type="primary" @click="openAddDialog(row, $index)">
<MkIcon name="icon_edit_outlined" />
</el-button>
<el-button link type="info" @click="deleteField($index)">
<MkIcon name="icon_delete-trash_outlined" />
</el-button>
</template>
</el-table-column>
</el-table>
<el-empty v-else description="暂无参数,请点击添加" :image-size="60" />

<ParametersFieldDialog ref="ParamsFieldDialogRef" @refresh="refreshFieldList" />
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { cloneDeep, set } from 'lodash'
import type { WorkflowNodeModel } from '@/workflow-canvas/core/workflow-node'

import ParametersFieldDialog from './ParametersFieldDialog.vue'

defineOptions({ name: 'WorkflowParameterExtractionFieldTable' })

const props = defineProps<{ nodeModel: WorkflowNodeModel }>()

const ParamsFieldDialogRef = ref<InstanceType<typeof ParametersFieldDialog>>()

const nodeProps = props.nodeModel.properties as unknown as {
config: Record<string, unknown>
node_data: Record<string, unknown>
}

const inputFieldList = computed<Array<Record<string, unknown>>>({
get: () => {
if (!nodeProps.node_data) {
set(nodeProps, 'node_data', {})
}
if (!Array.isArray(nodeProps.node_data.variable_list)) {
set(nodeProps.node_data, 'variable_list', [])
}
return nodeProps.node_data.variable_list as Array<Record<string, unknown>>
},
set: (value) => {
set(nodeProps.node_data, 'variable_list', value)
},
})

function syncConfig() {
const fields = [{ label: '结果', value: 'result' }, ...inputFieldList.value.map((item) => ({ label: item.label, value: item.field }))]
if (!nodeProps.config) {
set(nodeProps, 'config', {})
}
set(nodeProps.config, 'fields', fields)
props.nodeModel.clearNextNodeField(false)
}

function openAddDialog(data?: Record<string, unknown>, index?: number) {
ParamsFieldDialogRef.value?.open(data, index)
}

function deleteField(index: number) {
const list = cloneDeep(inputFieldList.value)
list.splice(index, 1)
inputFieldList.value = list
syncConfig()
}

function refreshFieldList(data: Record<string, unknown>, index?: number) {
const field = data as { field: string }
for (let i = 0; i < inputFieldList.value.length; i++) {
if ((inputFieldList.value[i] as { field: string }).field === field.field && index !== i) {
return
}
}

const list = cloneDeep(inputFieldList.value)
if (index === undefined || index === null) {
list.push(data)
} else {
list.splice(index, 1, data)
}
inputFieldList.value = list
ParamsFieldDialogRef.value?.close()
syncConfig()
}
</script>
11 changes: 11 additions & 0 deletions ui/src/workflow-canvas/nodes/parameter-extraction-node/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import ParameterExtractionNodeVue from './index.vue'
import { WorkflowNodeModel, WorkflowNodeView } from '@/workflow-canvas/core/workflow-node'
import { WorkflowNodeType } from '@/workflow-canvas/types'

class ParameterExtractionNodeView extends WorkflowNodeView {
constructor(props: ConstructorParameters<typeof WorkflowNodeView>[0]) {
super(props, ParameterExtractionNodeVue)
}
}

export default { type: WorkflowNodeType.ParameterExtractionNode, model: WorkflowNodeModel, view: ParameterExtractionNodeView }
Loading
Loading