feat: 支持批量上传关卡

This commit is contained in:
richarjiang
2026-05-01 08:44:56 +08:00
parent f3f27def2b
commit 66a9ee2950
27 changed files with 5262 additions and 515 deletions

81
lib/cos-client.ts Normal file
View File

@@ -0,0 +1,81 @@
import COS from 'cos-js-sdk-v5'
import { apiFetch } from '@/lib/api'
interface TempKeyResponse {
credentials: {
tmpSecretId: string
tmpSecretKey: string
sessionToken: string
}
startTime: number
expiredTime: number
bucket: string
region: string
}
let cachedKey: TempKeyResponse | null = null
async function getTempKey(forceRefresh = false): Promise<TempKeyResponse> {
const now = Math.floor(Date.now() / 1000)
// 提前 60 秒失效,避免边界问题
if (!forceRefresh && cachedKey && cachedKey.expiredTime - 60 > now) {
return cachedKey
}
const res = await apiFetch('/api/cos/temp-key')
if (!res.ok) {
throw new Error('获取上传凭证失败')
}
const data = (await res.json()) as TempKeyResponse
cachedKey = data
return data
}
function buildCosClient(key: TempKeyResponse): COS {
return new COS({
getAuthorization: (_options, callback) => {
callback({
TmpSecretId: key.credentials.tmpSecretId,
TmpSecretKey: key.credentials.tmpSecretKey,
SecurityToken: key.credentials.sessionToken,
StartTime: key.startTime,
ExpiredTime: key.expiredTime,
})
},
})
}
function randomFilename(originalName: string): string {
const ext = originalName.split('.').pop() || 'jpg'
const timestamp = Date.now()
const randomStr = Math.random().toString(36).substring(2, 8)
return `mini_game/images/${timestamp}_${randomStr}.${ext}`
}
/**
* 上传单个文件到腾讯云 COS返回可访问的 URL。
*/
export async function uploadToCos(file: File | Blob, originalName?: string): Promise<string> {
const name = originalName || (file as File).name || 'upload.jpg'
const key = await getTempKey()
const cos = buildCosClient(key)
const filename = randomFilename(name)
return new Promise<string>((resolve, reject) => {
cos.putObject(
{
Bucket: key.bucket,
Region: key.region,
Key: filename,
Body: file as File,
},
(err) => {
if (err) {
reject(new Error(err.message || '上传失败'))
return
}
const url = `https://${key.bucket}.cos.${key.region}.myqcloud.com/${filename}`
resolve(url)
}
)
})
}