import { useState, useCallback } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { toast } from 'sonner'; import { fileClient } from '../api/fileClient'; import type { FileType } from '../types/file'; // 文件管理钩子 export interface UseFileManagementOptions { defaultPageSize?: number; } export const useFileManagement = (options: UseFileManagementOptions = {}) => { const { defaultPageSize = 10 } = options; const [pagination, setPagination] = useState({ current: 1, pageSize: defaultPageSize, total: 0, }); const [searchText, setSearchText] = useState(''); const queryClient = useQueryClient(); // 获取文件列表 const { data: filesData, isLoading, error, refetch } = useQuery({ queryKey: ['files', pagination.current, pagination.pageSize, searchText], queryFn: async () => { const response = await fileClient.$get({ query: { page: pagination.current, pageSize: pagination.pageSize, keyword: searchText || undefined, }, }); if (!response.ok) { throw new Error('获取文件列表失败'); } return await response.json(); }, }); // 更新文件信息 const updateFileMutation = useMutation({ mutationFn: async ({ id, data }: { id: number; data: { name: string; description?: string } }) => { const response = await fileClient[':id'].$put({ param: { id: Number(id) }, json: data, }); if (!response.ok) { throw new Error('更新文件失败'); } return await response.json(); }, onSuccess: () => { toast.success('文件信息更新成功'); queryClient.invalidateQueries({ queryKey: ['files'] }); }, onError: (error: Error) => { toast.error(`更新失败: ${error.message}`); }, }); // 删除文件 const deleteFileMutation = useMutation({ mutationFn: async (id: number) => { const response = await fileClient[':id'].$delete({ param: { id: Number(id) }, }); if (!response.ok) { throw new Error('删除文件失败'); } }, onSuccess: () => { toast.success('文件删除成功'); queryClient.invalidateQueries({ queryKey: ['files'] }); }, onError: (error: Error) => { toast.error(`删除失败: ${error.message}`); }, }); // 搜索文件 const handleSearch = useCallback((text: string) => { setSearchText(text); setPagination(prev => ({ ...prev, current: 1 })); }, []); // 分页处理 const handlePageChange = useCallback((page: number, pageSize: number) => { setPagination(prev => ({ ...prev, current: page, pageSize })); }, []); // 文件预览 const handlePreview = useCallback((file: FileType) => { if (isPreviewable(file.type)) { window.open(file.fullUrl, '_blank'); } else { toast.warning('该文件类型不支持预览'); } }, []); // 文件下载 const handleDownload = useCallback((file: FileType) => { const a = document.createElement('a'); a.href = file.fullUrl; a.download = file.name; document.body.appendChild(a); a.click(); document.body.removeChild(a); }, []); // 检查是否为可预览的文件类型 const isPreviewable = (fileType: string | null) => { if (!fileType) return false; return fileType.startsWith('image/') || fileType.startsWith('video/'); }; return { // 数据 files: filesData?.data || [], pagination: filesData?.pagination || pagination, // 状态 isLoading, error, searchText, // 操作 handleSearch, handlePageChange, handlePreview, handleDownload, updateFile: updateFileMutation.mutateAsync, deleteFile: deleteFileMutation.mutateAsync, refetch, // 工具函数 isPreviewable, }; };