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 && ( +