Files
mixvideo-v2/apps/desktop/src/store/outfitSearchStore.ts
imeepos fa194a5db2 feat: 服装搭配页面UI美化和UX改进
UI优化内容:
- 重新设计页面头部,使用优雅的渐变背景和现代化图标
- 优化标签导航,采用卡片式设计和平滑动画效果
- 美化搜索面板,改进输入框、筛选器和按钮的视觉设计
- 重构图片上传组件,添加拖拽区域样式和上传进度动画
- 优化搜索结果展示,使用网格布局和悬停效果
- 改进AI分析结果展示,采用卡片式布局和颜色编码
- 增强LLM聊天界面,现代化消息气泡和打字动画

 响应式设计:
- 实现移动优先的响应式布局
- 优化平板端和桌面端适配
- 修复1200px宽度下的左右布局显示问题
- 添加触摸友好的交互元素

 用户体验提升:
- 统一设计语言和视觉风格
- 添加流畅的页面切换和组件加载动画
- 优化加载状态、错误提示和空状态设计
- 改进信息层次和视觉可读性

 技术改进:
- 使用Tailwind CSS类替代内联样式
- 统一使用Lucide React图标库
- 完善CSS变量和设计令牌系统
- 添加兼容性变量支持旧的命名格式

符合promptx/frontend-developer规定的前端开发规范,确保界面美观、操作流畅、动画优美,符合用户操作习惯和大众审美习惯。
2025-07-17 23:27:52 +08:00

327 lines
8.4 KiB
TypeScript

import { create } from 'zustand';
import {
OutfitSearchState,
SearchRequest,
DEFAULT_SEARCH_CONFIG,
} from '../types/outfitSearch';
import OutfitSearchService from '../services/outfitSearchService';
/**
* 服装搭配搜索状态管理
* 遵循 Tauri 开发规范的状态管理模式
*/
export const useOutfitSearchStore = create<OutfitSearchState>((set, _get) => ({
// 搜索状态
searchConfig: DEFAULT_SEARCH_CONFIG,
searchResults: [],
isSearching: false,
searchError: null,
// 分析状态
analysisResult: null,
isAnalyzing: false,
analysisError: null,
// LLM问答状态
llmResponse: null,
isAsking: false,
llmError: null,
// UI状态
selectedImage: null,
showAdvancedFilters: false,
currentPage: 1,
// 历史记录
searchHistory: [],
// 操作方法
updateSearchConfig: (config) => {
set((state) => ({
searchConfig: { ...state.searchConfig, ...config },
}));
},
executeSearch: async (request) => {
set({ isSearching: true, searchError: null });
try {
const response = await OutfitSearchService.searchSimilarOutfits(request);
set({
searchResults: response.results,
isSearching: false,
currentPage: Math.floor(request.page_offset / request.page_size) + 1,
});
// 添加到搜索历史
const historyItem = {
id: Date.now().toString(),
query: request.query,
config: request.config,
results_count: response.total_size,
search_time_ms: response.search_time_ms,
created_at: new Date().toISOString(),
};
set((state) => ({
searchHistory: [historyItem, ...state.searchHistory.slice(0, 9)], // 保留最近10条
}));
} catch (error) {
console.error('Search failed:', error);
set({
isSearching: false,
searchError: error instanceof Error ? error.message : '搜索失败',
searchResults: [],
});
}
},
analyzeImage: async (request) => {
set({ isAnalyzing: true, analysisError: null });
try {
const response = await OutfitSearchService.analyzeOutfitImage(request);
set({
analysisResult: response.result,
isAnalyzing: false,
});
// 基于分析结果生成搜索配置
try {
const generatedConfig = await OutfitSearchService.generateSearchConfigFromAnalysis(
response.result
);
set((state) => ({
searchConfig: { ...state.searchConfig, ...generatedConfig },
}));
} catch (configError) {
console.warn('Failed to generate search config from analysis:', configError);
}
} catch (error) {
console.error('Image analysis failed:', error);
set({
isAnalyzing: false,
analysisError: error instanceof Error ? error.message : '图像分析失败',
analysisResult: null,
});
}
},
askLLM: async (request) => {
set({ isAsking: true, llmError: null });
try {
const response = await OutfitSearchService.askLLMOutfitAdvice(request);
set({
llmResponse: response,
isAsking: false,
});
} catch (error) {
console.error('LLM query failed:', error);
set({
isAsking: false,
llmError: error instanceof Error ? error.message : 'LLM问答失败',
llmResponse: null,
});
}
},
clearResults: () => {
set({
searchResults: [],
searchError: null,
currentPage: 1,
});
},
clearErrors: () => {
set({
searchError: null,
analysisError: null,
llmError: null,
});
},
setSelectedImage: (imagePath) => {
set({ selectedImage: imagePath });
// 如果清除了图像,也清除分析结果
if (!imagePath) {
set({ analysisResult: null, analysisError: null });
}
},
toggleAdvancedFilters: () => {
set((state) => ({
showAdvancedFilters: !state.showAdvancedFilters,
}));
},
loadSearchHistory: async () => {
// 这里可以从本地存储或数据库加载搜索历史
// 暂时使用空实现
try {
// const history = await loadSearchHistoryFromStorage();
// set({ searchHistory: history });
} catch (error) {
console.error('Failed to load search history:', error);
}
},
}));
/**
* 搜索相关的辅助函数
*/
export const useOutfitSearchActions = () => {
const store = useOutfitSearchStore();
return {
// 快速搜索
quickSearch: async (query: string) => {
const request: SearchRequest = {
query,
config: store.searchConfig,
page_size: 9,
page_offset: 0,
};
await store.executeSearch(request);
},
// 分页搜索
searchWithPagination: async (page: number, pageSize: number = 9) => {
const request: SearchRequest = {
query: store.searchHistory[0]?.query || 'model',
config: store.searchConfig,
page_size: pageSize,
page_offset: (page - 1) * pageSize,
};
await store.executeSearch(request);
},
// 基于分析结果搜索
searchFromAnalysis: async () => {
if (!store.analysisResult) return;
try {
const generatedConfig = await OutfitSearchService.generateSearchConfigFromAnalysis(
store.analysisResult
);
const request: SearchRequest = {
query: store.analysisResult.style_description || 'model',
config: generatedConfig,
page_size: 9,
page_offset: 0,
};
await store.executeSearch(request);
} catch (error) {
console.error('Failed to search from analysis:', error);
}
},
// 重置所有状态
resetAll: () => {
store.clearResults();
store.clearErrors();
store.setSelectedImage(null);
store.updateSearchConfig(DEFAULT_SEARCH_CONFIG);
useOutfitSearchStore.setState({
analysisResult: null,
llmResponse: null,
showAdvancedFilters: false,
currentPage: 1,
});
},
// 导出搜索配置
exportSearchConfig: () => {
return JSON.stringify(store.searchConfig, null, 2);
},
// 导入搜索配置
importSearchConfig: (configJson: string) => {
try {
const config = JSON.parse(configJson);
store.updateSearchConfig(config);
return true;
} catch (error) {
console.error('Failed to import search config:', error);
return false;
}
},
// 获取搜索统计
getSearchStats: () => {
const { searchHistory, searchResults } = store;
return {
totalSearches: searchHistory.length,
averageResultsCount: searchHistory.length > 0
? searchHistory.reduce((sum, item) => sum + item.results_count, 0) / searchHistory.length
: 0,
averageSearchTime: searchHistory.length > 0
? searchHistory.reduce((sum, item) => sum + item.search_time_ms, 0) / searchHistory.length
: 0,
currentResultsCount: searchResults.length,
};
},
};
};
/**
* 选择器函数
*/
export const useOutfitSearchSelectors = () => {
return {
// 获取当前搜索状态
useSearchState: () => useOutfitSearchStore((state) => ({
isSearching: state.isSearching,
searchError: state.searchError,
results: state.searchResults,
currentPage: state.currentPage,
})),
// 获取分析状态
useAnalysisState: () => useOutfitSearchStore((state) => ({
isAnalyzing: state.isAnalyzing,
analysisError: state.analysisError,
result: state.analysisResult,
selectedImage: state.selectedImage,
})),
// 获取LLM状态
useLLMState: () => useOutfitSearchStore((state) => ({
isAsking: state.isAsking,
llmError: state.llmError,
response: state.llmResponse,
})),
// 获取UI状态
useUIState: () => useOutfitSearchStore((state) => ({
showAdvancedFilters: state.showAdvancedFilters,
searchConfig: state.searchConfig,
})),
// 检查是否有活动筛选
useHasActiveFilters: () => useOutfitSearchStore((state) => {
const { searchConfig } = state;
return (
searchConfig.categories.length > 0 ||
searchConfig.environments.length > 0 ||
Object.values(searchConfig.color_filters).some(f => f.enabled) ||
Object.values(searchConfig.design_styles).some(styles => styles.length > 0)
);
}),
};
};
export default useOutfitSearchStore;