feat(orders): добавить WYSIWYG редактор для резюме заказа

Интеграция библиотеки Quill.js для форматирования текста в поле
резюме заказа. Добавлено отображение резюме в списке заказов с
возможностью раскрытия длинного текста. Обновлен вид резюме
в детальной странице заказа для поддержки HTML-разметки.
This commit is contained in:
2026-01-16 18:46:04 +03:00
parent 39e050f087
commit edad388ea8
4 changed files with 168 additions and 5 deletions

View File

@@ -2,6 +2,44 @@
{% 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 %}
<div class="container-fluid">
<div class="row mb-4">
@@ -22,9 +60,9 @@
{% endif %}
</h1>
{% if order.summary %}
<div class="alert alert-info mt-3">
<h6><i class="bi bi-sticky"></i> Резюме заказа:</h6>
<p class="mb-0">{{ order.summary|linebreaks }}</p>
<div class="order-summary-block">
<h6><i class="bi bi-sticky"></i> Резюме заказа</h6>
<div class="order-summary-detail">{{ order.summary|safe }}</div>
</div>
{% endif %}
</div>

View File

@@ -279,9 +279,34 @@
</div>
<div class="card-body">
<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 }}
<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>
@@ -2370,5 +2395,59 @@ document.addEventListener('DOMContentLoaded', function() {
});
})();
</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 %}

View File

@@ -5,6 +5,31 @@
{% block extra_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 %}
{% block content %}
@@ -97,6 +122,7 @@
<th>Дата</th>
<th>Время</th>
<th>Тип</th>
<th>Резюме</th>
<th>Статус</th>
<th>Сумма</th>
<th>Оплата</th>
@@ -132,6 +158,13 @@
<span class="badge bg-secondary">Самовывоз</span>
{% endif %}
</td>
<td class="order-summary-cell">
{% if order.summary %}
<div class="order-summary-text" title="Клик для раскрытия/сворачивания">{{ order.summary|safe }}</div>
{% else %}
<span class="text-muted">&mdash;</span>
{% endif %}
</td>
<td>
<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="Кликните для изменения">
@@ -347,6 +380,13 @@
}, 200);
});
});
// Toggle для раскрытия/сворачивания резюме заказа
document.querySelectorAll('.order-summary-text').forEach(function(el) {
el.addEventListener('click', function() {
this.classList.toggle('expanded');
});
});
})();
</script>
{% endblock %}

View File

@@ -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-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">
@@ -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/i18n/ru.js"></script>
<!-- Quill.js (WYSIWYG редактор) -->
<script src="https://cdn.quilljs.com/1.3.6/quill.min.js"></script>
<!-- Auth functionality -->
<script src="{% static 'accounts/js/auth.js' %}"></script>