- Brief 支持代理商附件上传 (迁移 007) - 项目新增 platform 字段 (迁移 008),前端创建/展示平台信息 - 修复 AI 规则解析:处理中文引号导致 JSON 解析失败的问题 - 修复消息中心崩溃:补全后端消息类型映射 + fallback 保护 - 项目创建时自动发送消息通知 - .gitignore 排除 backend/data/ 数据库文件 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
80 lines
2.1 KiB
TypeScript
80 lines
2.1 KiB
TypeScript
'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<UploadResult>
|
||
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<string | null>(null)
|
||
|
||
const reset = useCallback(() => {
|
||
setIsUploading(false)
|
||
setProgress(0)
|
||
setError(null)
|
||
}, [])
|
||
|
||
const upload = useCallback(async (file: File): Promise<UploadResult> => {
|
||
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
|
||
}
|
||
|
||
// 后端代理上传:文件 → 后端 → TOS,避免浏览器 CORS/代理问题
|
||
setProgress(5)
|
||
const result = await api.proxyUpload(file, fileType, (pct) => {
|
||
setProgress(5 + Math.round(pct * 0.9))
|
||
})
|
||
|
||
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 }
|
||
}
|