refactor(channels): consolidate pricing index, tighten types, polish DTOs

Follow-up to the available-channels review pass. No behavior change for
end users; tightens internals based on three independent code reviews.

Backend
- service/channel.go: collapse buildPricingLookup + pricedNamesFor
  into a single platformPricingIndex (byLower + originalCase + ordered
  names), built once per SupportedModels call. Fixes a casing-
  consistency bug where the same logical model appeared with mapping
  case in the exact branch but pricing case in the wildcard branch —
  pricing's original case now wins everywhere.
- service/channel.go: doc that a mapping key of just "*" expands to
  every priced model on the platform (intentional "passthrough all").
- service/channel_available.go: normalize empty BillingModelSource to
  channel_mapped at construction time, removing the same fallback
  duplicated in the admin DTO mapper and the admin Vue template.
- handler/admin/available_channel_handler.go: unexport
  availableChannelToAdminResponse (same-package usage only); mapper
  is now a pure passthrough.
- handler/available_channel_handler.go: drop the middleware2 alias
  (no name collision in this file).

Frontend
- utils/pricing.ts: extract formatScaled, used by SupportedModelChip
  and PricingRow.
- api/admin/channels.ts: re-export BillingMode from constants/channel;
  tighten Channel.status / billing_model_source to ChannelStatus /
  BillingModelSource (and same for AvailableChannel).
- components/channels/AvailableChannelsTable.vue: drop dead
  withDefaults wrapper (loading is required, both call sites pass it).
- views/admin/AvailableChannelsView.vue: drop the redundant
  || BILLING_MODEL_SOURCE_CHANNEL_MAPPED fallback (now applied in
  service layer); remove unused import.
- i18n zh + en: delete unused tierLabel and tokenRange keys from
  both availableChannels.pricing and admin.availableChannels.pricing.

Tests
- New: SupportedModels_ExactKeyUsesPricedCaseWhenAvailable locks the
  pricing-case-wins rule.
- New: SupportedModels_AsteriskOnlyMappingExpandsAllPriced documents
  the "*" expansion rule.
- Admin handler: existing tests adjusted to pass an explicit
  BillingModelSource (default-fill is now exercised by service tests).
This commit is contained in:
erio
2026-04-21 01:05:14 +08:00
parent 654cfb6480
commit 365ef1fdf7
14 changed files with 128 additions and 108 deletions

View File

@@ -59,11 +59,7 @@
<template #cell-billing_model_source="{ row }">
<span class="text-xs text-gray-700 dark:text-gray-300">
{{
t(
`admin.availableChannels.billingSource.${row.billing_model_source || BILLING_MODEL_SOURCE_CHANNEL_MAPPED}`
)
}}
{{ t(`admin.availableChannels.billingSource.${row.billing_model_source}`) }}
</span>
</template>
</AvailableChannelsTable>
@@ -82,10 +78,7 @@ import AvailableChannelsTable from '@/components/channels/AvailableChannelsTable
import channelsAPI, { type AvailableChannel } from '@/api/admin/channels'
import { useAppStore } from '@/stores/app'
import { extractApiErrorMessage } from '@/utils/apiError'
import {
CHANNEL_STATUS_ACTIVE,
BILLING_MODEL_SOURCE_CHANNEL_MAPPED
} from '@/constants/channel'
import { CHANNEL_STATUS_ACTIVE } from '@/constants/channel'
const { t } = useI18n()
const appStore = useAppStore()