♻️ refactor(model-pricing): improve table UI and optimize code structure (#1365)

- Replace model count with group ratio display (x2.2, x1) in group filter
- Remove redundant "Available Groups" column from pricing table
- Remove "Availability" column and related logic completely
- Move "Supported Endpoint Types" column to fixed right position
- Clean up unused parameters and variables in PricingTableColumns.js
- Optimize variable declarations (let → const) and simplify render logic
- Improve code readability and reduce memory allocations

This refactor enhances user experience by:
- Providing clearer group ratio information in filters
- Simplifying table layout while maintaining essential functionality
- Improving performance through better code organization

Breaking changes: None
This commit is contained in:
t0ng7u
2025-07-23 11:20:55 +08:00
parent 8a54512037
commit a99dbc78c9
4 changed files with 31 additions and 107 deletions

View File

@@ -84,7 +84,7 @@ const PricingSidebar = ({
<PricingCategories {...categoryProps} setActiveKey={setActiveKey} loading={loading} t={t} />
<PricingGroups filterGroup={filterGroup} setFilterGroup={setFilterGroup} usableGroup={categoryProps.usableGroup} models={categoryProps.models} loading={loading} t={t} />
<PricingGroups filterGroup={filterGroup} setFilterGroup={setFilterGroup} usableGroup={categoryProps.usableGroup} groupRatio={categoryProps.groupRatio} models={categoryProps.models} loading={loading} t={t} />
<PricingQuotaTypes filterQuotaType={filterQuotaType} setFilterQuotaType={setFilterQuotaType} models={categoryProps.models} loading={loading} t={t} />
</div>

View File

@@ -19,8 +19,7 @@ For commercial licensing, please contact support@quantumnous.com
import React from 'react';
import { Tag, Space, Tooltip, Switch } from '@douyinfe/semi-ui';
import { IconHelpCircle, IconCheckCircleStroked, IconClose } from '@douyinfe/semi-icons';
import { Popover } from '@douyinfe/semi-ui';
import { IconHelpCircle } from '@douyinfe/semi-icons';
import { renderModelTag, stringToColor } from '../../../helpers';
function renderQuotaType(type, t) {
@@ -42,33 +41,6 @@ function renderQuotaType(type, t) {
}
}
function renderAvailable(available, t) {
if (available) {
return (
<Popover
content={<div style={{ padding: 8 }}>{t('您的分组可以使用该模型')}</div>}
position='top'
key={String(available)}
className="bg-green-50"
>
<IconCheckCircleStroked style={{ color: 'rgb(22 163 74)' }} size='large' />
</Popover>
);
}
// 分组不可用时显示红色关闭图标
return (
<Popover
content={<div style={{ padding: 8 }}>{t('你的分组无权使用该模型')}</div>}
position='top'
key="not-available"
className="bg-red-50"
>
<IconClose style={{ color: 'rgb(239 68 68)' }} size='large' />
</Popover>
);
}
function renderSupportedEndpoints(endpoints) {
if (!endpoints || endpoints.length === 0) {
return null;
@@ -91,22 +63,20 @@ function renderSupportedEndpoints(endpoints) {
export const getPricingTableColumns = ({
t,
selectedGroup,
usableGroup,
groupRatio,
copyText,
setModalImageUrl,
setIsModalOpenurl,
currency,
showWithRecharge,
tokenUnit,
setTokenUnit,
displayPrice,
handleGroupClick,
showRatio,
}) => {
const endpointColumn = {
title: t('可用端点类型'),
dataIndex: 'supported_endpoint_types',
fixed: 'right',
render: (text, record, index) => {
return renderSupportedEndpoints(text);
},
@@ -135,56 +105,7 @@ export const getPricingTableColumns = ({
sorter: (a, b) => a.quota_type - b.quota_type,
};
const enableGroupColumn = {
title: t('可用分组'),
dataIndex: 'enable_groups',
render: (text, record, index) => {
return (
<Space wrap>
{text.map((group) => {
if (usableGroup[group]) {
if (group === selectedGroup) {
return (
<Tag key={group} color='blue' shape='circle' prefixIcon={<IconCheckCircleStroked />}>
{group}
</Tag>
);
} else {
return (
<Tag
key={group}
color='blue'
shape='circle'
onClick={() => handleGroupClick(group)}
className="cursor-pointer hover:opacity-80 transition-opacity"
>
{group}
</Tag>
);
}
}
})}
</Space>
);
},
};
const baseColumns = [endpointColumn, modelNameColumn, quotaColumn, enableGroupColumn];
const availabilityColumn = {
title: t('可用性'),
dataIndex: 'available',
fixed: 'right',
render: (text, record, index) => {
return renderAvailable(record.enable_groups.includes(selectedGroup), t);
},
sorter: (a, b) => {
const aAvailable = a.enable_groups.includes(selectedGroup);
const bAvailable = b.enable_groups.includes(selectedGroup);
return Number(aAvailable) - Number(bAvailable);
},
defaultSortOrder: 'descend',
};
const baseColumns = [modelNameColumn, quotaColumn];
const ratioColumn = {
title: () => (
@@ -203,9 +124,8 @@ export const getPricingTableColumns = ({
),
dataIndex: 'model_ratio',
render: (text, record, index) => {
let content = text;
let completionRatio = parseFloat(record.completion_ratio.toFixed(3));
content = (
const completionRatio = parseFloat(record.completion_ratio.toFixed(3));
const content = (
<div className="space-y-1">
<div className="text-gray-700">
{t('模型倍率')}{record.quota_type === 0 ? text : t('无')}
@@ -238,25 +158,23 @@ export const getPricingTableColumns = ({
),
dataIndex: 'model_price',
render: (text, record, index) => {
let content = text;
if (record.quota_type === 0) {
let inputRatioPriceUSD = record.model_ratio * 2 * groupRatio[selectedGroup];
let completionRatioPriceUSD =
const inputRatioPriceUSD = record.model_ratio * 2 * groupRatio[selectedGroup];
const completionRatioPriceUSD =
record.model_ratio * record.completion_ratio * 2 * groupRatio[selectedGroup];
const unitDivisor = tokenUnit === 'K' ? 1000 : 1;
const unitLabel = tokenUnit === 'K' ? 'K' : 'M';
let displayInput = displayPrice(inputRatioPriceUSD);
let displayCompletion = displayPrice(completionRatioPriceUSD);
const rawDisplayInput = displayPrice(inputRatioPriceUSD);
const rawDisplayCompletion = displayPrice(completionRatioPriceUSD);
const divisor = unitDivisor;
const numInput = parseFloat(displayInput.replace(/[^0-9.]/g, '')) / divisor;
const numCompletion = parseFloat(displayCompletion.replace(/[^0-9.]/g, '')) / divisor;
const numInput = parseFloat(rawDisplayInput.replace(/[^0-9.]/g, '')) / unitDivisor;
const numCompletion = parseFloat(rawDisplayCompletion.replace(/[^0-9.]/g, '')) / unitDivisor;
displayInput = `${currency === 'CNY' ? '¥' : '$'}${numInput.toFixed(3)}`;
displayCompletion = `${currency === 'CNY' ? '¥' : '$'}${numCompletion.toFixed(3)}`;
content = (
const displayInput = `${currency === 'CNY' ? '¥' : '$'}${numInput.toFixed(3)}`;
const displayCompletion = `${currency === 'CNY' ? '¥' : '$'}${numCompletion.toFixed(3)}`;
return (
<div className="space-y-1">
<div className="text-gray-700">
{t('提示')} {displayInput} / 1{unitLabel} tokens
@@ -267,15 +185,14 @@ export const getPricingTableColumns = ({
</div>
);
} else {
let priceUSD = parseFloat(text) * groupRatio[selectedGroup];
let displayVal = displayPrice(priceUSD);
content = (
const priceUSD = parseFloat(text) * groupRatio[selectedGroup];
const displayVal = displayPrice(priceUSD);
return (
<div className="text-gray-700">
{t('模型价格')}{displayVal}
</div>
);
}
return content;
},
};
@@ -284,6 +201,6 @@ export const getPricingTableColumns = ({
columns.push(ratioColumn);
}
columns.push(priceColumn);
columns.push(availabilityColumn);
columns.push(endpointColumn);
return columns;
};

View File

@@ -25,24 +25,30 @@ import SelectableButtonGroup from '../../../common/ui/SelectableButtonGroup';
* @param {string} filterGroup 当前选中的分组,'all' 表示不过滤
* @param {Function} setFilterGroup 设置选中分组
* @param {Record<string, any>} usableGroup 后端返回的可用分组对象
* @param {Record<string, number>} groupRatio 分组倍率对象
* @param {Array} models 模型列表
* @param {boolean} loading 是否加载中
* @param {Function} t i18n
*/
const PricingGroups = ({ filterGroup, setFilterGroup, usableGroup = {}, models = [], loading = false, t }) => {
const PricingGroups = ({ filterGroup, setFilterGroup, usableGroup = {}, groupRatio = {}, models = [], loading = false, t }) => {
const groups = ['all', ...Object.keys(usableGroup).filter(key => key !== '')];
const items = groups.map((g) => {
let count = 0;
let ratioDisplay = '';
if (g === 'all') {
count = models.length;
ratioDisplay = t('全部');
} else {
count = models.filter(m => m.enable_groups && m.enable_groups.includes(g)).length;
const ratio = groupRatio[g];
if (ratio !== undefined && ratio !== null) {
ratioDisplay = `x${ratio}`;
} else {
ratioDisplay = 'x1';
}
}
return {
value: g,
label: g === 'all' ? t('全部分组') : g,
tagCount: count,
tagCount: ratioDisplay,
};
});

View File

@@ -116,6 +116,7 @@ const PricingFilterModal = ({
filterGroup={filterGroup}
setFilterGroup={setFilterGroup}
usableGroup={categoryProps.usableGroup}
groupRatio={categoryProps.groupRatio}
models={categoryProps.models}
loading={loading}
t={t}