| @@ -0,0 +1,98 @@ | |||
| --- | |||
| title: 完整删除渠道选择功能 | |||
| date: 2026-05-16 | |||
| status: approved | |||
| --- | |||
| # 设计方案:完整删除渠道选择功能 | |||
| ## 背景 | |||
| 渠道选择功能允许用户强制指定使用某个具体渠道,而非系统自动分发。有 3 个入口: | |||
| 1. Token 密钥格式 `sk-{key}:{channelId}` | |||
| 2. Playground 通道下拉框 | |||
| 3. 渠道列表 API (`GET /api/user/model_channels`, `GET /api/user/channels`) | |||
| 此外还有 `is_default` 默认渠道标记功能,用于 Playground 下拉框的默认选中项和定价页面的默认通道显示。 | |||
| **删除原因**:该功能增加代码复杂度且线上无用户使用。 | |||
| ## 决策 | |||
| - **方案**:一次性完整删除(方案 A) | |||
| - **is_default 数据库字段**:保留列,不执行 migration,只删除功能代码 | |||
| - **Distribute() 自动分发**:完全保留 | |||
| - **线上用户影响**:无,已确认无用户使用 `sk-xxx:channelId` 格式 | |||
| ## 后端改动 | |||
| ### Middleware 层 | |||
| **`middleware/auth.go`**: | |||
| - `parseTokenKey()` 简化为只提取 key,去掉冒号和短横线分割 channelId 的逻辑 | |||
| - `SetupContextForToken()` 删除第 412-415 行的 `specific_channel_id` context 设置 | |||
| **`middleware/distributor.go`**: | |||
| - `ModelRequest` 结构体删除 `ChannelId int` 字段 | |||
| - `Distribute()` 删除第 39-62 行的 `specific_channel_id` 分支,直接进入自动分发 | |||
| - `getModelRequest()` 删除第 377-382 行的 channel_id body/header 处理 | |||
| ### Controller 层 | |||
| - **删除整个** `controller/playground_channels.go` | |||
| - `controller/relay.go`:删除 `shouldRetry()` 和 `shouldRetryTaskRelay()` 中 `specific_channel_id` 判断 | |||
| - `controller/channel.go`:删除 `GetUserChannelsForBinding()` | |||
| - `controller/channel_pricing.go`:删除 `SetDefaultChannel()` 和 `ClearDefaultChannel()` 控制器函数 | |||
| ### Model 层 | |||
| - `model/ability.go`:删除 `GetModelChannelsForGroup()` | |||
| - `model/channel.go`:删除 `GetAllChannelsForBinding()` | |||
| - `model/channel_pricing.go`:删除 `GetDefaultChannelId()`、`SetDefaultChannel()`、`ClearDefaultChannel()`、`defaultChannelCache` 缓存及其锁和辅助函数 | |||
| - `model/pricing.go`:删除 `PricingModel.DefaultChannelName` 字段及其赋值逻辑 | |||
| - `model/channel_pricing_test.go`:删除相关测试用例 | |||
| ### 路由和常量 | |||
| - `constant/context_key.go`:删除 `ContextKeyTokenSpecificChannelId` | |||
| - `router/api-router.go`:删除 4 条路由(`model_channels`、`channels`、`/set_default`、`/default/*name`) | |||
| - `i18n/keys.go`:删除 `MsgChannelIdFormatError`、`MsgDistributorInvalidChannelId` | |||
| - `i18n/locales/*.yaml`:删除对应翻译条目 | |||
| ## 前端改动 | |||
| ### Playground 相关 | |||
| | 文件 | 操作 | | |||
| |------|------| | |||
| | `web/src/components/playground/SettingsPanel.jsx` | 删除通道选择 `<Select>` 组件 | | |||
| | `web/src/pages/Playground/index.jsx` | 删除 channels 加载、`X-Channel-Id` header、body `channel_id` | | |||
| | `web/src/constants/playground.constants.js` | 删除 `channelId: 0` | | |||
| | `web/src/hooks/playground/usePlaygroundState.js` | 删除 `channels` 状态 | | |||
| ### 其他前端 | |||
| | 文件 | 操作 | | |||
| |------|------| | |||
| | `web/src/components/table/tokens/modals/EditTokenModal.jsx` | 删除冗余 channels 加载代码 | | |||
| | `web/src/pages/Setting/Operation/SettingsChannelAffinity.jsx` | 从 `CONTEXT_KEY_PRESETS` 移除 `specific_channel_id` | | |||
| | `web/src/pages/Setting/Ratio/ChannelPricingView.jsx` | 删除默认通道列和星号按钮 | | |||
| | `web/src/components/table/model-pricing/view/card/PricingCardView.jsx` | 删除 `default_channel_name` 标签 | | |||
| | `web/src/components/table/model-pricing/modal/components/ChannelPricingCard.jsx` | 删除 isDefault 标签 | | |||
| | `web/src/helpers/api.js` | 删除 `channelPricingApi.setDefault` 和 `clearDefault` | | |||
| ## 不改动的部分 | |||
| - **数据库**:`is_default` 列保留在 `channel_pricing` 表,无 migration | |||
| - **Distribute() 自动分发**:核心路由逻辑完全保留 | |||
| - **计费系统**:不受影响 | |||
| - **渠道亲和性系统**:只删 `specific_channel_id` 预设项,系统本身正常 | |||
| ## 删除后的行为变化 | |||
| | 场景 | 变化前 | 变化后 | | |||
| |------|--------|--------| | |||
| | API 请求 | `sk-xxx:42` 强制走渠道 42 | 密钥匹配失败(key 格式变化) | | |||
| | Playground | 可选通道下拉框 | 全部走系统自动分发 | | |||
| | 请求失败重试 | 指定渠道时不重试 | 所有请求都能自动重试 | | |||
| | 定价页面 | 显示默认通道标记 | 不再显示 | | |||