Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
23_ИСТ_1_1_Какушкина_Ольга_ЛР_6.3.docx
Скачиваний:
0
Добавлен:
23.06.2025
Размер:
526.93 Кб
Скачать

М ИНОБРНАУКИ РОССИИ

ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ

УЧРЕЖДЕНИЕ ВЫСШЕГО ОБРАЗОВАНИЯ

НИЖЕГОРОДСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ

УНИВЕРСИТЕТ ИМ. Р.Е.АЛЕКСЕЕВА

Институт радиоэлектроники и информационных технологий

Кафедра «Графические информационные системы»

ОТЧЕТ

к лабораторной работе №6.3

«Инициализация и валидация форм. Работа с сервером.»

(наименование работы)

по дисциплине

«WEB-технологии»

(наименование дисциплины)

ПРОВЕРИЛ:

Агафонов Н.Е.

(подпись)

(фамилия, и.,о.)

СТУДЕНТ:

Какушкна О.В

(подпись)

(фамилия, и.,о.)

23-ИСТ-1-1

(шифр группы)

Оглавление

МИНОБРНАУКИ РОССИИ 1

НИЖЕГОРОДСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ 1

1 Введение 3

1.1 Цели и задачи 3

1.1.1. Цель работы: 3

1.1.2. Постановка задачи: 3

2 Основная Часть 4

3 Заключение 21

  1. Введение

    1. Цели и задачи

      1. Цель работы:

Работа с сервером. Создание запросов основной системы.

      1. Постановка задачи:

  • Разработка основной системы

  • Распределение данных по страницам

  • Осуществление запросов к серверу

  1. Основная Часть

Добавим добавление и отображение секций на главной странице и сделаем доступным пользователю загружать фотографии.

  • Создадим сервер для загрузки фотографий с помощью exspress и multer. Определим папку images для хранения загруженных файлов, создавая ее, если она не существует. Пропишем const upload = multer({ dest: uploadFolder });: настраивает multer для сохранения загружаемых файлов в папку images. app.use('/images', express.static(uploadFolder));: настраивает маршрут, позволяющий статически раздавать файлы из папки images, чтобы их можно было получить по URL /images/filename.

Далее создадим Роут для загрузки файлов:

  • Маршрут /upload: Позволяет загружать файл на сервер. Использует middleware upload.single('file') из multer, который позволяет загружать один файл с именем поля file из формы. При успешной загрузке (если req.file существует) формируется URL загруженного изображения, который отправляется обратно клиенту в формате JSON. Если файл не загружен, сервер возвращает статус 400 с сообщением об ошибке.

Теперь пропишем логику для создания/удаления/редактирования секции. Создание секции:

  • Маршрут /sections Позволяет создать новую секцию. Получает текущие секции с помощью getSections(), добавляет новую секцию в массив, и сохраняет обновленный массив обратно в db.json. Возвращает новую секцию с кодом состояния 201 (создано).

  • Обновление секции: Маршрут PUT /sections/:id: Позволяет обновить секцию по ID. Найденный индекс секции обновляется с данными из req.body. Если секция не найдена, возвращает статус 404 с сообщением об ошибке.

  • Маршрут DELETE /sections/:id: Удаляет секцию по ID. Если секция найдена, ее удаляют и сохраняют обновленный массив. При успешном удалении возвращает статус 204 (без содержимого). Если секция не найдена, возвращает статус 404 с сообщением об ошибке.

  • Маршрут GET /sections: Возвращает все секции из db.json. Использует функцию getSections() для получения данных и отправляет их обратно в формате JSON.

Теперь реализуем работу на странице администратора с добавлением, редактированием, удалением секции чтобы они еще отображались на главной странице. Шаблон компонента:

<app-header></app-header>

<div class="admin-container">

<div class="sidebar">

<h2>Админ-панель</h2>

<ul class="sidebar-menu">

<li><a href="teacher-add">Добавить учителя</a></li>

</ul>

</div>

<div class="content">

<h2 class="zagolovok">Создание секции</h2>

<form

id="sectionForm"

*ngIf="!editSectionId; else editTemplate"

(ngSubmit)="onSubmit()"

class="admin-form"

#myForm="ngForm"

>

<div class="form-group">

<label for="title">Заголовок</label>

<input

type="text"

id="title"

[(ngModel)]="section.title"

name="title"

required

/>

<div *ngIf="myForm.submitted && !section.title" class="error-message">

Это поле обязательно.

</div>

</div>

<div class="form-group">

<label for="instructor">Выбрать преподавателя</label>

<select

id="instructor"

[(ngModel)]="section.instructor"

name="instructor"

required

>

<option *ngFor="let teacher of teachers" [value]="teacher.id">

{{ teacher.firstName }} {{ teacher.lastName }}

</option>

</select>

<div *ngIf="myForm.submitted && !section.instructor" class="error-message">

Это поле обязательно.

</div>

</div>

<div class="form-group">

<label for="startTime">Время начала</label>

<input

type="time"

id="startTime"

[(ngModel)]="section.startTime"

name="startTime"

required

/>

<div *ngIf="myForm.submitted && !section.startTime" class="error-message">

Это поле обязательно.

</div>

</div>

<div class="form-group">

<label for="endTime">Время окончания</label>

<input

type="time"

id="endTime"

[(ngModel)]="section.endTime"

name="endTime"

required

/>

<div *ngIf="myForm.submitted && !section.endTime" class="error-message">

Это поле обязательно.

</div>

</div>

<div class="form-group">

<label for="day">День</label>

<input type="text" id="day" [(ngModel)]="section.day" name="day" required />

<div *ngIf="myForm.submitted && !section.day" class="error-message">

Это поле обязательно.

</div>

</div>

<div class="form-group">

<label for="capacity">Вместимость</label>

<input

type="number"

id="capacity"

[(ngModel)]="section.capacity"

name="capacity"

required

min="1"

/>

<div

*ngIf="myForm.submitted && (section.capacity < 1 || !section.capacity)"

class="error-message"

>

Вместимость должна быть хотя бы 1.

</div>

</div>

<div class="form-group">

<label for="image">Изображение</label>

<input

type="file"

id="image"

(change)="onFileSelected($event)"

accept="image/*"

required

/>

<button type="button" (click)="uploadImage(section)">Загрузить</button>

<div *ngIf="myForm.submitted && !section.imageUrl" class="error-message">

Это поле обязательно.

</div>

</div>

<button type="submit">Создать секцию</button>

</form>

<!-- Шаблон редактирования секции -->

<ng-template #editTemplate>

<h3 class="zagolovok">Редактирование секции</h3>

<form

id="sectionForm"

(ngSubmit)="onSaveEdit(section)"

class="admin-form"

>

<div class="form-group">

<label for="title">Заголовок</label>

<input

type="text"

id="title"

[(ngModel)]="section.title"

name="title"

required

/>

</div>

<div class="form-group">

<label for="instructor">Инструктор</label>

<select

id="instructor"

[(ngModel)]="section.instructor"

name="instructor"

required

>

<option *ngFor="let teacher of teachers" [value]="teacher.id">

{{ teacher.firstName }} {{ teacher.lastName }}

</option>

</select>

</div>

<div class="form-group">

<label for="startTime">Время начала</label>

<input

type="time"

id="startTime"

[(ngModel)]="section.startTime"

name="startTime"

required

/>

</div>

<div class="form-group">

<label for="endTime">Время окончания</label>

<input

type="time"

id="endTime"

[(ngModel)]="section.endTime"

name="endTime"

required

/>

</div>

<div class="form-group">

<label for="day">День</label>

<input type="text" id="day" [(ngModel)]="section.day" name="day" required />

</div>

<div class="form-group">

<label for="capacity">Вместимость</label>

<input

type="number"

id="capacity"

[(ngModel)]="section.capacity"

name="capacity"

required

min="1"

/>

</div>

<button type="submit">Сохранить изменения</button>

<button type="button" (click)="resetForm()">Отменить</button>

</form>

</ng-template>

<h2 class="zagolovok">Список секций</h2>

<div class="photo-container">

<div *ngFor="let section of sections" class="container_photo">

<img

[src]="section.imageUrl"

alt="{{ section.title }}"

class="section-image"

/>

<h3 class="zagolovok_section">{{ section.title }}</h3>

<div class="section-details">

<p>

<strong>Инструктор:</strong>

{{ getTeacherNameById(section.instructor) }}

</p>

<p><strong>Время начала:</strong> {{ section.startTime }}</p>

<p><strong>Время окончания:</strong> {{ section.endTime }}</p>

<p><strong>День:</strong> {{ section.day }}</p>

<p><strong>Вместимость:</strong> {{ section.capacity }}</p>

</div>

<div class="buttons">

<button (click)="onEdit(section)" class="btn" >Изменить</button>

<button (click)="onDelete(section)" class="btn" >Удалить</button>

</div>

</div>

</div>

</div>

</div>

<app-footer></app-footer>

  • Теперь реализуем логику компонента. ngOnInit: Вызывается при инициализации компонента. Загружает секции и учителей, вызывая методы loadSections() и loadTeachers().

  • onFileSelected(event: any) устанавливает выбранный файл (selectedFile), когда пользователь выбирает файл для загрузки. Загружает изображение с помощью UploadService. Если загрузка успешна, обновляет URL изображения у секции и сбрасывает выбор файла.

В UploadService :

uploadFile(file: File): Observable<any> {

    const formData = new FormData();

    formData.append('file', file);

    return this.http.post(this.uploadUrl, formData);

  }

  • onSubmit(): Проверяет, валидна ли созданная секция. Если валидна, генерирует ID для секции и отправляет данные на сервер через SectionService для создания новой секции.

  • Теперь редактирование секции onEdit(section: Section): устанавливает текущую секцию для редактирования и прокручивает страницу к форме секции с помощью scrollIntoView.

  • Сохранение изменений в редактируемой секции: сохраняет изменения для редактируемой секции. Если у секции изменился инструктор, обновляет секции для старого и нового инструкторов.

  • Удаление секции: удаляет секцию после подтверждения от пользователя. Удаляет секцию у учителя, который ее курирует. Сам метод удаления:

Теперь реализуем метод чтобы у учителя, который вел эту секцию , удалилась эта секция

После проделанных изменений пользователя нужно добавляет ID секции к курируемым секциям у соответствующего учителя.

Теперь отобразим эти секции на главной странице main-page: шаблон блока секций

<div class="photo-container">

    <div *ngFor="let section of sections" class="container_photo">

        <img [src]="section.imageUrl" alt="{{ section.title }}" class="section-image" />

        <h3 class="zagolovok_section">{{ section.title }}</h3>

        <div class="section-details">

            <p><strong>Инструктор:</strong> {{ getTeacherNameById(section.instructor) }}</p>

            <p><strong>Время:</strong> {{ section.startTime }} - {{ section.endTime }}</p>

            <p><strong>День:</strong> {{ section.day }}</p>

            <p><strong>Вместимость:</strong> {{ section.capacity }}</p>

            <div *ngIf="section.capacity === 0" class="error-message">

                <p>Записаться на эту секцию невозможно. Мест нет!</p>

            </div>

        </div>

    </div>

</div>

Теперь рассмотрим логику отображения:

При загрузке страницы метод loadSections this.sectionService.getSections() делает HTTP-запрос к API (локальному, в данном случае), чтобы получить массив секций.

Метод subscribe позволяет подписаться на возвращаемый Observable. Когда данные будут загружены, функция обратного вызова получит их и присвоит переменной sections в компоненте.

А в шаблоне страницы *ngFor: Эта директива создает элементы <div> для каждой секции в массиве sections, который был загружен ранее.

Динамическое связывание: Данные секции, такие как imageUrl, title, startTime, endTime, day, capacity, отображаются с использованием {{  section.title }}

Получение имени инструктора: Для отображения имени инструктора вызывается метод getTeacherNameById(section.instructor), который ищет инструктора по его ID.

Соседние файлы в предмете Web технологии