后台管理功能开发,AI配置管理
This commit is contained in:
@@ -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>
|
||||
@@ -21,5 +21,10 @@ export const menuConfig: MenuItem[] = [
|
||||
path: '/user',
|
||||
title: '用户管理',
|
||||
icon: 'UserFilled'
|
||||
},
|
||||
{
|
||||
path: '/aiconfig',
|
||||
title: 'AI配置管理',
|
||||
icon: 'Setting'
|
||||
}
|
||||
]
|
||||
@@ -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',
|
||||
|
||||
@@ -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' }
|
||||
]
|
||||
@@ -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
Reference in New Issue
Block a user