mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 08:59:16 +00:00
feat: API Keys图标系统和UI优化
主要功能增强: - 实现API Key自定义图标功能,支持图片上传、裁剪和智能压缩 - 新增IconPicker组件,提供内置图标选择和图片上传功能 - 支持固定尺寸裁剪区域,可拖拽定位选择头像区域 - 智能图片压缩:PNG保留透明度,JPEG用于不透明图片 UI/UX改进: - 优化表格布局:移除账号列,在名称下方显示账号绑定信息 - 调整行高和字体大小,提升信息密度 - 最后使用时间改为相对时间显示,悬浮显示具体时间 - 过期时间编辑改为点击文本触发,带悬浮下划线效果 - 更新默认API Key图标为蓝色渐变设计 - 修复表格悬浮偏移和横向滚动条问题 - 将"TOKEN 数量"改为"Token数" 后端支持: - apiKeyService增加icon字段持久化 - admin路由增加图标数据处理和验证 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -110,19 +110,23 @@
|
||||
class="mb-1.5 block text-xs font-semibold text-gray-700 dark:text-gray-300 sm:mb-2 sm:text-sm"
|
||||
>名称 <span class="text-red-500">*</span></label
|
||||
>
|
||||
<input
|
||||
v-model="form.name"
|
||||
class="form-input w-full border-gray-300 text-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
|
||||
:class="{ 'border-red-500': errors.name }"
|
||||
:placeholder="
|
||||
form.createType === 'batch'
|
||||
? '输入基础名称(将自动添加序号)'
|
||||
: '为您的 API Key 取一个名称'
|
||||
"
|
||||
required
|
||||
type="text"
|
||||
@input="errors.name = ''"
|
||||
/>
|
||||
<div class="flex items-center gap-2">
|
||||
<!-- 图标选择器 -->
|
||||
<IconPicker v-model="form.icon" size="medium" />
|
||||
<input
|
||||
v-model="form.name"
|
||||
class="form-input flex-1 border-gray-300 text-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
|
||||
:class="{ 'border-red-500': errors.name }"
|
||||
:placeholder="
|
||||
form.createType === 'batch'
|
||||
? '输入基础名称(将自动添加序号)'
|
||||
: '为您的 API Key 取一个名称'
|
||||
"
|
||||
required
|
||||
type="text"
|
||||
@input="errors.name = ''"
|
||||
/>
|
||||
</div>
|
||||
<p v-if="errors.name" class="mt-1 text-xs text-red-500 dark:text-red-400">
|
||||
{{ errors.name }}
|
||||
</p>
|
||||
@@ -807,6 +811,7 @@ import { useClientsStore } from '@/stores/clients'
|
||||
import { useApiKeysStore } from '@/stores/apiKeys'
|
||||
import { apiClient } from '@/config/api'
|
||||
import AccountSelector from '@/components/common/AccountSelector.vue'
|
||||
import IconPicker from '@/components/common/IconPicker.vue'
|
||||
|
||||
const props = defineProps({
|
||||
accounts: {
|
||||
@@ -853,6 +858,7 @@ const form = reactive({
|
||||
createType: 'single',
|
||||
batchCount: 10,
|
||||
name: '',
|
||||
icon: '',
|
||||
description: '',
|
||||
rateLimitWindow: '',
|
||||
rateLimitRequests: '',
|
||||
@@ -1198,7 +1204,8 @@ const createApiKey = async () => {
|
||||
// 单个创建
|
||||
const data = {
|
||||
...baseData,
|
||||
name: form.name
|
||||
name: form.name,
|
||||
icon: form.icon || ''
|
||||
}
|
||||
|
||||
const result = await apiClient.post('/admin/api-keys', data)
|
||||
@@ -1216,7 +1223,8 @@ const createApiKey = async () => {
|
||||
...baseData,
|
||||
createType: 'batch',
|
||||
baseName: form.name,
|
||||
count: form.batchCount
|
||||
count: form.batchCount,
|
||||
icon: form.icon || ''
|
||||
}
|
||||
|
||||
const result = await apiClient.post('/admin/api-keys/batch', data)
|
||||
|
||||
@@ -32,14 +32,18 @@
|
||||
class="mb-1.5 block text-xs font-semibold text-gray-700 dark:text-gray-300 sm:mb-3 sm:text-sm"
|
||||
>名称</label
|
||||
>
|
||||
<input
|
||||
v-model="form.name"
|
||||
class="form-input w-full border-gray-300 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"
|
||||
/>
|
||||
<div class="flex items-center gap-2">
|
||||
<!-- 图标选择器 -->
|
||||
<IconPicker v-model="form.icon" size="medium" />
|
||||
<input
|
||||
v-model="form.name"
|
||||
class="form-input flex-1 border-gray-300 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"
|
||||
/>
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400 sm:mt-2">
|
||||
用于识别此 API Key 的用途
|
||||
</p>
|
||||
@@ -658,6 +662,7 @@ import { useClientsStore } from '@/stores/clients'
|
||||
import { useApiKeysStore } from '@/stores/apiKeys'
|
||||
import { apiClient } from '@/config/api'
|
||||
import AccountSelector from '@/components/common/AccountSelector.vue'
|
||||
import IconPicker from '@/components/common/IconPicker.vue'
|
||||
|
||||
const props = defineProps({
|
||||
apiKey: {
|
||||
@@ -705,6 +710,7 @@ const unselectedTags = computed(() => {
|
||||
// 表单数据
|
||||
const form = reactive({
|
||||
name: '',
|
||||
icon: '',
|
||||
tokenLimit: '', // 保留用于检测历史数据
|
||||
rateLimitWindow: '',
|
||||
rateLimitRequests: '',
|
||||
@@ -803,6 +809,7 @@ const updateApiKey = async () => {
|
||||
// 准备提交的数据
|
||||
const data = {
|
||||
name: form.name, // 添加名称字段
|
||||
icon: form.icon || '', // 添加图标字段
|
||||
tokenLimit: 0, // 清除历史token限制
|
||||
rateLimitWindow:
|
||||
form.rateLimitWindow !== '' && form.rateLimitWindow !== null
|
||||
@@ -1035,6 +1042,7 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
form.name = props.apiKey.name
|
||||
form.icon = props.apiKey.icon || ''
|
||||
|
||||
// 处理速率限制迁移:如果有tokenLimit且没有rateLimitCost,提示用户
|
||||
form.tokenLimit = props.apiKey.tokenLimit || ''
|
||||
|
||||
Reference in New Issue
Block a user