Как реализовать интерактивное редактирование и пересчет итогов в отчете СКД без переформирования

Программист 1С v8.3 (Управляемые формы) Управленческий учет IT и автоматизация бизнеса
← На главную

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

Объект ТабличныйДокумент в платформе 1С изначально предназначен для отображения и печати плоских или иерархических данных, а не для работы в режиме табличного процессора с автоматическими реактивными формулами. Разберем технические и архитектурные способы реализации этой задачи.

Вариант 1. Быстрый пересчет итогов по дельте через события табличного документа

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

Разберем логику работы по шагам:

  1. Для редактируемых колонок табличного документа устанавливаем свойство ячейки СодержитЗначение в значение Истина и указываем тип значения (например, Число).
  2. В событии элемента формы ПриАктивизацииОбласти сохраняем текущее (старое) значение ячейки в реквизит формы.
  3. В событии ПриИзмененииСодержимогоОбласти получаем новое введенное значение и находим разницу: Дельта = НовоеЗначение - СтароеЗначение.
  4. Пересчитываем значение зависимой ячейки в текущей строке (например, Сумма = Количество * Цена) и дельту для суммы.
  5. Прибавляем вычисленную дельту к ячейкам итогов вышестоящих группировок вверх по иерархии.

Чтобы не выполнять тяжелый поиск строк-родителей в момент редактирования, координаты родительских ячеек связываются заранее при компоновке отчета. Для этого в свойство ячейки Расшифровка (или в структуру параметров расшифровки) помещается массив номеров строк родительских группировок.

Посмотрим на пример клиентского кода обработчиков:


&НаКлиенте
Перем ПредыдущееЗначениеЯчейки;

&НаКлиенте
Процедура ТабличныйДокументПриАктивизацииОбласти(Элемент)
	
	ТекущаяОбласть = Элемент.ТекущаяОбласть;
	Если ТекущаяОбласть.СодержитЗначение Тогда
		ПредыдущееЗначениеЯчейки = ТекущаяОбласть.Значение;
	Иначе
		ПредыдущееЗначениеЯчейки = 0;
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Процедура ТабличныйДокументПриИзмененииСодержимогоОбласти(Элемент, Область)
	
	Если Не Область.СодержитЗначение Тогда
		Возврат;
	КонецЕсли;
	
	НовоеЗначение = Область.Значение;
	Дельта = НовоеЗначение - ПредыдущееЗначениеЯчейки;
	
	Если Дельта = 0 Тогда
		Возврат;
	КонецЕсли;
	
	// Если в расшифровке ячейки хранится структура с массивом строк-родителей
	Если ТипЗнч(Область.Расшифровка) = Тип("Структура") И Область.Расшифровка.Свойство("СтрокиРодителей") Тогда
		
		НомерКолонки = Область.Лево;
		
		Для Каждого НомерСтрокиРодителя Из Область.Расшифровка.СтрокиРодителей Цикл
			ОбластьРодителя = Элемент.Область(НомерСтрокиРодителя, НомерКолонки);
			ОбластьРодителя.Значение = ОбластьРодителя.Значение + Дельта;
			ОбластьРодителя.Текст = Формат(ОбластьРодителя.Значение, "ЧДЦ=2");
		КонецЦикла;
		
	КонецЕсли;
	
	ПредыдущееЗначениеЯчейки = НовоеЗначение;
	
КонецПроцедуры

Такой подход выполняется исключительно на клиенте через обращения к объекту ОбластьЯчеекТабличногоДокумента, не вызывая серверных контекстных вызовов, что обеспечивает мгновенный отклик интерфейса.

Вариант 2. Хранение детальных записей в памяти и фоновая перекомпоновка

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

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

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

Вариант 3. Использование дерева значений на управляемой форме

При проектировании автоматизированных рабочих мест вместо отчета на СКД часто целесообразнее использовать обработку с элементом формы Таблица в режиме отображения Дерево.

Проанализируем преимущества такого подхода:

  1. Реквизит формы с типом ДанныеФормыДерево изначально поддерживает строгую иерархическую структуру.
  2. У каждой строки доступно свойство Строка.Родитель, что позволяет организовывать пересчет итогов циклом подъема к корневому элементу без работы с номерами ячеек и расшифровками:

&НаКлиенте
Процедура ДеревоДанныхКоличествоПриИзменении(Элемент)
	
	СтрокаДерева = Элементы.ДеревоДанных.ТекущиеДанные;
	СтрокаДерева.Сумма = СтрокаДерева.Количество * СтрокаДерева.Цена;
	
	// Рекурсивный или циклический пересчет итогов вверх по дереву
	Родитель = СтрокаДерева.ПолучитьРодителя();
	Пока Родитель <> Неопределено Цикл
		СуммаПоРодителю = 0;
		Для Каждого ПодчиненнаяСтрока Из Родитель.ПолучитьЭлементы() Цикл
			СуммаПоРодителю = СуммаПоРодителю + ПодчиненнаяСтрока.Сумма;
		КонецЦикла;
		
		Родитель.Сумма = СуммаПоРодителю;
		Родитель = Родитель.ПолучитьРодителя();
	КонецЦикла;
	
КонецПроцедуры

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

← На главную