import React, { useState, useCallback, useEffect } from 'react'; import { Sparkles, Wand2, Shirt, Download, Copy, RefreshCw, Settings, Info, Heart, ArrowLeftRight } from 'lucide-react'; import OutfitRecommendationService from '../../services/outfitRecommendationService'; import { OutfitRecommendation, OutfitRecommendationGroup, GroupingStrategy, STYLE_OPTIONS, OCCASION_OPTIONS, SEASON_OPTIONS } from '../../types/outfitRecommendation'; import OutfitRecommendationList from '../../components/outfit/OutfitRecommendationList'; import { CustomSelect } from '../../components/CustomSelect'; import { MaterialSearchPanel, MaterialDetailModal } from '../../components/material'; // localStorage 键名 const STORAGE_KEY = 'outfit-recommendation-state'; // 状态接口 interface SavedState { query: string; targetStyle: string; occasions: string[]; season: string; colorPreferences: string[]; count: number; groups: OutfitRecommendationGroup[]; groupingStrategy: GroupingStrategy | null; recommendations: OutfitRecommendation[]; showAdvanced: boolean; } /** * AI穿搭方案推荐小工具 * 遵循 Tauri 开发规范和 UI/UX 设计标准 */ const OutfitRecommendationTool: React.FC = () => { // 状态管理 const [query, setQuery] = useState(''); const [targetStyle, setTargetStyle] = useState(''); const [occasions, setOccasions] = useState([]); const [season, setSeason] = useState(''); const [colorPreferences, setColorPreferences] = useState([]); const [count, setCount] = useState(3); // 分组相关状态 const [groups, setGroups] = useState([]); const [groupingStrategy, setGroupingStrategy] = useState(null); const [recommendations, setRecommendations] = useState([]); const [isGenerating, setIsGenerating] = useState(false); const [error, setError] = useState(null); const [showAdvanced, setShowAdvanced] = useState(false); // 素材检索状态 const [showMaterialSearch, setShowMaterialSearch] = useState(false); const [selectedRecommendation, setSelectedRecommendation] = useState(null); // 素材详情状态 const [showMaterialDetail, setShowMaterialDetail] = useState(false); const [selectedMaterial, setSelectedMaterial] = useState(null); // 方案对比状态 const [selectedForComparison, setSelectedForComparison] = useState([]); // 状态恢复提示 const [showRestoredTip, setShowRestoredTip] = useState(false); // 保存状态到localStorage const saveState = useCallback(() => { try { const state: SavedState = { query, targetStyle, occasions, season, colorPreferences, count, groups, groupingStrategy, recommendations, showAdvanced, }; localStorage.setItem(STORAGE_KEY, JSON.stringify(state)); } catch (error) { console.warn('保存状态失败:', error); } }, [query, targetStyle, occasions, season, colorPreferences, count, groups, groupingStrategy, recommendations, showAdvanced]); // 从localStorage恢复状态 const restoreState = useCallback(() => { try { const savedState = localStorage.getItem(STORAGE_KEY); if (savedState) { const state: SavedState = JSON.parse(savedState); setQuery(state.query || ''); setTargetStyle(state.targetStyle || ''); setOccasions(state.occasions || []); setSeason(state.season || ''); setColorPreferences(state.colorPreferences || []); setCount(state.count || 3); setGroups(state.groups || []); setGroupingStrategy(state.groupingStrategy || null); setRecommendations(state.recommendations || []); setShowAdvanced(state.showAdvanced || false); return true; // 表示成功恢复了状态 } } catch (error) { console.warn('恢复状态失败:', error); } return false; // 表示没有恢复状态 }, []); // 组件加载时恢复状态 useEffect(() => { const restored = restoreState(); if (restored) { setShowRestoredTip(true); // 3秒后自动隐藏提示 setTimeout(() => { setShowRestoredTip(false); }, 3000); } }, [restoreState]); // 状态变化时自动保存(防抖) useEffect(() => { const timeoutId = setTimeout(() => { if (recommendations.length > 0) { saveState(); } }, 1000); // 1秒防抖 return () => clearTimeout(timeoutId); }, [recommendations, saveState]); // 监听对比选择,当选择了2个方案时自动跳转到对比页面 useEffect(() => { if (selectedForComparison.length === 2) { // 将选中的方案保存到localStorage,供对比页面使用 try { localStorage.setItem('outfit-comparison-data', JSON.stringify({ leftFavorite: { id: selectedForComparison[0].id, recommendation_data: selectedForComparison[0], custom_name: selectedForComparison[0].title, created_at: new Date().toISOString() }, rightFavorite: { id: selectedForComparison[1].id, recommendation_data: selectedForComparison[1], custom_name: selectedForComparison[1].title, created_at: new Date().toISOString() } })); // 短暂延迟后跳转,让用户看到选择反馈 setTimeout(() => { window.location.href = '/tools/outfit-comparison'; }, 500); } catch (error) { console.error('保存对比数据失败:', error); } } }, [selectedForComparison]); // 生成穿搭方案 const handleGenerate = useCallback(async () => { if (!query.trim()) { setError('请输入穿搭关键词或描述'); return; } setIsGenerating(true); setError(null); try { const response = await OutfitRecommendationService.generateRecommendations({ query: query.trim(), target_style: targetStyle || undefined, occasions: occasions.length > 0 ? occasions : undefined, season: season || undefined, color_preferences: colorPreferences.length > 0 ? colorPreferences : undefined, count, }); // 更新分组和方案数据 if (response.groups && response.groups.length > 0) { setGroups(response.groups); setGroupingStrategy(response.grouping_strategy); // 为向后兼容,也设置recommendations setRecommendations(response.recommendations || []); } else { // 向后兼容模式 setGroups([]); setGroupingStrategy(null); setRecommendations(response.recommendations || []); } // 生成成功后立即保存状态 setTimeout(() => { saveState(); }, 100); } catch (err) { console.error('穿搭方案生成失败:', err); setError(err instanceof Error ? err.message : '穿搭方案生成失败'); } finally { setIsGenerating(false); } }, [query, targetStyle, occasions, season, colorPreferences, count]); // 重新生成 const handleRegenerate = useCallback(() => { handleGenerate(); }, [handleGenerate]); // 获取更多同类方案 const handleLoadMoreForGroup = useCallback(async (groupId: string, styleKeywords: string[]) => { try { console.log(`🎨 获取分组 ${groupId} 的更多方案,关键词:`, styleKeywords); // 构建增强的查询 const enhancedQuery = `${query} ${styleKeywords.join(' ')}`; const response = await OutfitRecommendationService.generateRecommendations({ query: enhancedQuery, target_style: targetStyle || undefined, occasions: occasions.length > 0 ? occasions : undefined, season: season || undefined, color_preferences: colorPreferences.length > 0 ? colorPreferences : undefined, count: 3, // 每次获取3个新方案 }); // 找到对应的分组并添加新方案 if (response.groups && response.groups.length > 0) { // 如果返回了分组,合并到现有分组中 setGroups(prevGroups => { return prevGroups.map(group => { if (group.group_id === groupId) { // 找到匹配的新分组并合并方案 const newGroup = response.groups.find(g => g.style_keywords.some(keyword => styleKeywords.includes(keyword) ) ); if (newGroup) { return { ...group, children: [...group.children, ...newGroup.children] }; } } return group; }); }); } else if (response.recommendations) { // 向后兼容:直接添加到对应分组 setGroups(prevGroups => { return prevGroups.map(group => { if (group.group_id === groupId) { return { ...group, children: [...group.children, ...(response.recommendations || [])] }; } return group; }); }); } } catch (err) { console.error('获取更多方案失败:', err); setError(err instanceof Error ? err.message : '获取更多方案失败'); } }, [query, targetStyle, occasions, season, colorPreferences]); // 清空表单 const handleClear = useCallback(() => { setQuery(''); setTargetStyle(''); setOccasions([]); setSeason(''); setColorPreferences([]); setCount(3); setGroups([]); setGroupingStrategy(null); setRecommendations([]); setError(null); setShowRestoredTip(false); // 清除保存的状态 try { localStorage.removeItem(STORAGE_KEY); } catch (error) { console.warn('清除保存状态失败:', error); } }, []); // 导出结果 const handleExport = useCallback(() => { if (recommendations.length === 0) { return; } const exportData = { query, generated_at: new Date().toISOString(), recommendations: recommendations.map(rec => ({ title: rec.title, description: rec.description, overall_style: rec.overall_style, style_tags: rec.style_tags, occasions: rec.occasions, seasons: rec.seasons, color_theme: rec.color_theme, items: rec.items, tiktok_tips: rec.tiktok_tips, styling_tips: rec.styling_tips, })) }; const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `outfit-recommendations-${Date.now()}.json`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); }, [recommendations, query]); // 打开收藏管理 const handleOpenFavoriteManagement = useCallback(() => { // 使用路由跳转到收藏管理页面 window.location.href = '/tools/outfit-favorites'; }, []); // 打开方案对比 const handleOpenComparison = useCallback(() => { // 使用路由跳转到方案对比页面 window.location.href = '/tools/outfit-comparison'; }, []); // 添加到对比 const handleAddToComparison = useCallback((recommendation: OutfitRecommendation) => { setSelectedForComparison(prev => { if (prev.find(r => r.id === recommendation.id)) { // 如果已存在,则移除 return prev.filter(r => r.id !== recommendation.id); } else if (prev.length < 2) { // 如果少于2个,则添加 return [...prev, recommendation]; } else { // 如果已有2个,替换第一个 return [prev[1], recommendation]; } }); }, []); // 复制结果 const handleCopy = useCallback(() => { if (recommendations.length === 0) { return; } const text = recommendations.map(rec => `${rec.title}\n${rec.description}\n风格: ${rec.style_tags.join(', ')}\n\n` ).join(''); navigator.clipboard.writeText(text); }, [recommendations]); // 处理素材检索 const handleMaterialSearch = useCallback((recommendation: OutfitRecommendation) => { setSelectedRecommendation(recommendation); setShowMaterialSearch(true); }, []); // 关闭素材检索面板 const handleCloseMaterialSearch = useCallback(() => { setShowMaterialSearch(false); setSelectedRecommendation(null); }, []); // 处理素材选择 const handleMaterialSelect = useCallback((material: any) => { console.log('选择素材:', material); setSelectedMaterial(material); setShowMaterialDetail(true); }, []); // 关闭素材详情 const handleCloseMaterialDetail = useCallback(() => { setShowMaterialDetail(false); setSelectedMaterial(null); }, []); return (
{/* 顶部导航 */}

AI穿搭方案推荐

{showRestoredTip && (
已恢复上次结果
)}

基于TikTok视觉趋势的智能穿搭建议

{/* 收藏管理入口 */} {/* 方案对比入口 */} {/* 分隔线 */} {recommendations.length > 0 && (
)} {recommendations.length > 0 && ( <> )}
{/* 主要内容 */}
{/* 左侧输入区域 */}
{/* 基础输入 */}