Как в 1С визуально сравнить два дерева значений с подсветкой различий?

Программист 1С v8.3 (Управляемые формы) Управленческий учет Промышленность, строительство и АПК
← На главную

Перед разработчиками 1С часто встает задача сравнить две иерархические структуры данных, например, два состава изделия (спецификации), и наглядно показать пользователю различия. В идеале это должно выглядеть как встроенный в платформу механизм "Сравнение и объединение конфигураций", где можно одновременно разворачивать узлы и видеть, какие элементы были добавлены, изменены или удалены. Рассмотрим, как реализовать подобный функционал, поскольку готового решения в платформе 1С для этого нет.

Проанализируем основные подходы к решению этой задачи, от самых простых до наиболее гибких и функциональных.

Решение 1: Разработка собственной формы для сравнения

Это самый мощный и гибкий способ, который позволяет полностью воссоздать желаемое поведение. Он предполагает создание собственной управляемой формы, на которой будут размещены два элемента типа "Дерево" или "Таблица" (в режиме отображения иерархии), и реализацию логики сравнения и синхронизации.

Разберем по шагам, как это можно сделать.

  1. Подготовка данных и алгоритм сравнения.

    Ключевая задача — рекурсивно обойти оба дерева и построить объединенную структуру, в которой будет отмечен статус каждого элемента: "Не изменился", "Добавлен", "Удален" или "Изменен".

    • Сначала необходимо определить ключевые колонки, по которым будут сопоставляться строки в деревьях. Например, для состава изделия это может быть "Номенклатура" и "Характеристика".
    • Создайте результирующее дерево значений, которое будет содержать все колонки из исходных деревьев плюс дополнительную колонку, например, СтатусСравнения.
    • Напишите рекурсивную процедуру, которая будет принимать на вход две коллекции строк (узлы из первого и второго дерева).
    • Внутри процедуры сопоставьте строки из двух коллекций по ключевым полям. Проще всего сначала загрузить строки из каждой коллекции в соответствия для быстрого поиска.
    • Обойдите строки первого дерева. Для каждой строки ищите соответствующую во втором.
      • Если строка найдена: сравните значения в остальных колонках. Если они отличаются, добавьте в результирующее дерево строку со статусом "Изменен". Если совпадают — со статусом "Не изменился".
      • Если строка не найдена: добавьте в результат строку из первого дерева со статусом "Удален".
    • Обойдите строки второго дерева, чтобы найти те, которых не было в первом. Добавьте их в результат со статусом "Добавлен".
    • Для всех сопоставленных строк рекурсивно вызовите эту же процедуру для их дочерних коллекций строк.
  2. Визуализация на форме.

    После того как объединенное дерево готово, его можно отобразить на форме. Но для создания эффекта "бок о бок" нужно два элемента управления.

    • Разместите на форме два элемента типа "Таблица" (отображающие деревья).
    • Вместо сложного объединения можно пойти другим путем: оставить два исходных дерева, но раскрасить их. Для этого нужно обойти оба дерева и для каждой строки программно установить цвет фона или текста в зависимости от результата сравнения.
    • Синхронизация навигации. Это самая важная часть для удобства пользователя.
      • Создайте обработчик события ПриАктивизацииСтроки для первого дерева. В этом обработчике получите уникальный идентификатор активной строки (например, значение из ключевой колонки).
      • Выполните поиск строки с таким же идентификатором во втором дереве.
      • Если строка найдена, программно установите ее как текущую: Элементы.ВтороеДерево.ТекущаяСтрока = НайденныйИдентификаторСтроки;
      • Аналогичный обработчик создайте для второго дерева, чтобы навигация работала в обе стороны.
      • Таким же образом синхронизируйте события разворачивания и сворачивания узлов (ПередРазворачиванием, ПередСворачиванием), чтобы при раскрытии ветки в одном дереве она автоматически раскрывалась и во втором.

Преимущества: полный контроль над внешним видом и поведением, максимальное удобство для пользователя.
Недостатки: высокая трудоемкость реализации.

Решение 2: Использование системы компоновки данных (СКД)

Этот метод отлично подходит для быстрого получения отчета о различиях без сложной интерактивности. Идея заключается в использовании мощного механизма запросов для сравнения данных.

  1. Выгрузите оба дерева значений во временные таблицы. Это можно сделать через менеджер временных таблиц.
  2. Создайте запрос, в котором эти две временные таблицы соединяются через ПОЛНОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ (FULL OUTER JOIN) по ключевым полям.
  3. В секции ВЫБРАТЬ запроса используйте конструкцию ВЫБОР ... КОГДА ... для определения статуса каждой строки:
    
    ВЫБРАТЬ
        ВЫБОР
            КОГДА Таблица1.Ключ ЕСТЬ NULL ТОГДА "Добавлен"
            КОГДА Таблица2.Ключ ЕСТЬ NULL ТОГДА "Удален"
            КОГДА Таблица1.Значение <> Таблица2.Значение ТОГДА "Изменен"
            ИНАЧЕ "Не изменился"
        КОНЕЦ КАК Статус,
        ЕСТЬNULL(Таблица1.Ключ, Таблица2.Ключ) КАК Ключ,
        Таблица1.Значение КАК Значение1,
        Таблица2.Значение КАК Значение2,
        ЕСТЬNULL(Таблица1.Родитель, Таблица2.Родитель) КАК Родитель
    ИЗ
        ВТ_Дерево1 КАК Таблица1
            ПОЛНОЕ СОЕДИНЕНИЕ ВТ_Дерево2 КАК Таблица2
            ПО Таблица1.Ключ = Таблица2.Ключ
    
  4. Используйте этот запрос как источник данных для отчета на СКД.
  5. В настройках СКД настройте иерархию, используя поле "Родитель".
  6. Используйте условное оформление в настройках отчета, чтобы раскрашивать строки в зависимости от значения поля "Статус".

Преимущества: быстрота реализации, не требует сложного программирования, использует стандартный мощный механизм.
Недостатки: результат представляет собой отчет, а не интерактивный инструмент с синхронной навигацией.

Решение 3: Сравнение через текстовые файлы и внешние утилиты

Этот способ подходит для быстрой проверки различий разработчиком, но не для конечного пользователя.

  1. Сериализуйте каждое дерево значений в текстовый формат, например, в XML или JSON. Для быстрой, хотя и не самой читаемой сериализации можно использовать функцию ЗначениеВСтрокуВнутр().
  2. Сохраните полученные строки в два текстовых файла.
  3. Откройте эти файлы в любой программе для сравнения текста (diff tool), например, KDiff3, WinMerge, Araxis Merge или встроенный инструмент в VS Code.

Преимущества: очень просто и быстро в реализации.
Недостатки: требует внешнего ПО, неудобно для пользователя, результат не интегрирован в интерфейс 1С.

Решение 4: Использование объекта СравнениеФайлов (Толстый клиент)

Платформа предоставляет механизм для сравнения файлов, который можно приспособить для нашей задачи, но с существенными ограничениями.

  1. Создайте два объекта ТабличныйДокумент.
  2. Рекурсивно обойдите первое дерево и выведите его содержимое в первый табличный документ, сохраняя иерархию с помощью группировок (методы НачатьГруппуСтрок, ЗакончитьГруппуСтрок).
  3. Повторите операцию для второго дерева и второго табличного документа.
  4. Сохраните оба табличных документа во временные файлы с расширением .mxl.
  5. Вызовите метод СравнениеФайлов.ПоказатьРазличия(ПутьКФайлу1, ПутьКФайлу2).

Преимущества: использует стандартный, узнаваемый пользователями интерфейс сравнения.
Недостатки: работает только в толстом клиенте, не обеспечивает интерактивного разворачивания узлов, требует предварительной генерации файлов.

Итог: для создания действительно удобного и функционального инструмента, отвечающего исходному запросу, наиболее подходящим является первый метод — разработка собственной формы. Если же требуется быстро получить отчет о расхождениях, то оптимальным выбором будет второй метод с использованием СКД.

← На главную