mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 00:53:33 +00:00
Merge remote-tracking branch 'f3n9/main' into main-um-8
This commit is contained in:
@@ -890,6 +890,7 @@ router.put('/api-keys/:keyId', authenticateAdmin, async (req, res) => {
|
||||
try {
|
||||
const { keyId } = req.params
|
||||
const {
|
||||
name, // 添加名称字段
|
||||
tokenLimit,
|
||||
concurrencyLimit,
|
||||
rateLimitWindow,
|
||||
@@ -916,6 +917,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' })
|
||||
|
||||
@@ -33,12 +33,16 @@
|
||||
>名称</label
|
||||
>
|
||||
<input
|
||||
class="form-input w-full cursor-not-allowed bg-gray-100 text-sm dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400"
|
||||
disabled
|
||||
v-model="form.name"
|
||||
class="form-input w-full text-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
|
||||
maxlength="100"
|
||||
placeholder="请输入API Key名称"
|
||||
required
|
||||
type="text"
|
||||
:value="form.name"
|
||||
/>
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400 sm:mt-2">名称不可修改</p>
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400 sm:mt-2">
|
||||
用于识别此 API Key 的用途
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 所有者选择 -->
|
||||
@@ -798,6 +802,7 @@ const updateApiKey = async () => {
|
||||
try {
|
||||
// 准备提交的数据
|
||||
const data = {
|
||||
name: form.name, // 添加名称字段
|
||||
tokenLimit: 0, // 清除历史token限制
|
||||
rateLimitWindow:
|
||||
form.rateLimitWindow !== '' && form.rateLimitWindow !== null
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
<input
|
||||
v-model="searchKeyword"
|
||||
class="w-full rounded-lg border border-gray-200 bg-white px-3 py-2 pl-9 text-sm text-gray-700 placeholder-gray-400 shadow-sm transition-all duration-200 hover:border-gray-300 focus:border-cyan-500 focus:outline-none focus:ring-2 focus:ring-cyan-500/20 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 dark:placeholder-gray-500 dark:hover:border-gray-500"
|
||||
placeholder="搜索名称或所有者..."
|
||||
:placeholder="isLdapEnabled ? '搜索名称或所有者...' : '搜索名称...'"
|
||||
type="text"
|
||||
@input="currentPage = 1"
|
||||
/>
|
||||
@@ -405,7 +405,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 显示所有者信息 -->
|
||||
<div v-if="key.ownerDisplayName" class="mt-1 text-xs text-red-600">
|
||||
<div
|
||||
v-if="isLdapEnabled && key.ownerDisplayName"
|
||||
class="mt-1 text-xs text-red-600"
|
||||
>
|
||||
<i class="fas fa-user mr-1" />
|
||||
{{ key.ownerDisplayName }}
|
||||
</div>
|
||||
@@ -1031,7 +1034,7 @@
|
||||
使用共享池
|
||||
</div>
|
||||
<!-- 显示所有者信息 -->
|
||||
<div v-if="key.ownerDisplayName" class="text-xs text-red-600">
|
||||
<div v-if="isLdapEnabled && key.ownerDisplayName" class="text-xs text-red-600">
|
||||
<i class="fas fa-user mr-1" />
|
||||
{{ key.ownerDisplayName }}
|
||||
</div>
|
||||
@@ -1337,6 +1340,7 @@
|
||||
名称
|
||||
</th>
|
||||
<th
|
||||
v-if="isLdapEnabled"
|
||||
class="w-[15%] min-w-[120px] px-3 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-700 dark:text-gray-300"
|
||||
>
|
||||
创建者
|
||||
@@ -1393,7 +1397,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-3 py-4">
|
||||
<td v-if="isLdapEnabled" class="px-3 py-4">
|
||||
<div class="text-sm">
|
||||
<span v-if="key.createdBy === 'admin'" class="text-blue-600">
|
||||
<i class="fas fa-user-shield mr-1" />
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user