2023-09-16 19:21:05 +08:00

400 lines
9.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

export class LsjFile {
constructor(data) {
this.dom = null;
// files.type = waiting等待上传|| loading上传中|| success成功 || fail失败
this.files = new Map();
this.debug = data.debug || false;
this.id = data.id;
this.width = data.width;
this.height = data.height;
this.option = data.option;
this.instantly = data.instantly;
this.prohibited = data.prohibited;
this.onchange = data.onchange;
this.onprogress = data.onprogress;
this.uploadHandle = this._uploadHandle;
// #ifdef MP-WEIXIN
this.uploadHandle = this._uploadHandleWX;
// #endif
}
/**
* 创建File节点
* @param {string}path webview地址
*/
create(path) {
if (!this.dom) {
// #ifdef H5
let dom = document.createElement('input');
dom.type = 'file'
dom.value = ''
dom.style.height = this.height
dom.style.width = this.width
dom.style.position = 'absolute'
dom.style.top = 0
dom.style.left = 0
dom.style.right = 0
dom.style.bottom = 0
dom.style.opacity = 0
dom.style.zIndex = 999
dom.accept = this.prohibited.accept;
if (this.prohibited.multiple) {
dom.multiple = 'multiple';
}
dom.onchange = event => {
for (let file of event.target.files) {
if (this.files.size >= this.prohibited.count) {
this.toast(`只允许上传${this.prohibited.count}个文件`);
this.dom.value = '';
break;
}
this.addFile(file);
}
this._uploadAfter();
this.dom.value = '';
};
this.dom = dom;
// #endif
// #ifdef APP-PLUS
let styles = {
top: '-200px',
left: 0,
width: '1px',
height: '200px',
background: 'transparent'
};
let extras = {
debug: this.debug,
instantly: this.instantly,
prohibited: this.prohibited,
}
this.dom = plus.webview.create(path, this.id, styles,extras);
this.setData(this.option);
this._overrideUrlLoading();
// #endif
return this.dom;
}
}
/**
* 设置上传参数
* @param {object|string}name 上传参数,支持a.b 和 a[b]
*/
setData() {
let [name,value = ''] = arguments;
if (typeof name === 'object') {
Object.assign(this.option,name);
}
else {
this._setValue(this.option,name,value);
}
this.debug&&console.log(JSON.stringify(this.option));
// #ifdef APP-PLUS
this.dom.evalJS(`vm.setData('${JSON.stringify(this.option)}')`);
// #endif
}
/**
* 上传
* @param {string}name 文件名称
*/
async upload(name='') {
if (!this.option.url) {
throw Error('未设置上传地址');
}
// #ifndef APP-PLUS
if (name && this.files.has(name)) {
await this.uploadHandle(this.files.get(name));
}
else {
for (let item of this.files.values()) {
if (item.type === 'waiting' || item.type === 'fail') {
await this.uploadHandle(item);
}
}
}
// #endif
// #ifdef APP-PLUS
this.dom&&this.dom.evalJS(`vm.upload('${name}')`);
// #endif
}
// 选择文件change
addFile(file,isCallChange) {
let name = file.name;
this.debug&&console.log('文件名称',name,'大小',file.size);
if (file) {
// 限制文件格式
let path = '';
let suffix = name.substring(name.lastIndexOf(".")+1).toLowerCase();
let formats = this.prohibited.formats.toLowerCase();
// #ifndef MP-WEIXIN
path = URL.createObjectURL(file);
// #endif
// #ifdef MP-WEIXIN
path = file.path;
// #endif
if (formats&&!formats.includes(suffix)) {
this.toast(`不支持上传${suffix.toUpperCase()}格式文件`);
return false;
}
// 限制文件大小
if (file.size > 1024 * 1024 * Math.abs(this.prohibited.size)) {
this.toast(`附件大小请勿超过${this.prohibited.size}M`)
return false;
}
this.files.set(file.name,{file,path,name: file.name,size: file.size,progress: 0,type: 'waiting'});
return true;
}
}
/**
* 移除文件
* @param {string}name 不传name默认移除所有文件传入name移除指定name的文件
*/
clear(name='') {
// #ifdef APP-PLUS
this.dom&&this.dom.evalJS(`vm.clear('${name}')`);
// #endif
if (!name) {
this.files.clear();
}
else {
this.files.delete(name);
}
return this.onchange(this.files);
}
/**
* 提示框
* @param {string}msg 轻提示内容
*/
toast(msg) {
uni.showToast({
title: msg,
icon: 'none'
});
}
/**
* 微信小程序选择文件
* @param {number}count 可选择文件数量
*/
chooseMessageFile(type,count) {
wx.chooseMessageFile({
count: count,
type: type,
success: ({ tempFiles }) => {
for (let file of tempFiles) {
this.addFile(file);
}
this._uploadAfter();
},
fail: () => {
this.toast(`打开失败`);
}
})
}
_copyObject(obj) {
if (typeof obj !== "undefined") {
return JSON.parse(JSON.stringify(obj));
} else {
return obj;
}
}
/**
* 自动根据字符串路径设置对象中的值 支持.和[]
* @param {Object} dataObj 数据源
* @param {String} name 支持a.b 和 a[b]
* @param {String} value 值
* setValue(dataObj, name, value);
*/
_setValue(dataObj, name, value) {
// 通过正则表达式 查找路径数据
let dataValue;
if (typeof value === "object") {
dataValue = this._copyObject(value);
} else {
dataValue = value;
}
let regExp = new RegExp("([\\w$]+)|\\[(:\\d)\\]", "g");
const patten = name.match(regExp);
// 遍历路径 逐级查找 最后一级用于直接赋值
for (let i = 0; i < patten.length - 1; i++) {
let keyName = patten[i];
if (typeof dataObj[keyName] !== "object") dataObj[keyName] = {};
dataObj = dataObj[keyName];
}
// 最后一级
dataObj[patten[patten.length - 1]] = dataValue;
this.debug&&console.log('参数更新后',JSON.stringify(this.option));
}
_uploadAfter() {
this.onchange(this.files);
setTimeout(()=>{
this.instantly&&this.upload();
},1000)
}
_overrideUrlLoading() {
this.dom.overrideUrlLoading({ mode: 'reject' }, e => {
let {retype,item,files,end} = this._getRequest(
e.url
);
let _this = this;
switch (retype) {
case 'updateOption':
this.dom.evalJS(`vm.setData('${JSON.stringify(_this.option)}')`);
break
case 'change':
try {
_this.files = new Map([..._this.files,...JSON.parse(unescape(files))]);
} catch (e) {
return console.error('出错了,请检查代码')
}
_this.onchange(_this.files);
break
case 'progress':
try {
item = JSON.parse(unescape(item));
} catch (e) {
return console.error('出错了,请检查代码')
}
_this._changeFilesItem(item,end);
break
default:
break
}
})
}
_getRequest(url) {
let theRequest = new Object()
let index = url.indexOf('?')
if (index != -1) {
let str = url.substring(index + 1)
let strs = str.split('&')
for (let i = 0; i < strs.length; i++) {
theRequest[strs[i].split('=')[0]] = unescape(strs[i].split('=')[1])
}
}
return theRequest
}
_changeFilesItem(item,end=false) {
this.debug&&console.log('onprogress',JSON.stringify(item));
this.onprogress(item,end);
this.files.set(item.name,item);
}
_uploadHandle(item) {
item.type = 'loading';
delete item.responseText;
return new Promise((resolve,reject)=>{
this.debug&&console.log('option',JSON.stringify(this.option));
let {url,name,method='POST',header,formData} = this.option;
let form = new FormData();
for (let keys in formData) {
form.append(keys, formData[keys])
}
form.append(name, item.file);
let xmlRequest = new XMLHttpRequest();
xmlRequest.open(method, url, true);
for (let keys in header) {
xmlRequest.setRequestHeader(keys, header[keys])
}
xmlRequest.upload.addEventListener(
'progress',
event => {
if (event.lengthComputable) {
let progress = Math.ceil((event.loaded * 100) / event.total)
if (progress <= 100) {
item.progress = progress;
this._changeFilesItem(item);
}
}
},
false
);
xmlRequest.ontimeout = () => {
console.error('请求超时')
item.type = 'fail';
this._changeFilesItem(item,true);
return resolve(false);
}
xmlRequest.onreadystatechange = ev => {
if (xmlRequest.readyState == 4) {
if (xmlRequest.status == 200) {
this.debug&&console.log('上传完成:' + xmlRequest.responseText)
item['responseText'] = xmlRequest.responseText;
item.type = 'success';
this._changeFilesItem(item,true);
return resolve(true);
} else if (xmlRequest.status == 0) {
console.error('status = 0 :请检查请求头Content-Type与服务端是否匹配服务端已正确开启跨域并且nginx未拦截阻止请求')
}
console.error('--ERROR--status = ' + xmlRequest.status)
item.type = 'fail';
this._changeFilesItem(item,true);
return resolve(false);
}
}
xmlRequest.send(form)
});
}
_uploadHandleWX(item) {
item.type = 'loading';
delete item.responseText;
return new Promise((resolve,reject)=>{
this.debug&&console.log('option',JSON.stringify(this.option));
let form = {filePath: item.file.path,...this.option };
form['fail'] = ({ errMsg = '' }) => {
console.error('--ERROR--' + errMsg)
item.type = 'fail';
this._changeFilesItem(item,true);
return resolve(false);
}
form['success'] = res => {
if (res.statusCode == 200) {
this.debug&&console.log('上传完成,微信端返回不一定是字符串根据接口返回格式判断是否需要JSON.parse' + res.data)
item['responseText'] = res.data;
item.type = 'success';
this._changeFilesItem(item,true);
return resolve(true);
}
item.type = 'fail';
this._changeFilesItem(item,true);
return resolve(false);
}
let xmlRequest = uni.uploadFile(form);
xmlRequest.onProgressUpdate(({ progress = 0 }) => {
if (progress <= 100) {
item.progress = progress;
this._changeFilesItem(item);
}
})
});
}
}