From 8f6f459835779efa2e3308b90addfa20e81a4a66 Mon Sep 17 00:00:00 2001 From: shaw Date: Tue, 18 Aug 2026 17:12:01 +0800 Subject: [PATCH] fix(channels): support kimi/zhipu/deepseek platforms in channel pricing - ChannelsView platformOrder now includes the three CN provider platforms so channel pricing can be configured for them; composite group expansion/attachment stays limited to the five main platforms (matches backend isConcreteRequestPlatform and composite-routes target_platform validation) - SyncPricingModels maps kimi->moonshot, zhipu->zhipu, deepseek->deepseek; also fixes gemini mapping to "google" which matched zero catalog entries (provider key is "gemini") - Add CN platform colors to channel pricing model tag classes --- backend/internal/handler/admin/channel_handler.go | 5 ++++- .../internal/handler/admin/channel_handler_test.go | 2 +- frontend/src/components/admin/channel/types.ts | 6 ++++++ frontend/src/views/admin/ChannelsView.vue | 14 ++++++++++---- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/backend/internal/handler/admin/channel_handler.go b/backend/internal/handler/admin/channel_handler.go index 90c1a69b6d..dfce024fa3 100644 --- a/backend/internal/handler/admin/channel_handler.go +++ b/backend/internal/handler/admin/channel_handler.go @@ -568,9 +568,12 @@ func (h *ChannelHandler) GetModelDefaultPricing(c *gin.Context) { var platformToLiteLLMProvider = map[string]string{ service.PlatformAnthropic: "anthropic", service.PlatformOpenAI: "openai", - service.PlatformGemini: "google", + service.PlatformGemini: "gemini", service.PlatformAntigravity: "anthropic", service.PlatformGrok: "xai", + service.PlatformKimi: "moonshot", + service.PlatformZhipu: "zhipu", + service.PlatformDeepseek: "deepseek", } // SyncPricingModels 返回 LiteLLM 定价目录中指定平台的最新模型列表 diff --git a/backend/internal/handler/admin/channel_handler_test.go b/backend/internal/handler/admin/channel_handler_test.go index 7f9c050fa5..6c5ddedc92 100644 --- a/backend/internal/handler/admin/channel_handler_test.go +++ b/backend/internal/handler/admin/channel_handler_test.go @@ -502,7 +502,7 @@ func TestSyncPricingModels_ValidPlatform_EmptyService(t *testing.T) { svc := service.NewPricingService(nil, nil) router := setupSyncPricingModelsRouter(svc) - for _, platform := range []string{"anthropic", "openai", "gemini", "antigravity"} { + for _, platform := range []string{"anthropic", "openai", "gemini", "antigravity", "grok", "kimi", "zhipu", "deepseek"} { req := httptest.NewRequest(http.MethodGet, "/channels/pricing/sync-models?platform="+platform, nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) diff --git a/frontend/src/components/admin/channel/types.ts b/frontend/src/components/admin/channel/types.ts index 8809eff072..322a407c0c 100644 --- a/frontend/src/components/admin/channel/types.ts +++ b/frontend/src/components/admin/channel/types.ts @@ -368,6 +368,9 @@ export function getPlatformTagClass(platform: string): string { case 'gemini': return 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400' case 'antigravity': return 'bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400' case 'grok': return 'bg-slate-100 text-slate-700 dark:bg-slate-800 dark:text-slate-300' + case 'kimi': return 'bg-pink-100 text-pink-700 dark:bg-pink-900/30 dark:text-pink-400' + case 'zhipu': return 'bg-indigo-100 text-indigo-700 dark:bg-indigo-900/30 dark:text-indigo-400' + case 'deepseek': return 'bg-teal-100 text-teal-700 dark:bg-teal-900/30 dark:text-teal-400' default: return 'bg-gray-100 text-gray-700 dark:bg-gray-900/30 dark:text-gray-400' } } @@ -380,6 +383,9 @@ export function getPlatformTextClass(platform: string): string { case 'gemini': return 'text-blue-700 dark:text-blue-400' case 'antigravity': return 'text-purple-700 dark:text-purple-400' case 'grok': return 'text-slate-700 dark:text-slate-300' + case 'kimi': return 'text-pink-700 dark:text-pink-400' + case 'zhipu': return 'text-indigo-700 dark:text-indigo-400' + case 'deepseek': return 'text-teal-700 dark:text-teal-400' default: return '' } } diff --git a/frontend/src/views/admin/ChannelsView.vue b/frontend/src/views/admin/ChannelsView.vue index d431cb1293..e3a7ca8262 100644 --- a/frontend/src/views/admin/ChannelsView.vue +++ b/frontend/src/views/admin/ChannelsView.vue @@ -762,7 +762,10 @@ const form = reactive({ let abortController: AbortController | null = null // ── Platform config ── -const platformOrder: GroupPlatform[] = ['anthropic', 'openai', 'gemini', 'antigravity', 'grok'] +const platformOrder: GroupPlatform[] = ['anthropic', 'openai', 'gemini', 'antigravity', 'grok', 'kimi', 'zhipu', 'deepseek'] +// composite 分组仅覆盖主平台(与后端 isConcreteRequestPlatform / composite-routes target_platform 一致), +// 不含国产供应商平台。 +const compositePlatforms: GroupPlatform[] = ['anthropic', 'openai', 'gemini', 'antigravity', 'grok'] // ── Helpers ── function formatDate(value: string): string { @@ -801,7 +804,9 @@ function togglePlatform(platform: GroupPlatform) { } function getGroupsForPlatform(platform: GroupPlatform): AdminGroup[] { - return allGroups.value.filter(g => g.platform === platform || g.platform === 'composite') + return allGroups.value.filter( + g => g.platform === platform || (g.platform === 'composite' && compositePlatforms.includes(platform)) + ) } // ── Group helpers ── @@ -1183,7 +1188,7 @@ function apiToForm(channel: Channel): PlatformSection[] { for (const gid of channel.group_ids || []) { const p = groupPlatformMap.get(gid) if (p === 'composite') { - platformOrder.forEach(platform => activePlatforms.add(platform)) + compositePlatforms.forEach(platform => activePlatforms.add(platform)) } else if (p) { activePlatforms.add(p) } @@ -1202,7 +1207,8 @@ function apiToForm(channel: Channel): PlatformSection[] { const groupIds = (channel.group_ids || []).filter(gid => { const groupPlatform = groupPlatformMap.get(gid) - return groupPlatform === platform || groupPlatform === 'composite' + return groupPlatform === platform || + (groupPlatform === 'composite' && compositePlatforms.includes(platform)) }) const mapping = (channel.model_mapping || {})[platform] || {} const pricing = (channel.model_pricing || [])