@cataract6545/tmui
Version:
tm-vuetify是一个新势力由主题驱动的UI组件库,相比其它优势大,组件全,设计趋势紧跟未来。具有主题生成,主题实时切换,暗黑实时切换,lottie动画,图表等新颖功能,tmui TMUI
399 lines (370 loc) • 11.8 kB
text/typescript
//文件上传的状态值
export enum statusCode {
//待上传
upload = 0,
//上传中
uploading = 1,
//上传失败
fail = 2,
//上传成功
success = 3,
//超过大小限制
max = 4,
}
//文件对象结构
export interface file {
url: string,//当前显示的图片地址,这是个本地临时地址。待上传前,成功后会替换服务器地址。
status?: string,//上传状态文本
progress?: number,//当前文件上传的进度
uid?: string | number,//文件唯一标识id
statusCode?: statusCode,//文件状态
response?: any,//上传成功后的回调数据。
name?: string,//文件名称
[propName: string]: any
}
//上传class对象的配置。
export interface fileConfig {
maxSize?: number,//每一个文件上传的最大尺寸,默认为10mb
maxFile?: number,//一次选择文件最大数量。
fileType?: Array<string>,//文件选择的类型。
hostUrl?: string,//上传文件的服务器地址
fileList?: Array<file>,//已上传的文件列表。
autoUpload?: Boolean,
header?: Object,//头部参数。
formData?: Object,//额外的表单数据。
formName?: string,
statusCode?: number,//服务返回成功的状态码标志,默认200表示成功。
}
export function getUid(length = 3) {
return Number(Number(Math.random().toString().substr(3, length) + Date.now()).toString(8));
}
/**
* 上传文件。
* 作者:tmzdy
* 时间:2022年4月27日
* 联系:zhongjihan@sina.com
* @method {Function} beforeChooesefile -- 选择图片上传前执行的勾子。
* @method {Function} chooesefile -- 选择图片上传,弹出层进行选择文件 。
* @method {Function} chooesefileAfter -- 选择图片、视频文件成功后触发。返回选择后的文件。此时还未加入待上传列表,会返回 一个文件列表用于过滤。需要在函数中再返回 一个文件 列表,
* @method {Function} chooesefileSuccess -- 文件已经加入到了待上传文件列表,需要返回过滤的文件列表
* @method {Function} beforeAddfile -- 动态加入预计加入文件前执行的勾子,返回true才会正式加入到待上传列表中。
* @method {Function} addFile -- 动态加入预上传的文件。
* @method {Function} progress -- 进度。
* @method {Function} fail -- 失败。服务器出现非200时触发。
* @method {Function} beforeSuccess -- 服务器返回成功,立即执行的勾子。如果此时返回false,则表示文件 上传失败。
* @method {Function} success -- 成功。
* @method {Function} complete -- 单个文件完成。不管上传成功与失败否,都会触发此函数。
* @method {Function} uploadComplete -- 所有文件上传完时触发
* @method {Function} beforeStart -- 开始上传。前的校验勾子。如果返回false,将阻止上传
* @method {Function} start -- 开始上传。
* @method {Function} stop -- 停止上传。中止上传时触发的函数。
*/
export class uploadfile {
//文件列表。
filelist: Array<file> = [];
isStop = false;
index = 0;
config: fileConfig = {};
uploadobj: UniNamespace.UploadTask | null = null;
constructor(config: fileConfig) {
let cf: fileConfig = { maxSize: 10 * 1024 * 1024, maxFile: 9, fileType: ['album', 'camera'], fileList: [], autoUpload: true, header: {}, formData: {}, formName: 'file' }
cf = { ...cf, ...arguments[0] ?? {} };
//配置{name: 'file', // 上传时的文件key名。默认file,header: {}, // 上传的头部参数。}
this.config = cf;
this.addFile(cf.fileList);
delete this.config.fileList;
}
async beforeChooesefile() {
return true;
}
async chooesefileAfter(fileList: Array<file>) {
return fileList;
}
async chooesefileSuccess(fileList: Array<file>) {
return fileList;
}
delete(item: file) {
let index = this.filelist.findIndex(el => el.uid == item.uid);
if (index > -1) {
let p = [...this.filelist]
p.splice(index, 1)
this.filelist = [...p];
}
return this.filelist;
}
async clear() {
/** 清清前要选暂停所有正在上传的文件 */
this.stop();
this.filelist = [];
}
setFileStatus(item: file) {
let index = this.filelist.findIndex(el => el.uid == item.uid);
if (index > -1) {
let p = [...this.filelist]
p.splice(index, 1, item)
this.filelist = [...p];
}
}
/**
* 成功后返回选择后的图片列表。
*/
async chooesefile(): Promise<Array<file>> {
let t = this;
return new Promise(async (rs, rj) => {
let isready = await t.beforeChooesefile();
if (!isready) {
rs([])
return;
}
uni.chooseImage({
count: t.config.maxFile,
sourceType: t.config.fileType,
fail: (e) => {
rj("取消选择");
},
success: async (res) => {
if (res.tempFilePaths.length == 0) {
rj("未选择")
return;
}
let imgarray = res.tempFilePaths;
let fielist = res.tempFiles;
let jgsk: Array<file> = [];
//0待上传,1上传中,2上传失败,3上传成功。4超过大小限制
imgarray.forEach((item: string, index: number) => {
let isMaxsize = fielist[index].size > t.config.maxSize ? true : false;
jgsk.push({
url: item,
status: isMaxsize ? '超过大小' : "待上传",
progress: isMaxsize ? 100 : 0,
uid: getUid(),
statusCode: isMaxsize ? statusCode.max : statusCode.upload,
response: null,
name: fielist[index].name ?? ""
})
})
let isreadyChoose = await t.chooesefileAfter(jgsk);
if (!Array.isArray(isreadyChoose) || typeof isreadyChoose != 'object') {
rj("chooesefileAfter:函数过滤,没有返回文件列表。")
return;
}
t.filelist.push(...isreadyChoose)
t.chooesefileSuccess(isreadyChoose);
rs(isreadyChoose)
if (t.config.autoUpload) {
setTimeout(function () {
t.start();
}, 500);
}
}
})
})
}
async chooseMPH5weixinFile() {
let t = this;
return new Promise((rs, rj) => {
var fs = uni.chooseFile;
// #ifdef MP-WEIXIN || MP-QQ
fs = uni.chooseMessageFile;
// #endif
var config = {
count: t.config.maxfile,
type: t.config.type,
extension: t.config.extension,
}
if (!t.config.extension || !Array.isArray(t.config.extension) || t.config.extension?.length == 0) {
delete config.extension
}
fs({
...config,
fail: (e) => {
console.error(e);
uni.$tm.toast("已取消选择");
rj(e);
},
success: (res) => {
if (res.tempFiles.length == 0) {
uni.$tm.toast("未选择");
return;
}
let fielist = res.tempFiles;
let jgsk = [];
//0待上传,1上传中,2上传失败,3上传成功。4超过大小限制
fielist.forEach((item, index) => {
let isMaxsize = fielist[index].size > t.config.maxsize ? true : false;
let ftype = item.name || ""
if (ftype) {
ftype = ftype.substr(ftype.lastIndexOf(".") + 1).toLocaleLowerCase();
}
jgsk.push({
url: item.path,
name: item.name || '默认文件名称',
type: ftype,
status: isMaxsize ? '超过大小' : "待上传",
progress: isMaxsize ? 100 : 0,
fileId: guid(),
statusCode: isMaxsize ? 4 : 0,
data: null,//上传成功后的回调数据。
})
})
t.filelist.push(...jgsk)
t.selected(t.filelist);
if (t.config.isAuto) {
t.start();
}
rs(t.filelist)
}
})
})
}
setConfig(config: fileConfig) {
this.config = { ...this.config, ...config ?? {} }
}
/**
* 动态加入文件
* @param {Object} filelist
*/
addFile(filelist: Array<file> = []) {
if (typeof filelist !== 'object' && !Array.isArray(filelist)) return;
let total_uid = new Set(this.filelist.map(e => e.uid))
let total_url = new Set(this.filelist.map(e => e.url))
let cfilelist = filelist.map(el => {
return {
...el,
status: el?.status ?? "待上传",
statusCode: el?.statusCode ?? statusCode.upload,
uid: el?.uid ?? getUid(),
progress: el?.progress ?? 0,
name: el?.name ?? "",
response: el?.response ?? null,
url: el?.url ?? ""
}
})
let filterFIle = cfilelist.filter(item => !total_uid.has(item.uid) && !total_url.has(item.url))
this.filelist.push(...filterFIle)
}
beforeSuccess(item: file) {
return Promise.resolve(true);
}
beforeStart(item: file) {
return Promise.resolve(true);
}
// 进度。
progress(item: file,index:number) { }
// 失败
fail(item: file) { }
// 成功
success(item: file, fileList: Array<file>) { }
// 完成。
complete(filelist: file) { }
uploadComplete(filelist: Array<file>) { }
awaitTime() {
return new Promise((resolve) => {
setTimeout(() => {
resolve(true)
}, 20)
})
}
// 开始上传。
async start() {
if (this.filelist.length <= 0) {
console.error("未选择图片,已取消上传")
return;
}
let t = this;
// t重新开始上传从头开始。
this.index = 0;
this.isStop = false;
async function startupload() {
if (t.isStop) return;
let item = t.filelist[t.index];
if (!item || typeof item === 'undefined') {
// 文件不存在。直接结束。
t.uploadComplete(t.filelist);
return;
}
let canbleStart = await t.beforeStart(item)
if (!canbleStart) {
item.statusCode = statusCode.fail;
item.status = "不允许上传"
t.filelist.splice(t.index, 1, item)
t.index++;
t.setFileStatus(item)
t.fail(item)
t.complete(item);
startupload();
return;
}
if (item.statusCode == 3 || item.statusCode == 1 || item.statusCode == 4 || item.statusCode == 2) {
// 直接跳过。至下一个文件。
t.index++;
startupload();
return;
}
item.statusCode = statusCode.uploading;
item.status = "上传中..."
t.setFileStatus(item)
const upObj = t.uploadobj = uni.uploadFile({
url: String(t.config.hostUrl),
name: t.config?.formName ?? 'file',
header: t.config?.header ?? {},
filePath: item.url,
formData: { name: item.name, ...t.config.formData },
success: async (res) => {
if (t.isStop) return
item.response = res.data;
let isOksuccess = await t.beforeSuccess(item);
const statusCode_reonese = t.config?.statusCode ?? 200
if (res.statusCode != statusCode_reonese || !isOksuccess) {
item.statusCode = statusCode.fail;
item.status = "上传失败";
t.fail(item)
t.setFileStatus(item)
t.index++;
return;
}
// 上传成功。
item.statusCode = statusCode.success;
item.status = "上传成功";
t.setFileStatus(item)
t.success(item, t.filelist)
t.index++;
},
fail: (res) => {
if (t.isStop) return
item.statusCode = statusCode.fail;
item.status = "上传失败";
t.setFileStatus(item)
t.fail(item)
t.index++;
},
complete: async (res) => {
if (t.isStop) return
await t.awaitTime();
t.complete(item);
// 直接下一个文件。
startupload();
}
})
if (upObj) {
let item = t.filelist[t.index];
upObj.onProgressUpdate(async (res) => {
if (t.isStop) return
item.progress = res.progress;
item.statusCode = statusCode.uploading;
item.status = "...";
t.setFileStatus(item)
t.progress(item,t.index)
})
}
}
await startupload();
}
// 停止上传
stop() {
this.isStop = true;
if (this.uploadobj != null) {
this.uploadobj.abort()
}
}
}