Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Кольцова А.А. Разработка прототипа системы бронирования велопрокатной организации

.pdf
Скачиваний:
4
Добавлен:
22.08.2024
Размер:
5.83 Mб
Скачать

101

5.1 Описание организации информационной базы

5.1.1 Описание входящей информации

Реестр входящей информации представлен в таблице 12.

Таблица 12 – Реестр входящей информации

Наименование

Обрабатывает

Откуда

Формат

Описание

 

 

 

поступает

 

 

1

Данные о

Система

Пользователи

Электронный

Включает

 

пользователе

бронирования

 

 

информацию о

 

 

 

 

 

пользователе, такие

 

 

 

 

 

как имя, email,

 

 

 

 

 

телефон. Эти

 

 

 

 

 

данные

 

 

 

 

 

используются для

 

 

 

 

 

регистрации и

 

 

 

 

 

авторизации.

2

Учетные

Система

Пользователи

Электронный

Включает

 

данные

бронирования

 

 

информацию для

 

пользователя

 

 

 

авторизации, такие

 

 

 

 

 

как логин и пароль.

3

Данные о

Система

Пользователи

Электронный

Включает

 

бронировании

бронирования

 

 

информацию о

 

 

 

 

 

бронировании,

 

 

 

 

 

такие как даты,

 

 

 

 

 

время и выбранный

 

 

 

 

 

велосипед.

4

Данные на

Система

Менеджеры

Электронный

Включает

 

обновление

бронирования

по продажам

 

контактные данные

 

информации о

 

 

 

клиента, историю

 

клиенте

 

 

 

бронирований,

 

 

 

 

 

отзывы.

5

Данные на

Система

Менеджеры

Электронный

Включает

 

обновление

бронирования

по продажам

 

информацию о

 

каталога

 

 

 

велосипедах, такие

 

 

 

 

 

как модель,

 

 

 

 

 

доступность,

 

 

 

 

 

техническое

 

 

 

 

 

состояние.

6

Данные для

Система

Менеджеры

Электронный

Включает данные о

 

формирования

бронирования

по продажам

 

бронированиях,

 

отчета о

 

 

 

такие как даты,

 

бронировании

 

 

 

время, модели

 

 

 

 

 

велосипедов и

 

 

 

 

 

клиенты.

 

5.1.2 Описание исходящей информации

 

 

 

Реестр исходящей информации представлен в таблице 13.

 

102

Таблица 13 – Реестр исходящей информации

Наименование

Обрабатывает

Кому

Формат

Описание

 

 

 

отправляется

 

 

1

Подтверждение

Система

Пользователи

Электронный

Документ,

 

регистрации

бронирования

 

 

подтверждающий

 

 

 

 

 

успешную

 

 

 

 

 

регистрацию

 

 

 

 

 

пользователя в

 

 

 

 

 

системе.

2

Уведомление

Система

Пользователи

Электронный

Уведомление,

 

об авторизации

бронирования

 

 

отправляемое

 

 

 

 

 

после успешной

 

 

 

 

 

авторизации в

 

 

 

 

 

системе. Содержит

 

 

 

 

 

информацию о

 

 

 

 

 

времени и дате

 

 

 

 

 

входа.

3

Подтверждение

Система

Пользователи

Электронный

Документ,

 

бронирования

бронирования

 

 

подтверждающий

 

 

 

 

 

успешное

 

 

 

 

 

бронирование

 

 

 

 

 

велосипеда.

4

Отчет о

Система

Менеджеры

Электронный

Отчет,

 

клиентах

бронирования

по продажам

 

содержащий

 

 

 

 

 

информацию о

 

 

 

 

 

клиентах, такие

 

 

 

 

 

как контактные

 

 

 

 

 

данные и история

 

 

 

 

 

бронирований.

5

Каталог

Система

Пользователи

Электронный

Список всех

 

 

бронирования

 

 

доступных

 

 

 

 

 

велосипедов и

 

 

 

 

 

услуг с

 

 

 

 

 

описаниями,

 

 

 

 

 

фотографиями и

 

 

 

 

 

информацией о

 

 

 

 

 

наличии.

6

Отчет о

Система

Менеджеры

Электронный

Документ,

 

бронировании

бронирования

по продажам

 

представляющий

 

 

 

 

 

информацию о

 

 

 

 

 

предстоящих

 

 

 

 

 

бронированиях.

103

Приложение Д

Текст программы

Введение

Настоящий документ содержит описание текстов программ, входящих в состав информационной системы. В нем представлены коды основных модулей системы, а также краткие пояснения к ним.

Структура файлов

1.Файл header.php

Описание: Этот файл содержит HTML-код заголовка всех страниц. Он включает стили и скрипты, а также выводит навигационное меню, которое зависит от состояния сессии пользователя. В нем также реализована проверка куки для отображения ссылки на

бронирование.

<!DOCTYPE html> <html lang="ru"> <head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>RIDE-RENT</title>

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/aos/2.3.4/aos.css">

<link rel="stylesheet" href="css/styles.css">

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://unpkg.com/imask"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/aos/2.3.4/aos.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/vanilla-masker/1.1.1/vanilla-masker.min.js"></script> <script src="js/script.js"></script>

</head>

<body>

<header>

<h1 class="animate__animated">RIDE-RENT</h1> <nav>

<a href="index.php" class="animate__animated">Главная</a> <a href="catalog.php" class="animate__animated">Каталог</a> <?php

if (session_status() == PHP_SESSION_NONE) { session_start();

}

if (isset($_SESSION['user_id'])): ?>

<?php if ($_SESSION['role_id'] == 1): ?>

<a href="admin_profile.php" class="animate__animated">Админ-панель</a> <?php elseif ($_SESSION['role_id'] == 3): ?>

<a href="manager_profile.php" class="animate__animated">Панель менеджера</a> <?php else: ?>

<a href="profile.php" class="animate__animated">Личный кабинет</a> <?php endif; ?>

<a href="logout.php" class="animate__animated">Выход</a> <?php else: ?>

<a href="registration.php" class="animate__animated">Регистрация</a> <a href="login.php" class="animate__animated">Вход</a>

<?php endif; ?> </nav>

<a href="booking.php" id="booking-link" class="bron" style="display: none;">Перейти к бронированию</a> </header>

<script>

104

//Функция для получения значения куки function getCookie(name) {

let matches = document.cookie.match(new RegExp(

"(?:^|; )" + name.replace(/([.$?*|{}()[]\/+^])/g, '\\$1') + "=([^;]*)"

));

return matches ? decodeURIComponent(matches[1]) : undefined;

}

//Проверка наличия куки и отображение кнопки document.addEventListener('DOMContentLoaded', function() {

let bookings = getCookie('bookings'); if (bookings) {

document.getElementById('booking-link').style.display = 'block';

}

});

</script>

2.Файл footer.php

Описание: Файл содержит HTML-код нижнего колонтитула, который включается на

все страницы. В нем размещена информация о компании и ссылки на социальные сети.

<footer>

<p>Мы предоставляем качественные велосипеды для проката. Наша цель - обеспечить лучший опыт для наших клиентов.</p>

<div class="social-icons">

<a href="https://t.me/ko1tsovaa" target="_blank"> <img src="images/tele.svg" alt="Email">

</a>

<a href="https://wa.me/89189034094" target="_blank"> <img src="images/whatsapp1.svg" alt="Email">

</a>

<a href="https://vk.com/ko1tsovaa" target="_blank"> <img src="images/vk1.svg" alt="Email">

</a>

</div>

</footer>

3.Файл login.php

Описание: Этот файл отображает форму для входа пользователей в систему. Он также

показывает оповещения об ошибках или успехах входа.

<?php

include 'header.php'; include 'db.php';

// Показ оповещений

if (isset($_GET['error'])) {

echo '<div class="alert alert-error">' . htmlspecialchars($_GET['error']) . '</div>';

}

if (isset($_GET['success'])) {

echo '<div class="alert alert-success">' . htmlspecialchars($_GET['success']) . '</div>';

}

?>

<div class="login-container"> <h1>Вход</h1>

<form action="login_process.php" method="POST" class="form"> <label for="email">Электронная почта:</label>

<input type="email" id="email" name="email" required>

<label for="password">Пароль:</label>

<input type="password" id="password" name="password" required>

105

<button type="submit">Войти</button> </form>

</div>

<?php include 'footer.php'; ?> </body>

</html>

4.Файл db.php

Описание: Файл содержит код для подключения к базе данных MySQL и установки кодировки. Он используется для подключения к базе данных во всех остальных файлах.

<?php

$servername = "localhost"; $username = "root"; $password = "usbw"; $dbname = "bron";

// Создание подключения

$conn = new mysqli($servername, $username, $password, $dbname);

//Проверка подключения if ($conn->connect_error) {

die("Connection failed: " . $conn->connect_error);

}

//Устанавливаем кодировку

$conn->set_charset("utf8"); ?>

5.Файл catalog.php

Описание: Этот файл отвечает за отображение каталога велосипедов. В нем также реализована фильтрация велосипедов по различным параметрам и отображение списка доступных велосипедов из базы данных.

<?php include 'header.php'; ?> <?php include 'db.php'; ?>

<button id="toggle-filters">Показать/Скрыть фильтры</button> <div id="filters" class="catalog-filters" style="display: none;">

<form method="GET" action="catalog.php" class="none"> <label for="frameSize">Размер рамы:</label>

<select id="frameSize" name="frameSize"> <option value="">Любой</option> <?php

$frameSizes = $conn->query("SELECT * FROM FrameSizes"); while ($frameSize = $frameSizes->fetch_assoc()) {

echo '<option value="' . $frameSize['frame_size_id'] . '">' . htmlspecialchars($frameSize['frame_size'], ENT_QUOTES, 'UTF-8') . '</option>';

}

?>

</select>

<label for="ageLimit">Возрастное ограничение:</label> <select id="ageLimit" name="ageLimit">

<option value="">Любое</option> <?php

$ageLimits = $conn->query("SELECT * FROM AgeLimits"); while ($ageLimit = $ageLimits->fetch_assoc()) {

echo '<option value="' . $ageLimit['age_limit_id'] . '">' . htmlspecialchars($ageLimit['age_limit'], ENT_QUOTES, 'UTF- 8') . '</option>';

}

?>

</select>

<label for="availability">Статус:</label> <select id="availability" name="availability">

<option value="">Любой</option>

106

<?php

$availabilities = $conn->query("SELECT * FROM Availability"); while ($availability = $availabilities->fetch_assoc()) {

echo '<option value="' . $availability['availability_id'] . '">' . htmlspecialchars($availability['status'], ENT_QUOTES, 'UTF-8') . '</option>';

}

?>

</select>

<label for="category">Категория:</label> <select id="category" name="category">

<option value="">Любая</option> <?php

$categories = $conn->query("SELECT * FROM Categories"); while ($category = $categories->fetch_assoc()) {

echo '<option value="' . $category['category_id'] . '">' . htmlspecialchars($category['category_name'], ENT_QUOTES, 'UTF-8') . '</option>';

}

?>

</select>

<button type="submit">Фильтровать</button> </form>

</div>

<div class="catalog"> <?php

$conditions = [];

if (!empty($_GET['frameSize'])) {

$conditions[] = "B.frame_size_id = " . (int)$_GET['frameSize'];

}

if (!empty($_GET['ageLimit'])) {

$conditions[] = "B.age_limit_id = " . (int)$_GET['ageLimit'];

}

if (!empty($_GET['availability'])) {

$conditions[] = "B.availability_id = " . (int)$_GET['availability'];

}

if (!empty($_GET['category'])) {

$conditions[] = "B.category_id = " . (int)$_GET['category'];

}

$whereClause = !empty($conditions) ? 'WHERE ' . implode(' AND ', $conditions) : '';

$sql = "SELECT B.bike_id, B.bike_model, B.serial_number, B.photo, A.status as Availability, FS.frame_size as FrameSize, AL.age_limit as AgeLimit, C.category_name

FROM Bikes B

LEFT JOIN FrameSizes FS ON B.frame_size_id = FS.frame_size_id LEFT JOIN AgeLimits AL ON B.age_limit_id = AL.age_limit_id LEFT JOIN Availability A ON B.availability_id = A.availability_id LEFT JOIN Categories C ON B.category_id = C.category_id $whereClause";

$result = $conn->query($sql);

if ($result->num_rows > 0) {

while($row = $result->fetch_assoc()) {

echo '<div class="catalog-item" data-aos="fade-right">'; if ($row['photo']) {

echo '<img src="data:image/jpeg;base64,' . base64_encode($row['photo']) . '" alt="Фото велосипеда">'; } else {

echo '<img src="images/placeholder.png" alt="Изображение отсутствует">';

}

echo '<h3>'.htmlspecialchars($row['bike_model'], ENT_QUOTES, 'UTF-8').'</h3>';

echo '<p>Категория: '.htmlspecialchars($row['category_name'], ENT_QUOTES, 'UTF-8').'</p>'; echo '<p>Статус: '.htmlspecialchars($row['Availability'], ENT_QUOTES, 'UTF-8').'</p>';

echo '<p>Размер рамы: '.htmlspecialchars($row['FrameSize'], ENT_QUOTES, 'UTF-8').'</p>';

echo '<p>Возрастное ограничение: '.htmlspecialchars($row['AgeLimit'], ENT_QUOTES, 'UTF-8').'+</p>'; echo '<p>Серийный номер: '.htmlspecialchars($row['serial_number'], ENT_QUOTES, 'UTF-8').'</p>'; echo '<button class="booking-button" data-bike-id="' . $row['bike_id'] . '">Бронировать</button>';

echo '</div>';

}

} else {

echo '<p>Нет доступных велосипедов.</p>';

}

107

$conn->close(); ?>

</div>

<?php include 'footer.php'; ?> <script>

function addToBooking(bikeId) {

let bookings = getCookie('bookings');

bookings = bookings ? JSON.parse(bookings) : []; if (!bookings.includes(bikeId)) {

bookings.push(bikeId);

setCookie('bookings', JSON.stringify(bookings), 7); location.reload();

} else {

alert('Велосипед уже добавлен в бронирование');

}

}

function getCookie(name) {

let matches = document.cookie.match(new RegExp(

"(?:^|; )" + name.replace(/([.$?*|{}()[]\/+^])/g, '\\$1') + "=([^;]*)"

));

return matches ? decodeURIComponent(matches[1]) : undefined;

}

function setCookie(name, value, days) { let expires = "";

if (days) {

let date = new Date();

date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); expires = "; expires=" + date.toUTCString();

} else {

expires = "; expires=Thu, 01 Jan 1970 00:00:00 GMT";

}

document.cookie = name + "=" + (value || "") + expires + "; path=/";

}

document.addEventListener('DOMContentLoaded', function() { let bookings = getCookie('bookings');

bookings = bookings ? JSON.parse(bookings) : []; document.querySelectorAll('.booking-button').forEach(function(button) {

let bikeId = parseInt(button.getAttribute('data-bike-id')); if (bookings.includes(bikeId)) {

button.style.display = 'none'; } else {

button.addEventListener('click', function() { addToBooking(bikeId); button.style.display = 'none';

});

}

});

if (bookings.length === 0) { setCookie('bookings', '', -1);

}

});

</script>

</body>

</html>

6. Файл catalog_edit.php

Описание: Файл для администраторов и менеджеров, который позволяет добавлять,

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

<?php

include 'header_adm.php';

108

include 'db.php';

//Проверка роли пользователя if ($_SESSION['role_id'] != 3) { header("Location: login.php");

exit();

}

//Обработка загрузки изображения function handleFileUpload($file, &$error) {

$upload_ok = 1;

$image_file_type = strtolower(pathinfo($file["name"], PATHINFO_EXTENSION));

//Проверка, является ли файл изображением $check = getimagesize($file["tmp_name"]);

if ($check === false) {

$error = "Файл не является изображением."; $upload_ok = 0;

}

//Ограничение размера файла (5MB)

if ($file["size"] > 5000000) {

$error = "Извините, ваш файл слишком большой."; $upload_ok = 0;

}

// Разрешенные форматы файлов

if ($image_file_type != "jpg" && $image_file_type != "png" && $image_file_type != "jpeg" && $image_file_type != "gif") { $error = "Извините, только JPG, JPEG, PNG и GIF файлы разрешены.";

$upload_ok = 0;

}

// Проверка на ошибки if ($upload_ok == 0) {

return false; } else {

return file_get_contents($file["tmp_name"]);

}

}

// Добавление велосипеда

if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['action']) && $_POST['action'] == 'add') { $bike_model = $conn->real_escape_string($_POST['bike_model']);

$frame_size_id = (int)$_POST['frame_size_id']; $age_limit_id = (int)$_POST['age_limit_id'];

$serial_number = $conn->real_escape_string($_POST['serial_number']); $availability_id = (int)$_POST['availability_id'];

$category_id = (int)$_POST['category_id']; $photo = null;

if (isset($_FILES['photo']) && $_FILES['photo']['error'] == UPLOAD_ERR_OK) { $upload_error = "";

$photo = handleFileUpload($_FILES['photo'], $upload_error); if (!$photo) {

header("Location: catalog_edit.php?error=" . $upload_error); exit();

}

}

$stmt = $conn->prepare("INSERT INTO bikes (bike_model, frame_size_id, age_limit_id, serial_number, availability_id, category_id, photo) VALUES (?, ?, ?, ?, ?, ?, ?)");

$stmt->bind_param("siisiss", $bike_model, $frame_size_id, $age_limit_id, $serial_number, $availability_id, $category_id, $photo);

if ($stmt->execute()) {

header("Location: catalog_edit.php?message=Велосипед успешно добавлен."); exit();

} else {

header("Location: catalog_edit.php?error=Ошибка добавления велосипеда: " . $stmt->error); exit();

109

}

}

// Удаление велосипеда

if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['action']) && $_POST['action'] == 'delete' && isset($_POST['bike_id'])) {

$bike_id = (int)$_POST['bike_id'];

$delete_query = "DELETE FROM bikes WHERE bike_id = $bike_id";

if ($conn->query($delete_query) === TRUE) {

header("Location: catalog_edit.php?message=Велосипед успешно удален."); exit();

} else {

header("Location: catalog_edit.php?error=Ошибка удаления велосипеда: " . $conn->error); exit();

}

}

// Обновление информации о велосипеде

if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['bike_id']) && !isset($_POST['action'])) { $bike_id = (int)$_POST['bike_id'];

$bike_model = $conn->real_escape_string($_POST['bike_model']); $frame_size_id = (int)$_POST['frame_size_id'];

$age_limit_id = (int)$_POST['age_limit_id'];

$serial_number = $conn->real_escape_string($_POST['serial_number']); $availability_id = (int)$_POST['availability_id'];

$category_id = (int)$_POST['category_id']; $photo = null;

if (isset($_FILES['photo']) && $_FILES['photo']['error'] == UPLOAD_ERR_OK) { $upload_error = "";

$photo = handleFileUpload($_FILES['photo'], $upload_error); if (!$photo) {

header("Location: catalog_edit.php?error=" . $upload_error); exit();

}

}

if ($photo) {

$update_query = "UPDATE bikes SET bike_model = ?,

frame_size_id = ?, age_limit_id = ?, serial_number = ?, availability_id = ?, category_id = ?, photo = ?

WHERE bike_id = ?";

$stmt = $conn->prepare($update_query);

$stmt->bind_param("siisissi", $bike_model, $frame_size_id, $age_limit_id, $serial_number, $availability_id, $category_id, $photo, $bike_id);

} else {

$update_query = "UPDATE bikes SET bike_model = ?,

frame_size_id = ?, age_limit_id = ?, serial_number = ?, availability_id = ?, category_id = ? WHERE bike_id = ?";

$stmt = $conn->prepare($update_query);

$stmt->bind_param("siisisi", $bike_model, $frame_size_id, $age_limit_id, $serial_number, $availability_id, $category_id, $bike_id);

}

if ($stmt->execute()) {

header("Location: catalog_edit.php?message=Информация о велосипеде успешно обновлена."); exit();

} else {

header("Location: catalog_edit.php?error=Ошибка обновления информации: " . $stmt->error);

110

exit();

}

}

// Получение списка велосипедов $bikes_query = "SELECT * FROM bikes"; $bikes_result = $conn->query($bikes_query);

// Получение списка размеров рам $frame_sizes_query = "SELECT * FROM framesizes";

$frame_sizes_result = $conn->query($frame_sizes_query);

// Получение списка возрастных ограничений $age_limits_query = "SELECT * FROM agelimits"; $age_limits_result = $conn->query($age_limits_query);

// Получение списка доступности $availability_query = "SELECT * FROM availability";

$availability_result = $conn->query($availability_query);

// Получение списка категорий

$categories_query = "SELECT * FROM categories"; $categories_result = $conn->query($categories_query);

$conn->close(); ?>

<!DOCTYPE html> <html lang="ru"> <head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Управление каталогом</title>

<link rel="stylesheet" href="css/styles.css"> <script>

function filterTable() {

var input, filter, table, tr, td, i, j, txtValue;

input = document.getElementById("searchInput"); filter = input.value.toUpperCase();

table = document.getElementById("bikesTable"); tr = table.getElementsByTagName("tr");

for (i = 1; i < tr.length; i++) {

tr[i].style.display = "none"; // Hide all rows initially td = tr[i].getElementsByTagName("td");

for (j = 0; j < td.length; j++) { if (td[j]) {

txtValue = td[j].textContent || td[j].innerText;

if (txtValue.toUpperCase().indexOf(filter) > -1) { tr[i].style.display = ""; // Show the row if match is found break;

}

}

}

}

}

</script>

</head>

<body>

<div class="manager-container">

<h2>Управление каталогом велосипедов</h2>

<?php

if (isset($_GET['message'])) {

echo '<div class="alert alert-success">' . htmlspecialchars($_GET['message'], ENT_QUOTES, 'UTF-8') . '</div>';

}

if (isset($_GET['error'])) {

echo '<div class="alert alert-error">' . htmlspecialchars($_GET['error'], ENT_QUOTES, 'UTF-8') . '</div>';

}

?>

<h3>Добавить велосипед</h3>