Files
schoolNews/schoolNewsWeb/src/views/admin/manage/ai/AIConfigView.vue
2025-12-01 14:51:14 +08:00

449 lines
10 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>
<AdminLayout title="AI配置" subtitle="AI助手配置管理">
<div class="ai-config-container">
<!-- 智能体信息卡片 -->
<div class="agent-info-card">
<div class="agent-header">
<div class="agent-icon">
<img v-if="configForm.avatar" :src="FILE_DOWNLOAD_URL + configForm.avatar" alt="助手头像" />
<div v-else class="default-icon">
<img src="@/assets/imgs/assistant.svg" alt="助手头像" />
</div>
</div>
<div class="agent-info">
<h2 class="agent-name">{{ configForm.name || '未配置助手' }}</h2>
</div>
<div class="agent-status" :class="statusClass">
{{ statusText }}
</div>
</div>
</div>
<!-- 配置表单 -->
<div class="config-form-container">
<el-form :model="configForm" label-position="top" class="config-form">
<!-- 基本信息 -->
<div class="form-section">
<el-form-item label="助手名称" required>
<el-input
v-model="configForm.name"
placeholder="请输入助手名称"
maxlength="50"
show-word-limit
/>
</el-form-item>
<el-form-item label="助手头像">
<FileUpload
v-model:cover-url="configForm.avatar"
:as-dialog="false"
list-type="cover"
accept="image/*"
:max-size="2"
module="ai-agent"
tip="点击上传助手头像"
/>
</el-form-item>
<el-form-item label="助手描述">
<el-input
v-model="configForm.description"
type="textarea"
:rows="8"
placeholder="请输入助手描述介绍AI助手的功能、特点和用途..."
maxlength="2000"
show-word-limit
/>
</el-form-item>
<el-form-item label="联网功能">
<div class="internet-switch-container">
<el-switch
v-model="internetEnabled"
active-text="启用联网"
inactive-text="关闭联网"
:active-value="1"
:inactive-value="0"
/>
<div class="internet-description">
启用后AI助手可以访问互联网获取实时信息
</div>
</div>
</el-form-item>
</div>
<!-- 操作按钮 -->
<div class="form-actions">
<el-button type="primary" size="large" @click="handleSave" :loading="saving">
保存配置
</el-button>
<el-button size="large" @click="handleReset">
重置
</el-button>
</div>
</el-form>
</div>
</div>
</AdminLayout>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { AdminLayout } from '@/views/admin';
import { FileUpload } from '@/components/file';
import { aiAgentConfigApi } from '@/apis/ai';
import { FILE_DOWNLOAD_URL } from '@/config';
import type { AiAgentConfig } from '@/types';
defineOptions({
name: 'AIConfigView'
});
// 表单数据
const configForm = ref<AiAgentConfig>({
name: '',
avatar: '',
description: '',
connectInternet: 0,
modelName: '',
modelProvider: 'dify',
status: 1
});
// 联网开关(用于双向绑定)
const internetEnabled = computed({
get: () => configForm.value.connectInternet || 0,
set: (val) => {
configForm.value.connectInternet = val;
}
});
// 状态
const saving = ref(false);
const loading = ref(false);
// 状态文本
const statusText = computed(() => {
return configForm.value.status === 1 ? '运行中' : '已停用';
});
// 状态样式类
const statusClass = computed(() => {
return configForm.value.status === 1 ? 'status-active' : 'status-inactive';
});
// 加载配置
onMounted(async () => {
await loadConfig();
});
async function loadConfig() {
try {
loading.value = true;
// 获取启用的智能体列表
const result = await aiAgentConfigApi.listEnabledAgents();
if (result.success && result.dataList && result.dataList.length > 0) {
// 使用第一个启用的智能体
Object.assign(configForm.value, result.dataList[0]);
}
} catch (error) {
console.error('加载配置失败:', error);
ElMessage.warning('暂无配置信息,请填写配置');
} finally {
loading.value = false;
}
}
// 保存配置
async function handleSave() {
// 验证必填项
if (!configForm.value.name) {
ElMessage.warning('请输入助手名称');
return;
}
try {
saving.value = true;
// 判断是更新还是创建
if (configForm.value.id) {
await aiAgentConfigApi.updateAgent(configForm.value);
ElMessage.success('配置更新成功');
} else {
const result = await aiAgentConfigApi.createAgent(configForm.value);
if (result.success && result.data) {
configForm.value.id = result.data.id;
}
ElMessage.success('配置创建成功');
}
// 重新加载配置
await loadConfig();
} catch (error: any) {
console.error('保存配置失败:', error);
ElMessage.error(error.message || '保存配置失败');
} finally {
saving.value = false;
}
}
// 重置配置
async function handleReset() {
try {
await ElMessageBox.confirm(
'确定要重置配置吗?此操作将清空当前未保存的修改。',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
);
await loadConfig();
ElMessage.success('配置已重置');
} catch {
// 用户取消
}
}
</script>
<style lang="scss" scoped>
.ai-config-container {
padding: 24px;
max-width: 1600px;
margin: 0 auto;
}
.agent-info-card {
background: #FFFFFF;
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 14px;
padding: 24px;
margin-bottom: 24px;
.agent-header {
display: flex;
align-items: center;
gap: 12px;
.agent-icon {
width: 48px;
height: 48px;
border-radius: 10px;
background: #E7000B;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
flex-shrink: 0;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
.default-icon {
display: flex;
align-items: center;
justify-content: center;
}
}
.agent-info {
flex: 1;
min-width: 0;
.agent-name {
font-size: 16px;
font-weight: 400;
line-height: 1.5;
color: #101828;
margin: 0;
letter-spacing: -0.02em;
}
}
.agent-status {
padding: 2px 8px;
border-radius: 8px;
font-size: 12px;
font-weight: 500;
line-height: 1.33;
white-space: nowrap;
&.status-active {
background: #DCFCE7;
color: #008236;
border: 1px solid transparent;
}
&.status-inactive {
background: #FEF2F2;
color: #DC2626;
border: 1px solid transparent;
}
}
}
}
.config-form-container {
background: #FFFFFF;
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 14px;
padding: 24px;
}
.config-form {
max-width: 672px;
.form-section {
margin-bottom: 32px;
&:last-child {
margin-bottom: 0;
}
}
.section-title {
font-size: 16px;
font-weight: 500;
color: #101828;
margin: 0 0 16px 0;
padding-bottom: 8px;
border-bottom: 1px solid #F3F3F5;
}
:deep(.el-form-item) {
margin-bottom: 16px;
.el-form-item__label {
font-size: 14px;
font-weight: 500;
color: #0A0A0A;
line-height: 1;
margin-bottom: 8px;
padding: 0;
letter-spacing: -0.01em;
}
.el-input__wrapper {
background: #F3F3F5;
border: 1px solid transparent;
border-radius: 8px;
padding: 4px 12px;
box-shadow: none;
transition: all 0.2s;
&:hover {
border-color: rgba(231, 0, 11, 0.2);
}
&.is-focus {
border-color: #E7000B;
background: #FFFFFF;
}
}
.el-textarea__inner {
background: #F3F3F5;
border: 1px solid transparent;
border-radius: 8px;
padding: 8px 12px;
box-shadow: none;
transition: all 0.2s;
&:hover {
border-color: rgba(231, 0, 11, 0.2);
}
&:focus {
border-color: #E7000B;
background: #FFFFFF;
}
}
.el-input-number {
width: 100%;
.el-input__wrapper {
width: 100%;
}
}
}
.form-actions {
margin-top: 32px;
padding-top: 24px;
border-top: 1px solid #F3F3F5;
display: flex;
gap: 12px;
.el-button {
border-radius: 8px;
font-weight: 500;
letter-spacing: -0.01em;
&.el-button--primary {
background: #E7000B;
border-color: #E7000B;
color: #FFFFFF;
&:hover {
background: #C90009;
border-color: #C90009;
}
&:active {
background: #A30008;
border-color: #A30008;
}
}
&.el-button--default {
background: #F3F3F5;
border-color: transparent;
color: #0A0A0A;
&:hover {
background: #E5E5E7;
}
}
}
}
}
.internet-switch-container {
display: flex;
flex-direction: column;
gap: 8px;
.internet-description {
font-size: 13px;
color: #6B7240;
line-height: 1.5;
}
}
:deep(.el-switch) {
--el-switch-on-color: #E7000B;
.el-switch__label {
font-size: 14px;
color: #0A0A0A;
font-weight: 500;
}
&.is-checked .el-switch__label--left {
color: #6B7240;
}
&:not(.is-checked) .el-switch__label--right {
color: #6B7240;
}
}
</style>