💱 feat(model-pricing): add currency (USD/CNY) & token unit (M/K) toggles to Model Pricing table

* Introduced a currency switch to toggle prices between USD and CNY.
  * CNY prices are calculated by multiplying USD prices with the site-wide `price` rate from `/api/status`.
* Added a second switch to display prices per 1 M tokens or per 1 K tokens.
  * When “K” is selected, prices are divided by 1 000 and labels are updated accordingly.
* Extended component state with `currency` and `tokenUnit` variables.
* Integrated `StatusContext` to retrieve and memoize the current exchange rate.
* Updated price rendering logic and labels to reflect selected currency and token unit.
* Minor UI tweaks: kept Switch components compact and aligned with the table header.

No breaking changes.
This commit is contained in:
t0ng7u
2025-07-17 19:07:11 +08:00
parent 28d8d82ded
commit afa9c650fe

View File

@@ -16,7 +16,8 @@ import {
Card,
Tabs,
TabPane,
Empty
Empty,
Switch
} from '@douyinfe/semi-ui';
import {
IllustrationNoResult,
@@ -32,6 +33,7 @@ import {
} from '@douyinfe/semi-icons';
import { UserContext } from '../../context/User/index.js';
import { AlertCircle } from 'lucide-react';
import { StatusContext } from '../../context/Status/index.js';
const ModelPricing = () => {
const { t } = useTranslation();
@@ -44,6 +46,13 @@ const ModelPricing = () => {
const [activeKey, setActiveKey] = useState('all');
const [pageSize, setPageSize] = useState(10);
const [currency, setCurrency] = useState('USD');
const [tokenUnit, setTokenUnit] = useState('M');
const [statusState] = useContext(StatusContext);
const priceRate = useMemo(() => {
return statusState?.status?.price || 1;
}, [statusState]);
const rowSelection = useMemo(
() => ({
onChange: (selectedRowKeys, selectedRows) => {
@@ -245,33 +254,61 @@ const ModelPricing = () => {
},
},
{
title: t('模型价格'),
title: (
<div className="flex items-center space-x-2">
<span>{t('模型价格')}</span>
{/* 货币切换 */}
<Switch
checked={currency === 'RMB'}
onChange={(checked) => setCurrency(checked ? 'RMB' : 'USD')}
checkedText="¥"
uncheckedText="$"
/>
{/* 计费单位切换 */}
<Switch
checked={tokenUnit === 'K'}
onChange={(checked) => setTokenUnit(checked ? 'K' : 'M')}
checkedText="K"
uncheckedText="M"
/>
</div>
),
dataIndex: 'model_price',
render: (text, record, index) => {
let content = text;
if (record.quota_type === 0) {
let inputRatioPrice =
record.model_ratio * 2 * groupRatio[selectedGroup];
let inputRatioPrice = record.model_ratio * 2 * groupRatio[selectedGroup];
let completionRatioPrice =
record.model_ratio *
record.completion_ratio *
2 *
groupRatio[selectedGroup];
record.model_ratio * record.completion_ratio * 2 * groupRatio[selectedGroup];
if (currency === 'RMB') {
inputRatioPrice = inputRatioPrice * priceRate;
completionRatioPrice = completionRatioPrice * priceRate;
}
const unitDivisor = tokenUnit === 'K' ? 1000 : 1;
const unitLabel = tokenUnit === 'K' ? 'K' : 'M';
inputRatioPrice = inputRatioPrice / unitDivisor;
completionRatioPrice = completionRatioPrice / unitDivisor;
content = (
<div className="space-y-1">
<div className="text-gray-700">
{t('提示')} ${inputRatioPrice.toFixed(3)} / 1M tokens
{t('提示')} {currency === 'USD' ? '$' : '¥'}{inputRatioPrice.toFixed(3)} / 1{unitLabel} tokens
</div>
<div className="text-gray-700">
{t('补全')} ${completionRatioPrice.toFixed(3)} / 1M tokens
{t('补全')} {currency === 'USD' ? '$' : '¥'}{completionRatioPrice.toFixed(3)} / 1{unitLabel} tokens
</div>
</div>
);
} else {
let price = parseFloat(text) * groupRatio[selectedGroup];
if (currency === 'RMB') {
price = price * priceRate;
}
content = (
<div className="text-gray-700">
{t('模型价格')}${price.toFixed(3)}
{t('模型价格')}{currency === 'USD' ? '$' : '¥'}{price.toFixed(3)}
</div>
);
}