'use client' import { useState, useCallback } from 'react' import { api } from '@/lib/api' import { USE_MOCK } from '@/contexts/AuthContext' interface UploadResult { url: string file_key: string file_name: string file_size: number } interface UseOSSUploadReturn { upload: (file: File) => Promise isUploading: boolean progress: number error: string | null reset: () => void } export function useOSSUpload(fileType: string = 'general'): UseOSSUploadReturn { const [isUploading, setIsUploading] = useState(false) const [progress, setProgress] = useState(0) const [error, setError] = useState(null) const reset = useCallback(() => { setIsUploading(false) setProgress(0) setError(null) }, []) const upload = useCallback(async (file: File): Promise => { setIsUploading(true) setProgress(0) setError(null) try { if (USE_MOCK) { // Mock 模式:模拟 2 秒上传 for (let i = 0; i <= 100; i += 20) { await new Promise(r => setTimeout(r, 400)) setProgress(i) } const result: UploadResult = { url: `https://mock-oss.example.com/${fileType}/${Date.now()}_${file.name}`, file_key: `${fileType}/${Date.now()}_${file.name}`, file_name: file.name, file_size: file.size, } setProgress(100) setIsUploading(false) return result } // 1. 获取上传凭证 setProgress(10) const policy = await api.getUploadPolicy(fileType) // 2. 构建 OSS 直传 FormData const fileKey = `${policy.dir}${Date.now()}_${file.name}` const formData = new FormData() formData.append('key', fileKey) formData.append('policy', policy.policy) formData.append('OSSAccessKeyId', policy.access_key_id) formData.append('signature', policy.signature) formData.append('success_action_status', '200') formData.append('file', file) // 3. 上传到 OSS setProgress(30) const xhr = new XMLHttpRequest() await new Promise((resolve, reject) => { xhr.upload.onprogress = (e) => { if (e.lengthComputable) { setProgress(30 + Math.round((e.loaded / e.total) * 50)) } } xhr.onload = () => { if (xhr.status >= 200 && xhr.status < 300) { resolve() } else { reject(new Error(`上传失败: ${xhr.status}`)) } } xhr.onerror = () => reject(new Error('网络错误')) xhr.open('POST', policy.host) xhr.send(formData) }) // 4. 回调通知后端 setProgress(90) const result = await api.fileUploaded(fileKey, file.name, file.size, fileType) setProgress(100) setIsUploading(false) return { url: result.url, file_key: result.file_key, file_name: result.file_name, file_size: result.file_size, } } catch (err) { const message = err instanceof Error ? err.message : '上传失败' setError(message) setIsUploading(false) throw err } }, [fileType]) return { upload, isUploading, progress, error, reset } }