后台管理功能开发,AI配置管理

This commit is contained in:
2025-10-30 14:50:44 +08:00
parent dc0413d084
commit 8b6e3d0815
23 changed files with 4463 additions and 4 deletions
+207
View File
@@ -0,0 +1,207 @@
import request from '@/utils/request'
import type {
AiConfigPageRequest,
AiConfigCreateRequest,
AiConfigUpdateRequest
} from '@/types/aiconfig'
// 分页查询AI配置
export function getAiConfigPage(params: AiConfigPageRequest) {
return request({
url: '/aiConfig/page',
method: 'get',
params
})
}
// 根据ID获取AI配置
export function getAiConfigById(id: string) {
return request({
url: '/aiConfig/detail',
method: 'get',
params: { id }
})
}
// 创建AI配置
export function createAiConfig(data: AiConfigCreateRequest) {
return request({
url: '/aiConfig/create',
method: 'post',
data
})
}
// 更新AI配置
export function updateAiConfig(data: AiConfigUpdateRequest) {
return request({
url: '/aiConfig/update',
method: 'put',
data
})
}
// 删除AI配置
export function deleteAiConfig(id: string) {
return request({
url: '/aiConfig/delete',
method: 'delete',
params: { id }
})
}
// 根据配置类型查询AI配置
export function getAiConfigByType(configType: string) {
return request({
url: '/aiConfig/byConfigType',
method: 'get',
params: { configType }
})
}
// 根据服务提供商查询AI配置
export function getAiConfigByProvider(provider: string) {
return request({
url: '/aiConfig/byProvider',
method: 'get',
params: { provider }
})
}
// 根据使用场景查询AI配置
export function getAiConfigByUsageScenario(usageScenario: string) {
return request({
url: '/aiConfig/byUsageScenario',
method: 'get',
params: { usageScenario }
})
}
// 根据环境查询AI配置
export function getAiConfigByEnvironment(environment: string) {
return request({
url: '/aiConfig/byEnvironment',
method: 'get',
params: { environment }
})
}
// 查询已启用的AI配置
export function getEnabledAiConfigs() {
return request({
url: '/aiConfig/enabled',
method: 'get'
})
}
// 查询已禁用的AI配置
export function getDisabledAiConfigs() {
return request({
url: '/aiConfig/disabled',
method: 'get'
})
}
// 查询默认配置
export function getDefaultAiConfigs() {
return request({
url: '/aiConfig/default',
method: 'get'
})
}
// 根据配置键值查询AI配置
export function getAiConfigByKey(configKey: string) {
return request({
url: '/aiConfig/byConfigKey',
method: 'get',
params: { configKey }
})
}
// 启用AI配置
export function enableAiConfig(id: string) {
return request({
url: '/aiConfig/enable',
method: 'put',
params: { id }
})
}
// 禁用AI配置
export function disableAiConfig(id: string) {
return request({
url: '/aiConfig/disable',
method: 'put',
params: { id }
})
}
// 设置为默认配置
export function setAsDefaultConfig(id: string) {
return request({
url: '/aiConfig/setDefault',
method: 'put',
params: { id }
})
}
// 取消默认配置
export function unsetDefaultConfig(id: string) {
return request({
url: '/aiConfig/unsetDefault',
method: 'put',
params: { id }
})
}
// 查询最优配置
export function getBestAiConfig(usageScenario: string, environment: string) {
return request({
url: '/aiConfig/bestConfig',
method: 'get',
params: { usageScenario, environment }
})
}
// 统计已启用配置数量
export function countEnabledConfigs() {
return request({
url: '/aiConfig/countEnabled',
method: 'get'
})
}
// 统计已禁用配置数量
export function countDisabledConfigs() {
return request({
url: '/aiConfig/countDisabled',
method: 'get'
})
}
// 统计默认配置数量
export function countDefaultConfigs() {
return request({
url: '/aiConfig/countDefault',
method: 'get'
})
}
// 根据配置类型统计数量
export function countByConfigType(configType: string) {
return request({
url: '/aiConfig/countByConfigType',
method: 'get',
params: { configType }
})
}
// 根据服务提供商统计数量
export function countByProvider(provider: string) {
return request({
url: '/aiConfig/countByProvider',
method: 'get',
params: { provider }
})
}
@@ -0,0 +1,177 @@
<template>
<el-card>
<template #header>
<div class="card-header">
<span>AI配置快速操作</span>
<el-button type="text" @click="$router.push('/aiconfig/list')">
查看全部
</el-button>
</div>
</template>
<div class="quick-actions">
<el-row :gutter="20">
<el-col :span="12">
<div class="action-item">
<el-icon class="action-icon"><Setting /></el-icon>
<div class="action-content">
<div class="action-title">配置管理</div>
<div class="action-desc">管理AI接口配置</div>
</div>
<el-button type="primary" size="small" @click="$router.push('/aiconfig/list')">
管理
</el-button>
</div>
</el-col>
<el-col :span="12">
<div class="action-item">
<el-icon class="action-icon"><Star /></el-icon>
<div class="action-content">
<div class="action-title">默认配置</div>
<div class="action-desc">{{ defaultConfig ? defaultConfig.configName : '未设置' }}</div>
</div>
<el-button type="warning" size="small" @click="handleViewDefault" :disabled="!defaultConfig">
查看
</el-button>
</div>
</el-col>
</el-row>
<el-row :gutter="20" style="margin-top: 15px;">
<el-col :span="12">
<div class="action-item">
<el-icon class="action-icon"><CircleCheck /></el-icon>
<div class="action-content">
<div class="action-title">启用配置</div>
<div class="action-desc">{{ stats.enabled }} 个配置已启用</div>
</div>
<el-button type="success" size="small" @click="handleViewEnabled">
查看
</el-button>
</div>
</el-col>
<el-col :span="12">
<div class="action-item">
<el-icon class="action-icon"><Plus /></el-icon>
<div class="action-content">
<div class="action-title">新增配置</div>
<div class="action-desc">添加新的AI配置</div>
</div>
<el-button type="primary" size="small" @click="$router.push('/aiconfig/list')">
新增
</el-button>
</div>
</el-col>
</el-row>
</div>
</el-card>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { Setting, Star, CircleCheck, Plus } from '@element-plus/icons-vue'
import { getDefaultAiConfigs, countEnabledConfigs, countDisabledConfigs, countDefaultConfigs } from '@/api/aiconfig'
import type { AiConfig } from '@/types/aiconfig'
const router = useRouter()
const stats = reactive({
enabled: 0,
disabled: 0,
default: 0
})
const defaultConfig = ref<AiConfig | null>(null)
// 获取统计信息
const fetchStats = async () => {
try {
const [enabledRes, disabledRes, defaultRes] = await Promise.all([
countEnabledConfigs(),
countDisabledConfigs(),
countDefaultConfigs()
])
stats.enabled = enabledRes.data
stats.disabled = disabledRes.data
stats.default = defaultRes.data
} catch (error) {
console.error('获取统计信息失败:', error)
}
}
// 获取默认配置
const fetchDefaultConfig = async () => {
try {
const res = await getDefaultAiConfigs()
if (res.data && res.data.length > 0) {
defaultConfig.value = res.data[0]
}
} catch (error) {
console.error('获取默认配置失败:', error)
}
}
// 查看默认配置
const handleViewDefault = () => {
router.push('/aiconfig/list')
}
// 查看启用的配置
const handleViewEnabled = () => {
router.push('/aiconfig/list')
}
onMounted(() => {
fetchStats()
fetchDefaultConfig()
})
</script>
<style scoped lang="scss">
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.quick-actions {
.action-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px;
border: 1px solid #e4e7ed;
border-radius: 8px;
transition: all 0.3s;
&:hover {
border-color: #409eff;
background-color: #f0f9ff;
}
.action-icon {
font-size: 24px;
color: #409eff;
}
.action-content {
flex: 1;
.action-title {
font-size: 14px;
font-weight: 500;
color: #333;
margin-bottom: 4px;
}
.action-desc {
font-size: 12px;
color: #999;
}
}
}
}
</style>
+5
View File
@@ -21,5 +21,10 @@ export const menuConfig: MenuItem[] = [
path: '/user',
title: '用户管理',
icon: 'UserFilled'
},
{
path: '/aiconfig',
title: 'AI配置管理',
icon: 'Setting'
}
]
+14
View File
@@ -49,6 +49,20 @@ const routes: RouteRecordRaw[] = [
}
]
},
{
path: '/aiconfig',
component: Layout,
redirect: '/aiconfig/list',
meta: { title: 'AI配置管理', icon: 'Setting' },
children: [
{
path: 'list',
name: 'AiConfigList',
component: () => import('@/views/aiconfig/AiConfigList.vue'),
meta: { title: 'AI配置列表' }
}
]
},
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
+179
View File
@@ -0,0 +1,179 @@
// AI配置相关类型定义
export interface AiConfig {
id: string
configName: string
configKey: string
configType: string
provider: string
apiBaseUrl: string
apiToken: string
apiVersion?: string
modelName?: string
botId?: string
workflowId?: string
timeoutMs?: number
retryCount?: number
retryDelayMs?: number
maxTokens?: number
temperature?: number
topP?: number
supportStream?: number
supportFunctionCall?: number
supportVision?: number
supportFileUpload?: number
usageScenario: string
priority?: number
inputPricePer1k?: number
outputPricePer1k?: number
currency?: string
rateLimitPerMinute?: number
rateLimitPerHour?: number
rateLimitPerDay?: number
isEnabled?: number
isDefault?: number
environment?: string
customHeaders?: string
customParams?: string
webhookUrl?: string
healthCheckUrl?: string
healthCheckIntervalMinutes?: number
description?: string
usageNotes?: string
createTime?: string
updateTime?: string
}
export interface AiConfigPageRequest {
current: number
size: number
keyword?: string
configType?: string
provider?: string
usageScenario?: string
isEnabled?: number
isDefault?: number
environment?: string
orderBy?: string
orderDirection?: string
}
export interface AiConfigCreateRequest {
configName: string
configKey: string
configType: string
provider: string
apiBaseUrl: string
apiToken: string
apiVersion?: string
modelName?: string
botId?: string
workflowId?: string
timeoutMs?: number
retryCount?: number
retryDelayMs?: number
maxTokens?: number
temperature?: number
topP?: number
supportStream?: number
supportFunctionCall?: number
supportVision?: number
supportFileUpload?: number
usageScenario: string
priority?: number
inputPricePer1k?: number
outputPricePer1k?: number
currency?: string
rateLimitPerMinute?: number
rateLimitPerHour?: number
rateLimitPerDay?: number
isEnabled?: number
isDefault?: number
environment?: string
customHeaders?: string
customParams?: string
webhookUrl?: string
healthCheckUrl?: string
healthCheckIntervalMinutes?: number
description?: string
usageNotes?: string
}
export interface AiConfigUpdateRequest {
id: string
configName?: string
configKey?: string
configType?: string
provider?: string
apiBaseUrl?: string
apiToken?: string
apiVersion?: string
modelName?: string
botId?: string
workflowId?: string
timeoutMs?: number
retryCount?: number
retryDelayMs?: number
maxTokens?: number
temperature?: number
topP?: number
supportStream?: number
supportFunctionCall?: number
supportVision?: number
supportFileUpload?: number
usageScenario?: string
priority?: number
inputPricePer1k?: number
outputPricePer1k?: number
currency?: string
rateLimitPerMinute?: number
rateLimitPerHour?: number
rateLimitPerDay?: number
isEnabled?: number
isDefault?: number
environment?: string
customHeaders?: string
customParams?: string
webhookUrl?: string
healthCheckUrl?: string
healthCheckIntervalMinutes?: number
description?: string
usageNotes?: string
}
// 配置类型选项
export const CONFIG_TYPE_OPTIONS = [
{ label: 'Coze', value: 'coze' },
{ label: 'OpenAI', value: 'openai' },
{ label: 'Claude', value: 'claude' },
{ label: 'Gemini', value: 'gemini' }
]
// 服务提供商选项
export const PROVIDER_OPTIONS = [
{ label: 'Coze', value: 'coze' },
{ label: 'OpenAI', value: 'openai' },
{ label: 'Anthropic', value: 'anthropic' },
{ label: 'Google', value: 'google' }
]
// 使用场景选项
export const USAGE_SCENARIO_OPTIONS = [
{ label: '聊天', value: 'chat' },
{ label: '总结', value: 'summary' },
{ label: '情绪分析', value: 'emotion_analysis' },
{ label: '内容生成', value: 'content_generation' }
]
// 环境选项
export const ENVIRONMENT_OPTIONS = [
{ label: '开发环境', value: 'development' },
{ label: '测试环境', value: 'testing' },
{ label: '生产环境', value: 'production' }
]
// 货币选项
export const CURRENCY_OPTIONS = [
{ label: '美元', value: 'USD' },
{ label: '人民币', value: 'CNY' }
]
+94 -4
View File
@@ -60,8 +60,67 @@
</el-col>
</el-row>
<!-- AI配置统计 -->
<el-row :gutter="20" class="stats-row">
<el-col :span="6">
<el-card class="stat-card">
<div class="stat-content">
<div class="stat-icon" style="background-color: #909399;">
<el-icon><Setting /></el-icon>
</div>
<div class="stat-info">
<div class="stat-value">{{ aiStats.total }}</div>
<div class="stat-label">AI配置总数</div>
</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="stat-card">
<div class="stat-content">
<div class="stat-icon" style="background-color: #67c23a;">
<el-icon><CircleCheck /></el-icon>
</div>
<div class="stat-info">
<div class="stat-value">{{ aiStats.enabled }}</div>
<div class="stat-label">已启用配置</div>
</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="stat-card">
<div class="stat-content">
<div class="stat-icon" style="background-color: #f56c6c;">
<el-icon><CircleClose /></el-icon>
</div>
<div class="stat-info">
<div class="stat-value">{{ aiStats.disabled }}</div>
<div class="stat-label">已禁用配置</div>
</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="stat-card">
<div class="stat-content">
<div class="stat-icon" style="background-color: #e6a23c;">
<el-icon><Star /></el-icon>
</div>
<div class="stat-info">
<div class="stat-value">{{ aiStats.default }}</div>
<div class="stat-label">默认配置</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="20" class="chart-row">
<el-col :span="16">
<el-col :span="12">
<el-card>
<template #header>
<span>用户增长趋势</span>
@@ -70,7 +129,7 @@
</el-card>
</el-col>
<el-col :span="8">
<el-col :span="6">
<el-card>
<template #header>
<span>最近登录</span>
@@ -81,17 +140,30 @@
</el-table>
</el-card>
</el-col>
<el-col :span="6">
<AiConfigQuickActions />
</el-col>
</el-row>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { User, UserFilled, TrendCharts, ChatDotRound } from '@element-plus/icons-vue'
import { ref, reactive, onMounted } from 'vue'
import { User, UserFilled, TrendCharts, ChatDotRound, Setting, CircleCheck, CircleClose, Star } from '@element-plus/icons-vue'
import * as echarts from 'echarts'
import { countEnabledConfigs, countDisabledConfigs, countDefaultConfigs } from '@/api/aiconfig'
import AiConfigQuickActions from '@/components/AiConfigQuickActions.vue'
const userChartRef = ref<HTMLElement>()
const aiStats = reactive({
total: 0,
enabled: 0,
disabled: 0,
default: 0
})
const recentLogins = ref([
{ username: '张三', time: '2分钟前' },
{ username: '李四', time: '5分钟前' },
@@ -101,8 +173,26 @@ const recentLogins = ref([
onMounted(() => {
initUserChart()
fetchAiStats()
})
// 获取AI配置统计
const fetchAiStats = async () => {
try {
const [enabledRes, disabledRes, defaultRes] = await Promise.all([
countEnabledConfigs(),
countDisabledConfigs(),
countDefaultConfigs()
])
aiStats.enabled = enabledRes.data
aiStats.disabled = disabledRes.data
aiStats.default = defaultRes.data
aiStats.total = aiStats.enabled + aiStats.disabled
} catch (error) {
console.error('获取AI配置统计失败:', error)
}
}
const initUserChart = () => {
if (!userChartRef.value) return
File diff suppressed because it is too large Load Diff