🎨 refactor(model-pricing/header): unify header design, extract SearchActions, and improve skeleton

- Extract SearchActions.jsx and replace inline renderSearchActions in PricingVendorIntro.jsx for reuse
- Refactor PricingVendorIntro.jsx:
  - Introduce renderHeaderCard(), tagStyle, getCoverStyle(), and MAX_VISIBLE_AVATARS constant
  - Standardize vendor header cover (gradient + background image) and tag contrast
  - Use border instead of ring for vendor badges; unify visuals and remove Tailwind ring dependency
  - Rotate vendors every 2s only when filterVendor === 'all' and vendor count > 3
  - Remove unused imports; keep prop surface minimal; pass setShowFilterModal downward only
- Refactor PricingVendorIntroSkeleton.jsx:
  - Add getCoverStyle() and rect() helpers; rebuild skeleton to match final UI
  - Replace invalid Skeleton.Input usage; add missing keys; unify colors/borders/radius
- Update PricingTopSection.jsx:
  - Manage filter modal locally; drop redundant prop passing
- Update PricingVendorIntroWithSkeleton.jsx:
  - Align prop interface; forward only required props and keep useMinimumLoadingTime
- Add: web/src/components/table/model-pricing/layout/header/SearchActions.jsx
- Lint: all files pass; no dark:* classes present in this scope

Files touched:
- web/src/components/table/model-pricing/layout/header/PricingTopSection.jsx
- web/src/components/table/model-pricing/layout/header/PricingVendorIntro.jsx
- web/src/components/table/model-pricing/layout/header/PricingVendorIntroWithSkeleton.jsx
- web/src/components/table/model-pricing/layout/header/PricingVendorIntroSkeleton.jsx
- web/src/components/table/model-pricing/layout/header/SearchActions.jsx (new)
This commit is contained in:
t0ng7u
2025-08-23 21:11:40 +08:00
parent 5d7ab194e2
commit f246c12959
7 changed files with 362 additions and 202 deletions

View File

@@ -23,48 +23,116 @@ import { Card, Skeleton } from '@douyinfe/semi-ui';
const PricingVendorIntroSkeleton = ({
isAllVendors = false
}) => {
// 统一的封面样式函数
const getCoverStyle = (primaryDarkerChannel) => ({
'--palette-primary-darkerChannel': primaryDarkerChannel,
backgroundImage: `linear-gradient(0deg, rgba(var(--palette-primary-darkerChannel) / 80%), rgba(var(--palette-primary-darkerChannel) / 80%)), url('/cover-4.webp')`,
backgroundSize: 'cover',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat'
});
// 快速生成骨架矩形
const rect = (style = {}, key) => (
<div key={key} className="animate-pulse" style={style} />
);
const placeholder = (
<div className='mb-4'>
<Card className="!rounded-2xl with-pastel-balls" bodyStyle={{ padding: '16px' }}>
<div className="flex items-start space-x-3 md:space-x-4">
{/* 供应商图标骨架 */}
<div className="flex-shrink-0 min-w-16 h-16 rounded-2xl bg-white shadow-md flex items-center justify-center px-2">
{isAllVendors ? (
<div className="flex items-center">
{Array.from({ length: 4 }).map((_, index) => (
<Skeleton.Avatar
key={index}
active
size="default"
style={{
<Card className="!rounded-2xl shadow-sm border-0"
cover={
<div
className="relative h-32"
style={getCoverStyle(isAllVendors ? '37 99 235' : '16 185 129')}
>
<div className="relative z-10 h-full flex items-center justify-between p-4">
{/* 左侧:标题和描述骨架 */}
<div className="flex-1 min-w-0 mr-4">
<div className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-3 mb-2">
{rect({
width: isAllVendors ? 120 : 100,
height: 24,
backgroundColor: 'rgba(255, 255, 255, 0.25)',
borderRadius: 8,
backdropFilter: 'blur(4px)'
})}
{rect({
width: 80,
height: 20,
backgroundColor: 'rgba(255, 255, 255, 0.2)',
borderRadius: 9999,
backdropFilter: 'blur(4px)',
border: '1px solid rgba(255,255,255,0.3)'
})}
</div>
<div className="space-y-2">
{rect({
width: '100%',
height: 14,
backgroundColor: 'rgba(255, 255, 255, 0.2)',
borderRadius: 4,
backdropFilter: 'blur(4px)'
})}
{rect({
width: '75%',
height: 14,
backgroundColor: 'rgba(255, 255, 255, 0.15)',
borderRadius: 4,
backdropFilter: 'blur(4px)'
})}
</div>
</div>
{/* 右侧:供应商图标骨架 */}
<div className="flex-shrink-0 min-w-16 h-16 rounded-2xl bg-white/90 shadow-md backdrop-blur-sm flex items-center justify-center px-2">
{isAllVendors ? (
<div className="flex items-center gap-2">
{Array.from({ length: 4 }).map((_, index) => (
rect({
width: 32,
height: 32,
marginRight: index < 3 ? -8 : 0,
}}
/>
))}
</div>
) : (
<Skeleton.Avatar active size="large" style={{ width: 40, height: 40, borderRadius: 8 }} />
)}
</div>
{/* 供应商信息骨架 */}
<div className="flex-1 min-w-0">
<div className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-3 mb-2">
<Skeleton.Title active style={{ width: 120, height: 24, marginBottom: 0 }} />
<Skeleton.Button active size="small" style={{ width: 80, height: 20, borderRadius: 12 }} />
backgroundColor: 'rgba(59, 130, 246, 0.1)',
borderRadius: 9999,
border: '1px solid rgba(59, 130, 246, 0.2)'
}, index)
))}
</div>
) : (
rect({
width: 40,
height: 40,
backgroundColor: 'rgba(16, 185, 129, 0.1)',
borderRadius: 12,
border: '1px solid rgba(16, 185, 129, 0.2)'
})
)}
</div>
<Skeleton.Paragraph
active
rows={2}
style={{ marginBottom: 0 }}
title={false}
/>
</div>
</div>
</Card>
</div>
}
>
{/* 搜索和操作区域骨架 */}
<div className="flex items-center gap-4 w-full">
{/* 搜索框骨架 */}
<div className="flex-1">
{rect({
width: '100%',
height: 32,
backgroundColor: 'rgba(156, 163, 175, 0.1)',
borderRadius: 8,
border: '1px solid rgba(156, 163, 175, 0.2)'
})}
</div>
{/* 操作按钮骨架 */}
{rect({
width: 80,
height: 32,
backgroundColor: 'rgba(59, 130, 246, 0.1)',
borderRadius: 8,
border: '1px solid rgba(59, 130, 246, 0.2)'
})}
</div>
</Card>
);
return (