feat(channels): aggregate by channel with platform sections + rowspan table

Switch the user-facing 'Available Channels' view from "one row per
platform" to "one channel row-group with N platform sections".

Backend: userAvailableChannel now holds Platforms []section instead
of being exploded. buildPlatformSections replaces
explodeChannelByPlatform with the same per-platform grouping logic.

Frontend: drop the DataTable wrapper for this view and write a
four-column grid table (渠道名 / 平台 / 分组 / 支持模型) where the
channel name only renders on the first platform row of each channel —
visual rowspan without hacking DataTable.

- api/channels.ts: UserChannelPlatformSection + platforms[]
- AvailableChannelsTable: rewritten as native grid (header + per-
  channel section with hover row highlight)
- AvailableChannelsView: search now filters platforms sub-array;
  channel-name / description hits still keep the whole channel
- i18n: add availableChannels.columns.platform (zh/en)
This commit is contained in:
erio
2026-04-21 19:46:55 +08:00
parent 800802b8aa
commit 3cdd5754df
7 changed files with 220 additions and 153 deletions

View File

@@ -40,18 +40,23 @@ export interface UserSupportedModel {
pricing: UserSupportedModelPricing | null
}
export interface UserAvailableChannel {
name: string
description: string
/**
* 所属平台anthropic / openai / antigravity / gemini ...)。后端按平台把一个渠道
* 摊开成多条记录,因此此字段决定整行的配色与图标。
*/
/**
* 渠道下单个平台的子视图:用户可访问的分组 + 该平台支持的模型。
* 后端把一个渠道按平台聚合成 sections前端可以把渠道名作为 row-group
* 一次渲染,后面按 sections 顺序用 rowspan 铺开。
*/
export interface UserChannelPlatformSection {
platform: string
groups: UserAvailableGroup[]
supported_models: UserSupportedModel[]
}
export interface UserAvailableChannel {
name: string
description: string
platforms: UserChannelPlatformSection[]
}
/** 列出当前用户可见的「可用渠道」(与 /groups/available 保持一致,返回平数组)。 */
export async function getAvailable(options?: { signal?: AbortSignal }): Promise<UserAvailableChannel[]> {
const { data } = await apiClient.get<UserAvailableChannel[]>('/channels/available', {