bp/app/Views/components/table/README.md

276 lines
8.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# DataTable Components
Переиспользуемые компоненты для отображения интерактивных таблиц с AJAX-загрузкой, сортировкой и поиском.
## Структура компонентов
```
public/
├── js/
│ └── modules/
│ └── DataTable.js # JS-модуль для инициализации таблиц
└── css/
└── components/
└── data-table.css # Стили для интерактивных таблиц
app/Views/components/table/
├── table.twig # Основной компонент таблицы
├── table_header.twig # Переиспользуемый заголовок
└── pagination.twig # Компонент пагинации
```
## Быстрый старт
### 1. Подключение стилей и скриптов
В вашем шаблоне добавьте:
```twig
{% block stylesheets %}
{{ parent() }}
<link rel="stylesheet" href="/css/components/data-table.css">
{% endblock %}
{% block scripts %}
{{ parent() }}
<script src="/js/modules/DataTable.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
new DataTable('your-table-id', {
url: '/your-module/table',
perPage: 10
});
});
</script>
{% endblock %}
```
### 2. Использование компонента таблицы
```twig
{{ include('@components/table/table.twig', {
id: 'products-table',
url: '/products/table',
perPage: 25,
sort: sort|default(''),
order: order|default('asc'),
filters: filters|default({}),
columns: [
{ name: 'name', label: 'Название', width: '35%' },
{ name: 'sku', label: 'Артикул', width: '15%' },
{ name: 'price', label: 'Цена', width: '15%' },
{ name: 'stock', label: 'Остаток', width: '15%' }
],
actions: { label: 'Действия', width: '20%' },
emptyMessage: 'Товары не найдены'
}) }}
```
## Конфигурация столбцов
Каждый столбец поддерживает следующие параметры:
| Параметр | Тип | Описание |
|----------|-----|----------|
| `name` | string | Идентификатор столбца (используется для сортировки и фильтрации) |
| `label` | string | Отображаемое название столбца |
| `width` | string | Ширина столбца (например, '35%', '200px') |
| `placeholder` | string | Текст-подсказка в поле поиска |
| `searchTitle` | string | Title для иконки поиска |
| `align` | string | CSS-класс выравнивания |
## Конфигурация пагинации
Компонент автоматически получает данные из объекта `pager`:
```php
// В контроллере
$pagination = [
'currentPage' => $pager->getCurrentPage(),
'totalPages' => $pager->getPageCount(),
'totalRecords' => $pager->getTotal(),
'perPage' => $perPage,
'from' => (($pager->getCurrentPage() - 1) * $perPage + 1),
'to' => min($pager->getCurrentPage() * $perPage, $pager->getTotal())
];
```
## Пример контроллера
```php
public function table()
{
$page = (int) ($this->request->getGet('page') ?? 1);
$perPage = (int) ($this->request->getGet('perPage') ?? 10);
$sort = $this->request->getGet('sort') ?? '';
$order = $this->request->getGet('order') ?? 'asc';
// Фильтры
$filters = [
'name' => $this->request->getGet('filters[name]') ?? '',
];
// Построение запроса
$builder = $this->model->builder();
// Применяем фильтры
if (!empty($filters['name'])) {
$builder->like('name', $filters['name']);
}
// Сортировка
if (!empty($sort)) {
$builder->orderBy($sort, $order);
}
// Пагинация
$items = $builder->paginate($perPage, 'default', $page);
$data = [
'items' => $items,
'pager' => $this->model->pager,
'perPage' => $perPage,
'sort' => $sort,
'order' => $order,
'filters' => $filters,
];
return $this->renderTwig('path/to/your/_table', $data);
}
```
## AJAX-ответ
Для AJAX-запросов контроллер должен возвращать только `tbody` и `tfoot`:
```twig
{# _table.twig для модуля #}
{% set isAjax = app.request.headers.get('X-Requested-With') == 'XMLHttpRequest' %}
{% if isAjax %}
{# AJAX: только tbody #}
<tbody>
{% for item in items %}
<tr>
<td>{{ item.name }}</td>
<td>{{ item.price }}</td>
<td class="text-end">
<a href="...">Редактировать</a>
</td>
</tr>
{% endfor %}
</tbody>
{% if items is not empty and pager %}
<tfoot>
<tr>
<td colspan="3">
{{ include('@components/table/pagination.twig', {
pagination: paginationData,
id: 'your-table-id'
}) }}
</td>
</tr>
</tfoot>
{% endif %}
{% else %}
{# Обычный запрос: полная таблица #}
<div class="table-responsive">
{{ include('@components/table/table.twig', {
id: 'your-table-id',
url: '/your-module/table',
perPage: perPage,
columns: columns,
pagination: paginationData,
actions: { label: 'Действия' },
emptyMessage: 'Нет данных'
}) }}
</div>
{% endif %}
```
## API DataTable
### Опции при инициализации
```javascript
new DataTable('container-id', {
url: '/api/endpoint', // URL для AJAX-загрузки
perPage: 10, // Записей на странице по умолчанию
debounceTime: 300, // Задержка поиска в мс
preserveSearchOnSort: true // Сохранять видимость поиска при сортировке
});
```
### Методы
```javascript
const table = new DataTable('my-table', options);
// Установка фильтра
table.setFilter('columnName', 'value');
// Установка количества записей
table.setPerPage(25);
// Переход на страницу
table.goToPage(3);
```
## Доступные CSS-классы
| Класс | Описание |
|-------|----------|
| `.data-table` | Основной контейнер таблицы |
| `.header-content` | Контейнер для элементов заголовка |
| `.header-text` | Текст заголовка столбца |
| `.search-trigger` | Иконка поиска |
| `.sort-icon` | Иконка сортировки |
| `.header-search-input` | Поле ввода поиска |
| `.sort-icon.active` | Активная сортировка |
| `.pagination-wrapper` | Обёртка пагинации |
## Расширение функциональности
### Добавление кастомных действий
Для добавления кнопок действий в строки:
```twig
{% for client in clients %}
<tr>
<td>{{ client.name }}</td>
<td>{{ client.email }}</td>
<td class="actions-cell text-end">
<a href="{{ editUrl }}" class="btn btn-sm btn-outline-primary">
<i class="fa-solid fa-pen"></i>
</a>
</td>
</tr>
{% endfor %}
```
### Кастомные строки
Компонент поддерживает произвольное содержимое ячеек через параметр `rows`:
```twig
{% set rows = [] %}
{% for product in products %}
{% set rows = rows|merge([{
cells: [
{ content: '<strong>' ~ product.name ~ '</strong>', class: '' },
{ content: product.price ~ ' ₽', class: 'text-end' }
],
actions: '<a href="...">Редактировать</a>'
}]) %}
{% endfor %}
{{ include('@components/table/table.twig', {
id: 'products-table',
rows: rows,
columns: columns,
...
}) }}
```