You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

286 lines
7.2 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!-- eslint-disable -->
<template>
<view>
<!-- #ifdef APP-PLUS -->
<view class="xe-upload" v-html="renderInput" :props="mergeProps" :change:props="XeUpload.renderProps"></view>
<!-- #endif -->
</view>
</template>
<script>
import {
chooseMedia,
chooseFile,
chooseMessageFile,
uploadFile,
} from '../../tools/apis';
import {
deepMerge,
awaitWrap,
base64ToPath,
isArray,
} from '../../tools/tools';
export default {
name: 'XeUpload',
props: {
options: {
default: () => ({}),
type: Object,
},
},
data() {
return {
id: 0, // APP上传框ID
renderInput: '', // APP上传框
};
},
computed: {
mergeOptions({ options = {} }) {
const tmpOptions = {
name: 'file',
};
return deepMerge(tmpOptions, options);
},
mergeProps({ id, renderInput, mergeOptions }) {
return {
id,
renderInput,
upload: mergeOptions,
};
},
},
methods: {
// 上传事件
async upload(type, config = {}) {
let tmpResult = [];
if (['image', 'video'].includes(type)) {
const [err, res] = await chooseMedia(type, config);
if (err) return this.handleError(err);
tmpResult = res?.tempFiles || [];
}
// H5 || APP-PLUS || MP-WEIXIN
if (['file'].includes(type)) {
let tmpFiles = {};
let tmpErr = null;
// #ifdef H5
[tmpErr, tmpFiles] = await chooseFile(config);
// #endif
// #ifdef MP-WEIXIN
[tmpErr, tmpFiles] = await chooseMessageFile(config);
// #endif
// #ifdef APP-PLUS
this.id = Math.floor(Math.random() * 100000000 + 1);
this.initInput(config.extension);
// #endif
if (tmpErr) return this.handleError(tmpErr);
tmpResult = tmpFiles?.tempFiles || [];
}
this.handleUpload(tmpResult);
},
// 初始化上传框
initInput(extension) {
const { id } = this;
let accept = extension;
if (isArray(extension)) {
accept = extension.join(',');
}
this.renderInput = `<input type="file" id="xe-upload-${id}" name="xe-upload" ${accept ? 'accept="' + accept + '"' : ''} />`;
},
// 文件上传没有传入上传url时返回本地链接
async handleUpload(files = []) {
if (files.filter((e) => Boolean(e)).length === 0) return;
const { mergeOptions } = this;
if (!mergeOptions.url) {
return this.handleEmits({
type: 'choose',
data: files,
});
}
const tmpUploads = files.map((e) =>
uploadFile(
{
...mergeOptions,
filePath: e.tempFilePath,
},
e,
)
);
const [err, res] = await awaitWrap(Promise.all(tmpUploads));
if (err) return this.handleError(err);
this.handleEmits({
type: 'success',
data: res,
});
},
// 处理失败事件
handleError(error) {
this.handleEmits({
type: 'warning',
data: error,
});
},
// 处理响应事件
async handleEmits(e) {
// #ifdef APP-PLUS
if (e.type === 'choose') {
// 将base64转为本地链接
for (let i = 0; i < e.data.length; i += 1) {
const item = e.data[i];
if (!item.base64Url) {
continue;
}
const [parseError, parseUrl] = await awaitWrap(base64ToPath(item.base64Url, item.name));
if (!parseError) {
e.data[i].tempFilePath = parseUrl;
} else {
e.data[i].tempFilePath = item.base64Url;
}
delete e.data[i].base64Url;
}
}
// #endif
this.$emit('callback', e);
},
},
};
</script>
<!-- #ifdef APP-PLUS -->
<script module="XeUpload" lang="renderjs">
import {
appUploadFile,
} from '../../tools/apis';
import {
awaitWrap,
fileToBase64,
} from '../../tools/tools';
export default {
data() {
return {
id: 0, // ID
uploadOptions: {}, //
};
},
methods: {
// XeUpload renderjs
renderProps(info) {
const { id, renderInput, upload } = info;
if (!renderInput) return;
this.id = id;
this.uploadOptions = upload;
this.$nextTick(() => {
const dom = document.getElementById(`xe-upload-${id}`);
dom.addEventListener('change', () => {
this.handleUpload();
});
dom?.click?.();
});
},
// 处理文件上传(没有传入url时返回本地链接)
async handleUpload() {
const {
url,
name,
header = {},
formData = {},
} = this.uploadOptions || {};
const dom = document.getElementById(`xe-upload-${this.id}`);
if (!dom.files[0]) return;
const tmpFileList = Array.from(dom.files);
const tmpUploads = [];
for (let i = 0; i < tmpFileList.length; i += 1) {
const e = tmpFileList[i];
let tmpType = 'file';
if (e.type.includes('image')) {
tmpType = 'image';
}
if (e.type.includes('video')) {
tmpType = 'video';
}
const tmpExts = {
size: e.size,
name: e.name,
type: e.type,
fileType: tmpType,
tempFilePath: '',
base64Url: '',
};
// 没有传入上传url时直接返回本地链接
if (!url) {
const [parseError, parseUrl] = await awaitWrap(fileToBase64(dom.files[i]));
if (!parseError) {
tmpExts.base64Url = parseUrl;
}
tmpUploads.push(tmpExts);
continue;
};
const tmpData = new FormData();
tmpData.append(name, dom.files[i], e.name);
for (let key in formData) {
tmpData.append(key, formData[key]);
}
// 上传进度
const onprogress = (ev) => {
if(ev.lengthComputable) {
var result = (ev.loaded / ev.total) * 100;
this.handleRenderEmits({
type: 'onprogress',
data: {
progress: Math.floor(result),
current: i + 1,
total: tmpFileList.length,
},
});
};
}
tmpUploads.push(appUploadFile({
url,
header,
formData: tmpData
}, tmpExts, onprogress ));
}
// 没有传入上传url时直接返回本地链接列表
if (!url) {
return this.handleRenderEmits({
type: 'choose',
data: tmpUploads,
});
}
this.handleRenderEmits({
type: 'onprogress',
data: {
progress: 0,
current: 1,
total: tmpFileList.length,
},
});
// 处理上传文件
const [err, res] = await awaitWrap(Promise.all(tmpUploads));
if (err) {
return this.handleRenderEmits({
type: 'warning',
data: err,
});
}
this.handleRenderEmits({
type: 'success',
data: res,
});
},
// 数据传输到XeUpload组件
handleRenderEmits(data) {
this.$ownerInstance.callMethod('handleEmits', data);
},
},
};
</script>
<!-- #endif -->
<style scoped>
.xe-upload {
display: none;
}
</style>