refactor(channels): centralize BillingModelSource normalization and exhaustive enum maps

- service: add normalizeBillingModelSource helper, apply in Create/GetByID/Update/List/ListAvailable outputs
- handler: drop channelToResponse fallback now that service owns the default; add passthrough test
- frontend: replace ternary status/billing-source lookups with Record<Enum, ...> maps so new union members fail the build
- chip/table: drop local type aliases, reuse UserSupportedModel/UserPricingInterval directly
- tests: assert short-circuit on ListAll error, wrap-prefix preservation, and Name-based default lookup
This commit is contained in:
erio
2026-04-21 11:31:54 +08:00
parent 88decb6e0c
commit 375aefa209
8 changed files with 122 additions and 53 deletions

View File

@@ -32,6 +32,9 @@ type AvailableChannel struct {
// 支持模型通过 (*Channel).SupportedModels() 计算得到(见 channel.go
// 关联分组信息通过 groupRepo.ListActive 查询后按 ID 映射;渠道 GroupIDs 中未在活跃列表中
// 的分组(已停用或删除)会被忽略。
//
// 前置条件s.groupRepo 必须非 nil由 wire DI 保证)。直接 nil-deref 用于 fail-fast
// 避免静默掩盖注入缺失。
func (s *ChannelService) ListAvailable(ctx context.Context) ([]AvailableChannel, error) {
channels, err := s.repo.ListAll(ctx)
if err != nil {
@@ -61,19 +64,16 @@ func (s *ChannelService) ListAvailable(ctx context.Context) ([]AvailableChannel,
groups = append(groups, ref)
}
}
sort.Slice(groups, func(i, j int) bool { return groups[i].Name < groups[j].Name })
sort.SliceStable(groups, func(i, j int) bool { return groups[i].Name < groups[j].Name })
billingSource := ch.BillingModelSource
if billingSource == "" {
billingSource = BillingModelSourceChannelMapped
}
normalizeBillingModelSource(ch)
out = append(out, AvailableChannel{
ID: ch.ID,
Name: ch.Name,
Description: ch.Description,
Status: ch.Status,
BillingModelSource: billingSource,
BillingModelSource: ch.BillingModelSource,
RestrictModels: ch.RestrictModels,
Groups: groups,
SupportedModels: ch.SupportedModels(),