refactor: 高级应用区分用户输入和接口传入的参数

This commit is contained in:
CaptainB 2024-10-21 11:52:53 +08:00 committed by 刘瑞斌
parent 26906df48a
commit a1484474c8
6 changed files with 135 additions and 184 deletions

View File

@ -401,7 +401,7 @@ function handleInputFieldList() {
} }
} }
default: default:
break return v
} }
}) })
: v.properties.input_field_list ? v.properties.input_field_list : v.properties.input_field_list ? v.properties.input_field_list

View File

@ -54,7 +54,7 @@ const formValue = computed({
}) })
const addOption = () => { const addOption = () => {
formValue.value.option_list.push('') formValue.value.option_list.push({ value: '' })
} }
const delOption = (index: number) => { const delOption = (index: number) => {
@ -77,4 +77,8 @@ onMounted(() => {
formValue.value.option_list = props.modelValue.option_list || [] formValue.value.option_list = props.modelValue.option_list || []
}) })
</script> </script>
<style lang="scss"></style> <style lang="scss" scoped>
:deep(.el-form-item__label) {
display: block;
}
</style>

View File

@ -5,7 +5,7 @@
<el-icon class="mr-4"> <el-icon class="mr-4">
<Plus /> <Plus />
</el-icon> </el-icon>
添加 添加参数
</el-button> </el-button>
</div> </div>
<el-table <el-table
@ -82,7 +82,7 @@ function refreshFieldList(data: any) {
// list // list
let arr = props.nodeModel.properties.user_input_field_list let arr = props.nodeModel.properties.user_input_field_list
for (let i = 0; i < arr.length; i++) { for (let i = 0; i < arr.length; i++) {
if (arr[i].variable === data.variable) { if (arr[i].field === data.variable) {
MsgError('参数已存在: ' + data.variable) MsgError('参数已存在: ' + data.variable)
return return
} }

View File

@ -7,104 +7,17 @@
:destroy-on-close="true" :destroy-on-close="true"
append-to-body append-to-body
> >
<el-form <DynamicsFormConstructor
v-model="currentItem"
label-position="top" label-position="top"
ref="fieldFormRef"
:rules="rules"
:model="form"
require-asterisk-position="right" require-asterisk-position="right"
> :input_type_list="inputTypeList"
<el-form-item label="参数" prop="variable"> ref="DynamicsFormConstructorRef"
<el-input ></DynamicsFormConstructor>
v-model="form.variable"
placeholder="请输入参数"
maxlength="64"
show-word-limit
@blur="form.variable = form.variable.trim()"
/>
</el-form-item>
<el-form-item label="显示名称" prop="name">
<el-input
v-model="form.name"
placeholder="请输入显示名称"
maxlength="64"
show-word-limit
@blur="form.name = form.name.trim()"
/>
</el-form-item>
<el-form-item label="输入类型">
<el-select v-model="form.type" @change="changeType">
<el-option label="文本框" value="input" />
<el-option label="日期" value="date" />
<el-option label="下拉选项" value="select" />
</el-select>
</el-form-item>
<el-form-item v-if="form.type === 'select'">
<template #label>
<div class="flex-between">
选项值
<el-button link type="primary" @click.stop="addOption()">
<el-icon class="mr-4"><Plus /></el-icon>
</el-button>
</div>
</template>
<div
class="w-full flex-between mb-8"
v-for="(option, $index) in form.optionList"
:key="$index"
>
<el-input v-model="form.optionList[$index]" placeholder="请输入选项值" />
<el-button link class="ml-8" @click.stop="delOption($index)">
<el-icon><Delete /></el-icon>
</el-button>
</div>
</el-form-item>
<el-form-item label="是否必填" @click.prevent>
<el-switch size="small" v-model="form.is_required"></el-switch>
</el-form-item>
<el-form-item
label="默认值"
prop="default_value"
:rules="{
required: form.is_required,
message: '请输入默认值',
trigger: 'blur'
}"
>
<el-input
v-if="form.type === 'input'"
v-model="form.default_value"
placeholder="请输入默认值"
@blur="form.name = form.name.trim()"
/>
<el-date-picker
v-else-if="form.type === 'date'"
v-model="form.default_value"
type="datetime"
placeholder="选择日期"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
/>
<el-select
v-else-if="form.type === 'select'"
v-model="form.default_value"
placeholder="请选择"
>
<el-option
v-for="(option, index) in form.optionList"
:key="index"
:label="option"
:value="option"
/>
</el-select>
</el-form-item>
</el-form>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click.prevent="dialogVisible = false"> 取消 </el-button> <el-button @click.prevent="dialogVisible = false"> 取消 </el-button>
<el-button type="primary" @click="submit(fieldFormRef)" :loading="loading"> <el-button type="primary" @click="submit()" :loading="loading">
{{ isEdit ? '保存' : '添加' }} {{ isEdit ? '保存' : '添加' }}
</el-button> </el-button>
</span> </span>
@ -112,89 +25,100 @@
</el-dialog> </el-dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, watch } from 'vue' import { ref } from 'vue'
import type { FormInstance } from 'element-plus' import { cloneDeep } from 'lodash'
import { cloneDeep, debounce } from 'lodash' import DynamicsFormConstructor from '@/components/dynamics-form/constructor/index.vue'
import { MsgError } from '@/utils/message' import type { FormField } from '@/components/dynamics-form/type'
const emit = defineEmits(['refresh']) const emit = defineEmits(['refresh'])
const fieldFormRef = ref() const DynamicsFormConstructorRef = ref()
const loading = ref<boolean>(false) const loading = ref<boolean>(false)
const isEdit = ref(false) const isEdit = ref(false)
const currentItem = ref<FormField>()
const form = ref<any>({ const currentIndex = ref(null)
name: '', const inputTypeList = ref([
variable: '', { label: '文本框', value: 'TextInputConstructor' },
type: 'input', { label: '单选框', value: 'SingleSelectConstructor' },
is_required: true, { label: '日期', value: 'DatePickerConstructor' }
assignment_method: 'user_input', ])
optionList: [''],
default_value: ''
})
const rules = reactive({
name: [{ required: true, message: '请输入显示名称', trigger: 'blur' }],
variable: [
{ required: true, message: '请输入参数', trigger: 'blur' },
{ pattern: /^[a-zA-Z0-9_]+$/, message: '只能输入字母数字和下划线', trigger: 'blur' }
]
})
const dialogVisible = ref<boolean>(false) const dialogVisible = ref<boolean>(false)
watch(dialogVisible, (bool) => {
if (!bool) {
form.value = {
name: '',
variable: '',
type: 'input',
is_required: true,
assignment_method: 'user_input',
optionList: [''],
default_value: ''
}
isEdit.value = false
}
})
const open = (row: any) => {
if (row) {
form.value = cloneDeep(row)
isEdit.value = true
}
const open = (row: any, index: any) => {
dialogVisible.value = true dialogVisible.value = true
if (row) {
isEdit.value = true
currentItem.value = cloneDeep(row)
currentIndex.value = index
// 线
if (row.input_type) {
return
}
//
switch (row.type) {
case 'input':
currentItem.value = {
field: row.field || row.variable,
input_type: 'TextInput',
label: row.label || row.name,
default_value: row.default_value,
required: row.required || row.is_required
}
break
case 'select':
currentItem.value = {
field: row.field || row.variable,
input_type: 'SingleSelect',
label: row.label || row.name,
default_value: row.default_value,
required: row.required || row.is_required,
option_list: row.optionList.map((o: any) => {
return { key: o, value: o }
})
}
break
case 'date':
currentItem.value = {
field: row.field || row.variable,
input_type: 'DatePicker',
label: row.label || row.name,
default_value: row.default_value,
required: row.required || row.is_required,
attrs: {
format: 'YYYY-MM-DD HH:mm:ss',
'value-format': 'YYYY-MM-DD HH:mm:ss',
type: 'datetime'
}
}
break
default:
break
}
}
} }
const close = () => { const close = () => {
dialogVisible.value = false dialogVisible.value = false
isEdit.value = false
currentIndex.value = null
currentItem.value = null as any
} }
const submit = async (formEl: FormInstance | undefined) => { const submit = async () => {
const formEl = DynamicsFormConstructorRef.value
if (!formEl) return if (!formEl) return
if (form.value.type === 'select' && form.value.optionList.length === 0) { await formEl.validate().then(() => {
return MsgError('请添加选项值') emit('refresh', formEl?.getData(), currentIndex.value)
} isEdit.value = false
await formEl.validate((valid) => { currentItem.value = null as any
if (valid) { currentIndex.value = null
emit('refresh', form.value)
}
}) })
} }
const addOption = () => {
form.value.optionList.push('')
}
const delOption = (index: number) => {
form.value.optionList.splice(index, 1)
}
const changeType = () => {
form.value.optionList = ['']
form.value.default_value = ''
}
defineExpose({ open, close }) defineExpose({ open, close })
</script> </script>

View File

@ -5,7 +5,7 @@
<el-icon class="mr-4"> <el-icon class="mr-4">
<Plus /> <Plus />
</el-icon> </el-icon>
添加 添加参数
</el-button> </el-button>
</div> </div>
<el-table <el-table
@ -13,20 +13,27 @@
:data="props.nodeModel.properties.user_input_field_list" :data="props.nodeModel.properties.user_input_field_list"
class="mb-16" class="mb-16"
> >
<el-table-column prop="variable" label="参数" /> <el-table-column prop="label" label="显示名称">
<el-table-column prop="name" label="显示名称" />
<el-table-column label="输入类型">
<template #default="{ row }"> <template #default="{ row }">
<el-tag type="info" class="info-tag" v-if="row.type === 'input'">文本框</el-tag> <span v-if="row.label && row.label.input_type === 'TooltipLabel'">{{ row.label.label }}</span>
<el-tag type="info" class="info-tag" v-if="row.type === 'date'">日期</el-tag> <span v-else>{{ row.label }}</span>
<el-tag type="info" class="info-tag" v-if="row.type === 'select'">下拉选项</el-tag> </template>
</el-table-column>
<el-table-column prop="field" label="参数" />
<el-table-column label="组件类型">
<template #default="{ row }">
<el-tag type="info" class="info-tag" v-if="row.input_type === 'TextInput'">文本框</el-tag>
<el-tag type="info" class="info-tag" v-if="row.input_type === 'Slider'">滑块</el-tag>
<el-tag type="info" class="info-tag" v-if="row.input_type === 'SwitchInput'">开关</el-tag>
<el-tag type="info" class="info-tag" v-if="row.input_type === 'SingleSelect'">单选框</el-tag>
<el-tag type="info" class="info-tag" v-if="row.input_type === 'DatePicker'">日期</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="default_value" label="默认值" /> <el-table-column prop="default_value" label="默认值" />
<el-table-column label="必填"> <el-table-column label="必填">
<template #default="{ row }"> <template #default="{ row }">
<div @click.stop> <div @click.stop>
<el-switch disabled size="small" v-model="row.is_required" /> <el-switch disabled size="small" v-model="row.required" />
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
@ -63,15 +70,11 @@ import { MsgError } from '@/utils/message'
const props = defineProps<{ nodeModel: any }>() const props = defineProps<{ nodeModel: any }>()
const currentIndex = ref(null)
const UserFieldFormDialogRef = ref() const UserFieldFormDialogRef = ref()
const inputFieldList = ref<any[]>([]) const inputFieldList = ref<any[]>([])
function openAddDialog(data?: any, index?: any) { function openAddDialog(data?: any, index?: any) {
if (typeof index !== 'undefined') { UserFieldFormDialogRef.value.open(data, index)
currentIndex.value = index
}
UserFieldFormDialogRef.value.open(data)
} }
function deleteField(index: any) { function deleteField(index: any) {
@ -80,27 +83,26 @@ function deleteField(index: any) {
} }
function refreshFieldList(data: any) { function refreshFieldList(data: any, index: any) {
for (let i = 0; i < inputFieldList.value.length; i++) { for (let i = 0; i < inputFieldList.value.length; i++) {
if (inputFieldList.value[i].variable === data.variable && currentIndex.value !== i) { if (inputFieldList.value[i].field === data.field && index !== i) {
MsgError('参数已存在: ' + data.variable) MsgError('参数已存在: ' + data.field)
return return
} }
} }
// list // list
let arr = props.nodeModel.properties.api_input_field_list let arr = props.nodeModel.properties.api_input_field_list
for (let i = 0; i < arr.length; i++) { for (let i = 0; i < arr.length; i++) {
if (arr[i].variable === data.variable) { if (arr[i].variable === data.field) {
MsgError('参数已存在: ' + data.variable) MsgError('参数已存在: ' + data.field)
return return
} }
} }
if (currentIndex.value !== null) { if (index !== null) {
inputFieldList.value.splice(currentIndex.value, 1, data) inputFieldList.value.splice(index, 1, data)
} else { } else {
inputFieldList.value.push(data) inputFieldList.value.push(data)
} }
currentIndex.value = null
UserFieldFormDialogRef.value.close() UserFieldFormDialogRef.value.close()
props.nodeModel.graphModel.eventCenter.emit('refreshFieldList') props.nodeModel.graphModel.eventCenter.emit('refreshFieldList')
} }
@ -119,6 +121,23 @@ onMounted(() => {
} else { } else {
inputFieldList.value.push(...props.nodeModel.properties.user_input_field_list) inputFieldList.value.push(...props.nodeModel.properties.user_input_field_list)
} }
//
inputFieldList.value.forEach((item, index) => {
item.label = item.label || item.name
item.field = item.field || item.variable
item.required = item.required || item.is_required
switch (item.type) {
case 'input':
item.input_type = 'TextInput'
break
case 'select':
item.input_type = 'SingleSelect'
break
case 'date':
item.input_type = 'DatePicker'
break
}
})
set(props.nodeModel.properties, 'user_input_field_list', inputFieldList) set(props.nodeModel.properties, 'user_input_field_list', inputFieldList)
}) })

View File

@ -35,14 +35,18 @@ const globalFields = [
{ label: '历史聊天记录', value: 'history_context' }, { label: '历史聊天记录', value: 'history_context' },
{ label: '对话id', value: 'chat_id' } { label: '对话id', value: 'chat_id' }
] ]
const inputFieldList = ref<any[]>([])
const getRefreshFieldList = () => { const getRefreshFieldList = () => {
const user_input_fields = props.nodeModel.graphModel.nodes const user_input_fields = props.nodeModel.graphModel.nodes
.filter((v: any) => v.id === 'base-node') .filter((v: any) => v.id === 'base-node')
.map((v: any) => cloneDeep(v.properties.user_input_field_list)) .map((v: any) => cloneDeep(v.properties.user_input_field_list))
.reduce((x: any, y: any) => [...x, ...y], []) .reduce((x: any, y: any) => [...x, ...y], [])
.map((i: any) => ({ label: i.name, value: i.variable })) .map((i: any) => {
if (i.label && i.label.input_type === 'TooltipLabel') {
return { label: i.label.label, value: i.field || i.variable }
}
return { label: i.label || i.name, value: i.field || i.variable }
})
const api_input_fields = props.nodeModel.graphModel.nodes const api_input_fields = props.nodeModel.graphModel.nodes
.filter((v: any) => v.id === 'base-node') .filter((v: any) => v.id === 'base-node')
.map((v: any) => cloneDeep(v.properties.api_input_field_list)) .map((v: any) => cloneDeep(v.properties.api_input_field_list))