odf_new/odf-uniapp/services/cos.js
zpc a6c639dd43
All checks were successful
continuous-integration/drone/push Build is passing
21
2026-04-05 16:51:24 +08:00

94 lines
2.8 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 })
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) => {
plus.io.resolveLocalFileSystemURL(filePath, (entry) => {
entry.file((file) => {
const reader = new plus.io.FileReader()
reader.onloadend = (e) => {
const base64 = e.target.result
// 将 base64 转为 ArrayBuffer
const binary = atob(base64.split(',')[1])
const len = binary.length
const bytes = new Uint8Array(len)
for (let i = 0; i < len; i++) {
bytes[i] = binary.charCodeAt(i)
}
// 使用 XMLHttpRequest 发送 PUT
const xhr = new XMLHttpRequest()
xhr.open('PUT', presignUrl, true)
xhr.setRequestHeader('Content-Type', 'image/jpeg')
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve()
} else {
reject(new Error(`COS上传失败: ${xhr.status}`))
}
}
xhr.onerror = () => reject(new Error('COS上传网络错误'))
xhr.send(bytes.buffer)
}
reader.onerror = () => reject(new Error('读取文件失败'))
reader.readAsDataURL(file)
})
}, (err) => {
reject(new Error('解析文件路径失败: ' + JSON.stringify(err)))
})
})
}
// #endif