203 lines
4.7 KiB
JavaScript
203 lines
4.7 KiB
JavaScript
import {
|
||
showQiniuUploadProgress,
|
||
hideQiniuUploadProgress,
|
||
updateQiniuUploadProgress,
|
||
resetQiniuUploadProgress,
|
||
qiniuUploadProgressState
|
||
} from './qiniuUploadProgress.js'
|
||
|
||
export const QINIU_UPLOAD_URL = 'https://up-z2.qiniup.com'
|
||
export const QINIU_CDN_PREFIX = 'https://api.ccttiot.com/'
|
||
|
||
export function fetchQiniuToken($u) {
|
||
return $u.get('/common/qiniuToken').then((res) => {
|
||
if (res.code == 200 && res.data) {
|
||
return res.data
|
||
}
|
||
return null
|
||
}).catch(() => null)
|
||
}
|
||
|
||
export function parseQiniuUploadKey(res) {
|
||
if (!res || res.statusCode !== 200 || res.data == null || res.data === '') {
|
||
return ''
|
||
}
|
||
try {
|
||
const body = typeof res.data === 'string' ? JSON.parse(res.data) : res.data
|
||
if (!body || body.error) {
|
||
return ''
|
||
}
|
||
const key = body.key
|
||
if (typeof key !== 'string' || !key.trim()) {
|
||
return ''
|
||
}
|
||
return key.trim()
|
||
} catch (e) {
|
||
return ''
|
||
}
|
||
}
|
||
|
||
export function parseQiniuUploadUrl(res, cdnPrefix = QINIU_CDN_PREFIX) {
|
||
const key = parseQiniuUploadKey(res)
|
||
return key ? cdnPrefix + key : ''
|
||
}
|
||
|
||
/** 校验上传结果,不合法则抛错 */
|
||
export function assertValidUploadResult(result, returnKey = false) {
|
||
if (result == null || result === '') {
|
||
throw new Error('upload result empty')
|
||
}
|
||
const value = String(result).trim()
|
||
if (!value || value === 'undefined' || value.indexOf('undefined') !== -1) {
|
||
throw new Error('upload result invalid')
|
||
}
|
||
if (returnKey) {
|
||
return value
|
||
}
|
||
if (!/^https?:\/\//.test(value)) {
|
||
throw new Error('upload url invalid')
|
||
}
|
||
return value
|
||
}
|
||
|
||
function doUploadQiniuFile(options = {}) {
|
||
const {
|
||
filePath,
|
||
token,
|
||
key,
|
||
cdnPrefix = QINIU_CDN_PREFIX,
|
||
returnKey = false,
|
||
onProgress
|
||
} = options
|
||
|
||
return new Promise((resolve, reject) => {
|
||
if (!filePath) {
|
||
reject(new Error('missing filePath'))
|
||
return
|
||
}
|
||
if (!token) {
|
||
reject(new Error('missing token'))
|
||
return
|
||
}
|
||
if (!key) {
|
||
reject(new Error('missing key'))
|
||
return
|
||
}
|
||
const uploadTask = uni.uploadFile({
|
||
url: QINIU_UPLOAD_URL,
|
||
filePath,
|
||
name: 'file',
|
||
formData: {
|
||
token,
|
||
key
|
||
},
|
||
success: (res) => {
|
||
const uploadKey = parseQiniuUploadKey(res)
|
||
if (!uploadKey) {
|
||
reject(new Error('upload parse failed'))
|
||
return
|
||
}
|
||
try {
|
||
const result = returnKey ? uploadKey : cdnPrefix + uploadKey
|
||
resolve(assertValidUploadResult(result, returnKey))
|
||
} catch (e) {
|
||
reject(e)
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
reject(err || new Error('upload request failed'))
|
||
}
|
||
})
|
||
if (uploadTask && uploadTask.onProgressUpdate && onProgress) {
|
||
uploadTask.onProgressUpdate(onProgress)
|
||
}
|
||
})
|
||
}
|
||
|
||
export function uploadQiniuFile(options = {}) {
|
||
const {
|
||
title = '上传中',
|
||
showProgress = true
|
||
} = options
|
||
|
||
if (showProgress) {
|
||
showQiniuUploadProgress(title)
|
||
}
|
||
|
||
return doUploadQiniuFile({
|
||
...options,
|
||
onProgress: showProgress ? updateQiniuUploadProgress : options.onProgress
|
||
}).then((result) => {
|
||
if (showProgress) {
|
||
qiniuUploadProgressState.progress = 100
|
||
qiniuUploadProgressState.speedText = '完成'
|
||
setTimeout(() => hideQiniuUploadProgress(), 200)
|
||
}
|
||
return result
|
||
}).catch((err) => {
|
||
if (showProgress) {
|
||
hideQiniuUploadProgress()
|
||
}
|
||
throw err
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 带 token 刷新与失败重试的上传(默认最多 3 次:首次 + 重试 2 次)
|
||
* 仅在上传结果校验通过后才 resolve,调用方可放心展示
|
||
*/
|
||
export async function uploadQiniuFileWithRetry($u, options = {}) {
|
||
const maxRetry = options.maxRetry != null ? options.maxRetry : 2
|
||
const showProgress = options.showProgress !== false
|
||
const title = options.title || '上传中'
|
||
const returnKey = !!options.returnKey
|
||
let token = options.token || null
|
||
let lastError = null
|
||
|
||
if (showProgress) {
|
||
showQiniuUploadProgress(title)
|
||
}
|
||
|
||
for (let attempt = 0; attempt <= maxRetry; attempt++) {
|
||
try {
|
||
if (!token) {
|
||
token = await fetchQiniuToken($u)
|
||
}
|
||
if (!token) {
|
||
throw new Error('no token')
|
||
}
|
||
if (attempt > 0 && showProgress) {
|
||
resetQiniuUploadProgress()
|
||
qiniuUploadProgressState.title = maxRetry > 0
|
||
? `${title}(重试 ${attempt}/${maxRetry})`
|
||
: title
|
||
}
|
||
|
||
const result = await doUploadQiniuFile({
|
||
...options,
|
||
token,
|
||
onProgress: showProgress ? updateQiniuUploadProgress : options.onProgress
|
||
})
|
||
|
||
const validResult = assertValidUploadResult(result, returnKey)
|
||
if (showProgress) {
|
||
qiniuUploadProgressState.progress = 100
|
||
qiniuUploadProgressState.speedText = '完成'
|
||
setTimeout(() => hideQiniuUploadProgress(), 200)
|
||
}
|
||
return validResult
|
||
} catch (e) {
|
||
lastError = e
|
||
token = null
|
||
if (attempt < maxRetry) {
|
||
token = await fetchQiniuToken($u)
|
||
}
|
||
}
|
||
}
|
||
|
||
if (showProgress) {
|
||
hideQiniuUploadProgress()
|
||
}
|
||
throw lastError || new Error('upload failed')
|
||
}
|