llm-chat/frontend/src/views/SettingsView.vue

379 lines
9.1 KiB
Vue

<template>
<div class="settings-view">
<div class="settings-header">
<h1 class="settings-title">
<el-icon><Setting /></el-icon>
设置
</h1>
<p class="settings-subtitle">个性化您的聊天体验</p>
</div>
<div class="settings-content">
<el-card class="settings-card">
<template #header>
<div class="card-header">
<el-icon><Brush /></el-icon>
<span>界面设置</span>
</div>
</template>
<div class="setting-item">
<div class="setting-info">
<h4>主题模式</h4>
<p>选择浅色或深色主题</p>
</div>
<el-switch
v-model="settings.theme"
active-value="dark"
inactive-value="light"
active-text="深色"
inactive-text="浅色"
@change="handleThemeChange"
/>
</div>
<div class="setting-item">
<div class="setting-info">
<h4>字体大小</h4>
<p>调整聊天内容的字体大小</p>
</div>
<el-slider
v-model="settings.fontSize"
:min="12"
:max="20"
:step="1"
:marks="fontSizeMarks"
style="width: 200px"
@change="handleFontSizeChange"
/>
</div>
<div class="setting-item">
<div class="setting-info">
<h4>消息气泡</h4>
<p>显示或隐藏消息气泡样式</p>
</div>
<el-switch
v-model="settings.showMessageBubbles"
@change="handleBubbleChange"
/>
</div>
</el-card>
<el-card class="settings-card">
<template #header>
<div class="card-header">
<el-icon><ChatDotRound /></el-icon>
<span>聊天设置</span>
</div>
</template>
<div class="setting-item">
<div class="setting-info">
<h4>自动保存</h4>
<p>自动保存对话到历史记录</p>
</div>
<el-switch
v-model="settings.autoSave"
@change="handleAutoSaveChange"
/>
</div>
<div class="setting-item">
<div class="setting-info">
<h4>流式输出</h4>
<p>实时显示AI回复的生成过程</p>
</div>
<el-switch
v-model="settings.streamResponse"
@change="handleStreamChange"
/>
</div>
<div class="setting-item">
<div class="setting-info">
<h4>回复长度</h4>
<p>控制AI回复的最大长度</p>
</div>
<el-select
v-model="settings.maxTokens"
placeholder="选择长度"
style="width: 120px"
@change="handleMaxTokensChange"
>
<el-option label="短" :value="512" />
<el-option label="中" :value="1024" />
<el-option label="长" :value="2048" />
</el-select>
</div>
</el-card>
<el-card class="settings-card">
<template #header>
<div class="card-header">
<el-icon><Operation /></el-icon>
<span>高级设置</span>
</div>
</template>
<div class="setting-item">
<div class="setting-info">
<h4>API设置</h4>
<p>配置LLM服务连接</p>
</div>
<el-button type="primary" text @click="showApiDialog = true">
配置
</el-button>
</div>
<div class="setting-item">
<div class="setting-info">
<h4>清除缓存</h4>
<p>清除应用缓存数据</p>
</div>
<el-button type="danger" text @click="handleClearCache">
清除
</el-button>
</div>
</el-card>
</div>
<!-- API配置对话框 -->
<el-dialog
v-model="showApiDialog"
title="API配置"
width="500px"
>
<el-form :model="apiSettings" label-width="100px">
<el-form-item label="API地址">
<el-input v-model="apiSettings.baseURL" placeholder="http://localhost:3000" />
</el-form-item>
<el-form-item label="API密钥">
<el-input v-model="apiSettings.apiKey" type="password" show-password />
</el-form-item>
<el-form-item label="模型名称">
<el-input v-model="apiSettings.model" placeholder="gpt-3.5-turbo" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="showApiDialog = false">取消</el-button>
<el-button type="primary" @click="handleSaveApiSettings">保存</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Setting, Brush, ChatDotRound, Operation } from '@element-plus/icons-vue'
import { useSettingsStore } from '@/stores'
const settingsStore = useSettingsStore()
const showApiDialog = ref(false)
// 设置数据
const settings = reactive({
theme: 'light',
fontSize: 14,
showMessageBubbles: true,
autoSave: true,
streamResponse: true,
maxTokens: 1024
})
// API设置
const apiSettings = reactive({
baseURL: '',
apiKey: '',
model: ''
})
// 字体大小标记
const fontSizeMarks = {
12: '12px',
14: '14px',
16: '16px',
18: '18px',
20: '20px'
}
// 处理主题变更
const handleThemeChange = (theme) => {
settingsStore.setTheme(theme)
ElMessage.success(`已切换到${theme === 'dark' ? '深色' : '浅色'}主题`)
}
// 处理字体大小变更
const handleFontSizeChange = (size) => {
settingsStore.setFontSize(size)
ElMessage.success(`字体大小已设置为 ${size}px`)
}
// 处理消息气泡变更
const handleBubbleChange = (show) => {
settingsStore.setShowMessageBubbles(show)
ElMessage.success(show ? '已启用消息气泡' : '已禁用消息气泡')
}
// 处理自动保存变更
const handleAutoSaveChange = (autoSave) => {
settingsStore.setAutoSave(autoSave)
ElMessage.success(autoSave ? '已启用自动保存' : '已禁用自动保存')
}
// 处理流式输出变更
const handleStreamChange = (stream) => {
settingsStore.setStreamResponse(stream)
ElMessage.success(stream ? '已启用流式输出' : '已禁用流式输出')
}
// 处理最大token变更
const handleMaxTokensChange = (maxTokens) => {
settingsStore.setMaxTokens(maxTokens)
const lengthText = maxTokens === 512 ? '短' : maxTokens === 1024 ? '中' : '长'
ElMessage.success(`回复长度已设置为${lengthText}`)
}
// 保存API设置
const handleSaveApiSettings = () => {
settingsStore.setApiSettings(apiSettings)
showApiDialog.value = false
ElMessage.success('API设置已保存')
}
// 清除缓存
const handleClearCache = () => {
ElMessageBox.confirm(
'确定要清除所有缓存数据吗?这将清除所有本地存储的设置和历史记录。',
'警告',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).then(() => {
settingsStore.clearCache()
ElMessage.success('缓存已清除')
// 重新加载页面
window.location.reload()
}).catch(() => {
// 用户取消
})
}
// 初始化设置
onMounted(() => {
// 加载设置
Object.assign(settings, settingsStore.settings)
Object.assign(apiSettings, settingsStore.apiSettings)
})
</script>
<style lang="scss" scoped>
.settings-view {
padding: 20px;
max-width: 800px;
margin: 0 auto;
}
.settings-header {
text-align: center;
margin-bottom: 40px;
.settings-title {
font-size: 32px;
font-weight: 600;
color: var(--el-text-color-primary);
margin-bottom: 8px;
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
.el-icon {
font-size: 36px;
color: var(--el-color-primary);
}
}
.settings-subtitle {
font-size: 16px;
color: var(--el-text-color-secondary);
}
}
.settings-content {
display: flex;
flex-direction: column;
gap: 24px;
}
.settings-card {
.card-header {
display: flex;
align-items: center;
gap: 8px;
font-size: 16px;
font-weight: 500;
.el-icon {
font-size: 18px;
}
}
.setting-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 0;
border-bottom: 1px solid var(--el-border-color-lighter);
&:last-child {
border-bottom: none;
}
.setting-info {
h4 {
margin: 0 0 4px 0;
font-size: 14px;
font-weight: 500;
color: var(--el-text-color-primary);
}
p {
margin: 0;
font-size: 12px;
color: var(--el-text-color-secondary);
}
}
}
}
// 响应式设计
@media (max-width: 768px) {
.settings-view {
padding: 16px;
}
.settings-header {
.settings-title {
font-size: 24px;
.el-icon {
font-size: 28px;
}
}
}
.setting-item {
flex-direction: column;
align-items: flex-start;
gap: 12px;
.setting-info {
width: 100%;
}
}
}
</style>