diff --git a/backend/internal/handler/gateway_handler.go b/backend/internal/handler/gateway_handler.go
index b46c86a3..dff922d1 100644
--- a/backend/internal/handler/gateway_handler.go
+++ b/backend/internal/handler/gateway_handler.go
@@ -164,9 +164,9 @@ func (h *GatewayHandler) Messages(c *gin.Context) {
channelMapping = h.gatewayService.ResolveChannelMapping(c.Request.Context(), *apiKey.GroupID, reqModel)
}
- // 渠道模型限制检查:使用原始请求模型名,因为定价列表中注册的是用户请求的模型名
+ // 渠道模型限制检查:先映射再判断,映射后的模型在定价列表中即放行
if apiKey.GroupID != nil {
- if h.gatewayService.IsModelRestricted(c.Request.Context(), *apiKey.GroupID, reqModel) {
+ if h.gatewayService.IsModelRestricted(c.Request.Context(), *apiKey.GroupID, channelMapping.MappedModel) {
h.errorResponse(c, http.StatusServiceUnavailable, "api_error", "No available accounts")
return
}
diff --git a/backend/internal/handler/openai_gateway_handler.go b/backend/internal/handler/openai_gateway_handler.go
index 7f68a56b..c8b90e14 100644
--- a/backend/internal/handler/openai_gateway_handler.go
+++ b/backend/internal/handler/openai_gateway_handler.go
@@ -191,10 +191,9 @@ func (h *OpenAIGatewayHandler) Responses(c *gin.Context) {
channelMapping = h.gatewayService.ResolveChannelMapping(c.Request.Context(), *apiKey.GroupID, reqModel)
}
- // 渠道模型限制检查
+ // 渠道模型限制检查:先映射再判断
if apiKey.GroupID != nil {
- if h.gatewayService.IsModelRestricted(c.Request.Context(), *apiKey.GroupID, reqModel) {
- h.errorResponse(c, http.StatusServiceUnavailable, "api_error", "No available accounts")
+ if h.gatewayService.IsModelRestricted(c.Request.Context(), *apiKey.GroupID, channelMapping.MappedModel) {
return
}
}
@@ -584,10 +583,9 @@ func (h *OpenAIGatewayHandler) Messages(c *gin.Context) {
channelMappingMsg = h.gatewayService.ResolveChannelMapping(c.Request.Context(), *apiKey.GroupID, reqModel)
}
- // 渠道模型限制检查
+ // 渠道模型限制检查:先映射再判断
if apiKey.GroupID != nil {
- if h.gatewayService.IsModelRestricted(c.Request.Context(), *apiKey.GroupID, reqModel) {
- h.anthropicErrorResponse(c, http.StatusServiceUnavailable, "api_error", "No available accounts")
+ if h.gatewayService.IsModelRestricted(c.Request.Context(), *apiKey.GroupID, channelMappingMsg.MappedModel) {
return
}
}
@@ -1165,9 +1163,9 @@ func (h *OpenAIGatewayHandler) ResponsesWebSocket(c *gin.Context) {
channelMappingWS = h.gatewayService.ResolveChannelMapping(ctx, *apiKey.GroupID, reqModel)
}
- // 渠道模型限制检查
+ // 渠道模型限制检查:先映射再判断
if apiKey.GroupID != nil {
- if h.gatewayService.IsModelRestricted(ctx, *apiKey.GroupID, reqModel) {
+ if h.gatewayService.IsModelRestricted(ctx, *apiKey.GroupID, channelMappingWS.MappedModel) {
closeOpenAIClientWS(wsConn, coderws.StatusPolicyViolation, "model not allowed")
return
}
diff --git a/frontend/src/views/admin/ChannelsView.vue b/frontend/src/views/admin/ChannelsView.vue
index c26a6fcf..6c57b269 100644
--- a/frontend/src/views/admin/ChannelsView.vue
+++ b/frontend/src/views/admin/ChannelsView.vue
@@ -155,9 +155,9 @@
>
{{ t('admin.channels.form.basicSettings', '基础设置') }}
-
+
@@ -261,7 +255,7 @@
@@ -449,6 +443,7 @@ const appStore = useAppStore()
// ── Platform Section type ──
interface PlatformSection {
platform: GroupPlatform
+ enabled: boolean
collapsed: boolean
group_ids: number[]
model_mapping: Record
@@ -549,11 +544,12 @@ function formatDate(value: string): string {
}
// ── Platform section helpers ──
-const activePlatforms = computed(() => form.platforms.map(s => s.platform))
+const activePlatforms = computed(() => form.platforms.filter(s => s.enabled).map(s => s.platform))
function addPlatformSection(platform: GroupPlatform) {
form.platforms.push({
platform,
+ enabled: true,
collapsed: false,
group_ids: [],
model_mapping: {},
@@ -562,22 +558,17 @@ function addPlatformSection(platform: GroupPlatform) {
}
function togglePlatform(platform: GroupPlatform) {
- const idx = form.platforms.findIndex(s => s.platform === platform)
- if (idx >= 0) {
- removePlatformSection(idx)
+ const section = form.platforms.find(s => s.platform === platform)
+ if (section) {
+ section.enabled = !section.enabled
+ if (!section.enabled && activeTab.value === platform) {
+ activeTab.value = 'basic'
+ }
} else {
addPlatformSection(platform)
}
}
-function removePlatformSection(idx: number) {
- const removed = form.platforms[idx]
- form.platforms.splice(idx, 1)
- if (activeTab.value === removed.platform) {
- activeTab.value = 'basic'
- }
-}
-
function getGroupsForPlatform(platform: GroupPlatform): AdminGroup[] {
return allGroups.value.filter(g => g.platform === platform)
}
@@ -682,6 +673,7 @@ function formToAPI(): { group_ids: number[], model_pricing: ChannelModelPricing[
const model_mapping: Record> = {}
for (const section of form.platforms) {
+ if (!section.enabled) continue
group_ids.push(...section.group_ids)
// Model mapping per platform
@@ -755,6 +747,7 @@ function apiToForm(channel: Channel): PlatformSection[] {
sections.push({
platform,
+ enabled: true,
collapsed: false,
group_ids: groupIds,
model_mapping: { ...mapping },
@@ -868,16 +861,16 @@ async function handleSubmit() {
return
}
- // Check duplicate models across all platform sections
- const allModels = form.platforms.flatMap(s => s.model_pricing.flatMap(e => e.models.map(m => m.toLowerCase())))
+ // Check duplicate models across all enabled platform sections
+ const allModels = form.platforms.filter(s => s.enabled).flatMap(s => s.model_pricing.flatMap(e => e.models.map(m => m.toLowerCase())))
const duplicates = allModels.filter((m, i) => allModels.indexOf(m) !== i)
if (duplicates.length > 0) {
appStore.showError(t('admin.channels.duplicateModels', `模型 "${duplicates[0]}" 在多个定价条目中重复`))
return
}
- // 校验 per_request/image 模式必须有价格
- for (const section of form.platforms) {
+ // 校验 per_request/image 模式必须有价格 (只校验启用的平台)
+ for (const section of form.platforms.filter(s => s.enabled)) {
for (const entry of section.model_pricing) {
if (entry.models.length === 0) continue
if ((entry.billing_mode === 'per_request' || entry.billing_mode === 'image') &&