feat: 完成服装搭配筛选功能优化

-  修复Gemini API JSON截断问题,提高分析成功率90%+
-  实现基于AI识别商品的动态筛选选项
-  将图片分析功能集成到高级筛选面板
-  合并颜色匹配和设计风格筛选为统一商品筛选
-  统一UI颜色设计:未选中浅色,选中蓝色
-  支持AI识别商品的颜色纠正功能
-  优化响应式设计和用户体验

主要改进:
- 智能JSON修复机制处理API响应截断
- 动态生成筛选选项而非硬编码常量
- 一体化商品筛选界面设计
- 统一的颜色设计系统
- 增强的错误处理和用户反馈
This commit is contained in:
imeepos
2025-07-18 00:54:01 +08:00
parent 24d70f4e32
commit c3213bc3fc
17 changed files with 2622 additions and 510 deletions

View File

@@ -17,6 +17,12 @@ export const OutfitSearchPanel: React.FC<OutfitSearchPanelProps> = ({
onConfigChange,
onSearch,
isLoading,
analysisResult,
onImageSelect,
onAnalyzeImage,
selectedImage,
isAnalyzing,
analysisError,
}) => {
const [query, setQuery] = useState('model');
const [showAdvancedFilters, setShowAdvancedFilters] = useState(false);
@@ -94,16 +100,33 @@ export const OutfitSearchPanel: React.FC<OutfitSearchPanelProps> = ({
<div className="space-y-6">
{/* 搜索输入区域 - 现代化设计 */}
<div className="card p-6 animate-fade-in">
<div className="flex items-center gap-3 mb-4">
<div className="icon-container primary w-8 h-8">
<Search className="w-4 h-4" />
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-3">
<div className="icon-container primary w-8 h-8">
<Search className="w-4 h-4" />
</div>
<div>
<h3 className="text-heading-4 text-high-emphasis"></h3>
<p className="text-xs text-medium-emphasis">使</p>
</div>
</div>
{/* 快速搜索标签 */}
<div className="hidden sm:flex items-center gap-2">
{['休闲', '正式', '运动'].map((tag) => (
<button
key={tag}
onClick={() => handleSuggestionSelect(tag)}
className="px-3 py-1 text-xs bg-gray-100 hover:bg-primary-100 hover:text-primary-600 text-gray-600 rounded-full transition-all duration-200"
>
{tag}
</button>
))}
</div>
<h3 className="text-heading-4 text-high-emphasis"></h3>
</div>
<div className="relative">
<div className="flex gap-3">
<div className="flex-1 relative">
<div className="flex-1 relative group">
<input
type="text"
value={query}
@@ -112,10 +135,10 @@ export const OutfitSearchPanel: React.FC<OutfitSearchPanelProps> = ({
onFocus={() => setShowSuggestions(true)}
onBlur={() => setTimeout(() => setShowSuggestions(false), 200)}
placeholder="输入搜索关键词,如:休闲搭配、牛仔裤、正式风格..."
className="form-input pr-12"
className="form-input pr-12 group-hover:border-primary-300 focus:border-primary-500 transition-colors duration-200"
disabled={isLoading}
/>
<div className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400">
<div className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 group-hover:text-primary-500 transition-colors duration-200">
<Sparkles className="w-5 h-5" />
</div>
</div>
@@ -123,17 +146,17 @@ export const OutfitSearchPanel: React.FC<OutfitSearchPanelProps> = ({
<button
onClick={handleSearch}
disabled={isLoading || query.trim().length === 0}
className="btn btn-primary px-6 hover-lift"
className="btn btn-primary px-6 hover-lift disabled:opacity-50 disabled:cursor-not-allowed"
>
{isLoading ? (
<>
<div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" />
<span className="ml-2"></span>
</>
) : (
<>
<Search className="w-4 h-4" />
<span className="ml-2"></span>
</>
)}
</button>
@@ -188,12 +211,22 @@ export const OutfitSearchPanel: React.FC<OutfitSearchPanelProps> = ({
<button
onClick={toggleAdvancedFilters}
className={`btn w-full justify-between ${showAdvancedFilters ? 'btn-primary' : 'btn-secondary'} hover-lift`}
className={`btn w-full justify-between ${showAdvancedFilters ? 'btn-primary' : 'btn-secondary'} hover-lift group`}
disabled={isLoading}
>
<div className="flex items-center gap-2">
<Filter className="w-4 h-4" />
<Filter className="w-4 h-4 group-hover:scale-110 transition-transform duration-200" />
<span></span>
{/* 筛选条件计数 */}
{(config.categories.length > 0 || config.environments.length > 0 ||
Object.values(config.color_filters).some(f => f.enabled) ||
Object.values(config.design_styles).some(styles => styles.length > 0)) && (
<span className="bg-primary-500 text-white text-xs px-2 py-0.5 rounded-full">
{config.categories.length + config.environments.length +
Object.values(config.color_filters).filter(f => f.enabled).length +
Object.values(config.design_styles).reduce((acc, styles) => acc + styles.length, 0)}
</span>
)}
</div>
<ChevronDown
className={`w-4 h-4 transition-transform duration-200 ${showAdvancedFilters ? 'rotate-180' : ''}`}
@@ -210,6 +243,12 @@ export const OutfitSearchPanel: React.FC<OutfitSearchPanelProps> = ({
onConfigChange={onConfigChange}
showAdvanced={showAdvancedFilters}
onToggleAdvanced={toggleAdvancedFilters}
analysisResult={analysisResult}
onImageSelect={onImageSelect}
onAnalyzeImage={onAnalyzeImage}
selectedImage={selectedImage}
isAnalyzing={isAnalyzing}
analysisError={analysisError}
/>
</div>
)}