Merge remote-tracking branch 'f3n9/main' into main-um-8

This commit is contained in:
Feng Yue
2025-09-03 17:43:36 +08:00
4 changed files with 45 additions and 14 deletions

View File

@@ -1 +1 @@
1.1.126 1.1.127

View File

@@ -890,6 +890,7 @@ router.put('/api-keys/:keyId', authenticateAdmin, async (req, res) => {
try { try {
const { keyId } = req.params const { keyId } = req.params
const { const {
name, // 添加名称字段
tokenLimit, tokenLimit,
concurrencyLimit, concurrencyLimit,
rateLimitWindow, rateLimitWindow,
@@ -916,6 +917,18 @@ router.put('/api-keys/:keyId', authenticateAdmin, async (req, res) => {
// 只允许更新指定字段 // 只允许更新指定字段
const updates = {} 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 (tokenLimit !== undefined && tokenLimit !== null && tokenLimit !== '') {
if (!Number.isInteger(Number(tokenLimit)) || Number(tokenLimit) < 0) { if (!Number.isInteger(Number(tokenLimit)) || Number(tokenLimit) < 0) {
return res.status(400).json({ error: 'Token limit must be a non-negative integer' }) return res.status(400).json({ error: 'Token limit must be a non-negative integer' })

View File

@@ -33,12 +33,16 @@
>名称</label >名称</label
> >
<input <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" v-model="form.name"
disabled 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" 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> </div>
<!-- 所有者选择 --> <!-- 所有者选择 -->
@@ -798,6 +802,7 @@ const updateApiKey = async () => {
try { try {
// 准备提交的数据 // 准备提交的数据
const data = { const data = {
name: form.name, // 添加名称字段
tokenLimit: 0, // 清除历史token限制 tokenLimit: 0, // 清除历史token限制
rateLimitWindow: rateLimitWindow:
form.rateLimitWindow !== '' && form.rateLimitWindow !== null form.rateLimitWindow !== '' && form.rateLimitWindow !== null

View File

@@ -105,7 +105,7 @@
<input <input
v-model="searchKeyword" 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" 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" type="text"
@input="currentPage = 1" @input="currentPage = 1"
/> />
@@ -405,7 +405,10 @@
</div> </div>
</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" /> <i class="fas fa-user mr-1" />
{{ key.ownerDisplayName }} {{ key.ownerDisplayName }}
</div> </div>
@@ -1031,7 +1034,7 @@
使用共享池 使用共享池
</div> </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" /> <i class="fas fa-user mr-1" />
{{ key.ownerDisplayName }} {{ key.ownerDisplayName }}
</div> </div>
@@ -1337,6 +1340,7 @@
名称 名称
</th> </th>
<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" 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>
</div> </div>
</td> </td>
<td class="px-3 py-4"> <td v-if="isLdapEnabled" class="px-3 py-4">
<div class="text-sm"> <div class="text-sm">
<span v-if="key.createdBy === 'admin'" class="text-blue-600"> <span v-if="key.createdBy === 'admin'" class="text-blue-600">
<i class="fas fa-user-shield mr-1" /> <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 { showToast } from '@/utils/toast'
import { apiClient } from '@/config/api' import { apiClient } from '@/config/api'
import { useClientsStore } from '@/stores/clients' import { useClientsStore } from '@/stores/clients'
import { useAuthStore } from '@/stores/auth'
import CreateApiKeyModal from '@/components/apikeys/CreateApiKeyModal.vue' import CreateApiKeyModal from '@/components/apikeys/CreateApiKeyModal.vue'
import EditApiKeyModal from '@/components/apikeys/EditApiKeyModal.vue' import EditApiKeyModal from '@/components/apikeys/EditApiKeyModal.vue'
import RenewApiKeyModal from '@/components/apikeys/RenewApiKeyModal.vue' import RenewApiKeyModal from '@/components/apikeys/RenewApiKeyModal.vue'
@@ -1568,8 +1573,12 @@ import CustomDropdown from '@/components/common/CustomDropdown.vue'
// 响应式数据 // 响应式数据
const clientsStore = useClientsStore() const clientsStore = useClientsStore()
const authStore = useAuthStore()
const apiKeys = ref([]) const apiKeys = ref([])
// 获取 LDAP 启用状态
const isLdapEnabled = computed(() => authStore.oemSettings?.ldapEnabled || false)
// 多选相关状态 // 多选相关状态
const selectedApiKeys = ref([]) const selectedApiKeys = ref([])
const selectAllChecked = ref(false) const selectAllChecked = ref(false)
@@ -1663,11 +1672,15 @@ const sortedApiKeys = computed(() => {
filteredKeys = filteredKeys.filter((key) => { filteredKeys = filteredKeys.filter((key) => {
// 搜索API Key名称 // 搜索API Key名称
const nameMatch = key.name && key.name.toLowerCase().includes(keyword) const nameMatch = key.name && key.name.toLowerCase().includes(keyword)
// 搜索所有者名称 // 如果启用了 LDAP搜索所有者名称
const ownerMatch = if (isLdapEnabled.value) {
key.ownerDisplayName && key.ownerDisplayName.toLowerCase().includes(keyword) const ownerMatch =
// 如果API Key名称或所有者名称匹配则包含该条目 key.ownerDisplayName && key.ownerDisplayName.toLowerCase().includes(keyword)
return nameMatch || ownerMatch // 如果API Key名称或所有者名称匹配则包含该条目
return nameMatch || ownerMatch
}
// 未启用 LDAP 时只搜索名称
return nameMatch
}) })
} }