-
Notifications
You must be signed in to change notification settings - Fork 11
feat(provider): 供应商管理增强 - API 地址选择和 UI 优化 #78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(provider): 供应商管理增强 - API 地址选择和 UI 优化 #78
Conversation
## 动机 - 用户在供应商平台(如 NEW API)管理多个 API 令牌,需要手动复制配置到 DuckCoding - 重复性操作易出错且效率低,缺乏导入溯源记录 ## 核心改动 ### 后端架构层 - 新增 `models/remote_token.rs`:定义 `RemoteToken`、`RemoteTokenGroup`、`CreateRemoteTokenRequest` 等数据模型 - 新增 `services/new_api/client.rs`:实现 NEW API 客户端(296行),提供令牌列表/创建/删除/分组查询功能 - 新增 `commands/token_commands.rs`:7个 Tauri 命令支持前端调用(`fetch_provider_tokens`、`import_token_as_profile` 等) - 扩展 `ProfileSource` 枚举:新增 `ImportedFromProvider` 变体,记录导入溯源信息(供应商ID/令牌ID/导入时间等) - 更新 `ProfileManager::load/save_profiles_store` 为 public,允许 token_commands 直接操作 ### 前端功能层 - 供应商管理页(`ProviderManagementPage`): - 新增可展开/折叠的表格行,展开后显示 `RemoteTokenManagement` 组件 - 支持查看令牌列表、创建令牌、删除令牌、导入到 Profile - Profile 管理页(`ProfileManagementPage`): - "创建 Profile" 按钮改为下拉菜单,新增"从供应商导入"选项 - 新增 `ImportFromProviderDialog` 组件(336行),支持选择供应商 → 选择令牌 → 填写配置 → 导入 - `ActiveProfileCard` 和 `ProfileCard` 显示来源信息(自定义 vs 从供应商导入) - 类型定义和命令包装: - `types/remote-token.ts`:前端类型定义 - `lib/tauri-commands/token.ts`:Tauri 命令的 TypeScript 包装器 ### 数据迁移 - `profile_v2.rs`:所有 Profile 创建逻辑默认 `source: ProfileSource::Custom`,保证向后兼容 ## 测试情况 - 后端单元测试:`token_commands.rs` 包含 4 个测试,`remote_token.rs` 包含 2 个测试 - 前端集成测试:手动验证导入流程(选择供应商 → 选择令牌 → 填写配置 → 成功导入) ## 影响范围 - **新增代码**:1059 行(前端 763 行 + 后端 296 行),无破坏性变更 - **修改模块**:ProfileManager、迁移系统、前端 Profile/Provider 管理页 - **数据兼容性**:旧 Profile 自动标记为 `Custom` 来源,无需手动迁移
- 清理代码重构过程中遗留的临时备份文件 - 该文件为旧版 main.rs 的副本,已完成模块化拆分 - 保持代码库整洁
## 后端变更
### API 修正
- 修复 `create_provider_token` 命令返回类型(`RemoteToken` -> `()`)
- 匹配 NEW API 实际行为(仅返回 `{ success, message }`,不返回令牌对象)
### 数据模型完善
- 扩展 `CreateRemoteTokenRequest` 字段:
- `group_id` -> `group`(改为分组名称)
- `quota` + `expire_days` -> `remain_quota` + `unlimited_quota` + `expired_time`
- 新增:`model_limits_enabled`、`model_limits`、`allow_ips`
- 同步更新单元测试 (`remote_token.rs`)
### 服务层适配
- `NewApiClient::create_token` 适配新请求体格式
- 文档注释说明 API 返回值特性
## 前端变更
### ImportFromProviderDialog 重写
- **双 Tab 设计**:
- Tab A:选择现有令牌并导入
- Tab B:创建新令牌并直接导入
- 新增 `forwardRef` 支持外部触发一键生成
- 自动为无前缀令牌补充 `sk-` 前缀
- 支持从自定义创建跳转(`autoTriggerGenerate` prop)
### 新增组件(4 个)
1. **CreateCustomProfileDialog**:手动创建 Profile 对话框
- 支持一键配置快捷入口(跳转到导入对话框)
- 可关闭的功能说明横幅
2. **DuckCodingGroupHint**:DuckCoding 分组说明组件
- 显示工具专用分组要求
- 集成控制台链接和一键生成按钮
3. **ProfileNameInput**:共享的 Profile 名称输入组件
- 统一的验证提示(禁止 `dc_proxy_` 前缀)
4. **TokenDetailCard**:令牌详情卡片
- 展示分组、额度、过期时间等信息
- 额度格式化(microdollars -> USD)
### 页面集成
- **ProfileManagementPage**:
- 替换"手动创建"入口为 `CreateCustomProfileDialog`
- 支持跨对话框流程(手动创建 -> 一键生成)
- 使用 `useRef` 控制导入对话框的生成触发
- **ProviderManagementPage**:
- 修复 React Fragment 警告(添加 `Fragment` 导入和 key)
### 类型定义同步
- `remote-token.ts`:更新 `CreateRemoteTokenRequest` 接口定义
- `token.ts`:修正 `createProviderToken` 返回类型(`RemoteToken` -> `void`)
## 测试覆盖
- ✅ 后端单元测试通过(`create_request_serialization`)
- ✅ 前端类型检查通过
## 影响范围
- 向后兼容:仅影响令牌创建流程,不影响现有导入功能
- 用户体验提升:提供更灵活的创建和导入选项
- 将项目许可证从 MIT 更改为 AGPL-3.0-only,强化开源保护 - 新增 ipaddr.js@2.3.0 依赖,用于令牌管理中的 IP 地址和 CIDR 表达式验证 BREAKING CHANGE: 许可证变更可能影响商业使用场景
**后端增强:** - 新增 `update_provider_token_full` 命令,支持更新令牌的所有字段(名称、分组、配额、过期时间、模型限制、IP 白名单) - 新增 `UpdateRemoteTokenRequest` 数据模型,定义完整的更新请求结构 - `NewApiClient::update_token_full` 方法实现完整字段更新逻辑 **前端功能:** - 新增 `EditTokenDialog` 组件,提供可视化编辑界面 - 令牌列表新增"编辑"按钮(Pencil 图标) - 自动加载令牌分组列表,支持分组选择 - 支持配额管理(无限额度开关)、有效期设置、模型限制、IP 白名单(CIDR 表达式) - 集成 ipaddr.js 进行 IP 地址格式验证 **技术细节:** - 保留原 `update_provider_token` 命令(仅更新名称)以保持向后兼容 - 编辑成功后自动刷新令牌列表 - 表单字段与 `CreateRemoteTokenDialog` 保持一致的 UX
**UI 架构变更:** - 从折叠式(Accordion)布局改为 Tabs 分组布局,提升用户体验 - 新增两个 Tab:「供应商管理」和「令牌管理」 - 删除展开/折叠按钮,简化交互流程 **功能优化:** - 供应商列表新增"查看令牌"按钮,点击自动跳转到令牌管理 Tab - 提取 `TokenManagementTab` 独立组件,支持供应商选择器 - 侧边栏导航文案优化:「供应商管理」→「供应商」(更简洁) **技术改进:** - 使用 `activeTab` 和 `selectedProviderId` 状态管理 Tab 切换和供应商联动 - 代码格式化:修复 ImportFromProviderDialog 中的 Prettier 警告 - 保持 RemoteTokenManagement 组件不变,仅调整容器结构 **用户体验提升:** - 减少嵌套层级,令牌管理界面更加清晰 - 支持直接从供应商列表快速跳转到对应令牌管理 - 统一视觉风格,与其他页面 Tabs 布局保持一致
## 动机
- 现有的令牌导入功能缺乏重复性检测,用户可能将同一令牌重复导入到多个工具
- 缺少可视化的导入状态提示,用户无法快速了解令牌的使用情况
- API Key 标准化处理不完整,部分令牌缺少 sk- 前缀导致兼容性问题
## 主要改动
### 后端(Rust)
- **ProfileManager 增强**(manager.rs)
- 新增 `check_import_status()` 方法:遍历所有工具的 Profile,检测指定令牌的导入状态
- 支持跨工具查询(claude-code、codex、gemini-cli)
- 返回每个工具的导入状态和已导入的 Profile 名称
- **类型定义扩展**(types.rs)
- 新增 `TokenImportStatus` 结构体:存储工具级导入状态
- 包含 `tool_id`、`is_imported`、`imported_profile_name` 字段
- **Tauri 命令**(token_commands.rs + main.rs)
- 新增 `check_token_import_status` 命令:暴露导入状态检测接口
- 注册到应用主入口
- **API 标准化**(new_api/client.rs)
- 自动为缺少 sk- 前缀的 API Key 添加前缀
- 统一 NewAPI 返回的令牌格式
### 前端(TypeScript/React)
- **ImportTokenDialog 重构**(ImportTokenDialog.tsx)
- 使用 Tabs 替换 Select 组件,提升交互体验
- **自动检测**:Dialog 打开时自动检测所有工具的导入状态
- **智能禁用**:已导入的工具 Tab 自动禁用,显示 Tooltip 提示
- **全量导入提醒**:所有工具都已导入时显示 Alert 提示
- **默认值优化**:自动设置 Profile 名称(`${token.name}_profile`)
- **防重复提交**:提交前二次校验当前工具是否已导入
- **API 和类型**(token.ts + remote-token.ts)
- 新增 `checkTokenImportStatus()` API 调用函数
- 新增 `TokenImportStatus` TypeScript 接口定义
- **UI 微调**
- EditTokenDialog:显示分组描述信息(desc + ratio)
- CreateRemoteTokenDialog:简化分组显示,仅保留倍率信息
## 技术实现
### 状态检测流程
```
1. Dialog 打开 → 调用 checkTokenImportStatus(provider_id, token_id)
2. 后端遍历所有工具的 Profile,匹配 ProfileSource::ImportedFromProvider
3. 返回三元组列表:[{tool_id, is_imported, imported_profile_name}]
4. 前端根据状态:禁用已导入工具、切换到可用工具、显示提示信息
```
### 防重复机制
- 前端:Tab 级禁用 + 提交前校验
- 后端:通过 ProfileSource 记录导入来源(provider_id + remote_token_id)
- UI 反馈:Tooltip 显示已导入的 Profile 名称
## 测试情况
- 手动测试场景:
- [x] 首次导入令牌到 Claude Code
- [x] 尝试重复导入同一令牌(Tab 正确禁用)
- [x] 导入到所有工具后显示全量导入提示
- [x] 切换工具 Tab 的响应性
- [x] API Key 标准化处理(sk- 前缀自动添加)
- 单元测试:现有测试保持通过(需补充 check_import_status 单元测试)
## 影响范围
- 新增功能:令牌导入状态检测
- 行为变更:防止重复导入同一令牌到同一工具
- API Key 格式:统一添加 sk- 前缀(不影响现有功能)
- UI 改进:ImportTokenDialog 交互体验优化
## 后续计划
- [ ] 添加 ProfileManager::check_import_status() 单元测试
- [ ] 支持批量导入时的状态检测
- [ ] 考虑在令牌列表页面显示导入状态标记
## 动机
- Profile 管理页面的"从供应商导入"对话框缺少令牌导入状态检测
- 用户可能在 Provider 页面和 Profile 页面重复导入同一令牌
- 三个对话框(CreateRemoteTokenDialog、EditTokenDialog、ImportFromProviderDialog)的分组选择器显示格式不一致
## 主要改动
### ImportFromProviderDialog 功能扩展
- **导入状态检测**:
- 新增 `tokenImportStatus` 和 `checkingImportStatus` 状态管理
- 实现 `checkImportStatus()` 异步检测函数
- 实现 `isTokenAlreadyImported()` 辅助判断函数
- **自动检测机制**:
- 令牌选择变更时自动触发导入状态检测
- 使用 `useEffect` 监听 `tokenId` 变化
- Dialog 关闭时重置检测状态
- **UI 反馈**:
- 已导入令牌显示红色 Alert 提示(显示工具名称和 Profile 名称)
- 导入按钮状态管理:
- 检测中:disabled
- 已导入:disabled + 按钮文本显示"已导入"
- 可导入:enabled + 按钮文本显示"导入"
- 导入按钮添加 Download 图标
### 分组选择器显示优化(跨组件统一)
**SelectValue(选中后的显示)**:
- 统一格式:`{group.id} ({group.ratio}x)`
- 使用 IIFE 计算显示内容
**SelectItem(下拉选项)**:
- **ImportFromProviderDialog**:`{group.id} ({group.ratio}x)` | `{group.desc}`
- **EditTokenDialog**:`{group.id} ({group.ratio}x)` | `{group.desc}`
- **CreateRemoteTokenDialog**:`{group.id}({group.ratio}x)` + `{group.desc}`(两行布局)
## 技术实现
### 状态检测流程
```
1. 用户选择令牌 → tokenId 变更
2. useEffect 触发 → 调用 checkImportStatus(provider, token)
3. 调用 checkTokenImportStatus(provider.id, token.id) 后端 API
4. 更新 tokenImportStatus 状态
5. UI 根据状态:显示 Alert + 禁用/启用按钮
```
### 代码优化
- 使用 IIFE(Immediately Invoked Function Expression)计算条件渲染内容
- 统一工具名称映射逻辑(claude-code → Claude Code, codex → Codex, gemini-cli → Gemini CLI)
- SelectValue 使用函数式计算避免重复逻辑
## 影响范围
- **新增功能**:Profile 页面的导入状态检测(与 Provider 页面保持一致)
- **UI 优化**:三个对话框的分组选择器显示格式统一
- **用户体验**:跨页面防止重复导入同一令牌到同一工具
## 测试情况
- 手动测试场景:
- [x] Profile 页面选择已导入令牌(正确显示 Alert 和禁用按钮)
- [x] Profile 页面选择未导入令牌(按钮正常启用)
- [x] 分组选择器显示格式统一性检查
- [x] 导入状态检测的响应性
## 后续优化
- [ ] 考虑提取分组选择器为独立组件(避免三处重复代码)
- [ ] 添加导入状态的缓存机制(减少重复检测)
主要变更: - 添加可选 API 地址字段,支持从 /api/status 自动获取地址列表 - 供应商表单添加下拉选择 + 自定义输入组合框 - 令牌导入时优先使用 api_address 字段作为 base_url - 供应商表单添加垂直滚动支持(max-h-90vh) - 强制验证配置后才能保存(按钮置灰 + toast 提示) - 修复验证逻辑:检查响应体 success 字段,避免误判 - 令牌删除添加确认对话框 - 仪表盘供应商选择器添加横向滚动支持 后端改动: - Provider 模型新增 api_address: Option<String> 字段 - 新增 fetch_provider_api_addresses 命令 - update_provider 方法支持更新 api_address - validate_provider_config 检查响应 success 字段 前端改动: - ProviderFormDialog 集成 API 地址选择器 - RemoteTokenManagement 添加删除确认对话框 - ProviderTabs 支持横向滚动 测试: - 所有单元测试通过 - ESLint + Clippy + Prettier + fmt 检查通过
- 将默认 DuckCoding 供应商的 api_address 设置为 https://jp.duckcoding.com - 优化国际用户访问速度和稳定性 - 令牌导入时将优先使用此 API 地址
|
本评论会随各平台任务完成自动更新:
This comment auto-updates as each platform finishes:
|
概述
本 PR 实现了供应商管理和远程令牌导入的完整功能体系,包含 9 个提交,涵盖从供应商配置到令牌导入、状态检测、UI 优化的全流程。
功能亮点
🎯 核心功能:远程令牌导入系统
令牌导入为 Profile (81d686a)
ProfileSource::ImportedFromProvider)令牌创建和导入优化 (1fab3ed)
TokenFormDialog){工具}-{令牌名})完整字段更新 (508dde5)
update_provider_token_full命令EditTokenDialog集成完整表单🔍 令牌状态检测系统
防重复导入机制 (e775583)
check_token_import_status命令TokenImportStatus(工具类型、Profile 名称、导入时间)Profile 管理页面集成 (6163b3f)
ActiveProfileCard显示当前 Profile 的导入来源🎨 供应商管理页面重构
Tabs 布局 (b8d1bb8)
供应商配置增强 (c3affcc)
api_address字段/api/status获取 API 地址列表api_address作为base_url✨ UI/UX 优化 (c3affcc)
供应商表单增强
max-h-90vh)验证逻辑修复
success字段,避免误判success字段的 API(默认true)message字段作为错误信息令牌管理增强
🔧 其他改进
许可证更新 (18272f0)
ipaddress依赖(0.1.3)代码清理 (84f4812)
temp_old_main.rs技术实现
后端(Rust)
新增 Tauri 命令
fetch_provider_api_addresses- 获取 API 地址列表check_token_import_status- 检测令牌导入状态import_token_as_profile- 导入令牌为 Profilecreate_custom_profile- 创建自定义 Profileupdate_provider_token_full- 完整更新远程令牌数据模型扩展
Provider新增api_address: Option<String>ProfileSource新增ImportedFromProvider变体TokenImportStatus类型定义服务层增强
ProfileManager::check_import_status- 检测导入状态ProviderManager::update_provider- 支持api_address更新validate_provider_config- 增强验证逻辑前端(React + TypeScript)
新增组件
TokenFormDialog- 统一的令牌创建/编辑对话框ImportTokenDialog- 令牌导入对话框TokenManagementTab- 令牌管理 TabRemoteTokenManagement- 远程令牌管理组件组件增强
ProviderFormDialog- API 地址选择、滚动、强制验证ActiveProfileCard- 显示导入来源和快捷链接ProviderTabs- 横向滚动支持页面重构
ProviderManagementPage- 双 Tab 布局数据流设计
测试情况
代码质量检查
功能测试
供应商管理
令牌管理
令牌导入
Profile 管理
UI 交互
向后兼容性
api_address字段可选,旧数据自动兼容success字段的 API变更统计
主要文件
src-tauri/src/commands/token_commands.rs- 令牌导入命令src-tauri/src/commands/provider_commands.rs- 供应商管理命令src-tauri/src/services/profile_manager/types.rs- 导入状态类型src/pages/ProviderManagementPage/- 完整重构src/pages/ProfileManagementPage/- 导入状态集成风险评估
低风险 ✅
需注意⚠️
依赖变更
后续计划
截图/演示
(可选)添加关键功能的截图或 GIF 演示:
相关 Issue: #XX(如有)
Breaking Changes: 无
License Change: MIT → AGPL-3.0