From 16d397125a5c78490e225c8005fdd167bfff6d69 Mon Sep 17 00:00:00 2001 From: shaw Date: Wed, 3 Sep 2025 17:28:13 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81apikey=E5=90=8D?= =?UTF-8?q?=E7=A7=B0=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/admin.js | 13 ++++++++ .../components/apikeys/EditApiKeyModal.vue | 13 +++++--- web/admin-spa/src/views/ApiKeysView.vue | 31 +++++++++++++------ 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/routes/admin.js b/src/routes/admin.js index 31792278..8c824eab 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -873,6 +873,7 @@ router.put('/api-keys/:keyId', authenticateAdmin, async (req, res) => { try { const { keyId } = req.params const { + name, // 添加名称字段 tokenLimit, concurrencyLimit, rateLimitWindow, @@ -899,6 +900,18 @@ router.put('/api-keys/:keyId', authenticateAdmin, async (req, res) => { // 只允许更新指定字段 const updates = {} + // 处理名称字段 + if (name !== undefined && name !== null && name !== '') { + const trimmedName = name.toString().trim() + if (trimmedName.length === 0) { + return res.status(400).json({ error: 'API Key name cannot be empty' }) + } + if (trimmedName.length > 100) { + return res.status(400).json({ error: 'API Key name must be less than 100 characters' }) + } + updates.name = trimmedName + } + if (tokenLimit !== undefined && tokenLimit !== null && tokenLimit !== '') { if (!Number.isInteger(Number(tokenLimit)) || Number(tokenLimit) < 0) { return res.status(400).json({ error: 'Token limit must be a non-negative integer' }) diff --git a/web/admin-spa/src/components/apikeys/EditApiKeyModal.vue b/web/admin-spa/src/components/apikeys/EditApiKeyModal.vue index 1484f41a..c84aeb37 100644 --- a/web/admin-spa/src/components/apikeys/EditApiKeyModal.vue +++ b/web/admin-spa/src/components/apikeys/EditApiKeyModal.vue @@ -33,12 +33,16 @@ >名称 -

名称不可修改

+

+ 用于识别此 API Key 的用途 +

@@ -798,6 +802,7 @@ const updateApiKey = async () => { try { // 准备提交的数据 const data = { + name: form.name, // 添加名称字段 tokenLimit: 0, // 清除历史token限制 rateLimitWindow: form.rateLimitWindow !== '' && form.rateLimitWindow !== null diff --git a/web/admin-spa/src/views/ApiKeysView.vue b/web/admin-spa/src/views/ApiKeysView.vue index d1c36f59..20e48a7a 100644 --- a/web/admin-spa/src/views/ApiKeysView.vue +++ b/web/admin-spa/src/views/ApiKeysView.vue @@ -105,7 +105,7 @@ @@ -405,7 +405,10 @@ -
+
{{ key.ownerDisplayName }}
@@ -1031,7 +1034,7 @@ 使用共享池
-
+
{{ key.ownerDisplayName }}
@@ -1337,6 +1340,7 @@ 名称 创建者 @@ -1393,7 +1397,7 @@
- +
@@ -1555,6 +1559,7 @@ import { ref, computed, onMounted, watch } from 'vue' import { showToast } from '@/utils/toast' import { apiClient } from '@/config/api' import { useClientsStore } from '@/stores/clients' +import { useAuthStore } from '@/stores/auth' import CreateApiKeyModal from '@/components/apikeys/CreateApiKeyModal.vue' import EditApiKeyModal from '@/components/apikeys/EditApiKeyModal.vue' import RenewApiKeyModal from '@/components/apikeys/RenewApiKeyModal.vue' @@ -1568,8 +1573,12 @@ import CustomDropdown from '@/components/common/CustomDropdown.vue' // 响应式数据 const clientsStore = useClientsStore() +const authStore = useAuthStore() const apiKeys = ref([]) +// 获取 LDAP 启用状态 +const isLdapEnabled = computed(() => authStore.oemSettings?.ldapEnabled || false) + // 多选相关状态 const selectedApiKeys = ref([]) const selectAllChecked = ref(false) @@ -1663,11 +1672,15 @@ const sortedApiKeys = computed(() => { filteredKeys = filteredKeys.filter((key) => { // 搜索API Key名称 const nameMatch = key.name && key.name.toLowerCase().includes(keyword) - // 搜索所有者名称 - const ownerMatch = - key.ownerDisplayName && key.ownerDisplayName.toLowerCase().includes(keyword) - // 如果API Key名称或所有者名称匹配,则包含该条目 - return nameMatch || ownerMatch + // 如果启用了 LDAP,搜索所有者名称 + if (isLdapEnabled.value) { + const ownerMatch = + key.ownerDisplayName && key.ownerDisplayName.toLowerCase().includes(keyword) + // 如果API Key名称或所有者名称匹配,则包含该条目 + return nameMatch || ownerMatch + } + // 未启用 LDAP 时只搜索名称 + return nameMatch }) }