info
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
export function generateCoverURL (url, cropRule) {
|
||||
if (!url || !cropRule) return url
|
||||
|
||||
const parsedUrl = new URL(url)
|
||||
|
||||
if (parsedUrl.pathname.endsWith('.webp')) {
|
||||
return url
|
||||
}
|
||||
|
||||
const isQuery = parsedUrl.search.length > 0
|
||||
|
||||
const separator = isQuery ? '&' : '?'
|
||||
|
||||
return url + separator + cropRule
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
async function getImageInfo(tempFile, fileInfo) {
|
||||
return new Promise(resolve => {
|
||||
uni.getImageInfo({
|
||||
src: fileInfo.src,
|
||||
success: (res) => {
|
||||
fileInfo.width = res.width
|
||||
fileInfo.height = res.height
|
||||
},
|
||||
complete: () => {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function getVideoInfo(tempFile, fileInfo) {
|
||||
return new Promise(resolve => {
|
||||
// #ifdef H5
|
||||
if (!('duration' in tempFile)) {
|
||||
const video = document.createElement('video')
|
||||
video.src = tempFile.path
|
||||
// 获取视频的长度/时间
|
||||
video.addEventListener('loadedmetadata', () => {
|
||||
fileInfo.duration = video.duration
|
||||
fileInfo.width = video.videoWidth
|
||||
fileInfo.height = video.videoHeight
|
||||
|
||||
resolve()
|
||||
})
|
||||
return
|
||||
}
|
||||
// #endif
|
||||
|
||||
fileInfo.duration = tempFile.duration
|
||||
fileInfo.width = tempFile.width
|
||||
fileInfo.height = tempFile.height
|
||||
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
|
||||
export async function transformPreviewMediaList(tempFiles = []) {
|
||||
const files = []
|
||||
for (const tempFile of tempFiles) {
|
||||
const [mediaType = '', fileType] = (tempFile.type || tempFile.fileType)?.split('/') || []
|
||||
const fileInfo = {
|
||||
src: tempFile.path,
|
||||
size: tempFile.size,
|
||||
type: mediaType,
|
||||
fileType: fileType,
|
||||
name: tempFile.name
|
||||
}
|
||||
|
||||
if (mediaType === 'image') {
|
||||
await getImageInfo(tempFile, fileInfo)
|
||||
} else if (mediaType === 'video') {
|
||||
await getVideoInfo(tempFile, fileInfo)
|
||||
}
|
||||
|
||||
files.push(fileInfo)
|
||||
}
|
||||
|
||||
return files
|
||||
}
|
||||
|
||||
const imageExtname = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp']
|
||||
const videoExtname = ['.mp4', '.avi', '.mov', '.rmvb', '.rm', '.flv', '.3gp', '.wmv', '.mkv']
|
||||
export const extnameMap = {
|
||||
all: [...imageExtname, ...videoExtname],
|
||||
image: imageExtname,
|
||||
video: videoExtname,
|
||||
}
|
||||
|
||||
export function cropImg(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let ext
|
||||
let filePathProcessed = file.path // 处理结果
|
||||
// #ifdef H5
|
||||
ext = file.name.split('.').pop()
|
||||
resolve({
|
||||
path: filePathProcessed,
|
||||
ext,
|
||||
fileType: file.fileType
|
||||
})
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
uni.getImageInfo({
|
||||
src: file.path,
|
||||
success(info) {
|
||||
ext = info.type.toLowerCase()
|
||||
resolve({
|
||||
path: filePathProcessed,
|
||||
ext,
|
||||
fileType: file.fileType
|
||||
})
|
||||
},
|
||||
fail(err) {
|
||||
reject(new Error(err.errMsg || '未能获取图片类型'))
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
const uniMediaLibraryCo = uniCloud.importObject('uni-media-library-co', {
|
||||
customUI: true
|
||||
})
|
||||
|
||||
export default class UploadURL {
|
||||
constructor(props) {
|
||||
this.provider = props.provider
|
||||
this.images = props.images
|
||||
this.$mediaList = props.mediaList
|
||||
}
|
||||
|
||||
get preUploadImages () {
|
||||
return this.images.map(item => {
|
||||
return {
|
||||
src: item.thumbUrl,
|
||||
raw: item.url,
|
||||
// size: tempFile.size,
|
||||
type: 'image',
|
||||
// fileType: fileType,
|
||||
name: item.originalName,
|
||||
width: item.width,
|
||||
height: item.height,
|
||||
attributes: {
|
||||
description: item.description,
|
||||
alt: item.alt
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async upload () {
|
||||
if (!this.images || !this.images.length) return false
|
||||
|
||||
this.$mediaList.chooseFiles(
|
||||
this.preUploadImages,
|
||||
)
|
||||
|
||||
const promises = this.preUploadImages.map((item, index) => {
|
||||
this.$mediaList.mediaUploadProgress({
|
||||
index,
|
||||
loaded: 0,
|
||||
total: 0,
|
||||
tempFilePath: item.src
|
||||
})
|
||||
|
||||
return uniMediaLibraryCo.uploadImage({
|
||||
url: item.raw
|
||||
}).then(res => {
|
||||
return {
|
||||
path: item.src,
|
||||
url: res.data.fileId,
|
||||
attributes: item.attributes
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
await this.$mediaList.mediaUploadSuccess(
|
||||
await Promise.all(promises)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import createUploaderProviderInstance from './provider'
|
||||
|
||||
class Uploader {
|
||||
constructor(props) {
|
||||
props = Object.assign({
|
||||
provider: 'internal'
|
||||
}, props)
|
||||
|
||||
this.uploaderInstance = createUploaderProviderInstance(props.provider)
|
||||
this.imageLibraryProvider = props.imageLibraryProvider
|
||||
|
||||
this.callbacks = {}
|
||||
this.waitUploadFiles = []
|
||||
|
||||
this.uploaderInstance.on('progress', (data) => {
|
||||
this.emit('progress', data)
|
||||
})
|
||||
this.uploaderInstance.on('success', (data) => {
|
||||
this.emit('success', data)
|
||||
})
|
||||
this.uploaderInstance.on('error', (data) => {
|
||||
this.emit('error', data)
|
||||
})
|
||||
}
|
||||
|
||||
on (event, callback) {
|
||||
this.callbacks[event] = callback
|
||||
}
|
||||
|
||||
emit (event, data) {
|
||||
if (this.callbacks[event]) {
|
||||
this.callbacks[event](data)
|
||||
}
|
||||
}
|
||||
|
||||
async add (file) {
|
||||
if (file instanceof Array) {
|
||||
const files = await this.normalizeFiles(file)
|
||||
this.waitUploadFiles = this.waitUploadFiles.concat(files)
|
||||
} else {
|
||||
this.waitUploadFiles.push(
|
||||
await this.normalizeFiles([file])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async upload () {
|
||||
return this.uploaderInstance.upload(this.waitUploadFiles)
|
||||
}
|
||||
|
||||
async cloudUpload () {
|
||||
return this.uploaderInstance.cloudUpload(this.waitUploadFiles, {
|
||||
imageLibraryProvider: this.imageLibraryProvider
|
||||
})
|
||||
}
|
||||
|
||||
normalizeFiles (files) {
|
||||
return Promise.resolve(files)
|
||||
}
|
||||
}
|
||||
|
||||
export default Uploader
|
||||
@@ -0,0 +1,154 @@
|
||||
import Uploader from "./base";
|
||||
import UploaderFile from "./struct/upload-file";
|
||||
|
||||
export class FromFileUploader extends Uploader {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
chooseImage (options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.chooseImage({
|
||||
sizeType: ['original'],
|
||||
extension: options.extension,
|
||||
success: (res) => {
|
||||
resolve(res.tempFiles)
|
||||
},
|
||||
fail: (e) => {
|
||||
reject(e)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
chooseVideo (options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.chooseVideo({
|
||||
compressed: false,
|
||||
extension: options.extension,
|
||||
success: (res) => {
|
||||
resolve([
|
||||
{
|
||||
name: (res.tempFile && res.tempFile.name) || 'unknown',
|
||||
type: (res.tempFile && res.tempFile.type) || '',
|
||||
path: res.tempFilePath,
|
||||
duration: res.duration,
|
||||
size: res.size,
|
||||
height: res.height,
|
||||
width: res.width,
|
||||
}
|
||||
])
|
||||
},
|
||||
fail: (e) => {
|
||||
reject(e)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
chooseAll (options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.chooseFile({
|
||||
type: 'all',
|
||||
extension: options.extension,
|
||||
success: (res) => {
|
||||
resolve(res.tempFiles)
|
||||
},
|
||||
fail: (e) => {
|
||||
reject(e)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async chooseFileAndUpload (options) {
|
||||
const {type, onChooseFile, success, fail} = options
|
||||
let choosePromise
|
||||
|
||||
if (type === 'image') {
|
||||
choosePromise = this.chooseImage(options)
|
||||
} else if (type === 'video') {
|
||||
choosePromise = this.chooseVideo(options)
|
||||
} else {
|
||||
choosePromise = this.chooseAll(options)
|
||||
}
|
||||
|
||||
return choosePromise.then(files => {
|
||||
return this.add(files)
|
||||
}).then(() => {
|
||||
typeof onChooseFile === 'function' && onChooseFile(
|
||||
this.waitUploadFiles
|
||||
)
|
||||
return this.upload()
|
||||
}).then(success).catch(fail)
|
||||
}
|
||||
|
||||
getImageInfo(tempFile, fileInfo) {
|
||||
return new Promise(resolve => {
|
||||
uni.getImageInfo({
|
||||
src: fileInfo.originUrl,
|
||||
success: (res) => {
|
||||
fileInfo.attributes.width = res.width
|
||||
fileInfo.attributes.height = res.height
|
||||
},
|
||||
complete: () => {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getVideoInfo(tempFile, fileInfo) {
|
||||
return new Promise(resolve => {
|
||||
// #ifdef H5
|
||||
if (!('duration' in tempFile)) {
|
||||
const video = document.createElement('video')
|
||||
video.src = fileInfo.originUrl
|
||||
// 获取视频的长度/时间
|
||||
video.addEventListener('loadedmetadata', () => {
|
||||
fileInfo.attributes.duration = video.duration
|
||||
fileInfo.attributes.width = video.videoWidth
|
||||
fileInfo.attributes.height = video.videoHeight
|
||||
|
||||
resolve()
|
||||
})
|
||||
return
|
||||
}
|
||||
// #endif
|
||||
|
||||
fileInfo.attributes.duration = tempFile.duration
|
||||
fileInfo.attributes.width = tempFile.width
|
||||
fileInfo.attributes.height = tempFile.height
|
||||
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
|
||||
async normalizeFiles (files) {
|
||||
let newFiles = []
|
||||
for (const file of files) {
|
||||
const [mediaType = '', fileType] = (file.type || file.fileType)?.split('/') || []
|
||||
const fileInfo = {
|
||||
name: file.name,
|
||||
originUrl: file.path,
|
||||
thumbUrl: file.path,
|
||||
size: file.size,
|
||||
mediaType: mediaType,
|
||||
fileType: fileType,
|
||||
attributes: {}
|
||||
}
|
||||
|
||||
if (mediaType === 'image') {
|
||||
await this.getImageInfo(file, fileInfo)
|
||||
} else if (mediaType === 'video') {
|
||||
await this.getVideoInfo(file, fileInfo)
|
||||
}
|
||||
|
||||
newFiles.push(
|
||||
new UploaderFile(fileInfo)
|
||||
)
|
||||
}
|
||||
|
||||
return newFiles
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './file'
|
||||
export * from './url'
|
||||
@@ -0,0 +1,17 @@
|
||||
class UploadProvider {
|
||||
constructor() {
|
||||
this.callbacks = {}
|
||||
}
|
||||
|
||||
on (event, callback) {
|
||||
this.callbacks[event] = callback
|
||||
}
|
||||
|
||||
emit (event, data) {
|
||||
if (this.callbacks[event]) {
|
||||
this.callbacks[event](data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default UploadProvider
|
||||
@@ -0,0 +1,14 @@
|
||||
import InternalUploadProvider from './internal'
|
||||
import QiniuUploadProvider from './qiniu'
|
||||
function createUploaderProviderInstance (provider) {
|
||||
switch (provider) {
|
||||
case 'internal':
|
||||
return new InternalUploadProvider()
|
||||
case 'qiniu':
|
||||
return new QiniuUploadProvider()
|
||||
default:
|
||||
return new InternalUploadProvider()
|
||||
}
|
||||
}
|
||||
|
||||
export default createUploaderProviderInstance
|
||||
@@ -0,0 +1,81 @@
|
||||
import BaseProvider from './base';
|
||||
|
||||
const uniMediaLibraryCo = uniCloud.importObject('uni-media-library-co', {
|
||||
customUI: true
|
||||
})
|
||||
|
||||
class InternalUploadProvider extends BaseProvider {
|
||||
async upload (files) {
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i]
|
||||
const ext = await file.getFileType()
|
||||
|
||||
try {
|
||||
const result = await uniCloud.uploadFile({
|
||||
filePath: file.originUrl,
|
||||
fileType: file.mediaType,
|
||||
cloudPathAsRealPath: true,
|
||||
cloudPath: `uni-media-library/${Date.now()}.${ext}`,
|
||||
onUploadProgress: (progressEvent) => {
|
||||
file.setStatus('uploading')
|
||||
file.setPercent(Math.floor((progressEvent.loaded / progressEvent.total) * 100))
|
||||
this.emit('progress', file)
|
||||
}
|
||||
})
|
||||
file.setStatus('uploaded')
|
||||
file.setUrl(result.fileID)
|
||||
file.setPercent(100)
|
||||
} catch (e) {
|
||||
file.setStatus('failed')
|
||||
file.setError(e)
|
||||
console.error(e)
|
||||
}
|
||||
|
||||
if ((i + 1) === files.length) {
|
||||
this.emit('success', files)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async cloudUpload (files, options) {
|
||||
const { imageLibraryProvider } = options
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i]
|
||||
|
||||
try {
|
||||
file.setStatus('uploading')
|
||||
file.setPercent(0)
|
||||
this.emit('progress', file)
|
||||
|
||||
const result = await uniMediaLibraryCo.uploadImage({
|
||||
url: file.originUrl,
|
||||
id: file.id,
|
||||
provider: imageLibraryProvider
|
||||
})
|
||||
|
||||
if (!result.data.fileID) {
|
||||
file.setStatus('failed')
|
||||
file.setError(new Error('上传失败'))
|
||||
this.emit('error', file)
|
||||
return
|
||||
}
|
||||
|
||||
file.setStatus('uploaded')
|
||||
file.setUrl(result.data.fileID)
|
||||
file.setPercent(100)
|
||||
file.setAttributes(result.data.detail)
|
||||
} catch (e) {
|
||||
file.setStatus('failed')
|
||||
file.setError(e)
|
||||
console.error(e)
|
||||
this.emit('error', file)
|
||||
}
|
||||
|
||||
if ((i + 1) === files.length) {
|
||||
this.emit('success', files)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default InternalUploadProvider
|
||||
@@ -0,0 +1,5 @@
|
||||
import BaseProvider from './base';
|
||||
|
||||
class QiniuUploadProvider extends BaseProvider {}
|
||||
|
||||
export default QiniuUploadProvider
|
||||
@@ -0,0 +1,75 @@
|
||||
class UploaderFile {
|
||||
constructor(props = {}) {
|
||||
if (!props.name || !props.mediaType || !props.originUrl) {
|
||||
throw new Error('缺少必要字段')
|
||||
}
|
||||
|
||||
this.id = props.id // id
|
||||
this.name = props.name // originalName
|
||||
this.size = props.size // fileSize
|
||||
this.mediaType = props.mediaType // type
|
||||
this.fileType = props.fileType // fileType
|
||||
this.originUrl = props.originUrl // url
|
||||
this.thumbUrl = props.thumbUrl // thumbUrl
|
||||
this.attributes = props.attributes || {} // description, alt
|
||||
|
||||
this.url = '' // fileId
|
||||
this.status = 'waiting' // waiting, uploading, uploaded, failed
|
||||
this.percent = 0 // 0-100
|
||||
this.error = null
|
||||
}
|
||||
|
||||
setError (error) {
|
||||
this.error = error
|
||||
}
|
||||
|
||||
setUrl (url) {
|
||||
this.url = url
|
||||
}
|
||||
|
||||
setPercent (percent) {
|
||||
this.percent = percent
|
||||
}
|
||||
|
||||
setStatus (status) {
|
||||
this.status = status
|
||||
}
|
||||
|
||||
setAttributes (attributes = {}) {
|
||||
if (attributes.fileType) {
|
||||
this.fileType = attributes.fileType
|
||||
}
|
||||
|
||||
if (attributes.size) {
|
||||
this.size = attributes.size
|
||||
}
|
||||
|
||||
this.attributes = attributes
|
||||
}
|
||||
getFileType () {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (this.fileType) {
|
||||
return resolve(this.fileType)
|
||||
}
|
||||
|
||||
// #ifdef H5
|
||||
this.fileType = this.name.split('.').pop()
|
||||
resolve(this.fileType)
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
uni.getImageInfo({
|
||||
src: this.originUrl,
|
||||
success(info) {
|
||||
this.fileType = info.type.toLowerCase()
|
||||
resolve(this.fileType)
|
||||
},
|
||||
fail(err) {
|
||||
reject(new Error(err.errMsg || '未能获取图片类型'))
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default UploaderFile
|
||||
@@ -0,0 +1,20 @@
|
||||
import Uploader from './base';
|
||||
import UploaderFile from "./struct/upload-file";
|
||||
|
||||
export class FromURLUploader extends Uploader {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
normalizeFiles(files) {
|
||||
return files.map(file => {
|
||||
return new UploaderFile({
|
||||
id: file.id,
|
||||
name: file.name,
|
||||
originUrl: file.url,
|
||||
thumbUrl: file.thumbUrl || file.url,
|
||||
mediaType: file.mediaType
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user