109 lines
3.4 KiB
JavaScript
109 lines
3.4 KiB
JavaScript
import { post } from './api'
|
||
|
||
/**
|
||
* 从后端获取 COS 预签名上传 URL
|
||
* @param {number} count - 文件数量
|
||
* @param {string} ext - 文件扩展名
|
||
* @returns {Promise<Array<{cosKey, presignUrl, accessUrl}>>}
|
||
*/
|
||
export async function getPresignUrls(count, ext = '.jpg') {
|
||
const res = await post('/business/CosUpload/presignUrl', { count, ext }, { timeout: 120000 })
|
||
if (res.code !== 200) {
|
||
throw new Error(res.msg || '获取上传地址失败')
|
||
}
|
||
return res.data
|
||
}
|
||
|
||
/**
|
||
* 通过预签名 URL 直传文件到 COS
|
||
* @param {string} presignUrl - PUT 预签名 URL
|
||
* @param {string} filePath - 本地文件路径
|
||
* @returns {Promise<void>}
|
||
*/
|
||
export function uploadToCos(presignUrl, filePath) {
|
||
return new Promise((resolve, reject) => {
|
||
// #ifdef H5
|
||
_uploadH5(presignUrl, filePath).then(resolve).catch(reject)
|
||
// #endif
|
||
// #ifdef APP-PLUS
|
||
_uploadApp(presignUrl, filePath).then(resolve).catch(reject)
|
||
// #endif
|
||
})
|
||
}
|
||
|
||
// #ifdef H5
|
||
async function _uploadH5(presignUrl, filePath) {
|
||
// H5 端 filePath 可能是 base64 或 blob URL
|
||
let blob
|
||
if (filePath.startsWith('data:')) {
|
||
const resp = await fetch(filePath)
|
||
blob = await resp.blob()
|
||
} else {
|
||
const resp = await fetch(filePath)
|
||
blob = await resp.blob()
|
||
}
|
||
const res = await fetch(presignUrl, {
|
||
method: 'PUT',
|
||
headers: { 'Content-Type': 'image/jpeg' },
|
||
body: blob
|
||
})
|
||
if (!res.ok) {
|
||
throw new Error(`COS上传失败: ${res.status}`)
|
||
}
|
||
}
|
||
// #endif
|
||
|
||
// #ifdef APP-PLUS
|
||
function _uploadApp(presignUrl, filePath) {
|
||
return new Promise((resolve, reject) => {
|
||
console.log('[COS] APP端开始读取文件:', filePath)
|
||
plus.io.resolveLocalFileSystemURL(filePath, (entry) => {
|
||
entry.file((file) => {
|
||
console.log('[COS] 文件大小:', file.size, 'bytes')
|
||
const reader = new plus.io.FileReader()
|
||
reader.onloadend = (e) => {
|
||
const base64Data = e.target.result
|
||
const pure = base64Data.split(',')[1]
|
||
const binary = atob(pure)
|
||
const len = binary.length
|
||
const bytes = new Uint8Array(len)
|
||
for (let i = 0; i < len; i++) {
|
||
bytes[i] = binary.charCodeAt(i)
|
||
}
|
||
console.log('[COS] 文件读取完成, 准备PUT上传, 数据大小:', len, 'bytes')
|
||
|
||
// 使用 uni.request 发送 PUT,APP端走原生网络,支持 ArrayBuffer
|
||
uni.request({
|
||
url: presignUrl,
|
||
method: 'PUT',
|
||
header: { 'Content-Type': 'image/jpeg' },
|
||
data: bytes.buffer,
|
||
timeout: 120000,
|
||
success(res) {
|
||
console.log('[COS] PUT响应, statusCode:', res.statusCode)
|
||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
||
resolve()
|
||
} else {
|
||
reject(new Error(`COS上传失败: ${res.statusCode}`))
|
||
}
|
||
},
|
||
fail(err) {
|
||
console.error('[COS] PUT请求失败:', JSON.stringify(err))
|
||
reject(new Error('COS上传网络错误: ' + (err.errMsg || '')))
|
||
}
|
||
})
|
||
}
|
||
reader.onerror = () => {
|
||
console.error('[COS] 文件读取失败')
|
||
reject(new Error('读取文件失败'))
|
||
}
|
||
reader.readAsDataURL(file)
|
||
})
|
||
}, (err) => {
|
||
console.error('[COS] 解析文件路径失败:', JSON.stringify(err))
|
||
reject(new Error('解析文件路径失败: ' + JSON.stringify(err)))
|
||
})
|
||
})
|
||
}
|
||
// #endif
|