Перейти к содержанию

Группировка связанных операций

Архитектура

Связь между операциями

  • related_operation_id — поле дочерней (зеркальной) операции, ссылающееся на ID родительской
  • Пример: покупка SBER (parent) → продажа RUB (child, related_operation_id = parent.id)
  • У родительской операции related_operation_id = null
  • ВАЖНО: операция может быть child (покупка облигации при продаже валюты), но при этом являться "основной" на странице актива

Backend (реализовано)

В OperationController::index() (cryptodiary/app/Http/Controllers/OperationController.php):

  • При showRelatedOperations=false: в основной запрос добавляется whereNull('operations.related_operation_id') — скрываются дочерние операции
  • При showRelatedOperations=true: фильтр по related_operation_id НЕ применяется — в результат попадают все операции (и parent, и child)
  • Дочерние операции (relatedChildOperations) загружаются через constrained eager loading с полным набором scope-ов + фильтром distribution_id (если showSubsales=false)
  • Родительская операция (relatedParentOperation) также загружается с computed-полями — для показа контекста child-операций
  • $eagerScopes — замыкание с общим набором scope-ов для переиспользования в обоих eager load

Frontend (реализовано)

Store (src/stores/operations.jsupdateTable):

  1. mapOperationRow(row) — вынесенная функция маппинга для переиспользования
  2. При showRelatedOperations=true выполняется группировка:
    • allIds — Set всех ID в текущем результате
    • childrenToNest — Set ID child-операций, чей parent тоже в результате (они пропускаются как отдельные строки)
    • Для каждой не-пропущенной операции собираются sub-rows из трёх источников: a. resultChildren — операции из результата, ссылающиеся через related_operation_id b. eagerChildren — eager-loaded related_child_operations, которых нет в основном результате c. parentAsContext — eager-loaded related_parent_operation (когда текущая строка — child, а её parent не в результате)
    • Если есть sub-rows → строка помечается isParentOperation: true, sub-rows помечаются relatedParentId
  3. При showRelatedOperations=false — простой маппинг без группировки

Компонент (src/components/OperationsTable.vue):

  • <Table> получает groupable-пропсы при showRelatedOperations=true:
    • :groupable="operationsStore.filter.showRelatedOperations"
    • group-field="relatedParentId" — поле в sub-row, указывающее на главную строку
    • parent-field="isParentOperation" — булево поле, отмечающее строки-родители
    • parent-key-field="id" — поле в главной строке для связи с sub-rows

Таблица (src/components/ui/Table.vue):

  • Встроенный механизм groupable обеспечивает expand/collapse, indent и стилизацию parent/child

Ключевые файлы

  • src/stores/operations.js — store, фильтр, getOperations, updateTable (маппинг + группировка)
  • src/components/OperationsTable.vue — UI таблицы, передача groupable-пропсов
  • src/components/ui/Table.vue — универсальная таблица с groupable-механизмом
  • cryptodiary/app/Http/Controllers/OperationController.php — бэкенд, фильтрация + eager loading
  • cryptodiary/app/Models/Operation.php — модель, связи relatedChildOperations() / relatedParentOperation()