SUPPORT-8772:add new fileUpload

This commit is contained in:
adel.ka 2024-12-17 14:30:54 +03:00
parent ceecd93b79
commit 0c1c5bbdcf
21 changed files with 2282 additions and 20 deletions

View file

@ -4997,6 +4997,11 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"dev": true
},
"ng2-file-upload": {
"version": "1.3.0",
"resolved": "https://repo.micord.ru/repository/npm-all/ng2-file-upload/-/ng2-file-upload-1.3.0.tgz",
"integrity": "sha512-Pudxik6LWYsT8hNiEW7RfjgGWAnvfQywxwJYMdt1snTUe+KnlRc/QqPv3QEQW6plXTanuLkYz/TbqilSfSHOsw=="
},
"ngx-cookie": {
"version": "3.0.1",
"resolved": "https://repo.micord.ru/repository/npm-all/ngx-cookie/-/ngx-cookie-3.0.1.tgz",

View file

@ -49,10 +49,11 @@
"jsgantt-improved": "2.0.10-cg",
"moment": "2.30.1",
"moment-timezone": "0.5.46",
"ngx-treeview": "10.0.2-micord.2",
"ng2-file-upload": "^1.3.0",
"ngx-cookie": "3.0.1",
"ngx-international-phone-number": "1.0.6",
"ngx-toastr": "10.2.0-cg",
"ngx-treeview": "10.0.2-micord.2",
"popper.js": "1.14.7",
"reflect-metadata": "0.1.13",
"rxjs": "6.4.0",

View file

@ -1540,6 +1540,17 @@
}
}
.webbpm .ervu-file-upload .file-drop-zone {
position: relative;
display: flex;
justify-content: center;
padding: 152px 0 66px 0;
border: 1px dashed #0e243b;
border-radius: 16px;
background: #a58888;
}
/* ErvuFileUpload end *
/*
grid-checkbox

View file

@ -0,0 +1,31 @@
<div [id]="getObjectId()"
class="ervu-file-upload"
[ngbTooltip]="tooltip | emptyIfNull">
<div ng2FileDrop
[uploader]="uploader"
class="file-drop-zone"
*ngIf="(!maxFilesToUpload || uploader.queue.length < maxFilesToUpload) && isDropZoneVisible">
<span class="select-file-field-text">{{selectFileFieldText}}</span>
<button class="select-file-btn" (click)="openFileChooseDialog()">{{selectFileButtonName}}</button>
</div>
<!-- input is out of file-drop-zone because after change ngIf condition input doesn't firing events -->
<input type="file"
class="file-input"
ng2FileSelect
[uploader]="uploader"
[multiple]="!maxFilesToUpload || maxFilesToUpload > 1"
[accept]="getExtensions()"
hidden>
<div class="selected-file-list" *ngIf="isFilesListVisible">
<div class="selected-file" *ngFor="let item of uploader.queue">
<span class="selected-file-name">{{item?.file?.name}}</span>
<span class="selected-file-size" *ngIf="displayFileSize">{{item?.file?.size/1024/1024 | number: '.2'}} MB</span>
<button class="selected-file-delete-btn" (click)="removeFile(item)">{{removeFileButtonName}}</button>
</div>
</div>
<div class="file-upload-progress" *ngIf="displayProgressBar && isProgressBarVisible">
<div class="file-upload-progress-bar"
role="progressbar"
[ngStyle]="{ 'width': uploader.progress + '%' }"></div>
</div>
</div>

View file

@ -0,0 +1,229 @@
import {
AppConfigService,
Event,
InputControl,
MessagesService,
NotNull,
UnsupportedOperationError,
Visible,
} from "@webbpm/base-package";
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef,} from "@angular/core";
import {FileItem, FileLikeObject, FileUploader} from "ng2-file-upload";
@Component({
selector: 'ervu-file-upload',
templateUrl: './../../../../../src/resources/template/ervu-dashboard/ErvuFileUpload.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ErvuFileUpload extends InputControl {
private static readonly BACKEND_URL: string = "backend.context";
@NotNull("true") public selectFileFieldText: string;
@NotNull("true") public selectFileButtonName: string;
@NotNull("true") public removeFileButtonName: string;
public maxFileSizeMb: number;
public extensionFilter: string[] = [];
public maxFilesToUpload: number;
@NotNull("true") public displayFileSize: boolean = false;
@NotNull("true") public displayProgressBar: boolean = false;
@Visible("false") public uploader: FileUploader;
@Visible("false") public fileAddedEvent: Event<any> = new Event<any>();
@Visible("false") public fileDeletedEvent: Event<any> = new Event<any>();
@Visible("false") public fileUploadStartEvent: Event<any> = new Event<any>();
@Visible("false") public fileUploadEndEvent: Event<any> = new Event<any>();
@Visible("false") public fileUploadFailedEvent: Event<any> = new Event<any>();
public isDropZoneVisible: boolean = true;
public isFilesListVisible: boolean = true;
public isProgressBarVisible: boolean = false;
private fileInputEl: HTMLInputElement;
private url: string = '/backend/upload';
private messagesService: MessagesService;
private isUploadErrorOccurred = false;
private appConfigService: AppConfigService;
constructor(el: ElementRef, cd: ChangeDetectorRef) {
super(el, cd);
this.uploader = new FileUploader({url: this.url});
}
initialize() {
super.initialize();
this.messagesService = this.injector.get(MessagesService);
this.appConfigService = this.injector.get(AppConfigService);
this.url =
`/${this.appConfigService.getParamValue(ErvuFileUpload.BACKEND_URL)}/upload`;
this.uploader.setOptions({
url: this.url,
autoUpload: false,
filters: [{
name: 'extension', fn: (item: any): boolean => {
if (!this.extensionFilter.length) {
return true;
}
const fileExtension = item.name.substring(
item.name.lastIndexOf('.') + 1, item.name.length);
for (let ext of this.extensionFilter) {
if (ext.toUpperCase() === fileExtension.toUpperCase()) {
return true;
}
}
return false;
}
}],
maxFileSize: this.maxFileSizeMb
? this.maxFileSizeMb * 1024 * 1024
: undefined,
queueLimit: this.maxFilesToUpload
? this.maxFilesToUpload
: undefined,
headers: [{
name: "Client-Time-Zone",
value: Intl.DateTimeFormat().resolvedOptions().timeZone
}]
});
this.setUploaderMethods();
}
ngAfterViewInit() {
super.ngAfterViewInit();
this.fileInputEl = this.el.nativeElement.querySelector('.file-input');
}
openFileChooseDialog() {
this.fileInputEl.click();
}
@Visible() uploadFiles() {
this.uploader.uploadAll();
}
removeFile(item: FileItem) {
item.remove();
this.fileInputEl.value = null;
this.fileDeletedEvent.trigger();
this.cd.markForCheck();
}
private setUploaderMethods() {
this.uploader.onBeforeUploadItem = (fileItem: FileItem) => {
//refresh headers
this.uploader.setOptions({
headers: [{
name: "Client-Time-Zone",
value: Intl.DateTimeFormat().resolvedOptions().timeZone
}]
});
this.fileUploadStartEvent.trigger();
this.isDropZoneVisible = false;
this.isFilesListVisible = false;
this.isProgressBarVisible = true;
this.cd.markForCheck();
};
this.uploader.onErrorItem = (item: FileItem, response: string) => {
this.fileUploadFailedEvent.trigger();
this.uploader.cancelAll();
this.messagesService.error(`Не удалось отправить следующие файлы: ${item.file.name},` +
` ${this.uploader.getNotUploadedItems()
.map(notUploadeditem => notUploadeditem.file.name)
.join(', ')}.`);
this.uploader.clearQueue();
this.isDropZoneVisible = true;
this.isFilesListVisible = true;
this.isProgressBarVisible = false;
this.isUploadErrorOccurred = true;
this.cd.markForCheck();
};
this.uploader.onCompleteAll = () => {
if (!this.isUploadErrorOccurred) {
this.uploader.clearQueue();
this.fileUploadEndEvent.trigger();
this.isProgressBarVisible = false;
this.cd.markForCheck();
}
};
this.uploader.onAfterAddingFile = (fileItem: FileItem) => {
this.fileAddedEvent.trigger();
}
this.uploader.onWhenAddingFileFailed = (item: FileLikeObject, filter: any, options: any) => {
switch (filter.name) {
case "fileSize":
this.messagesService.error(
`Размер файла ${item.name} превышает предельно допустимый = ${this.maxFileSizeMb} MB`);
break;
case "queueLimit":
this.messagesService.error(`Не удалось добавить файл ${item.name}. ` +
`Достигнуто максимальное количество файлов для загрузки = ${this.maxFilesToUpload}`);
break;
case "extension":
this.messagesService.error(`Файл ${item.name} имеет недопустимое расширение.`);
break;
default:
this.messagesService.error(`Не удалось добавить файл ${item.name}.`);
}
this.fileInputEl.value = null;
this.cd.markForCheck();
};
}
@Visible() getExtensions(): string {
if (this.extensionFilter) {
return this.extensionFilter
.map(s => '.' + s)
.join(',')
}
return undefined;
}
subscribeToModelChange() {
//empty because there is no ngModel here
}
unsubscribeToModelChange() {
//empty because there is no ngModel here
}
@Visible() getPresentationValue(): string {
let fileNames: string = '';
let fileItems: FileItem[] = this.uploader.queue;
if (fileItems) {
fileItems.forEach((fileItem) => {
fileNames += fileItem.file.name;
});
}
return fileNames;
}
@Visible() getValue(): File[] {
return this.uploader.queue.map(fileItem => fileItem._file);
}
getValueAsModel(): any {
throw new UnsupportedOperationError("Unsupported operation");
}
setValue(value: any): any {
throw new UnsupportedOperationError("Unsupported operation");
}
@Visible()
public reset() {
//don't use super because there is no ngModel here
this.uploader.clearQueue();
this.fileInputEl.value = null;
this.isDropZoneVisible = true;
this.isFilesListVisible = true;
this.isProgressBarVisible = false;
this.isUploadErrorOccurred = false;
this.cd.markForCheck();
}
}

View file

@ -25,6 +25,8 @@ import {DropdownTreeViewComponent} from "../../component/field/DropdownTreeViewC
import {DropdownTreeviewSelectComponent} from "../../component/external/ngx-treeview/dropdown-treeview-select/dropdown-treeview-select.component";
import {TreeviewModule} from "ngx-treeview";
import {DataDateComponent} from "./component/data-date.component";
import {ErvuFileUpload} from "../../ervu-dashboard/component/field/ErvuFileUpload";
import {FileUploadModule} from "ng2-file-upload";
registerLocaleData(localeRu);
export const DIRECTIVES = [
@ -37,7 +39,8 @@ export const DIRECTIVES = [
forwardRef(() => FilterContainer),
forwardRef(() => DropdownTreeViewComponent),
forwardRef(() => DropdownTreeviewSelectComponent),
forwardRef(() => DataDateComponent)
forwardRef(() => DataDateComponent),
forwardRef(() => ErvuFileUpload)
];
@NgModule({
@ -52,7 +55,8 @@ export const DIRECTIVES = [
AgGridModule,
RouterModule,
InternationalPhoneNumberModule,
TreeviewModule.forRoot()
TreeviewModule.forRoot(),
FileUploadModule
],
declarations: [
DIRECTIVES

View file

@ -63,7 +63,8 @@
'tslib': 'npm:tslib/tslib.js',
'ngx-international-phone-number': 'npm:ngx-international-phone-number/ngx-international-phone-number.umd.js',
'google-libphonenumber': 'npm:google-libphonenumber/dist/libphonenumber.js',
'ngx-treeview': 'npm:ngx-treeview'
'ngx-treeview': 'npm:ngx-treeview',
'ng2-file-upload': 'npm:ng2-file-upload/bundles/ng2-file-upload.umd.js'
},
packages: {
'webbpm': { main: 'main', defaultExtension: 'js'},

View file

@ -63,7 +63,8 @@
'tslib': 'npm:tslib/tslib.js',
'ngx-international-phone-number': 'npm:ngx-international-phone-number/ngx-international-phone-number.umd.js',
'google-libphonenumber': 'npm:google-libphonenumber/dist/libphonenumber.js',
'ng2-dropdown-treeview': 'npm:ng2-dropdown-treeview'
'ng2-dropdown-treeview': 'npm:ng2-dropdown-treeview',
'ng2-file-upload': 'npm:ng2-file-upload/bundles/ng2-file-upload.umd.js'
},
packages: {
'preview': { main: './modules/preview/preview.main', defaultExtension: 'js'},