diff --git a/web/src/components/common/ui/ScrollableContainer.jsx b/web/src/components/common/ui/ScrollableContainer.jsx
index 0137c64b..4ddda7d8 100644
--- a/web/src/components/common/ui/ScrollableContainer.jsx
+++ b/web/src/components/common/ui/ScrollableContainer.jsx
@@ -38,7 +38,7 @@ const ScrollableContainer = forwardRef(({
children,
maxHeight = '24rem',
className = '',
- contentClassName = 'p-2',
+ contentClassName = '',
fadeIndicatorClassName = '',
checkInterval = 100,
scrollThreshold = 5,
diff --git a/web/src/components/common/ui/SelectableButtonGroup.jsx b/web/src/components/common/ui/SelectableButtonGroup.jsx
index 8637c821..2dd8f657 100644
--- a/web/src/components/common/ui/SelectableButtonGroup.jsx
+++ b/web/src/components/common/ui/SelectableButtonGroup.jsx
@@ -17,8 +17,7 @@ along with this program. If not, see .
For commercial licensing, please contact support@quantumnous.com
*/
-import React, { useState } from 'react';
-import { useIsMobile } from '../../../hooks/common/useIsMobile';
+import React, { useState, useRef, useEffect } from 'react';
import { useMinimumLoadingTime } from '../../../hooks/common/useMinimumLoadingTime';
import { useContainerWidth } from '../../../hooks/common/useContainerWidth';
import { Divider, Button, Tag, Row, Col, Collapsible, Checkbox, Skeleton, Tooltip } from '@douyinfe/semi-ui';
@@ -51,10 +50,34 @@ const SelectableButtonGroup = ({
loading = false
}) => {
const [isOpen, setIsOpen] = useState(false);
- const [skeletonCount] = useState(6);
- const isMobile = useIsMobile();
+ const [skeletonCount] = useState(12);
const [containerRef, containerWidth] = useContainerWidth();
+ const ConditionalTooltipText = ({ text }) => {
+ const textRef = useRef(null);
+ const [isOverflowing, setIsOverflowing] = useState(false);
+
+ useEffect(() => {
+ const el = textRef.current;
+ if (!el) return;
+ setIsOverflowing(el.scrollWidth > el.clientWidth);
+ }, [text, containerWidth]);
+
+ const textElement = (
+
+ {text}
+
+ );
+
+ return isOverflowing ? (
+
+ {textElement}
+
+ ) : (
+ textElement
+ );
+ };
+
// 基于容器宽度计算响应式列数和标签显示策略
const getResponsiveConfig = () => {
if (containerWidth <= 280) return { columns: 1, showTags: true }; // 极窄:1列+标签
@@ -176,9 +199,7 @@ const SelectableButtonGroup = ({
>
{item.icon && (
{item.icon})}
-
- {item.label}
-
+
{item.tagCount !== undefined && shouldShowTags && (
{item.tagCount}
)}
@@ -203,9 +224,7 @@ const SelectableButtonGroup = ({
>
{item.icon && ({item.icon})}
-
- {item.label}
-
+
{item.tagCount !== undefined && shouldShowTags && (
{item.tagCount}
)}
diff --git a/web/src/components/table/model-pricing/layout/PricingSidebar.jsx b/web/src/components/table/model-pricing/layout/PricingSidebar.jsx
index 074ee181..2a46e1c8 100644
--- a/web/src/components/table/model-pricing/layout/PricingSidebar.jsx
+++ b/web/src/components/table/model-pricing/layout/PricingSidebar.jsx
@@ -24,7 +24,7 @@ import PricingQuotaTypes from '../filter/PricingQuotaTypes';
import PricingEndpointTypes from '../filter/PricingEndpointTypes';
import PricingVendors from '../filter/PricingVendors';
import PricingTags from '../filter/PricingTags';
-import PricingDisplaySettings from '../filter/PricingDisplaySettings';
+
import { resetPricingFilters } from '../../../../helpers/utils';
import { usePricingFilterCounts } from '../../../../hooks/model-pricing/usePricingFilterCounts';
@@ -107,21 +107,6 @@ const PricingSidebar = ({
-
-
{
{/* 固定的顶部区域(分类介绍 + 搜索和操作) */}
{/* 可滚动的内容区域 */}
diff --git a/web/src/components/table/model-pricing/layout/header/PricingTopSection.jsx b/web/src/components/table/model-pricing/layout/header/PricingTopSection.jsx
index fe842fe3..78cea080 100644
--- a/web/src/components/table/model-pricing/layout/header/PricingTopSection.jsx
+++ b/web/src/components/table/model-pricing/layout/header/PricingTopSection.jsx
@@ -35,6 +35,16 @@ const PricingTopSection = memo(({
filteredModels,
loading,
searchValue,
+ showWithRecharge,
+ setShowWithRecharge,
+ currency,
+ setCurrency,
+ showRatio,
+ setShowRatio,
+ viewMode,
+ setViewMode,
+ tokenUnit,
+ setTokenUnit,
t
}) => {
const [showFilterModal, setShowFilterModal] = useState(false);
@@ -53,6 +63,16 @@ const PricingTopSection = memo(({
isMobile={isMobile}
searchValue={searchValue}
setShowFilterModal={setShowFilterModal}
+ showWithRecharge={showWithRecharge}
+ setShowWithRecharge={setShowWithRecharge}
+ currency={currency}
+ setCurrency={setCurrency}
+ showRatio={showRatio}
+ setShowRatio={setShowRatio}
+ viewMode={viewMode}
+ setViewMode={setViewMode}
+ tokenUnit={tokenUnit}
+ setTokenUnit={setTokenUnit}
t={t}
/>
@@ -78,6 +98,16 @@ const PricingTopSection = memo(({
isMobile={isMobile}
searchValue={searchValue}
setShowFilterModal={setShowFilterModal}
+ showWithRecharge={showWithRecharge}
+ setShowWithRecharge={setShowWithRecharge}
+ currency={currency}
+ setCurrency={setCurrency}
+ showRatio={showRatio}
+ setShowRatio={setShowRatio}
+ viewMode={viewMode}
+ setViewMode={setViewMode}
+ tokenUnit={tokenUnit}
+ setTokenUnit={setTokenUnit}
/>
)}
>
diff --git a/web/src/components/table/model-pricing/layout/header/PricingVendorIntro.jsx b/web/src/components/table/model-pricing/layout/header/PricingVendorIntro.jsx
index 2f02bd2b..718b94bb 100644
--- a/web/src/components/table/model-pricing/layout/header/PricingVendorIntro.jsx
+++ b/web/src/components/table/model-pricing/layout/header/PricingVendorIntro.jsx
@@ -126,7 +126,17 @@ const PricingVendorIntro = memo(({
handleCompositionEnd,
isMobile = false,
searchValue = '',
- setShowFilterModal
+ setShowFilterModal,
+ showWithRecharge,
+ setShowWithRecharge,
+ currency,
+ setCurrency,
+ showRatio,
+ setShowRatio,
+ viewMode,
+ setViewMode,
+ tokenUnit,
+ setTokenUnit
}) => {
const [currentOffset, setCurrentOffset] = useState(0);
const [descModalVisible, setDescModalVisible] = useState(false);
@@ -239,9 +249,19 @@ const PricingVendorIntro = memo(({
isMobile={isMobile}
searchValue={searchValue}
setShowFilterModal={setShowFilterModal}
+ showWithRecharge={showWithRecharge}
+ setShowWithRecharge={setShowWithRecharge}
+ currency={currency}
+ setCurrency={setCurrency}
+ showRatio={showRatio}
+ setShowRatio={setShowRatio}
+ viewMode={viewMode}
+ setViewMode={setViewMode}
+ tokenUnit={tokenUnit}
+ setTokenUnit={setTokenUnit}
t={t}
/>
- ), [selectedRowKeys, copyText, handleChange, handleCompositionStart, handleCompositionEnd, isMobile, searchValue, setShowFilterModal, t]);
+ ), [selectedRowKeys, copyText, handleChange, handleCompositionStart, handleCompositionEnd, isMobile, searchValue, setShowFilterModal, showWithRecharge, setShowWithRecharge, currency, setCurrency, showRatio, setShowRatio, viewMode, setViewMode, tokenUnit, setTokenUnit, t]);
const renderHeaderCard = useCallback(({ title, count, description, rightContent, primaryDarkerChannel }) => (
{
const handleCopyClick = useCallback(() => {
@@ -42,6 +52,14 @@ const SearchActions = memo(({
setShowFilterModal?.(true);
}, [setShowFilterModal]);
+ const handleViewModeToggle = useCallback(() => {
+ setViewMode?.(viewMode === 'table' ? 'card' : 'table');
+ }, [viewMode, setViewMode]);
+
+ const handleTokenUnitToggle = useCallback(() => {
+ setTokenUnit?.(tokenUnit === 'K' ? 'M' : 'K');
+ }, [tokenUnit, setTokenUnit]);
+
return (
@@ -67,6 +85,63 @@ const SearchActions = memo(({
{t('复制')}
+ {!isMobile && (
+ <>
+
+
+ {/* 充值价格显示开关 */}
+
+ {t('充值价格显示')}
+
+
+
+ {/* 货币单位选择 */}
+ {showWithRecharge && (
+
+ )}
+
+ {/* 显示倍率开关 */}
+
+ {t('倍率')}
+
+
+
+
+
+
+ {/* 视图模式切换按钮 */}
+
+
+ {/* Token单位切换按钮 */}
+
+ >
+ )}
+
{isMobile && (