2025-11-06 19:47:22 +08:00
|
|
|
|
<template>
|
2025-12-09 22:11:27 +08:00
|
|
|
|
<a-modal
|
|
|
|
|
|
:open="props.modelValue"
|
|
|
|
|
|
title="检索配置"
|
|
|
|
|
|
width="800px"
|
|
|
|
|
|
:confirm-loading="loading"
|
|
|
|
|
|
@ok="handleSave"
|
|
|
|
|
|
@cancel="handleCancel"
|
|
|
|
|
|
ok-text="保存"
|
|
|
|
|
|
cancel-text="取消"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="search-config-modal">
|
2025-11-06 19:47:22 +08:00
|
|
|
|
<div v-if="loading" class="config-loading">
|
|
|
|
|
|
<a-spin size="large" />
|
|
|
|
|
|
<p>加载配置参数中...</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div v-else-if="error" class="config-error">
|
2026-01-15 06:01:34 +08:00
|
|
|
|
<a-result status="error" title="配置加载失败" :sub-title="error">
|
2025-11-06 19:47:22 +08:00
|
|
|
|
<template #extra>
|
|
|
|
|
|
<a-button type="primary" @click="loadQueryParams">重新加载</a-button>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</a-result>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div v-else class="config-forms">
|
|
|
|
|
|
<a-form layout="vertical">
|
|
|
|
|
|
<a-row :gutter="16">
|
2026-05-17 18:06:39 +08:00
|
|
|
|
<a-col :span="12" v-for="param in visibleQueryParams" :key="param.key">
|
2025-11-06 19:47:22 +08:00
|
|
|
|
<a-form-item :label="param.label">
|
2026-01-27 17:07:18 +08:00
|
|
|
|
<template #extra v-if="param.description">
|
|
|
|
|
|
<div class="param-description">{{ param.description }}</div>
|
|
|
|
|
|
</template>
|
2025-11-06 19:47:22 +08:00
|
|
|
|
<a-select
|
|
|
|
|
|
v-if="param.type === 'select'"
|
|
|
|
|
|
v-model:value="meta[param.key]"
|
2026-01-15 06:01:34 +08:00
|
|
|
|
style="width: 100%"
|
2025-11-06 19:47:22 +08:00
|
|
|
|
>
|
|
|
|
|
|
<a-select-option
|
|
|
|
|
|
v-for="option in param.options"
|
|
|
|
|
|
:key="option.value"
|
|
|
|
|
|
:value="option.value"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ option.label }}
|
|
|
|
|
|
</a-select-option>
|
|
|
|
|
|
</a-select>
|
|
|
|
|
|
<a-select
|
|
|
|
|
|
v-else-if="param.type === 'boolean'"
|
2025-12-09 16:21:18 +08:00
|
|
|
|
:value="computedMeta[param.key]"
|
|
|
|
|
|
@update:value="(value) => updateMeta(param.key, value)"
|
2026-01-15 06:01:34 +08:00
|
|
|
|
style="width: 100%"
|
2025-11-06 19:47:22 +08:00
|
|
|
|
>
|
2025-12-09 16:21:18 +08:00
|
|
|
|
<a-select-option value="true">启用</a-select-option>
|
|
|
|
|
|
<a-select-option value="false">关闭</a-select-option>
|
2025-11-06 19:47:22 +08:00
|
|
|
|
</a-select>
|
|
|
|
|
|
<a-input-number
|
|
|
|
|
|
v-else-if="param.type === 'number'"
|
|
|
|
|
|
v-model:value="meta[param.key]"
|
2026-01-15 06:01:34 +08:00
|
|
|
|
style="width: 100%"
|
2025-11-06 19:47:22 +08:00
|
|
|
|
:min="param.min || 0"
|
|
|
|
|
|
:max="param.max || 100"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
</a-col>
|
|
|
|
|
|
</a-row>
|
|
|
|
|
|
</a-form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-12-09 22:11:27 +08:00
|
|
|
|
</a-modal>
|
2025-11-06 19:47:22 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
2026-01-15 06:01:34 +08:00
|
|
|
|
import { ref, reactive, computed, watch } from 'vue'
|
|
|
|
|
|
import { useDatabaseStore } from '@/stores/database'
|
|
|
|
|
|
import { message } from 'ant-design-vue'
|
|
|
|
|
|
import { queryApi } from '@/apis/knowledge_api'
|
2025-11-06 19:47:22 +08:00
|
|
|
|
|
|
|
|
|
|
const props = defineProps({
|
2025-12-09 22:11:27 +08:00
|
|
|
|
modelValue: {
|
|
|
|
|
|
type: Boolean,
|
|
|
|
|
|
default: false
|
|
|
|
|
|
},
|
2025-11-06 19:47:22 +08:00
|
|
|
|
databaseId: {
|
|
|
|
|
|
type: String,
|
2025-12-10 19:42:58 +08:00
|
|
|
|
default: ''
|
2025-11-06 19:47:22 +08:00
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
})
|
2025-11-06 19:47:22 +08:00
|
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const emit = defineEmits(['update:modelValue', 'save'])
|
2025-12-09 22:11:27 +08:00
|
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const store = useDatabaseStore()
|
2025-11-06 19:47:22 +08:00
|
|
|
|
|
|
|
|
|
|
// 响应式数据
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const loading = ref(false)
|
|
|
|
|
|
const error = ref('')
|
|
|
|
|
|
const queryParams = ref([])
|
|
|
|
|
|
const meta = reactive({})
|
2025-11-06 19:47:22 +08:00
|
|
|
|
|
2026-05-17 18:06:39 +08:00
|
|
|
|
const isDependencySatisfied = (param) => {
|
|
|
|
|
|
const dependency = param.depend_on
|
|
|
|
|
|
if (!dependency || dependency.length < 2) return true
|
|
|
|
|
|
const [key, expectedValue] = dependency
|
|
|
|
|
|
return meta[key] === expectedValue
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const visibleQueryParams = computed(() => queryParams.value.filter(isDependencySatisfied))
|
|
|
|
|
|
|
2025-12-09 16:21:18 +08:00
|
|
|
|
// 计算属性:处理布尔类型的双向绑定
|
|
|
|
|
|
const computedMeta = computed(() => {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const result = {}
|
2025-12-09 16:21:18 +08:00
|
|
|
|
for (const key in meta) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const param = queryParams.value.find((p) => p.key === key)
|
2025-12-09 16:21:18 +08:00
|
|
|
|
if (param?.type === 'boolean') {
|
|
|
|
|
|
// 对于布尔类型,返回字符串给 select,但保持内部为布尔值
|
2026-01-15 06:01:34 +08:00
|
|
|
|
result[key] = meta[key].toString()
|
2025-12-09 16:21:18 +08:00
|
|
|
|
} else {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
result[key] = meta[key]
|
2025-12-09 16:21:18 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
return result
|
|
|
|
|
|
})
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
// 处理值更新
|
|
|
|
|
|
const updateMeta = (key, value) => {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const param = queryParams.value.find((p) => p.key === key)
|
2025-12-09 16:21:18 +08:00
|
|
|
|
if (param?.type === 'boolean') {
|
|
|
|
|
|
// 将字符串转换回布尔值
|
2026-01-15 06:01:34 +08:00
|
|
|
|
meta[key] = value === 'true'
|
2025-12-09 16:21:18 +08:00
|
|
|
|
} else {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
meta[key] = value
|
2025-12-09 16:21:18 +08:00
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
}
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
2025-11-06 19:47:22 +08:00
|
|
|
|
// 加载查询参数
|
|
|
|
|
|
const loadQueryParams = async () => {
|
|
|
|
|
|
try {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
loading.value = true
|
|
|
|
|
|
error.value = ''
|
2025-11-06 19:47:22 +08:00
|
|
|
|
|
2025-12-10 19:42:58 +08:00
|
|
|
|
// 如果没有 databaseId,不执行请求
|
|
|
|
|
|
if (!props.databaseId) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
queryParams.value = []
|
|
|
|
|
|
loading.value = false
|
|
|
|
|
|
return
|
2025-12-10 19:42:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const response = await queryApi.getKnowledgeBaseQueryParams(props.databaseId)
|
|
|
|
|
|
queryParams.value = response.params?.options || []
|
2025-11-06 19:47:22 +08:00
|
|
|
|
|
|
|
|
|
|
// 过滤掉 include_distances 配置项,默认为 True 且不可修改
|
2026-01-15 06:01:34 +08:00
|
|
|
|
queryParams.value = queryParams.value.filter((param) => param.key !== 'include_distances')
|
2025-11-06 19:47:22 +08:00
|
|
|
|
|
|
|
|
|
|
// 初始化 meta 对象
|
2026-01-15 06:01:34 +08:00
|
|
|
|
queryParams.value.forEach((param) => {
|
2025-11-06 19:47:22 +08:00
|
|
|
|
if (param.default !== undefined) {
|
2025-12-09 16:21:18 +08:00
|
|
|
|
// 对于布尔类型,确保使用布尔值而不是字符串
|
|
|
|
|
|
if (param.type === 'boolean') {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
meta[param.key] = Boolean(param.default)
|
2025-12-09 16:21:18 +08:00
|
|
|
|
} else {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
meta[param.key] = param.default
|
2025-12-09 16:21:18 +08:00
|
|
|
|
}
|
2025-11-06 19:47:22 +08:00
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
})
|
2025-11-06 19:47:22 +08:00
|
|
|
|
|
|
|
|
|
|
// 确保设置 include_distances 为 true(即使不显示也要设置)
|
2026-01-15 06:01:34 +08:00
|
|
|
|
meta['include_distances'] = true
|
2025-11-06 19:47:22 +08:00
|
|
|
|
|
|
|
|
|
|
// 加载保存的配置
|
2026-01-15 06:01:34 +08:00
|
|
|
|
loadSavedConfig()
|
2025-11-06 19:47:22 +08:00
|
|
|
|
} catch (err) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
console.error('Failed to load query params:', err)
|
|
|
|
|
|
error.value = err.message || '加载查询参数失败'
|
2025-11-06 19:47:22 +08:00
|
|
|
|
} finally {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
loading.value = false
|
2025-11-06 19:47:22 +08:00
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
}
|
2025-11-06 19:47:22 +08:00
|
|
|
|
|
|
|
|
|
|
// 加载保存的配置
|
|
|
|
|
|
const loadSavedConfig = () => {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
if (!props.databaseId) return
|
2025-12-10 19:42:58 +08:00
|
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const saved = localStorage.getItem(`search-config-${props.databaseId}`)
|
2025-11-06 19:47:22 +08:00
|
|
|
|
if (saved) {
|
|
|
|
|
|
try {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const savedConfig = JSON.parse(saved)
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
// 处理布尔类型转换
|
2026-01-15 06:01:34 +08:00
|
|
|
|
queryParams.value.forEach((param) => {
|
2025-12-09 16:21:18 +08:00
|
|
|
|
if (param.type === 'boolean' && savedConfig[param.key] !== undefined) {
|
|
|
|
|
|
// 将字符串值转换为布尔值
|
|
|
|
|
|
if (typeof savedConfig[param.key] === 'string') {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
savedConfig[param.key] = savedConfig[param.key] === 'true'
|
2025-12-09 16:21:18 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
})
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
|
Object.assign(meta, savedConfig)
|
2025-11-06 19:47:22 +08:00
|
|
|
|
} catch (e) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
console.warn('Failed to parse saved config:', e)
|
2025-11-06 19:47:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 确保 include_distances 始终为 true,覆盖任何保存的值
|
2026-01-15 06:01:34 +08:00
|
|
|
|
meta['include_distances'] = true
|
|
|
|
|
|
}
|
2025-11-06 19:47:22 +08:00
|
|
|
|
|
|
|
|
|
|
// 重置为默认值
|
|
|
|
|
|
const resetToDefaults = () => {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
queryParams.value.forEach((param) => {
|
2025-11-06 19:47:22 +08:00
|
|
|
|
if (param.default !== undefined) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
meta[param.key] = param.default
|
2025-11-06 19:47:22 +08:00
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
})
|
2025-11-06 19:47:22 +08:00
|
|
|
|
// 确保 include_distances 始终为 true
|
2026-01-15 06:01:34 +08:00
|
|
|
|
meta['include_distances'] = true
|
|
|
|
|
|
message.success('已重置为默认配置')
|
|
|
|
|
|
}
|
2025-11-06 19:47:22 +08:00
|
|
|
|
|
2026-03-26 13:53:35 +08:00
|
|
|
|
defineExpose({ resetToDefaults })
|
|
|
|
|
|
|
2025-11-06 19:47:22 +08:00
|
|
|
|
// 保存配置
|
2025-12-09 22:11:27 +08:00
|
|
|
|
const handleSave = async () => {
|
2025-12-10 19:42:58 +08:00
|
|
|
|
// 如果没有 databaseId,不执行保存
|
|
|
|
|
|
if (!props.databaseId) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
message.error('无法保存配置:缺少知识库ID')
|
|
|
|
|
|
return
|
2025-12-10 19:42:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-06 19:47:22 +08:00
|
|
|
|
// 确保 include_distances 始终为 true
|
2026-01-15 06:01:34 +08:00
|
|
|
|
meta['include_distances'] = true
|
2025-11-06 19:47:22 +08:00
|
|
|
|
|
2025-12-09 21:11:51 +08:00
|
|
|
|
// 先保存到知识库元数据
|
2025-12-09 16:21:18 +08:00
|
|
|
|
try {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const response = await queryApi.updateKnowledgeBaseQueryParams(props.databaseId, meta)
|
2025-12-09 16:21:18 +08:00
|
|
|
|
if (response.message === 'success') {
|
2025-12-09 21:11:51 +08:00
|
|
|
|
// 服务器保存成功后,再保存到 localStorage(兼容性)
|
2026-01-15 06:01:34 +08:00
|
|
|
|
localStorage.setItem(`search-config-${props.databaseId}`, JSON.stringify(meta))
|
|
|
|
|
|
message.success('配置已保存')
|
2025-12-09 22:11:27 +08:00
|
|
|
|
|
|
|
|
|
|
// 更新 store 中的配置
|
2026-01-15 06:01:34 +08:00
|
|
|
|
Object.assign(store.meta, meta)
|
2025-12-09 22:11:27 +08:00
|
|
|
|
|
|
|
|
|
|
// 触发保存事件
|
2026-01-15 06:01:34 +08:00
|
|
|
|
emit('save', { ...meta })
|
|
|
|
|
|
emit('update:modelValue', false)
|
2025-12-09 16:21:18 +08:00
|
|
|
|
} else {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
throw new Error(response.message || '保存失败')
|
2025-12-09 16:21:18 +08:00
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
console.error('保存配置到知识库失败:', error)
|
|
|
|
|
|
message.error('保存配置失败:' + error.message)
|
2025-12-09 16:21:18 +08:00
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
}
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
2025-12-09 22:11:27 +08:00
|
|
|
|
// 处理取消
|
|
|
|
|
|
const handleCancel = () => {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
emit('update:modelValue', false)
|
|
|
|
|
|
}
|
2025-11-06 19:47:22 +08:00
|
|
|
|
|
2025-12-09 22:11:27 +08:00
|
|
|
|
// 监听弹窗显示状态,显示时加载数据
|
2026-01-15 06:01:34 +08:00
|
|
|
|
watch(
|
|
|
|
|
|
() => props.modelValue,
|
|
|
|
|
|
(newVal) => {
|
|
|
|
|
|
if (newVal && props.databaseId) {
|
|
|
|
|
|
loadQueryParams()
|
|
|
|
|
|
}
|
2025-12-09 22:11:27 +08:00
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
)
|
2025-11-06 19:47:22 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="less" scoped>
|
|
|
|
|
|
.config-loading,
|
|
|
|
|
|
.config-error {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
2025-12-09 22:11:27 +08:00
|
|
|
|
height: 300px;
|
2025-11-06 19:47:22 +08:00
|
|
|
|
color: var(--gray-500);
|
|
|
|
|
|
|
|
|
|
|
|
p {
|
|
|
|
|
|
margin-top: 16px;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.config-forms {
|
2025-12-09 22:11:27 +08:00
|
|
|
|
max-width: 100%;
|
2025-11-06 19:47:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-27 17:07:18 +08:00
|
|
|
|
.param-description {
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: var(--gray-500);
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
margin-top: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-06 19:47:22 +08:00
|
|
|
|
// 表单样式优化
|
|
|
|
|
|
:deep(.ant-form-item) {
|
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.ant-form-item-label > label) {
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
color: var(--gray-700);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.ant-input),
|
|
|
|
|
|
:deep(.ant-select-selector) {
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.ant-switch) {
|
|
|
|
|
|
background-color: var(--gray-300);
|
|
|
|
|
|
|
|
|
|
|
|
&.ant-switch-checked {
|
|
|
|
|
|
background-color: var(--main-color);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
</style>
|