Merge branch 'main' into feature/antigravity_auth

This commit is contained in:
song
2025-12-29 17:04:40 +08:00
40 changed files with 1045 additions and 288 deletions

View File

@@ -585,7 +585,7 @@
: 'https://api.anthropic.com'
"
/>
<p class="input-hint">{{ t('admin.accounts.baseUrlHint') }}</p>
<p class="input-hint">{{ baseUrlHint }}</p>
</div>
<div>
<label class="input-label">{{ t('admin.accounts.apiKeyRequired') }}</label>
@@ -602,13 +602,7 @@
: 'sk-ant-...'
"
/>
<p class="input-hint">
{{
form.platform === 'gemini'
? t('admin.accounts.gemini.apiKeyHint')
: t('admin.accounts.apiKeyHint')
}}
</p>
<p class="input-hint">{{ apiKeyHint }}</p>
</div>
<!-- Model Restriction Section (不适用于 Gemini) -->
@@ -1055,8 +1049,9 @@
</div>
</div>
<!-- Group Selection -->
<!-- Group Selection - 仅标准模式显示 -->
<GroupSelector
v-if="!authStore.isSimpleMode"
v-model="form.group_ids"
:groups="groups"
:platform="form.platform"
@@ -1172,6 +1167,7 @@
import { ref, reactive, computed, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useAppStore } from '@/stores/app'
import { useAuthStore } from '@/stores/auth'
import { adminAPI } from '@/api/admin'
import {
useAccountOAuth,
@@ -1199,6 +1195,7 @@ interface OAuthFlowExposed {
}
const { t } = useI18n()
const authStore = useAuthStore()
const oauthStepTitle = computed(() => {
if (form.platform === 'openai') return t('admin.accounts.oauth.openai.title')
@@ -1207,6 +1204,19 @@ const oauthStepTitle = computed(() => {
return t('admin.accounts.oauth.title')
})
// Platform-specific hints for API Key type
const baseUrlHint = computed(() => {
if (form.platform === 'openai') return t('admin.accounts.openai.baseUrlHint')
if (form.platform === 'gemini') return t('admin.accounts.gemini.baseUrlHint')
return t('admin.accounts.baseUrlHint')
})
const apiKeyHint = computed(() => {
if (form.platform === 'openai') return t('admin.accounts.openai.apiKeyHint')
if (form.platform === 'gemini') return t('admin.accounts.gemini.apiKeyHint')
return t('admin.accounts.apiKeyHint')
})
interface Props {
show: boolean
proxies: Proxy[]

View File

@@ -32,7 +32,7 @@
: 'https://api.anthropic.com'
"
/>
<p class="input-hint">{{ t('admin.accounts.baseUrlHint') }}</p>
<p class="input-hint">{{ baseUrlHint }}</p>
</div>
<div>
<label class="input-label">{{ t('admin.accounts.apiKey') }}</label>
@@ -497,8 +497,9 @@
</div>
</div>
<!-- Group Selection -->
<!-- Group Selection - 仅标准模式显示 -->
<GroupSelector
v-if="!authStore.isSimpleMode"
v-model="form.group_ids"
:groups="groups"
:platform="account?.platform"
@@ -549,6 +550,7 @@
import { ref, reactive, computed, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useAppStore } from '@/stores/app'
import { useAuthStore } from '@/stores/auth'
import { adminAPI } from '@/api/admin'
import type { Account, Proxy, Group } from '@/types'
import BaseDialog from '@/components/common/BaseDialog.vue'
@@ -571,6 +573,15 @@ const emit = defineEmits<{
const { t } = useI18n()
const appStore = useAppStore()
const authStore = useAuthStore()
// Platform-specific hint for Base URL
const baseUrlHint = computed(() => {
if (!props.account) return t('admin.accounts.baseUrlHint')
if (props.account.platform === 'openai') return t('admin.accounts.openai.baseUrlHint')
if (props.account.platform === 'gemini') return t('admin.accounts.gemini.baseUrlHint')
return t('admin.accounts.baseUrlHint')
})
// Model mapping type
interface ModelMapping {

View File

@@ -297,7 +297,7 @@ onUnmounted(() => {
}
.select-dropdown {
@apply absolute z-[100] mt-2 w-full;
@apply absolute left-0 z-[100] mt-2 min-w-full w-max max-w-[300px];
@apply bg-white dark:bg-dark-800;
@apply rounded-xl;
@apply border border-gray-200 dark:border-dark-700;
@@ -339,7 +339,7 @@ onUnmounted(() => {
}
.select-option-label {
@apply truncate;
@apply flex-1 min-w-0 truncate text-left;
}
.select-empty {

View File

@@ -45,8 +45,8 @@
</router-link>
</div>
<!-- Personal Section for Admin -->
<div class="sidebar-section">
<!-- Personal Section for Admin (hidden in simple mode) -->
<div v-if="!authStore.isSimpleMode" class="sidebar-section">
<div v-if="!sidebarCollapsed" class="sidebar-section-title">
{{ t('nav.myAccount') }}
</div>
@@ -402,36 +402,54 @@ const ChevronDoubleRightIcon = {
}
// User navigation items (for regular users)
const userNavItems = computed(() => [
{ path: '/dashboard', label: t('nav.dashboard'), icon: DashboardIcon },
{ path: '/keys', label: t('nav.apiKeys'), icon: KeyIcon },
{ path: '/usage', label: t('nav.usage'), icon: ChartIcon },
{ path: '/subscriptions', label: t('nav.mySubscriptions'), icon: CreditCardIcon },
{ path: '/redeem', label: t('nav.redeem'), icon: GiftIcon },
{ path: '/profile', label: t('nav.profile'), icon: UserIcon }
])
const userNavItems = computed(() => {
const items = [
{ path: '/dashboard', label: t('nav.dashboard'), icon: DashboardIcon },
{ path: '/keys', label: t('nav.apiKeys'), icon: KeyIcon },
{ path: '/usage', label: t('nav.usage'), icon: ChartIcon, hideInSimpleMode: true },
{ path: '/subscriptions', label: t('nav.mySubscriptions'), icon: CreditCardIcon, hideInSimpleMode: true },
{ path: '/redeem', label: t('nav.redeem'), icon: GiftIcon, hideInSimpleMode: true },
{ path: '/profile', label: t('nav.profile'), icon: UserIcon }
]
return authStore.isSimpleMode ? items.filter(item => !item.hideInSimpleMode) : items
})
// Personal navigation items (for admin's "My Account" section, without Dashboard)
const personalNavItems = computed(() => [
{ path: '/keys', label: t('nav.apiKeys'), icon: KeyIcon },
{ path: '/usage', label: t('nav.usage'), icon: ChartIcon },
{ path: '/subscriptions', label: t('nav.mySubscriptions'), icon: CreditCardIcon },
{ path: '/redeem', label: t('nav.redeem'), icon: GiftIcon },
{ path: '/profile', label: t('nav.profile'), icon: UserIcon }
])
const personalNavItems = computed(() => {
const items = [
{ path: '/keys', label: t('nav.apiKeys'), icon: KeyIcon },
{ path: '/usage', label: t('nav.usage'), icon: ChartIcon, hideInSimpleMode: true },
{ path: '/subscriptions', label: t('nav.mySubscriptions'), icon: CreditCardIcon, hideInSimpleMode: true },
{ path: '/redeem', label: t('nav.redeem'), icon: GiftIcon, hideInSimpleMode: true },
{ path: '/profile', label: t('nav.profile'), icon: UserIcon }
]
return authStore.isSimpleMode ? items.filter(item => !item.hideInSimpleMode) : items
})
// Admin navigation items
const adminNavItems = computed(() => [
{ path: '/admin/dashboard', label: t('nav.dashboard'), icon: DashboardIcon },
{ path: '/admin/users', label: t('nav.users'), icon: UsersIcon },
{ path: '/admin/groups', label: t('nav.groups'), icon: FolderIcon },
{ path: '/admin/subscriptions', label: t('nav.subscriptions'), icon: CreditCardIcon },
{ path: '/admin/accounts', label: t('nav.accounts'), icon: GlobeIcon },
{ path: '/admin/proxies', label: t('nav.proxies'), icon: ServerIcon },
{ path: '/admin/redeem', label: t('nav.redeemCodes'), icon: TicketIcon },
{ path: '/admin/usage', label: t('nav.usage'), icon: ChartIcon },
{ path: '/admin/settings', label: t('nav.settings'), icon: CogIcon }
])
const adminNavItems = computed(() => {
const baseItems = [
{ path: '/admin/dashboard', label: t('nav.dashboard'), icon: DashboardIcon },
{ path: '/admin/users', label: t('nav.users'), icon: UsersIcon, hideInSimpleMode: true },
{ path: '/admin/groups', label: t('nav.groups'), icon: FolderIcon, hideInSimpleMode: true },
{ path: '/admin/subscriptions', label: t('nav.subscriptions'), icon: CreditCardIcon, hideInSimpleMode: true },
{ path: '/admin/accounts', label: t('nav.accounts'), icon: GlobeIcon },
{ path: '/admin/proxies', label: t('nav.proxies'), icon: ServerIcon },
{ path: '/admin/redeem', label: t('nav.redeemCodes'), icon: TicketIcon, hideInSimpleMode: true },
{ path: '/admin/usage', label: t('nav.usage'), icon: ChartIcon },
]
// 简单模式下,在系统设置前插入 API密钥
if (authStore.isSimpleMode) {
const filtered = baseItems.filter(item => !item.hideInSimpleMode)
filtered.push({ path: '/keys', label: t('nav.apiKeys'), icon: KeyIcon })
filtered.push({ path: '/admin/settings', label: t('nav.settings'), icon: CogIcon })
return filtered
}
baseItems.push({ path: '/admin/settings', label: t('nav.settings'), icon: CogIcon })
return baseItems
})
function toggleSidebar() {
appStore.toggleSidebar()