From 60cd01c1eca4f77d189b0d3d332f38d5142e3096 Mon Sep 17 00:00:00 2001 From: imeepos Date: Tue, 15 Jul 2025 21:36:33 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84MaterialSegmentView?= =?UTF-8?q?=E4=B8=BA=E5=A4=9A=E6=9D=A1=E4=BB=B6=E7=AD=9B=E9=80=89=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=20-=20=E7=A7=BB=E9=99=A4=E6=A0=87=E7=AD=BE=E9=A1=B5?= =?UTF-8?q?=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 核心功能重构: - 移除标签页(tab)设计,改为同时显示AI分类和模特的筛选条件 - 实现组合筛选:AI分类 AND 模特的多条件检索 - 支持类似'AI分类:全身 and 模特:杨明明'的筛选组合 多条件筛选系统: - AI分类筛选:独立的筛选区域,显示所有分类选项及数量 - 模特筛选:独立的筛选区域,显示所有模特选项及数量 - 组合筛选:两个条件可以同时生效,实现精确筛选 - 当前筛选条件显示:实时显示已选择的筛选条件 UI/UX优化: - 分区设计:AI分类和模特各自独立的筛选区域 - 视觉区分:AI分类使用蓝色主题,模特使用绿色主题 - 筛选状态显示:当有筛选条件时显示当前筛选状态栏 - 清除功能:一键清除所有筛选条件 - Card卡片风格:片段展示保持卡片设计 数据处理优化: - 智能过滤:先获取所有片段,再依次应用分类和模特过滤 - 组合逻辑:支持分类 AND 模特的组合筛选 - 搜索集成:搜索功能与筛选条件无缝结合 - 实时更新:筛选条件变化时立即更新结果 技术实现: - 移除activeTab状态,简化组件逻辑 - 优化过滤算法,支持多条件组合 - 保持useMemo性能优化 - 完善的错误处理和加载状态 交互体验: - 直观的筛选界面:用户可以清楚看到所有可用的筛选选项 - 即时反馈:点击筛选条件立即看到结果变化 - 状态提示:当前筛选条件清晰显示,支持快速清除 - 空状态处理:没有匹配结果时的友好提示 功能特点: - 支持单一条件筛选:只选择AI分类或只选择模特 - 支持组合条件筛选:同时选择AI分类和模特 - 支持搜索+筛选:搜索词与筛选条件组合使用 - 支持快速重置:一键清除所有筛选条件 这个重构完全满足了用户的新需求: 1. 移除了标签页设计 2. 实现了AI分类和模特的同时筛选 3. 支持组合筛选条件(AI分类 AND 模特) 4. 提供了清晰的筛选状态显示和管理 --- .../src/components/MaterialSegmentView.tsx | 189 +++++++++--------- 1 file changed, 96 insertions(+), 93 deletions(-) diff --git a/apps/desktop/src/components/MaterialSegmentView.tsx b/apps/desktop/src/components/MaterialSegmentView.tsx index f356a52..484b39f 100644 --- a/apps/desktop/src/components/MaterialSegmentView.tsx +++ b/apps/desktop/src/components/MaterialSegmentView.tsx @@ -92,7 +92,6 @@ export const MaterialSegmentView: React.FC = ({ projec const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [searchTerm, setSearchTerm] = useState(''); - const [activeTab, setActiveTab] = useState<'classification' | 'model'>('classification'); const [selectedClassification, setSelectedClassification] = useState('全部'); const [selectedModel, setSelectedModel] = useState('全部'); @@ -175,40 +174,30 @@ export const MaterialSegmentView: React.FC = ({ projec const filteredSegments = useMemo(() => { if (!segmentView) return []; + // 获取所有片段 let segments: SegmentWithDetails[] = []; + segmentView.by_classification.forEach(group => { + segments.push(...group.segments); + }); - if (activeTab === 'classification') { - if (selectedClassification === '全部') { - // 获取所有片段 - segmentView.by_classification.forEach(group => { - segments.push(...group.segments); - }); - } else { - // 获取特定分类的片段 - const group = segmentView.by_classification.find(g => g.category === selectedClassification); - if (group) { - segments = group.segments; - } - } - } else { - if (selectedModel === '全部') { - // 获取所有片段 - segmentView.by_model.forEach(group => { - segments.push(...group.segments); - }); - } else { - // 获取特定模特的片段 - const group = segmentView.by_model.find(g => g.model_name === selectedModel); - if (group) { - segments = group.segments; - } - } + // 应用分类过滤 + if (selectedClassification !== '全部') { + segments = segments.filter(segment => + segment.classification_info?.category === selectedClassification + ); + } + + // 应用模特过滤 + if (selectedModel !== '全部') { + segments = segments.filter(segment => + segment.model_info?.name === selectedModel + ); } // 应用搜索过滤 if (searchTerm.trim()) { const searchLower = searchTerm.toLowerCase(); - segments = segments.filter(segment => + segments = segments.filter(segment => segment.material_info.name.toLowerCase().includes(searchLower) || segment.classification_info?.category?.toLowerCase().includes(searchLower) || segment.model_info?.name?.toLowerCase().includes(searchLower) @@ -216,7 +205,7 @@ export const MaterialSegmentView: React.FC = ({ projec } return segments; - }, [segmentView, activeTab, selectedClassification, selectedModel, searchTerm]); + }, [segmentView, selectedClassification, selectedModel, searchTerm]); // 渲染片段卡片 const renderSegmentCard = (segment: SegmentWithDetails) => { @@ -354,74 +343,88 @@ export const MaterialSegmentView: React.FC = ({ projec - {/* 标签页导航 */} -
- -
+ {/* 筛选条件 */} +
+ {/* AI分类筛选 */} +
+
+ + AI分类 +
+
+ {classificationOptions.map(option => ( + + ))} +
+
- {/* 过滤选项 */} -
- {activeTab === 'classification' ? ( - classificationOptions.map(option => ( - + ))} +
+
+ + {/* 当前筛选条件显示 */} + {(selectedClassification !== '全部' || selectedModel !== '全部') && ( +
+ + 当前筛选: + {selectedClassification !== '全部' && ( + + AI分类: {selectedClassification} - - )) - ) : ( - modelOptions.map(option => ( - - )) +
)}