feat(orders): добавить поле резюме заказа
Добавлено текстовое поле `summary` в модель `Order` для хранения краткого описания заказа на естественном языке. Обновлена форма `OrderForm` с добавлением виджета textarea, плейсхолдера и стилей. В шаблоны `order_form.html` и `order_detail.html` добавлены элементы для ввода и отображения резюме заказа. Создана соответствующая миграция.
This commit is contained in:
@@ -0,0 +1,29 @@
|
|||||||
|
# Generated by Django 5.0.10 on 2026-01-15 12:25
|
||||||
|
|
||||||
|
import integrations.models.ai_services.openrouter
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('integrations', '0008_openrouter_temperature_choices'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='glmintegration',
|
||||||
|
name='model_name',
|
||||||
|
field=models.CharField(choices=[('glm-4', 'GLM-4 (Платная, дешевле)'), ('glm-4.7', 'GLM-4.7 (Платная)'), ('charglm-3', 'ChargLM-3 (Платная)'), ('glm-4.6v', 'GLM-4.6V (Бесплатная)'), ('glm-4.5v', 'GLM-4.5V (Бесплатная)'), ('glm-4.5-air', 'GLM-4.5-Air (Бесплатная)'), ('glm-4.5-flash', 'GLM-4.5-Flash (Бесплатная)'), ('glm-4.5-flashx', 'GLM-4.5-FlashX (Бесплатная)')], default='glm-4', help_text='Название используемой модели GLM (например, glm-4.7, glm-4)', max_length=100, verbose_name='Название модели'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='openrouterintegration',
|
||||||
|
name='model_name',
|
||||||
|
field=models.CharField(choices=[('xiaomi/mimo-v2-flash:free', 'Xiaomi MIMO v2 Flash (Бесплатная)'), ('mistralai/devstral-2512:free', 'Mistral Devstral 2512 (Бесплатная)'), ('z-ai/glm-4.5-air:free', 'Z.AI GLM-4.5 Air (Бесплатная)'), ('qwen/qwen3-coder:free', 'Qwen 3 Coder (Бесплатная)')], default='xiaomi/mimo-v2-flash:free', help_text='Название используемой модели OpenRouter', max_length=100, verbose_name='Название модели'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='openrouterintegration',
|
||||||
|
name='temperature',
|
||||||
|
field=models.FloatField(choices=[(0.1, '0.1 - Очень консервативно'), (0.3, '0.3 - Консервативно'), (0.5, '0.5 - Умеренно'), (0.7, '0.7 - Баланс (по умолчанию)'), (1.0, '1.0 - Креативно'), (1.5, '1.5 - Очень креативно'), (2.0, '2.0 - Максимальная креативность')], default=0.7, help_text='Параметр температуры для генерации (0.0-2.0)', validators=[integrations.models.ai_services.openrouter.validate_temperature], verbose_name='Температура'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -194,9 +194,16 @@ class OrderForm(forms.ModelForm):
|
|||||||
'needs_product_photo',
|
'needs_product_photo',
|
||||||
'needs_delivery_photo',
|
'needs_delivery_photo',
|
||||||
'special_instructions',
|
'special_instructions',
|
||||||
|
'summary',
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
'special_instructions': forms.Textarea(attrs={'rows': 3}),
|
'special_instructions': forms.Textarea(attrs={'rows': 3}),
|
||||||
|
'summary': forms.Textarea(attrs={
|
||||||
|
'rows': 5,
|
||||||
|
'placeholder': 'Кратко опишите заказ на естественном языке...',
|
||||||
|
'class': 'form-control',
|
||||||
|
'style': 'resize: vertical; min-height: 100px;'
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
|||||||
18
myproject/orders/migrations/0003_order_summary.py
Normal file
18
myproject/orders/migrations/0003_order_summary.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.0.10 on 2026-01-15 12:25
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('orders', '0002_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='order',
|
||||||
|
name='summary',
|
||||||
|
field=models.TextField(blank=True, help_text="Краткое описание заказа на естественном языке (например: '21 фридом 60 см в упаковке на наше усмотрение')", null=True, verbose_name='Резюме заказа'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -122,6 +122,13 @@ class Order(models.Model):
|
|||||||
help_text="Комментарии и пожелания к заказу"
|
help_text="Комментарии и пожелания к заказу"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
summary = models.TextField(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
verbose_name="Резюме заказа",
|
||||||
|
help_text="Краткое описание заказа на естественном языке (например: '21 фридом 60 см в упаковке на наше усмотрение')"
|
||||||
|
)
|
||||||
|
|
||||||
# Фото
|
# Фото
|
||||||
needs_product_photo = models.BooleanField(
|
needs_product_photo = models.BooleanField(
|
||||||
default=False,
|
default=False,
|
||||||
|
|||||||
@@ -21,6 +21,12 @@
|
|||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</h1>
|
</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>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<a href="{% url 'orders:order-update' order.order_number %}" class="btn btn-primary">
|
<a href="{% url 'orders:order-update' order.order_number %}" class="btn btn-primary">
|
||||||
|
|||||||
@@ -171,6 +171,16 @@
|
|||||||
box-shadow: 0 0 20px rgba(220, 53, 69, 0.8), 0 0 30px rgba(220, 53, 69, 0.4);
|
box-shadow: 0 0 20px rgba(220, 53, 69, 0.8), 0 0 30px rgba(220, 53, 69, 0.4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Стили для текстовой области резюме заказа */
|
||||||
|
textarea[name="summary"] {
|
||||||
|
transition: border-color 0.3s ease, box-shadow 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea[name="summary"]:focus {
|
||||||
|
border-color: #80bdff;
|
||||||
|
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@@ -262,6 +272,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Резюме заказа -->
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-header">
|
||||||
|
<h5 class="mb-0">Резюме заказа</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="{{ form.summary.id_for_label }}" class="form-label">Краткое описание заказа</label>
|
||||||
|
{{ form.summary }}
|
||||||
|
<div class="form-text">Введите краткое резюме заказа на естественном языке (например: '21 фридом 60 см в упаковке на наше усмотрение'). Можно использовать переносы строк.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Товары в заказе -->
|
<!-- Товары в заказе -->
|
||||||
<div class="card mb-3">
|
<div class="card mb-3">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
@@ -1046,7 +1070,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
<!-- Delivery Date/Time Widget -->
|
<!-- Delivery Date/Time Widget -->
|
||||||
<script src="{% static 'orders/js/delivery_datetime.js' %}"></script>
|
<script src="{% static 'orders/js/delivery_datetime.js' %}"></script>
|
||||||
<script>
|
<script>
|
||||||
// Убеждаемся, что дата доставки правильно отображается при редактировании
|
// Убеждаемся, что дата доставки правильно отображается п<EFBFBD><EFBFBD>и ред<EFBFBD><EFBFBD>ктировании
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
const deliveryDateField = document.getElementById('{{ form.delivery_date.id_for_label }}');
|
const deliveryDateField = document.getElementById('{{ form.delivery_date.id_for_label }}');
|
||||||
{% if form.delivery_date.initial %}
|
{% if form.delivery_date.initial %}
|
||||||
|
|||||||
Reference in New Issue
Block a user