379 lines
9.1 KiB
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> |