diff --git a/README.md b/README.md index 512c435a3..a1c4d2106 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ INSTALL_DIR="$HOME/services/codex-proxy-rs" bash install.sh 部署完成后,打开 `http://127.0.0.1:8080`,使用 `admin@cpr.local` 和管理员密码登录 -API Key 持有者可在登录页切换身份,查看自己的用量与额度,并通过「密钥配置」复制 Codex 配置或导入 CCSwitch +API Key 持有者可在登录页切换身份,查看自己的用量与额度,并通过「密钥配置」复制 Codex 配置或导入 CC Switch 默认地址只能在服务器本机访问,从其他设备使用时,需要配置 [HTTPS 反向代理](deploy/README.md#公网访问) @@ -93,7 +93,7 @@ API Key 持有者可在登录页切换身份,查看自己的用量与额度, ## 客户端接入 -**Codex CLI / 桌面端**:在「使用密钥」中按操作系统复制配置,或通过 CCSwitch 导入,合并配置后重启 Codex +**Codex CLI / 桌面端**:在「使用密钥」中按操作系统复制配置,合并配置后重启 Codex;也可通过「导入到」把服务连接与密钥添加到 CC Switch 完整步骤、生图配置与排障见[客户端配置](deploy/README.md#客户端配置) diff --git a/docs/architecture.md b/docs/architecture.md index a141cdb22..94a3a2447 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -647,8 +647,8 @@ KeyUsageService 从 AuthService 的服务端身份或 Core 的入口认证结果 ObservabilityStore 的范围查询;数据面额度查询不执行推理准入或开启窗口,入口认证和适用的请求中间件仍会执行。 API 只输出各入口所需的字段白名单,不复用管理员的宽响应。 客户端配置通过 ClientKeyStore 显式读取当前会话绑定 Key 的明文,不进入用量响应。 -前端 `/key-usage` 独立于管理布局,不挂载管理员菜单或请求管理接口;配置弹窗和 Codex / CCSwitch -配置生成逻辑与管理端共用,明文仅在打开弹窗时获取,关闭后清除,不持久化到浏览器 +前端 `/key-usage` 独立于管理布局,不挂载管理员菜单或请求管理接口;配置弹窗、Codex 配置及 CC Switch +导入链接生成逻辑与管理端共用,明文仅在打开弹窗时获取,关闭后清除,不持久化到浏览器 ## 6. 路由、账号范围与 continuation diff --git a/frontend/src/components/ApiKeyConfigModal.vue b/frontend/src/components/ApiKeyConfigModal.vue index 97c3c82a4..a214aafc2 100644 --- a/frontend/src/components/ApiKeyConfigModal.vue +++ b/frontend/src/components/ApiKeyConfigModal.vue @@ -6,6 +6,7 @@ import { Apple, Copy, Monitor, Upload } from '@lucide/vue' import { computed, shallowRef } from 'vue' import { useI18n } from 'vue-i18n' import { buildCodexCcSwitchImportDeeplink, buildCodexConfig, CODEX_WEBSOCKET_ENABLED_BY_DEFAULT } from '@/utils/client' +import ClientImportModal from './ClientImportModal.vue' const props = defineProps<{ title?: string @@ -18,11 +19,13 @@ const props = defineProps<{ const emit = defineEmits<{ copy: [text: string] + afterLeave: [] }>() const { t } = useI18n({ useScope: 'global' }) const open = defineModel({ default: false }) +const showImport = shallowRef(false) const activePlatform = shallowRef('unix') const websocketEnabled = shallowRef(CODEX_WEBSOCKET_ENABLED_BY_DEFAULT) @@ -44,7 +47,7 @@ const codexConfig = computed(() => buildCodexConfig({ websocketEnabled: websocketEnabled.value, })) -function importToCcs() { +function importToClient() { if (!keyValue.value) return window.location.href = buildCodexCcSwitchImportDeeplink({ @@ -61,6 +64,7 @@ function importToCcs() { :title="title ?? t('keys.configuration.title')" :description="t('keys.configuration.description')" width="48rem" + @closed="showImport = false; emit('afterLeave')" >
@@ -103,13 +107,14 @@ function importToCcs() {
+ diff --git a/frontend/src/components/ClientImportModal.vue b/frontend/src/components/ClientImportModal.vue new file mode 100644 index 000000000..7f851f1d1 --- /dev/null +++ b/frontend/src/components/ClientImportModal.vue @@ -0,0 +1,56 @@ + + + diff --git a/frontend/src/i18n/locales/en/keys.json b/frontend/src/i18n/locales/en/keys.json index 7d06aa4b8..5b6c14185 100644 --- a/frontend/src/i18n/locales/en/keys.json +++ b/frontend/src/i18n/locales/en/keys.json @@ -4,7 +4,10 @@ "description": "Save or merge the configuration below and then restart Codex", "platform": "Platform", "toggleWebSocket": "Switch WebSocket configuration", - "importCcSwitch": "Add to CC Switch", + "importTo": "Import to", + "selectImportTool": "Choose a tool to import into", + "ccSwitchDescription": "Manage AI client configurations", + "viewOnGitHub": "View {name} on GitHub", "copiedToClipboard": "Copied to clipboard", "fullApiKeyNotAvailable": "Full API key not available", "title": "Use API key" @@ -40,9 +43,8 @@ }, "created": { "apiKeyCreated": "API key created", - "description": "Copy the API key or import it into CC Switch", + "description": "Copy the API key or import it into a client", "accessNotice": "This key grants gateway access, share it only with trusted callers", - "copyKey": "Copy key", "iHaveSaved": "I have saved" }, "filters": { diff --git a/frontend/src/i18n/locales/zh-Hans/keys.json b/frontend/src/i18n/locales/zh-Hans/keys.json index 864ebbab9..fe6fe84f1 100644 --- a/frontend/src/i18n/locales/zh-Hans/keys.json +++ b/frontend/src/i18n/locales/zh-Hans/keys.json @@ -4,7 +4,10 @@ "description": "保存或合并下方配置后重启 Codex", "platform": "配置平台", "toggleWebSocket": "切换 WebSocket 配置", - "importCcSwitch": "添加到 CC Switch", + "importTo": "导入到", + "selectImportTool": "选择要导入的工具", + "ccSwitchDescription": "管理和切换 AI 客户端配置", + "viewOnGitHub": "在 GitHub 查看 {name}", "copiedToClipboard": "已复制到剪贴板", "fullApiKeyNotAvailable": "完整 API Key 不可用", "title": "使用密钥" @@ -40,9 +43,8 @@ }, "created": { "apiKeyCreated": "API Key 已创建", - "description": "复制密钥,或直接导入 CCSwitch", + "description": "复制密钥,或导入到客户端", "accessNotice": "该密钥具有网关访问权限,请仅发送给可信调用方", - "copyKey": "复制密钥", "iHaveSaved": "我已保存" }, "filters": { diff --git a/frontend/src/i18n/locales/zh-Hant/keys.json b/frontend/src/i18n/locales/zh-Hant/keys.json index 225aec11f..09d6909ca 100644 --- a/frontend/src/i18n/locales/zh-Hant/keys.json +++ b/frontend/src/i18n/locales/zh-Hant/keys.json @@ -4,7 +4,10 @@ "description": "保存或合併下方配置後重啓 Codex", "platform": "配置平臺", "toggleWebSocket": "切換 WebSocket 配置", - "importCcSwitch": "添加到 CC Switch", + "importTo": "導入到", + "selectImportTool": "選擇要導入的工具", + "ccSwitchDescription": "管理和切換 AI 客戶端配置", + "viewOnGitHub": "在 GitHub 查看 {name}", "copiedToClipboard": "已複製到剪貼板", "fullApiKeyNotAvailable": "完整 API Key 不可用", "title": "使用密鑰" @@ -40,9 +43,8 @@ }, "created": { "apiKeyCreated": "API Key 已創建", - "description": "複製密鑰,或直接導入 CCSwitch", + "description": "複製密鑰,或導入到客戶端", "accessNotice": "該密鑰具有網關訪問權限,請僅發送給可信調用方", - "copyKey": "複製密鑰", "iHaveSaved": "我已保存" }, "filters": { diff --git a/frontend/src/views/keys/components/ApiKeyActions.vue b/frontend/src/views/keys/components/ApiKeyActions.vue index 667ccfe00..9d931a381 100644 --- a/frontend/src/views/keys/components/ApiKeyActions.vue +++ b/frontend/src/views/keys/components/ApiKeyActions.vue @@ -16,7 +16,7 @@ defineProps<{ const emit = defineEmits<{ use: [apiKey: ApiKey] - importCcs: [apiKey: ApiKey] + importClient: [apiKey: ApiKey] toggle: [apiKey: ApiKey] delete: [apiKey: ApiKey] edit: [apiKey: ApiKey] @@ -52,18 +52,18 @@ const { t } = useI18n({ useScope: 'global' })