合并所有新功能到Wei-Shaw仓库(排除ApiStatsView.vue)

 新增功能:
- GPT-5 High推理级别费用追踪和限制
- API Key图标上传功能
- 优化的进度条显示组件
- 暗黑模式UI兼容
- 完整的前后端集成

🔥 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
DuanNaiSheQu
2025-09-10 13:38:27 +08:00
parent ca79e08c81
commit af3d688e98
12 changed files with 775 additions and 805 deletions

View File

@@ -110,26 +110,70 @@
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
>
<div>
<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>
<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 = ''"
/>
<p v-if="errors.name" class="mt-1 text-xs text-red-500 dark:text-red-400">
{{ errors.name }}
</p>
</div>
<!-- 图标上传 -->
<div>
<label class="mb-2 block text-sm font-semibold text-gray-700 dark:text-gray-300">
图标 (可选)
</label>
<div class="space-y-3">
<!-- 当前图标预览 -->
<div v-if="form.icon" class="flex items-center gap-3">
<div
class="h-12 w-12 overflow-hidden rounded-lg border border-gray-200 dark:border-gray-600"
>
<img alt="API Key图标" class="h-full w-full object-cover" :src="form.icon" />
</div>
<button
class="text-sm text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300"
type="button"
@click="form.icon = ''"
>
移除图标
</button>
</div>
<!-- 图标上传按钮 -->
<div class="flex items-center gap-3">
<input
ref="iconInput"
accept="image/*"
class="hidden"
type="file"
@change="handleIconUpload"
/>
<button
class="flex items-center gap-2 rounded-md border border-gray-300 bg-white px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600"
type="button"
@click="$refs.iconInput.click()"
>
<i class="fas fa-upload" />
选择图标
</button>
<p class="text-xs text-gray-500 dark:text-gray-400">
支持 PNGJPG 格式建议尺寸 64x64px
</p>
</div>
</div>
</div>
<!-- 标签 -->
<div>
<label class="mb-2 block text-sm font-semibold text-gray-700 dark:text-gray-300"
@@ -384,6 +428,56 @@
</div>
</div>
<!-- GPT-5 High推理级别周费用限制 -->
<div>
<label class="mb-2 block text-sm font-semibold text-gray-700 dark:text-gray-300"
>GPT-5 High推理级别周费用限制 (美元)</label
>
<div class="space-y-2">
<div class="flex gap-2">
<button
class="rounded bg-gray-100 px-2 py-1 text-xs font-medium hover:bg-gray-200 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600"
type="button"
@click="form.weeklyGPT5HighCostLimit = '5'"
>
$5
</button>
<button
class="rounded bg-gray-100 px-2 py-1 text-xs font-medium hover:bg-gray-200 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600"
type="button"
@click="form.weeklyGPT5HighCostLimit = '20'"
>
$20
</button>
<button
class="rounded bg-gray-100 px-2 py-1 text-xs font-medium hover:bg-gray-200 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600"
type="button"
@click="form.weeklyGPT5HighCostLimit = '50'"
>
$50
</button>
<button
class="rounded bg-gray-100 px-2 py-1 text-xs font-medium hover:bg-gray-200 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600"
type="button"
@click="form.weeklyGPT5HighCostLimit = ''"
>
自定义
</button>
</div>
<input
v-model="form.weeklyGPT5HighCostLimit"
class="form-input w-full border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
min="0"
placeholder="0 表示无限制"
step="0.01"
type="number"
/>
<p class="text-xs text-gray-500 dark:text-gray-400">
设置 GPT-5 High推理级别的周费用限制周一到周日0 或留空表示无限制
</p>
</div>
</div>
<div>
<label class="mb-2 block text-sm font-semibold text-gray-700 dark:text-gray-300"
>并发限制 (可选)</label
@@ -804,6 +898,7 @@
<script setup>
import { ref, reactive, computed, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { showToast } from '@/utils/toast'
import { useClientsStore } from '@/stores/clients'
import { useApiKeysStore } from '@/stores/apiKeys'
@@ -862,6 +957,7 @@ const form = reactive({
concurrencyLimit: '',
dailyCostLimit: '',
weeklyOpusCostLimit: '',
weeklyGPT5HighCostLimit: '', // 新增GPT-5 High推理级别周费用限制
expireDuration: '',
customExpireDate: '',
expiresAt: null,
@@ -877,7 +973,8 @@ const form = reactive({
modelInput: '',
enableClientRestriction: false,
allowedClients: [],
tags: []
tags: [],
icon: '' // 新增图标base64编码
})
// 加载支持的客户端和已存在的标签
@@ -898,6 +995,35 @@ onMounted(async () => {
}
})
// 处理图标上传
const handleIconUpload = (event) => {
const file = event.target.files?.[0]
if (!file) return
// 检查文件类型
if (!file.type.startsWith('image/')) {
ElMessage.error('请选择图片文件')
return
}
// 检查文件大小 (限制为 2MB)
if (file.size > 2 * 1024 * 1024) {
ElMessage.error('图片大小不能超过 2MB')
return
}
// 读取文件并转换为 base64
const reader = new FileReader()
reader.onload = (e) => {
form.icon = e.target.result
ElMessage.success('图标上传成功')
}
reader.onerror = () => {
ElMessage.error('图标上传失败')
}
reader.readAsDataURL(file)
}
// 刷新账号列表
const refreshAccounts = async () => {
accountsLoading.value = true
@@ -1052,7 +1178,22 @@ const removeRestrictedModel = (index) => {
}
// 常用模型列表
const commonModels = ref(['claude-opus-4-20250514', 'claude-opus-4-1-20250805'])
const commonModels = ref([
// Claude 模型
'claude-opus-4-20250514',
'claude-opus-4-1-20250805',
// OpenAI 模型
'gpt-5',
'gpt-5 minimal',
'gpt-5 low',
'gpt-5 medium',
'gpt-5 high',
'gpt-4o',
'gpt-4o-mini',
'o1',
'o1-mini',
'o1-preview'
])
// 可用的快捷模型(过滤掉已在限制列表中的)
const availableQuickModels = computed(() => {
@@ -1155,6 +1296,11 @@ const createApiKey = async () => {
form.weeklyOpusCostLimit !== '' && form.weeklyOpusCostLimit !== null
? parseFloat(form.weeklyOpusCostLimit)
: 0,
// 新增GPT-5 High推理级别周费用限制
weeklyGPT5HighCostLimit:
form.weeklyGPT5HighCostLimit !== '' && form.weeklyGPT5HighCostLimit !== null
? parseFloat(form.weeklyGPT5HighCostLimit)
: 0,
expiresAt: form.expirationMode === 'fixed' ? form.expiresAt || undefined : undefined,
expirationMode: form.expirationMode,
activationDays: form.expirationMode === 'activation' ? form.activationDays : undefined,
@@ -1163,7 +1309,8 @@ const createApiKey = async () => {
enableModelRestriction: form.enableModelRestriction,
restrictedModels: form.restrictedModels,
enableClientRestriction: form.enableClientRestriction,
allowedClients: form.allowedClients
allowedClients: form.allowedClients,
icon: form.icon || undefined // 新增:图标
}
// 处理Claude账户绑定区分OAuth和Console