my-project/templates/base.html
2026-03-23 11:35:48 +05:00

620 lines
22 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}OfficeStyle - Офисная мебель{% endblock %}</title>
<!-- Bootstrap 5 -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome Icons -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<!-- Franklin Gothic Font -->
<link href="https://fonts.googleapis.com/css2?family=Franklin+Gothic:wght@400;500;600;700&display=swap" rel="stylesheet">
<!-- Custom CSS -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<!-- Favicon -->
<link rel="icon" href="{{ url_for('static', filename='OfficeStyle.png') }}" type="image/png">
<!-- Inline Styles -->
<style>
:root {
--alice-blue: #F0F8FF;
--light-steel-blue: #B0C4DE;
--steel-blue: #4682B4;
}
body {
font-family: 'Franklin Gothic', 'Arial Narrow', Arial, sans-serif;
background-color: var(--alice-blue);
margin: 0;
padding: 0;
}
.main-container {
background-color: #ffffff;
min-height: 100vh;
padding: 0;
}
.container {
max-width: 1400px;
margin: 0 auto;
padding: 20px 30px;
}
/* Навигационные вкладки */
.nav-tabs-section {
border-bottom: 2px solid var(--light-steel-blue);
margin-bottom: 25px;
}
.nav-tabs {
border-bottom: none;
gap: 5px;
}
.nav-tabs .nav-link {
color: #6c757d;
font-family: 'Franklin Gothic', 'Arial Narrow', Arial, sans-serif;
font-weight: 500;
border: 2px solid transparent;
border-radius: 10px 10px 0 0;
padding: 12px 25px;
transition: all 0.2s ease;
font-size: 1.1rem;
}
.nav-tabs .nav-link i {
margin-right: 8px;
font-size: 1.1rem;
}
.nav-tabs .nav-link:hover {
color: var(--steel-blue);
border-color: var(--light-steel-blue) var(--light-steel-blue) transparent;
background-color: rgba(176, 196, 222, 0.1);
}
.nav-tabs .nav-link.active {
color: var(--steel-blue);
font-weight: 600;
border-color: var(--light-steel-blue) var(--light-steel-blue) transparent;
border-bottom: 2px solid white;
background: linear-gradient(135deg, var(--alice-blue) 0%, #E6F2FF 100%);
}
/* Заголовки страниц */
.page-title {
color: var(--steel-blue);
font-size: 2rem;
font-weight: 600;
font-family: 'Franklin Gothic', 'Arial Narrow', Arial, sans-serif;
margin: 0;
}
/* Карточки */
.card {
border: 1px solid var(--light-steel-blue);
border-radius: 15px;
box-shadow: 0 4px 10px rgba(70, 130, 180, 0.1);
transition: all 0.2s ease;
}
.card:hover {
box-shadow: 0 8px 20px rgba(70, 130, 180, 0.15);
}
.card-header {
background: linear-gradient(135deg, var(--steel-blue) 0%, var(--light-steel-blue) 100%);
color: white;
border-radius: 15px 15px 0 0 !important;
padding: 15px 20px;
}
.card-header h2, .card-header h5 {
margin: 0;
font-weight: 600;
}
/* Кнопки */
.btn {
font-family: 'Franklin Gothic', 'Arial Narrow', Arial, sans-serif;
border: none;
border-radius: 8px;
padding: 10px 20px;
transition: all 0.2s ease;
font-weight: 500;
}
.btn-primary {
background: linear-gradient(135deg, var(--steel-blue) 0%, #3a6d99 100%);
color: white;
}
.btn-primary:hover {
background: linear-gradient(135deg, #3a6d99 0%, var(--steel-blue) 100%);
transform: translateY(-2px);
box-shadow: 0 4px 10px rgba(70, 130, 180, 0.3);
}
.btn-success {
background: linear-gradient(135deg, #28a745 0%, #218838 100%);
color: white;
}
.btn-success:hover {
background: linear-gradient(135deg, #218838 0%, #28a745 100%);
transform: translateY(-2px);
box-shadow: 0 4px 10px rgba(40, 167, 69, 0.3);
}
.btn-secondary {
background: linear-gradient(135deg, var(--light-steel-blue) 0%, #9fb6d4 100%);
color: #2c3e50;
}
.btn-secondary:hover {
background: linear-gradient(135deg, #9fb6d4 0%, var(--light-steel-blue) 100%);
transform: translateY(-2px);
box-shadow: 0 4px 10px rgba(176, 196, 222, 0.3);
color: #2c3e50;
}
.btn-info {
background: linear-gradient(135deg, var(--steel-blue) 0%, #3a6d99 100%);
color: white;
}
.btn-info:hover {
background: linear-gradient(135deg, #3a6d99 0%, var(--steel-blue) 100%);
transform: translateY(-2px);
box-shadow: 0 4px 10px rgba(70, 130, 180, 0.3);
}
.btn-back {
background: linear-gradient(135deg, var(--light-steel-blue) 0%, #9fb6d4 100%);
border: none;
border-radius: 8px;
padding: 10px 20px;
color: #2c3e50;
transition: all 0.2s ease;
}
.btn-back:hover {
background: linear-gradient(135deg, #9fb6d4 0%, var(--light-steel-blue) 100%);
transform: translateY(-2px);
box-shadow: 0 4px 10px rgba(176, 196, 222, 0.3);
}
/* Формы */
.form-label {
color: var(--steel-blue);
font-weight: 500;
font-family: 'Franklin Gothic', 'Arial Narrow', Arial, sans-serif;
margin-bottom: 5px;
}
.form-control, .form-select {
border: 2px solid var(--light-steel-blue);
border-radius: 8px;
padding: 10px 15px;
font-family: 'Franklin Gothic', 'Arial Narrow', Arial, sans-serif;
transition: all 0.2s ease;
}
.form-control:focus, .form-select:focus {
border-color: var(--steel-blue);
box-shadow: 0 0 0 0.2rem rgba(70, 130, 180, 0.25);
outline: none;
}
.form-control:hover, .form-select:hover {
border-color: var(--steel-blue);
}
.form-text {
color: #6c757d;
font-size: 0.85rem;
margin-top: 5px;
}
/* Таблицы */
.table {
background-color: white;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.table thead th {
background-color: var(--steel-blue);
color: white;
font-weight: 600;
border: none;
padding: 12px;
font-family: 'Franklin Gothic', 'Arial Narrow', Arial, sans-serif;
}
.table tbody tr:hover {
background-color: rgba(176, 196, 222, 0.2);
}
.table tbody td {
font-family: 'Franklin Gothic', 'Arial Narrow', Arial, sans-serif;
color: #2c3e50;
vertical-align: middle;
}
.table a {
color: var(--steel-blue);
text-decoration: none;
font-weight: 500;
}
.table a:hover {
text-decoration: underline;
}
/* Бейджи и статусы */
.badge {
padding: 8px 12px;
font-size: 0.85rem;
border-radius: 20px;
font-family: 'Franklin Gothic', 'Arial Narrow', Arial, sans-serif;
font-weight: 500;
}
.badge.bg-success {
background: linear-gradient(135deg, #28a745 0%, #218838 100%) !important;
color: white !important;
}
.badge.bg-warning {
background: linear-gradient(135deg, #ffc107 0%, #e0a800 100%) !important;
color: #2c3e50 !important;
}
.badge.bg-danger {
background: linear-gradient(135deg, #dc3545 0%, #c82333 100%) !important;
color: white !important;
}
.badge.bg-info {
background: linear-gradient(135deg, var(--steel-blue) 0%, #3a6d99 100%) !important;
color: white !important;
}
.badge.bg-secondary {
background: linear-gradient(135deg, #6c757d 0%, #5a6268 100%) !important;
color: white !important;
}
/* Статистика */
.stats-card {
background: linear-gradient(135deg, var(--alice-blue) 0%, #E6F2FF 100%);
border: 1px solid var(--light-steel-blue);
border-radius: 15px;
padding: 20px;
box-shadow: 0 4px 10px rgba(70, 130, 180, 0.1);
height: 100%;
}
.stat-item {
text-align: center;
padding: 15px;
background: linear-gradient(135deg, white 0%, #f8f9fa 100%);
border: 2px solid var(--light-steel-blue);
border-radius: 12px;
box-shadow: 0 4px 8px rgba(70, 130, 180, 0.15);
transition: all 0.2s ease;
height: 100%;
}
.stat-item:hover {
transform: translateY(-3px);
box-shadow: 0 8px 15px rgba(70, 130, 180, 0.25);
border-color: var(--steel-blue);
}
.stat-number {
color: #2c3e50;
font-size: 2rem;
font-weight: 700;
line-height: 1.2;
margin-bottom: 5px;
}
.stat-label {
color: #6c757d;
font-size: 0.9rem;
text-transform: uppercase;
letter-spacing: 0.5px;
}
/* Информационные блоки */
.info-card {
background: linear-gradient(135deg, var(--alice-blue) 0%, #E6F2FF 100%);
border: 1px solid var(--light-steel-blue);
border-radius: 15px;
padding: 20px;
box-shadow: 0 4px 10px rgba(70, 130, 180, 0.1);
}
.info-item {
margin-bottom: 10px;
padding: 8px 15px;
background-color: rgba(255, 255, 255, 0.5);
border-radius: 8px;
}
.info-label {
color: var(--steel-blue);
font-weight: 600;
margin-right: 10px;
}
.info-value {
color: #2c3e50;
}
/* Уведомления */
.flashed-messages {
margin-bottom: 20px;
}
.alert {
border-radius: 12px;
border: 1px solid var(--light-steel-blue);
background: linear-gradient(135deg, var(--alice-blue) 0%, #E6F2FF 100%);
border-left: 6px solid var(--steel-blue);
font-family: 'Franklin Gothic', 'Arial Narrow', Arial, sans-serif;
color: #2c3e50;
}
.alert-success {
border-left-color: #28a745;
}
.alert-danger {
border-left-color: #dc3545;
}
.alert-info {
border-left-color: var(--steel-blue);
}
.alert-link {
color: var(--steel-blue);
font-weight: 600;
text-decoration: none;
}
.alert-link:hover {
text-decoration: underline;
}
/* Модальное окно */
.modal-header {
background: linear-gradient(135deg, var(--steel-blue) 0%, var(--light-steel-blue) 100%);
color: white;
border-radius: 15px 15px 0 0;
}
.modal-content {
border: 1px solid var(--light-steel-blue);
border-radius: 15px;
}
.btn-close-white {
filter: invert(1) grayscale(100%) brightness(200%);
}
/* Адаптация для мобильных */
@media (max-width: 768px) {
.container {
padding: 15px;
}
.page-title {
font-size: 1.5rem;
}
.nav-tabs .nav-link {
padding: 8px 15px;
font-size: 0.9rem;
}
.stat-number {
font-size: 1.5rem;
}
.btn {
padding: 8px 15px;
font-size: 0.9rem;
}
}
</style>
</head>
<body>
<div class="main-container">
<div class="container">
{% block header %}
{% include 'components/header.html' %}
{% endblock %}
<!-- Навигационные вкладки - показываем только на основных страницах -->
{% if request.endpoint in ['index', 'orders_list', 'catalog'] %}
<div class="nav-tabs-section mb-4">
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'index' %}active{% endif %}" href="{{ url_for('index') }}">
<i class="fas fa-industry"></i> Партнеры
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'orders_list' %}active{% endif %}" href="{{ url_for('orders_list') }}">
<i class="fas fa-shopping-cart"></i> Заказы
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'catalog' %}active{% endif %}" href="{{ url_for('catalog') }}">
<i class="fas fa-box"></i> Товары
</a>
</li>
</ul>
</div>
{% endif %}
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<div class="flashed-messages">
{% for category, message in messages %}
<div class="alert alert-{{ category }} alert-dismissible fade show" role="alert">
<i class="fas fa-info-circle me-2"></i>{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
</div>
{% endif %}
{% endwith %}
{% block content %}
{% endblock %}
</div>
</div>
<!-- Project Info Modal -->
<div class="modal fade" id="projectInfoModal" tabindex="-1" aria-labelledby="projectInfoModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="projectInfoModalLabel">
<i class="fas fa-info-circle"></i> О проекте OfficeStyle
</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<h5>Система учета офисной мебели</h5>
<p><strong>Цель проекта:</strong> Управление производителями, типами мебели и расчет стоимости с учетом сборки и доставки.</p>
<h6>Основные функции:</h6>
<ul>
<li>Учет производителей мебели</li>
<li>Каталог типов офисной мебели</li>
<li>История заказов</li>
<li>Расчет стоимости с учетом сборки и доставки</li>
<li>Автоматические скидки</li>
</ul>
<div class="color-palette mt-3">
<h6>Цветовая палитра проекта:</h6>
<div class="d-flex gap-2">
<div style="width: 40px; height: 40px; background-color: #F0F8FF; border: 1px solid #ddd;"
data-bs-toggle="tooltip" title="Алиса синий (#F0F8FF)"></div>
<div style="width: 40px; height: 40px; background-color: #B0C4DE; border: 1px solid #ddd;"
data-bs-toggle="tooltip" title="Светло-стальной (#B0C4DE)"></div>
<div style="width: 40px; height: 40px; background-color: #4682B4; border: 1px solid #ddd;"
data-bs-toggle="tooltip" title="Стальной синий (#4682B4)"></div>
</div>
</div>
<div class="mt-3">
<h6>Технологии:</h6>
<span class="badge bg-primary me-1">Flask</span>
<span class="badge bg-success me-1">SQLite</span>
<span class="badge bg-info me-1">Bootstrap 5</span>
<span class="badge bg-warning me-1">Font Awesome</span>
<span class="badge bg-secondary me-1">Franklin Gothic</span>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
</div>
</div>
</div>
</div>
<!-- Bootstrap JS Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<!-- Custom JavaScript -->
<script src="{{ url_for('static', filename='js/script.js') }}"></script>
<!-- Inline JavaScript -->
<script>
// Initialize tooltips and popovers
document.addEventListener('DOMContentLoaded', function() {
// Tooltips
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
// Popovers
var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
var popoverList = popoverTriggerList.map(function (popoverTriggerEl) {
return new bootstrap.Popover(popoverTriggerEl);
});
// Auto-dismiss alerts after 5 seconds
setTimeout(function() {
var alerts = document.querySelectorAll('.alert:not(.alert-permanent)');
alerts.forEach(function(alert) {
var bsAlert = new bootstrap.Alert(alert);
bsAlert.close();
});
}, 5000);
});
// Function to show project info modal
function showProjectInfo() {
var projectInfoModal = new bootstrap.Modal(document.getElementById('projectInfoModal'));
projectInfoModal.show();
}
// Form validation helper
function validateForm(formId) {
var form = document.getElementById(formId);
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
}
form.classList.add('was-validated');
return form.checkValidity();
}
// Calculate furniture cost
function calculateFurnitureCost(basePrice, quantity, assemblyCoeff, deliveryCoeff) {
if (!basePrice || !quantity) {
alert('Введите базовую цену и количество');
return null;
}
basePrice = parseFloat(basePrice);
quantity = parseInt(quantity);
assemblyCoeff = parseFloat(assemblyCoeff) || 1.0;
deliveryCoeff = parseFloat(deliveryCoeff) || 1.0;
const baseCost = basePrice * quantity;
const assemblyCost = baseCost * (assemblyCoeff - 1.0);
const deliveryCost = baseCost * (deliveryCoeff - 1.0);
const totalCost = baseCost + assemblyCost + deliveryCost;
return {
baseCost: baseCost,
assemblyCost: assemblyCost,
deliveryCost: deliveryCost,
totalCost: totalCost
};
}
</script>
{% block scripts %}
{% endblock %}
</body>
</html>