📱 feat(pricing-header): show only search/copy/filter on mobile; hide vendor intro

- Mobile (isMobile=true): render SearchActions (search, copy, filter) only; hide vendor intro card
- Keep PricingFilterModal available on mobile for filtering
- Desktop/Non-mobile: unchanged behavior (vendor intro remains visible)
- Improves small-screen UX by reducing visual clutter and prioritizing primary actions

Files:
- web/src/components/table/model-pricing/layout/header/PricingTopSection.jsx

Notes:
- Added `SearchActions` import and conditional rendering
- No breaking changes; no styling changes required
This commit is contained in:
t0ng7u
2025-08-29 17:26:51 +08:00
parent 1bc0010f5c
commit 8ceb0316ce
7 changed files with 46 additions and 39 deletions
@@ -20,6 +20,7 @@ For commercial licensing, please contact support@quantumnous.com
import React, { useState, memo } from 'react'; import React, { useState, memo } from 'react';
import PricingFilterModal from '../../modal/PricingFilterModal'; import PricingFilterModal from '../../modal/PricingFilterModal';
import PricingVendorIntroWithSkeleton from './PricingVendorIntroWithSkeleton'; import PricingVendorIntroWithSkeleton from './PricingVendorIntroWithSkeleton';
import SearchActions from './SearchActions';
const PricingTopSection = memo(({ const PricingTopSection = memo(({
selectedRowKeys, selectedRowKeys,
@@ -40,28 +41,43 @@ const PricingTopSection = memo(({
return ( return (
<> <>
<PricingVendorIntroWithSkeleton {isMobile ? (
loading={loading} <>
filterVendor={filterVendor} <div className="w-full">
models={filteredModels} <SearchActions
allModels={models} selectedRowKeys={selectedRowKeys}
t={t} copyText={copyText}
selectedRowKeys={selectedRowKeys} handleChange={handleChange}
copyText={copyText} handleCompositionStart={handleCompositionStart}
handleChange={handleChange} handleCompositionEnd={handleCompositionEnd}
handleCompositionStart={handleCompositionStart} isMobile={isMobile}
handleCompositionEnd={handleCompositionEnd} searchValue={searchValue}
isMobile={isMobile} setShowFilterModal={setShowFilterModal}
searchValue={searchValue} t={t}
setShowFilterModal={setShowFilterModal} />
/> </div>
<PricingFilterModal
{isMobile && ( visible={showFilterModal}
<PricingFilterModal onClose={() => setShowFilterModal(false)}
visible={showFilterModal} sidebarProps={sidebarProps}
onClose={() => setShowFilterModal(false)} t={t}
sidebarProps={sidebarProps} />
</>
) : (
<PricingVendorIntroWithSkeleton
loading={loading}
filterVendor={filterVendor}
models={filteredModels}
allModels={models}
t={t} t={t}
selectedRowKeys={selectedRowKeys}
copyText={copyText}
handleChange={handleChange}
handleCompositionStart={handleCompositionStart}
handleCompositionEnd={handleCompositionEnd}
isMobile={isMobile}
searchValue={searchValue}
setShowFilterModal={setShowFilterModal}
/> />
)} )}
</> </>
@@ -247,7 +247,7 @@ const PricingVendorIntro = memo(({
<Card className="!rounded-2xl shadow-sm border-0" <Card className="!rounded-2xl shadow-sm border-0"
cover={ cover={
<div <div
className="relative h-32" className="relative h-full"
style={createCoverStyle(primaryDarkerChannel)} style={createCoverStyle(primaryDarkerChannel)}
> >
<div className="relative z-10 h-full flex items-center justify-between p-4"> <div className="relative z-10 h-full flex items-center justify-between p-4">
@@ -103,7 +103,7 @@ const PricingVendorIntroSkeleton = memo(({
<Card className="!rounded-2xl shadow-sm border-0" <Card className="!rounded-2xl shadow-sm border-0"
cover={ cover={
<div <div
className="relative h-32" className="relative h-full"
style={SKELETON_STYLES.cover(isAllVendors ? THEME_COLORS.allVendors.primary : THEME_COLORS.specific.primary)} style={SKELETON_STYLES.cover(isAllVendors ? THEME_COLORS.allVendors.primary : THEME_COLORS.specific.primary)}
> >
<div className="relative z-10 h-full flex items-center justify-between p-4"> <div className="relative z-10 h-full flex items-center justify-between p-4">
@@ -26,7 +26,7 @@ const PricingCardSkeleton = ({
showRatio = false showRatio = false
}) => { }) => {
const placeholder = ( const placeholder = (
<div className="px-2"> <div className="px-2 pt-2">
<div className="grid grid-cols-1 xl:grid-cols-2 2xl:grid-cols-3 gap-4"> <div className="grid grid-cols-1 xl:grid-cols-2 2xl:grid-cols-3 gap-4">
{Array.from({ length: skeletonCount }).map((_, index) => ( {Array.from({ length: skeletonCount }).map((_, index) => (
<Card <Card
@@ -202,7 +202,7 @@ const PricingCardView = ({
} }
return ( return (
<div className="px-2"> <div className="px-2 pt-2">
<div className="grid grid-cols-1 xl:grid-cols-2 2xl:grid-cols-3 gap-4"> <div className="grid grid-cols-1 xl:grid-cols-2 2xl:grid-cols-3 gap-4">
{paginatedModels.map((model, index) => { {paginatedModels.map((model, index) => {
const modelKey = getModelKey(model); const modelKey = getModelKey(model);
@@ -278,9 +278,7 @@ const PricingCardView = ({
{/* 底部区域 */} {/* 底部区域 */}
<div className="mt-auto"> <div className="mt-auto">
{/* 标签区域 */} {/* 标签区域 */}
<div className="mb-3"> {renderTags(model)}
{renderTags(model)}
</div>
{/* 倍率信息(可选) */} {/* 倍率信息(可选) */}
{showRatio && ( {showRatio && (
+2 -10
View File
@@ -656,22 +656,15 @@ export const calculateModelPrice = ({
// 格式化价格信息(用于卡片视图) // 格式化价格信息(用于卡片视图)
export const formatPriceInfo = (priceData, t) => { export const formatPriceInfo = (priceData, t) => {
const groupTag = priceData.usedGroup ? (
<span style={{ color: 'var(--semi-color-text-1)' }} className="ml-1 text-xs">
{t('分组')} {priceData.usedGroup}
</span>
) : null;
if (priceData.isPerToken) { if (priceData.isPerToken) {
return ( return (
<> <>
<span style={{ color: 'var(--semi-color-text-1)' }}> <span style={{ color: 'var(--semi-color-text-1)' }}>
{t('提示')} {priceData.inputPrice}/{priceData.unitLabel} {t('输入')} {priceData.inputPrice}/{priceData.unitLabel}
</span> </span>
<span style={{ color: 'var(--semi-color-text-1)' }}> <span style={{ color: 'var(--semi-color-text-1)' }}>
{t('补全')} {priceData.completionPrice}/{priceData.unitLabel} {t('输出')} {priceData.completionPrice}/{priceData.unitLabel}
</span> </span>
{groupTag}
</> </>
); );
} }
@@ -681,7 +674,6 @@ export const formatPriceInfo = (priceData, t) => {
<span style={{ color: 'var(--semi-color-text-1)' }}> <span style={{ color: 'var(--semi-color-text-1)' }}>
{t('模型价格')} {priceData.price} {t('模型价格')} {priceData.price}
</span> </span>
{groupTag}
</> </>
); );
}; };
+2 -1
View File
@@ -775,6 +775,7 @@ html.dark .with-pastel-balls::before {
} }
/* ==================== semi-ui 组件自定义样式 ==================== */ /* ==================== semi-ui 组件自定义样式 ==================== */
.semi-card-header { .semi-card-header,
.semi-card-body {
padding: 10px !important; padding: 10px !important;
} }