📱 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 919e6937ee
commit 5f0db18d3a
7 changed files with 46 additions and 39 deletions

View File

@@ -20,6 +20,7 @@ For commercial licensing, please contact support@quantumnous.com
import React, { useState, memo } from 'react';
import PricingFilterModal from '../../modal/PricingFilterModal';
import PricingVendorIntroWithSkeleton from './PricingVendorIntroWithSkeleton';
import SearchActions from './SearchActions';
const PricingTopSection = memo(({
selectedRowKeys,
@@ -40,28 +41,43 @@ const PricingTopSection = memo(({
return (
<>
<PricingVendorIntroWithSkeleton
loading={loading}
filterVendor={filterVendor}
models={filteredModels}
allModels={models}
t={t}
selectedRowKeys={selectedRowKeys}
copyText={copyText}
handleChange={handleChange}
handleCompositionStart={handleCompositionStart}
handleCompositionEnd={handleCompositionEnd}
isMobile={isMobile}
searchValue={searchValue}
setShowFilterModal={setShowFilterModal}
/>
{isMobile && (
<PricingFilterModal
visible={showFilterModal}
onClose={() => setShowFilterModal(false)}
sidebarProps={sidebarProps}
{isMobile ? (
<>
<div className="w-full">
<SearchActions
selectedRowKeys={selectedRowKeys}
copyText={copyText}
handleChange={handleChange}
handleCompositionStart={handleCompositionStart}
handleCompositionEnd={handleCompositionEnd}
isMobile={isMobile}
searchValue={searchValue}
setShowFilterModal={setShowFilterModal}
t={t}
/>
</div>
<PricingFilterModal
visible={showFilterModal}
onClose={() => setShowFilterModal(false)}
sidebarProps={sidebarProps}
t={t}
/>
</>
) : (
<PricingVendorIntroWithSkeleton
loading={loading}
filterVendor={filterVendor}
models={filteredModels}
allModels={models}
t={t}
selectedRowKeys={selectedRowKeys}
copyText={copyText}
handleChange={handleChange}
handleCompositionStart={handleCompositionStart}
handleCompositionEnd={handleCompositionEnd}
isMobile={isMobile}
searchValue={searchValue}
setShowFilterModal={setShowFilterModal}
/>
)}
</>

View File

@@ -247,7 +247,7 @@ const PricingVendorIntro = memo(({
<Card className="!rounded-2xl shadow-sm border-0"
cover={
<div
className="relative h-32"
className="relative h-full"
style={createCoverStyle(primaryDarkerChannel)}
>
<div className="relative z-10 h-full flex items-center justify-between p-4">

View File

@@ -103,7 +103,7 @@ const PricingVendorIntroSkeleton = memo(({
<Card className="!rounded-2xl shadow-sm border-0"
cover={
<div
className="relative h-32"
className="relative h-full"
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">

View File

@@ -26,7 +26,7 @@ const PricingCardSkeleton = ({
showRatio = false
}) => {
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">
{Array.from({ length: skeletonCount }).map((_, index) => (
<Card

View File

@@ -202,7 +202,7 @@ const PricingCardView = ({
}
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">
{paginatedModels.map((model, index) => {
const modelKey = getModelKey(model);
@@ -278,9 +278,7 @@ const PricingCardView = ({
{/* 底部区域 */}
<div className="mt-auto">
{/* 标签区域 */}
<div className="mb-3">
{renderTags(model)}
</div>
{renderTags(model)}
{/* 倍率信息(可选) */}
{showRatio && (

View File

@@ -656,22 +656,15 @@ export const calculateModelPrice = ({
// 格式化价格信息(用于卡片视图)
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) {
return (
<>
<span style={{ color: 'var(--semi-color-text-1)' }}>
{t('提示')} {priceData.inputPrice}/{priceData.unitLabel}
{t('输入')} {priceData.inputPrice}/{priceData.unitLabel}
</span>
<span style={{ color: 'var(--semi-color-text-1)' }}>
{t('补全')} {priceData.completionPrice}/{priceData.unitLabel}
{t('输出')} {priceData.completionPrice}/{priceData.unitLabel}
</span>
{groupTag}
</>
);
}
@@ -681,7 +674,6 @@ export const formatPriceInfo = (priceData, t) => {
<span style={{ color: 'var(--semi-color-text-1)' }}>
{t('模型价格')} {priceData.price}
</span>
{groupTag}
</>
);
};

View File

@@ -775,6 +775,7 @@ html.dark .with-pastel-balls::before {
}
/* ==================== semi-ui 组件自定义样式 ==================== */
.semi-card-header {
.semi-card-header,
.semi-card-body {
padding: 10px !important;
}