feat(orders): добавить WYSIWYG редактор для резюме заказа
Интеграция библиотеки Quill.js для форматирования текста в поле резюме заказа. Добавлено отображение резюме в списке заказов с возможностью раскрытия длинного текста. Обновлен вид резюме в детальной странице заказа для поддержки HTML-разметки.
This commit is contained in:
@@ -2,6 +2,44 @@
|
|||||||
|
|
||||||
{% block title %}Заказ {{ order.order_number }}{% endblock %}
|
{% block title %}Заказ {{ order.order_number }}{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_css %}
|
||||||
|
<style>
|
||||||
|
.order-summary-block {
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-left: 4px solid #6c757d;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 1rem 1.25rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
.order-summary-block h6 {
|
||||||
|
color: #495057;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
.order-summary-detail ul {
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
.order-summary-detail ol {
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
.order-summary-detail li {
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
.order-summary-detail p:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.order-summary-detail strong {
|
||||||
|
color: #212529;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.order-summary-detail em {
|
||||||
|
color: #495057;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row mb-4">
|
<div class="row mb-4">
|
||||||
@@ -22,9 +60,9 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</h1>
|
</h1>
|
||||||
{% if order.summary %}
|
{% if order.summary %}
|
||||||
<div class="alert alert-info mt-3">
|
<div class="order-summary-block">
|
||||||
<h6><i class="bi bi-sticky"></i> Резюме заказа:</h6>
|
<h6><i class="bi bi-sticky"></i> Резюме заказа</h6>
|
||||||
<p class="mb-0">{{ order.summary|linebreaks }}</p>
|
<div class="order-summary-detail">{{ order.summary|safe }}</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -279,9 +279,34 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="{{ form.summary.id_for_label }}" class="form-label">Краткое описание заказа</label>
|
<label class="form-label">Краткое описание заказа</label>
|
||||||
|
<!-- Скрываем оригинальную textarea -->
|
||||||
|
<style>
|
||||||
|
textarea[name="summary"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#quill-editor-summary {
|
||||||
|
min-height: 120px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
#quill-editor-summary .ql-toolbar {
|
||||||
|
border-radius: 4px 4px 0 0;
|
||||||
|
}
|
||||||
|
#quill-editor-summary .ql-container {
|
||||||
|
border-radius: 0 0 4px 4px;
|
||||||
|
min-height: 80px;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
#quill-editor-summary .ql-picker.ql-color .ql-picker-label {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<!-- Контейнер для Quill редактора -->
|
||||||
|
<div id="quill-editor-summary"></div>
|
||||||
{{ form.summary }}
|
{{ form.summary }}
|
||||||
<div class="form-text">Введите краткое резюме заказа на естественном языке (например: '21 фридом 60 см в упаковке на наше усмотрение'). Можно использовать переносы строк.</div>
|
<div class="form-text">Можно использовать <strong>жирный</strong>, <em>курсив</em>, <span style="color: #e31e23;">цвет</span>, <span style="font-size: 18px;">размер</span> и списки.</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -2370,5 +2395,59 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!-- Quill WYSIWYG редактор для поля Резюме -->
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// Ждём загрузки DOM
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const summaryTextarea = document.querySelector('textarea[name="summary"]');
|
||||||
|
const quillContainer = document.getElementById('quill-editor-summary');
|
||||||
|
|
||||||
|
if (!summaryTextarea || !quillContainer) {
|
||||||
|
return; // Поле не найдено, выходим
|
||||||
|
}
|
||||||
|
|
||||||
|
// Инициализация Quill
|
||||||
|
const quill = new Quill('#quill-editor-summary', {
|
||||||
|
theme: 'snow',
|
||||||
|
placeholder: 'Кратко опишите заказ (например: 21 фридом 60 см в упаковке на наше усмотрение)...',
|
||||||
|
modules: {
|
||||||
|
toolbar: [
|
||||||
|
['bold', 'italic', 'underline'],
|
||||||
|
[{ 'color': [] }, { 'background': [] }],
|
||||||
|
[{ 'size': ['small', false, 'large', 'huge'] }],
|
||||||
|
[{ 'list': 'ordered'}, { 'list': 'bullet' }],
|
||||||
|
['clean']
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Загружаем существующее значение в редактор
|
||||||
|
const existingValue = summaryTextarea.value.trim();
|
||||||
|
if (existingValue) {
|
||||||
|
quill.root.innerHTML = existingValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Синхронизируем содержимое редактора с textarea при изменениях
|
||||||
|
quill.on('text-change', function() {
|
||||||
|
const html = quill.root.innerHTML;
|
||||||
|
// Если редактор пуст, сохраняем пустую строку
|
||||||
|
summaryTextarea.value = html === '<p><br></p>' ? '' : html;
|
||||||
|
});
|
||||||
|
|
||||||
|
// При отправке формы убедимся, что значение синхронизировано
|
||||||
|
const form = document.getElementById('order-form');
|
||||||
|
if (form) {
|
||||||
|
form.addEventListener('submit', function() {
|
||||||
|
const html = quill.root.innerHTML;
|
||||||
|
summaryTextarea.value = html === '<p><br></p>' ? '' : html;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,31 @@
|
|||||||
|
|
||||||
{% block extra_css %}
|
{% block extra_css %}
|
||||||
<link rel="stylesheet" href="{% static 'orders/css/date_filter.css' %}">
|
<link rel="stylesheet" href="{% static 'orders/css/date_filter.css' %}">
|
||||||
|
<style>
|
||||||
|
.order-summary-cell {
|
||||||
|
max-width: 280px;
|
||||||
|
}
|
||||||
|
.order-summary-text {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
|
overflow: hidden;
|
||||||
|
word-break: break-word;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
color: #212529;
|
||||||
|
}
|
||||||
|
.order-summary-text:hover {
|
||||||
|
color: #0d6efd;
|
||||||
|
}
|
||||||
|
.order-summary-text.expanded {
|
||||||
|
-webkit-line-clamp: unset;
|
||||||
|
max-height: none;
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
@@ -97,6 +122,7 @@
|
|||||||
<th>Дата</th>
|
<th>Дата</th>
|
||||||
<th>Время</th>
|
<th>Время</th>
|
||||||
<th>Тип</th>
|
<th>Тип</th>
|
||||||
|
<th>Резюме</th>
|
||||||
<th>Статус</th>
|
<th>Статус</th>
|
||||||
<th>Сумма</th>
|
<th>Сумма</th>
|
||||||
<th>Оплата</th>
|
<th>Оплата</th>
|
||||||
@@ -132,6 +158,13 @@
|
|||||||
<span class="badge bg-secondary">Самовывоз</span>
|
<span class="badge bg-secondary">Самовывоз</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
|
<td class="order-summary-cell">
|
||||||
|
{% if order.summary %}
|
||||||
|
<div class="order-summary-text" title="Клик для раскрытия/сворачивания">{{ order.summary|safe }}</div>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-muted">—</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="js-status-container" data-order-number="{{ order.order_number }}">
|
<div class="js-status-container" data-order-number="{{ order.order_number }}">
|
||||||
<span class="badge badge-lg js-status-badge" style="{% if order.status %}background-color: {{ order.status.color }}; color: #fff;{% else %}background-color: #6c757d; color: #fff;{% endif %} cursor: pointer; font-size: 0.9rem; padding: 0.5rem 0.75rem;" title="Кликните для изменения">
|
<span class="badge badge-lg js-status-badge" style="{% if order.status %}background-color: {{ order.status.color }}; color: #fff;{% else %}background-color: #6c757d; color: #fff;{% endif %} cursor: pointer; font-size: 0.9rem; padding: 0.5rem 0.75rem;" title="Кликните для изменения">
|
||||||
@@ -347,6 +380,13 @@
|
|||||||
}, 200);
|
}, 200);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Toggle для раскрытия/сворачивания резюме заказа
|
||||||
|
document.querySelectorAll('.order-summary-text').forEach(function(el) {
|
||||||
|
el.addEventListener('click', function() {
|
||||||
|
this.classList.toggle('expanded');
|
||||||
|
});
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -14,6 +14,9 @@
|
|||||||
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
|
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
|
||||||
<link href="https://cdn.jsdelivr.net/npm/select2-bootstrap-5-theme@1.3.0/dist/select2-bootstrap-5-theme.min.css" rel="stylesheet" />
|
<link href="https://cdn.jsdelivr.net/npm/select2-bootstrap-5-theme@1.3.0/dist/select2-bootstrap-5-theme.min.css" rel="stylesheet" />
|
||||||
|
|
||||||
|
<!-- Quill.js CSS (WYSIWYG редактор) -->
|
||||||
|
<link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet" />
|
||||||
|
|
||||||
<!-- Качество фото индикаторы -->
|
<!-- Качество фото индикаторы -->
|
||||||
<link rel="stylesheet" href="/static/css/quality_indicator.css">
|
<link rel="stylesheet" href="/static/css/quality_indicator.css">
|
||||||
|
|
||||||
@@ -55,6 +58,9 @@
|
|||||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/i18n/ru.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/i18n/ru.js"></script>
|
||||||
|
|
||||||
|
<!-- Quill.js (WYSIWYG редактор) -->
|
||||||
|
<script src="https://cdn.quilljs.com/1.3.6/quill.min.js"></script>
|
||||||
|
|
||||||
<!-- Auth functionality -->
|
<!-- Auth functionality -->
|
||||||
<script src="{% static 'accounts/js/auth.js' %}"></script>
|
<script src="{% static 'accounts/js/auth.js' %}"></script>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user