feat(channel): 通配符定价匹配 + OpenAI BillingModelSource + 按次价格校验 + 用户端计费模式展示

- 定价查找支持通配符(suffix *),最长前缀优先匹配
- 模型限制(restrict_models)同样支持通配符匹配
- OpenAI 网关接入渠道映射/BillingModelSource/模型限制
- 按次/图片计费模式创建时强制要求价格或层级(前后端)
- 用户使用记录列表增加计费模式 badge 列
This commit is contained in:
erio
2026-03-31 00:23:45 +08:00
parent 0fbc9a44d3
commit 8d03c52e15
11 changed files with 255 additions and 22 deletions

View File

@@ -276,11 +276,21 @@ func (h *ChannelHandler) Create(c *gin.Context) {
return
}
pricing := pricingRequestToService(req.ModelPricing)
for _, p := range pricing {
if p.BillingMode == service.BillingModePerRequest || p.BillingMode == service.BillingModeImage {
if p.PerRequestPrice == nil && len(p.Intervals) == 0 {
response.BadRequest(c, "Per-request price or intervals required for per_request/image billing mode")
return
}
}
}
channel, err := h.channelService.Create(c.Request.Context(), &service.CreateChannelInput{
Name: req.Name,
Description: req.Description,
GroupIDs: req.GroupIDs,
ModelPricing: pricingRequestToService(req.ModelPricing),
ModelPricing: pricing,
ModelMapping: req.ModelMapping,
BillingModelSource: req.BillingModelSource,
RestrictModels: req.RestrictModels,
@@ -319,6 +329,14 @@ func (h *ChannelHandler) Update(c *gin.Context) {
}
if req.ModelPricing != nil {
pricing := pricingRequestToService(*req.ModelPricing)
for _, p := range pricing {
if p.BillingMode == service.BillingModePerRequest || p.BillingMode == service.BillingModeImage {
if p.PerRequestPrice == nil && len(p.Intervals) == 0 {
response.BadRequest(c, "Per-request price or intervals required for per_request/image billing mode")
return
}
}
}
input.ModelPricing = &pricing
}