Optimize order statuses list page with compact card layout

- Changed from table to card-based design for better space efficiency
- Reduced padding and margins to fit 15+ statuses on screen without scrolling
- Minimized font sizes and icon sizes for compact display
- Added proper styling for edit and delete buttons with hover effects
- Improved visual hierarchy with color indicators and badges
- Maintained all functionality while improving UX

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-18 23:00:29 +03:00
parent efbc6ce595
commit a1888b7745
4 changed files with 339 additions and 374 deletions

View File

@@ -163,7 +163,28 @@ class ConfigurableKitProductCreateView(LoginRequiredMixin, CreateView):
return self.form_invalid(form)
if not option_formset.is_valid():
messages.error(self.request, 'Пожалуйста, исправьте ошибки в вариантах.')
# Логирование ошибок formset
import logging
logger = logging.getLogger(__name__)
logger.error(f"Option formset errors: {option_formset.errors}")
logger.error(f"Option formset non-form errors: {option_formset.non_form_errors()}")
# Показываем детальные ошибки
error_msg = 'Ошибки в вариантах:\n'
for i, form_errors in enumerate(option_formset.errors):
if form_errors:
error_msg += f' Вариант {i+1}: {form_errors}\n'
if option_formset.non_form_errors():
error_msg += f' Общие ошибки: {option_formset.non_form_errors()}\n'
messages.error(self.request, error_msg)
return self.render_to_response(self.get_context_data(form=form, option_formset=option_formset, attribute_formset=attribute_formset))
# Валидация что каждый вариант имеет выбранный комплект
validation_errors = self._validate_variant_kits(option_formset)
if validation_errors:
for error in validation_errors:
messages.error(self.request, error)
return self.render_to_response(self.get_context_data(form=form, option_formset=option_formset, attribute_formset=attribute_formset))
if not attribute_formset.is_valid():
@@ -297,6 +318,48 @@ class ConfigurableKitProductCreateView(LoginRequiredMixin, CreateView):
ConfigurableKitProductAttribute.objects.create(**create_kwargs)
def _validate_variant_kits(self, option_formset):
"""
Валидация что каждый вариант имеет выбранный комплект.
Возвращает список ошибок (пустой список если нет ошибок).
"""
errors = []
for idx, option_form in enumerate(option_formset):
# Пропускаем удаленные или пустые формы
if not option_form.cleaned_data or self._should_delete_form(option_form, option_formset):
continue
# Получаем kit_id из POST данных (он там должен быть установлен JavaScript'ом)
kit_id = self.request.POST.get(f'options-{idx}-kit', '').strip()
if not kit_id:
# Пытаемся получить из cleaned_data
kit_id = option_form.cleaned_data.get('kit')
if not kit_id:
# Если у варианта есть выбранные атрибуты, но нет комплекта - это ошибка
has_attributes = any(
option_form.cleaned_data.get(k)
for k in option_form.cleaned_data.keys()
if k.startswith('attribute_')
)
if has_attributes:
# Собираем названия выбранных атрибутов для сообщения об ошибке
selected_attrs = [
str(option_form.cleaned_data.get(k))
for k in option_form.cleaned_data.keys()
if k.startswith('attribute_') and option_form.cleaned_data.get(k)
]
errors.append(
f'Вариант {idx + 1} ({", ".join(selected_attrs)}): '
f'не выбран комплект. Пожалуйста, выберите значения атрибутов которые '
f'привязаны к одному комплекту.'
)
return errors
@staticmethod
def _should_delete_form(form, formset):
"""Проверить должна ли форма быть удалена"""
@@ -378,7 +441,28 @@ class ConfigurableKitProductUpdateView(LoginRequiredMixin, UpdateView):
return self.form_invalid(form)
if not option_formset.is_valid():
messages.error(self.request, 'Пожалуйста, исправьте ошибки в вариантах.')
# Логирование ошибок formset
import logging
logger = logging.getLogger(__name__)
logger.error(f"Option formset errors: {option_formset.errors}")
logger.error(f"Option formset non-form errors: {option_formset.non_form_errors()}")
# Показываем детальные ошибки
error_msg = 'Ошибки в вариантах:\n'
for i, form_errors in enumerate(option_formset.errors):
if form_errors:
error_msg += f' Вариант {i+1}: {form_errors}\n'
if option_formset.non_form_errors():
error_msg += f' Общие ошибки: {option_formset.non_form_errors()}\n'
messages.error(self.request, error_msg)
return self.render_to_response(self.get_context_data(form=form, option_formset=option_formset, attribute_formset=attribute_formset))
# Валидация что каждый вариант имеет выбранный комплект
validation_errors = self._validate_variant_kits(option_formset)
if validation_errors:
for error in validation_errors:
messages.error(self.request, error)
return self.render_to_response(self.get_context_data(form=form, option_formset=option_formset, attribute_formset=attribute_formset))
if not attribute_formset.is_valid():
@@ -511,6 +595,48 @@ class ConfigurableKitProductUpdateView(LoginRequiredMixin, UpdateView):
ConfigurableKitProductAttribute.objects.create(**create_kwargs)
def _validate_variant_kits(self, option_formset):
"""
Валидация что каждый вариант имеет выбранный комплект.
Возвращает список ошибок (пустой список если нет ошибок).
"""
errors = []
for idx, option_form in enumerate(option_formset):
# Пропускаем удаленные или пустые формы
if not option_form.cleaned_data or self._should_delete_form(option_form, option_formset):
continue
# Получаем kit_id из POST данных (он там должен быть установлен JavaScript'ом)
kit_id = self.request.POST.get(f'options-{idx}-kit', '').strip()
if not kit_id:
# Пытаемся получить из cleaned_data
kit_id = option_form.cleaned_data.get('kit')
if not kit_id:
# Если у варианта есть выбранные атрибуты, но нет комплекта - это ошибка
has_attributes = any(
option_form.cleaned_data.get(k)
for k in option_form.cleaned_data.keys()
if k.startswith('attribute_')
)
if has_attributes:
# Собираем названия выбранных атрибутов для сообщения об ошибке
selected_attrs = [
str(option_form.cleaned_data.get(k))
for k in option_form.cleaned_data.keys()
if k.startswith('attribute_') and option_form.cleaned_data.get(k)
]
errors.append(
f'Вариант {idx + 1} ({", ".join(selected_attrs)}): '
f'не выбран комплект. Пожалуйста, выберите значения атрибутов которые '
f'привязаны к одному комплекту.'
)
return errors
@staticmethod
def _should_delete_form(form, formset):
"""Проверить должна ли форма быть удалена"""