我正在使用带有 Angular 7 的 resumablejs 库。当尝试使用可恢复文件上传文件时,它可以正常工作到 1.5 GB,但是当文件大小 > 1.5 GB 时,它在某些情况下可以工作并且在某些情况下会崩溃。不知道是什么导致了这个问题。它在 Firefox 上运行良好,没有任何问题。我怎样才能使它与 Chrome 一起工作。
下面是组件。在这里,我们正在计算文件大小,然后将其显示在屏幕上。
export class ResumableAttachmentComponent
implements AfterViewInit, OnDestroy, OnChanges, OnInit {
@Output() fileSuccess = new EventEmitter<any>();
@Output() fileError = new EventEmitter<any>();
@Output() error = new EventEmitter<any>();
@Output() progress = new EventEmitter<any>();
@Output() pause = new EventEmitter<any>();
@Output() complete = new EventEmitter<any>();
@Output() uploadStart = new EventEmitter<any>();
@Output() uploadCancel = new EventEmitter<any>();
@Output() fileTypeError = new EventEmitter<any>();
@Output() removeBannerImage = new EventEmitter<any>();
@Output() onComponentInit = new EventEmitter<any>();
@Input() allowDirectorySelect = false;
@Input() maxFileSize = 1024 * 1024 * 1024 * 5; // 5GB
@Input() maxFiles = 1; // max number of file allowed
@Input() multiple = false;
@Input() pausable = false;
@Input() entityType: string;
@Input() entityIdentifierId: string;
@Input() categoryId: string;
@Input() chunkSize = 1024 * 1024 * 5; // 5 MB per chunk by default
@Input() checkBeforeUpload: () => boolean;
@Input() showCategory: boolean = true;
@Input() showUploadButton: boolean = true;
@Input() showDelete: boolean = false;
@Input() showUploadMessage: boolean = false;
@Input() fileType: string[] = []; // Allowing for both [extension, .extension, mime/type, mime/*]
@Input() theme: string = 'full';
@Input() permissionLevel: number;
@Input() permission: number;
@Input() bannerAttachment: any = null;
@Input() isUploadDisabled: any = false;
@Input() hasThumbnails: boolean = false;
Permissions = Permissions;
PermissionLevel = PermissionLevel;
fileSizeGreaterThanMaxAllowed = false;
numberOfFilesGreaterThanMaxAllowed = false;
// indicate that the upload is paused by user or not
paused = false;
progressBarElt: any;
querySet: boolean = false;
// text to show on the upload button depending on the fact the file upload is paused or not
uploadBtnText = localize('general_Upload');
filesToUpload: Resumable.ResumableFile[] = [];
disableUploadButton = true;
disablePauseButton = true;
disableCancelButton = true;
isChunking = false;
// @ts-ignore
resumable: Resumable;
supportResumable = false;
currentUser: IUserProfile;
baseUrl = titanApiUrl;
destroySubject = new Subject<any>();
showSelectButton: boolean;
@Input() gridSupport: {
gridData: SimpleGrid;
type: 'extend' | null;
onRowSelect: () => {};
};
resumableUploadedFiles: IResumableFileData;
backboneObservable$: Subscription;
showCommentsDialog: boolean;
tireComment: string;
constructor(
private userProfileService: UserProfileService,
private backbone: BackboneService,
private eltRef: ElementRef,
private renderer: Renderer2,
private notifyService: NotificationService,
private confirmationService: ConfirmationDialogService,
private router: Router,
private userPermissionHelper: UserPermissionHelper,
private attachmentService: AttachmentService
) {
this.currentUser = this.userProfileService.userProfile;
// cancel the file upload when user is navigating away from the page that contains the component
this.router.events
.filter(e => e instanceof NavigationStart)
.distinctUntilChanged()
.takeUntil(this.destroySubject.asObservable())
.subscribe((e: NavigationStart) => {
if (this.resumable && this.resumable.isUploading()) {
this.cancelUpload();
}
});
this.showSelectButton = true;
}
ngOnInit() {
this.checkPermission();
this.backboneObservable$ = this.backbone.message.subscribe(item => {
if (
item.type === BBMessageType.Resumable &&
item.subtype === BBMessageSubType.Resumable_Files_Attached
) {
this.resumableUploadedFiles = item.message;
}
});
this.duplicatesDialog.onSubmit = () => {
this.duplicatesDialog.show = false;
this.resumable.files.forEach(item => {
item.resumableObj.opts.query['overwrite'] =
this.duplicatesDialog.confirmedOverwrite.indexOf(
item.fileName
) >= 0;
});
};
this.onComponentInit.emit(this);
}
reset() {
// reset error flags
this.fileSizeGreaterThanMaxAllowed = false;
this.numberOfFilesGreaterThanMaxAllowed = false;
this.removeAllFiles();
this.isChunking = false;
this.paused = false;
this.uploadBtnText = localize('general_Upload');
//this.hideProgressBar = true
this.renderer.setStyle(this.progressBarElt, 'width', 0);
this.disableCancelButton = true;
this.disablePauseButton = true;
this.disableUploadButton = true;
}
ngOnDestroy() {
this.destroySubject.next();
this.backboneObservable$.unsubscribe();
}
ngAfterViewInit() {
if (!this.querySet) {
this.setResumableQuery();
}
}
hasUploadPermission: boolean = true;
ngOnChanges(changes: SimpleChanges) {
let self = this;
//If Test Template
if (
changes.hasOwnProperty('entityIdentifierId') &&
changes.entityIdentifierId.currentValue
) {
if (!self.querySet) {
self.setResumableQuery();
}
if (self.resumable) {
self.entityIdentifierId =
changes.entityIdentifierId.currentValue;
self.resumable.opts.query['entityId'] =
changes.entityIdentifierId.currentValue;
self.resumable.opts.query['entityIdentifierId'] =
changes.entityIdentifierId.currentValue;
}
}
if (changes.hasOwnProperty('entityType') && self.resumable) {
self.resumable.opts.query['entityType'] = this.entityType;
}
//Hijack query to add new/selected category id
if (changes.hasOwnProperty('categoryId') && self.resumable) {
self.resumable.opts.query['categoryId'] = this.categoryId;
}
if (changes.permission && changes.permissionLevel) {
self.hasUploadPermission = this.userPermissionHelper.checkPermission(
this.permission,
this.permissionLevel
);
}
if (changes.fileType && self.resumable) {
self.resumable.opts.fileType = this.fileType;
}
}
submitComment() {
this.resumable.opts.query['comment'] = this.tireComment;
this.resumable.upload();
this.tireComment = '';
this.showCommentsDialog = false;
}
setResumableQuery() {
let maxFileAllowed = this.multiple ? undefined : this.maxFiles; // undefined => allow to upload multiple file
//
// extra parameters to include in the multipart POST with data
let query = {};
if (this.entityType) {
query['entityType'] = this.entityType;
}
if (this.entityIdentifierId) {
query['entityIdentifierId'] = this.entityIdentifierId;
}
if (this.categoryId) {
query['categoryId'] = this.categoryId;
}
if (this.hasThumbnails) {
query['createThumbnail'] = true;
} else {
query['createThumbnail'] = false;
}
let fileUploadOptions: Resumable.ConfigurationHash = {
target: `${this.baseUrl}ResumableFile/Upload`,
simultaneousUploads: 1,
maxFiles: maxFileAllowed,
chunkSize: this.chunkSize,
forceChunkSize: true,
fileParameterName: 'file', // The name of the multipart POST parameter to use for the file chunk
query,
headers: {
userId: this.currentUser.id,
tenantId: this.currentUser.defaultTenantId
},
fileType: this.fileType,
fileTypeErrorCallback: this.onFileTypeError.bind(this)
};
// @ts-ignore
this.resumable = new Resumable(fileUploadOptions);
this.supportResumable = this.resumable.support; // check if the current browser suport resumable
// add event only if the browser support resumable upload
if (this.supportResumable) {
this.progressBarElt = this.eltRef.nativeElement.querySelector(
'.t-resumable-attachment-progress-bar-indicator'
);
let chooseFileBtn;
if (this.theme === 'icon') {
chooseFileBtn = this.eltRef.nativeElement.querySelector(
'.icon-theme-resumable'
);
} else {
chooseFileBtn = this.eltRef.nativeElement.querySelector(
'.choose-file'
);
}
if (chooseFileBtn) {
this.resumable.assignBrowse(
chooseFileBtn,
this.allowDirectorySelect
);
this.resumable.assignDrop(
this.eltRef.nativeElement.querySelector('.drop-area')
);
} else {
setTimeout(() => {
if (!this.querySet) {
this.setResumableQuery();
}
}, 400);
return;
}
this.setEvents();
}
this.querySet = true;
}
uploadTheFile() {
if (
this.checkBeforeUpload &&
typeof this.checkBeforeUpload === 'function'
) {
let checkResult = this.checkBeforeUpload();
// start the upload only if the check function return true
if (checkResult) {
// this.onUploadStart()
this.resumable.upload();
}
} else if (
this.checkBeforeUpload &&
typeof this.checkBeforeUpload !== 'function'
) {
throw new Error(
"The 'checkBeforeUpload' attribute must be a function."
);
} else {
// this.onUploadStart()
this.resumable.upload();
/* temporarily commenting the Comment popup while uploading file for Tire Model Request
if (this.entityType == 'TireModelSpecs') {
this.showCommentsDialog = true;
} else {
this.resumable.upload();
}*/
}
}
pauseFile() {
this.resumable.pause();
}
cancelUpload() {
this.resumable.cancel();
}
private setEvents() {
this.resumable.on('error', this.onError.bind(this));
this.resumable.on('fileError', this.onFileError.bind(this));
this.resumable.on('pause', this.onPause.bind(this));
this.resumable.on('complete', this.onComplete.bind(this));
this.resumable.on('fileSuccess', this.onFileSuccess.bind(this));
this.resumable.on('cancel', this.onUploadCancel.bind(this));
this.resumable.on('uploadStart', this.onUploadStart.bind(this));
//this.resumable.on('uploadStart', this.startUploadAfterCheckIsOk)
this.resumable.on('fileProgress', this.onProgress.bind(this));
this.resumable.on('fileAdded', this.onFileAdded.bind(this));
this.resumable.on('chunkingStart', this.onChunkingStart.bind(this));
this.resumable.on(
'chunkingComplete',
this.onChunkingComplete.bind(this)
);
}
@Output() onFileAdd = new EventEmitter();
private onFileAdded(file: ResumableFile, event) {
this.numberOfFilesGreaterThanMaxAllowed = false;
this.fileSizeGreaterThanMaxAllowed = false;
this.isDragOver = false;
//Getting Preview Image
let resumableFile: ResumableFile = this.resumable.files.find(item => {
// @ts-ignore
return file.file.uniqueIdentifier === item.uniqueIdentifier;
});
// @ts-ignore
resumableFile.fileReader = new FileReader();
// @ts-ignore
resumableFile.fileReader.readAsDataURL(file.file);
/**
* Show preview only if MIME type is of image type
*/
if (resumableFile.file.type.startsWith('image')) {
resumableFile.isPreviewSupported = true;
}
/**
* TODO: Check if total size was being looked at here..
*/
// @ts-ignore
if (this.resumable.getSize() > this.maxFileSize) {
this.fileSizeGreaterThanMaxAllowed = true;
this.filesToUpload = [...this.resumable.files];
} else if (
!this.multiple &&
this.resumable.files &&
this.resumable.files.length > this.maxFiles
) {
this.numberOfFilesGreaterThanMaxAllowed = true;
} else {
this.filesToUpload = [...this.resumable.files]; // get the updated list of files to upload
this.disableUploadButton = false;
this.renderer.setStyle(this.progressBarElt, 'width', 0);
}
this.disableCancelButton = false;
if (this.theme === 'icon') {
this.uploadTheFile();
} else {
this.duplicatesDialog.duplicatesArray = [];
this.checkForDuplicates();
}
this.setRealLastModifiedDate(resumableFile, file.file.lastModified);
this.onFileAdd.emit(this.filesToUpload);
}
setRealLastModifiedDate(file: ResumableFile, dateMS) {
file['resumableObj'].opts.query['documentLastModifiedByDate'] = moment(
dateMS
).format('YYYY/MM/DD HH:mm');
}
duplicatesDialog: {
duplicatesArray: any[];
confirmedOverwrite: any[];
show: boolean;
onSubmit: any;
} = {
duplicatesArray: [],
confirmedOverwrite: [],
show: false,
onSubmit: () => {}
};
checkForDuplicates() {
if (
this.resumableUploadedFiles &&
this.currentUser.tenantFeatureMap.overwriteFile &&
this.resumableUploadedFiles.categoryId === this.categoryId &&
this.resumableUploadedFiles.entityIdentifierId ===
this.entityIdentifierId
) {
this.filesToUpload.forEach(item => {
if (
this.resumableUploadedFiles.data.indexOf(item.fileName) >= 0
) {
this.duplicatesDialog.duplicatesArray.push(item.fileName);
} else {
item['resumableObj'].opts.query['overwrite'] = false;
}
});
}
if (this.duplicatesDialog.duplicatesArray.length > 0) {
this.duplicatesDialog.show = true;
}
}
private onPause() {
this.paused = true;
this.disableUploadButton = false;
this.uploadBtnText = localize('general_Resume');
this.pause.emit();
}
onComplete() {
this.complete.emit();
//Reset filesToUpload after completion
this.removeAllFiles();
}
OnRemoveBannerImg() {
this.confirmationService.setConfirm({
message: localize('general_ConformMessageForDelete'),
header: localize('general_Delete'),
accept: () => {
this.removeBannerImage.emit();
},
reject: () => {}
});
}
// `message` is the response body from the server.
private onFileSuccess(file: ResumableFile, message: any) {
if (this.showUploadMessage) {
this.notifyService.notify({
severity: 'success',
summary: localize('general_Success'),
detail: localize('general_MessageSuccessFileUploaded')
});
}
this.filesToUpload = [];
this.fileSuccess.emit({ file, message });
this.disableCancelButton = true;
this.disablePauseButton = true;
this.disableUploadButton = true;
}
// error on a specific file
private onFileError(file: ResumableFile, message: any) {
this.fileError.emit({ file, message });
}
// general error
private onError(message: any, file: ResumableFile) {
this.error.emit({ file, message });
}
onUploadStart() {
//this.hideProgressBar = false
this.uploadStart.emit(this.resumable.files.length);
this.paused = false;
this.disableUploadButton = true;
this.uploadBtnText = localize('general_Upload');
this.disableCancelButton = false;
this.disablePauseButton = false;
this.disableUploadButton = true;
}
private onProgress(file: ResumableFile) {
let fileClone: any = { ...file };
fileClone.uploaded = file.progress(false);
let totalProgress = this.resumable.progress();
let progressPercentage = Math.floor(totalProgress * 100) + '%';
this.renderer.setStyle(
this.progressBarElt,
'width',
progressPercentage
);
this.progress.emit({ file: fileClone, uploaded: totalProgress });
}
/**
* return individual file upload progress
*/
parseProgress(file: ResumableFile) {
return (
Math.round(Math.floor(file.progress(false) * 100) * 10) / 10 + '%'
);
}
private onUploadCancel() {
this.paused = false;
this.uploadBtnText = localize('general_Upload');
this.filesToUpload = this.resumable.files;
this.renderer.setStyle(this.progressBarElt, 'width', 0);
this.uploadCancel.emit();
this.disableCancelButton = true;
this.disablePauseButton = true;
this.disableUploadButton = true;
}
private removeAllFiles() {
let copy = [...this.resumable.files];
copy.forEach((f: any) => this.resumable.removeFile(f));
this.filesToUpload = this.resumable.files;
this.duplicatesDialog.confirmedOverwrite = [];
this.duplicatesDialog.duplicatesArray = [];
}
private onChunkingStart() {
this.isChunking = true;
}
private onChunkingComplete() {
this.isChunking = false;
}
private onFileTypeError(file, errorCount) {
this.fileTypeError.emit({ file, errorCount });
}
removeFile(file: any) {
this.resumable.removeFile(file);
// update the list when a file is removed
this.filesToUpload = this.resumable.files;
this.onFileAdd.emit(this.filesToUpload);
}
getFileSize(sizeInOctet: number) {
sizeInOctet = +sizeInOctet; // convert to number in case ng pass the value as string
let KB = 1024;
let MB = 1024 * 1024;
let GB = 1024 * 1024 * 1024;
if (sizeInOctet >= KB) {
if (sizeInOctet >= MB) {
if (sizeInOctet >= GB) {
return `${(sizeInOctet / GB).toFixed(2)} GB`;
}
return `${(sizeInOctet / MB).toFixed(2)} MB`;
}
return `${(sizeInOctet / KB).toFixed(2)} KB`;
}
return `${sizeInOctet} Bytes`;
}
// case multiple file
// Hide pause/resume when the upload has completed
// Show pause, hide resume on upload start
isDragOver: boolean = false;
onDrop($event) {
this.isDragOver = false;
}
allowDrop($event) {
this.isDragOver = true;
}
onLeave() {
this.isDragOver = false;
}
hasAccess: boolean = false;
hasReadAccess: boolean = false;
hasDeleteAccess: boolean = false;
hasCreateAccess: boolean = false;
checkPermission() {
if (
this.permission &&
this.permissionLevel &&
this.entityIdentifierId &&
this.entityType
) {
this.hasDeleteAccess =
this.userPermissionHelper.checkPermission(
this.permission,
PermissionLevel.Delete
) ||
this.userPermissionHelper.checkSpecialPermission(
this.permission,
PermissionLevel.Delete,
this.entityIdentifierId,
this.entityType
);
this.hasReadAccess =
this.userPermissionHelper.checkPermission(
this.permission,
PermissionLevel.Read
) ||
this.userPermissionHelper.checkSpecialPermission(
this.permission,
PermissionLevel.Read,
this.entityIdentifierId,
this.entityType
);
this.hasCreateAccess =
this.userPermissionHelper.checkPermission(
this.permission,
PermissionLevel.Create
) ||
this.userPermissionHelper.checkSpecialPermission(
this.permission,
PermissionLevel.Create,
this.entityIdentifierId,
this.entityType
);
this.hasAccess =
this.hasCreateAccess ||
this.hasDeleteAccess ||
this.hasReadAccess;
}
}
checkFileList() {
if (!this.resumable) {
return !this.isChunking;
} else {
return !this.isChunking && !this.resumable.isUploading();
}
}
downloadAttachment(id) {
this.attachmentService.download(id);
}
viewLog(id) {
this.attachmentService.getLogByDocumentId;
}
previewFileUrl: string = '';
previewDialog: boolean = false;
expandImage(previewFileUrl) {
this.previewFileUrl = previewFileUrl;
this.previewDialog = true;
}
}