Иерархическая таблица на базе Vue 3, TypeScript и AG Grid Enterprise (Tree Data).
npm install
npm run devТестирование:
npm test # Unit и компонентные тесты
npm run test:perf # Замеры производительностиsrc/domain/TreeStore.ts- хранилище дерева.src/composables/useTreeGrid.ts- слой реактивности. Выполняет загрузку JSON, формирует пути для дерева и передает данные в компонент.src/components/TreeGrid.vue- настройка и рендеринг AG Grid.public/items.json- данные, имитирующие ответ сервера.tests/- тесты хранилища, компонентов и производительности.
Требование ТЗ о "минимальном количестве обходов массива" напрямую влияет на выбор структур данных. Если использовать обычные массивы, каждая операция поиска, получения детей или родителей будет требовать перебора всех элементов (сложность O(N)).
Для обеспечения O(1) при чтении в TreeStore при инициализации (setItems) строятся индексы за один проход по массиву. Используются четыре Map:
byId- для мгновенного поиска элемента.parentById- для построения цепочки родителей.childrenByParentId- вложенныеMapдля хранения детей. Сохраняют insertion order, что соответствует порядку в исходном массиве.indexById- для точечного обновления элемента в исходном массиве без повторного поиска.
Мутации (addItem, removeItem, updateItem) обновляют индексы инкрементально, не пересчитывая структуру с нуля.
AG Grid требует от строки массив путей (path) от корня до узла. Метод getAllParents за счет parentById строит этот путь за O(depth), избегая рекурсивного перебора всего дерева.
- Колонка дерева: Текст "Группа/Элемент" и иконки разворачивания выводятся в колонке "Категория" через
innerRendererвautoGroupColumnDef. - Нумерация: Колонка "№ п/п" использует
params.node.rowIndex + 1. Это обеспечивает динамическую нумерацию видимых строк: при сворачивании групп номера пересчитываются, не оставляя пустот. - Загрузка данных: Состояние загрузки управляется через проп
:loading="loading". Дерево разворачивается автоматически при поступлении данных благодаря:group-default-expanded="-1".
Тесты (tests/performance.spec.ts) генерируют дерево из 50 000 элементов и замеряют время операций.
Метрики (Node.js 20):
- Построение индексов (
setItems): ~23 мс - 2000 операций чтения: ~1.1 мс
Лимиты в тестах (100 мс на запись, 20 мс на чтение) заданы с запасом на слабое железо. При этом они отсекают любые попытки заменить Map на линейный поиск - деградация до O(N) мгновенно превысит эти пороги на 50 000 элементах.
- Порядок детей: Соответствует порядку в исходном массиве.
getAllChildren: Возвращает узлы в порядке DFS (pre-order), не включая сам родительский элемент.getAllParents: Возвращает цепочку от текущего элемента до корня (включая сам элемент).- Отсутствие ID:
getItemвозвращаетundefined, методы получения списков -[], мутации игнорируются (no-op). - Отсутствие
label: В качестве наименования выводитсяString(id). - Смена родителя: Элемент перемещается в конец списка детей нового родителя. Встроена защита от создания циклов (попытка сделать элемент потомком самого себя игнорируется).