feat(channel): 渠道管理系统 — 多模式定价 + 统一计费解析

Cherry-picked from release/custom-0.1.106: a9117600
This commit is contained in:
erio
2026-04-04 11:00:55 +08:00
parent b384570de3
commit 91c9b8d062
27 changed files with 3682 additions and 8 deletions

View File

@@ -0,0 +1,121 @@
/**
* Admin Channels API endpoints
* Handles channel management for administrators
*/
import { apiClient } from '../client'
export type BillingMode = 'token' | 'per_request' | 'image'
export interface PricingInterval {
id?: number
min_tokens: number
max_tokens: number | null
tier_label: string
input_price: number | null
output_price: number | null
cache_write_price: number | null
cache_read_price: number | null
per_request_price: number | null
sort_order: number
}
export interface ChannelModelPricing {
id?: number
models: string[]
billing_mode: BillingMode
input_price: number | null
output_price: number | null
cache_write_price: number | null
cache_read_price: number | null
image_output_price: number | null
intervals: PricingInterval[]
}
export interface Channel {
id: number
name: string
description: string
status: string
group_ids: number[]
model_pricing: ChannelModelPricing[]
created_at: string
updated_at: string
}
export interface CreateChannelRequest {
name: string
description?: string
group_ids?: number[]
model_pricing?: ChannelModelPricing[]
}
export interface UpdateChannelRequest {
name?: string
description?: string
status?: string
group_ids?: number[]
model_pricing?: ChannelModelPricing[]
}
interface PaginatedResponse<T> {
items: T[]
total: number
}
/**
* List channels with pagination
*/
export async function list(
page: number = 1,
pageSize: number = 20,
filters?: {
status?: string
search?: string
},
options?: { signal?: AbortSignal }
): Promise<PaginatedResponse<Channel>> {
const { data } = await apiClient.get<PaginatedResponse<Channel>>('/admin/channels', {
params: {
page,
page_size: pageSize,
...filters
},
signal: options?.signal
})
return data
}
/**
* Get channel by ID
*/
export async function getById(id: number): Promise<Channel> {
const { data } = await apiClient.get<Channel>(`/admin/channels/${id}`)
return data
}
/**
* Create a new channel
*/
export async function create(req: CreateChannelRequest): Promise<Channel> {
const { data } = await apiClient.post<Channel>('/admin/channels', req)
return data
}
/**
* Update a channel
*/
export async function update(id: number, req: UpdateChannelRequest): Promise<Channel> {
const { data } = await apiClient.put<Channel>(`/admin/channels/${id}`, req)
return data
}
/**
* Delete a channel
*/
export async function remove(id: number): Promise<void> {
await apiClient.delete(`/admin/channels/${id}`)
}
const channelsAPI = { list, getById, create, update, remove }
export default channelsAPI

View File

@@ -25,6 +25,7 @@ import apiKeysAPI from './apiKeys'
import scheduledTestsAPI from './scheduledTests'
import backupAPI from './backup'
import tlsFingerprintProfileAPI from './tlsFingerprintProfile'
import channelsAPI from './channels'
/**
* Unified admin API object for convenient access
@@ -51,7 +52,8 @@ export const adminAPI = {
apiKeys: apiKeysAPI,
scheduledTests: scheduledTestsAPI,
backup: backupAPI,
tlsFingerprintProfiles: tlsFingerprintProfileAPI
tlsFingerprintProfiles: tlsFingerprintProfileAPI,
channels: channelsAPI
}
export {
@@ -76,7 +78,8 @@ export {
apiKeysAPI,
scheduledTestsAPI,
backupAPI,
tlsFingerprintProfileAPI
tlsFingerprintProfileAPI,
channelsAPI
}
export default adminAPI