Compare commits
6 Commits
437a3fcc58
...
master
Author | SHA1 | Date | |
---|---|---|---|
52b2af097f | |||
ea5e731bd2 | |||
74a7fe7eb6 | |||
2f9d552e43 | |||
004671c006 | |||
0f6a1e7a45 |
@ -40,7 +40,7 @@ export default abstract class ApiService {
|
|||||||
Object.keys(queryParams).forEach(key => {
|
Object.keys(queryParams).forEach(key => {
|
||||||
const value = queryParams[key];
|
const value = queryParams[key];
|
||||||
if (value !== null && value !== undefined) {
|
if (value !== null && value !== undefined) {
|
||||||
if (typeof (value) === typeof (Array)) {
|
if (Array.isArray(value)) {
|
||||||
(value as Array<any>).forEach(x => url.searchParams.append(key, x.toString()));
|
(value as Array<any>).forEach(x => url.searchParams.append(key, x.toString()));
|
||||||
} else
|
} else
|
||||||
url.searchParams.append(key, value.toString());
|
url.searchParams.append(key, value.toString());
|
||||||
|
@ -74,14 +74,14 @@ export class ScheduleService extends ApiService {
|
|||||||
return this.addAuth(request).post<any>(request);
|
return this.addAuth(request).post<any>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public uploadScheduleFile(files: File[], force: boolean) {
|
public uploadScheduleFile(files: File[], campus: string[], force: boolean) {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
files.forEach(file => formData.append('files', file, file.name));
|
files.forEach(file => formData.append('files', file, file.name));
|
||||||
|
|
||||||
const request = this.createRequestBuilder()
|
const request = this.createRequestBuilder()
|
||||||
.setEndpoint('Upload')
|
.setEndpoint('Upload')
|
||||||
.setData(formData)
|
.setData(formData)
|
||||||
.setQueryParams({force: force})
|
.setQueryParams({force: force, defaultCampus: campus})
|
||||||
.build;
|
.build;
|
||||||
|
|
||||||
return this.addAuth(request).post(request);
|
return this.addAuth(request).post(request);
|
||||||
|
@ -18,11 +18,23 @@
|
|||||||
@if (selectedFiles.length > 0) {
|
@if (selectedFiles.length > 0) {
|
||||||
<div style="margin-top: 15px;">
|
<div style="margin-top: 15px;">
|
||||||
<p>Выбранные файлы:</p>
|
<p>Выбранные файлы:</p>
|
||||||
<ul>
|
@for (item of selectedFiles; track $index) {
|
||||||
@for (file of selectedFiles; track $index) {
|
<p>
|
||||||
<li>{{ file.name }}</li>
|
{{ item.file.name }}
|
||||||
|
</p>
|
||||||
|
<mat-form-field color="accent" style="margin-bottom: 18px;">
|
||||||
|
<mat-label>Кампус по умолчанию</mat-label>
|
||||||
|
<input matInput type="text" [(ngModel)]="item.campus"
|
||||||
|
[matAutocomplete]="auto">
|
||||||
|
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="onSelectCampus($event.option.value, item)">
|
||||||
|
@for (option of onFilter(item.campus); track $index) {
|
||||||
|
<mat-option [value]="option">
|
||||||
|
{{ option }}
|
||||||
|
</mat-option>
|
||||||
|
}
|
||||||
|
</mat-autocomplete>
|
||||||
|
</mat-form-field>
|
||||||
}
|
}
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</app-configuration-card>
|
</app-configuration-card>
|
||||||
|
@ -9,6 +9,12 @@ import {MatButtonModule} from "@angular/material/button";
|
|||||||
import {MatIcon} from "@angular/material/icon";
|
import {MatIcon} from "@angular/material/icon";
|
||||||
import {ScheduleService} from "@api/v1/configuration/schedule.service";
|
import {ScheduleService} from "@api/v1/configuration/schedule.service";
|
||||||
import {DataSpinnerComponent} from "@component/common/data-spinner/data-spinner.component";
|
import {DataSpinnerComponent} from "@component/common/data-spinner/data-spinner.component";
|
||||||
|
import {MatFormFieldModule} from "@angular/material/form-field";
|
||||||
|
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
|
||||||
|
import {MatInput} from "@angular/material/input";
|
||||||
|
import {ToastrService} from "ngx-toastr";
|
||||||
|
import {MatAutocomplete, MatAutocompleteTrigger, MatOption} from "@angular/material/autocomplete";
|
||||||
|
import {CampusService} from "@api/v1/campus.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-schedule-file-upload',
|
selector: 'app-schedule-file-upload',
|
||||||
@ -16,17 +22,36 @@ import {DataSpinnerComponent} from "@component/common/data-spinner/data-spinner.
|
|||||||
ConfigurationCardComponent,
|
ConfigurationCardComponent,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatIcon,
|
MatIcon,
|
||||||
DataSpinnerComponent
|
DataSpinnerComponent,
|
||||||
|
MatFormFieldModule,
|
||||||
|
FormsModule,
|
||||||
|
MatInput,
|
||||||
|
MatAutocomplete,
|
||||||
|
MatAutocompleteTrigger,
|
||||||
|
MatOption,
|
||||||
|
ReactiveFormsModule
|
||||||
],
|
],
|
||||||
templateUrl: './schedule-file-upload.component.html',
|
templateUrl: './schedule-file-upload.component.html',
|
||||||
providers: [ScheduleService]
|
providers: [ScheduleService, CampusService]
|
||||||
})
|
})
|
||||||
export class ScheduleFileUploadComponent {
|
export class ScheduleFileUploadComponent {
|
||||||
selectedFiles: File[] = [];
|
protected selectedFiles: { file: File, campus: string }[] = [];
|
||||||
fileLoading: boolean = false;
|
protected fileLoading: boolean = false;
|
||||||
|
protected campuses: string[] = [];
|
||||||
@ViewChild('fileInput') input!: ElementRef;
|
@ViewChild('fileInput') input!: ElementRef;
|
||||||
|
|
||||||
constructor(private dialog: MatDialog, private api: ScheduleService) {
|
constructor(
|
||||||
|
private dialog: MatDialog,
|
||||||
|
private api: ScheduleService,
|
||||||
|
private notify: ToastrService,
|
||||||
|
campus: CampusService) {
|
||||||
|
campus.getCampus().subscribe(data => {
|
||||||
|
this.campuses = data.map(x => x.codeName);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onSelectCampus(value: string, item: { file: File, campus: string }) {
|
||||||
|
item.campus = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected saveFunction() {
|
protected saveFunction() {
|
||||||
@ -34,23 +59,32 @@ export class ScheduleFileUploadComponent {
|
|||||||
const dialogRef = this.dialog.open(ConfirmDeleteScheduleDialogComponent);
|
const dialogRef = this.dialog.open(ConfirmDeleteScheduleDialogComponent);
|
||||||
|
|
||||||
return dialogRef.afterClosed().pipe(switchMap(result => {
|
return dialogRef.afterClosed().pipe(switchMap(result => {
|
||||||
return this.api.uploadScheduleFile(this.selectedFiles, result);
|
return this.api.uploadScheduleFile(
|
||||||
|
this.selectedFiles.map(x => x.file),
|
||||||
|
this.selectedFiles.map(x => x.campus),
|
||||||
|
result);
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onFileChooseClick() {
|
protected onFilter(value: string): string[] {
|
||||||
|
const filterValue = value?.toLowerCase() || '';
|
||||||
|
return this.campuses.filter(campus => campus.toLowerCase().includes(filterValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onFileChooseClick() {
|
||||||
this.fileLoading = true;
|
this.fileLoading = true;
|
||||||
this.input.nativeElement.click();
|
this.input.nativeElement.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
onFileSelected(event: any): void {
|
protected onFileSelected(event: any): void {
|
||||||
this.fileLoading = false;
|
this.fileLoading = false;
|
||||||
this.selectedFiles = Array.from(event.target.files);
|
this.selectedFiles = Array.from(event.target.files).map(file => ({file: <File>file, campus: ''}));
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpload(data: Observable<any>): void {
|
protected onUpload(data: Observable<any>): void {
|
||||||
data.subscribe(_ => {
|
data.subscribe(_ => {
|
||||||
|
this.notify.info(`Файлы в размере ${this.selectedFiles.length} успешно загружены. Задача поставлена в очередь`);
|
||||||
this.selectedFiles = [];
|
this.selectedFiles = [];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -69,9 +69,9 @@ export class SkipUpdateScheduleComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
validateSaveButton(): boolean {
|
validateSaveButton(): boolean {
|
||||||
return this.dateItems.some(item =>
|
return (this.dateItems.length == 0 || this.dateItems.some(item =>
|
||||||
(item.start && item.end) || item.date
|
(item.start && item.end) || item.date
|
||||||
) && JSON.stringify(this.dateItems) != JSON.stringify(this.dateItemsBefore);
|
)) && JSON.stringify(this.dateItems) != JSON.stringify(this.dateItemsBefore);
|
||||||
}
|
}
|
||||||
|
|
||||||
saveFunction() {
|
saveFunction() {
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
.notification-content {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close-button {
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
<div class="notification-content" [class]="data.className">
|
|
||||||
<span>
|
|
||||||
{{ data.message }}
|
|
||||||
</span>
|
|
||||||
<button mat-icon-button class="close-button" (click)="dismiss()">
|
|
||||||
<mat-icon>close</mat-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
@if (showProgressBar) {
|
|
||||||
<mat-progress-bar mode="determinate" [value]="progress" [color]="color"/>
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
import {Component, Inject} from '@angular/core';
|
|
||||||
import {MatIcon} from "@angular/material/icon";
|
|
||||||
import {MatProgressBar} from "@angular/material/progress-bar";
|
|
||||||
import {MAT_SNACK_BAR_DATA, MatSnackBarRef} from "@angular/material/snack-bar";
|
|
||||||
import {MatIconButton} from "@angular/material/button";
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-notification',
|
|
||||||
standalone: true,
|
|
||||||
imports: [
|
|
||||||
MatIconButton,
|
|
||||||
MatIcon,
|
|
||||||
MatProgressBar
|
|
||||||
],
|
|
||||||
templateUrl: './notification.component.html',
|
|
||||||
styleUrl: './notification.component.css'
|
|
||||||
})
|
|
||||||
|
|
||||||
export class NotificationComponent {
|
|
||||||
showProgressBar: boolean = false;
|
|
||||||
progress: number = 100;
|
|
||||||
color: string = "primary";
|
|
||||||
|
|
||||||
constructor(@Inject(MAT_SNACK_BAR_DATA) public data: any, private snackBarRef: MatSnackBarRef<NotificationComponent>) {
|
|
||||||
if (data.duration) {
|
|
||||||
this.startProgress(data.duration);
|
|
||||||
this.showProgressBar = true;
|
|
||||||
}
|
|
||||||
if (data.color) {
|
|
||||||
this.color = data.color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dismiss(): void {
|
|
||||||
this.snackBarRef.dismiss();
|
|
||||||
}
|
|
||||||
|
|
||||||
private startProgress(duration: number): void {
|
|
||||||
const interval: number = duration / 100;
|
|
||||||
const progressInterval = setInterval(async () => {
|
|
||||||
this.progress--;
|
|
||||||
if (this.progress === 0) {
|
|
||||||
clearInterval(progressInterval);
|
|
||||||
setTimeout(() => {
|
|
||||||
this.dismiss();
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
}, interval);
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user