feat(channel): 模型映射 + 分组搜索 + 卡片折叠 + 冲突校验
- 渠道模型映射:新增 model_mapping JSONB 字段,在账号映射之前执行 - 分组选择:添加搜索过滤 + 平台图标 - 定价卡片:支持折叠/展开,已有数据默认折叠 - 模型冲突校验:前后端均禁止同一渠道内重复模型 - 迁移 083: channels 表添加 model_mapping 列
This commit is contained in:
@@ -36,6 +36,8 @@ type Channel struct {
|
||||
GroupIDs []int64
|
||||
// 模型定价列表
|
||||
ModelPricing []ChannelModelPricing
|
||||
// 渠道级模型映射
|
||||
ModelMapping map[string]string
|
||||
}
|
||||
|
||||
// ChannelModelPricing 渠道模型定价条目
|
||||
@@ -71,6 +73,33 @@ type PricingInterval struct {
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// ResolveMappedModel 解析渠道级模型映射,返回映射后的模型名。
|
||||
// 支持通配符(如 "claude-*" → "claude-sonnet-4")。
|
||||
// 如果没有匹配的映射规则,返回原始模型名。
|
||||
func (c *Channel) ResolveMappedModel(requestedModel string) string {
|
||||
if len(c.ModelMapping) == 0 {
|
||||
return requestedModel
|
||||
}
|
||||
lower := strings.ToLower(requestedModel)
|
||||
// 精确匹配优先
|
||||
for src, dst := range c.ModelMapping {
|
||||
if strings.ToLower(src) == lower {
|
||||
return dst
|
||||
}
|
||||
}
|
||||
// 通配符匹配
|
||||
for src, dst := range c.ModelMapping {
|
||||
srcLower := strings.ToLower(src)
|
||||
if strings.HasSuffix(srcLower, "*") {
|
||||
prefix := strings.TrimSuffix(srcLower, "*")
|
||||
if strings.HasPrefix(lower, prefix) {
|
||||
return dst
|
||||
}
|
||||
}
|
||||
}
|
||||
return requestedModel
|
||||
}
|
||||
|
||||
// IsActive 判断渠道是否启用
|
||||
func (c *Channel) IsActive() bool {
|
||||
return c.Status == StatusActive
|
||||
@@ -168,5 +197,11 @@ func (c *Channel) Clone() *Channel {
|
||||
cp.ModelPricing[i] = c.ModelPricing[i].Clone()
|
||||
}
|
||||
}
|
||||
if c.ModelMapping != nil {
|
||||
cp.ModelMapping = make(map[string]string, len(c.ModelMapping))
|
||||
for k, v := range c.ModelMapping {
|
||||
cp.ModelMapping[k] = v
|
||||
}
|
||||
}
|
||||
return &cp
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user