import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { ToastController, IonicModule, LoadingController, } from '@ionic/angular'; import * as Parse from 'parse'; import * as qiniu from 'qiniu-js'; @Component({ selector: 'app-upload', templateUrl: './upload.component.html', styleUrls: ['./upload.component.scss'], standalone: true, imports: [IonicModule], }) export class UploadComponent implements OnInit { @Input('files') files: Array = []; @Input('boxWidth') boxWidth: number = 390; //盒子宽度 @Input('fileWidth') fileWidth: number = 86; //图片高度 @Input('fileHeight') fileHeight: number = 86; //图片宽度 @Input('maxlenght') maxlenght: number = 1; //文件数量限制 @Input('type') type: string = 'image'; @Input('size') size: number = 2048; //上传文件限制大小单位KB @Input('multiple') multiple: boolean = false; //是否允许选择多张 @Output() onChange: EventEmitter = new EventEmitter(); showBlockNum: number = 4; //每行显示数量 get accept() { let type; switch (this.type) { case 'image': type = 'image/*'; break; case 'pdf': type = 'application/pdf'; break; case 'audio': type = 'audio/*'; break; case 'video': type = 'video/*'; break; default: type = 'file'; break; } return type; } disabled: boolean = false; company: string = localStorage.getItem('company') || 'Qje9D4bqol'; config: { uptoken: string; domain: string; bucket: string } = { uptoken: '', domain: '', bucket: '', }; fileList: Array<{ url: string; name: string; type: string; size?: number; file?: any; }> = []; Previewfilelist: any; //预览图片数组 loading: any; currentPreviewImg:string = '' constructor( public toastController: ToastController, public loadCtrl: LoadingController ) { Parse.Cloud.run('qiniu_uptoken', { company: this.company }).then((data) => { this.config = { uptoken: data.uptoken, domain: data.domain, bucket: data.bucket, }; }); } ngOnInit() { /* 计算文件布局 */ let n = Math.floor(this.boxWidth / this.fileWidth); if (n * this.fileWidth + (n - 1) * 10 > this.boxWidth) { this.showBlockNum = n - 1; } else { this.showBlockNum = n; } this.fileList = this.files.map((item: any) => { console.log(item); return { url: item?.url, name: item?.name, type: 'http', // status: 'done', }; }); this.Previewfilelist = this.fileList; } onPreview(url:string){ this.currentPreviewImg = url } onDelete(index: number) { console.log(index); this.fileList.splice(index, 1); } async onAdd(e: any) { let files = e.target.files; if (this.fileList.length + files.length > this.maxlenght) { const toast = await this.toastController.create({ message: '超出上传文件数量', color: 'warning', duration: 1000, }); toast.present(); return; } for (let index = 0; index < files.length; index++) { const f = files[index]; this.changeFileReader(f); } console.log(this.fileList); } //转图片格式 changeFileReader(file: any) { return new Promise((res) => { const windowURL = window.URL || window.webkitURL; const src = windowURL.createObjectURL(file); let size = file.size / 1024; //KB this.fileList.push({ url: src, size: size, name: file.name || '未知', type: 'local', file: file, }); res(true); return; // const reader: any = new FileReader(); // reader.readAsDataURL(file); // reader.filename = file.name; // console.log(file); // let _this = this; // reader.onload = async function (e: any) { // let size = e.total / 1024; //KB // let baseUrl = e.target.result; // if (size > _this.size) { // const toast = await _this.toastController.create({ // message: file.name + '文件过大', // color: 'warning', // duration: 1000, // }); // toast.present(); // res(true); // return; // } // _this.fileList.push({ // url: baseUrl, // size: size, // name: file.name || '未知', // type: 'local', // file: file, // }); // res(true); // }; }); } async onUpload() { let authLoad = await this.authSpaceCount(); if (!authLoad) { const toast = await this.toastController.create({ message: '文件存储空间已满,请联系维护人员。', color: 'warning', duration: 1000, }); toast.present(); } let fs = this.fileList; this.loading = await this.loadCtrl.create({ message: '上传中' }); this.loading.present(); for (let index = 0; index < fs.length; index++) { const f = fs[index]; if (f.type == 'local') { console.log(f); let url = await this.onQiniuUpFile(f); await this.saveAttachment({ size: f.size, url: url, name: f.name, type: this.fileList[index].file.type, }); this.fileList[index].url = url; this.fileList[index].type = 'http'; delete this.fileList[index].file; delete this.fileList[index].size; } } this.onChange.emit(this.fileList); this.loading.dismiss(); } /* 校验存储空间 */ async authSpaceCount(): Promise { let company = this.company; let query = new Parse.Query('Company'); query.select('configSpace'); let comObj = await query.get(company); let limit = comObj.get('configSpace') && comObj.get('configSpace').limit; // return new Promise((res, rej) => { let res = await fetch( `https://server.fmode.cn/api/storage/space?c=${company}` ); let data = await res.json(); console.log(data); if (data?.code == 200) { let spaceMap = data.data; let _spaceLimit = this.getLimitBytes(limit); let spaceUsed = spaceMap.totalSize; console.log('总空间:', _spaceLimit); console.log('已用空间:', spaceUsed); if (!_spaceLimit || spaceUsed > _spaceLimit) { return false; } return true; } return false; } // 单位 getLimitBytes(limit: string) { let u: number = 1024 * 1024 * 1024; if (limit) { let num = Number(limit.slice(0, limit.length - 2)); let unit: string = limit.slice(-2); switch (unit) { case 'EB': u = 1024 * 1024 * 1024 * 1024 * 1024 * 1024; break; case 'PB': u = 1024 * 1024 * 1024 * 1024 * 1024; break; case 'TB': u = 1024 * 1024 * 1024 * 1024; break; case 'GB': u = 1024 * 1024 * 1024; break; case 'MB': u = 1024 * 1024; break; case 'KB': u = 1024; break; default: break; } return num * u; } return u; } onQiniuUpFile(file: any): Promise { return new Promise((resolve, reject) => { console.log('进入了上传'); let datepath = this.DateFormat(new Date(), 'hhmmss'); let qiniuFileKey = this.company + '/' + datepath + '/' + file.name; const putExtra = { fname: '', params: {}, mimeType: this.accept, }; const config = { useCdnDomain: true, //使用cdn加速 }; const observable = qiniu.upload( file.file, qiniuFileKey, this.config.uptoken, putExtra, config ); observable.subscribe({ next: (result) => { // 主要用来展示进度 console.log('上传===', result); }, error: async (err) => { console.error(err); const toast = await this.toastController.create({ message: '上传失败', color: 'warning', duration: 1000, }); toast.present(); reject(err); }, complete: (res) => { console.log('上传完成'); console.log(res.key); console.log(`${this.config.domain}${res.key}`); resolve(`${this.config.domain}${res.key}`); // this.loading.dismiss(); }, }); }); } async saveAttachment( file: { size?: number; url: string; name: string; type: string }, cateId?: string ) { let Attachment = Parse.Object.extend('Attachment'); let attachment = new Attachment(); file.size && attachment.set('size', Math.ceil(file.size)); attachment.set('url', file.url); attachment.set('name', file.name); attachment.set('mime', file.type); attachment.set('company', { __type: 'Pointer', className: 'Company', objectId: this.company, }); cateId && attachment.set('category', { __type: 'Pointer', className: 'Category', objectId: cateId, }); return await attachment.save(); } DateFormat(date: Date, fmt: string) { //author: meizz let o: any = { 'M+': date.getMonth() + 1, //月份 'd+': date.getDate(), //日 'h+': date.getHours(), //小时 'm+': date.getMinutes(), //分 's+': date.getSeconds(), //秒 'q+': Math.floor((date.getMonth() + 3) / 3), //季度 S: date.getMilliseconds(), //毫秒 }; if (/(y+)/.test(fmt)) fmt = fmt.replace( RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length) ); for (let k in o) if (new RegExp('(' + k + ')').test(fmt)) fmt = fmt.replace( RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length) ); return fmt; } }