feat: 实现OpenAI账户管理和统一调度系统

- 新增 OpenAI 账户管理服务,支持多账户轮询和负载均衡
- 实现统一的 OpenAI API 调度器,智能选择最优账户
- 优化成本计算器,支持更精确的 token 计算
- 更新模型定价数据,包含最新的 OpenAI 模型价格
- 增强 API Key 管理,支持更灵活的配额控制
- 改进管理界面,添加教程视图和账户分组管理
- 优化限流配置组件,提供更直观的用户体验

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
shaw
2025-08-11 13:58:43 +08:00
parent f22a38d24a
commit f462684f97
22 changed files with 6163 additions and 3134 deletions

View File

@@ -371,6 +371,10 @@
<input v-model="form.permissions" class="mr-2" type="radio" value="gemini" />
<span class="text-sm text-gray-700"> Gemini</span>
</label>
<label class="flex cursor-pointer items-center">
<input v-model="form.permissions" class="mr-2" type="radio" value="openai" />
<span class="text-sm text-gray-700"> OpenAI</span>
</label>
</div>
<p class="mt-2 text-xs text-gray-500">控制此 API Key 可以访问哪些服务</p>
</div>
@@ -402,7 +406,7 @@
v-model="form.claudeAccountId"
:accounts="localAccounts.claude"
default-option-text="使用共享账号池"
:disabled="form.permissions === 'gemini'"
:disabled="form.permissions === 'gemini' || form.permissions === 'openai'"
:groups="localAccounts.claudeGroups"
placeholder="请选择Claude账号"
platform="claude"
@@ -414,12 +418,24 @@
v-model="form.geminiAccountId"
:accounts="localAccounts.gemini"
default-option-text="使用共享账号池"
:disabled="form.permissions === 'claude'"
:disabled="form.permissions === 'claude' || form.permissions === 'openai'"
:groups="localAccounts.geminiGroups"
placeholder="请选择Gemini账号"
platform="gemini"
/>
</div>
<div>
<label class="mb-1 block text-sm font-medium text-gray-600">OpenAI 专属账号</label>
<AccountSelector
v-model="form.openaiAccountId"
:accounts="localAccounts.openai"
default-option-text="使用共享账号池"
:disabled="form.permissions === 'claude' || form.permissions === 'gemini'"
:groups="localAccounts.openaiGroups"
placeholder="请选择OpenAI账号"
platform="openai"
/>
</div>
</div>
<p class="mt-2 text-xs text-gray-500">
选择专属账号后此API Key将只使用该账号不选择则使用共享账号池
@@ -598,7 +614,14 @@ const clientsStore = useClientsStore()
const apiKeysStore = useApiKeysStore()
const loading = ref(false)
const accountsLoading = ref(false)
const localAccounts = ref({ claude: [], gemini: [], claudeGroups: [], geminiGroups: [] })
const localAccounts = ref({
claude: [],
gemini: [],
openai: [],
claudeGroups: [],
geminiGroups: [],
openaiGroups: []
})
// 表单验证状态
const errors = ref({
@@ -634,6 +657,7 @@ const form = reactive({
permissions: 'all',
claudeAccountId: '',
geminiAccountId: '',
openaiAccountId: '',
enableModelRestriction: false,
restrictedModels: [],
modelInput: '',
@@ -651,8 +675,10 @@ onMounted(async () => {
localAccounts.value = {
claude: props.accounts.claude || [],
gemini: props.accounts.gemini || [],
openai: props.accounts.openai || [],
claudeGroups: props.accounts.claudeGroups || [],
geminiGroups: props.accounts.geminiGroups || []
geminiGroups: props.accounts.geminiGroups || [],
openaiGroups: props.accounts.openaiGroups || []
}
}
})
@@ -661,10 +687,11 @@ onMounted(async () => {
const refreshAccounts = async () => {
accountsLoading.value = true
try {
const [claudeData, claudeConsoleData, geminiData, groupsData] = await Promise.all([
const [claudeData, claudeConsoleData, geminiData, openaiData, groupsData] = await Promise.all([
apiClient.get('/admin/claude-accounts'),
apiClient.get('/admin/claude-console-accounts'),
apiClient.get('/admin/gemini-accounts'),
apiClient.get('/admin/openai-accounts'),
apiClient.get('/admin/account-groups')
])
@@ -700,11 +727,19 @@ const refreshAccounts = async () => {
}))
}
if (openaiData.success) {
localAccounts.value.openai = (openaiData.data || []).map((account) => ({
...account,
isDedicated: account.accountType === 'dedicated' // 保留以便向后兼容
}))
}
// 处理分组数据
if (groupsData.success) {
const allGroups = groupsData.data || []
localAccounts.value.claudeGroups = allGroups.filter((g) => g.platform === 'claude')
localAccounts.value.geminiGroups = allGroups.filter((g) => g.platform === 'gemini')
localAccounts.value.openaiGroups = allGroups.filter((g) => g.platform === 'openai')
}
showToast('账号列表已刷新', 'success')
@@ -899,6 +934,11 @@ const createApiKey = async () => {
baseData.geminiAccountId = form.geminiAccountId
}
// OpenAI账户绑定
if (form.openaiAccountId) {
baseData.openaiAccountId = form.openaiAccountId
}
if (form.createType === 'single') {
// 单个创建
const data = {