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

@@ -127,19 +127,13 @@ import {
BILLING_MODE_IMAGE,
type BillingMode
} from '@/constants/channel'
// 复用 api/channels.ts 的用户侧最小形态 DTO
// admin ChannelModelPricing 字段更多但结构上是用户 DTO 的超集admin 视图传入可直接通过结构化子类型检查
import type { UserPricingInterval, UserSupportedModel } from '@/api/channels'
/**
* 复用 api/channels.ts 的用户侧最小形态 DTO
* admin ChannelModelPricing 字段更多但结构上是用户 DTO 的超集
* 因此 admin 视图传入时 TypeScript 结构化子类型会直接通过
*/
type PricingInterval = UserPricingInterval
type SupportedModelLike = UserSupportedModel
const props = withDefaults(
defineProps<{
model: SupportedModelLike
model: UserSupportedModel
/** i18n 前缀管理端传 `admin.availableChannels.pricing`用户端传 `availableChannels.pricing` */
pricingKeyPrefix?: string
noPricingLabel?: string
@@ -180,7 +174,7 @@ function formatRange(min: number, max: number | null): string {
return `(${min}, ${maxLabel}]`
}
function formatInterval(iv: PricingInterval, mode: BillingMode): string {
function formatInterval(iv: UserPricingInterval, mode: BillingMode): string {
if (mode === BILLING_MODE_PER_REQUEST || mode === BILLING_MODE_IMAGE) {
return formatScaled(iv.per_request_price, 1)
}