add CRM module start

This commit is contained in:
root
2026-01-15 07:09:36 +03:00
parent b14f293a45
commit b810a17649
40 changed files with 3807 additions and 14 deletions
+133
View File
@@ -0,0 +1,133 @@
{#
calendar.twig - Универсальный компонент календаря
Параметры:
- events: Массив событий
Пример:
events: [
{
id: 1,
title: 'Событие 1',
date: '2026-01-15',
color: '#3B82F6',
url: '/path/to/event'
}
]
- currentMonth: Текущий месяц в формате YYYY-MM
- prevMonth: URL или параметр для предыдущего месяца
- nextMonth: URL или параметр для следующего месяца
- eventComponent: Имя Twig компонента для рендеринга событий (опционально)
- onEventClick: JavaScript функция при клике на событие (опционально)
- showLegend: Показывать легенду (опционально, по умолчанию true)
- legend: Массив для легенды (опционально)
Пример:
legend: [
{ name: 'Этап 1', color: '#3B82F6' }
]
#}
{# Навигация по месяцам #}
{% if showNavigation|default(true) %}
<div class="card shadow-sm mb-4">
<div class="card-body d-flex justify-content-between align-items-center">
<a href="{{ prevMonth }}" class="btn btn-outline-secondary">
<i class="fa-solid fa-chevron-left me-1"></i>Предыдущий
</a>
<h5 class="mb-0">{{ monthName }}</h5>
<a href="{{ nextMonth }}" class="btn btn-outline-secondary">
Следующий<i class="fa-solid fa-chevron-right ms-1"></i>
</a>
</div>
</div>
{% endif %}
{# Календарь #}
<div class="card shadow-sm">
<div class="card-body p-0">
<div class="calendar">
{# Дни недели #}
<div class="calendar-header bg-light">
{% for day in ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'] %}
<div class="calendar-header-cell text-center py-2 text-muted small fw-normal">
{{ day }}
</div>
{% endfor %}
</div>
{# Сетка календаря #}
<div class="calendar-grid">
{# Пустые ячейки до первого дня #}
{% for i in 0..(firstDayOfWeek - 1) %}
<div class="calendar-cell bg-light"></div>
{% endfor %}
{# Дни месяца #}
{% for day in 1..daysInMonth %}
{% set dateStr = currentMonth ~ '-' ~ (day < 10 ? '0' ~ day : day) %}
{% set dayEvents = eventsByDate[dateStr]|default([]) %}
{% set isToday = dateStr == today %}
<div class="calendar-cell {{ isToday ? 'calendar-cell-today' : '' }}">
<div class="calendar-day-number {{ isToday ? 'text-primary fw-bold' : '' }}">
{{ day }}
</div>
<div class="calendar-events">
{% for event in dayEvents|slice(0, 3) %}
{% if eventComponent is defined %}
{{ include(eventComponent, {event: event}) }}
{% else %}
{{ include('@components/calendar/default_event.twig', {event: event, onEventClick: onEventClick|default('')}) }}
{% endif %}
{% endfor %}
{% if dayEvents|length > 3 %}
<div class="calendar-events-more text-muted small">
+{{ dayEvents|length - 3 }} ещё
</div>
{% endif %}
</div>
</div>
{% endfor %}
{# Пустые ячейки после последнего дня #}
{% set remainingCells = 7 - ((firstDayOfWeek + daysInMonth) % 7) %}
{% if remainingCells < 7 %}
{% for i in 1..remainingCells %}
<div class="calendar-cell bg-light"></div>
{% endfor %}
{% endif %}
</div>
</div>
</div>
</div>
{# Легенда #}
{% if showLegend|default(true) and (legend is defined or events is defined) %}
<div class="card shadow-sm mt-4">
<div class="card-body">
<h6 class="card-title">Легенда</h6>
<div class="d-flex flex-wrap gap-2">
{% if legend is defined %}
{% for item in legend %}
<span class="badge"
style="background-color: {{ item.color }}20; color: {{ item.color }}; border: 1px solid {{ item.color }}40;">
{{ item.name }}
</span>
{% endfor %}
{% else %}
{# Автоматическая легенда из типов событий #}
{% set uniqueColors = {} %}
{% for event in events %}
{% if event.color is defined and event.color not in uniqueColors %}
<span class="badge"
style="background-color: {{ event.color }}20; color: {{ event.color }}; border: 1px solid {{ event.color }}40;">
{{ event.title }}
</span>
{% set uniqueColors = uniqueColors|merge([event.color]) %}
{% endif %}
{% endfor %}
{% endif %}
</div>
</div>
</div>
{% endif %}
@@ -0,0 +1,29 @@
{#
default_event.twig - Событие по умолчанию для Календаря
Параметры:
- event: Объект события
Ожидаемые поля:
- id: Идентификатор
- title: Заголовок
- date: Дата события (для сравнения с today)
- color: Цвет для бордера
- url: Ссылка (опционально)
- onEventClick: JavaScript функция при клике (опционально)
#}
{% if event.url %}
<a href="{{ event.url }}"
class="calendar-event"
style="border-left-color: {{ event.color|default('#6B7280') }}"
{% if onEventClick %}onclick="{{ onEventClick }}({{ event.id }}); return false;"{% endif %}
title="{{ event.title }}">
{{ event.title|length > 15 ? event.title|slice(0, 15) ~ '...' : event.title }}
</a>
{% else %}
<div class="calendar-event"
style="border-left-color: {{ event.color|default('#6B7280') }}"
{% if onEventClick %}onclick="{{ onEventClick }}({{ event.id }});"{% endif %}
title="{{ event.title }}">
{{ event.title|length > 15 ? event.title|slice(0, 15) ~ '...' : event.title }}
</div>
{% endif %}