ForcePilot/web/src/components/SearchConfigTab.vue
Zhao Minhao 55f2e020b5
Add dark/light theme toggle feature (#343)
* Add dark/light theme toggle feature

* update: refine dark/light theme and related components

* 调整语义化主题变量,优化暗/亮模式切换效果

* Revert "调整语义化主题变量,优化暗/亮模式切换效果"

This reverts commit 85d9373297686fdbacb252a880b2847d20a39641.

* 深色模式适配:减少 !important,迁移 CSS 变量,优化布局

* style: 替换硬编码颜色值为CSS变量以支持主题切换

将多处硬编码的颜色值(如#fff、#f0f0f0等)替换为CSS变量(如--gray-0、--gray-150等),统一管理颜色样式,便于主题切换和样式维护。主要修改包括背景色、边框色、文字色等视觉元素,同时移除不再需要的深色模式适配代码。

* style: 使用CSS变量替换硬编码颜色值

* refactor(theme): 重构主题系统,统一使用CSS变量并优化暗色模式实现

- 移除冗余的theme.js配置文件,将主题配置集中到theme store
- 使用ant-design-vue的darkAlgorithm实现暗色模式
- 在多个组件中替换硬编码颜色值为CSS变量
- 优化用户信息组件,整合文档中心和主题切换功能
- 更新基础CSS样式,完善颜色系统和滚动条样式

* reset: 恢复被覆盖的修改(96d257a7ace38c94e2b113d56472d211d1141087)

* feat(theme): 实现深色主题支持并重构样式系统

重构颜色变量系统,添加深色主题支持
移除硬编码颜色值,统一使用CSS变量
优化图表组件以响应主题切换
清理无用样式代码,提升可维护性

* docs: 更新开发规范文档

* style: 调整边框和背景颜色样式

---------

Co-authored-by: Wenjie Zhang <xerrors@163.com>
2025-11-23 01:39:44 +08:00

246 lines
5.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="search-config-tab">
<div class="config-header">
<p class="config-title">检索配置</p>
<div class="config-actions">
<a-button size="small" @click="resetToDefaults">重置默认</a-button>
<a-button size="small" type="primary" @click="saveConfig">保存配置</a-button>
</div>
</div>
<div class="config-content">
<div v-if="loading" class="config-loading">
<a-spin size="large" />
<p>加载配置参数中...</p>
</div>
<div v-else-if="error" class="config-error">
<a-result
status="error"
title="配置加载失败"
:sub-title="error"
>
<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">
<a-col :span="12" v-for="param in queryParams" :key="param.key">
<a-form-item :label="param.label">
<a-select
v-if="param.type === 'select'"
v-model:value="meta[param.key]"
style="width: 100%;"
>
<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'"
v-model:value="meta[param.key]"
style="width: 100%;"
>
<a-select-option :value="true">启用</a-select-option>
<a-select-option :value="false">关闭</a-select-option>
</a-select>
<a-input-number
v-else-if="param.type === 'number'"
v-model:value="meta[param.key]"
style="width: 100%;"
:min="param.min || 0"
:max="param.max || 100"
/>
</a-form-item>
</a-col>
</a-row>
</a-form>
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive, computed, onMounted } from 'vue';
import { useDatabaseStore } from '@/stores/database';
import { message } from 'ant-design-vue';
import { queryApi } from '@/apis/knowledge_api';
const props = defineProps({
databaseId: {
type: String,
required: true
}
});
const store = useDatabaseStore();
// 响应式数据
const loading = ref(false);
const error = ref('');
const queryParams = ref([]);
const meta = reactive({});
// 加载查询参数
const loadQueryParams = async () => {
try {
loading.value = true;
error.value = '';
const response = await queryApi.getKnowledgeBaseQueryParams(props.databaseId);
queryParams.value = response.params?.options || [];
// 过滤掉 include_distances 配置项,默认为 True 且不可修改
queryParams.value = queryParams.value.filter(param => param.key !== 'include_distances');
// 初始化 meta 对象
queryParams.value.forEach(param => {
if (param.default !== undefined) {
meta[param.key] = param.default;
}
});
// 确保设置 include_distances 为 true即使不显示也要设置
meta['include_distances'] = true;
// 加载保存的配置
loadSavedConfig();
} catch (err) {
console.error('Failed to load query params:', err);
error.value = err.message || '加载查询参数失败';
} finally {
loading.value = false;
}
};
// 加载保存的配置
const loadSavedConfig = () => {
const saved = localStorage.getItem(`search-config-${props.databaseId}`);
if (saved) {
try {
const savedConfig = JSON.parse(saved);
Object.assign(meta, savedConfig);
} catch (e) {
console.warn('Failed to parse saved config:', e);
}
}
// 确保 include_distances 始终为 true覆盖任何保存的值
meta['include_distances'] = true;
};
// 重置为默认值
const resetToDefaults = () => {
queryParams.value.forEach(param => {
if (param.default !== undefined) {
meta[param.key] = param.default;
}
});
// 确保 include_distances 始终为 true
meta['include_distances'] = true;
message.success('已重置为默认配置');
};
// 保存配置
const saveConfig = () => {
// 确保 include_distances 始终为 true
meta['include_distances'] = true;
localStorage.setItem(`search-config-${props.databaseId}`, JSON.stringify(meta));
// 更新 store 中的配置
Object.assign(store.meta, meta);
message.success('配置已保存');
};
// 组件挂载时加载数据
onMounted(() => {
loadQueryParams();
});
</script>
<style lang="less" scoped>
.search-config-tab {
height: 100%;
display: flex;
flex-direction: column;
background: var(--gray-0);
}
.config-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 16px;
// border-bottom: 1px solid var(--gray-200);
flex-shrink: 0;
.config-title {
margin: 0;
color: var(--gray-800);
}
.config-actions {
display: flex;
gap: 8px;
}
}
.config-content {
flex: 1;
padding: 16px;
overflow-y: auto;
}
.config-loading,
.config-error {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100%;
color: var(--gray-500);
p {
margin-top: 16px;
font-size: 14px;
}
}
.config-forms {
max-width: 800px;
}
// 表单样式优化
: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);
}
}
</style>