Compare commits

...

10 Commits

27 changed files with 471 additions and 752 deletions

View File

@ -4,9 +4,6 @@ import {DateOnly} from "@model/DateOnly";
import {PeriodTimes} from "@model/pairPeriodTime"; import {PeriodTimes} from "@model/pairPeriodTime";
import {ScheduleRequest} from "@api/v1/scheduleRequest"; import {ScheduleRequest} from "@api/v1/scheduleRequest";
import {ScheduleResponse} from "@api/v1/scheduleResponse"; import {ScheduleResponse} from "@api/v1/scheduleResponse";
import {GroupScheduleResponse} from "@api/v1/groupScheduleResponse";
import {ProfessorScheduleResponse} from "@api/v1/professorScheduleResponse";
import {LectureHallScheduleResponse} from "@api/v1/lectureHallScheduleResponse";
import {map} from "rxjs"; import {map} from "rxjs";
@Injectable() @Injectable()
@ -27,18 +24,18 @@ export class ScheduleService extends ApiService {
} }
public getByGroup(id : number, isEven: boolean | null = null, disciplines: Array<number> | null = null, professors: Array<number> | null = null, lectureHalls: Array<number> | null = null) { public getByGroup(id : number, isEven: boolean | null = null, disciplines: Array<number> | null = null, professors: Array<number> | null = null, lectureHalls: Array<number> | null = null) {
return this.get<GroupScheduleResponse>('GetByGroup' + id.toString(), {isEven: isEven, disciplines: disciplines, professors: professors, lectureHalls: lectureHalls}); return this.get<ScheduleResponse[]>('GetByGroup/' + id.toString(), {isEven: isEven, disciplines: disciplines, professors: professors, lectureHalls: lectureHalls});
} }
public getByProfessor(id : number, isEven: boolean | null = null, disciplines: Array<number> | null = null, groups: Array<number> | null = null, lectureHalls: Array<number> | null = null) { public getByProfessor(id : number, isEven: boolean | null = null, disciplines: Array<number> | null = null, groups: Array<number> | null = null, lectureHalls: Array<number> | null = null) {
return this.get<ProfessorScheduleResponse>('GetByProfessor' + id.toString(), {isEven: isEven, disciplines: disciplines, groups: groups, lectureHalls: lectureHalls}); return this.get<ScheduleResponse[]>('GetByProfessor/' + id.toString(), {isEven: isEven, disciplines: disciplines, groups: groups, lectureHalls: lectureHalls});
} }
public getByLectureHall(id : number, isEven: boolean | null = null, disciplines: Array<number> | null = null, groups: Array<number> | null = null, professors: Array<number> | null = null) { public getByLectureHall(id : number, isEven: boolean | null = null, disciplines: Array<number> | null = null, groups: Array<number> | null = null, professors: Array<number> | null = null) {
return this.get<LectureHallScheduleResponse>('GetByLectureHall' + id.toString(), {isEven: isEven, disciplines: disciplines, groups: groups, professors: professors}); return this.get<ScheduleResponse[]>('GetByLectureHall/' + id.toString(), {isEven: isEven, disciplines: disciplines, groups: groups, professors: professors});
} }
public getByDiscipline(id : number, isEven: boolean | null = null, groups: Array<number> | null = null, professors: Array<number> | null = null, lectureHalls: Array<number> | null = null) { public getByDiscipline(id : number, isEven: boolean | null = null, groups: Array<number> | null = null, professors: Array<number> | null = null, lectureHalls: Array<number> | null = null) {
return this.get<GroupScheduleResponse>('GetByDiscipline' + id.toString(), {isEven: isEven, groups: groups, professors: professors, lectureHalls: lectureHalls}); return this.get<ScheduleResponse[]>('GetByDiscipline/' + id.toString(), {isEven: isEven, groups: groups, professors: professors, lectureHalls: lectureHalls});
} }
} }

View File

@ -6,6 +6,7 @@ import {CreateUserRequest} from "@api/v1/createUserRequest";
import {LoggingRequest} from "@api/v1/loggingRequest"; import {LoggingRequest} from "@api/v1/loggingRequest";
import {EmailRequest} from "@api/v1/emailRequest"; import {EmailRequest} from "@api/v1/emailRequest";
import {ScheduleConfigurationRequest} from "@api/v1/scheduleConfigurationRequest"; import {ScheduleConfigurationRequest} from "@api/v1/scheduleConfigurationRequest";
import {DateOnly} from "@model/DateOnly";
@Injectable() @Injectable()
export default class SetupService extends ApiService { export default class SetupService extends ApiService {
@ -49,6 +50,7 @@ export default class SetupService extends ApiService {
} }
public setSchedule(data: ScheduleConfigurationRequest) { public setSchedule(data: ScheduleConfigurationRequest) {
data.startTerm = new DateOnly(data.startTerm).toString();
return this.post<boolean>('SetSchedule', data); return this.post<boolean>('SetSchedule', data);
} }

View File

@ -1,6 +1,8 @@
import {Component} from '@angular/core'; import {Component} from '@angular/core';
import {RouterOutlet} from '@angular/router'; import {RouterOutlet} from '@angular/router';
import {FooterComponent} from "@component/footer/footer.component"; import {FooterComponent} from "@component/common/footer/footer.component";
import localeRu from '@angular/common/locales/ru';
import { registerLocaleData } from '@angular/common';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@ -11,4 +13,7 @@ import {FooterComponent} from "@component/footer/footer.component";
<app-footer/>` <app-footer/>`
}) })
export class AppComponent { export class AppComponent {
constructor() {
registerLocaleData(localeRu);
}
} }

View File

@ -3,7 +3,8 @@ import { provideRouter } from '@angular/router';
import { routes } from './app.routes'; import { routes } from './app.routes';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import {provideHttpClient} from "@angular/common/http";
export const appConfig: ApplicationConfig = { export const appConfig: ApplicationConfig = {
providers: [provideRouter(routes), provideAnimationsAsync()] providers: [provideRouter(routes), provideAnimationsAsync(), provideHttpClient()]
}; };

View File

@ -1,3 +1,7 @@
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import {Routes} from '@angular/router';
import {ScheduleComponent} from "@page/schedule/schedule.component";
export const routes: Routes = []; export const routes: Routes = [];
export const routes: Routes = [
];

View File

@ -21,7 +21,7 @@
</div> </div>
<hr/> <hr/>
<div class="app-footer-copyright"> <div class="app-footer-copyright">
<span>Powered by Winsomnia &copy;{{ currentYear }}.</span> <span>Powered by <a href="https://winsomnia.net">Winsomnia</a> &copy;{{ currentYear }}.</span>
<a href="https://opensource.org/license/mit/">Code licensed under an MIT-style License.</a> <a href="https://opensource.org/license/mit/">Code licensed under an MIT-style License.</a>
<span>Current Version: {{ version }}</span> <span>Current Version: {{ version }}</span>
</div> </div>

View File

@ -6,12 +6,13 @@
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<mat-chip-listbox hideSingleSelectionIndicator (change)="chooseFaculty($event)"> <mat-chip-listbox hideSingleSelectionIndicator (change)="chooseFaculty($event)">
@for (faculty of faculties | async; track $index) { @for (faculty of faculties; track $index) {
<mat-chip-option [value]="faculty.id" color="accent"> <mat-chip-option [value]="faculty.id" color="accent">
{{ faculty.name }} {{ faculty.name }}
</mat-chip-option> </mat-chip-option>
} @empty { } @empty {
<app-loading-indicator [loading]="facultiesLoaded !== null" (retryFunction)="facultiesLoadRetry.emit()"/> <app-loading-indicator [loading]="facultiesLoaded !== null"
(retryFunction)="loadFaculties()"/>
} }
</mat-chip-listbox> </mat-chip-listbox>
</mat-expansion-panel> </mat-expansion-panel>
@ -22,14 +23,14 @@
Курс Курс
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<mat-chip-listbox hideSingleSelectionIndicator (change)="chooseCourseNumber($event)" [formControl]="chipCourse"> <mat-chip-listbox hideSingleSelectionIndicator (change)="chooseCourseNumber($event)" [formControl]="formChipCourse">
@for (course of courseNumbers | async; track $index) { @for (course of courseNumbers; track $index) {
<mat-chip-option [value]="course" color="accent"> <mat-chip-option [value]="course" color="accent">
{{ course }} {{ course }}
</mat-chip-option> </mat-chip-option>
} @empty { } @empty {
<app-loading-indicator [loading]="groupsLoaded !== null" <app-loading-indicator [loading]="groupsLoaded !== null"
(retryFunction)="groupsLoadRetry.emit(this.facultyId!)"/> (retryFunction)="loadCourseGroup()"/>
} }
</mat-chip-listbox> </mat-chip-listbox>
</mat-expansion-panel> </mat-expansion-panel>
@ -40,14 +41,14 @@
Группа Группа
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<mat-chip-listbox hideSingleSelectionIndicator (change)="chooseGroup($event)" [formControl]="chipGroup"> <mat-chip-listbox hideSingleSelectionIndicator (change)="chooseGroup($event)" [formControl]="formChipGroup">
@for (group of filteredGroups | async; track $index) { @for (group of filteredGroups; track $index) {
<mat-chip-option [value]="group.id" color="accent"> <mat-chip-option [value]="group.id" color="accent">
{{ group.name }} {{ group.name }}
</mat-chip-option> </mat-chip-option>
} @empty { } @empty {
<app-loading-indicator [loading]="groupsLoaded !== null" <app-loading-indicator [loading]="groupsLoaded !== null"
(retryFunction)="groupsLoadRetry.emit(this.facultyId!)"/> (retryFunction)="loadCourseGroup()"/>
} }
</mat-chip-listbox> </mat-chip-listbox>
</mat-expansion-panel> </mat-expansion-panel>

View File

@ -1,12 +1,13 @@
import {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core'; import {Component, EventEmitter, Output, ViewChild} from '@angular/core';
import {MatExpansionModule, MatExpansionPanel} from "@angular/material/expansion"; import {MatExpansionModule, MatExpansionPanel} from "@angular/material/expansion";
import {MatChipListboxChange, MatChipsModule} from '@angular/material/chips'; import {MatChipListboxChange, MatChipsModule} from '@angular/material/chips';
import {FormControl, ReactiveFormsModule} from "@angular/forms"; import {FormControl, FormsModule, ReactiveFormsModule} from "@angular/forms";
import {AsyncPipe} from "@angular/common"; import {catchError} from "rxjs";
import {map, Observable, of} from "rxjs";
import {LoadingIndicatorComponent} from "@component/common/loading-indicator/loading-indicator.component"; import {LoadingIndicatorComponent} from "@component/common/loading-indicator/loading-indicator.component";
import {GroupResponse} from "@api/v1/groupResponse"; import {GroupResponse} from "@api/v1/groupResponse";
import {FacultyResponse} from "@api/v1/facultyResponse"; import {FacultyResponse} from "@api/v1/facultyResponse";
import {FacultyService} from "@api/v1/faculty.service";
import {GroupService} from "@api/v1/group.service";
@Component({ @Component({
selector: 'app-group', selector: 'app-group',
@ -16,49 +17,98 @@ import {FacultyResponse} from "@api/v1/facultyResponse";
MatChipsModule, MatChipsModule,
ReactiveFormsModule, ReactiveFormsModule,
LoadingIndicatorComponent, LoadingIndicatorComponent,
AsyncPipe FormsModule
], ],
templateUrl: './group.component.html', templateUrl: './group.component.html',
styleUrl: './group.component.css' styleUrl: './group.component.css',
providers: [FacultyService, GroupService]
}) })
export class GroupComponent { export class GroupComponent {
protected facultyId: number | null = null; protected facultyId: number | null = null;
protected courseNumber: number | null = null; protected courseNumber: number | null = null;
protected filteredGroups: Observable<GroupResponse[]> = of([]); protected filteredGroups: GroupResponse[] = [];
protected courseNumbers: Observable<number[]> = of([]); protected courseNumbers: number[] = [];
protected groups: Observable<GroupResponse[]> = of([]); private groups: GroupResponse[] = [];
protected chipCourse: FormControl = new FormControl(); protected formChipCourse: FormControl = new FormControl();
protected chipGroup: FormControl = new FormControl(); protected formChipGroup: FormControl = new FormControl();
protected faculties: FacultyResponse[] = [];
@ViewChild('courseNumberPanel') courseNumberPanel!: MatExpansionPanel; @ViewChild('courseNumberPanel') courseNumberPanel!: MatExpansionPanel;
@ViewChild('groupPanel') groupPanel!: MatExpansionPanel; @ViewChild('groupPanel') groupPanel!: MatExpansionPanel;
@Input() faculties: Observable<FacultyResponse[]> = of([]); protected facultiesLoaded: boolean | null = false;
@Input() facultiesLoaded: boolean | null = false; protected groupsLoaded: boolean | null = false;
@Output() facultiesLoadRetry: EventEmitter<void> = new EventEmitter<void>();
@Input() groupsLoaded: boolean | null = false;
@Output() groupsLoadRetry: EventEmitter<number> = new EventEmitter<number>();
@Input() set setGroups(data: Observable<GroupResponse[]>) { @Output() eventResult = new EventEmitter<number>();
this.groups = data;
this.courseNumbers = this.groups.pipe( constructor(private facultyApi: FacultyService, private groupApi: GroupService) {
map(data => data.map(g => g.courseNumber)), this.loadFaculties();
map(courseNumbersArray => courseNumbersArray.filter((value, index, self) => self.indexOf(value) === index)),
map(uniqueCourseNumbers => uniqueCourseNumbers.sort((a, b) => a - b))
);
} }
@Output() groupSelected = new EventEmitter<number>(); protected loadFaculties() {
@Output() facultySelected = new EventEmitter<number>(); this.facultiesLoaded = false;
this.facultyApi.getFaculties()
.pipe(catchError(error => {
this.facultiesLoaded = null;
throw error;
}))
.subscribe(data => {
this.faculties = data;
this.facultiesLoaded = true;
});
}
private filteringCourseNumber() {
this.courseNumbers = Array.from(
new Set(
this.groups
.filter(x => x.facultyId === this.facultyId)
.map(x => x.courseNumber)
)
).sort((a, b) => a - b);
}
private filteringGroup() {
this.filteredGroups = this.groups.filter(x => x.facultyId === this.facultyId && x.courseNumber === this.courseNumber);
}
protected loadCourseGroup() {
if (this.groups.length === 0) {
this.groupsLoaded = false;
this.groupApi.getGroups().pipe(
catchError(error => {
this.groupsLoaded = null;
throw error;
})
).subscribe(data => {
this.groups = data;
if (this.courseNumber === null)
this.filteringCourseNumber();
else
this.filteringGroup();
this.groupsLoaded = true;
});
return
}
if (this.courseNumber === null)
this.filteringCourseNumber();
else
this.filteringGroup();
}
protected chooseFaculty(event: MatChipListboxChange) { protected chooseFaculty(event: MatChipListboxChange) {
this.courseNumber = null; this.courseNumber = null;
this.groups = of([]); this.groups = [];
this.chipGroup.reset(); this.formChipGroup.reset();
this.chipCourse.reset(); this.formChipCourse.reset();
if (event.value === undefined || event.value === null) { if (event.value === undefined || event.value === null) {
this.facultyId = null; this.facultyId = null;
@ -67,12 +117,12 @@ export class GroupComponent {
this.facultyId = event.value; this.facultyId = event.value;
this.courseNumberPanel.open(); this.courseNumberPanel.open();
this.facultySelected.emit(this.facultyId!); this.loadCourseGroup();
} }
protected chooseCourseNumber(event: MatChipListboxChange) { protected chooseCourseNumber(event: MatChipListboxChange) {
this.filteredGroups = of([]); this.filteredGroups = [];
this.chipGroup.reset(); this.formChipGroup.reset();
if (event.value === undefined || event.value === null) { if (event.value === undefined || event.value === null) {
this.courseNumber = null; this.courseNumber = null;
@ -81,8 +131,7 @@ export class GroupComponent {
this.courseNumber = event.value; this.courseNumber = event.value;
this.groupPanel.open(); this.groupPanel.open();
this.groups.subscribe(data => this.loadCourseGroup();
this.filteredGroups = of(data.filter(g => g.courseNumber === this.courseNumber)));
} }
protected chooseGroup(event: MatChipListboxChange) { protected chooseGroup(event: MatChipListboxChange) {
@ -90,6 +139,6 @@ export class GroupComponent {
return; return;
this.groupPanel.close(); this.groupPanel.close();
this.groupSelected.emit(event.value); this.eventResult.emit(event.value);
} }
} }

View File

@ -6,12 +6,12 @@
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<mat-chip-listbox hideSingleSelectionIndicator (change)="chooseCampus($event)"> <mat-chip-listbox hideSingleSelectionIndicator (change)="chooseCampus($event)">
@for (campus of campuses | async; track $index) { @for (campus of campuses; track $index) {
<mat-chip-option [value]="campus.id" color="accent"> <mat-chip-option [value]="campus.id" color="accent">
{{ campus.codeName }} {{ campus.codeName }}
</mat-chip-option> </mat-chip-option>
} @empty { } @empty {
<app-loading-indicator [loading]="campusesLoaded !== null" (retryFunction)="campusesLoadRetry.emit()"/> <app-loading-indicator [loading]="campusesLoaded !== null" (retryFunction)="loadCampuses()"/>
} }
</mat-chip-listbox> </mat-chip-listbox>
</mat-expansion-panel> </mat-expansion-panel>
@ -23,12 +23,12 @@
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<mat-chip-listbox hideSingleSelectionIndicator (change)="chooseLectureHall($event)" [formControl]="chipLecture"> <mat-chip-listbox hideSingleSelectionIndicator (change)="chooseLectureHall($event)" [formControl]="chipLecture">
@for (lectureHall of lectureHalls | async; track $index) { @for (lectureHall of lectureHallsFiltered; track $index) {
<mat-chip-option [value]="lectureHall.id" color="accent"> <mat-chip-option [value]="lectureHall.id" color="accent">
{{ lectureHall.name }} {{ lectureHall.name }}
</mat-chip-option> </mat-chip-option>
} @empty { } @empty {
<app-loading-indicator [loading]="lectureHallsLoaded !== null" (retryFunction)="lectureHallsLoadRetry.emit()"/> <app-loading-indicator [loading]="lectureHallsLoaded !== null" (retryFunction)="loadLectureHalls()"/>
} }
</mat-chip-listbox> </mat-chip-listbox>
</mat-expansion-panel> </mat-expansion-panel>

View File

@ -2,11 +2,13 @@ import {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core';
import {AsyncPipe} from "@angular/common"; import {AsyncPipe} from "@angular/common";
import {MatAccordion, MatExpansionModule, MatExpansionPanel} from "@angular/material/expansion"; import {MatAccordion, MatExpansionModule, MatExpansionPanel} from "@angular/material/expansion";
import {MatChipListboxChange, MatChipsModule} from "@angular/material/chips"; import {MatChipListboxChange, MatChipsModule} from "@angular/material/chips";
import {Observable, of} from "rxjs"; import {catchError, Observable, of} from "rxjs";
import {FormControl, ReactiveFormsModule} from "@angular/forms"; import {FormControl, ReactiveFormsModule} from "@angular/forms";
import {LoadingIndicatorComponent} from "@component/common/loading-indicator/loading-indicator.component"; import {LoadingIndicatorComponent} from "@component/common/loading-indicator/loading-indicator.component";
import {CampusBasicInfoResponse} from "@api/v1/campusBasicInfoResponse"; import {CampusBasicInfoResponse} from "@api/v1/campusBasicInfoResponse";
import {LectureHallResponse} from "@api/v1/lectureHallResponse"; import {LectureHallResponse} from "@api/v1/lectureHallResponse";
import {CampusService} from "@api/v1/campus.service";
import {LectureHallService} from "@api/v1/lectureHall.service";
@Component({ @Component({
selector: 'app-lecture-hall', selector: 'app-lecture-hall',
@ -20,7 +22,8 @@ import {LectureHallResponse} from "@api/v1/lectureHallResponse";
LoadingIndicatorComponent LoadingIndicatorComponent
], ],
templateUrl: './lecture-hall.component.html', templateUrl: './lecture-hall.component.html',
styleUrl: './lecture-hall.component.css' styleUrl: './lecture-hall.component.css',
providers: [CampusService, LectureHallService]
}) })
export class LectureHallComponent { export class LectureHallComponent {
@ -29,29 +32,66 @@ export class LectureHallComponent {
@ViewChild('lecturePanel') lecturePanel!: MatExpansionPanel; @ViewChild('lecturePanel') lecturePanel!: MatExpansionPanel;
@Input() campuses: Observable<CampusBasicInfoResponse[]> = of([]); protected campuses: CampusBasicInfoResponse[] = [];
@Input() campusesLoaded: boolean | null = false; protected campusesLoaded: boolean | null = false;
@Output() campusesLoadRetry: EventEmitter<void> = new EventEmitter<void>();
@Input() lectureHalls: Observable<LectureHallResponse[]> = of([]);
@Input() lectureHallsLoaded: boolean | null = false;
@Output() lectureHallsLoadRetry: EventEmitter<number> = new EventEmitter<number>();
@Output() campusSelected = new EventEmitter<number>(); private lectureHalls: LectureHallResponse[] = [];
@Output() lectureHallSelected = new EventEmitter<number>(); protected lectureHallsFiltered: LectureHallResponse[] = [];
protected lectureHallsLoaded: boolean | null = false;
@Output() eventResult = new EventEmitter<number>();
constructor(private campusApi: CampusService, private lectureHallApi: LectureHallService) {
this.loadCampuses();
}
protected loadCampuses() {
this.campusesLoaded = false;
this.campusApi.getCampus()
.pipe(catchError(error => {
this.campusesLoaded = null;
throw error;
}))
.subscribe(data => {
this.campuses = data;
this.campusesLoaded = true;
});
}
private filteringLectureHalls() {
this.lectureHallsFiltered = this.lectureHalls.filter(x => x.campusId === this.campusId);
}
protected chooseCampus(event: MatChipListboxChange) { protected chooseCampus(event: MatChipListboxChange) {
this.chipLecture.reset(); this.chipLecture.reset();
if (event.value === undefined || event.value === null) { if (event.value === undefined || event.value === null) {
this.campusId = null; this.campusId = null;
this.lectureHalls = of([]); this.lectureHalls = [];
return; return;
} }
this.campusId = event.value; this.campusId = event.value;
this.lecturePanel.open(); this.lecturePanel.open();
this.campusSelected.emit(this.campusId!); if (this.lectureHalls.length === 0)
this.loadLectureHalls();
else
this.filteringLectureHalls();
}
protected loadLectureHalls() {
this.lectureHallsLoaded = false;
this.lectureHallApi.getLectureHalls()
.pipe(catchError(error => {
this.lectureHallsLoaded = null;
throw error;
}))
.subscribe(data => {
this.lectureHalls = data;
this.filteringLectureHalls();
this.lectureHallsLoaded = true;
});
} }
protected chooseLectureHall(event: MatChipListboxChange) { protected chooseLectureHall(event: MatChipListboxChange) {
@ -59,6 +99,6 @@ export class LectureHallComponent {
return; return;
this.lecturePanel.close(); this.lecturePanel.close();
this.lectureHallSelected.emit(event.value); this.eventResult.emit(event.value);
} }
} }

View File

@ -1,6 +1,6 @@
<div class="search-content"> <div class="search-content">
@if (professors.length === 0) { @if (professors.length === 0) {
<app-loading-indicator [loading]="professorsLoaded !== null" (retryFunction)="professorsLoadRetry.emit()"/> <app-loading-indicator [loading]="professorsLoaded !== null" (retryFunction)="loadProfessors()"/>
} @else { } @else {
<mat-form-field color="accent" style="width: 100%;"> <mat-form-field color="accent" style="width: 100%;">
<input type="text" placeholder="Поиск..." matInput [formControl]="professorControl" [matAutocomplete]="auto"> <input type="text" placeholder="Поиск..." matInput [formControl]="professorControl" [matAutocomplete]="auto">

View File

@ -3,9 +3,10 @@ import {MatFormField, MatInput} from "@angular/material/input";
import {FormControl, ReactiveFormsModule} from "@angular/forms"; import {FormControl, ReactiveFormsModule} from "@angular/forms";
import {MatAutocompleteModule, MatAutocompleteSelectedEvent} from "@angular/material/autocomplete"; import {MatAutocompleteModule, MatAutocompleteSelectedEvent} from "@angular/material/autocomplete";
import {AsyncPipe} from "@angular/common"; import {AsyncPipe} from "@angular/common";
import {map, Observable, startWith} from "rxjs"; import {catchError, map, Observable, startWith} from "rxjs";
import {LoadingIndicatorComponent} from "@component/common/loading-indicator/loading-indicator.component"; import {LoadingIndicatorComponent} from "@component/common/loading-indicator/loading-indicator.component";
import {ProfessorResponse} from "@api/v1/professorResponse"; import {ProfessorResponse} from "@api/v1/professorResponse";
import {ProfessorService} from "@api/v1/professor.service";
@Component({ @Component({
selector: 'app-professor', selector: 'app-professor',
@ -19,17 +20,37 @@ import {ProfessorResponse} from "@api/v1/professorResponse";
LoadingIndicatorComponent LoadingIndicatorComponent
], ],
templateUrl: './professor.component.html', templateUrl: './professor.component.html',
styleUrl: './professor.component.css' styleUrl: './professor.component.css',
providers: [ProfessorService]
}) })
export class ProfessorComponent implements OnInit { export class ProfessorComponent implements OnInit {
protected professorControl = new FormControl(); protected professorControl = new FormControl();
protected filteredProfessors!: Observable<ProfessorResponse[]>; protected filteredProfessors!: Observable<ProfessorResponse[]>;
@Input() professors: ProfessorResponse[] = []; protected professors: ProfessorResponse[] = [];
@Output() professorSelected = new EventEmitter<number>(); protected professorsLoaded: boolean | null = false;
@Input() professorsLoaded: boolean | null = false; @Output() eventResult = new EventEmitter<number>();
@Output() professorsLoadRetry: EventEmitter<void> = new EventEmitter<void>();
constructor(private api: ProfessorService) {
this.loadProfessors();
}
protected loadProfessors() {
if (this.professors.length === 0) {
this.professorsLoaded = false;
this.api.getProfessors()
.pipe(catchError(error => {
this.professorsLoaded = null;
throw error;
}))
.subscribe(data => {
this.professors = data;
this.professorsLoaded = true;
});
}
}
ngOnInit(): void { ngOnInit(): void {
this.filteredProfessors = this.professorControl.valueChanges.pipe( this.filteredProfessors = this.professorControl.valueChanges.pipe(
@ -53,7 +74,7 @@ export class ProfessorComponent implements OnInit {
const selectedOption = this.professors.find(teacher => teacher.id === event.option.value); const selectedOption = this.professors.find(teacher => teacher.id === event.option.value);
if (selectedOption) { if (selectedOption) {
this.professorControl.setValue(selectedOption.name); this.professorControl.setValue(selectedOption.name);
this.professorSelected.emit(selectedOption.id); this.eventResult.emit(selectedOption.id);
} }
} }
} }

View File

@ -2,35 +2,34 @@
(selectedTabChange)="chooseTabs($event)"> (selectedTabChange)="chooseTabs($event)">
<mat-tab label="Группа"> <mat-tab label="Группа">
<div> <div>
<app-group (groupSelected)="groupSelected.emit($event)" (facultySelected)="groupLoad($event)" <app-group (eventResult)="groupSelected($event)"/>
[setGroups]="groups" [faculties]="faculties" [facultiesLoaded]="facultiesLoaded"
[groupsLoaded]="groupLoaded" (groupsLoadRetry)="groupLoad($event)"
(facultiesLoadRetry)="facultyLoad()"/>
</div> </div>
</mat-tab> </mat-tab>
<mat-tab label="Преподаватель"> <mat-tab label="Преподаватель">
<div> <div>
<app-professor (professorSelected)="professorSelected.emit($event)" [professors]="professorsData" [professorsLoaded]="professorsLoaded" (professorsLoadRetry)="professorsLoad()"/> <app-professor (eventResult)="professorSelected($event)"/>
</div> </div>
</mat-tab> </mat-tab>
<mat-tab label="Кабинет"> <mat-tab label="Кабинет">
<div> <div>
<app-lecture-hall (lectureHallSelected)="lectureHallSelected.emit($event)" [campuses]="campuses" <app-lecture-hall (eventResult)="lectureHallSelected($event)"/>
(campusSelected)="lectureHallLoad($event)" [lectureHalls]="lectureHalls"
[campusesLoaded]="campusesLoaded" [lectureHallsLoaded]="lectureHallsLoaded"
(campusesLoadRetry)="campusLoad()"
(lectureHallsLoadRetry)="lectureHallLoad($event)"/>
</div> </div>
</mat-tab> </mat-tab>
<!--
<mat-tab label="Другое"> <mat-tab label="Другое">
<div class="margin-other-button"> <div class="margin-other-button">
<app-other idButton="disciplines-button" textButton="Дисциплины" #discipline [dataLoaded]="disciplinesLoaded" (retryLoadData)="loadDisciplines()"/> <app-other idButton="disciplines-button" textButton="Дисциплины" #discipline [dataLoaded]="disciplinesLoaded"
<app-other idButton="lecture-button" textButton="Кабинеты" #lecture [dataLoaded]="campusesLoaded && lectureHallsLoaded" (retryLoadData)="loadLectureHalls()"/> (retryLoadData)="loadDisciplines()"/>
<app-other idButton="group-button" textButton="Группы" #group [dataLoaded]="facultiesLoaded && groupLoaded" (retryLoadData)="loadGroups()"/> <app-other idButton="lecture-button" textButton="Кабинеты" #lecture
<app-other idButton="professor-button" textButton="Профессоры" #professor [dataLoaded]="professorsLoaded" (retryLoadData)="professorsLoad()"/> [dataLoaded]="campusesLoaded && lectureHallsLoaded" (retryLoadData)="loadLectureHalls()"/>
<app-other idButton="group-button" textButton="Группы" #group [dataLoaded]="facultiesLoaded && groupLoaded"
(retryLoadData)="loadGroups()"/>
<app-other idButton="professor-button" textButton="Профессоры" #professor [dataLoaded]="professorsLoaded"
(retryLoadData)="professorsLoad()"/>
<section> <section>
<button mat-flat-button (click)="onClickNagmi()">Отфильтровать</button> <button mat-flat-button>Отфильтровать</button>
</section> </section>
</div> </div>
</mat-tab> </mat-tab>
-->
</mat-tab-group> </mat-tab-group>

View File

@ -1,38 +1,31 @@
import {Component, EventEmitter, Output, ViewChild} from '@angular/core'; import {Component, EventEmitter, Output} from '@angular/core';
import {HttpClientModule} from "@angular/common/http";
import {OtherComponent} from "@component/schedule/tabs/other/other.component"; import {OtherComponent} from "@component/schedule/tabs/other/other.component";
import {MatTab, MatTabChangeEvent, MatTabGroup} from "@angular/material/tabs"; import {MatTab, MatTabChangeEvent, MatTabGroup} from "@angular/material/tabs";
import {catchError, map, Observable, of, switchMap, tap} from "rxjs"; import {map, Observable} from "rxjs";
import {ReactiveFormsModule} from "@angular/forms"; import {ReactiveFormsModule} from "@angular/forms";
import {AsyncPipe, NgIf} from "@angular/common";
import {MatButton} from "@angular/material/button"; import {MatButton} from "@angular/material/button";
import {DataSpinnerComponent} from "@component/common/data-spinner/data-spinner.component"; import {DataSpinnerComponent} from "@component/common/data-spinner/data-spinner.component";
import {ProfessorResponse} from "@api/v1/professorResponse";
import {FacultyResponse} from "@api/v1/facultyResponse";
import {GroupResponse} from "@api/v1/groupResponse";
import {CampusBasicInfoResponse} from "@api/v1/campusBasicInfoResponse";
import {LectureHallResponse} from "@api/v1/lectureHallResponse";
import {DisciplineService} from "@api/v1/discipline.service";
import {GroupComponent} from "@component/schedule/tabs/group/group.component"; import {GroupComponent} from "@component/schedule/tabs/group/group.component";
import {ProfessorComponent} from "@component/schedule/tabs/professor/professor.component"; import {ProfessorComponent} from "@component/schedule/tabs/professor/professor.component";
import {LectureHallComponent} from "@component/schedule/tabs/lecture-hall/lecture-hall.component"; import {LectureHallComponent} from "@component/schedule/tabs/lecture-hall/lecture-hall.component";
import {FacultyService} from "@api/v1/faculty.service"; import {ScheduleService} from "@api/v1/schedule.service";
import {GroupService} from "@api/v1/group.service"; import {ScheduleResponse} from "@api/v1/scheduleResponse";
import {ProfessorService} from "@api/v1/professor.service";
import {CampusService} from "@api/v1/campus.service"; export enum TabsSelect {
import {LectureHallService} from "@api/v1/lectureHall.service"; Group,
Professor,
LectureHall,
Other
}
@Component({ @Component({
selector: 'app-tabs', selector: 'app-tabs',
standalone: true, standalone: true,
imports: [ imports: [
HttpClientModule,
OtherComponent, OtherComponent,
MatTabGroup, MatTabGroup,
MatTab, MatTab,
ReactiveFormsModule, ReactiveFormsModule,
AsyncPipe,
NgIf,
MatButton, MatButton,
DataSpinnerComponent, DataSpinnerComponent,
GroupComponent, GroupComponent,
@ -41,236 +34,126 @@ import {LectureHallService} from "@api/v1/lectureHall.service";
], ],
templateUrl: './tabs.component.html', templateUrl: './tabs.component.html',
styleUrl: './tabs.component.css', styleUrl: './tabs.component.css',
providers: [FacultyService, GroupService, ProfessorService, CampusService, LectureHallService, DisciplineService ] providers: [ScheduleService]
}) })
export class TabsComponent { export class TabsComponent {
protected professorsData: ProfessorResponse[] = []; @Output() eventResult = new EventEmitter<[TabsSelect, number, Observable<ScheduleResponse[]>]>();
protected faculties: Observable<FacultyResponse[]> = of([]); constructor(private scheduleApi: ScheduleService) {
protected groups: Observable<GroupResponse[]> = of([]); }
private groupsData: Observable<GroupResponse[]> = of([]);
protected campuses: Observable<CampusBasicInfoResponse[]> = of([]); protected groupSelected(id: number) {
protected lectureHalls: Observable<LectureHallResponse[]> = of([]); this.eventResult.emit(
private lectureHallsData: Observable<LectureHallResponse[]> = of([]); [
TabsSelect.Group,
id,
this.scheduleApi.getByGroup(id)
.pipe(
map(g =>
g.map(data =>
({
dayOfWeek: data.dayOfWeek,
pairNumber: data.pairNumber,
isEven: data.isEven,
discipline: data.discipline,
disciplineId: data.disciplineId,
isExcludedWeeks: data.isExcludedWeeks,
weeks: data.weeks,
typeOfOccupations: data.typeOfOccupations,
group: data.group,
groupId: data.groupId,
lectureHalls: data.lectureHalls,
lectureHallsId: data.lectureHallsId,
professors: data.professors,
professorsId: data.professorsId,
campus: data.campus,
campusId: data.campusId,
linkToMeet: data.linkToMeet
}))
)
)
]
);
}
// States protected professorSelected(id: number) {
protected facultiesLoaded: boolean | null = false; this.eventResult.emit(
protected groupLoaded: boolean | null = false; [
protected campusesLoaded: boolean | null = false; TabsSelect.Professor,
protected lectureHallsLoaded: boolean | null = false; id,
protected disciplinesLoaded: boolean | null = false; this.scheduleApi.getByProfessor(id)
protected professorsLoaded: boolean | null = false; .pipe(
map(p =>
p.map(data =>
({
dayOfWeek: data.dayOfWeek,
pairNumber: data.pairNumber,
isEven: data.isEven,
discipline: data.discipline,
disciplineId: data.disciplineId,
isExcludedWeeks: data.isExcludedWeeks,
weeks: data.weeks,
typeOfOccupations: data.typeOfOccupations,
group: data.group,
groupId: data.groupId,
lectureHalls: data.lectureHalls,
lectureHallsId: data.lectureHallsId,
professors: data.professors,
professorsId: data.professorsId,
campus: data.campus,
campusId: data.campusId,
linkToMeet: data.linkToMeet
}))
)
)
]
);
}
@Output() groupSelected: EventEmitter<number> = new EventEmitter<number>(); protected lectureHallSelected(id: number) {
@Output() lectureHallSelected: EventEmitter<number> = new EventEmitter<number>(); this.eventResult.emit(
@Output() professorSelected: EventEmitter<number> = new EventEmitter<number>(); [
TabsSelect.LectureHall,
constructor( id,
private facultyApi: FacultyService, this.scheduleApi.getByLectureHall(id)
private groupApi: GroupService, .pipe(
private professorApi: ProfessorService, map(lh =>
private campusApi: CampusService, lh.map(data =>
private lectureHallApi: LectureHallService, ({
private disciplineApi: DisciplineService) { dayOfWeek: data.dayOfWeek,
this.facultyLoad().then(); pairNumber: data.pairNumber,
isEven: data.isEven,
discipline: data.discipline,
disciplineId: data.disciplineId,
isExcludedWeeks: data.isExcludedWeeks,
weeks: data.weeks,
typeOfOccupations: data.typeOfOccupations,
group: data.group,
groupId: data.groupId,
lectureHalls: data.lectureHalls,
lectureHallsId: data.lectureHallsId,
professors: data.professors,
professorsId: data.professorsId,
campus: data.campus,
campusId: data.campusId,
linkToMeet: data.linkToMeet
}))
)
)
]
);
} }
protected async chooseTabs(event: MatTabChangeEvent) { protected async chooseTabs(event: MatTabChangeEvent) {
switch (event.index) { switch (event.index) {
case 0:
await this.facultyLoad();
break;
case 1:
this.professorsLoad();
break;
case 2:
await this.campusLoad();
break;
case 3:
await this.extensionLoad();
break;
} }
} }
protected async facultyLoad() { /*
if (this.facultiesLoaded === null) this.facultiesLoaded = false;
if (this.facultiesLoaded) return;
this.faculties = this.facultyApi.getFaculties().pipe(
tap(() => {
this.facultiesLoaded = true;
}),
catchError((error) => {
this.facultiesLoaded = null;
throw error;
})
);
}
protected groupLoad(id: number) {
if (this.groupLoaded === null) this.groupLoaded = false;
if (this.groupLoaded)
this.groups = this.groupsData.pipe(map(data => data.filter(x => x.facultyId === id)));
else
this.groups = this.groupApi.getByFaculty(id).pipe(
tap(() => {
this.groupLoaded = false;
}),
catchError((error) => {
this.groupLoaded = null;
throw error;
})
);
}
protected professorsLoad() {
if (this.professorsLoaded === null) this.professorsLoaded = false;
if (this.professorsLoaded) return;
this.professorApi.getProfessors().pipe(
catchError((error) => {
this.professorsLoaded = null;
throw error;
})
).subscribe(data => {
this.professorsData = data;
this.professorEx.Data = data.map(x =>
({
id: x.id,
name: x.altName ? x.altName : x.name,
selected: false
}));
});
}
protected async campusLoad() {
if (this.campusesLoaded === null) this.campusesLoaded = false;
if (this.campusesLoaded) return;
this.campuses = this.campusApi.getCampus().pipe(
tap(() => {
this.campusesLoaded = true;
}),
catchError((error) => {
this.campusesLoaded = null;
throw error;
})
);
}
protected lectureHallLoad(id: number) {
if (this.lectureHallsLoaded === null) this.lectureHallsLoaded = false;
if (this.lectureHallsLoaded)
this.lectureHalls = this.lectureHallsData.pipe(map(data => data.filter(x => x.campusId === id)));
else
this.lectureHalls = this.lectureHallApi.getByCampus(id).pipe(
tap(() => {
this.lectureHallsLoaded = false;
}),
catchError((error) => {
this.lectureHallsLoaded = null;
throw error;
})
);
}
protected async loadLectureHalls() {
if (!this.campusesLoaded)
await this.campusLoad();
if (!this.lectureHallsLoaded) {
this.lectureHallsData = this.lectureHallApi.getLectureHalls();
this.lectureHallsData.pipe(
switchMap(lectureHalls => this.campuses.pipe(
map(campuses => {
return lectureHalls.map(x => {
const campus = campuses.find(c => c.id === x.campusId);
const codeName = campus ? campus.codeName : '';
return {
id: x.id,
name: `${x.name} (${codeName})`,
selected: false
};
});
})
)),
).subscribe(data => {
this.lectureHallEx.Data = data;
this.lectureHallsLoaded = true;
this.campusesLoaded = true;
});
}
}
protected async loadDisciplines() {
if (!this.disciplinesLoaded) {
this.disciplineApi.getDisciplines().pipe(
catchError((error) => {
this.disciplinesLoaded = null;
throw error;
})).subscribe(data => {
this.disciplineEx.Data = data.map(x =>
({
id: x.id,
name: x.name,
selected: false
}));
this.disciplinesLoaded = true;
});
}
}
protected async loadGroups() {
if (!this.facultiesLoaded)
await this.facultyLoad();
if (!this.groupLoaded) {
this.groupsData = this.groupApi.getGroups();
this.groupsData.pipe(
switchMap(groups => this.faculties.pipe(
map(campuses => {
return groups.map(x => {
const faculties = campuses.find(c => c.id === x.facultyId);
const name = faculties ? faculties.name : '';
return {
id: x.id,
name: `${x.name} (${name})`,
selected: false
};
});
})
))
).subscribe(data => {
this.groupEx.Data = data;
this.groupLoaded = true;
});
}
}
protected async extensionLoad() {
// Lecture Hall
await this.loadLectureHalls();
// Disciplines
await this.loadDisciplines();
// Groups
await this.loadGroups();
// Professors
if (this.professorsData.length === 0)
this.professorsLoad();
}
@ViewChild('discipline') disciplineEx!: OtherComponent; @ViewChild('discipline') disciplineEx!: OtherComponent;
@ViewChild('lecture') lectureHallEx!: OtherComponent; @ViewChild('lecture') lectureHallEx!: OtherComponent;
@ViewChild('group') groupEx!: OtherComponent; @ViewChild('group') groupEx!: OtherComponent;
@ViewChild('professor') professorEx!: OtherComponent; @ViewChild('professor') professorEx!: OtherComponent;
*/
} }

View File

@ -0,0 +1,16 @@
.schedule {
padding: 50px 15%;
min-height: 60vh;
}
@media screen and (max-width: 599px) {
.schedule {
padding: 25px;
}
}
@media screen and (min-width: 600px) and (max-width: 959px) {
.schedule {
padding: 30px 10%;
}
}

View File

@ -0,0 +1,5 @@
<mat-sidenav-container class="schedule">
<app-tabs (eventResult)="result($event)"/>
<app-table-header [startWeek]="startWeek" [currentWeek]="currentWeek" (weekEvent)="handleWeekEvent($event)" #tableHeader/>
<app-table [currentWeek]="currentWeek" [startWeek]="startWeek" [data]="data" [isLoad]="isLoadTable"/>
</mat-sidenav-container>

View File

@ -0,0 +1,115 @@
import {Component, LOCALE_ID, ViewChild} from '@angular/core';
import {TableComponent} from "@component/schedule/table/table.component";
import {MatFormField, MatInput} from "@angular/material/input";
import {MatButton} from "@angular/material/button";
import {FormsModule} from "@angular/forms";
import {AdditionalText, TableHeaderComponent} from "@component/schedule/table-header/table-header.component";
import {addDays, weekInYear} from "@progress/kendo-date-math";
import {MatCard} from "@angular/material/card";
import {MatSidenavContainer} from "@angular/material/sidenav";
import {TabsComponent, TabsSelect} from "@component/schedule/tabs/tabs.component";
import {catchError, Observable} from "rxjs";
import {ScheduleService} from "@api/v1/schedule.service";
import {ScheduleResponse} from "@api/v1/scheduleResponse";
import {PeriodTimes} from "@model/pairPeriodTime";
@Component({
selector: 'app-schedule',
standalone: true,
imports: [
TableComponent,
MatInput,
MatFormField,
MatButton,
FormsModule,
TableHeaderComponent,
MatCard,
MatSidenavContainer,
TabsComponent
],
templateUrl: './schedule.component.html',
styleUrl: './schedule.component.css',
providers: [
ScheduleService,
{provide: LOCALE_ID, useValue: 'ru-RU'}
]
})
export class ScheduleComponent {
protected startWeek!: Date;
protected data: ScheduleResponse[] = [];
protected startTerm: Date;
protected isLoadTable: boolean = false;
protected pairPeriods: PeriodTimes = {};
@ViewChild('tableHeader') childComponent!: TableHeaderComponent;
constructor(private api: ScheduleService) {
this.calculateCurrentWeek();
this.startTerm = new Date(1, 1, 1);
api.pairPeriod().subscribe(date => {
this.pairPeriods = date;
});
api.startTerm().subscribe(date => {
this.startTerm = date.date;
});
}
protected result(data: [TabsSelect, number, Observable<ScheduleResponse[]>]) {
this.isLoadTable = true;
data[2]
.pipe(catchError(error => {
this.data = [];
throw error;
}))
.subscribe(x => {
this.data = x;
switch (data[0]) {
case TabsSelect.Group:
this.childComponent.AdditionalText(AdditionalText.Group, this.data[0].group);
break;
case TabsSelect.Professor:
let indexProfessor = this.data[0].professorsId.findIndex(p => p === data[1]);
console.log(indexProfessor);
console.log(data[1]);
this.childComponent.AdditionalText(AdditionalText.Professor, this.data[0].professors[indexProfessor]);
break;
case TabsSelect.LectureHall:
this.childComponent.AdditionalText(AdditionalText.LectureHall, `${this.data[0].lectureHalls[0]} (${this.data[0].campus[0]})`);
break;
case TabsSelect.Other:
this.childComponent.AdditionalText(AdditionalText.Other, '');
break;
}
this.isLoadTable = false;
});
}
private calculateCurrentWeek() {
let currentDate = new Date();
function startOfWeek(date: Date) {
return addDays(date, -date.getDay() + 1);
}
this.startWeek = currentDate.getDay() === 0 ? startOfWeek(addDays(currentDate, 1)) : startOfWeek(currentDate);
if (this.startWeek < this.startTerm)
this.startWeek = this.startTerm;
}
protected handleWeekEvent(eventData: boolean | null) {
if (eventData === null) {
this.calculateCurrentWeek();
} else if (eventData) {
this.startWeek = addDays(this.startWeek, 7);
} else {
this.startWeek = addDays(this.startWeek, -7);
}
}
get currentWeek(): number {
return (weekInYear(this.startWeek) - weekInYear(this.startTerm)) + 1;
}
}

View File

@ -1,67 +0,0 @@
/**
* MIREA Schedule Web API
* This API provides a convenient interface for retrieving data stored in the database. Special attention was paid to the lightweight and easy transfer of all necessary data. Made by the Winsomnia team.
*
* OpenAPI spec version: 1.0
* Contact: support@winsomnia.net
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { DayOfWeek } from '@model/dayOfWeek';
/**
* Represents information about a specific schedule entry for a professor.
*/
export interface DisciplineScheduleInfo {
dayOfWeek: DayOfWeek;
/**
* Gets or sets the pair number for the schedule entry.
*/
pairNumber: number;
/**
* Gets or sets a value indicating whether the pair is on an even week.
*/
isEven: boolean;
/**
* Gets or sets the type of occupation for the schedule entry.
*/
typeOfOccupation: Array<string>;
/**
* Gets or sets the names of the group for the schedule entry.
*/
group: string;
/**
* Gets or sets the IDs of the group for the schedule entry.
*/
groupId: number;
/**
* Gets or sets the names of the lecture halls for the schedule entry.
*/
lectureHalls: Array<string>;
/**
* Gets or sets the IDs of the lecture halls for the schedule entry.
*/
lectureHallsId: Array<number>;
/**
* Gets or sets the names of the professors for the schedule entry.
*/
professors: Array<string>;
/**
* Gets or sets the IDs of the professors for the schedule entry.
*/
professorsId: Array<number>;
/**
* Gets or sets the names of the campuses for the schedule entry.
*/
campus: Array<string>;
/**
* Gets or sets the IDs of the campuses for the schedule entry.
*/
campusId: Array<number>;
/**
* Gets or sets the links to online meetings for the schedule entry.
*/
linkToMeet: Array<string>;
}

View File

@ -1,30 +0,0 @@
/**
* MIREA Schedule Web API
* This API provides a convenient interface for retrieving data stored in the database. Special attention was paid to the lightweight and easy transfer of all necessary data. Made by the Winsomnia team.
*
* OpenAPI spec version: 1.0
* Contact: support@winsomnia.net
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { DisciplineScheduleInfo } from './disciplineScheduleInfo';
/**
* Represents a response containing schedule information for a professor.
*/
export interface DisciplineScheduleResponse {
/**
* Gets or sets the name of the discipline.
*/
discipline: string;
/**
* Gets or sets the ID of the discipline.
*/
disciplineId: number;
/**
* Gets or sets the schedules for the professor.
*/
schedules: Array<DisciplineScheduleInfo>;
}

View File

@ -1,75 +0,0 @@
/**
* MIREA Schedule Web API
* This API provides a convenient interface for retrieving data stored in the database. Special attention was paid to the lightweight and easy transfer of all necessary data. Made by the Winsomnia team.
*
* OpenAPI spec version: 1.0
* Contact: support@winsomnia.net
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { DayOfWeek } from '@/shared/structs/dayOfWeek';
/**
* Represents information about a specific schedule entry for a group.
*/
export interface GroupScheduleInfo {
dayOfWeek: DayOfWeek;
/**
* Gets or sets the pair number for the schedule entry.
*/
pairNumber: number;
/**
* Gets or sets a value indicating whether the pair is on an even week.
*/
isEven: boolean;
/**
* Gets or sets the name of the discipline for the schedule entry.
*/
discipline: string;
/**
* Gets or sets the ID of the discipline for the schedule entry.
*/
disciplineId: number;
/**
* Gets or sets exclude or include weeks for a specific discipline.
*/
isExcludedWeeks?: boolean;
/**
* The week numbers required for the correct display of the schedule. Whether there will be Mirea.Api.Dto.Responses.Schedule.GroupScheduleInfo.Discipline during the week or not depends on the Mirea.Api.Dto.Responses.Schedule.GroupScheduleInfo.IsExcludedWeeks property.
*/
weeks?: Array<number>;
/**
* Gets or sets the type of occupation for the schedule entry.
*/
typeOfOccupations: Array<string>;
/**
* Gets or sets the names of the lecture halls for the schedule entry.
*/
lectureHalls: Array<string>;
/**
* Gets or sets the IDs of the lecture halls for the schedule entry.
*/
lectureHallsId: Array<number>;
/**
* Gets or sets the names of the professors for the schedule entry.
*/
professors: Array<string>;
/**
* Gets or sets the IDs of the professors for the schedule entry.
*/
professorsId: Array<number>;
/**
* Gets or sets the names of the campuses for the schedule entry.
*/
campus: Array<string>;
/**
* Gets or sets the IDs of the campuses for the schedule entry.
*/
campusId: Array<number>;
/**
* Gets or sets the links to online meetings for the schedule entry.
*/
linkToMeet: Array<string>;
}

View File

@ -1,30 +0,0 @@
/**
* MIREA Schedule Web API
* This API provides a convenient interface for retrieving data stored in the database. Special attention was paid to the lightweight and easy transfer of all necessary data. Made by the Winsomnia team.
*
* OpenAPI spec version: 1.0
* Contact: support@winsomnia.net
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { GroupScheduleInfo } from './groupScheduleInfo';
/**
* Represents a response containing schedule information for a group.
*/
export interface GroupScheduleResponse {
/**
* Gets or sets the name of the group.
*/
group: string;
/**
* Gets or sets the ID of the group.
*/
groupId: number;
/**
* Gets or sets the schedules for the group.
*/
schedules: Array<GroupScheduleInfo>;
}

View File

@ -1,76 +0,0 @@
/**
* MIREA Schedule Web API
* This API provides a convenient interface for retrieving data stored in the database. Special attention was paid to the lightweight and easy transfer of all necessary data. Made by the Winsomnia team.
*
* OpenAPI spec version: 1.0
* Contact: support@winsomnia.net
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import {DayOfWeek} from "@model/dayOfWeek";
/**
* Represents information about a specific schedule entry for a lecture hall.
*/
export interface LectureHallScheduleInfo {
dayOfWeek: DayOfWeek;
/**
* Gets or sets the pair number for the schedule entry.
*/
pairNumber: number;
/**
* Gets or sets a value indicating whether the pair is on an even week.
*/
isEven: boolean;
/**
* Gets or sets the name of the discipline for the schedule entry.
*/
discipline: string;
/**
* Gets or sets the ID of the discipline for the schedule entry.
*/
disciplineId: number;
/**
* Gets or sets exclude or include weeks for a specific discipline.
*/
isExcludedWeeks?: boolean;
/**
* The week numbers required for the correct display of the schedule. Whether there will be Mirea.Api.Dto.Responses.Schedule.LectureHallScheduleInfo.Discipline during the week or not depends on the Mirea.Api.Dto.Responses.Schedule.LectureHallScheduleInfo.IsExcludedWeeks property.
*/
weeks?: Array<number>;
/**
* Gets or sets the type of occupation for the schedule entry.
*/
typeOfOccupations: Array<string>;
/**
* Gets or sets the names of the group for the schedule entry.
*/
group: string;
/**
* Gets or sets the IDs of the group for the schedule entry.
*/
groupId: number;
/**
* Gets or sets the names of the campuses for the schedule entry.
*/
campus: Array<string>;
/**
* Gets or sets the IDs of the campuses for the schedule entry.
*/
campusId: Array<number>;
/**
* Gets or sets the names of the professors for the schedule entry.
*/
professors: Array<string>;
/**
* Gets or sets the IDs of the professors for the schedule entry.
*/
professorsId: Array<number>;
/**
* Gets or sets the links to online meetings for the schedule entry.
*/
linkToMeet: Array<string>;
}

View File

@ -1,30 +0,0 @@
/**
* MIREA Schedule Web API
* This API provides a convenient interface for retrieving data stored in the database. Special attention was paid to the lightweight and easy transfer of all necessary data. Made by the Winsomnia team.
*
* OpenAPI spec version: 1.0
* Contact: support@winsomnia.net
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { LectureHallScheduleInfo } from './lectureHallScheduleInfo';
/**
* Represents a response containing schedule information for a lecture hall.
*/
export interface LectureHallScheduleResponse {
/**
* Gets or sets the names of the lecture halls.
*/
lectureHalls: string;
/**
* Gets or sets the IDs of the lecture halls.
*/
lectureHallsId: number;
/**
* Gets or sets the schedules for the lecture hall.
*/
schedules: Array<LectureHallScheduleInfo>;
}

View File

@ -1,76 +0,0 @@
/**
* MIREA Schedule Web API
* This API provides a convenient interface for retrieving data stored in the database. Special attention was paid to the lightweight and easy transfer of all necessary data. Made by the Winsomnia team.
*
* OpenAPI spec version: 1.0
* Contact: support@winsomnia.net
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import {DayOfWeek} from "@model/dayOfWeek";
/**
* Represents information about a specific schedule entry for a professor.
*/
export interface ProfessorScheduleInfo {
dayOfWeek: DayOfWeek;
/**
* Gets or sets the pair number for the schedule entry.
*/
pairNumber: number;
/**
* Gets or sets a value indicating whether the pair is on an even week.
*/
isEven: boolean;
/**
* Gets or sets the name of the discipline for the schedule entry.
*/
discipline: string;
/**
* Gets or sets the ID of the discipline for the schedule entry.
*/
disciplineId: number;
/**
* Gets or sets exclude or include weeks for a specific discipline.
*/
isExcludedWeeks?: boolean;
/**
* The week numbers required for the correct display of the schedule. Whether there will be Mirea.Api.Dto.Responses.Schedule.ProfessorScheduleInfo.Discipline during the week or not depends on the Mirea.Api.Dto.Responses.Schedule.ProfessorScheduleInfo.IsExcludedWeeks property.
*/
weeks?: Array<number>;
/**
* Gets or sets the type of occupation for the schedule entry.
*/
typeOfOccupations: Array<string>;
/**
* Gets or sets the names of the group for the schedule entry.
*/
group: string;
/**
* Gets or sets the IDs of the group for the schedule entry.
*/
groupId: number;
/**
* Gets or sets the names of the lecture halls for the schedule entry.
*/
lectureHalls: Array<string>;
/**
* Gets or sets the IDs of the lecture halls for the schedule entry.
*/
lectureHallsId: Array<number>;
/**
* Gets or sets the names of the campuses for the schedule entry.
*/
campus: Array<string>;
/**
* Gets or sets the IDs of the campuses for the schedule entry.
*/
campusId: Array<number>;
/**
* Gets or sets the links to online meetings for the schedule entry.
*/
linkToMeet: Array<string>;
}

View File

@ -1,30 +0,0 @@
/**
* MIREA Schedule Web API
* This API provides a convenient interface for retrieving data stored in the database. Special attention was paid to the lightweight and easy transfer of all necessary data. Made by the Winsomnia team.
*
* OpenAPI spec version: 1.0
* Contact: support@winsomnia.net
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { ProfessorScheduleInfo } from './professorScheduleInfo';
/**
* Represents a response containing schedule information for a professor.
*/
export interface ProfessorScheduleResponse {
/**
* Gets or sets the name of the professor.
*/
professor: string;
/**
* Gets or sets the ID of the professor.
*/
professorId: number;
/**
* Gets or sets the schedules for the professor.
*/
schedules: Array<ProfessorScheduleInfo>;
}

View File

@ -1,42 +1,36 @@
export class DateOnly { export class DateOnly {
private ticks: number; private readonly _ticks: number;
/*
constructor(year: number, month: number, day: number) {
this.ticks = new Date(year, month - 1, day).getTime();
}
*/
constructor(year: number, month: number, day: number); constructor(year: number, month: number, day: number);
constructor(date: Date); constructor(date: Date);
constructor(date: string); constructor(date: string);
constructor(yearOrDate: number | Date | string, month?: number, day?: number) { constructor(yearOrDate: number | Date | string, month?: number, day?: number) {
if (yearOrDate instanceof Date) { if (yearOrDate instanceof Date) {
this.ticks = yearOrDate.getTime(); this._ticks = yearOrDate.getTime();
} else if (typeof yearOrDate === 'number' && month !== undefined && day !== undefined) { } else if (typeof yearOrDate === 'number' && month !== undefined && day !== undefined) {
this.ticks = new Date(yearOrDate, month - 1, day).getTime(); this._ticks = new Date(yearOrDate, month - 1, day).getTime();
} else if (typeof yearOrDate === 'string') { } else if (typeof yearOrDate === 'string') {
const [year, month, day] = yearOrDate.split('-').map(Number); const [year, month, day] = yearOrDate.split('-').map(Number);
this.ticks = new Date(year, month - 1, day).getTime(); this._ticks = new Date(year, month - 1, day).getTime();
} else { } else {
throw new Error('Invalid constructor arguments'); throw new Error('Invalid constructor arguments');
} }
} }
get year(): number { get year(): number {
return new Date(this.ticks).getFullYear(); return new Date(this._ticks).getFullYear();
} }
get month(): number { get month(): number {
return new Date(this.ticks).getMonth() + 1; return new Date(this._ticks).getMonth() + 1;
} }
get day(): number { get day(): number {
return new Date(this.ticks).getDate(); return new Date(this._ticks).getDate();
} }
get date(): Date { get date(): Date {
return new Date(this.ticks); return new Date(this._ticks);
} }
toString(): string { toString(): string {

View File

@ -2,6 +2,7 @@
{ {
"compileOnSave": false, "compileOnSave": false,
"compilerOptions": { "compilerOptions": {
"resolveJsonModule": true,
"outDir": "./dist/out-tsc", "outDir": "./dist/out-tsc",
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"strict": true, "strict": true,