(29) На этот раз полностью доделал отчет. Тестовую базу с отчетом прикрепил.
Логисты в макете у меня объединяются следующим кодом:
// Выводим заголовки логистов в строке 4
Для Каждого ЛогистСсылка Из МассивЛогистов Цикл
МассивВодителейЛогиста = СоответствиеДанных[ЛогистСсылка];
КоличествоВодителей = МассивВодителейЛогиста.Количество();
// Создаем ячейку для логиста программно в строке 4
ТабДок.Область(4, НомерКолонки).Текст = СоответствиеЛогистов[ЛогистСсылка];
// Форматирование: жирный шрифт и выравнивание по центру
ТабДок.Область(4, НомерКолонки).Шрифт = Новый Шрифт(ТабДок.Область(4, НомерКолонки).Шрифт,,,Истина); // Жирный шрифт
ТабДок.Область(4, НомерКолонки).ГоризонтальноеПоложение = ГоризонтальноеПоложение.Центр;
ТабДок.Область(4, НомерКолонки).ШиринаКолонки = 20;
// Линия вокруг
ТабДок.Область(4, НомерКолонки).ГраницаСверху = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная,1);
ТабДок.Область(4, НомерКолонки).ГраницаСлева = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная,1);
ТабДок.Область(4, НомерКолонки).ГраницаСправа = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная,1);
// Размещение текста
ТабДок.Область(4, НомерКолонки).РазмещениеТекста = ТипРазмещенияТекстаТабличногоДокумента.Переносить;
// Устанавливаем цвет фона заголовка логиста (желтый)
ТабДок.Область(4, НомерКолонки).ЦветФона = WebЦвета.Золотой;
// Запоминаем начальную позицию для объединения
НачальнаяКолонка = НомерКолонки;
// Выводим пустые ячейки для остальных водителей
Для Инд = 2 По КоличествоВодителей Цикл
ТабДок.Область(4, НомерКолонки + Инд - 1).Текст = "";
// Устанавливаем цвет фона для всех ячеек логиста
ТабДок.Область(4, НомерКолонки + Инд - 1).ЦветФона = WebЦвета.Золотой;
КонецЦикла;
// Объединяем ячейки логиста над всеми его водителями
Если КоличествоВодителей > 1 Тогда
КонечнаяКолонка = НачальнаяКолонка + КоличествоВодителей - 1;
ТабДок.Область(4, НачальнаяКолонка, 4, КонечнаяКолонка).Объединить();
ТабДок.Область(4, КонечнаяКолонка).ГраницаСправа = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная,1);
КонецЕсли;
// Увеличиваем номер колонки для следующего логиста
НомерКолонки = НомерКолонки + КоличествоВодителей;
КонецЦикла;
Показать
А группировка у меня происходит благодаря использованию конструкции ИТОГИ ПО в языке запросов. Далее я обхожу результат запроса по группировкам и создаю соответствие логистов и массива их водителей (это СоответствиеДанных). Эти данные я далее использую при выводе в табличный документ:
// Получаем выборку по логистам
ВыборкаЛогисты = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Логист");
// Создаем соответствия для хранения данных
СоответствиеЛогистов = Новый Соответствие;
СоответствиеВодителей = Новый Соответствие;
СоответствиеДанных = Новый Соответствие;
// Заполняем структуру данными
Пока ВыборкаЛогисты.Следующий() Цикл
ЛогистСсылка = ВыборкаЛогисты.Логист;
ЛогистНаименование = ВыборкаЛогисты.ЛогистНаименование;
// Сохраняем информацию о логисте
СоответствиеЛогистов.Вставить(ЛогистСсылка, ЛогистНаименование);
// Получаем водителей для текущего логиста
ВыборкаВодители = ВыборкаЛогисты.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Водитель");
МассивВодителей = Новый Массив;
// Собираем данные о водителях
Пока ВыборкаВодители.Следующий() Цикл
ВодительСсылка = ВыборкаВодители.Водитель;
МассивВодителей.Добавить(ВодительСсылка);
// Сохраняем имя водителя
СоответствиеВодителей.Вставить(ВодительСсылка, ВыборкаВодители.ВодительНаименование);
// Получаем детальные данные для водителя
ВыборкаДетали = ВыборкаВодители.Выбрать();
Если ВыборкаДетали.Следующий() Тогда
// Создаем структуру для хранения показателей водителя
ДанныеВодителя = Новый Структура;
ДанныеВодителя.Вставить("ГосНомер", ВыборкаДетали.ГосНомер);
ДанныеВодителя.Вставить("ЦветКузова", ВыборкаДетали.ЦветКузова);
ДанныеВодителя.Вставить("Модель", ВыборкаДетали.Модель);
ДанныеВодителя.Вставить("ГодВыпуска", ВыборкаДетали.ГодВыпуска);
ДанныеВодителя.Вставить("КоличествоРейсов", ВыборкаДетали.КоличествоРейсов);
ДанныеВодителя.Вставить("ПройденноеРасстояние", ВыборкаДетали.ПройденноеРасстояние);
ДанныеВодителя.Вставить("СуммаВыручки", ВыборкаДетали.СуммаВыручки);
ДанныеВодителя.Вставить("РасходТоплива", ВыборкаДетали.РасходТоплива);
ДанныеВодителя.Вставить("ВремяВПути", ВыборкаДетали.ВремяВПути);
// Сохраняем данные водителя
СоответствиеДанных.Вставить(ВодительСсылка, ДанныеВодителя);
КонецЕсли;
КонецЦикла;
// Сохраняем список водителей для логиста
СоответствиеДанных.Вставить(ЛогистСсылка, МассивВодителей);
КонецЦикла;
// Получаем список всех логистов
МассивЛогистов = Новый Массив;
Для Каждого КлючИЗначение Из СоответствиеЛогистов Цикл
МассивЛогистов.Добавить(КлючИЗначение.Ключ);
КонецЦикла;
Суть в чем: Есть таблица водители, к ним прикреплены логисты. Необходимо чтобы была группировка по логистам вертикально. Под каждым логистом свои водители
(11) То есть нужно чтобы результат был точно как на картинке? Уж больно на СКД похожа картинка. Так что я предположил, что это картинка существующего у вас отчета на СКД, но вам нужно что-то другое.
(19) Да, это не то. А почему на СКД отчет? Интересуюсь из любопытства. ИМХО, СКД нужна, когда пользователь может захотеть что-то переделать в отчете. Отборы какие-то свои добавить. Если же ему четко нужен отчет как на картинке, то овчинка выделки не стоит. Чтобы выяснить какой-нибудь простой вопрос по созданию отчета на СКД нужно спрашивать на форуме. И так постоянно. Слишком много в СКД возможностей, слишком много переключателей, которые ты никогда не запомнишь и не выучишь. Выучишь если ты занимаешься ТОЛЬКО написанием отчетов на СКД, причем постоянно.
Хорошо. Если я не прав, то пусть фанаты СКД меня посрамят. Придут и расскажут как добиться нужного автору результата.
(20) Вы программист? Это мнение программиста. Я тоже программист и с этим мнением согласен.
Но есть и другое мнение. У меня есть знакомый - ученый-физик. Он постоянно выступает с докладами на всяких их физических конференциях. У него есть целый набор всяких программ для построения отчетов, диаграм, немыслимых математических вычислений.
Каждая из них больше, мощнее, сложнее на два порядка, чем СКД. Как по количеству галочек, так и по своим возможностям. Но вот умеет ведь ими пользоваться. А для него это всего лишь вспомогательный рабочий инструмент к основному виду деятельности (физике).
Каждому своё.
Я не фанат СКД и написал всё это не для того, чтобы кого-то посрамить. Просто описал ситуацию, которую видел сам. Дальше тут писать про это не имеет смысла, т.к. топик про другое совсем. Не будем флудить.
Тут больше вопрос к топикстартеру. А вот почему именно нужен такой длиииииинный отчет по-горизонтали и прям вот в таком виде?
Я понимаю, что может быть:
1. кто-то сказал "так надо и точка!" (бывает...)
2. захотелось поупражняться в создании нетрадиционных отчетов (похвально)
Ведь можно упростить... Зачем пытаться из палок и глины строить современный истребитель? Ну не может СКД этого с полпинка и не надо себя мучать.
Смысл финансовых отчетов - донести до их потребителя полезную информацию, а не в красотульках и навороченности.
Я не критикую и не пытаюсь тут умничать. Мне правда интересно: а зачем?
Пытаюсь сделать такой отчет. Правда, по преподавателям и ученикам вместо водителей и логистов. Но смысл тот же. Если времени хватит, то сюда выложу.
Ясно. Сочувствую. Не буду развивать мысль на темы: "а что это руководство будет делать с таким отчетом?" и "почему бы руководству нормальные отчет(ы) не захотеть?". Захотело - значит захотело. У меня руководства нет, мне проще)
(30) Создал тестовую базу, заполнил данными, создал отчет "Данные по логистам и водителям", но не довел до ума. Все сделал с помощью ИИ claude-3.7-sonnet. До создания макета уже не хватило времени. Код процедуры ПриКомпоновкеРезультата (уже вставлен в отчет):
// Модуль объекта отчета "ОтчетПоЛогистамИВодителям"
// Процедура формирования отчета
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// Отключаем стандартную обработку СКД
СтандартнаяОбработка = Ложь;
// Получаем параметры отчета из настроек компоновщика
КомпоновщикНастроек.ЗагрузитьНастройки(КомпоновщикНастроек.ПолучитьНастройки());
Параметры = КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы;
// Получаем параметр периода
ПериодПараметр = Параметры.Найти("Период");
Если ПериодПараметр <> Неопределено Тогда
Период = ПериодПараметр.Значение;
НачалоПериода = Период.ДатаНачала;
КонецПериода = Период.ДатаОкончания;
Иначе
НачалоПериода = ДобавитьМесяц(НачалоМесяца(ТекущаяДата()), -12);
КонецПериода = КонецМесяца(ТекущаяДата());
КонецЕсли;
// Получаем параметр отбора по логисту
ОтборЛогист = Неопределено;
ЛогистПараметр = Параметры.Найти("Логист");
Если ЛогистПараметр <> Неопределено И ЗначениеЗаполнено(ЛогистПараметр.Значение) Тогда
ОтборЛогист = ЛогистПараметр.Значение;
КонецЕсли;
// Формируем табличный документ
ТабДок = СформироватьОтчет(НачалоПериода, КонецПериода, ОтборЛогист);
// Передаем табличный документ для вывода
ДокументРезультат.Очистить();
ДокументРезультат.Вывести(ТабДок);
КонецПроцедуры
// Функция формирования отчета
Функция СформироватьОтчет(НачалоПериода, КонецПериода, ОтборЛогист = Неопределено)
// Создаем табличный документ
ТабДок = Новый ТабличныйДокумент;
// Устанавливаем параметры печати ДО установки ключа параметров печати
ТабДок.ОриентацияСтраницы = ОриентацияСтраницы.Ландшафт;
ТабДок.АвтоМасштаб = Истина;
ТабДок.ТолькоПросмотр = Истина;
ТабДок.ОтображатьСетку = Ложь;
ТабДок.ОтображатьЗаголовки = Ложь;
// Теперь устанавливаем ключ параметров печати
ТабДок.КлючПараметровПечати = "ПАРАМЕТРЫ_ПЕЧАТИ_ОтчетПоЛогистамИВодителям";
// Получаем макет отчета
Макет = ПолучитьМакет("Макет");
// Получаем области макета
ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
ОбластьЛогист = Макет.ПолучитьОбласть("Логист");
ОбластьВодитель = Макет.ПолучитьОбласть("Водитель");
ОбластьПоказатели = Макет.ПолучитьОбласть("Показатели");
ОбластьИтогоПоЛогисту = Макет.ПолучитьОбласть("ИтогоПоЛогисту");
ОбластьИтого = Макет.ПолучитьОбласть("Итого");
// Заполняем заголовок
ОбластьЗаголовок.Параметры.НачалоПериода = Формат(НачалоПериода, "ДЛФ=DD");
ОбластьЗаголовок.Параметры.КонецПериода = Формат(КонецПериода, "ДЛФ=DD");
// Добавляем информацию об отборе по логисту в заголовок
Если ЗначениеЗаполнено(ОтборЛогист) Тогда
ОбластьЗаголовок.Параметры.ОтборЛогист = "Логист: " + ОтборЛогист;
Иначе
ОбластьЗаголовок.Параметры.ОтборЛогист = "";
КонецЕсли;
ТабДок.Вывести(ОбластьЗаголовок);
// Запрос для получения данных о логистах и их водителях
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("НачалоПериода", НачалоПериода);
Запрос.УстановитьПараметр("КонецПериода", КонецПериода);
// Формируем текст запроса с учетом отбора по логисту
ТекстЗапроса =
"ВЫБРАТЬ
| РегистрНакопления.ПоказателиРейсов.Логист КАК Логист,
| РегистрНакопления.ПоказателиРейсов.Логист.Наименование КАК ЛогистНаименование,
| РегистрНакопления.ПоказателиРейсов.Водитель КАК Водитель,
| РегистрНакопления.ПоказателиРейсов.Водитель.Наименование КАК ВодительНаименование,
| РегистрНакопления.ПоказателиРейсов.ТранспортноеСредство КАК ТранспортноеСредство,
| РегистрНакопления.ПоказателиРейсов.ТранспортноеСредство.Наименование КАК ТСНаименование,
| РегистрНакопления.ПоказателиРейсов.ТранспортноеСредство.ЦветКузова КАК ЦветКузова,
| СУММА(РегистрНакопления.ПоказателиРейсов.КоличествоРейсов) КАК КоличествоРейсов,
| СУММА(РегистрНакопления.ПоказателиРейсов.ПройденноеРасстояние) КАК ПройденноеРасстояние,
| СУММА(РегистрНакопления.ПоказателиРейсов.СуммаВыручки) КАК СуммаВыручки,
| СУММА(РегистрНакопления.ПоказателиРейсов.РасходТоплива) КАК РасходТоплива
|ИЗ
| РегистрНакопления.ПоказателиРейсов КАК РегистрНакопления.ПоказателиРейсов
|ГДЕ
| РегистрНакопления.ПоказателиРейсов.Период МЕЖДУ &НачалоПериода И &КонецПериода";
// Добавляем условие отбора по логисту, если он указан
Если ЗначениеЗаполнено(ОтборЛогист) Тогда
Запрос.УстановитьПараметр("ОтборЛогист", ОтборЛогист);
ТекстЗапроса = ТекстЗапроса + "
| И РегистрНакопления.ПоказателиРейсов.Логист = &ОтборЛогист";
КонецЕсли;
// Добавляем группировки и итоги
ТекстЗапроса = ТекстЗапроса + "
|
|СГРУППИРОВАТЬ ПО
| РегистрНакопления.ПоказателиРейсов.Логист,
| РегистрНакопления.ПоказателиРейсов.Логист.Наименование,
| РегистрНакопления.ПоказателиРейсов.Водитель,
| РегистрНакопления.ПоказателиРейсов.Водитель.Наименование,
| РегистрНакопления.ПоказателиРейсов.ТранспортноеСредство,
| РегистрНакопления.ПоказателиРейсов.ТранспортноеСредство.Наименование,
| РегистрНакопления.ПоказателиРейсов.ТранспортноеСредство.ЦветКузова
|
|ИТОГИ ПО
| Логист,
| Водитель";
Запрос.Текст = ТекстЗапроса;
РезультатЗапроса = Запрос.Выполнить();
// Проверяем, есть ли данные в результате запроса
Если РезультатЗапроса.Пустой() Тогда
// Если данных нет, выводим сообщение
ОбластьПустойРезультат = Макет.ПолучитьОбласть("ПустойРезультат");
ТабДок.Вывести(ОбластьПустойРезультат);
Возврат ТабДок;
КонецЕсли;
// Цвета для выделения логистов
ЦветаЛогистов = Новый Массив;
ЦветаЛогистов.Добавить(WebЦвета.LightYellow);
ЦветаЛогистов.Добавить(WebЦвета.LightGreen);
ЦветаЛогистов.Добавить(WebЦвета.LightPink);
ЦветаЛогистов.Добавить(WebЦвета.LightBlue);
ЦветаЛогистов.Добавить(WebЦвета.LightCyan);
// Определяем количество логистов для расчета ширины секций
ВыборкаЛогистовКол = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Логист");
КоличествоЛогистов = 0;
Пока ВыборкаЛогистовКол.Следующий() Цикл
КоличествоЛогистов = КоличествоЛогистов + 1;
КонецЦикла;
// Создаем таблицу с горизонтальными секциями
// Первая строка - заголовки секций (логисты)
СтрокаЛогистов = ТабДок.ПолучитьОбласть(1, 1, 1, 1).СкопироватьОбласть();
ИндексЦвета = 0;
// Обходим результат запроса по логистам
ВыборкаЛогист = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Логист");
// Создаем горизонтальные секции для каждого логиста
Пока ВыборкаЛогист.Следующий() Цикл
ИндексЦвета = ?(ИндексЦвета >= ЦветаЛогистов.Количество() - 1, 0, ИндексЦвета + 1);
ТекущийЦвет = ЦветаЛогистов[ИндексЦвета];
// Создаем секцию для логиста
ОбластьЛогист.Параметры.Логист = ВыборкаЛогист.ЛогистНаименование;
// Если это первый логист, выводим область
Если ВыборкаЛогист.Номер() = 1 Тогда
НачалоОбласти = ТабДок.НачалоОбласти();
ТабДок.Вывести(ОбластьЛогист);
КонецОбласти = ТабДок.КонецОбласти();
Иначе
// Иначе присоединяем горизонтально
НачалоОбласти = ТабДок.НачалоОбласти();
ТабДок.Присоединить(ОбластьЛогист);
КонецОбласти = ТабДок.КонецОбласти();
КонецЕсли;
// Устанавливаем цвет фона для строки логиста
ТабДок.УстановитьОбластьФона(НачалоОбласти, КонецОбласти, ТекущийЦвет);
// Получаем водителей для текущего логиста
ВыборкаВодитель = ВыборкаЛогист.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Водитель");
// Определяем максимальное количество водителей для вертикального размера секции
МаксСтрок = ВыборкаВодитель.Количество();
// Сбрасываем выборку и обходим заново
ВыборкаВодитель = ВыборкаЛогист.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Водитель");
// Выводим заголовки для водителей
ОбластьВодитель.Параметры.Водитель = "Водитель-ФИО";
ОбластьВодитель.Параметры.ТС = "НомерТС";
ОбластьВодитель.Параметры.ЦветКузова = "Цвет";
// Если это первый логист, выводим область
Если ВыборкаЛогист.Номер() = 1 Тогда
НачалоОбласти = ТабДок.НачалоОбласти();
ТабДок.Вывести(ОбластьВодитель);
КонецОбласти = ТабДок.КонецОбласти();
Иначе
// Иначе присоединяем горизонтально
НачалоОбласти = ТабДок.НачалоОбласти();
ТабДок.Присоединить(ОбластьВодитель);
КонецОбласти = ТабДок.КонецОбласти();
КонецЕсли;
// Устанавливаем цвет фона для заголовка водителей
ТабДок.УстановитьОбластьФона(НачалоОбласти, КонецОбласти, ТекущийЦвет);
// Выводим данные по водителям
ТекНомерСтроки = 0;
Пока ВыборкаВодитель.Следующий() Цикл
ТекНомерСтроки = ТекНомерСтроки + 1;
// Получаем детальные данные для водителя
ВыборкаДетали = ВыборкаВодитель.Выбрать();
// Если есть данные, заполняем параметры
Если ВыборкаДетали.Следующий() Тогда
ОбластьВодитель.Параметры.Водитель = ВыборкаВодитель.ВодительНаименование;
ОбластьВодитель.Параметры.ТС = ВыборкаДетали.ТСНаименование;
ОбластьВодитель.Параметры.ЦветКузова = ВыборкаДетали.ЦветКузова;
// Если это первая строка для водителя и первый логист
Если ТекНомерСтроки = 1 И ВыборкаЛогист.Номер() = 1 Тогда
ТабДок.Вывести(ОбластьВодитель);
ИначеЕсли ТекНомерСтроки = 1 Тогда
// Если это первая строка для водителя, но не первый логист
ТабДок.Присоединить(ОбластьВодитель);
ИначеЕсли ВыборкаЛогист.Номер() = 1 Тогда
// Если это не первая строка для водителя, но первый логист
ТабДок.ВывестиГоризонтальныйРазделительСтрок();
ТабДок.Вывести(ОбластьВодитель);
Иначе
// Если это не первая строка для водителя и не первый логист
// Присоединяем по горизонтали к последней строке
ТабДок.Присоединить(ОбластьВодитель);
КонецЕсли;
// Выводим показатели для водителя
ОбластьПоказатели.Параметры.КоличествоРейсов = ВыборкаДетали.КоличествоРейсов;
ОбластьПоказатели.Параметры.ПройденноеРасстояние = ВыборкаДетали.ПройденноеРасстояние;
ОбластьПоказатели.Параметры.СуммаВыручки = ВыборкаДетали.СуммаВыручки;
ОбластьПоказатели.Параметры.РасходТоплива = ВыборкаДетали.РасходТоплива;
// Выводим показатели под строкой водителя
Если ТекНомерСтроки = 1 И ВыборкаЛогист.Номер() = 1 Тогда
ТабДок.Вывести(ОбластьПоказатели);
ИначеЕсли ТекНомерСтроки = 1 Тогда
ТабДок.Присоединить(ОбластьПоказатели);
ИначеЕсли ВыборкаЛогист.Номер() = 1 Тогда
ТабДок.ВывестиГоризонтальныйРазделительСтрок();
ТабДок.Вывести(ОбластьПоказатели);
Иначе
ТабДок.Присоединить(ОбластьПоказатели);
КонецЕсли;
КонецЕсли;
КонецЦикла;
// Выводим итоги по логисту
ОбластьИтогоПоЛогисту.Параметры.ИтогоКоличествоРейсов = ВыборкаЛогист.КоличествоРейсов;
ОбластьИтогоПоЛогисту.Параметры.ИтогоПройденноеРасстояние = ВыборкаЛогист.ПройденноеРасстояние;
ОбластьИтогоПоЛогисту.Параметры.ИтогоСуммаВыручки = ВыборкаЛогист.СуммаВыручки;
ОбластьИтогоПоЛогисту.Параметры.ИтогоРасходТоплива = ВыборкаЛогист.РасходТоплива;
// Выводим итоги под водителями
Если ВыборкаЛогист.Номер() = 1 Тогда
ТабДок.ВывестиГоризонтальныйРазделительСтрок();
НачалоОбласти = ТабДок.НачалоОбласти();
ТабДок.Вывести(ОбластьИтогоПоЛогисту);
КонецОбласти = ТабДок.КонецОбласти();
Иначе
НачалоОбласти = ТабДок.НачалоОбласти();
ТабДок.Присоединить(ОбластьИтогоПоЛогисту);
КонецОбласти = ТабДок.КонецОбласти();
КонецЕсли;
// Устанавливаем цвет фона для итогов
ТабДок.УстановитьОбластьФона(НачалоОбласти, КонецОбласти, ТекущийЦвет);
КонецЦикла;
// Выводим общие итоги в нижней части отчета
ТабДок.ВывестиГоризонтальныйРазделительСтрок();
// Получаем общие итоги из корневой выборки запроса
ВыборкаИтоги = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Если ВыборкаИтоги.Следующий() Тогда
ОбщееКоличествоРейсов = ВыборкаИтоги.КоличествоРейсов;
ОбщееПройденноеРасстояние = ВыборкаИтоги.ПройденноеРасстояние;
ОбщаяСуммаВыручки = ВыборкаИтоги.СуммаВыручки;
ОбщийРасходТоплива = ВыборкаИтоги.РасходТоплива;
ОбластьИтого.Параметры.ОбщееКоличествоРейсов = ОбщееКоличествоРейсов;
ОбластьИтого.Параметры.ОбщееПройденноеРасстояние = ОбщееПройденноеРасстояние;
ОбластьИтого.Параметры.ОбщаяСуммаВыручки = ОбщаяСуммаВыручки;
ОбластьИтого.Параметры.ОбщийРасходТоплива = ОбщийРасходТоплива;
ТабДок.Вывести(ОбластьИтого);
КонецЕсли;
// Настройка параметров фиксации областей
ТабДок.ФиксацияСверху = 2;
Возврат ТабДок;
КонецФункции
Что-то мне Клод не то посоветовал по поводу макета. Это я про пост 32. Ладно, попробую вечером опять с ним поговорить. Объяснить еще раз, что нам нужно. Пост 32 игнорируем.
(29) На этот раз полностью доделал отчет. Тестовую базу с отчетом прикрепил.
Логисты в макете у меня объединяются следующим кодом:
// Выводим заголовки логистов в строке 4
Для Каждого ЛогистСсылка Из МассивЛогистов Цикл
МассивВодителейЛогиста = СоответствиеДанных[ЛогистСсылка];
КоличествоВодителей = МассивВодителейЛогиста.Количество();
// Создаем ячейку для логиста программно в строке 4
ТабДок.Область(4, НомерКолонки).Текст = СоответствиеЛогистов[ЛогистСсылка];
// Форматирование: жирный шрифт и выравнивание по центру
ТабДок.Область(4, НомерКолонки).Шрифт = Новый Шрифт(ТабДок.Область(4, НомерКолонки).Шрифт,,,Истина); // Жирный шрифт
ТабДок.Область(4, НомерКолонки).ГоризонтальноеПоложение = ГоризонтальноеПоложение.Центр;
ТабДок.Область(4, НомерКолонки).ШиринаКолонки = 20;
// Линия вокруг
ТабДок.Область(4, НомерКолонки).ГраницаСверху = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная,1);
ТабДок.Область(4, НомерКолонки).ГраницаСлева = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная,1);
ТабДок.Область(4, НомерКолонки).ГраницаСправа = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная,1);
// Размещение текста
ТабДок.Область(4, НомерКолонки).РазмещениеТекста = ТипРазмещенияТекстаТабличногоДокумента.Переносить;
// Устанавливаем цвет фона заголовка логиста (желтый)
ТабДок.Область(4, НомерКолонки).ЦветФона = WebЦвета.Золотой;
// Запоминаем начальную позицию для объединения
НачальнаяКолонка = НомерКолонки;
// Выводим пустые ячейки для остальных водителей
Для Инд = 2 По КоличествоВодителей Цикл
ТабДок.Область(4, НомерКолонки + Инд - 1).Текст = "";
// Устанавливаем цвет фона для всех ячеек логиста
ТабДок.Область(4, НомерКолонки + Инд - 1).ЦветФона = WebЦвета.Золотой;
КонецЦикла;
// Объединяем ячейки логиста над всеми его водителями
Если КоличествоВодителей > 1 Тогда
КонечнаяКолонка = НачальнаяКолонка + КоличествоВодителей - 1;
ТабДок.Область(4, НачальнаяКолонка, 4, КонечнаяКолонка).Объединить();
ТабДок.Область(4, КонечнаяКолонка).ГраницаСправа = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная,1);
КонецЕсли;
// Увеличиваем номер колонки для следующего логиста
НомерКолонки = НомерКолонки + КоличествоВодителей;
КонецЦикла;
Показать
А группировка у меня происходит благодаря использованию конструкции ИТОГИ ПО в языке запросов. Далее я обхожу результат запроса по группировкам и создаю соответствие логистов и массива их водителей (это СоответствиеДанных). Эти данные я далее использую при выводе в табличный документ:
// Получаем выборку по логистам
ВыборкаЛогисты = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Логист");
// Создаем соответствия для хранения данных
СоответствиеЛогистов = Новый Соответствие;
СоответствиеВодителей = Новый Соответствие;
СоответствиеДанных = Новый Соответствие;
// Заполняем структуру данными
Пока ВыборкаЛогисты.Следующий() Цикл
ЛогистСсылка = ВыборкаЛогисты.Логист;
ЛогистНаименование = ВыборкаЛогисты.ЛогистНаименование;
// Сохраняем информацию о логисте
СоответствиеЛогистов.Вставить(ЛогистСсылка, ЛогистНаименование);
// Получаем водителей для текущего логиста
ВыборкаВодители = ВыборкаЛогисты.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Водитель");
МассивВодителей = Новый Массив;
// Собираем данные о водителях
Пока ВыборкаВодители.Следующий() Цикл
ВодительСсылка = ВыборкаВодители.Водитель;
МассивВодителей.Добавить(ВодительСсылка);
// Сохраняем имя водителя
СоответствиеВодителей.Вставить(ВодительСсылка, ВыборкаВодители.ВодительНаименование);
// Получаем детальные данные для водителя
ВыборкаДетали = ВыборкаВодители.Выбрать();
Если ВыборкаДетали.Следующий() Тогда
// Создаем структуру для хранения показателей водителя
ДанныеВодителя = Новый Структура;
ДанныеВодителя.Вставить("ГосНомер", ВыборкаДетали.ГосНомер);
ДанныеВодителя.Вставить("ЦветКузова", ВыборкаДетали.ЦветКузова);
ДанныеВодителя.Вставить("Модель", ВыборкаДетали.Модель);
ДанныеВодителя.Вставить("ГодВыпуска", ВыборкаДетали.ГодВыпуска);
ДанныеВодителя.Вставить("КоличествоРейсов", ВыборкаДетали.КоличествоРейсов);
ДанныеВодителя.Вставить("ПройденноеРасстояние", ВыборкаДетали.ПройденноеРасстояние);
ДанныеВодителя.Вставить("СуммаВыручки", ВыборкаДетали.СуммаВыручки);
ДанныеВодителя.Вставить("РасходТоплива", ВыборкаДетали.РасходТоплива);
ДанныеВодителя.Вставить("ВремяВПути", ВыборкаДетали.ВремяВПути);
// Сохраняем данные водителя
СоответствиеДанных.Вставить(ВодительСсылка, ДанныеВодителя);
КонецЕсли;
КонецЦикла;
// Сохраняем список водителей для логиста
СоответствиеДанных.Вставить(ЛогистСсылка, МассивВодителей);
КонецЦикла;
// Получаем список всех логистов
МассивЛогистов = Новый Массив;
Для Каждого КлючИЗначение Из СоответствиеЛогистов Цикл
МассивЛогистов.Добавить(КлючИЗначение.Ключ);
КонецЦикла;
(35) А сможешь файл своего отчета выложить, или его код? Я тогда вечером его загружу в Клод Соннет, попрошу проконсультировать. По моим наблюдениям, ИИ консультирует получше чем я. Да и код на 1С ловко пишет.
В общем, будущее поступило. Коллега мой на прошлой работе смеялся "И что же Денис будет делать, когда код на 1С будет ИИ писать? гы гы гы ))". Вот ответ на вопрос коллеги. Буду скармливать ТЗ Клод Соннету и контролировать выполнение.
Вы правы в обоих замечаниях. Давайте адаптируем решение под существующий код автора, учитывая, что у него уже есть сформированная таблица значений.
Вариант решения с использованием существующей таблицы значений
Поскольку у автора уже есть готовая таблица значений (`Таблица`), мы можем использовать её для создания структуры данных по логистам, а затем применить эту структуру для правильного объединения ячеек. Вот как это можно реализовать:
ТабДок = Новый ТабличныйДокумент;
ОбработкаОб = РеквизитФормыВЗначение("Объект");
НачалоПериода = НачалоДня(ЭтотОбъект.НачалоПериода);
КонецПериода = КонецДня(ЭтотОбъект.КонецПериода);
Если КонецПериода > ТекущаяДата() ИЛИ НЕ ЗначениеЗаполнено(ЭтотОбъект.КонецПериода) Тогда
КонецПериода = ТекущаяДата();
КонецЕсли;
Макет = ОбработкаОб.ПолучитьМакет("Макет");
КолонкаРеквизиты = Макет.ПолучитьОбласть("Реквизиты");
КолонкаРеквизиты.Параметры.НачалоПериода = Формат(НачалоПериода, "ДФ=dd.MM.yyyy");
КолонкаРеквизиты.Параметры.КонецПериода = Формат(КонецПериода, "ДФ=dd.MM.yyyy");
ТабДок.Вывести(КолонкаРеквизиты);
ОбластьИтого = Макет.ПолучитьОбласть("ОбластьИтого");
ТабДок.Вывести(ОбластьИтого);
ОбластьВодители = Макет.ПолучитьОбласть("ОбластьВодители");
Таблица = СформироватьТаблицу();
Таблица.Сортировать("Логист");
// Создаем структуру для группировки по логистам
СоответствиеЛогистов = Новый Соответствие; // Логист -> Количество водителей
МассивЛогистов = Новый Массив; // Для сохранения порядка логистов
// Заполняем структуру данных
Для каждого Строка Из Таблица Цикл
Логист = Строка.Логист;
Если СоответствиеЛогистов[Логист] = Неопределено Тогда
СоответствиеЛогистов.Вставить(Логист, 1);
МассивЛогистов.Добавить(Логист);
Иначе
СоответствиеЛогистов[Логист] = СоответствиеЛогистов[Логист] + 1;
КонецЕсли;
КонецЦикла;
// Выводим данные
ТекущаяКолонка = 1;
Для каждого Строка Из Таблица Цикл
ОбластьВодители.Параметры.ПериодРасчета = Формат(Строка.ПериодНачалоРасчета,"ДФ=dd.MM.yyyy") + " - " + Формат(Строка.ПериодКонецРасчета,"ДФ=dd.MM.yyyy");
ОбластьВодители.Параметры.Заполнить(Строка);
ТабДок.Присоединить(ОбластьВодители);
ТекущаяКолонка = ТекущаяКолонка + 1;
КонецЦикла;
// Объединяем ячейки для логистов
ТекущаяКолонка = 1;
Для каждого Логист Из МассивЛогистов Цикл
КоличествоВодителей = СоответствиеЛогистов[Логист];
Если КоличествоВодителей > 1 Тогда
// Объединяем ячейки для логиста в строке 3
ТабДок.Область(3, ТекущаяКолонка, 3, ТекущаяКолонка + КоличествоВодителей - 1).Объединить();
КонецЕсли;
ТекущаяКолонка = ТекущаяКолонка + КоличествоВодителей;
КонецЦикла;
Возврат (ТабДок);
Показать
Объяснение решения:
1. Сначала мы создаем структуру данных:
- `СоответствиеЛогистов` - хранит количество водителей для каждого логиста
- `МассивЛогистов` - сохраняет порядок логистов для правильного обхода
2. При первом проходе по таблице заполняем эту структуру.
3. Затем выводим данные в табличный документ как обычно.
4. После вывода всех данных делаем второй проход по логистам и объединяем ячейки для каждого логиста, у которого больше одного водителя.
Важное замечание:
В коде я предполагаю, что логисты находятся в строке 3 табличного документа. Если это не так, нужно заменить число 3 на правильный номер строки (судя по скриншоту, это строка 3).
Также обратите внимание, что этот код предполагает, что водители одного логиста идут подряд в таблице (что должно выполняться благодаря сортировке `Таблица.Сортировать("Логист")`).
Если нужны дополнительные корректировки под конкретную структуру макета автора, дайте знать - я адаптирую решение.
===== ЛОГИСТ: Иванов Иван ===== ===== ЛОГИСТ: Смирнова Елена ===== ===== ЛОГИСТ: Козлов Антон
Водитель: Васильев Сергей Водитель: Петров Алексей Водитель: Соколов Владимир
Водитель: Морозов Андрей Водитель: Сидоров Николай Водитель: Стас Михайлов
Водитель: Новиков Игорь Водитель: Кузнецов Дмитрий Водитель: Сергей Кошкин
Водитель: Федоров Михаил
о, честно говоря если соединять 3+ таблицы то увы я сам пока в этим потерялся. А вот с двумя, вполне рабочий вариант, но вы можете попробовать сами. Есть такая штука как автономерзаписи() в запросе можно группировать таблицу по нему)
Что получается примерно у меня: Как переместить вторую табл горизонтально с группировкой?? Новой группой в выбранных полях с расположением горизонтально не получается
Запросом получил таблицу, макет сделал с областями по колонкам(скриншот), в цикле добавляю область колонку с водителями.
А как сгруппировать по логистам водителей ХЗ.
Вот что там пишут:
При обходе результата запроса нередко возникает необходимость получения всех значений группировок внутри какой-либо другой группировки. Такая возможность может понадобиться, например, при выводе кросс отчета. Для обеспечения такой возможности в объекте ВыборкаИзРезультатаЗапроса предусмотрен третий параметр функции Выбрать().
Рассмотрим пример. Пусть нам необходимо получить кросс-отчет по остаткам номенклатуры на различных складах. Номенклатуру необходимо вывести в строках, склады - в колонках. Запрос для получения остатков будет выглядеть так:
ВЫБРАТЬ
УчетНоменклатурыОстатки.Номенклатура КАК Номенклатура,
УчетНоменклатурыОстатки.Номенклатура.Представление,
УчетНоменклатурыОстатки.Склад КАК Склад,
УчетНоменклатурыОстатки.Склад.Представление,
УчетНоменклатурыОстатки.КоличествоОстаток КАК КоличествоОстаток
ИЗ
РегистрНакопления.УчетНоменклатуры.Остатки КАК УчетНоменклатурыОстатки
ИТОГИ СУММА(КоличествоОстаток) ПО
ОБЩИЕ,
Номенклатура,
Склад
Показать
Для обхода номенклатуры воспользуемся выборкой из результата запроса:
ВыборкаНоменклатура = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Номенклатура");
Пока ВыборкаНоменклатура.Следующий() Цикл
ОбластьНоменклатура.Параметры.Заполнить(ВыборкаНоменклатура);
ТабДок.Вывести(ОбластьНоменклатура);
Для обхода внутри номенклатуры всех складов, присутствующих в результате запроса, получим вложенную выборку от выборки номенклатуры, с указанием третьего параметра "ВСЕ":
ВыборкаСклад = ВыборкаНоменклатура.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Склад", "ВСЕ");
Пока ВыборкаСклад.Следующий() Цикл
ОбластьСклад.Параметры.Заполнить(ВыборкаСклад);
ТабДок.Присоединить(ОбластьСклад);
КонецЦикла;
Но Клод мне рассказал как нарисовать макет. Вот его схематичная схема:
+-----------------------------------------------------+
| ЗАГОЛОВОК |
+-----------------------------------------------------+
| ЛОГИСТ 1 | ЛОГИСТ 2 | ЛОГИСТ 3 |
+-----------------------------------------------------+
| Водитель-ФИО | Водитель-ФИО | Водитель-ФИО |
| НомерТС | НомерТС | НомерТС |
| ЦветКузова | ЦветКузова | ЦветКузова |
+-----------------------------------------------------+
| Водитель 1 | Водитель 1 | Водитель 1 |
| ТС 1 | ТС 1 | ТС 1 |
| Цвет 1 | Цвет 1 | Цвет 1 |
+-----------------------------------------------------+
| Показатели 1 | Показатели 1 | Показатели 1 |
+-----------------------------------------------------+
| Водитель 2 | Водитель 2 | Водитель 2 |
| ТС 2 | ТС 2 | ТС 2 |
| Цвет 2 | Цвет 2 | Цвет 2 |
+-----------------------------------------------------+
| Показатели 2 | Показатели 2 | Показатели 2 |
+-----------------------------------------------------+
| ИТОГО ПО ЛОГИСТУ| ИТОГО ПО ЛОГИСТУ| ИТОГО ПО ЛОГИСТУ|
+-----------------------------------------------------+
| ИТОГО ПО ВСЕМ ЛОГИСТАМ |
+-----------------------------------------------------+
Создание и настройка областей макета:
Откройте конфигуратор и перейдите к отчету "ОтчетПоЛогистамИВодителям"
Создайте макет отчета:
В дереве объектов конфигурации найдите отчет
Перейдите на вкладку "Макеты"
Добавьте новый макет типа "Табличный документ" с именем "Макет"
Создайте области в макете:
a. Область "Заголовок" (1 строка x несколько колонок):
+----------------------------------------------+
| Отчет по логистам и водителям за период: |
| с [НачалоПериода] по [КонецПериода] |
| [ОтборЛогист] |
+----------------------------------------------+
Выделите область для заголовка (например, ячейки A1:G3)
Щелкните правой кнопкой мыши и выберите "Имя области" → "Определить"
Введите имя "Заголовок"
Настройте параметры: &НачалоПериода, &КонецПериода, &ОтборЛогист
b. Область "Логист" (1 строка x несколько колонок):
text+----------------+
[Логист]
+----------------+
Выделите область для логиста (например, ячейки A4:C4)
Определите имя области "Логист"
Настройте параметр: &Логист
c. Область "Водитель" (1 строка x несколько колонок):
text+----------------+
[Водитель]
[ТС]
[ЦветКузова]
+----------------+
Выделите область для водителя (например, ячейки A5:C7)
Определите имя области "Водитель"
Настройте параметры: &Водитель, &ТС, &ЦветКузова
d. Область "Показатели" (1 строка x несколько колонок):
text+----------------+
Рейсы: [КоличествоРейсов]
Расстояние: [ПройденноеРасстояние]
Выручка: [СуммаВыручки]
Топливо: [РасходТоплива]
+----------------+
Выделите область для показателей (например, ячейки A8:C11)
Определите имя области "Показатели"
Настройте параметры: &КоличествоРейсов, &ПройденноеРасстояние, &СуммаВыручки, &РасходТоплива
e. Область "ИтогоПоЛогисту" (1 строка x несколько колонок):
text+----------------+
ИТОГО:
Рейсы: [ИтогоКоличествоРейсов]
Расстояние: [ИтогоПройденноеРасстояние]
Выручка: [ИтогоСуммаВыручки]
Топливо: [ИтогоРасходТоплива]
+----------------+
Выделите область для итогов по логисту (например, ячейки A12:C16)
Определите имя области "ИтогоПоЛогисту"
Настройте параметры: &ИтогоКоличествоРейсов, &ИтогоПройденноеРасстояние, &ИтогоСуммаВыручки, &ИтогоРасходТоплива
f. Область "Итого" (1 строка x все колонки):
text+----------------------------------------------+
ИТОГО ПО ВСЕМ ЛОГИСТАМ:
Рейсы: [ОбщееКоличествоРейсов]
Расстояние: [ОбщееПройденноеРасстояние]
Выручка: [ОбщаяСуммаВыручки]
Топливо: [ОбщийРасходТоплива]
+----------------------------------------------+
Выделите область для общих итогов (например, ячейки A17:G21)
Определите имя области "Итого"
Настройте параметры: &ОбщееКоличествоРейсов, &ОбщееПройденноеРасстояние, &ОбщаяСуммаВыручки, &ОбщийРасходТоплива
g. Область "ПустойРезультат" (для случая отсутствия данных):
text+----------------------------------------------+
Нет данных для отображения по заданным
параметрам отчета
+----------------------------------------------+
Выделите область (например, ячейки A22:G23)
Определите имя области "ПустойРезультат"
Советы по созданию макета:
Размеры областей:
Сделайте области логиста, водителя и показателей одинаковой ширины, чтобы они красиво выстраивались горизонтально
Используйте объединение ячеек для создания удобного форматирования
Форматирование:
Для области "Логист" можно использовать жирный шрифт и выравнивание по центру
Для заголовков водителей также можно использовать жирный шрифт
Для числовых значений настройте формат ячеек с необходимым количеством десятичных знаков
Параметры:
Все параметры в макете должны начинаться с символа "&" (например, &Логист)
Проверьте, что имена параметров в макете совпадают с именами в коде
Цвета:
В самом макете не задавайте цвета фона для областей логистов - они будут установлены программно в коде
После создания и настройки всех областей макета, код отчета будет использовать их для формирования отчета, располагая секции логистов горизонтально и заполняя их данными о водителях и показателях.