Files
X-Financial/web/src/views/LlmSettingsPanel.vue
caoxiaozhu 2dcc72102d style: 全局 UI 主题皮肤重构与样式模块化
引入 Element Plus 主题定制和主题皮肤 composable,将全局
样式拆分为组件级独立 CSS 文件(侧边栏、顶栏、工作台等),
统一色彩变量和间距规范,重构所有视图和组件样式以适配新
主题系统,优化图表和知识图谱组件视觉表现,提取审计和差
旅报销相关子组件。
2026-05-27 09:17:57 +08:00

321 lines
12 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="model-grid">
<!-- 主模型配置 -->
<section class="settings-card">
<div class="card-head">
<div class="card-title-with-icon">
<div class="model-icon-box purple">
<i class="mdi mdi-brain"></i>
</div>
<div>
<h4>主模型配置</h4>
<p>用于 AI 助手和主业务排队调度的默认模型接入</p>
</div>
</div>
<div class="card-head-actions">
<button
class="test-button"
type="button"
:disabled="isModelTesting('main')"
@click="testModelConnection('main')"
>
<i :class="isModelTesting('main') ? 'mdi mdi-loading mdi-spin' : 'mdi mdi-connection'"></i>
<span>{{ isModelTesting('main') ? '测试中...' : '测试模型' }}</span>
</button>
</div>
</div>
<div class="form-grid">
<label class="field">
<span><em>*</em> 供应商</span>
<EnterpriseSelect
v-model="llmForm.mainProvider"
:options="providerOptions"
placeholder="选择供应商"
@change="applyProviderPreset('main')"
/>
</label>
<label class="field">
<span><em>*</em> 模型名称</span>
<input v-model="llmForm.mainModel" type="text" placeholder="请输入主模型名称" />
</label>
<label class="field field-full">
<span><em>*</em> 接口地址</span>
<input v-model="llmForm.mainEndpoint" type="text" placeholder="请输入模型接口地址" />
</label>
<label class="field field-full">
<span>API Key</span>
<input
v-model="llmForm.mainApiKey"
type="password"
autocomplete="off"
@focus="clearModelSecretMask('main')"
:placeholder="llmForm.mainApiKeyConfigured ? '已配置,如需修改请重新输入' : '保存后不会保留在草稿中'"
/>
<small v-if="llmForm.mainApiKeyConfigured" class="secret-bound-state">
<i class="mdi mdi-database-lock"></i>
<span>已从数据库加密加载测试会使用已保存密钥</span>
</small>
</label>
</div>
<div v-if="getModelTestState('main').message" class="test-feedback" :class="`is-${getModelTestState('main').status}`">
<i
:class="
getModelTestState('main').status === 'success'
? 'mdi mdi-check-circle'
: getModelTestState('main').status === 'testing'
? 'mdi mdi-loading mdi-spin'
: 'mdi mdi-alert-circle'
"
></i>
<span>{{ getModelTestState('main').message }}</span>
</div>
</section>
<!-- 备份模型配置 -->
<section class="settings-card">
<div class="card-head">
<div class="card-title-with-icon">
<div class="model-icon-box orange">
<i class="mdi mdi-lifebuoy"></i>
</div>
<div>
<h4>备份模型配置</h4>
<p>主模型不可用或限频时用于兜底切换的备用模型接入</p>
</div>
</div>
<div class="card-head-actions">
<button
class="test-button"
type="button"
:disabled="isModelTesting('backup')"
@click="testModelConnection('backup')"
>
<i :class="isModelTesting('backup') ? 'mdi mdi-loading mdi-spin' : 'mdi mdi-connection'"></i>
<span>{{ isModelTesting('backup') ? '测试中...' : '测试模型' }}</span>
</button>
</div>
</div>
<div class="form-grid">
<label class="field">
<span><em>*</em> 供应商</span>
<EnterpriseSelect
v-model="llmForm.backupProvider"
:options="providerOptions"
placeholder="选择供应商"
@change="applyProviderPreset('backup')"
/>
</label>
<label class="field">
<span><em>*</em> 模型名称</span>
<input v-model="llmForm.backupModel" type="text" placeholder="请输入备份模型名称" />
</label>
<label class="field field-full">
<span><em>*</em> 接口地址</span>
<input v-model="llmForm.backupEndpoint" type="text" placeholder="请输入模型接口地址" />
</label>
<label class="field field-full">
<span>API Key</span>
<input
v-model="llmForm.backupApiKey"
type="password"
autocomplete="off"
@focus="clearModelSecretMask('backup')"
:placeholder="llmForm.backupApiKeyConfigured ? '已配置,如需修改请重新输入' : '保存后不会保留在草稿中'"
/>
<small v-if="llmForm.backupApiKeyConfigured" class="secret-bound-state">
<i class="mdi mdi-database-lock"></i>
<span>已从数据库加密加载测试会使用已保存密钥</span>
</small>
</label>
</div>
<div v-if="getModelTestState('backup').message" class="test-feedback" :class="`is-${getModelTestState('backup').status}`">
<i
:class="
getModelTestState('backup').status === 'success'
? 'mdi mdi-check-circle'
: getModelTestState('backup').status === 'testing'
? 'mdi mdi-loading mdi-spin'
: 'mdi mdi-alert-circle'
"
></i>
<span>{{ getModelTestState('backup').message }}</span>
</div>
</section>
<!-- Embedding 模型配置 -->
<section class="settings-card">
<div class="card-head">
<div class="card-title-with-icon">
<div class="model-icon-box cyan">
<i class="mdi mdi-vector-combine"></i>
</div>
<div>
<h4>Embedding 模型配置</h4>
<p>用于向量检索知识库召回和语义匹配的嵌入模型设置</p>
</div>
</div>
<div class="card-head-actions">
<button
class="test-button"
type="button"
:disabled="isModelTesting('embedding')"
@click="testModelConnection('embedding')"
>
<i :class="isModelTesting('embedding') ? 'mdi mdi-loading mdi-spin' : 'mdi mdi-connection'"></i>
<span>{{ isModelTesting('embedding') ? '测试中...' : '测试模型' }}</span>
</button>
</div>
</div>
<div class="form-grid">
<label class="field">
<span><em>*</em> 供应商</span>
<EnterpriseSelect
v-model="llmForm.embeddingProvider"
:options="providerOptions"
placeholder="选择供应商"
@change="applyProviderPreset('embedding')"
/>
</label>
<label class="field">
<span><em>*</em> 模型名称</span>
<input v-model="llmForm.embeddingModel" type="text" placeholder="请输入 Embedding 模型名称" />
</label>
<label class="field field-full">
<span><em>*</em> 接口地址</span>
<input v-model="llmForm.embeddingEndpoint" type="text" placeholder="请输入模型接口地址" />
</label>
<label class="field field-full">
<span>API Key</span>
<input
v-model="llmForm.embeddingApiKey"
type="password"
autocomplete="off"
@focus="clearModelSecretMask('embedding')"
:placeholder="llmForm.embeddingApiKeyConfigured ? '已配置,如需修改请重新输入' : '保存后不会保留在草稿中'"
/>
<small v-if="llmForm.embeddingApiKeyConfigured" class="secret-bound-state">
<i class="mdi mdi-database-lock"></i>
<span>已从数据库加密加载测试会使用已保存密钥</span>
</small>
</label>
</div>
<div
v-if="getModelTestState('embedding').message"
class="test-feedback"
:class="`is-${getModelTestState('embedding').status}`"
>
<i
:class="
getModelTestState('embedding').status === 'success'
? 'mdi mdi-check-circle'
: getModelTestState('embedding').status === 'testing'
? 'mdi mdi-loading mdi-spin'
: 'mdi mdi-alert-circle'
"
></i>
<span>{{ getModelTestState('embedding').message }}</span>
</div>
</section>
<!-- Reranker 模型配置 -->
<section class="settings-card">
<div class="card-head">
<div class="card-title-with-icon">
<div class="model-icon-box teal">
<i class="mdi mdi-filter-variant"></i>
</div>
<div>
<h4>Reranker 模型配置</h4>
<p>用于检索结果重排和语义精排的 Reranker 模型设置</p>
</div>
</div>
<div class="card-head-actions">
<button
class="test-button"
type="button"
:disabled="isModelTesting('reranker')"
@click="testModelConnection('reranker')"
>
<i :class="isModelTesting('reranker') ? 'mdi mdi-loading mdi-spin' : 'mdi mdi-connection'"></i>
<span>{{ isModelTesting('reranker') ? '测试中...' : '测试模型' }}</span>
</button>
</div>
</div>
<div class="form-grid">
<label class="field">
<span><em>*</em> 供应商</span>
<EnterpriseSelect
v-model="llmForm.rerankerProvider"
:options="providerOptions"
placeholder="选择供应商"
@change="applyProviderPreset('reranker')"
/>
</label>
<label class="field">
<span><em>*</em> 模型名称</span>
<input v-model="llmForm.rerankerModel" type="text" placeholder="请输入 Reranker 模型名称" />
</label>
<label class="field field-full">
<span><em>*</em> 接口地址</span>
<input v-model="llmForm.rerankerEndpoint" type="text" placeholder="请输入模型接口地址" />
</label>
<label class="field field-full">
<span>API Key</span>
<input
v-model="llmForm.rerankerApiKey"
type="password"
autocomplete="off"
@focus="clearModelSecretMask('reranker')"
:placeholder="llmForm.rerankerApiKeyConfigured ? '已配置,如需修改请重新输入' : '保存后不会保留在草稿中'"
/>
<small v-if="llmForm.rerankerApiKeyConfigured" class="secret-bound-state">
<i class="mdi mdi-database-lock"></i>
<span>已从数据库加密加载测试会使用已保存密钥</span>
</small>
</label>
</div>
<div
v-if="getModelTestState('reranker').message"
class="test-feedback"
:class="`is-${getModelTestState('reranker').status}`"
>
<i
:class="
getModelTestState('reranker').status === 'success'
? 'mdi mdi-check-circle'
: getModelTestState('reranker').status === 'testing'
? 'mdi mdi-loading mdi-spin'
: 'mdi mdi-alert-circle'
"
></i>
<span>{{ getModelTestState('reranker').message }}</span>
</div>
</section>
</div>
</template>
<script src="./scripts/LlmSettingsPanel.js"></script>
<style scoped src="../assets/styles/views/settings-view-form.css"></style>
<style scoped src="../assets/styles/views/settings-view.css"></style>