import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import api from './api' import { categoryService } from './categoryService' // 照片数据类型 - 统一的显示格式 export interface Photo { id: number title: string description: string src: string category: string tags: string[] date: string exif: { camera: string lens: string settings: string location: string } // 后端原始数据 (仅供内部使用) file_path?: string thumbnail_path?: string user_id?: number category_id?: number created_at?: number updated_at?: number } // 分类数据类型 export interface Category { id: number name: string description: string created_at: number updated_at: number } // 后端分页响应格式 export interface PageResponse { total: number page: number size: number photos?: T[] categories?: T[] } // 后端API基础响应格式 export interface ApiResponse { code: number message: string data: T } // 查询键 export const queryKeys = { photos: ['photos'] as const, photo: (id: number) => ['photo', id] as const, categories: ['categories'] as const, } // 后端照片数据结构 interface BackendPhoto { id: number title?: string description?: string src?: string url?: string image_path?: string file_path?: string thumbnail_path?: string category?: string category_id?: number user_id?: number tags?: string[] date?: string created_at?: number updated_at?: number exif?: { camera?: string lens?: string settings?: string location?: string } } // 数据转换工具 const transformPhoto = async (backendPhoto: BackendPhoto): Promise => { // 如果使用Mock API,直接返回 if (process.env.NEXT_PUBLIC_USE_REAL_API !== 'true') { return { id: backendPhoto.id, title: backendPhoto.title || '无标题', description: backendPhoto.description || '', src: backendPhoto.src || '/placeholder.jpg', category: backendPhoto.category || 'general', tags: backendPhoto.tags || [], date: backendPhoto.date || new Date().toISOString().split('T')[0], exif: { camera: backendPhoto.exif?.camera || '未知', lens: backendPhoto.exif?.lens || '未知', settings: backendPhoto.exif?.settings || '未知', location: backendPhoto.exif?.location || '未知' } } } // 获取分类名称 const categoryName = await categoryService.getCategoryName(backendPhoto.category_id || 1) // 转换后端API数据格式 return { id: backendPhoto.id, title: backendPhoto.title || '无标题', description: backendPhoto.description || '', src: backendPhoto.file_path ? `http://localhost:8080${backendPhoto.file_path}` : '/placeholder.jpg', category: categoryName, tags: [], // 后端暂无标签系统,使用空数组 date: new Date((backendPhoto.created_at || Date.now() / 1000) * 1000).toISOString().split('T')[0], exif: { camera: '未知', lens: '未知', settings: '未知', location: '未知' }, // 保留原始数据供内部使用 file_path: backendPhoto.file_path, thumbnail_path: backendPhoto.thumbnail_path, user_id: backendPhoto.user_id, category_id: backendPhoto.category_id, created_at: backendPhoto.created_at, updated_at: backendPhoto.updated_at } } const _transformCategory = (backendCategory: Category | string): string => { if (process.env.NEXT_PUBLIC_USE_REAL_API !== 'true') { return typeof backendCategory === 'string' ? backendCategory : backendCategory.name } return typeof backendCategory === 'string' ? backendCategory : backendCategory.name } // 获取所有照片 export const usePhotos = () => { return useQuery({ queryKey: queryKeys.photos, queryFn: async (): Promise => { if (process.env.NEXT_PUBLIC_USE_REAL_API === 'true') { // 使用真实API,带分页参数 const response: { photos: BackendPhoto[] } = await api.get('/photos?page=1&page_size=100') const photos = response?.photos || [] // 并发处理所有照片的转换 return Promise.all(photos.map(transformPhoto)) } else { // 使用Mock API const photos: BackendPhoto[] = await api.get('/photos') return Promise.all(photos.map(transformPhoto)) } }, staleTime: 5 * 60 * 1000, // 5分钟内不重新获取 }) } // 分页获取照片 export const usePhotosPaginated = (page: number = 1, pageSize: number = 12) => { return useQuery({ queryKey: [...queryKeys.photos, 'paginated', page, pageSize], queryFn: async (): Promise<{ photos: Photo[], total: number, hasMore: boolean }> => { if (process.env.NEXT_PUBLIC_USE_REAL_API === 'true') { const response: { photos: BackendPhoto[], total: number } = await api.get(`/photos?page=${page}&page_size=${pageSize}`) const photos = response?.photos || [] const total = response?.total || 0 const transformedPhotos = await Promise.all(photos.map(transformPhoto)) return { photos: transformedPhotos, total, hasMore: (page * pageSize) < total } } else { // 使用Mock API - 模拟分页 const allPhotos: BackendPhoto[] = await api.get('/photos') const startIndex = (page - 1) * pageSize const endIndex = startIndex + pageSize const paginatedPhotos = allPhotos.slice(startIndex, endIndex) const transformedPhotos = await Promise.all(paginatedPhotos.map(transformPhoto)) return { photos: transformedPhotos, total: allPhotos.length, hasMore: endIndex < allPhotos.length } } }, staleTime: 5 * 60 * 1000, }) } // 无限滚动照片查询 export const useInfinitePhotos = (_pageSize: number = 12) => { return useQuery({ queryKey: [...queryKeys.photos, 'infinite'], queryFn: async (): Promise => { if (process.env.NEXT_PUBLIC_USE_REAL_API === 'true') { // 获取所有照片用于前端分页 const response: { photos: BackendPhoto[] } = await api.get('/photos?page=1&page_size=200') const photos = response?.photos || [] return Promise.all(photos.map(transformPhoto)) } else { const photos: BackendPhoto[] = await api.get('/photos') return Promise.all(photos.map(transformPhoto)) } }, staleTime: 5 * 60 * 1000, }) } // 获取单张照片 export const usePhoto = (id: number) => { return useQuery({ queryKey: queryKeys.photo(id), queryFn: async (): Promise => { if (process.env.NEXT_PUBLIC_USE_REAL_API === 'true') { const response: BackendPhoto = await api.get(`/photos/${id}`) return await transformPhoto(response) } else { return api.get(`/photos/${id}`) } }, enabled: !!id, }) } // 获取分类列表 export const useCategories = () => { return useQuery({ queryKey: queryKeys.categories, queryFn: async (): Promise => { if (process.env.NEXT_PUBLIC_USE_REAL_API === 'true') { const response: { categories: Category[] } = await api.get('/categories?page=1&page_size=100') const categories = response?.categories || [] return categories.map((cat: Category) => cat.name) } else { const categories: string[] = await api.get('/categories') return categories } }, staleTime: 10 * 60 * 1000, // 10分钟内不重新获取 }) } // 添加照片 export const useAddPhoto = () => { const queryClient = useQueryClient() return useMutation({ mutationFn: (photo: Omit) => api.post('/photos', photo), onSuccess: () => { queryClient.invalidateQueries({ queryKey: queryKeys.photos }) }, }) } // 更新照片 export const useUpdatePhoto = () => { const queryClient = useQueryClient() return useMutation({ mutationFn: ({ id, ...photo }: Partial & { id: number }) => api.put(`/photos/${id}`, photo), onSuccess: (data, variables) => { queryClient.invalidateQueries({ queryKey: queryKeys.photos }) queryClient.invalidateQueries({ queryKey: queryKeys.photo(variables.id) }) }, }) } // 删除照片 export const useDeletePhoto = () => { const queryClient = useQueryClient() return useMutation({ mutationFn: (id: number) => api.delete(`/photos/${id}`), onSuccess: () => { queryClient.invalidateQueries({ queryKey: queryKeys.photos }) }, }) }