ai-robot-core/ai-service-admin/src/components/embedding/EmbeddingConfigForm.vue

224 lines
5.4 KiB
Vue

<template>
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
:label-width="labelWidth"
v-bind="$attrs"
>
<el-form-item
v-for="(field, key) in schemaProperties"
:key="key"
:label="field.title || key"
:prop="key"
>
<template #label>
<span>{{ field.title || key }}</span>
<el-tooltip v-if="field.description" :content="field.description" placement="top">
<el-icon class="ml-1 cursor-help"><QuestionFilled /></el-icon>
</el-tooltip>
</template>
<el-input
v-if="field.type === 'string'"
v-model="formData[key]"
:placeholder="`请输入${field.title || key}`"
clearable
:show-password="isPasswordField(key)"
/>
<el-input-number
v-else-if="field.type === 'integer' || field.type === 'number'"
v-model="formData[key]"
:placeholder="`请输入${field.title || key}`"
:min="field.minimum"
:max="field.maximum"
:step="field.type === 'number' ? 0.1 : 1"
:precision="field.type === 'number' ? 2 : 0"
controls-position="right"
class="w-full"
/>
<el-switch
v-else-if="field.type === 'boolean'"
v-model="formData[key]"
/>
<el-select
v-else-if="field.enum && field.enum.length > 0"
v-model="formData[key]"
:placeholder="`请选择${field.title || key}`"
clearable
class="w-full"
>
<el-option
v-for="option in field.enum"
:key="option"
:label="option"
:value="option"
/>
</el-select>
</el-form-item>
</el-form>
</template>
<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'
import { QuestionFilled } from '@element-plus/icons-vue'
import type { FormInstance, FormRules } from 'element-plus'
interface SchemaProperty {
type: string
title?: string
description?: string
default?: any
enum?: string[]
minimum?: number
maximum?: number
required?: boolean
}
interface ConfigSchema {
type?: string
properties?: Record<string, SchemaProperty>
required?: string[]
}
const props = defineProps<{
schema: ConfigSchema
modelValue: Record<string, any>
labelWidth?: string
}>()
const emit = defineEmits<{
(e: 'update:modelValue', value: Record<string, any>): void
}>()
const formRef = ref<FormInstance>()
const formData = ref<Record<string, any>>({})
const schemaProperties = computed(() => {
return props.schema?.properties || {}
})
const requiredFields = computed(() => {
const required = props.schema?.required || []
const propsRequired = Object.entries(schemaProperties.value)
.filter(([, field]) => field.required)
.map(([key]) => key)
return [...new Set([...required, ...propsRequired])]
})
const formRules = computed<FormRules>(() => {
const rules: FormRules = {}
Object.entries(schemaProperties.value).forEach(([key, field]) => {
const fieldRules: any[] = []
if (requiredFields.value.includes(key)) {
fieldRules.push({
required: true,
message: `${field.title || key}不能为空`,
trigger: ['blur', 'change']
})
}
if (field.type === 'string' && field.minimum !== undefined) {
fieldRules.push({
min: field.minimum,
message: `${field.title || key}长度不能小于${field.minimum}`,
trigger: ['blur']
})
}
if (field.type === 'string' && field.maximum !== undefined) {
fieldRules.push({
max: field.maximum,
message: `${field.title || key}长度不能大于${field.maximum}`,
trigger: ['blur']
})
}
if (rules[key]) {
rules[key] = fieldRules
} else if (fieldRules.length > 0) {
rules[key] = fieldRules
}
})
return rules
})
const isPasswordField = (key: string): boolean => {
const lowerKey = key.toLowerCase()
return lowerKey.includes('password') || lowerKey.includes('secret') || lowerKey.includes('key') || lowerKey.includes('token')
}
const initFormData = () => {
const data: Record<string, any> = {}
Object.entries(schemaProperties.value).forEach(([key, field]) => {
if (props.modelValue && props.modelValue[key] !== undefined) {
data[key] = props.modelValue[key]
} else if (field.default !== undefined) {
data[key] = field.default
} else {
switch (field.type) {
case 'string':
data[key] = ''
break
case 'integer':
case 'number':
data[key] = field.minimum ?? 0
break
case 'boolean':
data[key] = false
break
default:
data[key] = null
}
}
})
formData.value = data
}
watch(
() => props.modelValue,
(newVal) => {
if (JSON.stringify(newVal) !== JSON.stringify(formData.value)) {
initFormData()
}
},
{ deep: true }
)
watch(
() => props.schema,
() => {
initFormData()
},
{ deep: true }
)
watch(
formData,
(val) => {
if (JSON.stringify(val) !== JSON.stringify(props.modelValue)) {
emit('update:modelValue', val)
}
},
{ deep: true }
)
onMounted(() => {
initFormData()
})
defineExpose({
validate: () => formRef.value?.validate(),
resetFields: () => formRef.value?.resetFields(),
clearValidate: () => formRef.value?.clearValidate()
})
</script>
<style scoped>
.w-full {
width: 100%;
}
.ml-1 {
margin-left: 4px;
}
.cursor-help {
cursor: help;
}
</style>