При разработке сложных отчетов, таких как Табель учета рабочего времени или шахматка продаж, программисты 1С часто сталкиваются с задачей, когда заранее неизвестно не только количество строк (список сотрудников), но и количество столбцов (произвольный период дат). Стандартный вывод областей по порядку сверху вниз здесь не подходит, так как структура таблицы должна расти в двух направлениях одновременно.
В этой статье мы подробно разберем, как правильно реализовать алгоритм формирования такого документа, избежав типичных ошибок с потерей параметров в ячейках и обеспечив высокую производительность формирования отчета.
Для решения задачи нам необходимо использовать комбинацию двух ключевых методов объекта ТабличныйДокумент: Вывести() и Присоединить(). Метод Вывести() добавляет область вниз (создает новую строку), а Присоединить() добавляет область справа к уже выведенной строке.
Рассмотрим пошагово логику, которую необходимо реализовать в коде:
Вывести().Присоединить().Посмотрим на пример реализации такого кода:
// Создаем результирующий документ и получаем макет
ТабДок = Новый ТабличныйДокумент;
Макет = ПолучитьМакет("МакетТабеля");
// Получаем области
ОбластьСтрокаЛево = Макет.ПолучитьОбласть("Строка|ФиксированныеКолонки");
ОбластьКолонкаДень = Макет.ПолучитьОбласть("Строка|КолонкаДня");
Для Каждого ТекущийСотрудник Из СписокСотрудников Цикл
// Заполняем ФИО в левой части строки
ОбластьСтрокаЛево.Параметры.Сотрудник = ТекущийСотрудник;
ТабДок.Вывести(ОбластьСтрокаЛево);
// Теперь добавляем колонки дней справа
Для День = 1 По КоличествоДнейВПериоде Цикл
// Заполняем данные конкретного дня
ОбластьКолонкаДень.Параметры.ЗначениеЯчейки = ПолучитьДанныеЗаДень(ТекущийСотрудник, День);
// Присоединяем область к текущей строке справа
ТабДок.Присоединить(ОбластьКолонкаДень);
КонецЦикла;
КонецЦикла;
Рассмотрим более продвинутый и надежный способ — использование пересечений горизонтальных и вертикальных секций. Этот метод позволяет избежать путаницы с параметрами, когда одна и та же область используется многократно.
В макете мы определяем горизонтальные секции (например, Строка) и вертикальные (например, День). Чтобы получить область на их пересечении, мы используем оператор вертикальной черты |.
Проанализируем преимущества этого подхода:
Макет.ПолучитьОбласть("Строка|День").Иногда создание сотен именованных областей в макете избыточно. Выясним, как можно заполнять данные напрямую в ТабличныйДокумент, зная координаты ячеек. Это полезно, когда структура документа очень сложная или требует динамического изменения оформления (например, закрашивание выходных).
Для этого используется метод Область(НомерСтроки, НомерКолонки). Обратите внимание, что нумерация начинается с 1.
// Пример прямой записи в ячейку
НомерСтроки = ТабДок.ВысотаТаблицы; // Текущая последняя строка
НомерКолонки = 5; // Например, колонка для 5-го числа
Ячейка = ТабДок.Область(НомерСтроки, НомерКолонки);
Ячейка.Текст = "8"; // Ставим 8 часов
Ячейка.ЦветФона = WebЦвета.СветлоЗеленый;
Важно: Прямая адресация работает медленнее, чем вывод по макету, поэтому используйте её только там, где стандартных областей недостаточно.
Если в вашем табеле 500 сотрудников и 31 день, это дает более 15 000 ячеек. При неправильном подходе формирование отчета может занять минуты. Разберем, как ускорить этот процесс:
Макет.ПолучитьОбласть() внутри циклов тысячи раз. Получите область один раз в переменную перед началом цикла.Область.Параметры.Имя = Значение, используйте метод ЗаполнитьЗначенияСвойств(Область.Параметры, СтруктураДанных). Это работает значительно быстрее на больших объемах.Чтобы табель был удобен для пользователя, необходимо предусмотреть фиксацию колонок и заголовков. Представьте, что пользователь прокручивает табель вправо к 31 числу — он должен продолжать видеть ФИО сотрудника.
Используйте следующие свойства объекта ТабличныйДокумент:
ТабДок.ФиксацияСлева = 2; — это зафиксирует первые две колонки (например, Номер и ФИО).ТабДок.ФиксацияСверху = 3; — зафиксирует шапку с датами.Также не забывайте про Условное оформление. При выводе колонки дня проверьте, не является ли этот день выходным:
Если ЭтоВыходнойДень(ТекущаяДата) Тогда
ОбластьДня.ЦветФона = WebЦвета.Лосось;
Иначе
ОбластьДня.ЦветФона = WebЦвета.Белый;
КонецЕсли;
Часто новички жалуются, что при использовании Присоединить() данные в предыдущих колонках исчезают или перезаписываются. Разберем причину: это происходит, когда вы пытаетесь заполнить параметры в уже выведенной области ТабДок.Параметры вместо того, чтобы заполнять их в объекте области до момента вывода.
Правильный алгоритм всегда такой: Получили область в переменную -> Заполнили параметры в переменной -> Вывели/Присоединили переменную в документ.
Таким образом, комбинируя циклы по строкам и колонкам с методом Присоединить(), вы сможете создавать отчеты любой сложности с динамической структурой.