88decb6e0c
- service: drop groupRepo nil guard (DI must inject), switch SupportedModels to SliceStable to match doc - frontend: reuse user-side DTO types in SupportedModelChip/AvailableChannelsTable instead of duplicating shapes; narrow admin statusLabel param to ChannelStatus - tests: replace nil-groupRepo case with ListAll/ListActive error propagation and BillingModelSource default-backfill coverage
88 lines
2.5 KiB
Go
88 lines
2.5 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// AvailableGroupRef 渠道视图中关联分组的简要信息。
|
|
type AvailableGroupRef struct {
|
|
ID int64
|
|
Name string
|
|
Platform string
|
|
}
|
|
|
|
// AvailableChannel 可用渠道视图:用于「可用渠道」页面展示渠道基础信息 +
|
|
// 关联的分组 + 推导出的支持模型列表(无通配符)。
|
|
type AvailableChannel struct {
|
|
ID int64
|
|
Name string
|
|
Description string
|
|
Status string
|
|
BillingModelSource string
|
|
RestrictModels bool
|
|
Groups []AvailableGroupRef
|
|
SupportedModels []SupportedModel
|
|
}
|
|
|
|
// ListAvailable 返回所有渠道的可用视图:每个渠道附带关联分组信息与支持模型列表。
|
|
//
|
|
// 支持模型通过 (*Channel).SupportedModels() 计算得到(见 channel.go)。
|
|
// 关联分组信息通过 groupRepo.ListActive 查询后按 ID 映射;渠道 GroupIDs 中未在活跃列表中
|
|
// 的分组(已停用或删除)会被忽略。
|
|
func (s *ChannelService) ListAvailable(ctx context.Context) ([]AvailableChannel, error) {
|
|
channels, err := s.repo.ListAll(ctx)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("list channels: %w", err)
|
|
}
|
|
|
|
groups, err := s.groupRepo.ListActive(ctx)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("list active groups: %w", err)
|
|
}
|
|
groupByID := make(map[int64]AvailableGroupRef, len(groups))
|
|
for i := range groups {
|
|
g := groups[i]
|
|
groupByID[g.ID] = AvailableGroupRef{
|
|
ID: g.ID,
|
|
Name: g.Name,
|
|
Platform: g.Platform,
|
|
}
|
|
}
|
|
|
|
out := make([]AvailableChannel, 0, len(channels))
|
|
for i := range channels {
|
|
ch := &channels[i]
|
|
groups := make([]AvailableGroupRef, 0, len(ch.GroupIDs))
|
|
for _, gid := range ch.GroupIDs {
|
|
if ref, ok := groupByID[gid]; ok {
|
|
groups = append(groups, ref)
|
|
}
|
|
}
|
|
sort.Slice(groups, func(i, j int) bool { return groups[i].Name < groups[j].Name })
|
|
|
|
billingSource := ch.BillingModelSource
|
|
if billingSource == "" {
|
|
billingSource = BillingModelSourceChannelMapped
|
|
}
|
|
|
|
out = append(out, AvailableChannel{
|
|
ID: ch.ID,
|
|
Name: ch.Name,
|
|
Description: ch.Description,
|
|
Status: ch.Status,
|
|
BillingModelSource: billingSource,
|
|
RestrictModels: ch.RestrictModels,
|
|
Groups: groups,
|
|
SupportedModels: ch.SupportedModels(),
|
|
})
|
|
}
|
|
|
|
sort.SliceStable(out, func(i, j int) bool {
|
|
return strings.ToLower(out[i].Name) < strings.ToLower(out[j].Name)
|
|
})
|
|
return out, nil
|
|
}
|