- {renderPriceInfo(model)}
+ {formatPriceInfo(priceData, t)}
@@ -313,7 +309,7 @@ const PricingCardView = ({
{t('补全')}: {model.quota_type === 0 ? parseFloat(model.completion_ratio.toFixed(3)) : t('无')}
- {t('分组')}: {priceData.usedGroupRatio}
+ {t('分组')}: {priceData?.usedGroupRatio ?? '-'}
diff --git a/web/src/components/table/model-pricing/view/table/PricingTableColumns.js b/web/src/components/table/model-pricing/view/table/PricingTableColumns.js
index 18e1fc89..0dd963a8 100644
--- a/web/src/components/table/model-pricing/view/table/PricingTableColumns.js
+++ b/web/src/components/table/model-pricing/view/table/PricingTableColumns.js
@@ -98,6 +98,25 @@ export const getPricingTableColumns = ({
displayPrice,
showRatio,
}) => {
+
+ const priceDataCache = new WeakMap();
+
+ const getPriceData = (record) => {
+ let cache = priceDataCache.get(record);
+ if (!cache) {
+ cache = calculateModelPrice({
+ record,
+ selectedGroup,
+ groupRatio,
+ tokenUnit,
+ displayPrice,
+ currency,
+ });
+ priceDataCache.set(record, cache);
+ }
+ return cache;
+ };
+
const endpointColumn = {
title: t('可用端点类型'),
dataIndex: 'supported_endpoint_types',
@@ -167,21 +186,21 @@ export const getPricingTableColumns = ({
dataIndex: 'model_ratio',
render: (text, record, index) => {
const completionRatio = parseFloat(record.completion_ratio.toFixed(3));
- const content = (
+ const priceData = getPriceData(record);
+
+ return (
{t('模型倍率')}:{record.quota_type === 0 ? text : t('无')}
- {t('补全倍率')}:
- {record.quota_type === 0 ? completionRatio : t('无')}
+ {t('补全倍率')}:{record.quota_type === 0 ? completionRatio : t('无')}
- {t('分组倍率')}:{groupRatio[selectedGroup]}
+ {t('分组倍率')}:{priceData?.usedGroupRatio ?? '-'}
);
- return content;
},
};
@@ -190,14 +209,7 @@ export const getPricingTableColumns = ({
dataIndex: 'model_price',
fixed: 'right',
render: (text, record, index) => {
- const priceData = calculateModelPrice({
- record,
- selectedGroup,
- groupRatio,
- tokenUnit,
- displayPrice,
- currency
- });
+ const priceData = getPriceData(record);
if (priceData.isPerToken) {
return (
diff --git a/web/src/components/table/tokens/TokensColumnDefs.js b/web/src/components/table/tokens/TokensColumnDefs.js
index 1d2ab9dd..443c59d3 100644
--- a/web/src/components/table/tokens/TokensColumnDefs.js
+++ b/web/src/components/table/tokens/TokensColumnDefs.js
@@ -305,6 +305,7 @@ const renderOperations = (text, record, onOpenLink, setEditingToken, setShowEdit
node: 'item',
key: i,
name,
+ value: item[name],
onClick: () => onOpenLink(name, item[name], record),
});
}
@@ -326,11 +327,8 @@ const renderOperations = (text, record, onOpenLink, setEditingToken, setShowEdit
if (chatsArray.length === 0) {
showError(t('请联系管理员配置聊天链接'));
} else {
- onOpenLink(
- 'default',
- chatsArray[0].name ? (parsed => parsed)(localStorage.getItem('chats')) : '',
- record,
- );
+ const first = chatsArray[0];
+ onOpenLink(first.name, first.value, record);
}
}}
>
diff --git a/web/src/hooks/model-pricing/useModelPricingData.js b/web/src/hooks/model-pricing/useModelPricingData.js
index c285cf4d..d209089c 100644
--- a/web/src/hooks/model-pricing/useModelPricingData.js
+++ b/web/src/hooks/model-pricing/useModelPricingData.js
@@ -211,9 +211,6 @@ export const useModelPricingData = () => {
};
const handleChange = (value) => {
- if (compositionRef.current.isComposition) {
- return;
- }
const newSearchValue = value ? value : '';
setSearchValue(newSearchValue);
};
@@ -231,9 +228,7 @@ export const useModelPricingData = () => {
const handleGroupClick = (group) => {
setSelectedGroup(group);
- // 同时将分组过滤设置为该分组
setFilterGroup(group);
-
if (group === 'all') {
showInfo(t('已切换至最优倍率视图,每个模型使用其最低倍率分组'));
} else {
diff --git a/web/src/hooks/model-pricing/usePricingFilterCounts.js b/web/src/hooks/model-pricing/usePricingFilterCounts.js
index ee7f41c7..046d3729 100644
--- a/web/src/hooks/model-pricing/usePricingFilterCounts.js
+++ b/web/src/hooks/model-pricing/usePricingFilterCounts.js
@@ -104,34 +104,27 @@ export const usePricingFilterCounts = ({
// 生成不同视图所需的模型集合
const quotaTypeModels = useMemo(
() => allModels.filter((m) => matchesFilters(m, ['quota'])),
- [allModels, filterGroup, filterEndpointType, filterVendor, filterTag]
+ [allModels, filterGroup, filterEndpointType, filterVendor, filterTag, searchValue]
);
const endpointTypeModels = useMemo(
() => allModels.filter((m) => matchesFilters(m, ['endpoint'])),
- [allModels, filterGroup, filterQuotaType, filterVendor, filterTag]
+ [allModels, filterGroup, filterQuotaType, filterVendor, filterTag, searchValue]
);
const vendorModels = useMemo(
() => allModels.filter((m) => matchesFilters(m, ['vendor'])),
- [allModels, filterGroup, filterQuotaType, filterEndpointType, filterTag]
+ [allModels, filterGroup, filterQuotaType, filterEndpointType, filterTag, searchValue]
);
const tagModels = useMemo(
() => allModels.filter((m) => matchesFilters(m, ['tag'])),
- [allModels, filterGroup, filterQuotaType, filterEndpointType, filterVendor]
+ [allModels, filterGroup, filterQuotaType, filterEndpointType, filterVendor, searchValue]
);
const groupCountModels = useMemo(
() => allModels.filter((m) => matchesFilters(m, ['group'])),
- [
- allModels,
- filterQuotaType,
- filterEndpointType,
- filterVendor,
- filterTag,
- searchValue,
- ]
+ [allModels, filterQuotaType, filterEndpointType, filterVendor, filterTag, searchValue]
);
return {