📱 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:
@@ -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 && (
|
||||||
|
|||||||
@@ -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
@@ -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;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user