diff --git a/movere_local/db.sqlite3 b/movere_local/db.sqlite3 index ce8a51b719a4b75e9a168f78b0fec53c06b682be..3b877c115f77c33707fce472a6918f20c9d8b64e 100644 Binary files a/movere_local/db.sqlite3 and b/movere_local/db.sqlite3 differ diff --git a/movere_local/mainapp/admin.py b/movere_local/mainapp/admin.py index 8c38f3f3dad51e4585f3984282c2a4bec5349c1e..8f08f0e51f493e59deb5914e1806e1612fa6a815 100644 --- a/movere_local/mainapp/admin.py +++ b/movere_local/mainapp/admin.py @@ -1,3 +1,7 @@ from django.contrib import admin +from .models import EditRequest, IncomingEditRequest, Order # Register your models here. +admin.site.register(EditRequest) +admin.site.register(IncomingEditRequest) +admin.site.register(Order) \ No newline at end of file diff --git a/movere_local/mainapp/forms.py b/movere_local/mainapp/forms.py index 721113687ae5cce6bba66de8901ce5f0b1fc7be1..15b265fb5c63fadd08043fcd800774a18b8cd409 100644 --- a/movere_local/mainapp/forms.py +++ b/movere_local/mainapp/forms.py @@ -24,7 +24,7 @@ class RequestForm(forms.ModelForm): ] file_choice = forms.ChoiceField(choices=FILE_CHOICES, widget=forms.RadioSelect) - storage_item = forms.ModelChoiceField(queryset=Storage.objects.none(), required=False) + storage_item = forms.ModelChoiceField(queryset=Storage.objects.none(), required=False, empty_label=None) upload_file = forms.FileField(required=False) class Meta: @@ -35,7 +35,7 @@ class RequestForm(forms.ModelForm): user = kwargs.pop('user', None) super().__init__(*args, **kwargs) if user: - self.fields['storage_item'].queryset = Storage.objects.filter(user=user) + self.fields['storage_item'].queryset = Storage.objects.filter(user=user, file_path__iregex=r'\.(jpg|jpeg|png)$') @@ -47,19 +47,48 @@ class OrderForm(forms.ModelForm): (CHOICE_FILE_UPLOAD, 'Загрузить файл вручную'), ] + # Поле для выбора должности (РѕРґРёРЅ вариант) + POSITION_CHOICES = [ + ('student', 'Студент Р’РЁР'), + ('professor', 'Преподаватель Р’РЁР'), + ('worker', 'Сотрудник Р’РЁР'), + ('other', 'Другое'), + ] + position = forms.ChoiceField(choices=POSITION_CHOICES, widget=forms.RadioSelect, label="Ваша должность") + + # Поле для целей (несколько вариантов) + PURPOSE_CHOICES = [ + ('course', 'Курсовая работа'), + ('diploma', 'Дипломная работа'), + ('project', 'Проект'), + ('other', 'Другое'), + ] + purpose = forms.MultipleChoiceField(choices=PURPOSE_CHOICES, widget=forms.CheckboxSelectMultiple, label="Цель 3D-печати") + + # Поле для текстового РІРІРѕРґР° цели + additional_purpose = forms.CharField(required=False, widget=forms.Textarea, label="Дополнительно укажите цель 3D-печати") + + # Поле для выбора материала (РѕРґРёРЅ вариант) + MATERIAL_CHOICES = [ + ('pla', 'Пластик PLA'), + ('abs', 'Пластик ABS'), + ('tpu', 'Резина TPU'), + ] + material = forms.ChoiceField(choices=MATERIAL_CHOICES, widget=forms.RadioSelect, label="Выберите материал") + file_choice = forms.ChoiceField(choices=FILE_CHOICES, widget=forms.RadioSelect) - storage_item = forms.ModelChoiceField(queryset=Storage.objects.none(), required=False) + storage_item = forms.ModelChoiceField(queryset=Storage.objects.none(), required=False, empty_label=None) upload_file = forms.FileField(required=False) class Meta: model = Order - fields = ['order_parameters'] # Добавьте РґСЂСѓРіРёРµ необходимые поля, если РЅСѓР¶РЅРѕ + fields = [] # Добавьте РґСЂСѓРіРёРµ необходимые поля, если РЅСѓР¶РЅРѕ def __init__(self, *args, **kwargs): user = kwargs.pop('user', None) super().__init__(*args, **kwargs) if user: - self.fields['storage_item'].queryset = Storage.objects.filter(user=user) + self.fields['storage_item'].queryset = Storage.objects.filter(user=user, file_path__iregex=r'\.(obj|stl|step|3mf)$') diff --git a/movere_local/mainapp/models.py b/movere_local/mainapp/models.py index f77595131172246b0591ecf32b16acf25ca778c6..62c2924a8c1c8eb78fe0e0ca1cadbac45176f52c 100644 --- a/movere_local/mainapp/models.py +++ b/movere_local/mainapp/models.py @@ -1,7 +1,9 @@ +import os from django.contrib.auth.models import User from django.db import models import threading import time +from mainapp.utils import upload_file_and_add_task class Order(models.Model): order_datetime = models.DateTimeField(auto_now_add=True) # Дата Рё время создания заказа @@ -17,7 +19,7 @@ class EditRequest(models.Model): req_datetime = models.DateTimeField(auto_now_add=True) # Дата Рё время создания заказа user = models.ForeignKey(User, on_delete=models.CASCADE) # РЎРІСЏР·СЊ СЃ пользователем req_parameters = models.TextField(default='no parameters') # Параметры заказа - file_path = models.CharField(max_length=255, blank=True, null=True) # Путь Рє файлу + file_path = models.CharField(max_length=255, blank=True, null=True) # Путь Рє файлу, отправлен пользователем req_state = models.CharField( max_length=50, default='in_progress', @@ -40,10 +42,34 @@ class EditRequest(models.Model): # Если это новый объект, запускаем фоновую задачу if is_new: threading.Thread(target=self.send_request_to_server, args=(), daemon=True).start() + # pass def send_request_to_server(self): # Заглушка для отправки данных РЅР° сервер print(f"Начало отправки данных для заявки {self.id}") + print('args: ', "109.71.247.8", + "root", + "s7+DMtcoXC5prR", + self.file_path, + f'DATA_FROM_MAIN_SERVER/{self.user.username}', + self.file_path, + self.req_parameters, + "queue_scripts/venv" ) + + upload_file_and_add_task( + server_ip="109.71.247.8", + username="root", + password="s7+DMtcoXC5prR", + local_file_path=self.file_path, + remote_dir=f'DATA_FROM_MAIN_SERVER/{self.user.username}', + remote_file_name=os.path.basename(self.file_path), + params=self.req_parameters, + venv_path="queue_scripts/venv", # Путь Рє виртуальному окружению РЅР° внешнем сервере + req_id=self.id + ) + + + time.sleep(5) # Симуляция задержки print(f"Данные для заявки {self.id} отправлены РЅР° сервер.") diff --git a/movere_local/mainapp/templates/mainapp/create_3d_model.html b/movere_local/mainapp/templates/mainapp/create_3d_model.html index f554c8ec6366243de359e03ce7499267365693a3..434da854a3855bae871b30686305e566d336c1f1 100644 --- a/movere_local/mainapp/templates/mainapp/create_3d_model.html +++ b/movere_local/mainapp/templates/mainapp/create_3d_model.html @@ -3,11 +3,245 @@ <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>Создать РЅРѕРІСѓСЋ 3D модель</title> + <title>MOVERE | Новая 3D модель</title> <style> + {% load static %} + @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap'); + @import url('https://fonts.googleapis.com/css2?family=Krona+One&display=swap'); + @import url('https://fonts.googleapis.com/css2?family=Mulish:wght@200..1000&display=swap'); + + .navbar { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + background-color: #121212; /* Цвет РІ тон страницы */ + padding: 30px 20px; + position: fixed; + top: 0; + z-index: 10; + /* box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); */ + } + .navbar .logo { + display: flex; /* Располагает элементы (логотип Рё текст) РІ РѕРґРЅСѓ строку */ + align-items: center; /* Вертикальное выравнивание элементов РїРѕ центру */ + margin-left: 100px; + margin-top: 20px; + /* margin-left: 30px; */ + } + .navbar .logo img { + height: 60px; /* Размер логотипа */ + margin-right: 15px; /* Отступ между логотипом Рё текстом */ + } + .navbar .logo span { + font-size: 20px; /* Размер текста */ + font-weight: bold; + color: #FFFFFF; /* Цвет текста */ + white-space: nowrap; /* Запрещает перенос текста РЅР° РЅРѕРІСѓСЋ строку */ + } + .navbar .profile-btn { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Mulish", sans-serif; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + .navbar .profile-btn:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + .navbar .storage_home_button { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Roboto", sans-serif; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + .navbar .storage_home_button:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + .navbar .btns_in_nav { + display: flex; + margin-right: 10%; + } + .navbar .btns_in_nav { + display: flex; + margin-right: 10%; + } + + + + + + h1 { + font-family: 'Mulish', Arial, sans-serif; + align-self: flex-start; + /* margin-left: 10%; РЎРґРІРёРі текста "3D LAB" влево */ + } + + + + + body { + margin: 0; + font-family: "Krona One", serif; + font-weight: 400; + font-style: normal; + background-color: #121212; + color: #FFFFFF; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100vh; + } + +.container { + display: flex; + flex-direction: column; + flex: 1; /* Занимает оставшееся пространство между навбаром Рё футером */ + width: 80%; /* РЁРёСЂРёРЅР° контента */ + max-width: 1200px; + margin: 15% auto; /* Центрирование контента */ + padding-bottom: 20px; /* Отступ РѕС‚ последнего элемента РґРѕ футера */ + padding-top: 15%; + font-family: 'Mulish', Arial, sans-serif; + +} + +.footer { + width: 100%; /* Футер растягивается РЅР° РІСЃСЋ ширину */ + text-align: center; + /* padding: 10px 20px; Внутренние отступы */ + background-color: #121212; /* Цвет фона футера */ + color: #888; /* Цвет текста */ + font-size: 12px; + margin-top: auto; /* Футер перемещается РІ самый РЅРёР· */ + margin-bottom: 20px; +} + /* .footer a { + color: #888; + text-decoration: none; + } + .footer a:hover { + color: #FFFFFF; + } */ + + + + + + .card { + background-color: #1E1E1E; /* Фон карточки */ + border-radius: 10px; /* Скругленные углы */ + padding: 20px; /* Внутренние отступы */ + margin-bottom: 20px; /* Отступ между карточками */ + box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.2); /* Легкая тень */ + } + + .card label { + font-family: 'Mulish', Arial, sans-serif; + font-size: 16px; + color: #FFFFFF; /* Цвет текста */ + display: block; + margin-bottom: 10px; /* Отступ РѕС‚ текста РґРѕ поля */ + } + .card input, + /* .card textarea, */ + .card select { + width: 100%; /* Растянуть поле РЅР° РІСЃСЋ ширину карточки */ + padding: 10px; + border-radius: 5px; + border: 1px solid #333333; /* Тонкая рамка */ + background-color: #121212; /* Фон поля */ + color: #FFFFFF; /* Цвет текста */ + font-family: 'Mulish', sans-serif; + font-size: 14px; + } + .card input[type="radio"], + .card input[type="checkbox"] { + width: auto; /* Убираем ширину для радио Рё чекбоксов */ + } + .card legend { + font-size: 16px; + color: #FFFFFF; + margin-bottom: 10px; + font-family: 'Mulish', sans-serif; + } + .card textarea { + + width: 98%; /* Заполнение карточки РїРѕ ширине */ + height: 120px; /* Фиксированная высота */ + margin: 0 auto; /* Центрирование РїРѕ горизонтали */ + display: block; /* Убирает лишнее пространство РІРѕРєСЂСѓРі */ + padding: 10px; + border-radius: 5px; /* Скругленные углы */ + border: 1px solid #333333; /* Рамка */ + background-color: #121212; /* Фон */ + color: #FFFFFF; /* Цвет текста */ + font-family: 'Mulish', sans-serif; + font-size: 14px; /* Размер текста */ + resize: none; /* Запрещаем изменение размера */ + } + + .card button[type="submit"] { + width: 100%; + padding: 10px; + border: none; + border-radius: 20px; + background-color: #8d53ff; + color: white; + font-size: 16px; + cursor: pointer; + font-family: 'Mulish', sans-serif; + transition: transform 0.2s, background-color 0.2s; /* Анимация */ + } + + .card button[type="submit"]:hover { + background-color: #9e6dff; /* Легкое осветление */ + transform: scale(1.01); /* Увеличение РїСЂРё наведении */ + } + + .card button[type="submit"]:active { + background-color: #9e6dff; /* Еще большее осветление */ + transform: scale(1.01); /* Увеличение РїСЂРё клике */ + } + .hidden { display: none; } </style> <script> + function validateFileInput(event) { + const fileInput = event.target; // Получаем поле РІРІРѕРґР° файла + const file = fileInput.files[0]; // Берем первый выбранный файл + + if (file) { + const fileName = file.name.toLowerCase(); // РРјСЏ файла РІ нижнем регистре + // Допустимые расширения + const allowedExtensions = ['.jpg', '.jpeg', '.png']; + // Проверка, заканчивается ли РёРјСЏ файла РЅР° РѕРґРЅРѕ РёР· допустимых расширений + const isValidExtension = allowedExtensions.some(extension => fileName.endsWith(extension)); + + if (!isValidExtension) { + alert('Допустимы только файлы СЃ расширениями: .jpg, .jpeg, .png !'); + fileInput.value = ''; // Очищаем поле + } + } + } function toggleFields() { const choice = document.querySelector('input[name="file_choice"]:checked').value; document.getElementById('storage_fields').style.display = (choice === 'storage') ? 'block' : 'none'; @@ -23,43 +257,79 @@ </script> </head> <body> - <h1>Создать РЅРѕРІСѓСЋ 3D модель</h1> - <button onclick="location.href='{% url 'home' %}'">Домой</button> - - <form method="post" enctype="multipart/form-data"> - {% csrf_token %} - <p> - <label for="id_req_parameters">Параметры заказа:</label> - <textarea name="req_parameters" cols="40" rows="10" required="" id="id_req_parameters"></textarea> - </p> - - <p> - <label>Выбор файла:</label> - <div id="file_choice"> - <label for="id_file_choice_0"> - <input type="radio" name="file_choice" value="storage" required="" id="id_file_choice_0"> - Загрузить РёР· хранилища - </label> - <label for="id_file_choice_1"> - <input type="radio" name="file_choice" value="upload" required="" id="id_file_choice_1"> - Загрузить файл вручную - </label> + <div class="navbar"> + <div class="logo"> + <a href="{% url 'home' %}" style="text-decoration: none; color: inherit; display: flex; align-items: center;"> + <img src="{% static 'mainapp/images/download.png' %}" alt="Logo"> + <span>MOVERELAB</span> + </a> + </div> + <div class="btns_in_nav"> + <button class="profile-btn" onclick="location.href='{% url 'home' %}'">Домой</button> + <button class="profile-btn" onclick="location.href='{% url 'profile' %}'">Профиль</button> + </div> + </div> + + + <div class="container"> + <h1>РќРћР’РђРЇ 3D МОДЕЛЬ</h1> + + + <form method="post" enctype="multipart/form-data"> + {% csrf_token %} + <!-- <p> + <label for="id_req_parameters">Параметры заказа:</label> + <textarea name="req_parameters" cols="40" rows="10" required="" id="id_req_parameters"></textarea> --> + <!-- </p> --> + <div class="card"> + <label for="id_req_parameters">Комментарии Рє модели</label> + <textarea name="req_parameters" id="id_req_parameters" placeholder="Введите текст..."></textarea> + </div> + + <div class="card"> + <label>Выбор файла:</label> + <div id="file_choice"> + {{ form.file_choice }} + </div> + </div> + + <!-- Поле выбора РёР· хранилища --> + <div class="card hidden" id="storage_fields"> + <legend>Выберите файл РёР· хранилища</legend> + {{ form.storage_item }} + </div> + + <!-- Поле загрузки файла --> + <div class="card hidden" id="upload_fields"> + <legend>Рли загрузите файл</legend> + + <!-- {{ form.upload_file }} --> + <input type="file" id="upload_file" name="upload_file" onchange="validateFileInput(event)" accept=".jpg,.jpeg,.png"> + + </div> + + <!-- <fieldset id="storage_fields" class="hidden"> + <legend>Выберите файл РёР· хранилища</legend> + {{ form.storage_item }} + </fieldset> + + <fieldset id="upload_fields" class="hidden"> + <legend>Рли загрузите файл</legend> + {{ form.upload_file }} + </fieldset> --> + + <div class="card"> + <button type="submit"> + Создать 3D модель + </button> </div> - </p> + </form> - <fieldset id="storage_fields" class="hidden"> - <legend>Выберите файл РёР· хранилища</legend> - {{ form.storage_item }} - </fieldset> + - <fieldset id="upload_fields" class="hidden"> - <legend>Рли загрузите файл</legend> - {{ form.upload_file }} - </fieldset> + </div> - <button type="submit">Создать 3D модель</button> - </form> - <a href="{% url 'view_editrequests' %}">Назад Рє СЃРїРёСЃРєСѓ заказов</a> + <div class="footer">(C) MOVERELAB</div> </body> </html> diff --git a/movere_local/mainapp/templates/mainapp/create_order.html b/movere_local/mainapp/templates/mainapp/create_order.html index 7058f9f2e972221818794b00a4bd68510826b59a..8ea2ada8db729301b9fde9f57633775645a86ee8 100644 --- a/movere_local/mainapp/templates/mainapp/create_order.html +++ b/movere_local/mainapp/templates/mainapp/create_order.html @@ -3,11 +3,245 @@ <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>Создать новый заказ</title> + <title>MOVERE | Новая Заявка</title> <style> + {% load static %} + @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap'); + @import url('https://fonts.googleapis.com/css2?family=Krona+One&display=swap'); + @import url('https://fonts.googleapis.com/css2?family=Mulish:wght@200..1000&display=swap'); + + + .navbar { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + background-color: #121212; /* Цвет РІ тон страницы */ + padding: 30px 20px; + position: fixed; + top: 0; + z-index: 10; + /* box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); */ + } + .navbar .logo { + display: flex; /* Располагает элементы (логотип Рё текст) РІ РѕРґРЅСѓ строку */ + align-items: center; /* Вертикальное выравнивание элементов РїРѕ центру */ + margin-left: 100px; + margin-top: 20px; + /* margin-left: 30px; */ + } + .navbar .logo img { + height: 60px; /* Размер логотипа */ + margin-right: 15px; /* Отступ между логотипом Рё текстом */ + } + .navbar .logo span { + font-size: 20px; /* Размер текста */ + font-weight: bold; + color: #FFFFFF; /* Цвет текста */ + white-space: nowrap; /* Запрещает перенос текста РЅР° РЅРѕРІСѓСЋ строку */ + } + .navbar .profile-btn { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Mulish", sans-serif; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + .navbar .profile-btn:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + .navbar .storage_home_button { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Mulish", sans-serif; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + .navbar .storage_home_button:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + .navbar .btns_in_nav { + display: flex; + margin-right: 10%; + } + /* .navbar .btns_in_nav { + display: flex; + margin-right: 10%; + } */ + + + + + + h1 { + font-family: 'Mulish', Arial, sans-serif; + align-self: flex-start; + /* margin-left: 10%; РЎРґРІРёРі текста "3D LAB" влево */ + } + + + + + body { + margin: 0; + font-family: "Krona One", serif; + font-weight: 400; + font-style: normal; + background-color: #121212; + color: #FFFFFF; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100vh; + } + +.container { + display: flex; + flex-direction: column; + flex: 1; /* Занимает оставшееся пространство между навбаром Рё футером */ + width: 80%; /* РЁРёСЂРёРЅР° контента */ + max-width: 1200px; + margin: 15% auto; /* Центрирование контента */ + padding-bottom: 20px; /* Отступ РѕС‚ последнего элемента РґРѕ футера */ + padding-top: 50%; +} + +.footer { + width: 100%; /* Футер растягивается РЅР° РІСЃСЋ ширину */ + text-align: center; + /* padding: 10px 20px; Внутренние отступы */ + background-color: #121212; /* Цвет фона футера */ + color: #888; /* Цвет текста */ + font-size: 12px; + margin-top: auto; /* Футер перемещается РІ самый РЅРёР· */ + margin-bottom: 20px; +} + /* .footer a { + color: #888; + text-decoration: none; + } + .footer a:hover { + color: #FFFFFF; + } */ + + + + + + .card { + background-color: #1E1E1E; /* Фон карточки */ + border-radius: 10px; /* Скругленные углы */ + padding: 20px; /* Внутренние отступы */ + margin-bottom: 20px; /* Отступ между карточками */ + box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.2); /* Легкая тень */ + } + + .card label { + font-family: 'Mulish', Arial, sans-serif; + font-size: 16px; + color: #FFFFFF; /* Цвет текста */ + display: block; + margin-bottom: 10px; /* Отступ РѕС‚ текста РґРѕ поля */ + } + .card input, + /* .card textarea, */ + .card select { + width: 100%; /* Растянуть поле РЅР° РІСЃСЋ ширину карточки */ + padding: 10px; + border-radius: 5px; + border: 1px solid #333333; /* Тонкая рамка */ + background-color: #121212; /* Фон поля */ + color: #FFFFFF; /* Цвет текста */ + font-family: 'Mulish', sans-serif; + font-size: 14px; + } + .card input[type="radio"], + .card input[type="checkbox"] { + width: auto; /* Убираем ширину для радио Рё чекбоксов */ + } + .card legend { + font-family: 'Mulish', sans-serif; + font-size: 16px; + color: #FFFFFF; + margin-bottom: 10px; + } + .card textarea { + width: 98%; /* Заполнение карточки РїРѕ ширине */ + height: 120px; /* Фиксированная высота */ + margin: 0 auto; /* Центрирование РїРѕ горизонтали */ + display: block; /* Убирает лишнее пространство РІРѕРєСЂСѓРі */ + padding: 10px; + border-radius: 5px; /* Скругленные углы */ + border: 1px solid #333333; /* Рамка */ + background-color: #121212; /* Фон */ + color: #FFFFFF; /* Цвет текста */ + font-family: 'Mulish', sans-serif; + font-size: 14px; /* Размер текста */ + resize: none; /* Запрещаем изменение размера */ + } + + .card button[type="submit"] { + width: 100%; + padding: 10px; + border: none; + border-radius: 20px; + background-color: #8d53ff; + color: white; + font-size: 16px; + cursor: pointer; + font-family: 'Mulish', sans-serif; + transition: transform 0.2s, background-color 0.2s; /* Анимация */ + } + + .card button[type="submit"]:hover { + background-color: #9e6dff; /* Легкое осветление */ + transform: scale(1.01); /* Увеличение РїСЂРё наведении */ + } + + .card button[type="submit"]:active { + background-color: #9e6dff; /* Еще большее осветление */ + transform: scale(1.01); /* Увеличение РїСЂРё клике */ + } + .hidden { display: none; } + </style> <script> + + function validateFileInput(event) { + const fileInput = event.target; // Получаем поле РІРІРѕРґР° файла + const file = fileInput.files[0]; // Берем первый выбранный файл + + if (file) { + const fileName = file.name.toLowerCase(); // РРјСЏ файла РІ нижнем регистре + // Допустимые расширения + const allowedExtensions = ['.obj', '.stl', '.step', '.3mf']; + // Проверка, заканчивается ли РёРјСЏ файла РЅР° РѕРґРЅРѕ РёР· допустимых расширений + const isValidExtension = allowedExtensions.some(extension => fileName.endsWith(extension)); + + if (!isValidExtension) { + alert('Допустимы только файлы СЃ расширениями: .obj, .stl, .step, .3mf!'); + fileInput.value = ''; // Очищаем поле + } + } + } function toggleFields() { const choice = document.querySelector('input[name="file_choice"]:checked').value; document.getElementById('storage_fields').style.display = (choice === 'storage') ? 'block' : 'none'; @@ -23,43 +257,84 @@ </script> </head> <body> - <h1>Создать новый заказ</h1> - <button onclick="location.href='{% url 'home' %}'">Домой</button> - - <form method="post" enctype="multipart/form-data"> - {% csrf_token %} - <p> - <label for="id_order_parameters">Параметры заказа:</label> - <textarea name="order_parameters" cols="40" rows="10" required="" id="id_order_parameters"></textarea> - </p> - - <p> - <label>Выбор файла:</label> - <div id="file_choice"> - <label for="id_file_choice_0"> - <input type="radio" name="file_choice" value="storage" required="" id="id_file_choice_0"> - Загрузить РёР· хранилища - </label> - <label for="id_file_choice_1"> - <input type="radio" name="file_choice" value="upload" required="" id="id_file_choice_1"> - Загрузить файл вручную - </label> + <div class="navbar"> + <div class="logo"> + <a href="{% url 'home' %}" style="text-decoration: none; color: inherit; display: flex; align-items: center;"> + <img src="{% static 'mainapp/images/download.png' %}" alt="Logo"> + <span>MOVERELAB</span> + </a> + </div> + <div class="btns_in_nav"> + <button class="profile-btn" onclick="location.href='{% url 'home' %}'">Домой</button> + <button class="profile-btn" onclick="location.href='{% url 'profile' %}'">Профиль</button> + </div> + </div> + + <div class="container"> + <h1>РќРћР’РђРЇ Р—РђРЇР’РљРђ</h1> + + <form method="post" enctype="multipart/form-data"> + {% csrf_token %} + + <!-- Карточка для должности --> + <div class="card"> + <label>Ваша должность:</label> + {{ form.position }} + </div> + + <!-- Карточка для цели 3D-печати --> + <div class="card"> + <label>Цель 3D-печати:</label> + {{ form.purpose }} + </div> + + <!-- Карточка для дополнительной цели --> + <div class="card"> + <label for="id_additional_purpose">Дополнительно РјРѕР¶РЅРѕ указать цель 3D-печати:</label> + <textarea name="additional_purpose" id="id_additional_purpose" placeholder="Введите текст..."></textarea> + </div> + + <!-- Карточка для выбора материала --> + <div class="card"> + <label>Выберите материал:</label> + {{ form.material }} </div> - </p> - <fieldset id="storage_fields" class="hidden"> - <legend>Выберите файл РёР· хранилища</legend> - {{ form.storage_item }} - </fieldset> + <!-- Карточка для выбора файла --> + <div class="card"> + <label>Выбор файла:</label> + <div id="file_choice"> + {{ form.file_choice }} + </div> + </div> + + <!-- Поле выбора РёР· хранилища --> + <div class="card hidden" id="storage_fields"> + <legend>Выберите файл РёР· хранилища</legend> + {{ form.storage_item }} + </div> + + <!-- Поле загрузки файла --> + <div class="card hidden" id="upload_fields"> + <legend>Рли загрузите файл</legend> + + <!-- {{ form.upload_file }} --> + <input type="file" id="upload_file" name="upload_file" onchange="validateFileInput(event)" accept=".obj,.stl,.step,.3mf"> + + </div> + + <!-- РљРЅРѕРїРєР° отправки --> + <div class="card"> + <button type="submit"> + Создать заявку + </button> + </div> + </form> + </div> - <fieldset id="upload_fields" class="hidden"> - <legend>Рли загрузите файл</legend> - {{ form.upload_file }} - </fieldset> + <!-- <a href="{% url 'view_orders' %}">Назад Рє СЃРїРёСЃРєСѓ заявок</a> --> + <div class="footer">(C) MOVERELAB</div> - <button type="submit">Создать заказ</button> - </form> - <a href="{% url 'view_orders' %}">Назад Рє СЃРїРёСЃРєСѓ заказов</a> </body> </html> diff --git a/movere_local/mainapp/templates/mainapp/home.html b/movere_local/mainapp/templates/mainapp/home.html index f078a0702ba6754b1014da58072177fe889f73a7..e17e7605b9ed700ecfe0c925b22d2908632b690b 100644 --- a/movere_local/mainapp/templates/mainapp/home.html +++ b/movere_local/mainapp/templates/mainapp/home.html @@ -1,4 +1,3 @@ -<!-- @@ -8,48 +7,16 @@ <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>Home</title> - {% load static %} Загрузка тега static - <link rel="stylesheet" href="{% static 'mainapp/css/styles.css' %}"> -</head> -<body> - <h1>Добро пожаловать!</h1> - - - - {% if is_manager %} - <button onclick="location.href='{% url 'manager_dashboard' %}'">Панель менеджера</button> - {% else %} - - - - <button onclick="location.href='{% url 'view_orders' %}'">Заказы</button> - <button onclick="location.href='{% url 'storage' %}'">Хранилище</button> - <button onclick="location.href='{% url 'view_archive' %}'">РђСЂС…РёРІ</button> - <button onclick="location.href='{% url 'create3d' %}'">Создать 3D!</button> - <button onclick="location.href='{% url 'home' %}'">Домой</button> - - {% endif %} - <button onclick="location.href='{% url 'profile' %}'">Профиль</button> -</body> -</html> ---> - - - - -<!DOCTYPE html> -<html lang="en"> -<head> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>Home</title> + <title>MOVERE | Home </title> <style> {% load static %} @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Krona+One&display=swap'); - + @import url('https://fonts.googleapis.com/css2?family=Mulish:wght@200..1000&display=swap'); + a { + text-decoration: none; + } .navbar { display: flex; justify-content: space-between; @@ -66,12 +33,14 @@ .navbar .logo { display: flex; /* Располагает элементы (логотип Рё текст) РІ РѕРґРЅСѓ строку */ align-items: center; /* Вертикальное выравнивание элементов РїРѕ центру */ + margin-left: 100px; + margin-top: 20px; /* margin-left: 30px; */ } .navbar .logo img { height: 60px; /* Размер логотипа */ - margin-right: 10px; /* Отступ между логотипом Рё текстом */ + margin-right: 15px; /* Отступ между логотипом Рё текстом */ } .navbar .logo span { @@ -81,12 +50,13 @@ white-space: nowrap; /* Запрещает перенос текста РЅР° РЅРѕРІСѓСЋ строку */ } + .navbar .profile-btn { - background-color: transparent; /* Прозрачный фон */ + background-color: rgb(45, 42, 42);/* Прозрачный фон */ color: #FFFFFF; border: 1px solid #ffffff00; /* Белая рамка */ padding: 15px 30px; /* Увеличенный внутренний отступ */ - font-family: "Roboto", sans-serif; + font-family: "Mulish", sans-serif; /* font-weight: bold; */ font-size: 16px; /* Увеличенный размер шрифта */ border-radius: 20px; /* Скругленные углы */ @@ -97,9 +67,35 @@ } .navbar .profile-btn:hover { - background-color: rgba(255, 255, 255, 0.2); /* Полупрозрачный белый РїСЂРё наведении */ + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + + .navbar .storage_home_button { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Mulish", sans-serif; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + + .navbar .storage_home_button:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ } + + + .navbar .btns_in_nav { + display: flex; + margin-right: 10%; + } body { margin: 0; font-family: "Krona One", serif; @@ -123,35 +119,47 @@ display: flex; gap: 20px; } - + .card { - width: 300px; - height: 400px; - background-color: #3A3A3A; - border-radius: 10px; - display: flex; - flex-direction: column; - align-items: center; - justify-content: flex-end; - overflow: hidden; - position: relative; - cursor: pointer; - transition: transform 0.3s; - } - - .card:hover { - transform: scale(1.05); - } - - .card img { - width: 100%; - height: 100%; - object-fit: cover; - position: absolute; - top: 0; - left: 0; - z-index: 1; - } + position: relative; + width: 300px; + height: 400px; + background-color: #3A3A3A; + border-radius: 10px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-end; + overflow: hidden; + cursor: pointer; + transition: transform 0.3s; +} + +.card:hover { + transform: scale(1.05); +} + +.card svg { + position: absolute; + top: 20px; + left: 50%; + transform: translateX(-50%); + width: 80%; + height: 80%; +} + +.card svg .color-change { + fill: #ffffff; /* Начальный цвет */ + transition: fill 0.2s ease; /* Плавное изменение цвета */ +} + +.card svg .no-change { + fill: none; /* Оставляем как есть */ +} + +.card:hover svg .color-change { + fill: #8d53ff; /* Цвет РїСЂРё наведении */ +} .card video { width: 100%; @@ -170,11 +178,11 @@ .card .label { position: relative; - font-family: 'Roboto', Arial, sans-serif; + font-family: 'Mulish', Arial, sans-serif; color: #FFFFFF; padding: 5px 10px; border-radius: 5px; - font-size: 14px; + font-size: 20px; font-weight: bold; margin-bottom: 5px; text-align: center; @@ -182,12 +190,12 @@ } .card .description { - font-family: 'Roboto', Arial, sans-serif; + font-family: 'Mulish', Arial, sans-serif; position: relative; - color: #FFFFFF; + color: #c1c1c1; padding: 5px 10px; border-radius: 5px; - font-size: 12px; + font-size: 16px; text-align: center; margin-bottom: 10px; z-index: 3; @@ -235,38 +243,59 @@ <div class="container"> {% if is_manager %} - <button onclick="location.href='{% url 'manager_dashboard' %}'">Панель менеджера</button> + <div class="card"> + <a href="{% url 'manager_dashboard' %}" class="card"> + <svg width="250px" height="250px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <path class="color-change" d="M15.2 6l-1.1-0.2c-0.1-0.2-0.1-0.4-0.2-0.6l0.6-0.9 0.5-0.7-2.6-2.6-0.7 0.5-0.9 0.6c-0.2-0.1-0.4-0.1-0.6-0.2l-0.2-1.1-0.2-0.8h-3.6l-0.2 0.8-0.2 1.1c-0.2 0.1-0.4 0.1-0.6 0.2l-0.9-0.6-0.7-0.4-2.5 2.5 0.5 0.7 0.6 0.9c-0.2 0.2-0.2 0.4-0.3 0.6l-1.1 0.2-0.8 0.2v3.6l0.8 0.2 1.1 0.2c0.1 0.2 0.1 0.4 0.2 0.6l-0.6 0.9-0.5 0.7 2.6 2.6 0.7-0.5 0.9-0.6c0.2 0.1 0.4 0.1 0.6 0.2l0.2 1.1 0.2 0.8h3.6l0.2-0.8 0.2-1.1c0.2-0.1 0.4-0.1 0.6-0.2l0.9 0.6 0.7 0.5 2.6-2.6-0.5-0.7-0.6-0.9c0.1-0.2 0.2-0.4 0.2-0.6l1.1-0.2 0.8-0.2v-3.6l-0.8-0.2zM15 9l-1.7 0.3c-0.1 0.5-0.3 1-0.6 1.5l0.9 1.4-1.4 1.4-1.4-0.9c-0.5 0.3-1 0.5-1.5 0.6l-0.3 1.7h-2l-0.3-1.7c-0.5-0.1-1-0.3-1.5-0.6l-1.4 0.9-1.4-1.4 0.9-1.4c-0.3-0.5-0.5-1-0.6-1.5l-1.7-0.3v-2l1.7-0.3c0.1-0.5 0.3-1 0.6-1.5l-1-1.4 1.4-1.4 1.4 0.9c0.5-0.3 1-0.5 1.5-0.6l0.4-1.7h2l0.3 1.7c0.5 0.1 1 0.3 1.5 0.6l1.4-0.9 1.4 1.4-0.9 1.4c0.3 0.5 0.5 1 0.6 1.5l1.7 0.3v2z"></path> + <path class="color-change" d="M8 4.5c-1.9 0-3.5 1.6-3.5 3.5s1.6 3.5 3.5 3.5 3.5-1.6 3.5-3.5c0-1.9-1.6-3.5-3.5-3.5zM8 10.5c-1.4 0-2.5-1.1-2.5-2.5s1.1-2.5 2.5-2.5 2.5 1.1 2.5 2.5c0 1.4-1.1 2.5-2.5 2.5z"></path> + </svg> + <div class="label">ПАНЕЛЬ МЕНЕДЖЕРА</div> + <div class="description">Р’СЃРµ заявки РЅР° 3D печать Рё управление РёРјРё </div> + </a> + </div> + {% else %} - - <a href="{% url 'create_order' %}" class="card"> - <img src="{% static 'mainapp/images/tunder.png' %}" alt="Preview"> - <video src="{% static 'mainapp/images/purple_tunder.mp4' %}" muted data-playing="false"></video> - <div class="label">НАПЕЧАТАТЬ</div> - <div class="description">Отправить заявку РЅР° печать РЅР° 3D принтере</div> - </a> + <div class="card"> + <a href="{% url 'create_order' %}" class="card"> + <svg width="250px" height="250px" viewBox="0 0 256 256" id="Flat" xmlns="http://www.w3.org/2000/svg"> + <path class="color-change" d="M226.40723,72.72314c-.0127-.02368-.01856-.04907-.03223-.07251-.00391-.00732-.00977-.01293-.01416-.02026a11.99344,11.99344,0,0,0-4.47754-4.41064l-88-49.5a12.07124,12.07124,0,0,0-11.7666,0l-88,49.5a11.99326,11.99326,0,0,0-4.48389,4.42334c-.00586.01025-.01367.01782-.01953.02783-.01416.02588-.02051.05347-.03418.07959A11.98438,11.98438,0,0,0,28,78.67871v98.64258a12.01534,12.01534,0,0,0,6.1167,10.459l88.00049,49.5a11.97922,11.97922,0,0,0,5.606,1.51343c.085.0061.16553.02686.252.02759h.03613c.1001,0,.19434-.022.293-.0293a11.98372,11.98372,0,0,0,5.5791-1.51172l88-49.5A12.01534,12.01534,0,0,0,228,177.32129V78.67871A11.98919,11.98919,0,0,0,226.40723,72.72314ZM126.03906,25.69238a4.02317,4.02317,0,0,1,3.92188,0l85.91113,48.32471-86.94238,49.39355L40.18945,73.98291Zm-88,155.11524A4.00514,4.00514,0,0,1,36,177.32129V80.80664l88.92822,49.53223-.86865,98.85547Zm179.92188,0-85.90039,48.31909.86816-98.78711L220,80.87305v96.44824A4.00514,4.00514,0,0,1,217.96094,180.80762Z"/> + </svg> + <div class="label">НАПЕЧАТАТЬ</div> + <div class="description">Отправить заявку РЅР° печать РЅР° 3D принтере</div> + </a> + </div> + <div class="card"> <a href="{% url 'create3d' %}" class="card"> - <!-- <img src="{% static 'mainapp/images/store.png' %}" alt="Preview"> --> - <!-- <video src="{% static 'mainapp/images/store.mp4' %}" muted data-playing="false"></video> --> + <svg width="250px" height="250px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path class="color-change" fill-rule="evenodd" clip-rule="evenodd" d="M12.5 6.00004C12.5 5.31322 12.2163 4.67366 11.7431 4.25578C11.2602 3.82926 10.5847 3.64296 9.87881 3.88387C9.12643 4.14065 8.27977 4.57906 7.61885 5.33233C7.12428 5.89599 6.74984 6.61798 6.58793 7.53045C5.74098 7.65664 5.00843 8.16524 4.47868 8.87157C3.86487 9.68999 3.5 10.7977 3.5 12C3.5 13.2023 3.86487 14.31 4.47868 15.1284C4.99276 15.8139 5.69782 16.3131 6.51308 16.4574C6.50452 16.494 6.5 16.5322 6.5 16.5715C6.5 17.7099 6.9821 18.5424 7.66175 19.1267C8.32466 19.6965 9.1633 20.0221 9.89841 20.212C11.366 20.5912 12.5 19.3418 12.5 18V6.00004ZM7.48691 16.4573C7.49547 16.494 7.5 16.5322 7.5 16.5715C7.5 17.3882 7.83089 17.9534 8.31361 18.3683C8.81308 18.7977 9.48618 19.0727 10.1486 19.2438C10.8199 19.4173 11.5 18.8674 11.5 18V6.00004C11.5 5.58229 11.3265 5.22198 11.0812 5.00533C10.8456 4.79731 10.5413 4.71442 10.2018 4.83027C9.55295 5.05172 8.87946 5.41182 8.37053 5.99186C7.87016 6.56214 7.5 7.37709 7.5 8.57147C7.5 8.84761 7.27614 9.07147 7 9.07147C6.72388 9.07147 6.50003 8.84764 6.5 8.57152C6.04804 8.70228 5.62513 9.00964 5.27868 9.47157C4.80671 10.1009 4.5 10.9932 4.5 12C4.5 13.0068 4.80671 13.8991 5.27868 14.5284C5.75054 15.1576 6.36424 15.5 7 15.5C7.59053 15.5 8.15996 15.2055 8.61676 14.6603C8.79412 14.4487 9.10948 14.4209 9.32114 14.5982C9.53279 14.7756 9.5606 15.091 9.38324 15.3026C8.88463 15.8976 8.23125 16.3255 7.48691 16.4573Z"/> + <path class="color-change" fill-rule="evenodd" clip-rule="evenodd" d="M16.55 11.5H14.5C14.2239 11.5 14 11.7239 14 12C14 12.2761 14.2239 12.5 14.5 12.5H16.55C16.7816 13.6411 17.7905 14.5 19 14.5C20.3807 14.5 21.5 13.3807 21.5 12C21.5 10.6193 20.3807 9.5 19 9.5C17.7905 9.5 16.7816 10.3589 16.55 11.5ZM17.5 11.9963C17.502 11.1695 18.1728 10.5 19 10.5C19.8284 10.5 20.5 11.1716 20.5 12C20.5 12.8284 19.8284 13.5 19 13.5C18.1728 13.5 17.502 12.8305 17.5 12.0037L17.5 12L17.5 11.9963Z"/> + <path class="color-change" fill-rule="evenodd" clip-rule="evenodd" d="M17.3385 16.132C17.7802 15.7388 18.3622 15.5 19 15.5C20.3807 15.5 21.5 16.6193 21.5 18C21.5 19.3807 20.3807 20.5 19 20.5C17.6193 20.5 16.5 19.3807 16.5 18C16.5 17.6162 16.5865 17.2527 16.741 16.9277C16.7227 16.9166 16.7049 16.9042 16.6877 16.8904L14.1877 14.8904C13.972 14.7179 13.9371 14.4033 14.1096 14.1877C14.2821 13.972 14.5967 13.9371 14.8124 14.1096L17.3124 16.1096C17.3214 16.1168 17.3301 16.1243 17.3385 16.132ZM19 16.5C18.1716 16.5 17.5 17.1716 17.5 18C17.5 18.8284 18.1716 19.5 19 19.5C19.8284 19.5 20.5 18.8284 20.5 18C20.5 17.1716 19.8284 16.5 19 16.5Z" /> + <path class="color-change" fill-rule="evenodd" clip-rule="evenodd" d="M19 3.5C17.6193 3.5 16.5 4.61929 16.5 6C16.5 6.38376 16.5865 6.74733 16.741 7.07228C16.7227 7.08341 16.7049 7.09584 16.6877 7.10958L14.1877 9.10958C13.972 9.28209 13.9371 9.59674 14.1096 9.81237C14.2821 10.028 14.5967 10.063 14.8124 9.89045L17.3124 7.89045C17.3214 7.88323 17.3301 7.87575 17.3385 7.86804C17.7802 8.26116 18.3622 8.5 19 8.5C20.3807 8.5 21.5 7.38071 21.5 6C21.5 4.61929 20.3807 3.5 19 3.5ZM17.5 6C17.5 5.17157 18.1716 4.5 19 4.5C19.8284 4.5 20.5 5.17157 20.5 6C20.5 6.82843 19.8284 7.5 19 7.5C18.1716 7.5 17.5 6.82843 17.5 6Z" /> + </svg> <div class="label">СОЗДАТЬ</div> <div class="description">Сгенерировать 3D модель РїСЂРё помощи РР</div> </a> </div> <div class="card"> <a href="{% url 'redactor' %}" class="card"> - <!-- <img src="{% static 'mainapp/images/store.png' %}" alt="Preview"> --> - <!-- <video src="{% static 'mainapp/images/store.mp4' %}" muted data-playing="false"></video> --> + <svg width="250px" height="250px" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"> + <path class="color-change" d="M832 512a32 32 0 1 1 64 0v352a32 32 0 0 1-32 32H160a32 32 0 0 1-32-32V160a32 32 0 0 1 32-32h352a32 32 0 0 1 0 64H192v640h640V512z"/> + <path class="color-change" d="m469.952 554.24 52.8-7.552L847.104 222.4a32 32 0 1 0-45.248-45.248L477.44 501.44l-7.552 52.8zm422.4-422.4a96 96 0 0 1 0 135.808l-331.84 331.84a32 32 0 0 1-18.112 9.088L436.8 623.68a32 32 0 0 1-36.224-36.224l15.104-105.6a32 32 0 0 1 9.024-18.112l331.904-331.84a96 96 0 0 1 135.744 0z"/> + </svg> <div class="label">РЕДАКТРР РћР’РђРўР¬</div> <div class="description">Редактировать 3D модель РїСЂСЏРјРѕ РІ браузере</div> </a> </div> <div class="card"> <a href="{% url 'view_story_and_files' %}" class="card"> - <img src="{% static 'mainapp/images/store.png' %}" alt="Preview"> - <video src="{% static 'mainapp/images/store.mp4' %}" muted data-playing="false"></video> + <svg width="250px" height="250px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> + <path class="color-change" d="M9.5 2h-6A1.502 1.502 0 0 0 2 3.5v6A1.502 1.502 0 0 0 3.5 11h6A1.502 1.502 0 0 0 11 9.5v-6A1.502 1.502 0 0 0 9.5 2zm.5 7.5a.501.501 0 0 1-.5.5h-6a.501.501 0 0 1-.5-.5v-6a.501.501 0 0 1 .5-.5h6a.501.501 0 0 1 .5.5zM20.5 2h-6A1.502 1.502 0 0 0 13 3.5v6a1.502 1.502 0 0 0 1.5 1.5h6A1.502 1.502 0 0 0 22 9.5v-6A1.502 1.502 0 0 0 20.5 2zm.5 7.5a.501.501 0 0 1-.5.5h-6a.501.501 0 0 1-.5-.5v-6a.501.501 0 0 1 .5-.5h6a.501.501 0 0 1 .5.5zM9.5 13h-6A1.502 1.502 0 0 0 2 14.5v6A1.502 1.502 0 0 0 3.5 22h6a1.502 1.502 0 0 0 1.5-1.5v-6A1.502 1.502 0 0 0 9.5 13zm.5 7.5a.501.501 0 0 1-.5.5h-6a.501.501 0 0 1-.5-.5v-6a.501.501 0 0 1 .5-.5h6a.501.501 0 0 1 .5.5zM20.5 13h-6a1.502 1.502 0 0 0-1.5 1.5v6a1.502 1.502 0 0 0 1.5 1.5h6a1.502 1.502 0 0 0 1.5-1.5v-6a1.502 1.502 0 0 0-1.5-1.5zm.5 7.5a.501.501 0 0 1-.5.5h-6a.501.501 0 0 1-.5-.5v-6a.501.501 0 0 1 .5-.5h6a.501.501 0 0 1 .5.5z"/> + <path class="no-change" fill="none" d="M0 0h24v24H0z"/> + </svg> <div class="label">Р—РђРљРђР—Р« РФАЙЛЫ</div> - <div class="description">РЎРїРёСЃРѕРє заявок, запросов, файлов</div> + <div class="description">РЎРїРёСЃРѕРє заявок, запросов, хранилище Рё архив </div> </a> </div> diff --git a/movere_local/mainapp/templates/mainapp/manager_dashboard.html b/movere_local/mainapp/templates/mainapp/manager_dashboard.html index c03bf42bb556327d82098391eb39b11387d190d7..d871488fb910fc3623be615ed7e220eb3a219f84 100644 --- a/movere_local/mainapp/templates/mainapp/manager_dashboard.html +++ b/movere_local/mainapp/templates/mainapp/manager_dashboard.html @@ -5,28 +5,416 @@ <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Панель менеджера</title> <style> - table { + + {% load static %} + @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap'); + @import url('https://fonts.googleapis.com/css2?family=Krona+One&display=swap'); + @import url('https://fonts.googleapis.com/css2?family=Mulish:wght@200..1000&display=swap'); + + body { + margin: 0; + font-family: "Mulish", sans-serif; + font-weight: 400; + font-style: normal; + background-color: #121212; + color: #FFFFFF; + display: flex; + flex-direction: column; + align-items: center; + height: 100vh; + word-break: break-all; + } + + .navbar { + display: flex; + justify-content: space-between; + align-items: center; width: 100%; - border-collapse: collapse; + background-color: #121212; /* Цвет РІ тон страницы */ + padding: 30px 20px; + position: fixed; + top: 0; + z-index: 10; + word-break: normal; + /* box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); */ } - th, td { - border: 1px solid #ddd; - padding: 8px; - white-space: nowrap; + + .navbar .logo { + display: flex; /* Располагает элементы (логотип Рё текст) РІ РѕРґРЅСѓ строку */ + align-items: center; /* Вертикальное выравнивание элементов РїРѕ центру */ + margin-left: 100px; + margin-top: 20px; + /* margin-left: 30px; */ } - th { - background-color: #f2f2f2; + + .navbar .logo img { + height: 60px; /* Размер логотипа */ + margin-right: 15px; /* Отступ между логотипом Рё текстом */ } - th.sortable:hover { + + .navbar .logo span { + font-family: "Krona One", serif; + font-size: 20px; /* Размер текста */ + font-weight: bold; + color: #FFFFFF; /* Цвет текста */ + white-space: nowrap; /* Запрещает перенос текста РЅР° РЅРѕРІСѓСЋ строку */ + } + + + .navbar .profile-btn { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Mulish", sans-serif; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ } + + .navbar .profile-btn:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + + .navbar .storage_home_button { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Mulish", sans-serif; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + + .navbar .storage_home_button:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + + + .navbar .btns_in_nav { + display: flex; + margin-right: 10%; + } + + + + + .view_orders_h1 { + align-self: flex-start; /* Расположить элемент слева */ + /* margin: 20px; Отступы сверху Рё слева */ + color: rgb(255, 253, 253); + font-size: 20px; + font-family: "Mulish", sans-serif; + /* font-family: "Krona One", serif; */ + text-align: left; + margin-top: 10%; + padding: 0 5%; + + } + + + .container { + display: flex; + gap: 10px; + } + + + .card { + width: 200px; + height: 300px; + background-color: #3A3A3A; + border-radius: 10px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-end; + overflow: hidden; + position: relative; + cursor: pointer; + transition: transform 0.3s; + } + + .card:hover { + transform: scale(1.05); + } + + .card img { + width: 100%; + height: 100%; + object-fit: cover; + position: absolute; + top: 0; + left: 0; + z-index: 1; + } + + .card video { + width: 100%; + height: 100%; + object-fit: cover; + display: none; + position: absolute; + top: 0; + left: 0; + z-index: 2; + } + + .card video[data-playing="true"] { + display: block; + } + + .card .label { + position: relative; + font-family: 'Roboto', Arial, sans-serif; + color: #FFFFFF; + padding: 5px 10px; + border-radius: 5px; + font-size: 14px; + font-weight: bold; + margin-bottom: 5px; + text-align: center; + z-index: 3; + } + + .card .description { + font-family: 'Roboto', Arial, sans-serif; + position: relative; + color: #FFFFFF; + padding: 5px 10px; + border-radius: 5px; + font-size: 12px; + text-align: center; + margin-bottom: 10px; + z-index: 3; + } + + .home-button { + background-color: transparent; /* Фон РєРЅРѕРїРєРё прозрачный */ + position: absolute; + padding: 1px 1px; /* Отступы внутри РєРЅРѕРїРєРё */ + top: 7%; + right: 3%; + width: 7%; + font-size: 20px; + font-weight: 700; + color: rgb(247, 249, 250); /* Цвет текста */ + border: none; /* Убирает границу */ + outline: none; /* Убирает контур РїСЂРё фокусе */ + } + + .create-order-button { + display: block; + padding: 8px 16px; + background-color: transparent; + color: white; + font-size: 20px; + text-decoration: none; + border-radius: 5px; + text-align: center; + transition: background-color 0.3s; /* Добавляем плавную анимацию */ + z-index: 1000; /* Убедитесь, что РєРЅРѕРїРєР° будет РІРёРґРЅР° над РґСЂСѓРіРёРјРё элементами */ + } + + .create-order-button:hover { + background-color: #4a4646; /* меняем цвет фона РЅР° серый РїСЂРё наведении */ + + } + + .modal { + display: none; /* Скрытое РїРѕ умолчанию */ + position: fixed; /* Фиксийрованное положение */ + z-index: 1; /* Лежит над РґСЂСѓРіРёРјРё элементами */ + left: 0; + top: 0; + width: 100%; /* Полная ширина */ + height: 100%; /* Полная высота */ + overflow: auto; /* Включение прокрутки, если необходимо */ + background-color: rgb(0,0,0); /* Цвет фона */ + background-color: rgba(0,0,0,0.4); /* Черный фон СЃ небольшой прозрачностью */ +} + +.modal-content { + background-color: #ad8181; + margin: 15% auto; /* 15% сверху Рё РїРѕ центру РїРѕ горизонтали */ + padding: 20px; + border: 1px solid #888; + width: 50%; /* Можете изменить ширину */ +} + +.close { + color: #aaa; + float: right; + font-size: 28px; + font-weight: bold; +} + +.close:hover, +.close:focus { + color: black; + cursor: pointer; +} + + + + +table { + width: 90%; + table-layout: fixed; /* Фиксированная ширина колонок */ + border-collapse: collapse; + + + border-spacing: 0; + margin: 10px auto; + border-radius: 10px; + overflow: hidden; + background-color: #1e1e1e; +} + +th, td { + width: 20%; /* Устанавливаем одинаковую ширину для всех колонок */ + border-bottom: 1px solid #616161; + border-right: 0.5px solid #7b7b7b; + padding: 12px 15px; + color: #f0f0f0; + vertical-align: top; /* Содержимое РїРѕ верхнему краю */ +} + + th.sortable a { + text-decoration: none; /* Отменяем подчеркивание ссылок */ + color: white; /* Цвет текста ссылок */ + } + th:nth-child(1) { width: 5%; } + th:nth-child(2) { width: 12%; } + th:nth-child(3) { width: 15%; } + th:nth-child(4) { width: 19%; } + th:nth-child(5) { width: 19%; } + th:nth-child(6) { width: 10%; } + th:nth-child(7) { width: 10%; } + + + + th:last-child, td:last-child { + border-right: none; /* Убирает правую границу Сѓ последней колонки */ + width: 20%; + } + + + th { + background-color: #292929; /* Более темный фон для заголовков */ + color: #ffffff; /* Белый цвет текста для заголовков */ + + } + + td { + vertical-align: top; /* Выравнивание содержимого ячейки РїРѕ верху */ + } + + + .status-column ul { + list-style-type: none; /* Убирает маркеры СЃРїРёСЃРєР° */ + padding: 0; /* Убирает отступ слева, если РѕРЅ есть */ + top: 10px; + } + + td .order-card { + margin: 10px; + width: 90%; /* Карточка занимает РІСЃСЋ ширину колонки */ + box-sizing: border-box; /* Включаем padding Рё border РІ расчет ширины */ + /* margin: 0 auto; Центрируем содержимое внутри ячейки */ + background-color: #4a4646; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + border: 2px solid rgba(255, 255, 255, 0.62); + border-width: 0.5px; + color: white; + border-radius: 8px; + padding: 10px; + text-wrap: wrap; + + } + /* .order-card { + margin: 10px; + padding: 10px; + border-radius: 8px; + background-color: #4a4646; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + border: 2px solid rgba(255, 255, 255, 0.62); + border-width: 0.5px; + color: white; + cursor: pointer; + } */ + + + /* Стили для формы */ + +/* Стили для select элемента */ +select { + + width: 100%; /* ширина, соответствующая ширине формы */ + padding: 8px; /* внутренний отступ */ + /* margin-top: 10px; отступ сверху */ + border: 1px solid #8d53ff; /* граница */ + border-radius: 4px; /* скругленные углы */ + display: block; /* блочное отображение */ + font-family: "Mulish", sans-serif; + +} + + button { + background-color: #8d53ff; /* цвет фона */ + width: 100%; + + border: none; /* без рамки */ + border-radius: 4px; /* скругленные углы */ + color: white; + font-family: "Mulish", sans-serif; + } + + .footer { + font-family: "Krona One", sans-serif; + width: 100%; /* Футер растягивается РЅР° РІСЃСЋ ширину */ + text-align: center; + /* padding: 10px 20px; Внутренние отступы */ + background-color: #121212; /* Цвет фона футера */ + color: #888; /* Цвет текста */ + font-size: 12px; + margin-top: 20px; /* Футер перемещается РІ самый РЅРёР· */ + margin-bottom: 20px; + } + </style> + </head> <body> - <h1>Панель менеджера</h1> - <h2>Р’СЃРµ заказы</h2> - <button onclick="location.href='{% url 'home' %}'">Домой</button> + + <div class="navbar"> + <div class="logo"> + <a href="{% url 'home' %}" style="text-decoration: none; color: inherit; display: flex; align-items: center;"> + <img src="{% static 'mainapp/images/download.png' %}" alt="Logo"> + <span>MOVERELAB</span> + </a> + </div> + <div class="btns_in_nav"> + <button class="profile-btn" onclick="location.href='{% url 'home' %}'">Домой</button> + <button class="storage_home_button" onclick="location.href='{% url 'profile' %}'">Профиль</button> + </div> + </div> + + <div class = 'view_orders_h1'> + <h1>>>> РЎРџРРЎРћРљ Р—РђРљРђР—РћР’</h1> + </div> + <table> <thead> <tr> @@ -37,15 +425,22 @@ <th>Файлы</th> <th class="sortable"><a href="?sort=order_state">Статус</a></th> <th>Рзменить статус</th> + </tr> </thead> <tbody> {% for order in orders %} <tr> <td>{{ order.id }}</td> - <td>{{ order.order_datetime }}</td> + <td>{{ order.order_datetime|date:"Y-m-d" }}</td> <td>{{ order.user.username }}</td> - <td>{{ order.order_parameters }}</td> + <td> + {% for key, value in order.parsed_params.items%} + + <li><strong>{{key}}</strong> : {{value}}</span> + + {% endfor %} + </td> <td> {% if order.file_basename %} {{ order.file_basename }} @@ -53,7 +448,12 @@ Нет файлов {% endif %} </td> - <td>{{ order.order_state }}</td> + <td> {% if order.order_state == 'wait_confirmation' %} + awaiting + {% else %} + {{ order.order_state }} + {% endif %} + </td> <td> <form method="post" action="{% url 'manager_dashboard' %}"> {% csrf_token %} @@ -77,6 +477,7 @@ </tbody> </table> - <a href="{% url 'home' %}">Назад РЅР° главную</a> + + <div class="footer">(C) MOVERELAB</div> </body> </html> diff --git a/movere_local/mainapp/templates/mainapp/redactor.html b/movere_local/mainapp/templates/mainapp/redactor.html index 35cc8c791c02659b50d6e4048f57217f978bc7d0..386710df18c289a0629a241ba78a4dfd8ca6a1ff 100644 --- a/movere_local/mainapp/templates/mainapp/redactor.html +++ b/movere_local/mainapp/templates/mainapp/redactor.html @@ -5,9 +5,178 @@ <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>3D Object Viewer</title> <style> + {% load static %} + @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap'); + @import url('https://fonts.googleapis.com/css2?family=Krona+One&display=swap'); + @import url('https://fonts.googleapis.com/css2?family=Mulish:wght@200..1000&display=swap'); + + + .navbar { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + background-color: #121212; /* Цвет РІ тон страницы */ + padding: 30px 20px; + position: fixed; + top: 0; + z-index: 10; + /* box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); */ + } + + .navbar .logo { + display: flex; /* Располагает элементы (логотип Рё текст) РІ РѕРґРЅСѓ строку */ + align-items: center; /* Вертикальное выравнивание элементов РїРѕ центру */ + margin-left: 100px; + margin-top: 20px; + /* margin-left: 30px; */ + } + + .navbar .logo img { + height: 60px; /* Размер логотипа */ + margin-right: 15px; /* Отступ между логотипом Рё текстом */ + } + + .navbar .logo span { + font-family: "Krona One", serif; + font-size: 20px; /* Размер текста */ + font-weight: bold; + color: #FFFFFF; /* Цвет текста */ + white-space: nowrap; /* Запрещает перенос текста РЅР° РЅРѕРІСѓСЋ строку */ + } + + + + .navbar .profile-btn { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Mulish", sans-serif; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + + .navbar .profile-btn:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + + .navbar .storage_home_button { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Roboto", sans-serif; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + + .navbar .storage_home_button:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + + + .navbar .btns_in_nav { + display: flex; + margin-right: 10%; + } + + .navbar2 { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + background-color: transparent; /* Цвет РІ тон страницы */ + padding: 30px 20px; + position: fixed; + top: 0; + z-index: 10; + /* box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); */ + } + + .navbar2 .logo { + display: flex; /* Располагает элементы (логотип Рё текст) РІ РѕРґРЅСѓ строку */ + align-items: center; /* Вертикальное выравнивание элементов РїРѕ центру */ + margin-left: 100px; + margin-top: 20px; + /* margin-left: 30px; */ + } + + .navbar2 .logo img { + height: 60px; /* Размер логотипа */ + margin-right: 15px; /* Отступ между логотипом Рё текстом */ + } + + .navbar2 .logo span { + font-family: "Krona One", serif; + font-size: 20px; /* Размер текста */ + font-weight: bold; + color: #121212; /* Цвет текста */ + white-space: nowrap; /* Запрещает перенос текста РЅР° РЅРѕРІСѓСЋ строку */ + } + + + .navbar2 .profile-btn { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Mulish", sans-serif; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + + .navbar2 .profile-btn:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + + .navbar2 .storage_home_button { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Mulish", sans-serif; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + + .navbar2 .storage_home_button:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + + + .navbar2 .btns_in_nav { + display: flex; + margin-right: 10%; + } + body { margin: 0; - font-family: Arial, sans-serif; + font-family: "Mulish", sans-serif; display: flex; justify-content: center; align-items: center; @@ -47,7 +216,7 @@ } label { - background-color: rgb(116, 12, 173); + background-color: #8d53ff; color: white; padding: 15px 30px; font-size: 18px; @@ -58,7 +227,7 @@ } label:hover { - background-color: rgb(100, 0, 182); + background-color: #9e6dff; } .info-text { @@ -70,9 +239,9 @@ #new-file-button { position: absolute; - bottom: 20px; - right: 20px; - background-color: rgb(116, 12, 173); + bottom: 40px; + left: 100px; + background-color: #8d53ff; color: white; padding: 10px 20px; border-radius: 20px; @@ -83,13 +252,13 @@ } #new-file-button:hover { - background-color: rgb(100, 0, 182); + background-color: #9e6dff; } #scale-controls { position: absolute; - top: 20px; - left: 20px; + top: 180px; + left: 100px; z-index: 10; background-color: rgba(255, 255, 255, 0.7); padding: 10px; @@ -108,9 +277,9 @@ #export-button { position: absolute; - top: 20px; - right: 20px; - background-color: rgb(116, 12, 173); + bottom: 40px; + right: 100px; + background-color: #8d53ff; color: white; padding: 10px 20px; border-radius: 20px; @@ -121,43 +290,51 @@ } #export-button:hover { - background-color: rgb(100, 0, 182); + background-color: #9e6dff; } - .storage_home_button { - background-color: rgb(45, 42, 42); /* Фон РєРЅРѕРїРєРё прозрачный */ - font-family: "Krona One", serif; - position: absolute; - border: none; - padding: 1px 1px; /* Отступы внутри РєРЅРѕРїРєРё */ - top: 7%; - right: 3%; - width: 70px; - font-size: 13px; - font-weight: 700; - color: white; /* Цвет текста */ - outline: none; /* Убирает контур РїСЂРё фокусе */ - transition: background-color 0.3s; - border-radius: 12px; /* Закругленные углы таблицы */ - height: 25px; /* Фиксированная высота */ - } - .storage_home_button:hover { - font-family: "Krona One", serif; - background-color: rgb(58, 54, 54); /* Фон РєРЅРѕРїРєРё прозрачный */ - } + + </style> </head> <body> + + <div class="navbar2"> + <div class="logo"> + <a href="{% url 'home' %}" style="text-decoration: none; color: inherit; display: flex; align-items: center;"> + <img src="{% static 'mainapp/images/download.png' %}" alt="Logo"> + <span>MOVERELAB</span> + </a> + </div> + <div class="btns_in_nav"> + <button class="profile-btn" onclick="location.href='{% url 'profile' %}'">Профиль</button> + <button class="storage_home_button" onclick="location.href='{% url 'home' %}'">Домой</button> + </div> + </div> + <div id="upload-container"> + + <div class="navbar"> + <div class="logo"> + <a href="{% url 'home' %}" style="text-decoration: none; color: inherit; display: flex; align-items: center;"> + <img src="{% static 'mainapp/images/download.png' %}" alt="Logo"> + <span>MOVERELAB</span> + </a> + </div> + <div class="btns_in_nav"> + <button class="profile-btn" onclick="location.href='{% url 'profile' %}'">Профиль</button> + <button class="storage_home_button" onclick="location.href='{% url 'home' %}'">Домой</button> + </div> + </div> + <label for="upload">Upload 3D Object</label> <input type="file" id="upload" accept=".stl,.obj"> <p class="info-text">Supported formats: STL, OBJ</p> - <button class="storage_home_button" onclick="location.href='{% url 'home' %}'">Домой</button> - </div> + </div> <button id="new-file-button">Choose Another File</button> @@ -195,8 +372,7 @@ let object; let isMouseDown = false; let startX, startY; - let rotationX = 0; - let rotationY = 0; + let rotationQuaternion = new THREE.Quaternion(); function clearObject() { if (object) { @@ -303,18 +479,23 @@ }); window.addEventListener('mousemove', event => { - if (isMouseDown && object) { - const deltaX = event.clientX - startX; - const deltaY = event.clientY - startY; + if (isMouseDown && object) { + const deltaX = event.clientX - startX; + const deltaY = event.clientY - startY; + + startX = event.clientX; + startY = event.clientY; + + const quaternionX = new THREE.Quaternion(); + const quaternionY = new THREE.Quaternion(); - rotationX += deltaY * 0.01; - rotationY += deltaX * 0.01; + quaternionX.setFromAxisAngle(new THREE.Vector3(1, 0, 0), deltaY * 0.01); + quaternionY.setFromAxisAngle(new THREE.Vector3(0, 1, 0), deltaX * 0.01); - startX = event.clientX; - startY = event.clientY; + rotationQuaternion.multiplyQuaternions(quaternionY, rotationQuaternion); + rotationQuaternion.multiplyQuaternions(quaternionX, rotationQuaternion); - object.rotation.x = rotationX; - object.rotation.y = rotationY; + object.quaternion.copy(rotationQuaternion); } }); diff --git a/movere_local/mainapp/templates/mainapp/storage.html b/movere_local/mainapp/templates/mainapp/storage.html index 2890f4db0c3512a2106ec940cab53e87e60d43fe..e28b2045b8f522d092c8d26e101d4053526a3dc4 100644 --- a/movere_local/mainapp/templates/mainapp/storage.html +++ b/movere_local/mainapp/templates/mainapp/storage.html @@ -1,22 +1,307 @@ -<h2>Хранилище</h2> - -<a href="{% url 'upload_file' %}">Загрузить файл</a> -<button onclick="location.href='{% url 'home' %}'">Домой</button> - -{% if items %} - <ul> - {% for item in items %} - <li> - <strong>{{ item.item_name }}</strong>: {{ item.description }} <br> - Дата добавления: {{ item.created_at }} - <a href="{% url 'download_item' item.id %}">Скачать</a> - <form action="{% url 'delete_item' item.id %}" method="POST" style="display:inline;"> - {% csrf_token %} - <button type="submit" onclick="return confirm('Р’С‹ уверены, что хотите удалить этот элемент?');">Удалить</button> - </form> - </li> - {% endfor %} - </ul> -{% else %} - <p>РЈ вас РїРѕРєР° нет элементов РІ хранилище.</p> -{% endif %} \ No newline at end of file +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>MOVERE | Хранилище</title> + <style> + + {% load static %} + @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap'); + @import url('https://fonts.googleapis.com/css2?family=Krona+One&display=swap'); + @import url('https://fonts.googleapis.com/css2?family=Mulish:wght@200..1000&display=swap'); + body { + margin: 0; + font-family: "Krona One", serif; + font-weight: 400; + font-style: normal; + background-color: #121212; + color: #FFFFFF; + display: flex; + flex-direction: column; + align-items: center; + height: 100vh; + } + + .navbar { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + background-color: #121212; /* Цвет РІ тон страницы */ + padding: 30px 20px; + position: fixed; + top: 0; + z-index: 10; + /* box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); */ + } + + .navbar .logo { + display: flex; /* Располагает элементы (логотип Рё текст) РІ РѕРґРЅСѓ строку */ + align-items: center; /* Вертикальное выравнивание элементов РїРѕ центру */ + margin-left: 100px; + margin-top: 20px; + /* margin-left: 30px; */ + } + + .navbar .logo img { + height: 60px; /* Размер логотипа */ + margin-right: 15px; /* Отступ между логотипом Рё текстом */ + } + + .navbar .logo span { + font-size: 20px; /* Размер текста */ + font-weight: bold; + color: #FFFFFF; /* Цвет текста */ + white-space: nowrap; /* Запрещает перенос текста РЅР° РЅРѕРІСѓСЋ строку */ + } + + + .navbar .profile-btn { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Mulish"; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + + .navbar .profile-btn:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + + .navbar .storage_home_button { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Mulish", sans-serif; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + + .navbar .storage_home_button:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + + + .navbar .btns_in_nav { + display: flex; + margin-right: 10%; + } + + + + .view_orders_h1 { + align-self: flex-start; /* Расположить элемент слева */ + /* margin: 20px; Отступы сверху Рё слева */ + color: rgb(255, 253, 253); + font-size: 20px; + /* font-family: "Krona One", serif; */ + text-align: left; + margin-top: 10%; + padding: 0 5%; + font-family: "Mulish", serif; + } + + h2 { + font-size: 32px; + margin-top: 20px; + font-weight: bold; + color: rgb(255, 253, 253); + text-align: center; + } + + .buttons-container { + display: flex; + justify-content: flex-start; + gap: 15px; + margin: 20px 0; + /* width: 25%; */ + text-align: left; + } + + .buttons-container a, + .buttons-container button { + text-decoration: none; + justify-content: flex-start; + padding: 10px 20px; + + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + /* padding: 15px 30px; Увеличенный внутренний отступ */ + font-family: "Mulish"; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + /* margin-right: 10%; Отступ справа */ + /* margin-left: 10%; */ + + } + + .buttons-container a:hover, + .buttons-container button:hover { + background-color: rgb(58, 54, 54); + transform: scale(1.05); + } + + ul { + list-style: none; + padding: 0; + width: 90%; + max-width: 800px; + margin: 0 auto; + font-family: "Mulish", serif; + } + + li { + background-color: #1E1E1E; + border: 1px solid #333; + border-radius: 8px; + margin-bottom: 10px; + padding: 15px; + display: flex; + flex-direction: column; + gap: 10px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); + font-family: "Mulish", serif; + } + + li strong { + font-size: 18px; + color: #eeefee; + } + + li span { + color: #ccc; + font-size: 14px; + } + + .actions { + display: flex; + gap: 10px; + margin-top: 10px; + } + + .actions a, + .actions button { + text-decoration: none; + background-color: #2196F3; + color: white; + padding: 8px 12px; + border: none; + border-radius: 5px; + font-size: 14px; + cursor: pointer; + transition: background-color 0.3s, transform 0.2s; + font-family: "Mulish", serif; + } + + .actions a:hover { + background-color: #1B87D3; + } + + .actions button { + background-color: #f44336; + } + + .actions button:hover { + background-color: #D32F2F; + } + + .no-items { + font-size: 18px; + color: #ccc; + text-align: center; + margin-top: 20px; + } + + .view_orders_h1 { + align-self: flex-start; /* Расположить элемент слева */ + /* margin: 20px; Отступы сверху Рё слева */ + color: rgb(255, 253, 253); + font-size: 20px; + /* font-family: "Krona One", serif; */ + text-align: left; + margin-top: 10%; + padding: 0 5%; + font-family: "Mulish", serif; + } + .footer { + width: 100%; /* Футер растягивается РЅР° РІСЃСЋ ширину */ + text-align: center; + /* padding: 10px 20px; Внутренние отступы */ + background-color: #121212; /* Цвет фона футера */ + color: #888; /* Цвет текста */ + font-size: 12px; + margin-top: 60px; /* Футер перемещается РІ самый РЅРёР· */ + margin-bottom: 20px; +} + </style> +</head> +<body> + + <div class="navbar"> + <div class="logo"> + <a href="{% url 'home' %}" style="text-decoration: none; color: inherit; display: flex; align-items: center;"> + <img src="{% static 'mainapp/images/download.png' %}" alt="Logo"> + <span>MOVERELAB</span> + </a> + </div> + <div class="btns_in_nav"> + <button class="profile-btn" onclick="location.href='{% url 'home' %}'">Домой</button> + <button class="profile-btn" onclick="location.href='{% url 'profile' %}'">Профиль</button> + </div> + </div> + + <div class = 'view_orders_h1'> + <h1><span style="font-family: 'Krona One', monospace; font-weight: 400; font-size: 40px;">>>></span> РҐР РђРќРР›РЩЕ</h1> + </div> + + + <div class="buttons-container"> + <a href="{% url 'upload_file' %}">+ Загрузить файл</a> + + </div> + + {% if items %} + <ul> + {% for item in items %} + <li> + <strong>{{ item.item_name }}</strong> + <span>{{ item.description }}</span> + <span>{{ item.basename_filepath }}</span> + <span>Дата добавления: {{ item.created_at|date:"Y-m-d" }}</span> + <div class="actions"> + <a href="{% url 'download_item' item.id %}">Скачать</a> + <form action="{% url 'delete_item' item.id %}" method="POST" style="display:inline;"> + {% csrf_token %} + <button type="submit" onclick="return confirm('Р’С‹ уверены, что хотите удалить этот элемент?');">Удалить</button> + </form> + </div> + </li> + {% endfor %} + </ul> + {% else %} + <p class="no-items">РЈ вас РїРѕРєР° нет элементов РІ хранилище.</p> + {% endif %} + + <div class="footer">(C) MOVERELAB</div> +</body> +</html> diff --git a/movere_local/mainapp/templates/mainapp/upload_file.html b/movere_local/mainapp/templates/mainapp/upload_file.html index ff3310fba0c19c37881a4352333b968d317b7714..796e48a7c5f98b1688f68f3cef701161ba1a7511 100644 --- a/movere_local/mainapp/templates/mainapp/upload_file.html +++ b/movere_local/mainapp/templates/mainapp/upload_file.html @@ -1,13 +1,317 @@ -<h2>Загрузить файл</h2> - -{% if error_message %} -<script type="text/javascript"> - alert("{{ error_message }}"); -</script> -{% endif %} - -<form method="post" enctype="multipart/form-data"> - {% csrf_token %} - {{ form.as_p }} - <button type="submit">Загрузить</button> -</form> +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>MOVERE | Загрузить файл</title> + + + + <style> + {% load static %} + @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap'); + @import url('https://fonts.googleapis.com/css2?family=Krona+One&display=swap'); + @import url('https://fonts.googleapis.com/css2?family=Mulish:wght@200..1000&display=swap'); + + + .navbar { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + background-color: #121212; /* Цвет РІ тон страницы */ + padding: 30px 20px; + position: fixed; + top: 0; + z-index: 10; + /* box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); */ + } + .navbar .logo { + display: flex; /* Располагает элементы (логотип Рё текст) РІ РѕРґРЅСѓ строку */ + align-items: center; /* Вертикальное выравнивание элементов РїРѕ центру */ + margin-left: 100px; + margin-top: 20px; + /* margin-left: 30px; */ + } + .navbar .logo img { + height: 60px; /* Размер логотипа */ + margin-right: 15px; /* Отступ между логотипом Рё текстом */ + } + .navbar .logo span { + font-size: 20px; /* Размер текста */ + font-weight: bold; + color: #FFFFFF; /* Цвет текста */ + white-space: nowrap; /* Запрещает перенос текста РЅР° РЅРѕРІСѓСЋ строку */ + } + .navbar .profile-btn { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Mulish", sans-serif; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + .navbar .profile-btn:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + .navbar .storage_home_button { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Mulish", sans-serif; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + .navbar .storage_home_button:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + .navbar .btns_in_nav { + display: flex; + margin-right: 10%; + } + /* .navbar .btns_in_nav { + display: flex; + margin-right: 10%; + } */ + + + + + + h1 { + font-family: 'Mulish', Arial, sans-serif; + align-self: flex-start; + /* margin-left: 10%; РЎРґРІРёРі текста "3D LAB" влево */ + } + + + + + body { + margin: 0; + font-family: "Krona One", serif; + font-weight: 400; + font-style: normal; + background-color: #121212; + color: #FFFFFF; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100vh; + } + +.container { + display: flex; + flex-direction: column; + flex: 1; /* Занимает оставшееся пространство между навбаром Рё футером */ + width: 80%; /* РЁРёСЂРёРЅР° контента */ + max-width: 1200px; + margin: 15% auto; /* Центрирование контента */ + padding-bottom: 20px; /* Отступ РѕС‚ последнего элемента РґРѕ футера */ + padding-top: 20%; + +} + +.footer { + width: 100%; /* Футер растягивается РЅР° РІСЃСЋ ширину */ + text-align: center; + /* padding: 10px 20px; Внутренние отступы */ + background-color: #121212; /* Цвет фона футера */ + color: #888; /* Цвет текста */ + font-size: 12px; + margin-top: auto; /* Футер перемещается РІ самый РЅРёР· */ + margin-bottom: 20px; +} + /* .footer a { + color: #888; + text-decoration: none; + } + .footer a:hover { + color: #FFFFFF; + } */ + + + + + + .card { + background-color: #1E1E1E; /* Фон карточки */ + border-radius: 10px; /* Скругленные углы */ + padding: 20px; /* Внутренние отступы */ + margin-bottom: 20px; /* Отступ между карточками */ + box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.2); /* Легкая тень */ + } + + .card label { + font-family: 'Mulish', Arial, sans-serif; + font-size: 16px; + color: #FFFFFF; /* Цвет текста */ + display: block; + margin-bottom: 10px; /* Отступ РѕС‚ текста РґРѕ поля */ + } + .card input, + /* .card textarea, */ + .card select { + width: 98%; /* Растянуть поле РЅР° РІСЃСЋ ширину карточки */ + padding: 10px; + border-radius: 5px; + border: 1px solid #333333; /* Тонкая рамка */ + background-color: #121212; /* Фон поля */ + color: #FFFFFF; /* Цвет текста */ + font-family: 'Mulish', sans-serif; + font-size: 14px; + } + .card input[type="radio"], + .card input[type="checkbox"] { + width: auto; /* Убираем ширину для радио Рё чекбоксов */ + } + .card legend { + font-family: 'Mulish', sans-serif; + font-size: 16px; + color: #FFFFFF; + margin-bottom: 10px; + } + .card textarea { + width: 98%; /* Заполнение карточки РїРѕ ширине */ + height: 120px; /* Фиксированная высота */ + margin: 0 auto; /* Центрирование РїРѕ горизонтали */ + display: block; /* Убирает лишнее пространство РІРѕРєСЂСѓРі */ + padding: 10px; + border-radius: 5px; /* Скругленные углы */ + border: 1px solid #333333; /* Рамка */ + background-color: #121212; /* Фон */ + color: #FFFFFF; /* Цвет текста */ + font-family: 'Mulish', sans-serif; + font-size: 14px; /* Размер текста */ + resize: none; /* Запрещаем изменение размера */ + } + #id_item_name { + width: 98%; /* Заполнение карточки РїРѕ ширине */ + height: 20px; /* Фиксированная высота */ + margin: 0 auto; /* Центрирование РїРѕ горизонтали */ + display: block; /* Убирает лишнее пространство РІРѕРєСЂСѓРі */ + padding: 10px; + border-radius: 5px; /* Скругленные углы */ + border: 1px solid #333333; /* Рамка */ + background-color: #121212; /* Фон */ + color: #FFFFFF; /* Цвет текста */ + font-family: 'Mulish', sans-serif; + font-size: 14px; /* Размер текста */ + resize: none; /* Запрещаем изменение размера */ + } + + .card button[type="submit"] { + width: 100%; + padding: 10px; + border: none; + border-radius: 20px; + background-color: rgb(116, 12, 173); + color: white; + font-size: 16px; + cursor: pointer; + font-family: 'Mulish', sans-serif; + transition: transform 0.2s, background-color 0.2s; /* Анимация */ + } + + .card button[type="submit"]:hover { + background-color: rgb(128, 35, 179); /* Легкое осветление */ + transform: scale(1.01); /* Увеличение РїСЂРё наведении */ + } + + .card button[type="submit"]:active { + background-color: rgba(128, 35, 179); /* Еще большее осветление */ + transform: scale(1.01); /* Увеличение РїСЂРё клике */ + } + + .hidden { display: none; } + + </style> +</head> +<body> + + <div class="navbar"> + <div class="logo"> + <a href="{% url 'home' %}" style="text-decoration: none; color: inherit; display: flex; align-items: center;"> + <img src="{% static 'mainapp/images/download.png' %}" alt="Logo"> + <span>MOVERELAB</span> + </a> + </div> + <div class="btns_in_nav"> + <button class="profile-btn" onclick="location.href='{% url 'home' %}'">Домой</button> + <button class="profile-btn" onclick="location.href='{% url 'profile' %}'">Профиль</button> + </div> + </div> + + + + <div class="container"> + <h1>ЗАГРУЗРРўР¬ НОВЫЙ ФАЙЛ</h1> + {% if error_message %} + <script type="text/javascript"> + alert("{{ error_message }}"); + </script> + {% endif %} + + <form method="post" enctype="multipart/form-data"> + {% csrf_token %} + + + + <!-- Карточка для дополнительной цели --> + <div class="card"> + <label for="id_tem_name">Название</label> + <textarea name="item_name" id="id_item_name" placeholder="Название"></textarea> + </div> + <!-- Карточка для дополнительной цели --> + <div class="card"> + <label for="id_description">Описание</label> + <textarea name="description" id="id_description" placeholder="Описание"></textarea> + </div> + + + + <!-- Карточка для выбора файла --> + <div class="card"> + <label>Выбор файла:</label> + <div id="file_choice"> + {{ form.file }} + </div> + </div> + + + + + + <!-- РљРЅРѕРїРєР° отправки --> + <div class="card"> + <button type="submit"> + Загрузить + </button> + </div> + </form> + </div> + + + + + + + + <div class="footer">(C) MOVERELAB</div> +</body> +</html> diff --git a/movere_local/mainapp/templates/mainapp/view_archive.html b/movere_local/mainapp/templates/mainapp/view_archive.html index a09213db799308f2899d657f490b35da8b2a592b..f05ab74dfa4155f03d4a993b83eca6130fe74326 100644 --- a/movere_local/mainapp/templates/mainapp/view_archive.html +++ b/movere_local/mainapp/templates/mainapp/view_archive.html @@ -3,62 +3,647 @@ <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>РђСЂС…РёРІ заказов</title> + <title>MOVERE | РђСЂС…РёРІ</title> <style> - table { + + {% load static %} + @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap'); + @import url('https://fonts.googleapis.com/css2?family=Krona+One&display=swap'); + @import url('https://fonts.googleapis.com/css2?family=Mulish:wght@200..1000&display=swap'); + + + body { + margin: 0; + font-family: "Krona One", serif; + font-weight: 400; + font-style: normal; + background-color: #121212; + color: #FFFFFF; + display: flex; + flex-direction: column; + align-items: center; + height: 100vh; + } + + .navbar { + display: flex; + justify-content: space-between; + align-items: center; width: 100%; - border-collapse: collapse; + background-color: #121212; /* Цвет РІ тон страницы */ + padding: 30px 20px; + position: fixed; + top: 0; + z-index: 10; + /* box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); */ } - th, td { - border: 1px solid #ddd; - padding: 8px; + + .navbar .logo { + display: flex; /* Располагает элементы (логотип Рё текст) РІ РѕРґРЅСѓ строку */ + align-items: center; /* Вертикальное выравнивание элементов РїРѕ центру */ + margin-left: 100px; + margin-top: 20px; + /* margin-left: 30px; */ + } + + .navbar .logo img { + height: 60px; /* Размер логотипа */ + margin-right: 15px; /* Отступ между логотипом Рё текстом */ + } + + .navbar .logo span { + font-size: 20px; /* Размер текста */ + font-weight: bold; + color: #FFFFFF; /* Цвет текста */ + white-space: nowrap; /* Запрещает перенос текста РЅР° РЅРѕРІСѓСЋ строку */ + } + + + .navbar .profile-btn { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Mulish"; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + + .navbar .profile-btn:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + + .navbar .storage_home_button { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Mulish", sans-serif; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + + .navbar .storage_home_button:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + + + .navbar .btns_in_nav { + display: flex; + margin-right: 10%; + } + + + + .view_orders_h1 { + align-self: flex-start; /* Расположить элемент слева */ + /* margin: 20px; Отступы сверху Рё слева */ + color: rgb(255, 253, 253); + font-size: 20px; + /* font-family: "Krona One", serif; */ text-align: left; + margin-top: 10%; + padding: 0 5%; + font-family: "Mulish", serif; + } + + + .container { + display: flex; + gap: 10px; + } + + + .card { + width: 200px; + height: 300px; + background-color: #3A3A3A; + border-radius: 10px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-end; + overflow: hidden; + position: relative; + cursor: pointer; + transition: transform 0.3s; + } + + .card:hover { + transform: scale(1.05); + } + + .card img { + width: 100%; + height: 100%; + object-fit: cover; + position: absolute; + top: 0; + left: 0; + z-index: 1; + } + + .card video { + width: 100%; + height: 100%; + object-fit: cover; + display: none; + position: absolute; + top: 0; + left: 0; + z-index: 2; + } + + .card video[data-playing="true"] { + display: block; + } + + .card .label { + position: relative; + font-family: 'Mulish', Arial, sans-serif; + color: #FFFFFF; + padding: 5px 10px; + border-radius: 5px; + font-size: 14px; + font-weight: bold; + margin-bottom: 5px; + text-align: center; + z-index: 3; + } + + .card .description { + font-family: 'Mulish', Arial, sans-serif; + position: relative; + color: #FFFFFF; + padding: 5px 10px; + border-radius: 5px; + font-size: 12px; + text-align: center; + margin-bottom: 10px; + z-index: 3; + } + + .home-button { + background-color: transparent; /* Фон РєРЅРѕРїРєРё прозрачный */ + position: absolute; + padding: 1px 1px; /* Отступы внутри РєРЅРѕРїРєРё */ + top: 7%; + right: 3%; + width: 7%; + font-size: 20px; + font-weight: 700; + color: rgb(247, 249, 250); /* Цвет текста */ + border: none; /* Убирает границу */ + outline: none; /* Убирает контур РїСЂРё фокусе */ + } + + .create-order-button { + display: block; + padding: 8px 16px; + background-color: transparent; + color: white; + font-size: 20px; + text-decoration: none; + border-radius: 5px; + text-align: center; + transition: background-color 0.3s; /* Добавляем плавную анимацию */ + z-index: 1000; /* Убедитесь, что РєРЅРѕРїРєР° будет РІРёРґРЅР° над РґСЂСѓРіРёРјРё элементами */ + } + + .create-order-button:hover { + background-color: #4a4646; /* меняем цвет фона РЅР° серый РїСЂРё наведении */ + } + + .modal { + display: none; /* Скрытое РїРѕ умолчанию */ + position: fixed; /* Фиксийрованное положение */ + z-index: 1; /* Лежит над РґСЂСѓРіРёРјРё элементами */ + left: 0; + top: 0; + width: 100%; /* Полная ширина */ + height: 100%; /* Полная высота */ + overflow: auto; /* Включение прокрутки, если необходимо */ + background-color: rgb(0,0,0); /* Цвет фона */ + background-color: rgba(0,0,0,0.4); /* Черный фон СЃ небольшой прозрачностью */ + border-radius: 20px; + } + + .modal-content { + background-color: #d7d7d7; + color: black; + margin: 15% auto; /* 15% сверху Рё РїРѕ центру РїРѕ горизонтали */ + padding: 20px; + border: 1px solid #888; + width: 50%; /* Можете изменить ширину */ + border-radius: 20px; + font-family: "Mulish", sans-serif; + } + /* Общий стиль для РєРЅРѕРїРѕРє */ +.modal-btn { + display: inline-block; + padding: 10px 20px; + font-size: 16px; + font-family: "Mulish", sans-serif; + font-weight: bold; + color: white; + background-color: #4CAF50; /* Зелёный цвет РїРѕ умолчанию */ + border: none; + border-radius: 8px; + cursor: pointer; + transition: background-color 0.3s, transform 0.2s; +} + +/* РљРЅРѕРїРєР° отмены заказа */ +.cancel-btn { + background-color: #f44336; /* Красный цвет */ +} + +.cancel-btn:hover { + background-color: #d32f2f; /* Темнее РїСЂРё наведении */ +} + +/* РљРЅРѕРїРєР° "Р’ архив" */ +.archive-btn { + background-color: #2196F3; /* РЎРёРЅРёР№ цвет */ +} + +.archive-btn:hover { + background-color: #1976D2; /* Темнее РїСЂРё наведении */ +} + +/* Рффект нажатия */ +.modal-btn:active { + transform: scale(0.95); +} + +/* Модальное РѕРєРЅРѕ: стиль для действий */ +.modal-actions { + margin-top: 20px; + display: flex; + gap: 10px; /* Расстояние между кнопками */ +} + + .close { + color: #aaa; + float: right; + font-size: 28px; + font-weight: bold; + } + + .close:hover, + .close:focus { + color: black; + cursor: pointer; + } + + + + + table { + width: 90%; + table-layout: fixed; /* Фиксированная ширина колонок */ + border-collapse: separate; + border-spacing: 0; + margin: 10px auto; + border-radius: 10px; + overflow: hidden; + background-color: #1e1e1e; + font-family: "Mulish", serif; + font-optical-sizing: auto; + font-weight: 400; + font-style: normal; + } + + th, td { + width: 20%; /* Устанавливаем одинаковую ширину для всех колонок */ + border-bottom: 0.5px solid #606060; + border-right: 0.5px solid #5f5f5f; + padding: 12px 15px; + color: #f0f0f0; + vertical-align: top; /* Содержимое РїРѕ верхнему краю */ + } + + + + th:last-child, td:last-child { + border-right: none; /* Убирает правую границу Сѓ последней колонки */ + width: 20%; + } + + th:first-child, td:first-child { + width: 20%; /* Установите ширину первого столбца РїРѕ вашему усмотрению */ + } + th { - background-color: #f2f2f2; + background-color: #292929; /* Более темный фон для заголовков */ + color: #ffffff; /* Белый цвет текста для заголовков */ + } + + td { + vertical-align: top; /* Выравнивание содержимого ячейки РїРѕ верху */ + } + .status-column { - width: 20%; + width: 20%; /*РЁРёСЂРёРЅР° колонки статуса*/ + } + + .status-column ul { + list-style-type: none; /* Убирает маркеры СЃРїРёСЃРєР° */ + padding: 0; /* Убирает отступ слева, если РѕРЅ есть */ + top: 10px; + } + + td .order-card { + margin: 10px; + width: 90%; /* Карточка занимает РІСЃСЋ ширину колонки */ + box-sizing: border-box; /* Включаем padding Рё border РІ расчет ширины */ + /* margin: 0 auto; Центрируем содержимое внутри ячейки */ + background-color: #4a4646; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + border: 2px solid rgba(255, 255, 255, 0.62); + border-width: 0.0px; + color: white; + border-radius: 8px; + padding: 10px; + text-wrap: wrap; + transition-duration: 0.2s; + + } + td .order-card:hover { + + background-color: #524f4f;/* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.05); + cursor: pointer; + + } + + + .footer { + width: 100%; /* Футер растягивается РЅР° РІСЃСЋ ширину */ + text-align: center; + /* padding: 10px 20px; Внутренние отступы */ + background-color: #121212; /* Цвет фона футера */ + color: #888; /* Цвет текста */ + font-size: 12px; + margin-top: 5%; /* Футер перемещается РІ самый РЅРёР· */ + margin-bottom: 5%; + } + + + </style> + + + + + +<script> + // Объекты для переводов + const translations = { + keys: { + position: "Должность", + purpose: "Цель 3D-печати", + additional_purpose: "Дополнительная информация", + material: "Материал" + }, + values: { + student: "Студент Р’РЁР", + professor: "Преподаватель Р’РЁР", + worker: "Сотрудник Р’РЁР", + other: "Другое", + course: "Курсовая работа", + diploma: "Дипломная работа", + project: "Проект", + pla: "Пластик PLA", + abs: "Пластик ABS", + tpu: "Резина TPU", + wait_confirmation: "Ожидает подтверждения", + in_work: "Р’ работе", + ready: "Готов", + done: "Получен", + canceled: "Отменен" + } + }; + + // Функция перевода ключей Рё значений + function translateParameters(parameters) { + const translated = {}; + for (const [key, value] of Object.entries(parameters)) { + const translatedKey = translations.keys[key] || key; // Перевод ключа + if (Array.isArray(value)) { + // Если значение — массив, переводим элементы массива + translated[translatedKey] = value.map(item => translations.values[item] || item).join(", "); + } else { + // Переводим одиночное значение + translated[translatedKey] = translations.values[value] || value; + } + } + return translated; + } + + + document.addEventListener('DOMContentLoaded', function () { + // Получаем элементы модального РѕРєРЅР° + const modal = document.getElementById("orderModal"); + const closeBtn = modal.querySelector(".close"); + const modalContent = modal.querySelector("p"); + + // Добавляем обработчики событий для каждой карточки + document.querySelectorAll('.order-card').forEach(card => { + card.addEventListener('click', function () { + // Получаем данные РёР· атрибутов карточки + const orderId = this.getAttribute('data-id') || "Неизвестный"; + const orderDate = this.getAttribute('data-date') || "РќРµ указана"; + const orderParameters = this.getAttribute('data-parameters') || "{}"; + const orderStatus = this.getAttribute('data-status') || "Неизвестен"; + + // Парсим параметры + let parsedParameters; + try { + parsedParameters = JSON.parse(orderParameters.replace(/'/g, '"')); + } catch (e) { + console.error("Ошибка парсинга параметров:", e); + parsedParameters = {}; + } + + // Генерируем HTML для параметров + let parametersHTML = "<ul>"; + for (const [key, value] of Object.entries(parsedParameters)) { + parametersHTML += `<li><strong>${key}:</strong> ${value}</li>`; + } + parametersHTML += "</ul>"; + + // Генерируем HTML содержимое модального РѕРєРЅР° + modalContent.innerHTML = ` + <strong>ID заказа:</strong> ${orderId}<br> + <strong>Дата:</strong> ${orderDate}<br> + <strong>Параметры:</strong> ${parametersHTML} + <strong>Статус:</strong> ${orderStatus}<br> + `; + + // Показываем модальное РѕРєРЅРѕ + modal.style.display = "block"; + }); + }); + + // Закрытие модального РѕРєРЅР° РїСЂРё клике РЅР° РєРЅРѕРїРєСѓ закрытия + closeBtn.addEventListener('click', function () { + modal.style.display = "none"; + }); + + // Закрытие модального РѕРєРЅР° РїСЂРё клике РІРЅРµ его содержимого + window.addEventListener('click', function (event) { + if (event.target === modal) { + modal.style.display = "none"; + } + }); + + // Закрытие модального РѕРєРЅР° РїСЂРё нажатии клавиши "Escape" + document.addEventListener('keydown', function (event) { + if (event.key === "Escape") { + modal.style.display = "none"; + } + }); + }); + +</script> + + + + + + </head> <body> - <h1>РђСЂС…РёРІ заказов</h1> - <a href="{% url 'view_orders' %}" style="display: inline-block; padding: 10px 20px; background-color: #4CAF50; color: white; text-decoration: none; border-radius: 5px;">Назад Рє заказам</a> - <button onclick="location.href='{% url 'home' %}'">Домой</button> - <table> - <thead> - <tr> - {% for status, _ in archive_orders_status_list %} - <th class="status-column"> - {% if status == 'done' %}Выполнен{% elif status == 'canceled' %}Отменен{% endif %} - </th> - {% endfor %} - </tr> - </thead> + <div class="navbar"> + <div class="logo"> + <a href="{% url 'home' %}" style="text-decoration: none; color: inherit; display: flex; align-items: center;"> + <img src="{% static 'mainapp/images/download.png' %}" alt="Logo"> + <span>MOVERELAB</span> + </a> + </div> + <div class="btns_in_nav"> + <button class="profile-btn" onclick="location.href='{% url 'home' %}'">Домой</button> + <button class="profile-btn" onclick="location.href='{% url 'profile' %}'">Профиль</button> + </div> + </div> + + + <div class = 'view_orders_h1'> + <h1><span style="font-family: 'Krona One', monospace; font-weight: 400; font-size: 40px;">>>></span> РђР РҐРР’</h1> + </div> + + + <div class='view_orders_table'> + <table> + <thead> + <tr> + {% for status, _ in archive_orders_status_list %} + <th class="status-column"> + {% if status == 'done' %} + Выполнен + {% elif status == 'canceled' %} + Отменен + {% endif %} + </th> + {% endfor %} + </tr> + </thead> <tbody> <tr> {% for status, archive_orders in archive_orders_status_list %} <td class="status-column"> {% if archive_orders %} <ul> - {% for order in archive_orders %} - <li> - Заказ ID: {{ order.id }} <br> - Дата: {{ order.order_datetime }} <br> - Параметры: {{ order.order_parameters }} <br> - Файл: {% if order.file_basename %}{{ order.file_basename }}{% else %}Нет файла{% endif %} + {% for order, params in archive_orders %} + <li class="order-card" + data-id="{{ order.id }}" + data-date="{{ order.order_datetime|date:'Y-m-d' }}" + data-parameters="{{ params }}" + data-status="{{ order.order_state }}"> + + + + + + <span style="font-size: 19px;">Номер заказа: {{ order.id }} </span><br> + <span style="font-weight: 300; font-size: 16px; color: gray">{{ order.order_datetime|date:"Y-m-d" }}</span><br> + + + + <svg fill="#ffffff" width="15px" height="15px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg"> + <title>file</title> + <path d="M26.731 9.902c-0.005-0.035-0.011-0.066-0.019-0.095l0.001 0.005c-0.031-0.134-0.094-0.249-0.182-0.342l0 0-8-8c-0.092-0.087-0.207-0.15-0.335-0.181l-0.005-0.001c-0.027-0.008-0.059-0.014-0.092-0.019l-0.003-0c-0.026-0.007-0.059-0.014-0.092-0.019l-0.004-0h-12c-0.414 0-0.75 0.336-0.75 0.75v0 28c0 0.414 0.336 0.75 0.75 0.75h20c0.414-0 0.75-0.336 0.75-0.75v0-20c-0.005-0.038-0.012-0.071-0.020-0.103l0.001 0.005zM24.189 9.25h-5.439v-5.439zM6.75 29.25v-26.5h10.5v7.25c0 0.414 0.336 0.75 0.75 0.75h7.25v18.5z"></path> + </svg> + {% if order.file_basename %}{{ order.file_basename }}{% else %} Нет файла {% endif %} <br> + + + <div> + {% if order.order_state == 'wait_confirmation' %} + <svg fill="rgb(58, 174, 231)" width="15px" height="15px" viewBox="0 0 1920 1920" xmlns="http://www.w3.org/2000/svg"> + <path d="M960 112.941c-467.125 0-847.059 379.934-847.059 847.059 0 467.125 379.934 847.059 847.059 847.059 467.125 0 847.059-379.934 847.059-847.059 0-467.125-379.934-847.059-847.059-847.059M960 1920C430.645 1920 0 1489.355 0 960S430.645 0 960 0s960 430.645 960 960-430.645 960-960 960m417.905-575.955L903.552 988.28V395.34h112.941v536.47l429.177 321.77-67.765 90.465Z" fill-rule="evenodd"/> + </svg> + <span style="color: rgb(58, 174, 231);">Ожидает подтверждения</span> + {% elif order.order_state == 'in_work' %} + <svg width="15px" height="15px" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--emojione-monotone" preserveAspectRatio="xMidYMid meet"><path d="M61.287 53.542c-2.649-2.041-9.702-7.678-16.271-14.452c-4.366-4.505-6.223-9.015-9.533-12.429c-2.998-3.092-5.725-4.894-5.725-4.894l-.768.792l-5.188-5.35l2.004-2.067a.912.912 0 0 0 0-1.262l-.414-.427c.002-.002 5.898-7.936 13.353-5.742c.866.257 1.638.694 1.857.471c.298-.306-.837-1.482-1.502-2.162c-9.431-9.65-19.834 1.104-19.839 1.109l-.367-.379a.846.846 0 0 0-1.222 0l-9.239 9.528a.912.912 0 0 0 0 1.262s1.131 1.979-1.835 2.335c-1.194.145-1.942.414-2.366.769a431.18 431.18 0 0 0-1.979 2.009a.912.912 0 0 0 0 1.262l6.914 7.132a.847.847 0 0 0 1.223 0s1.906-1.99 1.947-2.042c.343-.438.605-1.208.743-2.44c.348-3.06 2.264-1.892 2.264-1.892a.846.846 0 0 0 1.224 0l2.004-2.067l5.186 5.349l-.768.793s1.748 2.813 4.746 5.905c3.309 3.413 7.683 5.328 12.05 9.833c6.567 6.774 12.032 14.047 14.014 16.78c.748 1.029.867.934 1.78-.009l2.849-2.938l2.847-2.937c.915-.946 1.009-1.068.011-1.84" fill="rgb(196, 61, 250)"></path><path d="M34.008 22.689a53.27 53.27 0 0 1 2.497 2.408c1.592 1.642 2.924 3.479 4.259 5.44l8.942-8.943A9.938 9.938 0 0 0 61.72 9.584L53.604 17.7l-5.76-1.543l-1.544-5.763l8.114-8.111a9.92 9.92 0 0 0-9.381 2.63a9.932 9.932 0 0 0-2.631 9.38l-8.394 8.396" fill="rgb(196, 61, 250)"></path><path d="M26.489 35.429a53.723 53.723 0 0 1-2.479-2.743l-9.717 9.718a9.926 9.926 0 0 0-9.381 2.629c-3.883 3.88-3.882 10.174 0 14.055a9.934 9.934 0 0 0 14.054 0a9.939 9.939 0 0 0 2.631-9.384l10.004-10.003c-1.84-1.338-3.567-2.679-5.112-4.272M13.483 57.821l-5.761-1.544l-1.543-5.762l4.218-4.215l5.76 1.541l1.543 5.763l-4.217 4.217" fill="rgb(196, 61, 250)"></path></svg> + + <span style="color: rgb(196, 61, 250);">Р’ работе</span> + {% elif order.order_state == 'ready' %} + <svg width="15px" height="15px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path d="M8.5 12.5L10.5 14.5L15.5 9.5" stroke="rgb(0, 195, 0)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> + <path d="M7 3.33782C8.47087 2.48697 10.1786 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 10.1786 2.48697 8.47087 3.33782 7" stroke="rgb(0, 195, 0)" stroke-width="1.5" stroke-linecap="round"/> + </svg> + <span style="color: rgb(0, 195, 0);">Готов</span> + {% elif order.order_state == 'done' %} + <svg width="15px" height="15px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path fill-rule="evenodd" clip-rule="evenodd" d="M17.4964 21.9284C17.844 21.7894 18.1491 21.6495 18.4116 21.5176C18.9328 22.4046 19.8969 23 21 23C22.6569 23 24 21.6568 24 20V14C24 12.3431 22.6569 11 21 11C19.5981 11 18.4208 11.9616 18.0917 13.2612C17.8059 13.3614 17.5176 13.4549 17.2253 13.5384C16.3793 13.7801 15.3603 13.9999 14.5 13.9999C13.2254 13.9999 10.942 13.5353 9.62034 13.2364C8.61831 13.0098 7.58908 13.5704 7.25848 14.5622L6.86313 15.7483C5.75472 15.335 4.41275 14.6642 3.47619 14.1674C2.42859 13.6117 1.09699 14.0649 0.644722 15.1956L0.329309 15.9841C0.0210913 16.7546 0.215635 17.6654 0.890813 18.2217C1.66307 18.8581 3.1914 20.0378 5.06434 21.063C6.91913 22.0782 9.21562 22.9999 11.5 22.9999C14.1367 22.9999 16.1374 22.472 17.4964 21.9284ZM20 20C20 20.5523 20.4477 21 21 21C21.5523 21 22 20.5523 22 20V14C22 13.4477 21.5523 13 21 13C20.4477 13 20 13.4477 20 14V20ZM14.5 15.9999C12.9615 15.9999 10.4534 15.4753 9.17918 15.1872C9.17918 15.1872 8.84483 16.1278 8.7959 16.2745L12.6465 17.2776C13.1084 17.3979 13.372 17.8839 13.2211 18.3367C13.0935 18.7194 12.7092 18.9536 12.3114 18.8865C11.0903 18.6805 8.55235 18.2299 7.25848 17.8365C5.51594 17.3066 3.71083 16.5559 2.53894 15.9342C2.53894 15.9342 2.22946 16.6189 2.19506 16.7049C2.92373 17.3031 4.32792 18.3799 6.0246 19.3086C7.76488 20.2611 9.70942 20.9999 11.5 20.9999C15.023 20.9999 17.1768 19.9555 18 19.465V15.3956C16.8681 15.7339 15.6865 15.9999 14.5 15.9999Z" fill="grey"/> + <path d="M12 1C11.4477 1 11 1.44772 11 2V7.58564L9.7071 6.29278C9.3166 5.9024 8.68342 5.9024 8.29292 6.29278C7.90235 6.68341 7.90235 7.31646 8.29292 7.70709L11.292 10.7063C11.6823 11.0965 12.3149 11.0968 12.7055 10.707L15.705 7.71368C16.0955 7.3233 16.0955 6.69 15.705 6.29962C15.3145 5.90899 14.6813 5.90899 14.2908 6.29962L13 7.59034V2C13 1.44772 12.5523 1 12 1Z" fill="grey"/> + </svg> + <span style="color: grey;">Получен</span> + {% elif order.order_state == 'canceled' %} + <svg width="15px" height="15px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path d="M16 8L8 16M8.00001 8L16 16M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z" stroke="red" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> + </svg> + <span style="color: red;">Отменен</span> + {% endif %} + </div> + </li> {% endfor %} </ul> {% else %} - Нет архивных заказов + {% endif %} </td> {% endfor %} </tr> </tbody> </table> + </div> + + <div id="orderModal" class="modal"> + <div class="modal-content"> + <span class="close">×</span> + <p>Здесь будет информация Рѕ заказе.</p> + </div> + </div> + + <div class="footer">(C) MOVERELAB</div> </body> </html> diff --git a/movere_local/mainapp/templates/mainapp/view_editrequests.html b/movere_local/mainapp/templates/mainapp/view_editrequests.html index 1b76a82026cc94eb6503dc9810e37705335378fa..54d637eaecc7c7b4076977fc4e575bdc1df503b3 100644 --- a/movere_local/mainapp/templates/mainapp/view_editrequests.html +++ b/movere_local/mainapp/templates/mainapp/view_editrequests.html @@ -3,33 +3,714 @@ <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>РњРѕРё запросы Рє нейросети</title> + <meta name="csrf-token" content="{{ csrf_token }}"> + <title>MOVERE | РњРѕРё Запросы</title> <style> - table { + + {% load static %} + @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap'); + @import url('https://fonts.googleapis.com/css2?family=Krona+One&display=swap'); + @import url('https://fonts.googleapis.com/css2?family=Mulish:wght@200..1000&display=swap'); + + + body { + margin: 0; + font-family: "Krona One", serif; + font-weight: 400; + font-style: normal; + background-color: #121212; + color: #FFFFFF; + display: flex; + flex-direction: column; + align-items: center; + height: 100vh; + } + + .navbar { + display: flex; + justify-content: space-between; + align-items: center; width: 100%; - border-collapse: collapse; + background-color: #121212; /* Цвет РІ тон страницы */ + padding: 30px 20px; + position: fixed; + top: 0; + z-index: 10; + /* box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); */ } - th, td { - border: 1px solid #ddd; - padding: 8px; + + .navbar .logo { + display: flex; /* Располагает элементы (логотип Рё текст) РІ РѕРґРЅСѓ строку */ + align-items: center; /* Вертикальное выравнивание элементов РїРѕ центру */ + margin-left: 100px; + margin-top: 20px; + /* margin-left: 30px; */ + } + + .navbar .logo img { + height: 60px; /* Размер логотипа */ + margin-right: 15px; /* Отступ между логотипом Рё текстом */ + } + + .navbar .logo span { + font-size: 20px; /* Размер текста */ + font-weight: bold; + color: #FFFFFF; /* Цвет текста */ + white-space: nowrap; /* Запрещает перенос текста РЅР° РЅРѕРІСѓСЋ строку */ + } + + + .navbar .profile-btn { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Mulish"; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + + .navbar .profile-btn:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + + .navbar .storage_home_button { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Mulish", sans-serif; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + + .navbar .storage_home_button:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + + + .navbar .btns_in_nav { + display: flex; + margin-right: 10%; + } + + + + .view_orders_h1 { + align-self: flex-start; /* Расположить элемент слева */ + /* margin: 20px; Отступы сверху Рё слева */ + color: rgb(255, 253, 253); + font-size: 20px; + /* font-family: "Krona One", serif; */ text-align: left; + margin-top: 10%; + padding: 0 5%; + font-family: "Mulish", serif; + } + + + .container { + display: flex; + gap: 10px; + } + + + .card { + width: 200px; + height: 300px; + background-color: #3A3A3A; + border-radius: 10px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-end; + overflow: hidden; + position: relative; + cursor: pointer; + transition: transform 0.3s; + } + + .card:hover { + transform: scale(1.05); + } + + .card img { + width: 100%; + height: 100%; + object-fit: cover; + position: absolute; + top: 0; + left: 0; + z-index: 1; + } + + .card video { + width: 100%; + height: 100%; + object-fit: cover; + display: none; + position: absolute; + top: 0; + left: 0; + z-index: 2; + } + + .card video[data-playing="true"] { + display: block; + } + + .card .label { + position: relative; + font-family: 'Mulish', Arial, sans-serif; + color: #FFFFFF; + padding: 5px 10px; + border-radius: 5px; + font-size: 14px; + font-weight: bold; + margin-bottom: 5px; + text-align: center; + z-index: 3; + } + + .card .description { + font-family: 'Mulish', Arial, sans-serif; + position: relative; + color: #FFFFFF; + padding: 5px 10px; + border-radius: 5px; + font-size: 12px; + text-align: center; + margin-bottom: 10px; + z-index: 3; + } + + .home-button { + background-color: transparent; /* Фон РєРЅРѕРїРєРё прозрачный */ + position: absolute; + padding: 1px 1px; /* Отступы внутри РєРЅРѕРїРєРё */ + top: 7%; + right: 3%; + width: 7%; + font-size: 20px; + font-weight: 700; + color: rgb(247, 249, 250); /* Цвет текста */ + border: none; /* Убирает границу */ + outline: none; /* Убирает контур РїСЂРё фокусе */ + } + + .create-order-button { + display: block; + padding: 8px 16px; + background-color: transparent; + color: white; + font-size: 20px; + text-decoration: none; + border-radius: 5px; + text-align: center; + transition: background-color 0.3s; /* Добавляем плавную анимацию */ + z-index: 1000; /* Убедитесь, что РєРЅРѕРїРєР° будет РІРёРґРЅР° над РґСЂСѓРіРёРјРё элементами */ + } + + .create-order-button:hover { + background-color: #4a4646; /* меняем цвет фона РЅР° серый РїСЂРё наведении */ + + } + + .modal { + display: none; /* Скрытое РїРѕ умолчанию */ + position: fixed; /* Фиксийрованное положение */ + z-index: 1; /* Лежит над РґСЂСѓРіРёРјРё элементами */ + left: 0; + top: 0; + width: 100%; /* Полная ширина */ + height: 100%; /* Полная высота */ + overflow: auto; /* Включение прокрутки, если необходимо */ + background-color: rgb(0,0,0); /* Цвет фона */ + background-color: rgba(0,0,0,0.4); /* Черный фон СЃ небольшой прозрачностью */ + border-radius: 20px; + } + + .modal-content { + background-color: #d7d7d7; + color: black; + margin: 15% auto; /* 15% сверху Рё РїРѕ центру РїРѕ горизонтали */ + padding: 20px; + border: 1px solid #888; + width: 50%; /* Можете изменить ширину */ + border-radius: 20px; + font-family: "Mulish", sans-serif; + } + /* Общий стиль для РєРЅРѕРїРѕРє */ +.modal-btn { + display: inline-block; + padding: 10px 20px; + font-size: 16px; + font-family: "Mulish", sans-serif; + font-weight: bold; + color: white; + background-color: #4CAF50; /* Зелёный цвет РїРѕ умолчанию */ + border: none; + border-radius: 8px; + cursor: pointer; + transition: background-color 0.3s, transform 0.2s; +} + +/* РљРЅРѕРїРєР° отмены заказа */ +.cancel-btn { + background-color: #f44336; /* Красный цвет */ +} + +.cancel-btn:hover { + background-color: #d32f2f; /* Темнее РїСЂРё наведении */ +} + +/* РљРЅРѕРїРєР° "Р’ архив" */ +.archive-btn { + background-color: #2196F3; /* РЎРёРЅРёР№ цвет */ +} + +.archive-btn:hover { + background-color: #1976D2; /* Темнее РїСЂРё наведении */ +} + + +.btn-download { + text-decoration: none; + background-color: #2196F3; /* РЎРёРЅРёР№ цвет */ +} + +.btn-download:hover { + background-color: #1976D2; /* Темнее РїСЂРё наведении */ +} + +/* Рффект нажатия */ +.modal-btn:active { + transform: scale(0.95); +} + +/* Модальное РѕРєРЅРѕ: стиль для действий */ +.modal-actions { + margin-top: 20px; + display: flex; + gap: 10px; /* Расстояние между кнопками */ +} + + .close { + color: #aaa; + float: right; + font-size: 28px; + font-weight: bold; + } + + .close:hover, + .close:focus { + color: black; + cursor: pointer; + } + + + + + table { + width: 90%; + table-layout: fixed; /* Фиксированная ширина колонок */ + border-collapse: separate; + border-spacing: 0; + margin: 10px auto; + border-radius: 10px; + overflow: hidden; + background-color: #1e1e1e; + font-family: "Mulish", serif; + font-optical-sizing: auto; + font-weight: 400; + font-style: normal; + } + + th, td { + width: 20%; /* Устанавливаем одинаковую ширину для всех колонок */ + border-bottom: 0.5px solid #606060; + border-right: 0.5px solid #5f5f5f; + padding: 12px 15px; + color: #f0f0f0; + vertical-align: top; /* Содержимое РїРѕ верхнему краю */ + } + + + + th:last-child, td:last-child { + border-right: none; /* Убирает правую границу Сѓ последней колонки */ + width: 20%; } + + th:first-child, td:first-child { + width: 20%; /* Установите ширину первого столбца РїРѕ вашему усмотрению */ + } + th { - background-color: #f2f2f2; + background-color: #292929; /* Более темный фон для заголовков */ + color: #ffffff; /* Белый цвет текста для заголовков */ + + } + + td { + vertical-align: top; /* Выравнивание содержимого ячейки РїРѕ верху */ } + .status-column { - width: 20%; + width: 20%; /*РЁРёСЂРёРЅР° колонки статуса*/ + } + + .status-column ul { + list-style-type: none; /* Убирает маркеры СЃРїРёСЃРєР° */ + padding: 0; /* Убирает отступ слева, если РѕРЅ есть */ + top: 10px; + } + + td .order-card { + margin: 10px; + width: 90%; /* Карточка занимает РІСЃСЋ ширину колонки */ + box-sizing: border-box; /* Включаем padding Рё border РІ расчет ширины */ + /* margin: 0 auto; Центрируем содержимое внутри ячейки */ + background-color: #4a4646; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + border: 2px solid rgba(255, 255, 255, 0.62); + border-width: 0.0px; + color: white; + border-radius: 8px; + padding: 10px; + text-wrap: wrap; + transition-duration: 0.2s; + + } + td .order-card:hover { + + background-color: #524f4f;/* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.05); + cursor: pointer; + + } + + + + + </style> + <script> + // Объекты для переводов + const translations = { + keys: { + position: "Должность", + purpose: "Цель 3D-печати", + additional_purpose: "Дополнительная информация", + material: "Материал" + }, + values: { + student: "Студент Р’РЁР", + professor: "Преподаватель Р’РЁР", + worker: "Сотрудник Р’РЁР", + other: "Другое", + course: "Курсовая работа", + diploma: "Дипломная работа", + project: "Проект", + pla: "Пластик PLA", + abs: "Пластик ABS", + tpu: "Резина TPU", + wait_confirmation: "Ожидает подтверждения", + in_progress: "Р’ работе", + ready: "Готов", + done: "Получен", + canceled: "Отменен" + } + }; + + // Функция перевода ключей Рё значений + function translateParameters(parameters) { + const translated = {}; + for (const [key, value] of Object.entries(parameters)) { + const translatedKey = translations.keys[key] || key; // Перевод ключа + if (Array.isArray(value)) { + // Если значение — массив, переводим элементы массива + translated[translatedKey] = value.map(item => translations.values[item] || item).join(", "); + } else { + // Переводим одиночное значение + translated[translatedKey] = translations.values[value] || value; + } + } + return translated; + } + + document.addEventListener('DOMContentLoaded', function () { + const modal = document.getElementById("orderModal"); + const closeBtn = document.querySelector(".close"); + const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content'); + + // Открытие модального РѕРєРЅР° РїСЂРё клике РЅР° карточку + document.querySelectorAll('.order-card').forEach(card => { + card.addEventListener('click', function () { + const orderId = this.getAttribute('data-id'); + const orderDate = this.getAttribute('data-date'); + const orderParameters = this.getAttribute('data-parameters'); + const orderStatus = this.getAttribute('data-status'); + + const downloadUrl = this.getAttribute('data-download-url'); + + + + + // Генерация HTML параметров + let parametersHTML = '<ul>'; + // for (const [key, value] of Object.entries(translatedParameters)) { + // parametersHTML += `<li><strong>${key}:</strong> ${value}</li>`; + // } + + parametersHTML += orderParameters + parametersHTML += '</ul>'; + + const translatedStatus = translations.values[orderStatus] || orderStatus; + + // Действия + let actionsHTML = ''; + if (orderStatus === 'ready') { + console.log('AAaaaa',downloadUrl ) + actionsHTML = ` + <div style="margin-top: 20px;"> + <a href="${downloadUrl}" class="modal-btn btn-download" target="_blank" rel="noopener noreferrer">Скачать файл</a> + </div>`; + } + + // Заполняем содержимое модального РѕРєРЅР° + modal.querySelector('p').innerHTML = ` + <strong>ID заказа:</strong> ${orderId}<br> + <strong>Дата:</strong> ${orderDate}<br> + <strong>Комменатрии:</strong> ${parametersHTML} + <strong>Статус:</strong> ${translatedStatus}<br> + <div class="modal-actions">${actionsHTML}</div> + `; + + modal.style.display = "block"; + }); + }); + + // Закрытие модального РѕРєРЅР° + closeBtn.onclick = function () { + modal.style.display = "none"; + }; + + window.onclick = function (event) { + if (event.target === modal) { + modal.style.display = "none"; + } + }; + document.addEventListener('keydown', function (event) { + if (event.key === "Escape") { + modal.style.display = "none"; + } + }); + }); + + + </script> </head> <body> - <h1>РЎРїРёСЃРѕРє заявок</h1> - <a href="{% url 'create3d' %}" style="display: inline-block; padding: 10px 20px; background-color: #4CAF50; color: white; text-decoration: none; border-radius: 5px;">Создать новый заказ</a> - <button onclick="location.href='{% url 'home' %}'">Домой</button> + + <div class="navbar"> + <div class="logo"> + <a href="{% url 'home' %}" style="text-decoration: none; color: inherit; display: flex; align-items: center;"> + <img src="{% static 'mainapp/images/download.png' %}" alt="Logo"> + <span>MOVERELAB</span> + </a> + </div> + <div class="btns_in_nav"> + <button class="profile-btn" onclick="location.href='{% url 'home' %}'">Домой</button> + <button class="profile-btn" onclick="location.href='{% url 'profile' %}'">Профиль</button> + </div> + </div> + + <div class = 'view_orders_h1'> + <h1><span style="font-family: 'Krona One', monospace; font-weight: 400; font-size: 40px;">>>></span> Р—РђРџР РћРЎР«</h1> + </div> + + + <!-- <h1>РЎРїРёСЃРѕРє заявок</h1> --> + + <!-- <a href="{% url 'create3d' %}" style="display: inline-block; padding: 10px 20px; background-color: #4CAF50; color: white; text-decoration: none; border-radius: 5px;">Создать новый заказ</a> + <button onclick="location.href='{% url 'home' %}'">Домой</button> --> + <div class='view_orders_table'> <table> + <thead> + <tr> + {% for status, _ in orders_status_list %} + <th class="status-column"> + {% if status == 'in_progress' %} + Р’ работе + + {% elif status == 'ready' %} + Готов + + {% elif status == 'error' %} + Ошибка РїСЂРё генерации + {% endif %} + </th> + {% endfor %} + </tr> + </thead> + <tbody> + <tr> + <!-- Ячейка для РєРЅРѕРїРєРё "Добавить новый заказ" --> + <td class="status-column"> + {% if orders_status_list.0.0 == 'in_progress' %} + <ul> + {% for order in orders_status_list.0.1 %} + <li class="order-card" + data-id="{{ order.id }}" + data-date="{{ order.req_datetime|date:'Y-m-d' }}" + data-parameters="{{ order.req_parameters }}" + data-status="{{ order.req_state}}" + data-download-url="{% url 'download_item_from_nn' order.id %}"> + <span style="font-size: 19px;">Запрос {{ order.id }} </span><br> + <span style="font-weight: 300; font-size: 16px; color: gray">{{ order.req_datetime|date:"Y-m-d" }}</span><br> + + + <br> + <br> + + + <svg width="15px" height="15px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path d="M13.5 3H12H8C6.34315 3 5 4.34315 5 6V18C5 19.6569 6.34315 21 8 21H12M13.5 3L19 8.625M13.5 3V7.625C13.5 8.17728 13.9477 8.625 14.5 8.625H19M19 8.625V11.8125" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> + <path d="M17.5 21L17.5 15M17.5 15L20 17.5M17.5 15L15 17.5" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> + </svg> + {% if order.sent_by_user %}{{ order.sent_by_user }}{% else %}{% endif %} <br> + <!-- Полученный файл: {% if order.recieved_from_server %}{{ order.recieved_from_server }}{% else %}Нет файла{% endif %} <br> --> + <!-- {% if order.recieved_from_server %}<a href="{% url 'download_item_from_nn' order.id %}">Скачать</a>{% else %}Нет файла{% endif %} --> + + <!-- Отображение статуса заказа --> + <br> + <div> + + {% if order.req_state == 'in_progress' %} + <svg width="15px" height="15px" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--emojione-monotone" preserveAspectRatio="xMidYMid meet"><path d="M61.287 53.542c-2.649-2.041-9.702-7.678-16.271-14.452c-4.366-4.505-6.223-9.015-9.533-12.429c-2.998-3.092-5.725-4.894-5.725-4.894l-.768.792l-5.188-5.35l2.004-2.067a.912.912 0 0 0 0-1.262l-.414-.427c.002-.002 5.898-7.936 13.353-5.742c.866.257 1.638.694 1.857.471c.298-.306-.837-1.482-1.502-2.162c-9.431-9.65-19.834 1.104-19.839 1.109l-.367-.379a.846.846 0 0 0-1.222 0l-9.239 9.528a.912.912 0 0 0 0 1.262s1.131 1.979-1.835 2.335c-1.194.145-1.942.414-2.366.769a431.18 431.18 0 0 0-1.979 2.009a.912.912 0 0 0 0 1.262l6.914 7.132a.847.847 0 0 0 1.223 0s1.906-1.99 1.947-2.042c.343-.438.605-1.208.743-2.44c.348-3.06 2.264-1.892 2.264-1.892a.846.846 0 0 0 1.224 0l2.004-2.067l5.186 5.349l-.768.793s1.748 2.813 4.746 5.905c3.309 3.413 7.683 5.328 12.05 9.833c6.567 6.774 12.032 14.047 14.014 16.78c.748 1.029.867.934 1.78-.009l2.849-2.938l2.847-2.937c.915-.946 1.009-1.068.011-1.84" fill="rgb(163, 32, 214)"></path><path d="M34.008 22.689a53.27 53.27 0 0 1 2.497 2.408c1.592 1.642 2.924 3.479 4.259 5.44l8.942-8.943A9.938 9.938 0 0 0 61.72 9.584L53.604 17.7l-5.76-1.543l-1.544-5.763l8.114-8.111a9.92 9.92 0 0 0-9.381 2.63a9.932 9.932 0 0 0-2.631 9.38l-8.394 8.396" fill="rgb(163, 32, 214)"></path><path d="M26.489 35.429a53.723 53.723 0 0 1-2.479-2.743l-9.717 9.718a9.926 9.926 0 0 0-9.381 2.629c-3.883 3.88-3.882 10.174 0 14.055a9.934 9.934 0 0 0 14.054 0a9.939 9.939 0 0 0 2.631-9.384l10.004-10.003c-1.84-1.338-3.567-2.679-5.112-4.272M13.483 57.821l-5.761-1.544l-1.543-5.762l4.218-4.215l5.76 1.541l1.543 5.763l-4.217 4.217" fill="rgb(163, 32, 214)"></path></svg> + <span style="color: rgb(163, 32, 214);">Р’ работе</span> + {% elif order.req_state == 'ready' %} + <svg fill="green" width="15px" height="15px" viewBox="0 0 1920 1920" xmlns="http://www.w3.org/2000/svg"> + <path d="M960 112.941c-467.125 0-847.059 379.934-847.059 847.059 0 467.125 379.934 847.059 847.059 847.059 467.125 0 847.059-379.934 847.059-847.059 0-467.125-379.934-847.059-847.059-847.059M960 1920C430.645 1920 0 1489.355 0 960S430.645 0 960 0s960 430.645 960 960-430.645 960-960 960m-107.449-800L759.05 869.491l90.509-90.51 141.524 141.524L1070.91 689.672l90.51 90.509-398.869 398.869Z" fill-rule="evenodd"/> + </svg> + <span style="color: green;">Готово</span> + + {% elif order.req_state == 'error' %} + <svg fill="red" width="15px" height="15px" viewBox="0 0 1920 1920" xmlns="http://www.w3.org/2000/svg"> + <path d="M960 112.941c-467.125 0-847.059 379.934-847.059 847.059 0 467.125 379.934 847.059 847.059 847.059 467.125 0 847.059-379.934 847.059-847.059 0-467.125-379.934-847.059-847.059-847.059M960 1920C430.645 1920 0 1489.355 0 960S430.645 0 960 0s960 430.645 960 960-430.645 960-960 960m158.867-1164.91l160.774 160.774-90.509 90.51-160.774-160.774-160.774 160.774-90.51-90.51 160.774-160.774-160.774-160.774 90.51-90.509 160.774 160.774 160.774-160.774 90.509 90.509-160.774 160.774Z" fill-rule="evenodd"/> + </svg> + <span style="color: red;">Ошибка</span> + {% endif %} + </div> + + + + </li> + {% endfor %} + </ul> + {% else %} + + {% endif %} + <a href="{% url 'create3d' %}" class="create-order-button">+ Создать РЅРѕРІСѓСЋ модель</a> + </td> + <!-- Печать остальных заказов РїРѕ статусам --> + {% for status, orders in orders_status_list %} + {% if status != 'in_progress' %} + <td class="status-column"> + {% if orders %} + <ul> + {% for order in orders %} + <li class="order-card" + data-id="{{ order.id }}" + data-date="{{ order.req_datetime|date:'Y-m-d' }}" + data-parameters="{{ order.req_parameters }}" + data-status="{{ order.req_state}}" + data-download-url="{% url 'download_item_from_nn' order.id %}"> + + <span style="font-size: 19px;">Запрос {{ order.id }} </span><br> + <span style="font-weight: 300; font-size: 16px; color: gray">{{ order.req_datetime|date:"Y-m-d" }}</span><br> + + + <br> + <br> + + + <svg width="15px" height="15px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path d="M13.5 3H12H8C6.34315 3 5 4.34315 5 6V18C5 19.6569 6.34315 21 8 21H12M13.5 3L19 8.625M13.5 3V7.625C13.5 8.17728 13.9477 8.625 14.5 8.625H19M19 8.625V11.8125" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> + <path d="M17.5 21L17.5 15M17.5 15L20 17.5M17.5 15L15 17.5" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> + </svg> + {% if order.sent_by_user %}{{ order.sent_by_user }}{% else %}Нет файла{% endif %} <br> + {% if order.recieved_from_server %} + <svg width="15px" height="15px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path d="M13.5 3H12H8C6.34315 3 5 4.34315 5 6V18C5 19.6569 6.34315 21 8 21H12M13.5 3L19 8.625M13.5 3V7.625C13.5 8.17728 13.9477 8.625 14.5 8.625H19M19 8.625V11.8125" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> + <path d="M17.5 15V21M17.5 21L15 18.5M17.5 21L20 18.5" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> + </svg> + {{ order.recieved_from_server }} + {% else %}{% endif %} <br> + + + <!-- Отображение статуса заказа --> + <div> + + {% if order.req_state == 'in_progress' %} + <svg width="15px" height="15px" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--emojione-monotone" preserveAspectRatio="xMidYMid meet"><path d="M61.287 53.542c-2.649-2.041-9.702-7.678-16.271-14.452c-4.366-4.505-6.223-9.015-9.533-12.429c-2.998-3.092-5.725-4.894-5.725-4.894l-.768.792l-5.188-5.35l2.004-2.067a.912.912 0 0 0 0-1.262l-.414-.427c.002-.002 5.898-7.936 13.353-5.742c.866.257 1.638.694 1.857.471c.298-.306-.837-1.482-1.502-2.162c-9.431-9.65-19.834 1.104-19.839 1.109l-.367-.379a.846.846 0 0 0-1.222 0l-9.239 9.528a.912.912 0 0 0 0 1.262s1.131 1.979-1.835 2.335c-1.194.145-1.942.414-2.366.769a431.18 431.18 0 0 0-1.979 2.009a.912.912 0 0 0 0 1.262l6.914 7.132a.847.847 0 0 0 1.223 0s1.906-1.99 1.947-2.042c.343-.438.605-1.208.743-2.44c.348-3.06 2.264-1.892 2.264-1.892a.846.846 0 0 0 1.224 0l2.004-2.067l5.186 5.349l-.768.793s1.748 2.813 4.746 5.905c3.309 3.413 7.683 5.328 12.05 9.833c6.567 6.774 12.032 14.047 14.014 16.78c.748 1.029.867.934 1.78-.009l2.849-2.938l2.847-2.937c.915-.946 1.009-1.068.011-1.84" fill="rgb(163, 32, 214)"></path><path d="M34.008 22.689a53.27 53.27 0 0 1 2.497 2.408c1.592 1.642 2.924 3.479 4.259 5.44l8.942-8.943A9.938 9.938 0 0 0 61.72 9.584L53.604 17.7l-5.76-1.543l-1.544-5.763l8.114-8.111a9.92 9.92 0 0 0-9.381 2.63a9.932 9.932 0 0 0-2.631 9.38l-8.394 8.396" fill="rgb(163, 32, 214)"></path><path d="M26.489 35.429a53.723 53.723 0 0 1-2.479-2.743l-9.717 9.718a9.926 9.926 0 0 0-9.381 2.629c-3.883 3.88-3.882 10.174 0 14.055a9.934 9.934 0 0 0 14.054 0a9.939 9.939 0 0 0 2.631-9.384l10.004-10.003c-1.84-1.338-3.567-2.679-5.112-4.272M13.483 57.821l-5.761-1.544l-1.543-5.762l4.218-4.215l5.76 1.541l1.543 5.763l-4.217 4.217" fill="rgb(163, 32, 214)"></path></svg> + <span style="color: rgb(163, 32, 214);">Р’ работе</span> + {% elif order.req_state == 'ready' %} + <svg width="15px" height="15px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path d="M8.5 12.5L10.5 14.5L15.5 9.5" stroke="rgb(0, 195, 0)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> + <path d="M7 3.33782C8.47087 2.48697 10.1786 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 10.1786 2.48697 8.47087 3.33782 7" stroke="rgb(0, 195, 0)" stroke-width="1.5" stroke-linecap="round"/> + </svg> + <span style="color: green;">Готово</span> + + {% elif order.req_state == 'error' %} + <svg width="15px" height="15px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path d="M16 8L8 16M8.00001 8L16 16M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z" stroke="red" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> + </svg> + <span style="color: red;">Ошибка</span> + {% endif %} + </div> + + + + </li> + {% endfor %} + </ul> + {% else %} + + {% endif %} + </td> + {% endif %} + {% endfor %} + </tr> + </tbody> + </table> +</div> + + <div id="orderModal" class="modal"> + <div class="modal-content"> + <span class="close">×</span> + <p>Здесь будет информация Рѕ заказе.</p> + </div> + </div> + + <!-- <table> <thead> <tr> {% for status, _ in orders_status_list %} @@ -56,11 +737,11 @@ {% for order in orders %} <li> Заказ ID: {{ order.id }} <br> - Дата: {{ order.order_datetime }} <br> - Параметры: {{ order.order_parameters }} <br> - Файл: {% if order.file_basename %}{{ order.file_basename }}{% else %}Нет файла{% endif %} <br> - - + Дата: {{ order.req_datetime }} <br> + Параметры: {{ order.req_parameters }} <br> + Отправленный файл: {% if order.sent_by_user %}{{ order.sent_by_user }}{% else %}Нет файла{% endif %} <br> + Полученный файл: {% if order.recieved_from_server %}{{ order.recieved_from_server }}{% else %}Нет файла{% endif %} <br> + {% if order.recieved_from_server %}<a href="{% url 'download_item_from_nn' order.id %}">Скачать</a>{% else %}Нет файла{% endif %} </li> {% endfor %} </ul> @@ -71,6 +752,6 @@ {% endfor %} </tr> </tbody> - </table> + </table> --> </body> </html> diff --git a/movere_local/mainapp/templates/mainapp/view_orders.html b/movere_local/mainapp/templates/mainapp/view_orders.html index 3e255f65e34d2f85773e48bdf37c96958b1c90aa..880179e28cff9b3c5e94c2eec8ec7e56135879f1 100644 --- a/movere_local/mainapp/templates/mainapp/view_orders.html +++ b/movere_local/mainapp/templates/mainapp/view_orders.html @@ -1,95 +1,775 @@ <!DOCTYPE html> <html lang="en"> <head> + <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>РњРѕРё заказы</title> + <meta name="csrf-token" content="{{ csrf_token }}"> + <title>MOVERE | РњРѕРё заявки </title> + + <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js"></script> + <script src="https://cdn.jsdelivr.net/npm/three/examples/js/loaders/OBJLoader.js"></script> + <script src="https://cdn.jsdelivr.net/npm/three/examples/js/loaders/STLLoader.js"></script> + + + <style> - table { + + {% load static %} + @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap'); + @import url('https://fonts.googleapis.com/css2?family=Krona+One&display=swap'); + @import url('https://fonts.googleapis.com/css2?family=Mulish:wght@200..1000&display=swap'); + + + body { + margin: 0; + font-family: "Krona One", serif; + font-weight: 400; + font-style: normal; + background-color: #121212; + color: #FFFFFF; + display: flex; + flex-direction: column; + align-items: center; + height: 100vh; + } + + .navbar { + display: flex; + justify-content: space-between; + align-items: center; width: 100%; - border-collapse: collapse; + background-color: #121212; /* Цвет РІ тон страницы */ + padding: 30px 20px; + position: fixed; + top: 0; + z-index: 10; + /* box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); */ } - th, td { - border: 1px solid #ddd; - padding: 8px; + + .navbar .logo { + display: flex; /* Располагает элементы (логотип Рё текст) РІ РѕРґРЅСѓ строку */ + align-items: center; /* Вертикальное выравнивание элементов РїРѕ центру */ + margin-left: 100px; + margin-top: 20px; + /* margin-left: 30px; */ + } + + .navbar .logo img { + height: 60px; /* Размер логотипа */ + margin-right: 15px; /* Отступ между логотипом Рё текстом */ + } + + .navbar .logo span { + font-size: 20px; /* Размер текста */ + font-weight: bold; + color: #FFFFFF; /* Цвет текста */ + white-space: nowrap; /* Запрещает перенос текста РЅР° РЅРѕРІСѓСЋ строку */ + } + + + .navbar .profile-btn { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Mulish"; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + + .navbar .profile-btn:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + + .navbar .storage_home_button { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Mulish", sans-serif; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + + .navbar .storage_home_button:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + + + .navbar .btns_in_nav { + display: flex; + margin-right: 10%; + } + + + + .view_orders_h1 { + align-self: flex-start; /* Расположить элемент слева */ + /* margin: 20px; Отступы сверху Рё слева */ + color: rgb(255, 253, 253); + font-size: 20px; + /* font-family: "Krona One", serif; */ text-align: left; + margin-top: 10%; + padding: 0 5%; + font-family: "Mulish", serif; + } + + + .container { + display: flex; + gap: 10px; } + + + .card { + width: 200px; + height: 300px; + background-color: #3A3A3A; + border-radius: 10px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-end; + overflow: hidden; + position: relative; + cursor: pointer; + transition: transform 0.3s; + } + + .card:hover { + transform: scale(1.05); + } + + .card img { + width: 100%; + height: 100%; + object-fit: cover; + position: absolute; + top: 0; + left: 0; + z-index: 1; + } + + .card video { + width: 100%; + height: 100%; + object-fit: cover; + display: none; + position: absolute; + top: 0; + left: 0; + z-index: 2; + } + + .card video[data-playing="true"] { + display: block; + } + + .card .label { + position: relative; + font-family: 'Mulish', Arial, sans-serif; + color: #FFFFFF; + padding: 5px 10px; + border-radius: 5px; + font-size: 14px; + font-weight: bold; + margin-bottom: 5px; + text-align: center; + z-index: 3; + } + + .card .description { + font-family: 'Mulish', Arial, sans-serif; + position: relative; + color: #FFFFFF; + padding: 5px 10px; + border-radius: 5px; + font-size: 12px; + text-align: center; + margin-bottom: 10px; + z-index: 3; + } + + .home-button { + background-color: transparent; /* Фон РєРЅРѕРїРєРё прозрачный */ + position: absolute; + padding: 1px 1px; /* Отступы внутри РєРЅРѕРїРєРё */ + top: 7%; + right: 3%; + width: 7%; + font-size: 20px; + font-weight: 700; + color: rgb(247, 249, 250); /* Цвет текста */ + border: none; /* Убирает границу */ + outline: none; /* Убирает контур РїСЂРё фокусе */ + } + + .create-order-button { + display: block; + padding: 8px 16px; + background-color: transparent; + color: white; + font-size: 20px; + text-decoration: none; + border-radius: 5px; + text-align: center; + transition: background-color 0.3s; /* Добавляем плавную анимацию */ + z-index: 1000; /* Убедитесь, что РєРЅРѕРїРєР° будет РІРёРґРЅР° над РґСЂСѓРіРёРјРё элементами */ + } + + .create-order-button:hover { + background-color: #4a4646; /* меняем цвет фона РЅР° серый РїСЂРё наведении */ + + } + + .modal { + display: none; /* Скрытое РїРѕ умолчанию */ + position: fixed; /* Фиксийрованное положение */ + z-index: 1; /* Лежит над РґСЂСѓРіРёРјРё элементами */ + left: 0; + top: 0; + width: 100%; /* Полная ширина */ + height: 100%; /* Полная высота */ + overflow: auto; /* Включение прокрутки, если необходимо */ + background-color: rgb(0,0,0); /* Цвет фона */ + background-color: rgba(0,0,0,0.4); /* Черный фон СЃ небольшой прозрачностью */ + border-radius: 20px; + } + + .modal-content { + background-color: #d7d7d7; + color: black; + margin: 15% auto; /* 15% сверху Рё РїРѕ центру РїРѕ горизонтали */ + padding: 20px; + border: 1px solid #888; + width: 50%; /* Можете изменить ширину */ + border-radius: 20px; + font-family: "Mulish", sans-serif; + } + /* Общий стиль для РєРЅРѕРїРѕРє */ +.modal-btn { + display: inline-block; + padding: 10px 20px; + font-size: 16px; + font-family: "Mulish", sans-serif; + font-weight: bold; + color: white; + background-color: #4CAF50; /* Зелёный цвет РїРѕ умолчанию */ + border: none; + border-radius: 8px; + cursor: pointer; + transition: background-color 0.3s, transform 0.2s; +} + +/* РљРЅРѕРїРєР° отмены заказа */ +.cancel-btn { + background-color: #f44336; /* Красный цвет */ +} + +.cancel-btn:hover { + background-color: #d32f2f; /* Темнее РїСЂРё наведении */ +} + +/* РљРЅРѕРїРєР° "Р’ архив" */ +.archive-btn { + background-color: #2196F3; /* РЎРёРЅРёР№ цвет */ +} + +.archive-btn:hover { + background-color: #1976D2; /* Темнее РїСЂРё наведении */ +} + +/* Рффект нажатия */ +.modal-btn:active { + transform: scale(0.95); +} + +/* Модальное РѕРєРЅРѕ: стиль для действий */ +.modal-actions { + margin-top: 20px; + display: flex; + gap: 10px; /* Расстояние между кнопками */ +} + + .close { + color: #aaa; + float: right; + font-size: 28px; + font-weight: bold; + } + + .close:hover, + .close:focus { + color: black; + cursor: pointer; + } + + + + + table { + width: 90%; + table-layout: fixed; /* Фиксированная ширина колонок */ + border-collapse: separate; + border-spacing: 0; + margin: 10px auto; + border-radius: 10px; + overflow: hidden; + background-color: #1e1e1e; + font-family: "Mulish", serif; + font-optical-sizing: auto; + font-weight: 400; + font-style: normal; + } + + th, td { + width: 20%; /* Устанавливаем одинаковую ширину для всех колонок */ + border-bottom: 0.5px solid #606060; + border-right: 0.5px solid #5f5f5f; + padding: 12px 15px; + color: #f0f0f0; + vertical-align: top; /* Содержимое РїРѕ верхнему краю */ + } + + + + th:last-child, td:last-child { + border-right: none; /* Убирает правую границу Сѓ последней колонки */ + width: 20%; + } + + th:first-child, td:first-child { + width: 20%; /* Установите ширину первого столбца РїРѕ вашему усмотрению */ + } + th { - background-color: #f2f2f2; + background-color: #292929; /* Более темный фон для заголовков */ + color: #ffffff; /* Белый цвет текста для заголовков */ + + } + + td { + vertical-align: top; /* Выравнивание содержимого ячейки РїРѕ верху */ } + .status-column { - width: 20%; + width: 20%; /*РЁРёСЂРёРЅР° колонки статуса*/ } + + .status-column ul { + list-style-type: none; /* Убирает маркеры СЃРїРёСЃРєР° */ + padding: 0; /* Убирает отступ слева, если РѕРЅ есть */ + top: 10px; + } + + td .order-card { + margin: 10px; + width: 90%; /* Карточка занимает РІСЃСЋ ширину колонки */ + box-sizing: border-box; /* Включаем padding Рё border РІ расчет ширины */ + /* margin: 0 auto; Центрируем содержимое внутри ячейки */ + background-color: #4a4646; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + border: 2px solid rgba(255, 255, 255, 0.62); + border-width: 0.0px; + color: white; + border-radius: 8px; + padding: 10px; + text-wrap: wrap; + transition-duration: 0.2s; + + + } + td .order-card:hover { + + background-color: #524f4f;/* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.05); + cursor: pointer; + + } + + + + + </style> - <script> - function confirmCancel(orderId) { - if (confirm('Р’С‹ уверены, что хотите отменить этот заказ?')) { - document.getElementById('cancel-form-' + orderId).submit(); + + + + +<script> + // Объекты для переводов + const translations = { + keys: { + position: "Должность", + purpose: "Цель 3D-печати", + additional_purpose: "Дополнительная информация", + material: "Материал" + }, + values: { + student: "Студент Р’РЁР", + professor: "Преподаватель Р’РЁР", + worker: "Сотрудник Р’РЁР", + other: "Другое", + course: "Курсовая работа", + diploma: "Дипломная работа", + project: "Проект", + pla: "Пластик PLA", + abs: "Пластик ABS", + tpu: "Резина TPU", + wait_confirmation: "Ожидает подтверждения", + in_work: "Р’ работе", + ready: "Готов", + done: "Получен", + canceled: "Отменен" + } + }; + + // Функция перевода ключей Рё значений + function translateParameters(parameters) { + const translated = {}; + for (const [key, value] of Object.entries(parameters)) { + const translatedKey = translations.keys[key] || key; // Перевод ключа + if (Array.isArray(value)) { + // Если значение — массив, переводим элементы массива + translated[translatedKey] = value.map(item => translations.values[item] || item).join(", "); + } else { + // Переводим одиночное значение + translated[translatedKey] = translations.values[value] || value; + } + } + return translated; + } + + document.addEventListener('DOMContentLoaded', function () { + const modal = document.getElementById("orderModal"); + const closeBtn = document.querySelector(".close"); + const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content'); + + // Открытие модального РѕРєРЅР° РїСЂРё клике РЅР° карточку + document.querySelectorAll('.order-card').forEach(card => { + card.addEventListener('click', function () { + const orderId = this.getAttribute('data-id'); + const orderDate = this.getAttribute('data-date'); + const orderParameters = this.getAttribute('data-parameters'); + const orderStatus = this.getAttribute('data-status'); + + let parsedParameters = {}; + try { + parsedParameters = JSON.parse(orderParameters.replace(/'/g, '"')); + } catch (e) { + console.error("Ошибка парсинга параметров:", e); + } + + // Перевод параметров + const translatedParameters = translateParameters(parsedParameters); + + // Генерация HTML параметров + let parametersHTML = '<ul>'; + for (const [key, value] of Object.entries(translatedParameters)) { + parametersHTML += `<li><strong>${key}:</strong> ${value}</li>`; + } + parametersHTML += '</ul>'; + + const translatedStatus = translations.values[orderStatus] || orderStatus; + + // Действия + let actionsHTML = ''; + if (orderStatus === 'wait_confirmation') { + actionsHTML = ` + <button class="modal-btn cancel-btn" onclick="confirmCancel(${orderId})">Отменить заказ</button> + <form id="cancel-form-${orderId}" method="post" action="/cancel_order/${orderId}/" style="display: none;"> + <input type="hidden" name="csrfmiddlewaretoken" value="${csrfToken}"> + </form> + `; + } else if (orderStatus === 'done' || orderStatus === 'canceled') { + actionsHTML = ` + <form method="post" action="/archive_order/${orderId}/"> + <input type="hidden" name="csrfmiddlewaretoken" value="${csrfToken}"> + <button class="modal-btn archive-btn" type="submit">Р’ архив</button> + </form> + `; + } + + // Заполняем содержимое модального РѕРєРЅР° + modal.querySelector('p').innerHTML = ` + <strong>ID заказа:</strong> ${orderId}<br> + <strong>Дата:</strong> ${orderDate}<br> + <strong>Параметры:</strong> ${parametersHTML} + <strong>Статус:</strong> ${translatedStatus}<br> + <div class="modal-actions">${actionsHTML}</div> + `; + + modal.style.display = "block"; + }); + }); + + // Закрытие модального РѕРєРЅР° + closeBtn.onclick = function () { + modal.style.display = "none"; + }; + + window.onclick = function (event) { + if (event.target === modal) { + modal.style.display = "none"; + } + }; + + document.addEventListener('keydown', function (event) { + if (event.key === "Escape") { + modal.style.display = "none"; } + }); + }); + + function confirmCancel(orderId) { + if (confirm('Р’С‹ уверены, что хотите отменить этот заказ?')) { + document.getElementById('cancel-form-' + orderId).submit(); } - </script> + } +</script> + + + + </head> <body> - <h1>РЎРїРёСЃРѕРє заказов</h1> - - <a href="{% url 'create_order' %}" style="display: inline-block; padding: 10px 20px; background-color: #4CAF50; color: white; text-decoration: none; border-radius: 5px;">Создать новый заказ</a> - <button onclick="location.href='{% url 'home' %}'">Домой</button> - - <table> - <thead> - <tr> - {% for status, _ in orders_status_list %} - <th class="status-column"> - {% if status == 'wait_confirmation' %} - Ожидает подтверждения - {% elif status == 'in_work' %} - Отправлен РЅР° печать - {% elif status == 'ready' %} - Готов - {% elif status == 'done' %} - Выполнен - {% elif status == 'canceled' %} - Отменен - {% endif %} - </th> - {% endfor %} - </tr> - </thead> - <tbody> - <tr> - {% for status, orders in orders_status_list %} + + + + <div class="navbar"> + <div class="logo"> + <a href="{% url 'home' %}" style="text-decoration: none; color: inherit; display: flex; align-items: center;"> + <img src="{% static 'mainapp/images/download.png' %}" alt="Logo"> + <span>MOVERELAB</span> + </a> + </div> + <div class="btns_in_nav"> + <button class="profile-btn" onclick="location.href='{% url 'home' %}'">Домой</button> + <button class="profile-btn" onclick="location.href='{% url 'profile' %}'">Профиль</button> + </div> + </div> + + + + + <div class = 'view_orders_h1'> + <h1><span style="font-family: 'Krona One', monospace; font-weight: 400; font-size: 40px;">>>></span> Р—РђРЇР’РљР</h1> + </div> + + <div class='view_orders_table'> + <table> + <thead> + <tr> + {% for status, _ in orders_status_list %} + <th class="status-column"> + {% if status == 'wait_confirmation' %} + Ожидает подтверждения + {% elif status == 'in_work' %} + Отправлен РЅР° печать + {% elif status == 'ready' %} + Готов Рє выдаче + {% elif status == 'done' %} + Выполнен + {% elif status == 'canceled' %} + Отменен + {% endif %} + </th> + {% endfor %} + </tr> + </thead> + <tbody> + <tr> + <!-- Ячейка для РєРЅРѕРїРєРё "Добавить новый заказ" --> <td class="status-column"> - {% if orders %} + {% if orders_status_list.0.0 == 'wait_confirmation' %} <ul> - {% for order in orders %} - <li> - Заказ ID: {{ order.id }} <br> - Дата: {{ order.order_datetime }} <br> - Параметры: {{ order.order_parameters }} <br> - Файл: {% if order.file_basename %}{{ order.file_basename }}{% else %}Нет файла{% endif %} <br> - - {% if order.order_state == 'wait_confirmation' %} - <!-- РљРЅРѕРїРєР° для отмены заказа СЃ подтверждением --> - <button onclick="confirmCancel({{ order.id }})">Отменить заказ</button> - <form id="cancel-form-{{ order.id }}" method="post" action="{% url 'cancel_order' order.id %}" style="display: none;"> - {% csrf_token %} - </form> - {% elif order.order_state == 'done' or order.order_state == 'canceled' %} - <form method="post" action="{% url 'archive_order' order.id %}"> - {% csrf_token %} - <button type="submit">Р’ архив</button> - </form> + {% for order, params in orders_status_list.0.1 %} + <li class="order-card" + data-id="{{ order.id }}" + data-date="{{ order.order_datetime|date:'Y-m-d' }}" + data-parameters="{{ params }}" + data-status="{{ order.order_state }}"> + + <span style="font-size: 19px;">Номер заказа: {{ order.id }} </span><br> + <span style="font-weight: 300; font-size: 16px; color: gray">{{ order.order_datetime|date:"Y-m-d" }}</span><br> + <!-- Параметры: <br> + {% for param_key, param_value in params.items %} + {% if param_key != 'purpose' %} + {{param_key}}: {{param_value}} <br> + {% else %} + {{param_key}}: {{param_value|join:", "}} {% endif %} - </li> - {% endfor %} + {% endfor %} --> + + <!-- <div id="order-parameters-{{ order.id }}">{{ order.order_parameters }}</div><br> --> + <br> + <br> + + + <svg fill="#ffffff" width="15px" height="15px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg"> + <title>file</title> + <path d="M26.731 9.902c-0.005-0.035-0.011-0.066-0.019-0.095l0.001 0.005c-0.031-0.134-0.094-0.249-0.182-0.342l0 0-8-8c-0.092-0.087-0.207-0.15-0.335-0.181l-0.005-0.001c-0.027-0.008-0.059-0.014-0.092-0.019l-0.003-0c-0.026-0.007-0.059-0.014-0.092-0.019l-0.004-0h-12c-0.414 0-0.75 0.336-0.75 0.75v0 28c0 0.414 0.336 0.75 0.75 0.75h20c0.414-0 0.75-0.336 0.75-0.75v0-20c-0.005-0.038-0.012-0.071-0.020-0.103l0.001 0.005zM24.189 9.25h-5.439v-5.439zM6.75 29.25v-26.5h10.5v7.25c0 0.414 0.336 0.75 0.75 0.75h7.25v18.5z"></path> + </svg> + {% if order.file_basename %}{{ order.file_basename }}{% else %}Нет файла{% endif %}<br> + + + + <!-- Отображение статуса заказа --> + <div> + {% if order.order_state == 'wait_confirmation' %} + <svg fill="rgb(58, 174, 231)" width="15px" height="15px" viewBox="0 0 1920 1920" xmlns="http://www.w3.org/2000/svg"> + <path d="M960 112.941c-467.125 0-847.059 379.934-847.059 847.059 0 467.125 379.934 847.059 847.059 847.059 467.125 0 847.059-379.934 847.059-847.059 0-467.125-379.934-847.059-847.059-847.059M960 1920C430.645 1920 0 1489.355 0 960S430.645 0 960 0s960 430.645 960 960-430.645 960-960 960m417.905-575.955L903.552 988.28V395.34h112.941v536.47l429.177 321.77-67.765 90.465Z" fill-rule="evenodd"/> + </svg> + <span style="color: rgb(58, 174, 231);">Ожидает подтверждения</span> + {% elif order.order_state == 'in_work' %} + <svg width="15px" height="15px" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--emojione-monotone" preserveAspectRatio="xMidYMid meet"><path d="M61.287 53.542c-2.649-2.041-9.702-7.678-16.271-14.452c-4.366-4.505-6.223-9.015-9.533-12.429c-2.998-3.092-5.725-4.894-5.725-4.894l-.768.792l-5.188-5.35l2.004-2.067a.912.912 0 0 0 0-1.262l-.414-.427c.002-.002 5.898-7.936 13.353-5.742c.866.257 1.638.694 1.857.471c.298-.306-.837-1.482-1.502-2.162c-9.431-9.65-19.834 1.104-19.839 1.109l-.367-.379a.846.846 0 0 0-1.222 0l-9.239 9.528a.912.912 0 0 0 0 1.262s1.131 1.979-1.835 2.335c-1.194.145-1.942.414-2.366.769a431.18 431.18 0 0 0-1.979 2.009a.912.912 0 0 0 0 1.262l6.914 7.132a.847.847 0 0 0 1.223 0s1.906-1.99 1.947-2.042c.343-.438.605-1.208.743-2.44c.348-3.06 2.264-1.892 2.264-1.892a.846.846 0 0 0 1.224 0l2.004-2.067l5.186 5.349l-.768.793s1.748 2.813 4.746 5.905c3.309 3.413 7.683 5.328 12.05 9.833c6.567 6.774 12.032 14.047 14.014 16.78c.748 1.029.867.934 1.78-.009l2.849-2.938l2.847-2.937c.915-.946 1.009-1.068.011-1.84" fill="rgb(163, 32, 214)"></path><path d="M34.008 22.689a53.27 53.27 0 0 1 2.497 2.408c1.592 1.642 2.924 3.479 4.259 5.44l8.942-8.943A9.938 9.938 0 0 0 61.72 9.584L53.604 17.7l-5.76-1.543l-1.544-5.763l8.114-8.111a9.92 9.92 0 0 0-9.381 2.63a9.932 9.932 0 0 0-2.631 9.38l-8.394 8.396" fill="rgb(163, 32, 214)"></path><path d="M26.489 35.429a53.723 53.723 0 0 1-2.479-2.743l-9.717 9.718a9.926 9.926 0 0 0-9.381 2.629c-3.883 3.88-3.882 10.174 0 14.055a9.934 9.934 0 0 0 14.054 0a9.939 9.939 0 0 0 2.631-9.384l10.004-10.003c-1.84-1.338-3.567-2.679-5.112-4.272M13.483 57.821l-5.761-1.544l-1.543-5.762l4.218-4.215l5.76 1.541l1.543 5.763l-4.217 4.217" fill="rgb(163, 32, 214)"></path></svg> + <span style="color: rgb(163, 32, 214);">Р’ работе</span> + {% elif order.order_state == 'ready' %} + <svg fill="green" width="15px" height="15px" viewBox="0 0 1920 1920" xmlns="http://www.w3.org/2000/svg"> + <path d="M960 112.941c-467.125 0-847.059 379.934-847.059 847.059 0 467.125 379.934 847.059 847.059 847.059 467.125 0 847.059-379.934 847.059-847.059 0-467.125-379.934-847.059-847.059-847.059M960 1920C430.645 1920 0 1489.355 0 960S430.645 0 960 0s960 430.645 960 960-430.645 960-960 960m-107.449-800L759.05 869.491l90.509-90.51 141.524 141.524L1070.91 689.672l90.51 90.509-398.869 398.869Z" fill-rule="evenodd"/> + </svg> + <span style="color: green;">Готов</span> + {% elif order.order_state == 'done' %} + <svg fill="grey" width="15px" height="15px" viewBox="0 0 1920 1920" xmlns="http://www.w3.org/2000/svg"> + <path d="M960 112.941c-467.125 0-847.059 379.934-847.059 847.059 0 467.125 379.934 847.059 847.059 847.059 467.125 0 847.059-379.934 847.059-847.059 0-467.125-379.934-847.059-847.059-847.059M960 1920C430.645 1920 0 1489.355 0 960S430.645 0 960 0s960 430.645 960 960-430.645 960-960 960m113.255-1135.592H846.745v640h226.51v-640Z" fill-rule="evenodd"/> + </svg> + <span style="color: grey;">Получен</span> + {% elif order.order_state == 'canceled' %} + <svg fill="red" width="15px" height="15px" viewBox="0 0 1920 1920" xmlns="http://www.w3.org/2000/svg"> + <path d="M960 112.941c-467.125 0-847.059 379.934-847.059 847.059 0 467.125 379.934 847.059 847.059 847.059 467.125 0 847.059-379.934 847.059-847.059 0-467.125-379.934-847.059-847.059-847.059M960 1920C430.645 1920 0 1489.355 0 960S430.645 0 960 0s960 430.645 960 960-430.645 960-960 960m158.867-1164.91l160.774 160.774-90.509 90.51-160.774-160.774-160.774 160.774-90.51-90.51 160.774-160.774-160.774-160.774 90.51-90.509 160.774 160.774 160.774-160.774 90.509 90.509-160.774 160.774Z" fill-rule="evenodd"/> + </svg> + <span style="color: red;">Отменен</span> + {% endif %} + </div> + + + <!-- РљРЅРѕРїРєР° для отмены заказа СЃ подтверждением --> + <!-- {% if order.order_state == 'wait_confirmation' %} + <button class="delete-btn" onclick="confirmCancel({{ order.id }})">Отменить заказ</button> + <form id="cancel-form-{{ order.id }}" method="post" action="{% url 'cancel_order' order.id %}" style="display: none;"> + {% csrf_token %} + </form> + {% elif order.order_state == 'done' or order.order_state == 'canceled' %} + <form method="post" action="{% url 'archive_order' order.id %}"> + {% csrf_token %} + <button type="submit">Р’ архив</button> + </form> + {% endif %} --> + </li> + {% endfor %} </ul> {% else %} - Нет заказов + {% endif %} + <a href="{% url 'create_order' %}" class="create-order-button">+ Создать новый заказ</a> </td> - {% endfor %} - </tr> - </tbody> - </table> + <!-- Печать остальных заказов РїРѕ статусам --> + {% for status, orders in orders_status_list %} + {% if status != 'wait_confirmation' %} + <td class="status-column"> + {% if orders %} + <ul> + {% for order, params in orders %} + <li class="order-card" + data-id="{{ order.id }}" + data-date="{{ order.order_datetime|date:'Y-m-d' }}" + data-parameters="{{ order.order_parameters }}" + data-status="{{ order.order_state }}"> + <span style="font-size: 19px;">Номер заказа: {{ order.id }} </span><br> + <span style="font-weight: 300; font-size: 16px; color: gray">{{ order.order_datetime|date:"Y-m-d" }}</span><br> + + <!-- Параметры: <br> + {% for param_key, param_value in params.items %} + {% if param_key != 'purpose' %} + {{param_key}}: {{param_value}} <br> + {% else %} + {{param_key}}: {{param_value|join:", "}} + {% endif %} + {% endfor %} --> + <br> + <br> + <svg fill="#ffffff" width="15px" height="15px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg"> + <title>file</title> + <path d="M26.731 9.902c-0.005-0.035-0.011-0.066-0.019-0.095l0.001 0.005c-0.031-0.134-0.094-0.249-0.182-0.342l0 0-8-8c-0.092-0.087-0.207-0.15-0.335-0.181l-0.005-0.001c-0.027-0.008-0.059-0.014-0.092-0.019l-0.003-0c-0.026-0.007-0.059-0.014-0.092-0.019l-0.004-0h-12c-0.414 0-0.75 0.336-0.75 0.75v0 28c0 0.414 0.336 0.75 0.75 0.75h20c0.414-0 0.75-0.336 0.75-0.75v0-20c-0.005-0.038-0.012-0.071-0.020-0.103l0.001 0.005zM24.189 9.25h-5.439v-5.439zM6.75 29.25v-26.5h10.5v7.25c0 0.414 0.336 0.75 0.75 0.75h7.25v18.5z"></path> + </svg> + {% if order.file_basename %}{{ order.file_basename }}{% else %} Нет файла {% endif %} <br> + + <!-- Отображение статуса заказа --> + <div> + {% if order.order_state == 'wait_confirmation' %} + <svg fill="rgb(58, 174, 231)" width="15px" height="15px" viewBox="0 0 1920 1920" xmlns="http://www.w3.org/2000/svg"> + <path d="M960 112.941c-467.125 0-847.059 379.934-847.059 847.059 0 467.125 379.934 847.059 847.059 847.059 467.125 0 847.059-379.934 847.059-847.059 0-467.125-379.934-847.059-847.059-847.059M960 1920C430.645 1920 0 1489.355 0 960S430.645 0 960 0s960 430.645 960 960-430.645 960-960 960m417.905-575.955L903.552 988.28V395.34h112.941v536.47l429.177 321.77-67.765 90.465Z" fill-rule="evenodd"/> + </svg> + <span style="color: rgb(58, 174, 231);">Ожидает подтверждения</span> + {% elif order.order_state == 'in_work' %} + <svg width="15px" height="15px" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--emojione-monotone" preserveAspectRatio="xMidYMid meet"><path d="M61.287 53.542c-2.649-2.041-9.702-7.678-16.271-14.452c-4.366-4.505-6.223-9.015-9.533-12.429c-2.998-3.092-5.725-4.894-5.725-4.894l-.768.792l-5.188-5.35l2.004-2.067a.912.912 0 0 0 0-1.262l-.414-.427c.002-.002 5.898-7.936 13.353-5.742c.866.257 1.638.694 1.857.471c.298-.306-.837-1.482-1.502-2.162c-9.431-9.65-19.834 1.104-19.839 1.109l-.367-.379a.846.846 0 0 0-1.222 0l-9.239 9.528a.912.912 0 0 0 0 1.262s1.131 1.979-1.835 2.335c-1.194.145-1.942.414-2.366.769a431.18 431.18 0 0 0-1.979 2.009a.912.912 0 0 0 0 1.262l6.914 7.132a.847.847 0 0 0 1.223 0s1.906-1.99 1.947-2.042c.343-.438.605-1.208.743-2.44c.348-3.06 2.264-1.892 2.264-1.892a.846.846 0 0 0 1.224 0l2.004-2.067l5.186 5.349l-.768.793s1.748 2.813 4.746 5.905c3.309 3.413 7.683 5.328 12.05 9.833c6.567 6.774 12.032 14.047 14.014 16.78c.748 1.029.867.934 1.78-.009l2.849-2.938l2.847-2.937c.915-.946 1.009-1.068.011-1.84" fill="rgb(196, 61, 250)"></path><path d="M34.008 22.689a53.27 53.27 0 0 1 2.497 2.408c1.592 1.642 2.924 3.479 4.259 5.44l8.942-8.943A9.938 9.938 0 0 0 61.72 9.584L53.604 17.7l-5.76-1.543l-1.544-5.763l8.114-8.111a9.92 9.92 0 0 0-9.381 2.63a9.932 9.932 0 0 0-2.631 9.38l-8.394 8.396" fill="rgb(196, 61, 250)"></path><path d="M26.489 35.429a53.723 53.723 0 0 1-2.479-2.743l-9.717 9.718a9.926 9.926 0 0 0-9.381 2.629c-3.883 3.88-3.882 10.174 0 14.055a9.934 9.934 0 0 0 14.054 0a9.939 9.939 0 0 0 2.631-9.384l10.004-10.003c-1.84-1.338-3.567-2.679-5.112-4.272M13.483 57.821l-5.761-1.544l-1.543-5.762l4.218-4.215l5.76 1.541l1.543 5.763l-4.217 4.217" fill="rgb(196, 61, 250)"></path></svg> + + <span style="color: rgb(196, 61, 250);">Р’ работе</span> + {% elif order.order_state == 'ready' %} + <svg width="15px" height="15px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path d="M8.5 12.5L10.5 14.5L15.5 9.5" stroke="rgb(0, 195, 0)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> + <path d="M7 3.33782C8.47087 2.48697 10.1786 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 10.1786 2.48697 8.47087 3.33782 7" stroke="rgb(0, 195, 0)" stroke-width="1.5" stroke-linecap="round"/> + </svg> + <span style="color: rgb(0, 195, 0);">Готов</span> + {% elif order.order_state == 'done' %} + <svg width="15px" height="15px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path fill-rule="evenodd" clip-rule="evenodd" d="M17.4964 21.9284C17.844 21.7894 18.1491 21.6495 18.4116 21.5176C18.9328 22.4046 19.8969 23 21 23C22.6569 23 24 21.6568 24 20V14C24 12.3431 22.6569 11 21 11C19.5981 11 18.4208 11.9616 18.0917 13.2612C17.8059 13.3614 17.5176 13.4549 17.2253 13.5384C16.3793 13.7801 15.3603 13.9999 14.5 13.9999C13.2254 13.9999 10.942 13.5353 9.62034 13.2364C8.61831 13.0098 7.58908 13.5704 7.25848 14.5622L6.86313 15.7483C5.75472 15.335 4.41275 14.6642 3.47619 14.1674C2.42859 13.6117 1.09699 14.0649 0.644722 15.1956L0.329309 15.9841C0.0210913 16.7546 0.215635 17.6654 0.890813 18.2217C1.66307 18.8581 3.1914 20.0378 5.06434 21.063C6.91913 22.0782 9.21562 22.9999 11.5 22.9999C14.1367 22.9999 16.1374 22.472 17.4964 21.9284ZM20 20C20 20.5523 20.4477 21 21 21C21.5523 21 22 20.5523 22 20V14C22 13.4477 21.5523 13 21 13C20.4477 13 20 13.4477 20 14V20ZM14.5 15.9999C12.9615 15.9999 10.4534 15.4753 9.17918 15.1872C9.17918 15.1872 8.84483 16.1278 8.7959 16.2745L12.6465 17.2776C13.1084 17.3979 13.372 17.8839 13.2211 18.3367C13.0935 18.7194 12.7092 18.9536 12.3114 18.8865C11.0903 18.6805 8.55235 18.2299 7.25848 17.8365C5.51594 17.3066 3.71083 16.5559 2.53894 15.9342C2.53894 15.9342 2.22946 16.6189 2.19506 16.7049C2.92373 17.3031 4.32792 18.3799 6.0246 19.3086C7.76488 20.2611 9.70942 20.9999 11.5 20.9999C15.023 20.9999 17.1768 19.9555 18 19.465V15.3956C16.8681 15.7339 15.6865 15.9999 14.5 15.9999Z" fill="grey"/> + <path d="M12 1C11.4477 1 11 1.44772 11 2V7.58564L9.7071 6.29278C9.3166 5.9024 8.68342 5.9024 8.29292 6.29278C7.90235 6.68341 7.90235 7.31646 8.29292 7.70709L11.292 10.7063C11.6823 11.0965 12.3149 11.0968 12.7055 10.707L15.705 7.71368C16.0955 7.3233 16.0955 6.69 15.705 6.29962C15.3145 5.90899 14.6813 5.90899 14.2908 6.29962L13 7.59034V2C13 1.44772 12.5523 1 12 1Z" fill="grey"/> + </svg> + <span style="color: grey;">Получен</span> + {% elif order.order_state == 'canceled' %} + <svg width="15px" height="15px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path d="M16 8L8 16M8.00001 8L16 16M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z" stroke="red" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> + </svg> + <span style="color: red;">Отменен</span> + {% endif %} + </div> + + <!-- {% if order.order_state == 'wait_confirmation' %} + РљРЅРѕРїРєР° для отмены заказа СЃ подтверждением + <button onclick="confirmCancel({{ order.id }})" style="margin-bottom: 20px;" >Отменить заказ</button> + <form id="cancel-form-{{ order.id }}" method="post" action="{% url 'cancel_order' order.id %}" style="display: none;"> + {% csrf_token %} + </form> + {% elif order.order_state == 'done' or order.order_state == 'canceled' %} + <form method="post" action="{% url 'archive_order' order.id %}"> + {% csrf_token %} + <button type="submit">Р’ архив</button> + </form> + {% endif %} --> + </li> + {% endfor %} + </ul> + {% else %} + + {% endif %} + </td> + {% endif %} + {% endfor %} + </tr> + </tbody> + </table> + </div> + + <div id="orderModal" class="modal"> + <div class="modal-content"> + <span class="close">×</span> + <p>Здесь будет информация Рѕ заказе.</p> + </div> + </div> </body> </html> diff --git a/movere_local/mainapp/templates/mainapp/view_story_and_files.html b/movere_local/mainapp/templates/mainapp/view_story_and_files.html index a00f37784b690e96e2e3a6e142f751f382cae920..87ac62964e9b3327ade470403eabdf91f5460395 100644 --- a/movere_local/mainapp/templates/mainapp/view_story_and_files.html +++ b/movere_local/mainapp/templates/mainapp/view_story_and_files.html @@ -12,7 +12,11 @@ {% load static %} @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Krona+One&display=swap'); - + @import url('https://fonts.googleapis.com/css2?family=Mulish:wght@200..1000&display=swap'); + + a { + text-decoration: none; + } .navbar { display: flex; @@ -30,11 +34,14 @@ .navbar .logo { display: flex; /* Располагает элементы (логотип Рё текст) РІ РѕРґРЅСѓ строку */ align-items: center; /* Вертикальное выравнивание элементов РїРѕ центру */ + margin-left: 100px; + margin-top: 20px; + /* margin-left: 30px; */ } .navbar .logo img { height: 60px; /* Размер логотипа */ - margin-right: 10px; /* Отступ между логотипом Рё текстом */ + margin-right: 15px; /* Отступ между логотипом Рё текстом */ } .navbar .logo span { @@ -43,10 +50,12 @@ color: #FFFFFF; /* Цвет текста */ white-space: nowrap; /* Запрещает перенос текста РЅР° РЅРѕРІСѓСЋ строку */ } + + .navbar .profile-btn { - background-color: transparent; /* Прозрачный фон */ + background-color: rgb(45, 42, 42);/* Прозрачный фон */ color: #FFFFFF; - border: 1px solid #4d4d4d; /* Белая рамка */ + border: 1px solid #ffffff00; /* Белая рамка */ padding: 15px 30px; /* Увеличенный внутренний отступ */ font-family: "Roboto", sans-serif; /* font-weight: bold; */ @@ -54,13 +63,40 @@ border-radius: 20px; /* Скругленные углы */ cursor: pointer; transition: transform 0.3s, background-color 0.3s, color 0.3s; - /* margin-left: 10%; Отступ справа */ + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ } .navbar .profile-btn:hover { - background-color: rgba(255, 255, 255, 0.2); /* Полупрозрачный белый РїСЂРё наведении */ + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ } + + .navbar .storage_home_button { + background-color: rgb(45, 42, 42);/* Прозрачный фон */ + color: #FFFFFF; + border: 1px solid #ffffff00; /* Белая рамка */ + padding: 15px 30px; /* Увеличенный внутренний отступ */ + font-family: "Roboto", sans-serif; + /* font-weight: bold; */ + font-size: 16px; /* Увеличенный размер шрифта */ + border-radius: 20px; /* Скругленные углы */ + cursor: pointer; + transition: transform 0.3s, background-color 0.3s, color 0.3s; + margin-right: 10%; /*Отступ справа */ + /* margin-left: 10%; */ + } + + .navbar .storage_home_button:hover { + background-color: rgb(58, 54, 54); /* Полупрозрачный белый РїСЂРё наведении */ + transform: scale(1.1); /* Увеличение РєРЅРѕРїРєРё */ + } + + + .navbar .btns_in_nav { + display: flex; + margin-right: 10%; + } body { margin: 0; font-family: "Krona One", serif; @@ -86,33 +122,45 @@ } .card { - width: 300px; - height: 400px; - background-color: #3A3A3A; - border-radius: 10px; - display: flex; - flex-direction: column; - align-items: center; - justify-content: flex-end; - overflow: hidden; - position: relative; - cursor: pointer; - transition: transform 0.3s; - } + position: relative; + width: 300px; + height: 400px; + background-color: #3A3A3A; + border-radius: 10px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-end; + overflow: hidden; + cursor: pointer; + transition: transform 0.3s; +} - .card:hover { - transform: scale(1.05); - } +.card:hover { + transform: scale(1.05); +} - .card img { - width: 100%; - height: 100%; - object-fit: cover; - position: absolute; - top: 0; - left: 0; - z-index: 1; - } +.card svg { + position: absolute; + top: 20px; + left: 50%; + transform: translateX(-50%); + width: 80%; + height: 80%; +} + +.card svg .color-change { + fill: #ffffff; /* Начальный цвет */ + transition: fill 0.2s ease; /* Плавное изменение цвета */ +} + +.card svg .no-change { + fill: none; /* Оставляем как есть */ +} + +.card:hover svg .color-change { + fill: #8d53ff; /* Цвет РїСЂРё наведении */ +} .card video { width: 100%; @@ -131,11 +179,11 @@ .card .label { position: relative; - font-family: 'Roboto', Arial, sans-serif; + font-family: 'Mulish', Arial, sans-serif; color: #FFFFFF; padding: 5px 10px; border-radius: 5px; - font-size: 14px; + font-size: 20px; font-weight: bold; margin-bottom: 5px; text-align: center; @@ -143,12 +191,12 @@ } .card .description { - font-family: 'Roboto', Arial, sans-serif; + font-family: 'Mulish', Arial, sans-serif; position: relative; - color: #FFFFFF; + color: #c1c1c1; padding: 5px 10px; border-radius: 5px; - font-size: 12px; + font-size: 16px; text-align: center; margin-bottom: 10px; z-index: 3; @@ -198,31 +246,119 @@ <a href="{% url 'view_orders' %}" class="card"> - <!-- <img src="{% static 'mainapp/images/tunder.png' %}" alt="Preview"> --> - <!-- <video src="{% static 'mainapp/images/purple_tunder.mp4' %}" muted data-playing="false"></video> --> + <svg height="250px" width="250px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" + viewBox="0 0 470 470" xml:space="preserve"> + <!-- <path class="color-change" d="M18 5.498l-5.5-2.26L7 5.499v5.655l-5 2.054v6.443l5.5 2.259 5-2.054 5 2.054 5.5-2.26v-6.442l-5-2.054zm-.5 9.462l-3.432-1.404 3.576-1.468 3.432 1.41zM12 8.127v4.669l-4-1.643V6.492zm1 4.669V8.127l4-1.635v4.661zm-2.068.76L7.5 14.96l-3.576-1.463 3.432-1.41zM8 15.836l4-1.636v4.78l-4 1.642zm8.076-10.047L12.5 7.25 8.924 5.79 12.5 4.32zM3 14.2l4 1.636v4.786L3 18.98zm10 0l4 1.636v4.786l-4-1.642zm5 6.422v-4.786l4-1.636v4.78z"/> + <path class="no-change" fill="none" d="M0 0h24v24H0z"/> --> + + <path class="color-change" d="M211.683,151.084c-2.086-3.58-6.679-4.788-10.256-2.705l-51.978,30.281c-3.579,2.085-4.79,6.677-2.705,10.256 + c1.394,2.392,3.906,3.726,6.487,3.726c1.282,0,2.581-0.329,3.769-1.021l51.978-30.281 + C212.557,159.255,213.768,154.663,211.683,151.084z"/> + <path class="color-change" d="M261.021,161.34l51.978,30.28c1.188,0.691,2.486,1.021,3.769,1.021c2.581,0,5.094-1.334,6.487-3.726 + c2.085-3.579,0.874-8.171-2.705-10.256l-51.978-30.28c-3.579-2.084-8.17-0.875-10.256,2.705 + C256.231,154.663,257.442,159.255,261.021,161.34z"/> + <path class="color-change" d="M149.551,356.399l51.877,30.223c1.188,0.692,2.486,1.021,3.769,1.021c2.581,0,5.094-1.334,6.487-3.726 + c2.085-3.579,0.874-8.171-2.705-10.256l-51.877-30.223c-3.579-2.088-8.17-0.874-10.256,2.705 + C144.761,349.723,145.972,354.314,149.551,356.399z"/> + <path class="color-change" d="M465.642,267.424c-0.006-0.597-0.084-1.196-0.235-1.787c-0.019-0.072-0.04-0.142-0.061-0.213 + c-0.063-0.218-0.137-0.434-0.221-0.649c-0.029-0.076-0.057-0.151-0.089-0.226c-0.102-0.238-0.217-0.472-0.346-0.703 + c-0.018-0.032-0.032-0.067-0.051-0.099c-0.16-0.277-0.323-0.515-0.494-0.745c-0.04-0.054-0.084-0.104-0.126-0.156 + c-0.148-0.187-0.303-0.366-0.466-0.536c-0.053-0.055-0.106-0.109-0.161-0.163c-0.185-0.181-0.376-0.352-0.577-0.511 + c-0.034-0.027-0.065-0.056-0.099-0.082c-0.243-0.186-0.495-0.356-0.756-0.51c-0.039-0.026-107.888-62.857-107.888-62.857V72.5 + c0-0.026-0.005-0.05-0.005-0.076c-0.006-0.597-0.084-1.196-0.235-1.787c-0.019-0.072-0.04-0.142-0.061-0.213 + c-0.063-0.218-0.137-0.434-0.221-0.649c-0.029-0.076-0.057-0.151-0.089-0.226c-0.102-0.238-0.217-0.472-0.346-0.703 + c-0.018-0.032-0.032-0.067-0.051-0.099c-0.16-0.278-0.323-0.516-0.495-0.746c-0.039-0.052-0.082-0.101-0.122-0.152 + c-0.15-0.19-0.307-0.371-0.471-0.542c-0.051-0.053-0.102-0.105-0.155-0.156c-0.188-0.185-0.384-0.36-0.589-0.522 + c-0.029-0.023-0.056-0.049-0.086-0.071c-0.245-0.189-0.5-0.36-0.764-0.516C350.349,66.02,238.775,1.02,238.775,1.02 + c-2.334-1.359-5.217-1.359-7.551,0l-111.573,65c-0.297,0.178-0.554,0.351-0.801,0.54c-0.027,0.021-0.052,0.044-0.079,0.066 + c-0.207,0.164-0.405,0.34-0.595,0.527c-0.052,0.051-0.102,0.102-0.153,0.155c-0.165,0.172-0.322,0.354-0.472,0.544 + c-0.04,0.051-0.083,0.099-0.122,0.151c-0.172,0.23-0.335,0.468-0.483,0.722c-0.031,0.056-0.045,0.09-0.063,0.123 + c-0.129,0.231-0.244,0.465-0.346,0.703c-0.032,0.074-0.06,0.15-0.089,0.226c-0.084,0.214-0.158,0.43-0.221,0.649 + c-0.021,0.071-0.042,0.141-0.06,0.213c-0.152,0.591-0.23,1.19-0.235,1.787c0,0.025-0.005,0.05-0.005,0.076v125.689L8.078,261.02 + c-0.3,0.18-0.553,0.35-0.796,0.537c-0.033,0.026-0.064,0.054-0.097,0.08c-0.201,0.16-0.393,0.331-0.578,0.512 + c-0.054,0.053-0.108,0.107-0.16,0.162c-0.163,0.17-0.318,0.349-0.466,0.536c-0.042,0.053-0.086,0.103-0.126,0.157 + c-0.171,0.229-0.334,0.467-0.482,0.72c-0.031,0.056-0.045,0.09-0.063,0.123c-0.129,0.231-0.244,0.465-0.346,0.703 + c-0.032,0.074-0.06,0.15-0.089,0.226c-0.084,0.214-0.158,0.43-0.221,0.649c-0.021,0.071-0.042,0.141-0.06,0.213 + c-0.152,0.591-0.23,1.19-0.235,1.787c0,0.025-0.005,0.05-0.005,0.076v130c0,2.669,1.419,5.137,3.725,6.48l111.573,65 + c0.021,0.012,0.044,0.02,0.065,0.032c0.268,0.153,0.545,0.293,0.833,0.413c0.28,0.116,0.562,0.208,0.85,0.289 + c0.071,0.02,0.143,0.037,0.215,0.055c0.225,0.056,0.454,0.101,0.687,0.136c0.077,0.012,0.152,0.026,0.229,0.035 + c0.295,0.035,0.593,0.059,0.897,0.059s0.603-0.023,0.897-0.059c0.077-0.009,0.152-0.023,0.229-0.035 + c0.233-0.035,0.462-0.08,0.687-0.136c0.072-0.018,0.144-0.035,0.215-0.055c0.288-0.081,0.57-0.173,0.843-0.286 + c0.294-0.122,0.571-0.262,0.839-0.416c0.021-0.012,0.044-0.02,0.065-0.032L235,406.18l107.798,62.801 + c0.021,0.012,0.044,0.02,0.065,0.032c0.268,0.153,0.544,0.293,0.832,0.413c0.281,0.116,0.562,0.208,0.849,0.289 + c0.072,0.02,0.144,0.038,0.216,0.056c0.225,0.056,0.453,0.101,0.686,0.136c0.077,0.012,0.153,0.026,0.23,0.035 + c0.295,0.035,0.593,0.059,0.897,0.059s0.602-0.023,0.897-0.059c0.077-0.009,0.153-0.023,0.23-0.035 + c0.232-0.035,0.461-0.08,0.686-0.136c0.072-0.018,0.144-0.035,0.216-0.056c0.287-0.081,0.569-0.173,0.841-0.286 + c0.296-0.123,0.572-0.263,0.84-0.416c0.021-0.012,0.044-0.02,0.065-0.032l111.573-65c2.306-1.344,3.725-3.812,3.725-6.48v-130 + C465.646,267.474,465.642,267.45,465.642,267.424z M443.247,267.5l-96.674,56.32l-96.674-56.32l96.674-56.32L443.247,267.5z + M130.927,85.549l96.573,56.261v112.64l-96.573-56.261V85.549z M339.073,198.189L242.5,254.451v-112.64l96.573-56.261V198.189z + M227.5,393.189l-96.573,56.262v-112.64l96.573-56.261V393.189z M242.5,280.549l96.573,56.261v112.64L242.5,393.189V280.549z + M235,16.18l96.674,56.32L235,128.82L138.326,72.5L235,16.18z M123.427,211.18l96.674,56.32l-96.674,56.32L26.753,267.5 + L123.427,211.18z M19.354,280.549l96.573,56.261v112.64l-96.573-56.262V280.549z M354.073,449.451v-112.64l96.573-56.261v112.64 + L354.073,449.451z"/> + <path class="color-change" d="M323.156,346.142c-2.086-3.58-6.678-4.788-10.256-2.705l-51.877,30.223c-3.579,2.085-4.79,6.677-2.705,10.256 + c1.394,2.392,3.906,3.726,6.487,3.726c1.282,0,2.581-0.329,3.769-1.021l51.877-30.223 + C324.03,354.313,325.241,349.721,323.156,346.142z"/> + <path class="color-change" d="M100.109,346.084c-2.086-3.58-6.679-4.788-10.256-2.705l-51.877,30.223c-3.579,2.085-4.79,6.677-2.705,10.256 + c1.394,2.392,3.906,3.726,6.487,3.726c1.282,0,2.581-0.329,3.769-1.021l51.877-30.223 + C100.983,354.255,102.194,349.663,100.109,346.084z"/> + <path class="color-change" d="M432.024,373.603l-51.676-30.105c-3.579-2.087-8.171-0.875-10.256,2.705c-2.085,3.579-0.874,8.171,2.705,10.256 + l51.676,30.105c1.188,0.692,2.486,1.021,3.769,1.021c2.581,0,5.094-1.334,6.487-3.726 + C436.814,380.279,435.604,375.688,432.024,373.603z"/> + + + </svg> <div class="label">РњРћР Р—РђРЇР’РљР</div> <div class="description"></div> </a> <div class="card"> <a href="{% url 'view_editrequests' %}" class="card"> - <!-- <img src="{% static 'mainapp/images/store.png' %}" alt="Preview"> --> - <!-- <video src="{% static 'mainapp/images/store.mp4' %}" muted data-playing="false"></video> --> - <div class="label">МОРМОДЕЛР</div> - <div class="description">РР</div> + <svg width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> + <path class="color-change" d="M6,19.7439414 C4.25221144,19.1261868 3,17.4593282 3,15.5 L3,8.5 C3,6.01471863 5.01471863,4 7.5,4 L8,4 L8,3.5 C8,2.67157288 8.67157288,2 9.5,2 L14.5,2 C15.3284271,2 16,2.67157288 16,3.5 L16,4 L16.5,4 C18.9852814,4 21,6.01471863 21,8.5 L21,15.5 C21,17.4593282 19.7477886,19.1261868 18,19.7439414 L18,20.5 C18,21.3284271 17.3284271,22 16.5,22 L7.5,22 C6.67157288,22 6,21.3284271 6,20.5 L6,19.7439414 L6,19.7439414 Z M7,19.9725356 L7,20.5 C7,20.7761424 7.22385763,21 7.5,21 L16.5,21 C16.7761424,21 17,20.7761424 17,20.5 L17,19.9725356 C16.8358331,19.9906833 16.6690045,20 16.5,20 L7.5,20 C7.33099545,20 7.16416693,19.9906833 7,19.9725356 L7,19.9725356 Z M9,4 L15,4 L15,3.5 C15,3.22385763 14.7761424,3 14.5,3 L9.5,3 C9.22385763,3 9,3.22385763 9,3.5 L9,4 Z M7.5,5 C5.56700338,5 4,6.56700338 4,8.5 L4,15.5 C4,17.4329966 5.56700338,19 7.5,19 L16.5,19 C18.4329966,19 20,17.4329966 20,15.5 L20,8.5 C20,6.56700338 18.4329966,5 16.5,5 L7.5,5 Z M14.5,10 L15.5,10 C15.7761424,10 16,10.2238576 16,10.5 L16,11.5 C16,11.7761424 15.7761424,12 15.5,12 L14.5,12 C14.2238576,12 14,11.7761424 14,11.5 L14,10.5 C14,10.2238576 14.2238576,10 14.5,10 Z M8.5,10 L9.5,10 C9.77614237,10 10,10.2238576 10,10.5 L10,11.5 C10,11.7761424 9.77614237,12 9.5,12 L8.5,12 C8.22385763,12 8,11.7761424 8,11.5 L8,10.5 C8,10.2238576 8.22385763,10 8.5,10 Z M9.14644661,14.8535534 C8.95118446,14.6582912 8.95118446,14.3417088 9.14644661,14.1464466 C9.34170876,13.9511845 9.65829124,13.9511845 9.85355339,14.1464466 C10.4248566,14.7177498 11.1304821,15 12,15 C12.8695179,15 13.5751434,14.7177498 14.1464466,14.1464466 C14.3417088,13.9511845 14.6582912,13.9511845 14.8535534,14.1464466 C15.0488155,14.3417088 15.0488155,14.6582912 14.8535534,14.8535534 C14.0915232,15.6155836 13.1304821,16 12,16 C10.8695179,16 9.90847678,15.6155836 9.14644661,14.8535534 Z"/> + </svg> + <div class="label">МОРГЕНЕРАЦРР</div> + <div class="description"></div> </a> </div> <div class="card"> <a href="{% url 'view_archive' %}" class="card"> - <!-- <img src="{% static 'mainapp/images/store.png' %}" alt="Preview"> --> - <!-- <video src="{% static 'mainapp/images/store.mp4' %}" muted data-playing="false"></video> --> + <svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path class="color-change" fill-rule="evenodd" clip-rule="evenodd" d="M5.07868 5.06891C8.87402 1.27893 15.0437 1.31923 18.8622 5.13778C22.6824 8.95797 22.7211 15.1313 18.9262 18.9262C15.1312 22.7211 8.95793 22.6824 5.13774 18.8622C2.87389 16.5984 1.93904 13.5099 2.34047 10.5812C2.39672 10.1708 2.775 9.88377 3.18537 9.94002C3.59575 9.99627 3.88282 10.3745 3.82658 10.7849C3.4866 13.2652 4.27782 15.881 6.1984 17.8016C9.44288 21.0461 14.6664 21.0646 17.8655 17.8655C21.0646 14.6664 21.046 9.44292 17.8015 6.19844C14.5587 2.95561 9.33889 2.93539 6.13935 6.12957L6.88705 6.13333C7.30126 6.13541 7.63535 6.47288 7.63327 6.88709C7.63119 7.3013 7.29372 7.63539 6.87951 7.63331L4.33396 7.62052C3.92269 7.61845 3.58981 7.28556 3.58774 6.8743L3.57495 4.32874C3.57286 3.91454 3.90696 3.57707 4.32117 3.57498C4.73538 3.5729 5.07285 3.907 5.07493 4.32121L5.07868 5.06891ZM11.9999 7.24992C12.4141 7.24992 12.7499 7.58571 12.7499 7.99992V11.6893L15.0302 13.9696C15.3231 14.2625 15.3231 14.7374 15.0302 15.0302C14.7373 15.3231 14.2624 15.3231 13.9696 15.0302L11.2499 12.3106V7.99992C11.2499 7.58571 11.5857 7.24992 11.9999 7.24992Z"/> + </svg> <div class="label">РђР РҐРР’</div> <div class="description"></div> </a> </div> <div class="card"> <a href="{% url 'storage' %}" class="card"> - <img src="{% static 'mainapp/images/store.png' %}" alt="Preview"> - <video src="{% static 'mainapp/images/store.mp4' %}" muted data-playing="false"></video> + <svg version="1.1" id="CLOUD_NETWORK" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" + y="0px" width="800px" height="800px" viewBox="0 0 1800 1800" enable-background="new 0 0 1800 1800" xml:space="preserve"> + <path class="color-change" d="M1635.687,1278.4c-47.769,0-88.294,31.611-101.762,75.016h-145.789v-349.629h73.367 + c4.988,0.22,9.674,0.326,14.307,0.326c4.782,0,9.635-0.115,14.817-0.348c0.079-0.005,0.158-0.01,0.237-0.01 + c173.133-7.938,308.756-150.018,308.756-323.454c0-134.669-81.956-253.44-205.979-301.697 + c-14.456-100.161-63.179-192.209-138.563-260.994c-80.945-73.862-185.92-114.539-295.579-114.539 + c-137.799,0-266.188,64.115-349.019,172.916c-45.162-22.9-95.19-34.891-146.321-34.891c-139.064,0-261.005,87.974-305.833,217.184 + c-11.335-1.191-22.746-1.793-34.13-1.793C145.642,356.487,0.38,501.749,0.38,680.302c0,178.549,145.262,323.812,323.815,323.812 + c5.393,0,10.958-0.146,16.592-0.436c0.875,0.074,1.758,0.109,2.65,0.109h72.515v349.629h-145.79 + c-13.467-43.404-53.993-75.016-101.761-75.016c-58.735,0-106.521,47.787-106.521,106.521c0,58.735,47.786,106.521,106.521,106.521 + c47.769,0,88.294-31.611,101.761-75.016h177.295c17.401,0,31.506-14.104,31.506-31.506v-381.135h194.534v586.93 + c-43.404,13.463-75.016,53.988-75.016,101.762c0,58.735,47.787,106.521,106.521,106.521s106.521-47.786,106.521-106.521 + c0-47.773-31.611-88.299-75.016-101.762v-586.93h331.067v586.93c-43.403,13.463-75.016,53.988-75.016,101.762 + c0,58.735,47.787,106.521,106.521,106.521c58.735,0,106.522-47.786,106.522-106.521c0-47.773-31.612-88.299-75.016-101.762v-586.93 + h194.534v381.135c0,17.401,14.104,31.506,31.506,31.506h177.295c13.468,43.404,53.993,75.016,101.762,75.016 + c58.735,0,106.521-47.786,106.521-106.521C1742.208,1326.188,1694.422,1278.4,1635.687,1278.4z M168.401,1428.432 + c-23.99,0-43.51-19.52-43.51-43.51s19.52-43.51,43.51-43.51c23.99,0,43.51,19.52,43.51,43.51S192.391,1428.432,168.401,1428.432z + M705.004,1735.988c-23.99,0-43.51-19.52-43.51-43.51s19.52-43.51,43.51-43.51s43.51,19.52,43.51,43.51 + S728.994,1735.988,705.004,1735.988z M1099.083,1735.988c-23.989,0-43.509-19.52-43.509-43.51s19.52-43.51,43.509-43.51 + c23.99,0,43.51,19.52,43.51,43.51S1123.073,1735.988,1099.083,1735.988z M341.398,940.525c-5.886,0.382-11.674,0.575-17.204,0.575 + c-143.807,0-260.803-116.996-260.803-260.799c0-143.807,116.996-260.803,260.803-260.803c16.909,0,33.875,1.644,50.428,4.883 + c16.469,3.2,32.53-7.002,36.608-23.247c29.133-116.007,133.14-197.026,252.927-197.026c49.272,0,97.252,13.81,138.753,39.941 + c14.479,9.116,33.615,5.006,43.062-9.279c69.877-105.629,187.079-168.687,313.525-168.687c194.314,0,355.039,145.629,373.86,338.749 + c1.222,12.531,9.784,23.133,21.783,26.961c108.539,34.626,181.467,134.493,181.467,248.509c0,139.628-109.119,254.017-248.452,260.5 + c-0.065,0-0.127,0.005-0.193,0.009c-8.602,0.387-15.744,0.387-24.311,0c-0.479-0.021-0.963-0.035-1.441-0.035H347.895 + C345.763,940.468,343.587,940.385,341.398,940.525z M1635.687,1428.432c-23.99,0-43.51-19.52-43.51-43.51s19.52-43.51,43.51-43.51 + s43.51,19.52,43.51,43.51S1659.677,1428.432,1635.687,1428.432z"/> + </svg> <div class="label">РҐР РђРќРР›РЩЕ</div> <div class="description"></div> </a> diff --git a/movere_local/mainapp/urls.py b/movere_local/mainapp/urls.py index 7c111143ba7dc55e5ada68773c92576e5ecd6b05..23385ca4931c7151219f8ec5a288cde2f6dc5585 100644 --- a/movere_local/mainapp/urls.py +++ b/movere_local/mainapp/urls.py @@ -22,6 +22,7 @@ urlpatterns = [ path('storage/delete/<int:item_id>/', views.delete_item, name='delete_item'), path('storage/upload/', views.upload_file, name='upload_file'), path('storage/download/<int:item_id>/', views.download_item, name='download_item'), + path('view_editrequests/download/<int:item_id>/', views.download_item_from_nn, name='download_item_from_nn'), path('create_order/', views.create_order, name='create_order'), path('archive_order/<int:order_id>/', views.archive_order, name='archive_order'), path('view_archive/', views.view_archive, name='view_archive'), @@ -31,6 +32,7 @@ urlpatterns = [ path('cancel_order/<int:order_id>/', views.cancel_order, name='cancel_order'), path('story-and-files', views.view_story_and_files, name='view_story_and_files'), path('redactor/', views.redactor, name='redactor'), + path('api/orders/by-username/<str:username>/', views.order_list_by_username_api, name='order_list_by_username_api'), # path('serve-file/<str:file_name>/', views.serve_file, name='serve_file'), diff --git a/movere_local/mainapp/utils.py b/movere_local/mainapp/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..59438e3df8be48e0520b49a8ba037db8e4824c23 --- /dev/null +++ b/movere_local/mainapp/utils.py @@ -0,0 +1,59 @@ +import paramiko +import os + +def upload_file_and_add_task(server_ip, username, password, local_file_path, remote_dir, remote_file_name, params, venv_path, req_id): + try: + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + ssh.connect(server_ip, username=username, password=password) + print(f"Подключение Рє {server_ip} установлено.") + + # Проверяем Рё создаём директорию РЅР° внешнем сервере + command_check_dir = f"if [ ! -d {remote_dir} ]; then mkdir -p {remote_dir}; fi" + ssh.exec_command(command_check_dir) + print(f"Директория {remote_dir} проверена/создана.") + + # Открываем SFTP-соединение + sftp = ssh.open_sftp() + + # Загружаем файл + remote_file_path = os.path.join(remote_dir, remote_file_name) + sftp.put(local_file_path, remote_file_path) + print(f"Файл загружен: {remote_file_path}") + sftp.close() + + # Команда для активации виртуального окружения Рё запуска скрипта + add_task_script = "queue_scripts/add_task_to_queue.py" # Укажите путь Рє скрипту РЅР° сервере + command_add_task = ( + f"cd {os.path.dirname(add_task_script)} && " + f"source venv/bin/activate && " + f"python3 {os.path.basename(add_task_script)} {req_id} {remote_file_path} \"{params}\"" + ) + print(f"Запуск команды: {command_add_task}") + + # Выполняем команду + stdin, stdout, stderr = ssh.exec_command(command_add_task) + print("STDOUT:", stdout.read().decode('utf-8')) + print("STDERR:", stderr.read().decode('utf-8')) + + # Закрываем соединение + ssh.close() + print("Операция завершена.") + + except Exception as e: + print(f"Ошибка: {e}") + + +if __name__ == "__main__": + # Пример использования + upload_file_and_add_task( + server_ip="192.168.1.100", + username="root", + password="password", + local_file_path="/path/to/local/file.txt", + remote_dir="/path/to/remote/directory", + remote_file_name="uploaded_file.txt", + params="--param1=value1 --param2=value2", + venv_path="/path/to/remote/.venv", # Путь Рє виртуальному окружению РЅР° внешнем сервере, + req_id=0 + ) diff --git a/movere_local/mainapp/views.py b/movere_local/mainapp/views.py index c370504a73a5791ad71bc599502cd94a05358c40..2ab259439d0876bcfe84709d561e84902f33cdfe 100644 --- a/movere_local/mainapp/views.py +++ b/movere_local/mainapp/views.py @@ -17,7 +17,7 @@ from rest_framework.response import Response from rest_framework.decorators import api_view from .models import Order from .serializers import OrderSerializer - +import ast @@ -106,6 +106,31 @@ def download_file(request, file_name): # response['Content-Disposition'] = f'attachment; filename={os.path.basename(full_path)}' # return response +from django.contrib.auth.models import User +@csrf_exempt +def order_list_by_username_api(request, username): + # Проверка ключа API + api_key = request.headers.get('Authorization') + if api_key != f"Api-Key {settings.API_KEY}": + return JsonResponse({'error': 'Unauthorized'}, status=403) + + if request.method == 'GET': + + # Проверка существует ли пользователь СЃ таким именем + try: + user = User.objects.get(username=username) + except User.DoesNotExist: + return JsonResponse({'error': 'User not found'}, status=404) + + # Фильтрация заказов РїРѕ пользователю + orders = Order.objects.filter(user=user) + orders_data = list(orders.values('id', 'order_state')) # Выбирайте нужные поля + return JsonResponse(orders_data, safe=False) + + return JsonResponse({'error': 'Method not allowed'}, status=405) + + + @csrf_exempt def order_list_api(request): @@ -168,10 +193,14 @@ def home(request): def make_order(request): return render(request, 'mainapp/make_order.html') - +# @login_required +# def redactor(request): +# return render(request, 'mainapp/redactor.html') @login_required def redactor(request): - return render(request, 'mainapp/redactor.html') + # Фильтруем файлы пользователя СЃ допустимыми расширениями + storage_files = Storage.objects.filter(user=request.user, file_path__iregex=r'\.(stl|obj)$') + return render(request, 'mainapp/redactor.html', {'storage_files': storage_files}) @login_required @@ -182,10 +211,30 @@ def view_story_and_files(request): @login_required def view_archive(request): user_archive_orders = OrderArchive.objects.filter(user=request.user) + coolpaths = {order.id: order.file_path for order in user_archive_orders} + def create_new_list_for_view(orders_by_status): + total = [] + for key, value in orders_by_status.items(): + # print(key, value) + new_list = [] + + for order in value: + try: + order.file_preview_path = coolpaths.get(order.id, "") + parsed_params = parse_params(order.order_parameters) + new_list.append([order, parsed_params]) + except: + new_list.append([order, {}]) + new_str = [key, new_list] + total.append(new_str) + return total statuses = ['done', 'canceled'] archive_orders_by_status = {status: user_archive_orders.filter(order_state=status) for status in statuses} + + new_archive_orders_status_list = create_new_list_for_view(archive_orders_by_status) + archive_orders_status_list = [] for status in statuses: archive_orders = archive_orders_by_status[status] @@ -196,7 +245,10 @@ def view_archive(request): order.file_basename = [] archive_orders_status_list.append((status, archive_orders)) - return render(request, 'mainapp/view_archive.html', {'archive_orders_status_list': archive_orders_status_list}) + + + + return render(request, 'mainapp/view_archive.html', {'archive_orders_status_list': new_archive_orders_status_list}) @login_required @@ -216,13 +268,46 @@ def archive_order(request, order_id): return redirect('view_orders') +import ast +def parse_params(parametrs): + d = ast.literal_eval(parametrs) + return d + @login_required def view_orders(request): user_orders = Order.objects.filter(user=request.user) + coolpaths = {order.id: order.file_path for order in user_orders} + + # Добавляем путь Рє файлу как атрибут каждого заказа + # for order in user_orders: + # order.file_preview_path = coolpaths.get(order.id, "") + # print(f"Order ID: {order.id}, File Path: {order.file_preview_path}") + # print(user_orders[0]) + statuses = ['wait_confirmation', 'in_work', 'ready', 'done', 'canceled'] orders_by_status = {status: user_orders.filter(order_state=status) for status in statuses} + def create_new_list_for_view(orders_by_status): + total = [] + for key, value in orders_by_status.items(): + # print(key, value) + new_list = [] + + for order in value: + try: + order.file_preview_path = coolpaths.get(order.id, "") + parsed_params = parse_params(order.order_parameters) + new_list.append([order, parsed_params]) + except: + new_list.append([order, {}]) + new_str = [key, new_list] + total.append(new_str) + return total + + new_orders_status_list = create_new_list_for_view(orders_by_status) + # print(new_orders_status_list) + orders_status_list = [] for status in statuses: orders = orders_by_status[status] @@ -234,8 +319,12 @@ def view_orders(request): else: order.file_basename = [] orders_status_list.append((status, orders)) - - return render(request, 'mainapp/view_orders.html', {'orders_status_list': orders_status_list}) + # for s in new_orders_status_list: + # print(s[0]) + # for order_batch in s[1]: + # print(order_batch[0].file_preview_path) + # # print(order.file_preview_path) + return render(request, 'mainapp/view_orders.html', {'orders_status_list': new_orders_status_list, 'coolpaths':coolpaths}) from .forms import OrderForm @@ -248,6 +337,17 @@ def create_order(request): order = form.save(commit=False) order.user = request.user + # Объединяем параметры РІ словарь + order_parameters = { + "position": form.cleaned_data.get("position"), + "purpose": form.cleaned_data.get("purpose"), # РЎРїРёСЃРѕРє выбранных целей + "additional_purpose": form.cleaned_data.get("additional_purpose"), + "material": form.cleaned_data.get("material"), + } + # longstr = f'position:{form.cleaned_data.get("position")}__purpose:{form.cleaned_data.get("purpose")}__additional_purpose:{form.cleaned_data.get("additional_purpose")}__material:{form.cleaned_data.get("material")}' + # order.order_parameters = longstr + order.order_parameters = str(order_parameters) # Сохраняем словарь как строку + file_choice = form.cleaned_data.get('file_choice') if file_choice == OrderForm.CHOICE_FILE_FROM_STORAGE: @@ -267,13 +367,14 @@ def create_order(request): return redirect('view_orders') else: form = OrderForm(user=request.user) - return render(request, 'mainapp/create_order.html', {'form': form}) @login_required def storage(request): items = Storage.objects.filter(user=request.user) + for item in items: + item.basename_filepath = os.path.basename(item.file_path) return render(request, 'mainapp/storage.html', {'items': items}) @@ -291,6 +392,21 @@ def download_item(request, item_id): else: # Если файла нет, РјРѕР¶РЅРѕ вернуть ошибку или редирект return redirect('storage') + +@login_required +def download_item_from_nn(request, item_id): + item = get_object_or_404(EditRequest, id=item_id, user=request.user) + print('объект: ', item) + print('ищу: ', 'media/' + item.received_file) + # Проверяем, существует ли файл + if os.path.exists('media/' + item.received_file): + # Отправляем файл пользователю для скачивания + print('нашел: ', 'media/' + item.received_file) + return FileResponse(open('media/' + item.received_file, 'rb'), as_attachment=True, filename=os.path.basename(item.received_file)) + else: + print('РЅРµ нашел: ', 'media/' + item.received_file) + # Если файла нет, РјРѕР¶РЅРѕ вернуть ошибку или редирект + return redirect('view_editrequests') @login_required @@ -444,6 +560,11 @@ def logout(request): @login_required def manager_dashboard(request): + + + def parse_params(parametrs): + d = ast.literal_eval(parametrs) + return d if request.user.groups.filter(name='manager').exists(): if request.method == 'POST': order_id = request.POST.get('order_id') @@ -462,8 +583,14 @@ def manager_dashboard(request): sort_by = 'order_datetime' # Получаем РІСЃРµ заказы для отображения + orders = Order.objects.all().order_by(sort_by) for order in orders: + try: + parsed_params = parse_params(order.order_parameters) + order.parsed_params = parsed_params + except: + order.parsed_params = {} if order.file_path: order.file_basename = os.path.basename(order.file_path) else: @@ -511,11 +638,16 @@ def view_editrequests(request): orders = reqs_by_status[status] for order in orders: # Рзвлекаем только basename РёР· файловых путей + if order.file_path: + order.sent_by_user = os.path.basename(order.file_path) + else: + order.sent_by_user = [] + if order.received_file: - order.file_basename = os.path.basename(order.received_file) - + order.recieved_from_server = os.path.basename(order.received_file) else: - order.file_basename = [] + order.recieved_from_server = [] + orders_status_list.append((status, orders)) return render(request, 'mainapp/view_editrequests.html', {'orders_status_list': orders_status_list}) \ No newline at end of file diff --git a/movere_local/media/algorithm.txt b/movere_local/media/algorithm.txt new file mode 100644 index 0000000000000000000000000000000000000000..e8280378eb279d746d4b8ec986d3ed6b68bbf885 --- /dev/null +++ b/movere_local/media/algorithm.txt @@ -0,0 +1,11 @@ +algorithm.gms + +#========================================================================= +* /////////////////////// OPTIMIZATION /////////////////////// +#========================================================================= +* launch optimization logic, passing full sequence of coalition-changing-times +* This will result in a sequence of progressive optimizations, +* one for each %coalitions_t_sequence% time passed +$batinclude "algorithm/optimization_loop" %coalitions_t_sequence% + + diff --git a/movere_local/media/modules.txt b/movere_local/media/modules.txt new file mode 100644 index 0000000000000000000000000000000000000000..dc5b679c06eeaac41144ef7a49750dab10f9841b --- /dev/null +++ b/movere_local/media/modules.txt @@ -0,0 +1,36 @@ +modules.gms + +$set phase %1 + +$batinclude 'modules/core_time' %2 # Core block to align correctly time epriods +$batinclude 'modules/core_regions' %2 # Regions settings and exogenous data imports + +$batinclude 'modules/core_economy' %2 # Core block for economy +$batinclude 'modules/core_emissions' %2 # Core block for emissions +$batinclude 'modules/core_welfare' %2 # Core block for welfare + +$batinclude 'modules/cooperation_%cooperation%' %2 # Cooperation setup +$batinclude 'modules/core_algorithm' %2 # Solve settings + +$batinclude 'modules/mod_macc' %2 # MAC curves, abatement cost +$batinclude 'modules/mod_land_use' %2 # Land-use HUB +$batinclude 'modules/hub_climate' %2 # Climate HUB +$batinclude 'modules/mod_climate_regional' %2 # Regional climate module +$batinclude 'modules/hub_impact' %2 # Climate Impact HUB + + +# POLICY +$batinclude 'modules/core_policy' %2 # All policy options +$if set pol_ndc $batinclude 'modules/pol_ndc' %2 # NDC policy module + +# Optional Modules +$if set mod_adaptation $batinclude 'modules/mod_adaptation' %2 # Adaptation Module +$if set mod_government $batinclude 'modules/mod_government' %2 # Government Module +$if set mod_labour $batinclude 'modules/mod_labour' %2 # Labour Module +$if set mod_inequality $batinclude 'modules/mod_inequality' %2 # Inequality Module +$if set mod_srm $batinclude 'modules/mod_srm' %2 # Solar Radiation management Module +$if set mod_slr $batinclude 'modules/mod_slr' %2 # Sea level rise Module +$if set mod_natural_capital $batinclude 'modules/mod_natural_capital' %2 # Nature Capital Green Module +$if set mod_emission_pulse $batinclude 'modules/mod_emission_pulse' %2 # Emission Pulse for SCC computation +$if set mod_dac $batinclude 'modules/mod_emi_stor' %2 # Emission storage module +$if set mod_dac $batinclude 'modules/mod_dac' %2 # Negative emissions module diff --git a/nn_server/queue_scripts/add_task_to_queue.py b/nn_server/queue_scripts/add_task_to_queue.py new file mode 100644 index 0000000000000000000000000000000000000000..30aa0934b31a493654292ee5e291a3df40b5a5a8 --- /dev/null +++ b/nn_server/queue_scripts/add_task_to_queue.py @@ -0,0 +1,25 @@ +# add_task_to_queue.py +import sqlite3 +import argparse + +def add_task_to_queue(req_id, file_path, params): + conn = sqlite3.connect('task_queue.db') + cursor = conn.cursor() + + cursor.execute(''' + INSERT INTO task_queue (req_id, file_path, params, status) + VALUES (?, ?, ?, 'pending') + ''', (req_id, file_path, params)) + + conn.commit() + conn.close() + print(f"Задача добавлена РІ очередь: req_id = {req_id} файл={file_path}, параметры={params}") + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Добавление задачи РІ очередь") + parser.add_argument("req_id", help="related id of req") + parser.add_argument("file_path", help="Путь РґРѕ файла") + parser.add_argument("params", help="Параметры для выполнения задачи") + args = parser.parse_args() + + add_task_to_queue(args.req_id, args.file_path, args.params) diff --git a/nn_server/queue_scripts/initialize_db.py b/nn_server/queue_scripts/initialize_db.py new file mode 100644 index 0000000000000000000000000000000000000000..e85f2d613300b23a1f2172e4b21aae2e55c0ed11 --- /dev/null +++ b/nn_server/queue_scripts/initialize_db.py @@ -0,0 +1,23 @@ +# initialize_db.py +import sqlite3 + +def initialize_db(): + conn = sqlite3.connect('task_queue.db') + cursor = conn.cursor() + + # Создаём таблицу для хранения задач + cursor.execute(''' + CREATE TABLE IF NOT EXISTS task_queue ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + req_id INTEGER NOT NULL, + file_path TEXT NOT NULL, + params TEXT NOT NULL, + status TEXT NOT NULL DEFAULT 'pending' + ) + ''') + conn.commit() + conn.close() + print("База данных Рё таблица очереди задач инициализированы.") + +if __name__ == "__main__": + initialize_db() diff --git a/nn_server/queue_scripts/task_queue.db b/nn_server/queue_scripts/task_queue.db new file mode 100644 index 0000000000000000000000000000000000000000..d5ada469eb41e1aacb3404b57ac531af1a8e1d3a Binary files /dev/null and b/nn_server/queue_scripts/task_queue.db differ diff --git a/nn_server/queue_scripts/worker.py b/nn_server/queue_scripts/worker.py new file mode 100644 index 0000000000000000000000000000000000000000..53413077c90c8ad4b929fbe229695365a675a01e --- /dev/null +++ b/nn_server/queue_scripts/worker.py @@ -0,0 +1,211 @@ +from datetime import datetime +import sqlite3 +import subprocess +import os +import time +import paramiko + + + + + + + + + +def process_task(task): + try: + print(f"Обработка задачи: файл={task[2]}, параметры={task[3]}") + + # Основные пути Рё параметры + base_dir = "/root/echo_1311/Generaton/TripoSR-main" # Абсолютный путь Рє папке СЃ run.py + conda_env = "venv" # РРјСЏ окружения Conda + file_path = task[2] # Р’С…РѕРґРЅРѕР№ файл (полный путь) + params = task[3] # Дополнительные параметры + + # Создание выходной директории + output_base_dir = "/root/DATA_TO_MAIN" # Основная директория для выходных данных + output_subdir = os.path.basename(os.path.dirname(file_path)) or "default" + output_dir = os.path.join(output_base_dir, output_subdir) + os.makedirs(output_dir, exist_ok=True) + print(f"Выходная директория создана: {output_dir}") + + # Полная команда для выполнения run.py + command = f""" + source /root/anaconda3/etc/profile.d/conda.sh && \ + conda activate {conda_env} && \ + cd {base_dir} && \ + python run.py /root/{file_path} --output-dir {output_dir} + """ + + # Выполнение команды + result = subprocess.run(command, shell=True, capture_output=True, text=True, executable="/bin/bash") + + # Проверяем результат выполнения + if result.returncode == 0: + print(f"Задача выполнена успешно: ID={task[0]}") + print("Вывод:", result.stdout) + return True + else: + print(f"Ошибка выполнения задачи: ID={task[0]}") + print("Вывод:", result.stdout) + print("Ошибка:", result.stderr) + return False + + except Exception as e: + print(f"Ошибка обработки задачи: {e}") + return False + + + + + +# Отправка файла РЅР° РѕСЃРЅРѕРІРЅРѕР№ сервер +def send_file_to_main_server(local_file_path, remote_dir, server_ip, username, password): + try: + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + ssh.connect(server_ip, username=username, password=password) + + # Проверяем Рё создаём директорию РЅР° РѕСЃРЅРѕРІРЅРѕРј сервере + command_check_dir = f"if [ ! -d {remote_dir} ]; then mkdir -p {remote_dir}; fi" + ssh.exec_command(command_check_dir) + print(f"Директория {remote_dir} проверена/создана.") + + # Открываем SFTP-соединение + sftp = ssh.open_sftp() + remote_file_path = os.path.join(remote_dir, os.path.basename(local_file_path))[:-4] + f'_{datetime.now().strftime("%Y_%m_%d_%H_%M_%S")}.obj' + sftp.put(local_file_path, remote_file_path) + sftp.close() + ssh.close() + + print(f"Файл {local_file_path} успешно отправлен РЅР° {remote_file_path}") + return remote_file_path # Путь файла РЅР° РѕСЃРЅРѕРІРЅРѕРј сервере + except Exception as e: + print(f"Ошибка РїСЂРё отправке файла РЅР° РѕСЃРЅРѕРІРЅРѕР№ сервер: {e}") + return None + +def invoke_function_on_main_server(request_id, result_file_path, status, server_ip, username, password): + try: + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + ssh.connect(server_ip, username=username, password=password) + + # Команда для вызова функции через СЃРєСЂРёРїС‚ create_objects.py + if result_file_path != '': + + command = f""" + source /var/venvs/movere_venv/bin/activate && \ + cd /var/www/myprojectdir/movere && \ + + python create_incoming_editreq.py \ + --request_id {request_id} \ + --file_path "{result_file_path}" \ + --status {status} + """ + + + else: + + command = f""" + source /var/venvs/movere_venv/bin/activate && \ + cd /var/www/myprojectdir/movere && \ + + python create_incoming_editreq.py \ + --request_id {request_id} \ + --status {status} + """ + + stdin, stdout, stderr = ssh.exec_command(command) + + # Чтение вывода команды + stdout_output = stdout.read().decode('utf-8') + stderr_output = stderr.read().decode('utf-8') + + print("STDOUT:", stdout_output) + print("STDERR:", stderr_output) + + ssh.close() + except Exception as e: + print(f"Ошибка РїСЂРё вызове функции РЅР° РѕСЃРЅРѕРІРЅРѕРј сервере: {e}") + +def process_queue(): + while True: + conn = sqlite3.connect('task_queue.db') + cursor = conn.cursor() + + # Рзвлекаем первую задачу СЃРѕ статусом 'pending' + cursor.execute(''' + SELECT id, req_id, file_path, params FROM task_queue WHERE status = 'pending' ORDER BY id ASC LIMIT 1 + ''') + task = cursor.fetchone() + + if task: + # Обновляем статус задачи РЅР° 'in_progress' + cursor.execute(''' + UPDATE task_queue SET status = 'in_progress' WHERE id = ? + ''', (task[0],)) + conn.commit() + + # Обрабатываем задачу + success = process_task(task) + print('Результат обработки задачи: ', success) + if success: + # Удаляем задачу РёР· очереди после успешного выполнения + cursor.execute(''' + UPDATE task_queue SET status = 'ready' WHERE id = ? + ''', (task[0],)) + + else: + # Если ошибка, возвращаем статус задачи РІ 'pending' + cursor.execute(''' + UPDATE task_queue SET status = 'error' WHERE id = ? + ''', (task[0],)) + + conn.commit() + + if success: + + file_path = task[2] + + + output_base_dir = "/root/DATA_TO_MAIN" # Основная директория для выходных данных + output_subdir = os.path.basename(os.path.dirname(file_path)) or "default" + output_dir = os.path.join(output_base_dir, output_subdir) + output_path = os.path.join(output_dir, '0', 'mesh.obj') + # os.makedirs(output_dir, exist_ok=True) + + print(f"Беру отсюда: {output_path}") + dst_dir = os.path.join('/var/www/myprojectdir/movere/media/DATA_FROM_NN_SERVER_UPLOAD/', output_subdir) + print(f"Кладу СЃСЋРґР°: {dst_dir}") + + if os.path.isfile(output_path): + + # print(f"Беру отсюда: {output_path}") + # dst_dir = os.path.join('/var/www/myprojectdir/movere/media/DATA_FROM_NN_SERVER_UPLOAD/', output_subdir) + # print(f"Кладу СЃСЋРґР°: {dst_dir}") + path_to_on_base = send_file_to_main_server(output_path, dst_dir, '176.124.214.56', 'root', 'a_Pmz3U1hoosKV') + if path_to_on_base is not None: + + + invoke_function_on_main_server(task[1], os.path.join(os.path.join('DATA_FROM_NN_SERVER_UPLOAD/', output_subdir), os.path.basename(path_to_on_base)), 'ready', '176.124.214.56', 'root', 'a_Pmz3U1hoosKV') + else: + success = False + + else: + success = False + if not success: + invoke_function_on_main_server(task[1], '', 'error', '176.124.214.56', 'root', 'a_Pmz3U1hoosKV') + + + + + else: + print("Очередь пуста. Ожидание новых задач...") + + conn.close() + time.sleep(5) # Задержка перед следующей итерацией + + +if __name__ == "__main__": + process_queue() diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/api_test.py b/test/api_test.py index 4d70c13e45cae90584a5374e38dd08656722ce8f..bd627dce065ae1f4b9e126a228da98482d20f4db 100644 --- a/test/api_test.py +++ b/test/api_test.py @@ -9,6 +9,34 @@ STATUS_AWAITING_CONFIRMATION = 'wait_confirmation' STATUS_READY = 'ready' STATUS_FINISHED = 'done' +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + + +""" +Запрашивает информацию всех заказов. +Параметры: + username - логин пользователя; + +Вовращаемое значение: + СЃРїРёСЃРѕРє всех заказов. +""" +def get_order_statuses_with_ids(username): + try: + response = requests.get(f"{BASE_URL}{ORDERS_BY_USERNAME_ENDPOINT}{username}/", headers=HEADERS) + response.raise_for_status() # Если РєРѕРґ ответа РЅРµ 200, то выкинет исключение HTTPError + orders = response.json() + return [(order['id'], order['order_state']) for order in orders] + except requests.exceptions.RequestException as e: + # Логирование или обработка исключений + print(f"Ошибка РїСЂРё запросе СЃРїРёСЃРєР° заказов: {e}") + return [] + + + + + """ Запрашивает информацию всех заказов. @@ -109,3 +137,9 @@ def set_order_status(order_id : int, """ def mark_order_as_processed(order_id): return set_order_status(order_id=order_id, status=STATUS_FINISHED) + + +if __name__ == "__main__": + data = get_order_statuses_with_ids('red') + print(data) + diff --git a/test/tg_bot.py b/test/tg_bot.py new file mode 100644 index 0000000000000000000000000000000000000000..8475f68b243c25489a4daf6ea72b42d3dacf1bd5 --- /dev/null +++ b/test/tg_bot.py @@ -0,0 +1,179 @@ +import logging +from aiogram import Bot, Dispatcher, Router, types +from aiogram.fsm.context import FSMContext +from aiogram.fsm.storage.memory import MemoryStorage +from aiogram.filters import Command +from aiogram.types import CallbackQuery +from aiogram.utils.keyboard import InlineKeyboardBuilder +from aiogram.fsm.state import State, StatesGroup + +from test.api_test import get_order_statuses_with_ids # РРјРїРѕСЂС‚ функции для получения заказов +from config import token +# Устанавливаем уровень логирования +logging.basicConfig(level=logging.INFO) + +# Токен вашего бота +# +bot = Bot(token=token) +storage = MemoryStorage() +dp = Dispatcher(storage=storage) + +# Создаём роутер для обработки команд +router = Router() +dp.include_router(router) + +# Состояния для FSM +class AuthStates(StatesGroup): + waiting_for_login = State() + +# Словарь для хранения состояния авторизации Рё начального сообщения /start +auth_users = {} +start_message_ids = {} + +# Команда /start +@router.message(Command(commands=['start'])) +async def send_welcome(message: types.Message, state: FSMContext): + chat_id = message.chat.id + + # Сохраняем message_id команды /start + start_message_ids[chat_id] = message.message_id + + # Сбрасываем авторизацию + auth_users[chat_id] = None + + # Создаем инлайн-РєРЅРѕРїРєРё "Старт", "Р’С…РѕРґ" Рё "Регистрация" + builder = InlineKeyboardBuilder() + builder.add(types.InlineKeyboardButton(text="Старт", callback_data="start")) + builder.add(types.InlineKeyboardButton(text="Р’С…РѕРґ", callback_data="login")) + builder.add(types.InlineKeyboardButton(text="Регистрация", url="https://lms.hse.ru/")) + + await message.answer("Привет! Выберите действие:", reply_markup=builder.as_markup()) + +# Удаление всех сообщений РґРѕ /start +async def delete_messages_up_to_start(chat_id: int, current_message_id: int): + start_message_id = start_message_ids.get(chat_id) + if not start_message_id: + return + + for message_id in range(start_message_id + 1, current_message_id + 1): + try: + await bot.delete_message(chat_id, message_id) + except Exception as e: + logging.warning(f"РќРµ удалось удалить сообщение {message_id}: {e}") + +# Обработчик нажатия РєРЅРѕРїРєРё "Старт" +@router.callback_query(lambda call: call.data == 'start') +async def send_about(call: CallbackQuery): + await delete_messages_up_to_start(call.message.chat.id, call.message.message_id) + builder = InlineKeyboardBuilder() + builder.add(types.InlineKeyboardButton(text="Назад", callback_data="main_menu")) + await call.message.answer("Ртот Р±РѕС‚ был создан студентами для лаборатории РњРРРњ.", reply_markup=builder.as_markup()) + +# Обработчик нажатия РЅР° "Р’С…РѕРґ" +@router.callback_query(lambda call: call.data == 'login') +async def ask_for_login(call: CallbackQuery, state: FSMContext): + await delete_messages_up_to_start(call.message.chat.id, call.message.message_id) + + builder = InlineKeyboardBuilder() + builder.add(types.InlineKeyboardButton(text="Назад", callback_data="main_menu")) + await call.message.answer("Введите ваш логин:", reply_markup=builder.as_markup()) + await state.set_state(AuthStates.waiting_for_login) + +# Обработка РІРІРѕРґР° логина +@router.message(AuthStates.waiting_for_login) +async def get_login(message: types.Message, state: FSMContext): + await delete_messages_up_to_start(message.chat.id, message.message_id) + + # Сохраняем логин РІ словарь авторизованных пользователей + chat_id = message.chat.id + login = message.text + auth_users[chat_id] = login + + await state.clear() + await message.answer(f"Р’С‹ успешно вошли РІ систему как {login}.") + await show_profile_menu(chat_id) + +# Отображение меню профиля +async def show_profile_menu(chat_id): + builder = InlineKeyboardBuilder() + builder.add(types.InlineKeyboardButton(text="Профиль", callback_data="profile")) + builder.add(types.InlineKeyboardButton(text="РњРѕРё заказы", callback_data="show_orders")) # Новая РєРЅРѕРїРєР° для заказа + await bot.send_message(chat_id, "Выберите действие:", reply_markup=builder.as_markup()) + +# Обработчик нажатия РЅР° "Профиль" +@router.callback_query(lambda call: call.data == 'profile') +async def show_profile(call: CallbackQuery): + # Получаем логин РёР· словаря auth_users + login = auth_users.get(call.message.chat.id, "РќРµ указан") # Если логин РЅРµ найден, показываем "РќРµ указан" + + # Удаляем предыдущие сообщения + await delete_messages_up_to_start(call.message.chat.id, call.message.message_id) + + builder = InlineKeyboardBuilder() + builder.add(types.InlineKeyboardButton(text="Выйти", callback_data="logout")) + builder.add(types.InlineKeyboardButton(text="Назад", callback_data="profile_menu")) + + await call.message.answer(f"Ваш профиль:\nЛогин: {login}\nВыберите действие:", reply_markup=builder.as_markup()) + +# Обработчик нажатия РЅР° "Назад" РёР· профиля +@router.callback_query(lambda call: call.data == 'profile_menu') +async def back_to_profile_menu(call: CallbackQuery): + await delete_messages_up_to_start(call.message.chat.id, call.message.message_id) + await show_profile_menu(call.message.chat.id) + +# Обработчик выхода РёР· профиля +@router.callback_query(lambda call: call.data == 'logout') +async def logout_user(call: CallbackQuery, state: FSMContext): + await delete_messages_up_to_start(call.message.chat.id, call.message.message_id) + chat_id = call.message.chat.id + auth_users[chat_id] = None # Забываем пользователя РїСЂРё выходе + await call.message.answer("Р’С‹ вышли РёР· профиля.") + await send_welcome(call.message, state) + +# Обработчик возврата РІ главное меню +@router.callback_query(lambda call: call.data == 'main_menu') +async def back_to_main_menu(call: CallbackQuery, state: FSMContext): + await delete_messages_up_to_start(call.message.chat.id, call.message.message_id) + await send_welcome(call.message, state) + +# Обработчик команды /profil +@router.message(Command(commands=['profil'])) +async def show_profile_status(message: types.Message): + chat_id = message.chat.id + + # Проверяем, авторизован ли пользователь + login = auth_users.get(chat_id) + + if login: # Если пользователь авторизован, показываем его логин + await message.answer(f"Р’С‹ авторизованы как {login}.") + else: # Если пользователь РЅРµ авторизован + await message.answer("Р’С‹ РЅРµ авторизованы. Пожалуйста, войдите РІ систему.") + +# Обработчик нажатия РЅР° "РњРѕРё заказы" +@router.callback_query(lambda call: call.data == 'show_orders') +async def show_orders(call: CallbackQuery): + chat_id = call.message.chat.id + login = auth_users.get(chat_id) + + # Удаляем предыдущие сообщения + await delete_messages_up_to_start(chat_id, call.message.message_id) + + if login: + user_orders = get_order_statuses_with_ids(login) + if user_orders: + order_details = [f"Order ID: {order_id}, Status: {status}" for order_id, status in user_orders] + orders_text = "Ваши заказы:\n" + "\n".join(order_details) + else: + orders_text = "Заказы отсутствуют." + + # Строим меню СЃ РєРЅРѕРїРєРѕР№ возврата + builder = InlineKeyboardBuilder() + builder.add(types.InlineKeyboardButton(text="Назад", callback_data="profile_menu")) + + await call.message.answer(orders_text, reply_markup=builder.as_markup()) + else: + await call.message.answer("Р’С‹ РЅРµ авторизованы. Пожалуйста, войдите РІ систему.") + +# Запуск бота +if __name__ == '__main__': + dp.run_polling(bot, skip_updates=True)