feat: 用户创建和注册时使用系统配置的默认配额

- 新增 /api/admin/users/defaults/quota 接口获取默认配额
- 用户注册时从系统配置读取默认配额
- 管理员创建用户时自动获取并使用系统默认配额
This commit is contained in:
fawney19
2026-01-15 17:41:04 +08:00
parent 026f4b9c0e
commit d9645fa062
4 changed files with 52 additions and 6 deletions

View File

@@ -98,6 +98,11 @@ export const usersApi = {
await apiClient.patch(`/api/admin/users/${userId}/quota`) await apiClient.patch(`/api/admin/users/${userId}/quota`)
}, },
async getDefaultQuota(): Promise<{ default_quota_usd: number }> {
const response = await apiClient.get<{ default_quota_usd: number }>('/api/admin/users/defaults/quota')
return response.data
},
// 管理员统计 // 管理员统计
async getUsageStats(): Promise<any> { async getUsageStats(): Promise<any> {
const response = await apiClient.get('/api/admin/usage/stats') const response = await apiClient.get('/api/admin/usage/stats')

View File

@@ -363,6 +363,7 @@ import { ModelMultiSelect } from '@/components/common'
import { getProvidersSummary } from '@/api/endpoints/providers' import { getProvidersSummary } from '@/api/endpoints/providers'
import { getGlobalModels } from '@/api/global-models' import { getGlobalModels } from '@/api/global-models'
import { adminApi } from '@/api/admin' import { adminApi } from '@/api/admin'
import { usersApi } from '@/api/users'
import { log } from '@/utils/logger' import { log } from '@/utils/logger'
import type { ProviderWithEndpointsSummary, GlobalModelResponse } from '@/api/endpoints/types' import type { ProviderWithEndpointsSummary, GlobalModelResponse } from '@/api/endpoints/types'
@@ -402,6 +403,7 @@ const endpointDropdownOpen = ref(false)
const providers = ref<ProviderWithEndpointsSummary[]>([]) const providers = ref<ProviderWithEndpointsSummary[]>([])
const globalModels = ref<GlobalModelResponse[]>([]) const globalModels = ref<GlobalModelResponse[]>([])
const apiFormats = ref<Array<{ value: string; label: string }>>([]) const apiFormats = ref<Array<{ value: string; label: string }>>([])
const defaultQuota = ref<number>(10)
// 表单数据 // 表单数据
const form = ref({ const form = ref({
@@ -430,7 +432,7 @@ function resetForm() {
password: '', password: '',
confirmPassword: '', confirmPassword: '',
email: '', email: '',
quota: 10, quota: defaultQuota.value,
role: 'user', role: 'user',
unlimited: false, unlimited: false,
is_active: true, is_active: true,
@@ -479,18 +481,22 @@ const isFormValid = computed(() => {
}) })
// 加载访问控制选项 // 加载访问控制选项
async function loadAccessControlOptions() { async function loadAccessControlOptions(): Promise<boolean> {
try { try {
const [providersData, modelsData, formatsData] = await Promise.all([ const [providersData, modelsData, formatsData, quotaData] = await Promise.all([
getProvidersSummary(), getProvidersSummary(),
getGlobalModels({ limit: 1000, is_active: true }), getGlobalModels({ limit: 1000, is_active: true }),
adminApi.getApiFormats() adminApi.getApiFormats(),
usersApi.getDefaultQuota()
]) ])
providers.value = providersData providers.value = providersData
globalModels.value = modelsData.models || [] globalModels.value = modelsData.models || []
apiFormats.value = formatsData.formats || [] apiFormats.value = formatsData.formats || []
defaultQuota.value = quotaData.default_quota_usd
return true
} catch (err) { } catch (err) {
log.error('加载访问限制选项失败:', err) log.error('加载访问限制选项失败:', err)
return false
} }
} }
@@ -551,9 +557,13 @@ function setSaving(value: boolean) {
} }
// 监听打开状态,加载选项数据 // 监听打开状态,加载选项数据
watch(isOpen, (val) => { watch(isOpen, async (val) => {
if (val) { if (val) {
loadAccessControlOptions() const success = await loadAccessControlOptions()
// 创建模式下,仅在加载成功时更新表单配额
if (!isEditMode.value && success) {
form.value.quota = defaultQuota.value
}
} }
}) })

View File

@@ -15,6 +15,7 @@ from src.database import get_db
from src.models.admin_requests import UpdateUserRequest from src.models.admin_requests import UpdateUserRequest
from src.models.api import CreateApiKeyRequest, CreateUserRequest from src.models.api import CreateApiKeyRequest, CreateUserRequest
from src.models.database import ApiKey, User, UserRole from src.models.database import ApiKey, User, UserRole
from src.services.system.config import SystemConfigService
from src.services.user.apikey import ApiKeyService from src.services.user.apikey import ApiKeyService
from src.services.user.service import UserService from src.services.user.service import UserService
@@ -197,6 +198,20 @@ async def delete_user_api_key(
return await pipeline.run(adapter=adapter, http_request=request, db=db, mode=adapter.mode) return await pipeline.run(adapter=adapter, http_request=request, db=db, mode=adapter.mode)
@router.get("/defaults/quota")
async def get_default_quota(request: Request, db: Session = Depends(get_db)):
"""
获取默认用户配额
获取系统配置的默认用户配额值,用于创建用户时的默认值。
**返回字段**:
- `default_quota_usd`: 默认配额USD
"""
adapter = AdminGetDefaultQuotaAdapter()
return await pipeline.run(adapter=adapter, http_request=request, db=db, mode=adapter.mode)
# ============== 管理员适配器实现 ============== # ============== 管理员适配器实现 ==============
@@ -586,3 +601,15 @@ class AdminDeleteUserKeyAdapter(AdminApiAdapter):
) )
return {"message": "API Key已删除"} return {"message": "API Key已删除"}
class AdminGetDefaultQuotaAdapter(AdminApiAdapter):
"""获取系统默认用户配额"""
async def handle(self, context): # type: ignore[override]
db = context.db
default_quota = SystemConfigService.get_config(db, "default_user_quota_usd", default=10.0)
return {
"default_quota_usd": float(default_quota),
}

View File

@@ -470,12 +470,16 @@ class AuthRegisterAdapter(AuthPublicAdapter):
) )
try: try:
# 读取系统配置的默认配额
default_quota = SystemConfigService.get_config(db, "default_user_quota_usd", default=10.0)
user = UserService.create_user( user = UserService.create_user(
db=db, db=db,
email=register_request.email, email=register_request.email,
username=register_request.username, username=register_request.username,
password=register_request.password, password=register_request.password,
role=UserRole.USER, role=UserRole.USER,
quota_usd=default_quota,
) )
AuditService.log_event( AuditService.log_event(
db=db, db=db,