Merge pull request #5851 from IanShaw027/feat/channel-pricing-tier-multipliers

fix(billing): restore Fast tier pricing under channel overrides, add configurable multipliers
This commit is contained in:
Wesley Liddick authored and GitHub committed 2026-08-20 10:13:17 +08:00
commit 1b5dc676a9
39 files changed
+1303 -280

No files matched your search

+18 -1
View File
@@ -448,6 +448,7 @@
:entry="entry"
:platform="section.platform"
enable-time-pricing
enable-tier-multipliers
@update="updatePricingEntry(sIdx, idx, $event)"
@remove="removePricingEntry(sIdx, idx)"
/>
@@ -633,7 +634,7 @@ import { extractApiErrorMessage } from '@/utils/apiError'
import { adminAPI } from '@/api/admin'
import type { Channel, ChannelModelPricing, CreateChannelRequest, UpdateChannelRequest, AccountStatsPricingRule } from '@/api/admin/channels'
import type { PricingFormEntry } from '@/components/admin/channel/types'
import { apiIntervalsToForm, apiTimePricingToForm, createDefaultTimePricingForm, findModelConflict, formIntervalsToAPI, formTimePricingToAPI, mTokToPerToken, perTokenToMTok, validateIntervals, validateTimePricing } from '@/components/admin/channel/types'
import { apiIntervalsToForm, apiTimePricingToForm, createDefaultTimePricingForm, findModelConflict, formIntervalsToAPI, formTimePricingToAPI, isValidPositiveMultiplier, mTokToPerToken, perTokenToMTok, validateIntervals, validateTimePricing } from '@/components/admin/channel/types'
import type { AdminGroup, GroupPlatform } from '@/types'
import type { Column } from '@/components/common/types'
import { platformTextClass, platformBadgeLightClass } from '@/utils/platformColors'
@@ -861,6 +862,8 @@ function addPricingEntry(sectionIdx: number) {
output_price: null,
cache_write_price: null,
cache_read_price: null,
fast_multiplier: null,
flex_multiplier: null,
image_input_price: null,
image_output_price: null,
per_request_price: null,
@@ -895,6 +898,8 @@ async function syncLatestModels(sectionIdx: number) {
output_price: null,
cache_write_price: null,
cache_read_price: null,
fast_multiplier: null,
flex_multiplier: null,
image_input_price: null,
image_output_price: null,
per_request_price: null,
@@ -1120,6 +1125,8 @@ function formToAPI(): { group_ids: number[], model_pricing: ChannelModelPricing[
output_price: mTokToPerToken(entry.output_price),
cache_write_price: mTokToPerToken(entry.cache_write_price),
cache_read_price: mTokToPerToken(entry.cache_read_price),
fast_multiplier: entry.fast_multiplier != null && entry.fast_multiplier !== '' ? Number(entry.fast_multiplier) : null,
flex_multiplier: entry.flex_multiplier != null && entry.flex_multiplier !== '' ? Number(entry.flex_multiplier) : null,
image_input_price: mTokToPerToken(entry.image_input_price),
image_output_price: mTokToPerToken(entry.image_output_price),
per_request_price: entry.per_request_price != null && entry.per_request_price !== '' ? Number(entry.per_request_price) : null,
@@ -1219,6 +1226,8 @@ function apiToForm(channel: Channel): PlatformSection[] {
output_price: perTokenToMTok(p.output_price),
cache_write_price: perTokenToMTok(p.cache_write_price),
cache_read_price: perTokenToMTok(p.cache_read_price),
fast_multiplier: p.fast_multiplier,
flex_multiplier: p.flex_multiplier,
image_input_price: perTokenToMTok(p.image_input_price),
image_output_price: perTokenToMTok(p.image_output_price),
per_request_price: p.per_request_price,
@@ -1524,6 +1533,14 @@ async function handleSubmit() {
// 校验区间合法性(范围、重叠等)
for (const section of form.platforms.filter(s => s.enabled)) {
for (const entry of section.model_pricing) {
if (!isValidPositiveMultiplier(entry.fast_multiplier) ||
!isValidPositiveMultiplier(entry.flex_multiplier)) {
const platformLabel = t('admin.groups.platforms.' + section.platform, section.platform)
const modelLabel = entry.models.join(', ') || t('admin.channels.form.unnamed')
appStore.showError(`${platformLabel} - ${modelLabel}: ${t('admin.channels.form.multiplierPositive')}`)
activeTab.value = section.platform
return
}
if (!entry.intervals || entry.intervals.length === 0) continue
const intervalErr = validateIntervals(entry.intervals, entry.billing_mode, t)
if (intervalErr) {