mirror of
https://gitee.com/wanwujie/sub2api
synced 2026-04-20 22:54:45 +08:00
feat: apikey使用弹出适配codex分组
This commit is contained in:
@@ -6,16 +6,33 @@
|
|||||||
@close="emit('close')"
|
@close="emit('close')"
|
||||||
>
|
>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
|
<!-- No Group Assigned Warning -->
|
||||||
|
<div v-if="!platform" class="flex items-start gap-3 p-4 rounded-lg bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800">
|
||||||
|
<svg class="w-5 h-5 text-yellow-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" />
|
||||||
|
</svg>
|
||||||
|
<div>
|
||||||
|
<p class="text-sm font-medium text-yellow-800 dark:text-yellow-200">
|
||||||
|
{{ t('keys.useKeyModal.noGroupTitle') }}
|
||||||
|
</p>
|
||||||
|
<p class="text-sm text-yellow-700 dark:text-yellow-300 mt-1">
|
||||||
|
{{ t('keys.useKeyModal.noGroupDescription') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Platform-specific content -->
|
||||||
|
<template v-else>
|
||||||
<!-- Description -->
|
<!-- Description -->
|
||||||
<p class="text-sm text-gray-600 dark:text-gray-400">
|
<p class="text-sm text-gray-600 dark:text-gray-400">
|
||||||
{{ t('keys.useKeyModal.description') }}
|
{{ platformDescription }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- OS Tabs -->
|
<!-- OS Tabs -->
|
||||||
<div class="border-b border-gray-200 dark:border-dark-700">
|
<div class="border-b border-gray-200 dark:border-dark-700">
|
||||||
<nav class="-mb-px flex space-x-4" aria-label="Tabs">
|
<nav class="-mb-px flex space-x-4" aria-label="Tabs">
|
||||||
<button
|
<button
|
||||||
v-for="tab in tabs"
|
v-for="tab in currentTabs"
|
||||||
:key="tab.id"
|
:key="tab.id"
|
||||||
@click="activeTab = tab.id"
|
@click="activeTab = tab.id"
|
||||||
:class="[
|
:class="[
|
||||||
@@ -33,30 +50,43 @@
|
|||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Code Block -->
|
<!-- Code Blocks (Stacked for multi-file platforms) -->
|
||||||
<div class="relative">
|
<div class="space-y-4">
|
||||||
|
<div
|
||||||
|
v-for="(file, index) in currentFiles"
|
||||||
|
:key="index"
|
||||||
|
class="relative"
|
||||||
|
>
|
||||||
|
<!-- File Hint (if exists) -->
|
||||||
|
<p v-if="file.hint" class="text-xs text-amber-600 dark:text-amber-400 mb-1.5 flex items-center gap-1">
|
||||||
|
<svg class="w-3.5 h-3.5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" />
|
||||||
|
</svg>
|
||||||
|
{{ file.hint }}
|
||||||
|
</p>
|
||||||
<div class="bg-gray-900 dark:bg-dark-900 rounded-xl overflow-hidden">
|
<div class="bg-gray-900 dark:bg-dark-900 rounded-xl overflow-hidden">
|
||||||
<!-- Code Header -->
|
<!-- Code Header -->
|
||||||
<div class="flex items-center justify-between px-4 py-2 bg-gray-800 dark:bg-dark-800 border-b border-gray-700 dark:border-dark-700">
|
<div class="flex items-center justify-between px-4 py-2 bg-gray-800 dark:bg-dark-800 border-b border-gray-700 dark:border-dark-700">
|
||||||
<span class="text-xs text-gray-400 font-mono">{{ activeTabConfig?.filename }}</span>
|
<span class="text-xs text-gray-400 font-mono">{{ file.path }}</span>
|
||||||
<button
|
<button
|
||||||
@click="copyConfig"
|
@click="copyContent(file.content, index)"
|
||||||
class="flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium rounded-lg transition-colors"
|
class="flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium rounded-lg transition-colors"
|
||||||
:class="copied
|
:class="copiedIndex === index
|
||||||
? 'bg-green-500/20 text-green-400'
|
? 'bg-green-500/20 text-green-400'
|
||||||
: 'bg-gray-700 hover:bg-gray-600 text-gray-300 hover:text-white'"
|
: 'bg-gray-700 hover:bg-gray-600 text-gray-300 hover:text-white'"
|
||||||
>
|
>
|
||||||
<svg v-if="copied" class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
|
<svg v-if="copiedIndex === index" class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
|
||||||
</svg>
|
</svg>
|
||||||
<svg v-else class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
|
<svg v-else class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184" />
|
||||||
</svg>
|
</svg>
|
||||||
{{ copied ? t('keys.useKeyModal.copied') : t('keys.useKeyModal.copy') }}
|
{{ copiedIndex === index ? t('keys.useKeyModal.copied') : t('keys.useKeyModal.copy') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<!-- Code Content -->
|
<!-- Code Content -->
|
||||||
<pre class="p-4 text-sm font-mono text-gray-100 overflow-x-auto"><code v-html="highlightedCode"></code></pre>
|
<pre class="p-4 text-sm font-mono text-gray-100 overflow-x-auto"><code v-html="file.highlighted"></code></pre>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -66,9 +96,10 @@
|
|||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" />
|
||||||
</svg>
|
</svg>
|
||||||
<p class="text-sm text-blue-700 dark:text-blue-300">
|
<p class="text-sm text-blue-700 dark:text-blue-300">
|
||||||
{{ t('keys.useKeyModal.note') }}
|
{{ platformNote }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@@ -85,29 +116,53 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, h } from 'vue'
|
import { ref, computed, h, watch, type Component } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import Modal from '@/components/common/Modal.vue'
|
import Modal from '@/components/common/Modal.vue'
|
||||||
import { useAppStore } from '@/stores/app'
|
import { useAppStore } from '@/stores/app'
|
||||||
|
import type { GroupPlatform } from '@/types'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
show: boolean
|
show: boolean
|
||||||
apiKey: string
|
apiKey: string
|
||||||
baseUrl: string
|
baseUrl: string
|
||||||
|
platform: GroupPlatform | null
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Emits {
|
interface Emits {
|
||||||
(e: 'close'): void
|
(e: 'close'): void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface TabConfig {
|
||||||
|
id: string
|
||||||
|
label: string
|
||||||
|
icon: Component
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FileConfig {
|
||||||
|
path: string
|
||||||
|
content: string
|
||||||
|
highlighted: string
|
||||||
|
hint?: string // Optional hint message for this file
|
||||||
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>()
|
const props = defineProps<Props>()
|
||||||
const emit = defineEmits<Emits>()
|
const emit = defineEmits<Emits>()
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
|
|
||||||
const copied = ref(false)
|
const copiedIndex = ref<number | null>(null)
|
||||||
const activeTab = ref<'unix' | 'cmd' | 'powershell'>('unix')
|
const activeTab = ref<string>('unix')
|
||||||
|
|
||||||
|
// Reset active tab when platform changes
|
||||||
|
watch(() => props.platform, (newPlatform) => {
|
||||||
|
if (newPlatform === 'openai') {
|
||||||
|
activeTab.value = 'unix'
|
||||||
|
} else {
|
||||||
|
activeTab.value = 'unix'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// Icon components
|
// Icon components
|
||||||
const AppleIcon = {
|
const AppleIcon = {
|
||||||
@@ -134,64 +189,162 @@ const WindowsIcon = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabs = [
|
// Anthropic tabs (3 shell types)
|
||||||
{ id: 'unix' as const, label: 'macOS / Linux', icon: AppleIcon, filename: 'Terminal' },
|
const anthropicTabs: TabConfig[] = [
|
||||||
{ id: 'cmd' as const, label: 'Windows CMD', icon: WindowsIcon, filename: 'Command Prompt' },
|
{ id: 'unix', label: 'macOS / Linux', icon: AppleIcon },
|
||||||
{ id: 'powershell' as const, label: 'PowerShell', icon: WindowsIcon, filename: 'PowerShell' }
|
{ id: 'cmd', label: 'Windows CMD', icon: WindowsIcon },
|
||||||
|
{ id: 'powershell', label: 'PowerShell', icon: WindowsIcon }
|
||||||
]
|
]
|
||||||
|
|
||||||
const activeTabConfig = computed(() => tabs.find(tab => tab.id === activeTab.value))
|
// OpenAI tabs (2 OS types)
|
||||||
|
const openaiTabs: TabConfig[] = [
|
||||||
|
{ id: 'unix', label: 'macOS / Linux', icon: AppleIcon },
|
||||||
|
{ id: 'windows', label: 'Windows', icon: WindowsIcon }
|
||||||
|
]
|
||||||
|
|
||||||
const configCode = computed(() => {
|
const currentTabs = computed(() => {
|
||||||
|
if (props.platform === 'openai') {
|
||||||
|
return openaiTabs
|
||||||
|
}
|
||||||
|
return anthropicTabs
|
||||||
|
})
|
||||||
|
|
||||||
|
const platformDescription = computed(() => {
|
||||||
|
if (props.platform === 'openai') {
|
||||||
|
return t('keys.useKeyModal.openai.description')
|
||||||
|
}
|
||||||
|
return t('keys.useKeyModal.description')
|
||||||
|
})
|
||||||
|
|
||||||
|
const platformNote = computed(() => {
|
||||||
|
if (props.platform === 'openai') {
|
||||||
|
if (activeTab.value === 'windows') {
|
||||||
|
return t('keys.useKeyModal.openai.noteWindows')
|
||||||
|
}
|
||||||
|
return t('keys.useKeyModal.openai.note')
|
||||||
|
}
|
||||||
|
return t('keys.useKeyModal.note')
|
||||||
|
})
|
||||||
|
|
||||||
|
// Syntax highlighting helpers
|
||||||
|
const keyword = (text: string) => `<span class="text-purple-400">${text}</span>`
|
||||||
|
const variable = (text: string) => `<span class="text-cyan-400">${text}</span>`
|
||||||
|
const string = (text: string) => `<span class="text-green-400">${text}</span>`
|
||||||
|
const operator = (text: string) => `<span class="text-yellow-400">${text}</span>`
|
||||||
|
const comment = (text: string) => `<span class="text-gray-500">${text}</span>`
|
||||||
|
const key = (text: string) => `<span class="text-blue-400">${text}</span>`
|
||||||
|
|
||||||
|
// Generate file configs based on platform and active tab
|
||||||
|
const currentFiles = computed((): FileConfig[] => {
|
||||||
const baseUrl = props.baseUrl || window.location.origin
|
const baseUrl = props.baseUrl || window.location.origin
|
||||||
const apiKey = props.apiKey
|
const apiKey = props.apiKey
|
||||||
|
|
||||||
|
if (props.platform === 'openai') {
|
||||||
|
return generateOpenAIFiles(baseUrl, apiKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
return generateAnthropicFiles(baseUrl, apiKey)
|
||||||
|
})
|
||||||
|
|
||||||
|
function generateAnthropicFiles(baseUrl: string, apiKey: string): FileConfig[] {
|
||||||
|
let path: string
|
||||||
|
let content: string
|
||||||
|
let highlighted: string
|
||||||
|
|
||||||
switch (activeTab.value) {
|
switch (activeTab.value) {
|
||||||
case 'unix':
|
case 'unix':
|
||||||
return `export ANTHROPIC_BASE_URL="${baseUrl}"
|
path = 'Terminal'
|
||||||
|
content = `export ANTHROPIC_BASE_URL="${baseUrl}"
|
||||||
export ANTHROPIC_AUTH_TOKEN="${apiKey}"`
|
export ANTHROPIC_AUTH_TOKEN="${apiKey}"`
|
||||||
case 'cmd':
|
highlighted = `${keyword('export')} ${variable('ANTHROPIC_BASE_URL')}${operator('=')}${string(`"${baseUrl}"`)}
|
||||||
return `set ANTHROPIC_BASE_URL=${baseUrl}
|
|
||||||
set ANTHROPIC_AUTH_TOKEN=${apiKey}`
|
|
||||||
case 'powershell':
|
|
||||||
return `$env:ANTHROPIC_BASE_URL="${baseUrl}"
|
|
||||||
$env:ANTHROPIC_AUTH_TOKEN="${apiKey}"`
|
|
||||||
default:
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const highlightedCode = computed(() => {
|
|
||||||
const baseUrl = props.baseUrl || window.location.origin
|
|
||||||
const apiKey = props.apiKey
|
|
||||||
|
|
||||||
// Build highlighted code directly to avoid regex replacement conflicts
|
|
||||||
const keyword = (text: string) => `<span class="text-purple-400">${text}</span>`
|
|
||||||
const variable = (text: string) => `<span class="text-cyan-400">${text}</span>`
|
|
||||||
const string = (text: string) => `<span class="text-green-400">${text}</span>`
|
|
||||||
const operator = (text: string) => `<span class="text-yellow-400">${text}</span>`
|
|
||||||
|
|
||||||
switch (activeTab.value) {
|
|
||||||
case 'unix':
|
|
||||||
return `${keyword('export')} ${variable('ANTHROPIC_BASE_URL')}${operator('=')}${string(`"${baseUrl}"`)}
|
|
||||||
${keyword('export')} ${variable('ANTHROPIC_AUTH_TOKEN')}${operator('=')}${string(`"${apiKey}"`)}`
|
${keyword('export')} ${variable('ANTHROPIC_AUTH_TOKEN')}${operator('=')}${string(`"${apiKey}"`)}`
|
||||||
|
break
|
||||||
case 'cmd':
|
case 'cmd':
|
||||||
return `${keyword('set')} ${variable('ANTHROPIC_BASE_URL')}${operator('=')}${baseUrl}
|
path = 'Command Prompt'
|
||||||
|
content = `set ANTHROPIC_BASE_URL=${baseUrl}
|
||||||
|
set ANTHROPIC_AUTH_TOKEN=${apiKey}`
|
||||||
|
highlighted = `${keyword('set')} ${variable('ANTHROPIC_BASE_URL')}${operator('=')}${baseUrl}
|
||||||
${keyword('set')} ${variable('ANTHROPIC_AUTH_TOKEN')}${operator('=')}${apiKey}`
|
${keyword('set')} ${variable('ANTHROPIC_AUTH_TOKEN')}${operator('=')}${apiKey}`
|
||||||
|
break
|
||||||
case 'powershell':
|
case 'powershell':
|
||||||
return `${keyword('$env:')}${variable('ANTHROPIC_BASE_URL')}${operator('=')}${string(`"${baseUrl}"`)}
|
path = 'PowerShell'
|
||||||
|
content = `$env:ANTHROPIC_BASE_URL="${baseUrl}"
|
||||||
|
$env:ANTHROPIC_AUTH_TOKEN="${apiKey}"`
|
||||||
|
highlighted = `${keyword('$env:')}${variable('ANTHROPIC_BASE_URL')}${operator('=')}${string(`"${baseUrl}"`)}
|
||||||
${keyword('$env:')}${variable('ANTHROPIC_AUTH_TOKEN')}${operator('=')}${string(`"${apiKey}"`)}`
|
${keyword('$env:')}${variable('ANTHROPIC_AUTH_TOKEN')}${operator('=')}${string(`"${apiKey}"`)}`
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
return ''
|
path = 'Terminal'
|
||||||
|
content = ''
|
||||||
|
highlighted = ''
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
const copyConfig = async () => {
|
return [{ path, content, highlighted }]
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateOpenAIFiles(baseUrl: string, apiKey: string): FileConfig[] {
|
||||||
|
const isWindows = activeTab.value === 'windows'
|
||||||
|
const configDir = isWindows ? '%userprofile%\\.codex' : '~/.codex'
|
||||||
|
|
||||||
|
// config.toml content
|
||||||
|
const configContent = `model_provider = "sub2api"
|
||||||
|
model = "gpt-5.2-codex"
|
||||||
|
model_reasoning_effort = "high"
|
||||||
|
network_access = "enabled"
|
||||||
|
disable_response_storage = true
|
||||||
|
windows_wsl_setup_acknowledged = true
|
||||||
|
model_verbosity = "high"
|
||||||
|
|
||||||
|
[model_providers.sub2api]
|
||||||
|
name = "sub2api"
|
||||||
|
base_url = "${baseUrl}"
|
||||||
|
wire_api = "responses"
|
||||||
|
requires_openai_auth = true`
|
||||||
|
|
||||||
|
const configHighlighted = `${key('model_provider')} ${operator('=')} ${string('"sub2api"')}
|
||||||
|
${key('model')} ${operator('=')} ${string('"gpt-5.2-codex"')}
|
||||||
|
${key('model_reasoning_effort')} ${operator('=')} ${string('"high"')}
|
||||||
|
${key('network_access')} ${operator('=')} ${string('"enabled"')}
|
||||||
|
${key('disable_response_storage')} ${operator('=')} ${keyword('true')}
|
||||||
|
${key('windows_wsl_setup_acknowledged')} ${operator('=')} ${keyword('true')}
|
||||||
|
${key('model_verbosity')} ${operator('=')} ${string('"high"')}
|
||||||
|
|
||||||
|
${comment('[model_providers.sub2api]')}
|
||||||
|
${key('name')} ${operator('=')} ${string('"sub2api"')}
|
||||||
|
${key('base_url')} ${operator('=')} ${string(`"${baseUrl}"`)}
|
||||||
|
${key('wire_api')} ${operator('=')} ${string('"responses"')}
|
||||||
|
${key('requires_openai_auth')} ${operator('=')} ${keyword('true')}`
|
||||||
|
|
||||||
|
// auth.json content
|
||||||
|
const authContent = `{
|
||||||
|
"OPENAI_API_KEY": "${apiKey}"
|
||||||
|
}`
|
||||||
|
|
||||||
|
const authHighlighted = `{
|
||||||
|
${key('"OPENAI_API_KEY"')}: ${string(`"${apiKey}"`)}
|
||||||
|
}`
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
path: `${configDir}/config.toml`,
|
||||||
|
content: configContent,
|
||||||
|
highlighted: configHighlighted,
|
||||||
|
hint: t('keys.useKeyModal.openai.configTomlHint')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: `${configDir}/auth.json`,
|
||||||
|
content: authContent,
|
||||||
|
highlighted: authHighlighted
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const copyContent = async (content: string, index: number) => {
|
||||||
try {
|
try {
|
||||||
await navigator.clipboard.writeText(configCode.value)
|
await navigator.clipboard.writeText(content)
|
||||||
copied.value = true
|
copiedIndex.value = index
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
copied.value = false
|
copiedIndex.value = null
|
||||||
}, 2000)
|
}, 2000)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
appStore.showError(t('common.copyFailed'))
|
appStore.showError(t('common.copyFailed'))
|
||||||
|
|||||||
@@ -243,6 +243,14 @@ export default {
|
|||||||
copy: 'Copy',
|
copy: 'Copy',
|
||||||
copied: 'Copied',
|
copied: 'Copied',
|
||||||
note: 'These environment variables will be active in the current terminal session. For permanent configuration, add them to ~/.bashrc, ~/.zshrc, or the appropriate configuration file.',
|
note: 'These environment variables will be active in the current terminal session. For permanent configuration, add them to ~/.bashrc, ~/.zshrc, or the appropriate configuration file.',
|
||||||
|
noGroupTitle: 'Please assign a group first',
|
||||||
|
noGroupDescription: 'This API key has not been assigned to a group. Please click the group column in the key list to assign one before viewing the configuration.',
|
||||||
|
openai: {
|
||||||
|
description: 'Add the following configuration files to your Codex CLI config directory.',
|
||||||
|
configTomlHint: 'Make sure the following content is at the beginning of the config.toml file',
|
||||||
|
note: 'Make sure the config directory exists. macOS/Linux users can run mkdir -p ~/.codex to create it.',
|
||||||
|
noteWindows: 'Press Win+R and enter %userprofile%\\.codex to open the config directory. Create it manually if it does not exist.',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
customKeyLabel: 'Custom Key',
|
customKeyLabel: 'Custom Key',
|
||||||
customKeyPlaceholder: 'Enter your custom key (min 16 chars)',
|
customKeyPlaceholder: 'Enter your custom key (min 16 chars)',
|
||||||
|
|||||||
@@ -239,6 +239,14 @@ export default {
|
|||||||
copy: '复制',
|
copy: '复制',
|
||||||
copied: '已复制',
|
copied: '已复制',
|
||||||
note: '这些环境变量将在当前终端会话中生效。如需永久配置,请将其添加到 ~/.bashrc、~/.zshrc 或相应的配置文件中。',
|
note: '这些环境变量将在当前终端会话中生效。如需永久配置,请将其添加到 ~/.bashrc、~/.zshrc 或相应的配置文件中。',
|
||||||
|
noGroupTitle: '请先分配分组',
|
||||||
|
noGroupDescription: '此 API 密钥尚未分配分组,请先在密钥列表中点击分组列进行分配,然后才能查看使用配置。',
|
||||||
|
openai: {
|
||||||
|
description: '将以下配置文件添加到 Codex CLI 配置目录中。',
|
||||||
|
configTomlHint: '请确保以下内容位于 config.toml 文件的开头部分',
|
||||||
|
note: '请确保配置目录存在。macOS/Linux 用户可运行 mkdir -p ~/.codex 创建目录。',
|
||||||
|
noteWindows: '按 Win+R,输入 %userprofile%\\.codex 打开配置目录。如目录不存在,请先手动创建。',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
customKeyLabel: '自定义密钥',
|
customKeyLabel: '自定义密钥',
|
||||||
customKeyPlaceholder: '输入自定义密钥(至少16个字符)',
|
customKeyPlaceholder: '输入自定义密钥(至少16个字符)',
|
||||||
|
|||||||
@@ -336,6 +336,7 @@
|
|||||||
:show="showUseKeyModal"
|
:show="showUseKeyModal"
|
||||||
:api-key="selectedKey?.key || ''"
|
:api-key="selectedKey?.key || ''"
|
||||||
:base-url="publicSettings?.api_base_url || ''"
|
:base-url="publicSettings?.api_base_url || ''"
|
||||||
|
:platform="selectedKey?.group?.platform || null"
|
||||||
@close="closeUseKeyModal"
|
@close="closeUseKeyModal"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user