mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
feat(admin-spa): 添加 API Key 标签管理功能
基于 PR #114 的功能需求,为新版 admin-spa 实现完整的标签系统: 后端改进: - apiKeyService 支持标签的创建、查询和更新 - admin 路由添加标签验证和处理逻辑 - 标签以 JSON 数组形式存储在 Redis 中 前端功能: - API Key 列表增加标签列,显示彩色标签徽章 - 添加标签筛选器,支持按标签过滤 API Keys - 创建和编辑 API Key 时可添加/删除标签 - 标签输入支持 Enter 键快速添加 - 自动收集并排序所有可用标签 界面优化: - 使用蓝色圆角标签样式,视觉清晰 - 无标签时显示"无标签"提示 - 标签管理操作流畅,支持即时添加删除 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -29,6 +29,40 @@
|
||||
>
|
||||
</div>
|
||||
|
||||
<!-- 标签 -->
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-3">标签</label>
|
||||
<div class="space-y-3">
|
||||
<!-- 已添加的标签 -->
|
||||
<div v-if="form.tags.length > 0" class="flex flex-wrap gap-2">
|
||||
<span v-for="(tag, index) in form.tags" :key="index"
|
||||
class="inline-flex items-center gap-1 px-3 py-1 bg-blue-100 text-blue-800 text-sm rounded-full">
|
||||
{{ tag }}
|
||||
<button type="button" @click="removeTag(index)"
|
||||
class="ml-1 hover:text-blue-900">
|
||||
<i class="fas fa-times text-xs"></i>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- 标签输入 -->
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
v-model="newTag"
|
||||
type="text"
|
||||
class="form-input flex-1"
|
||||
placeholder="输入新标签名称"
|
||||
@keypress.enter.prevent="addTag"
|
||||
>
|
||||
<button type="button" @click="addTag"
|
||||
class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors">
|
||||
<i class="fas fa-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
<p class="text-xs text-gray-500">用于标记不同团队或用途,方便筛选管理</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 速率限制设置 -->
|
||||
<div class="bg-blue-50 border border-blue-200 rounded-lg p-4 space-y-4">
|
||||
<div class="flex items-start gap-3 mb-3">
|
||||
@@ -375,6 +409,9 @@ const authStore = useAuthStore()
|
||||
const clientsStore = useClientsStore()
|
||||
const loading = ref(false)
|
||||
|
||||
// 标签相关
|
||||
const newTag = ref('')
|
||||
|
||||
// 支持的客户端列表
|
||||
const supportedClients = ref([])
|
||||
|
||||
@@ -397,7 +434,8 @@ const form = reactive({
|
||||
restrictedModels: [],
|
||||
modelInput: '',
|
||||
enableClientRestriction: false,
|
||||
allowedClients: []
|
||||
allowedClients: [],
|
||||
tags: []
|
||||
})
|
||||
|
||||
// 加载支持的客户端
|
||||
@@ -482,6 +520,21 @@ const removeRestrictedModel = (index) => {
|
||||
form.restrictedModels.splice(index, 1)
|
||||
}
|
||||
|
||||
// 标签管理方法
|
||||
const addTag = () => {
|
||||
if (newTag.value && newTag.value.trim()) {
|
||||
const tag = newTag.value.trim()
|
||||
if (!form.tags.includes(tag)) {
|
||||
form.tags.push(tag)
|
||||
}
|
||||
newTag.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
const removeTag = (index) => {
|
||||
form.tags.splice(index, 1)
|
||||
}
|
||||
|
||||
// 创建 API Key
|
||||
const createApiKey = async () => {
|
||||
loading.value = true
|
||||
@@ -499,7 +552,8 @@ const createApiKey = async () => {
|
||||
expiresAt: form.expiresAt || undefined,
|
||||
permissions: form.permissions,
|
||||
claudeAccountId: form.claudeAccountId || undefined,
|
||||
geminiAccountId: form.geminiAccountId || undefined
|
||||
geminiAccountId: form.geminiAccountId || undefined,
|
||||
tags: form.tags.length > 0 ? form.tags : undefined
|
||||
}
|
||||
|
||||
// 模型限制
|
||||
|
||||
Reference in New Issue
Block a user