Предположим, требуется обработка по загрузке / выгрузке / изменению массива данных или прочих действий, выполняющихся продолжительное время. При этом выполнение обработки не должно блокировать пользовательский интерфейс. Также необходимо отслеживать процент выполнения в виде индикатора прогресса. Например, так:
В статье рассмотрим решение с использованием программного интерфейса длительных операций и дополнительных отчетов и обработок БСП. Сразу скажу, что созданную обработку понадобится добавить в справочник дополнительных отчетов и обработок. Без этого решение неработоспособно. Поэтому, если Вы ищите пример с отслеживанием прогресса выполнения обработки без добавления в указанный справочник, то рекомендую поискать другие публикации.
Приступим к реализации. Для примера создадим внешнюю обработку по загрузке документов с реквизитами:
- КоличествоДокументовДляЗагрузки (Число)
- ДатаДокументов (Дата)
В модуле объекта обработки необходимо разместить методы по регистрации внешней обработки в справочнике дополнительных отчетов и обработок, а также процедуру вызова серверного метода:
#Область СлужебныйПрограммныйИнтерфейс
Функция СведенияОВнешнейОбработке() Экспорт
ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("3.1.6.100");
ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиДополнительнаяОбработка();
ПараметрыРегистрации.Версия = "1.0.0.0";
ПараметрыРегистрации.БезопасныйРежим = Ложь;
Команда = ПараметрыРегистрации.Команды.Добавить();
Команда.Представление = НСтр("ru = 'Серверный метод длительной операции'");
Команда.Идентификатор = ИдентификаторСерверногоМетодаОбработки();
Команда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовСерверногоМетода();
Команда.ПоказыватьОповещение = Ложь;
Команда.Скрыть = Истина;
Команда = ПараметрыРегистрации.Команды.Добавить();
Команда.Представление = НСтр("ru = 'Запуск загрузки документов'");
Команда.Идентификатор = ИдентификаторОткрытияФормыОбработки();
Команда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыОткрытиеФормы();
Команда.ПоказыватьОповещение = Ложь;
Возврат ПараметрыРегистрации;
КонецФункции
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ПараметрыВыполнения) Экспорт
// Здесь будем вызывать нашу долгую процедуру
КонецПроцедуры
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
Функция ИдентификаторСерверногоМетодаОбработки() Экспорт
Возврат Метаданные().Имя;
КонецФункции
Функция ИдентификаторОткрытияФормыОбработки()
Возврат СтрШаблон("%1_ОткрытиеФормы", Метаданные().Имя);
КонецФункции
#КонецОбласти
Здесь все довольно стандартно. Обратить внимание следует на следующие моменты:
- Отключение безопасного режима в параметрах регистрации:
ПараметрыРегистрации.БезопасныйРежим = Ложь;
- Получение идентификатора команды вызова серверного метода:
Функция ИдентификаторСерверногоМетодаОбработки() Экспорт
Далее реализуем процедуру «ВыполнитьКоманду()». Проверяем полученный идентификатор и, если он совпадает с идентификатором вызова серверного метода, запускаем длительную загрузку документов:
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ПараметрыВыполнения) Экспорт
Если ИдентификаторКоманды = ИдентификаторСерверногоМетодаОбработки() Тогда
ЗагрузитьДокументыЗаПериод(ПараметрыВыполнения);
КонецЕсли;
КонецПроцедуры
Ниже в области служебных процедур добавляем саму длительную загрузку документов за период:
// Параметры:
// ПараметрыВыполнения - Структура - см. ВыполнитьКоманду.ПараметрыВыполнения
//
Процедура ЗагрузитьДокументыЗаПериод(ПараметрыВыполнения)
// Пример получения переданных параметров
КоличествоДокументовДляЗагрузки = ПараметрыВыполнения.Контекст_КоличествоДокументовДляЗагрузки;
ДатаДокументов = ПараметрыВыполнения.Контекст_ДатаДокументов;
ПроцентВыполнения = 0;
СообщениеПрогресса = СтрШаблон("Начало загрузки документов за %1 в количетсве %2",
ДатаДокументов, КоличествоДокументовДляЗагрузки);
// Передаем информацию о прогрессе выполнения
ДлительныеОперации.СообщитьПрогресс(ПроцентВыполнения, СообщениеПрогресса);
// Имитируем задержку выполнения
Пауза();
// Далее все аналогично
ПроцентВыполнения = 50;
СообщениеПрогресса = СтрШаблон("Продолжение загрузки документов за %1 в количетсве %2",
ДатаДокументов, КоличествоДокументовДляЗагрузки);
ДлительныеОперации.СообщитьПрогресс(ПроцентВыполнения, СообщениеПрогресса);
Пауза();
//...
ПроцентВыполнения = 100;
СообщениеПрогресса = СтрШаблон("Завершение загрузки документов за %1 в количетсве %2",
ДатаДокументов, КоличествоДокументовДляЗагрузки);
ДлительныеОперации.СообщитьПрогресс(ПроцентВыполнения, СообщениеПрогресса);
КонецПроцедуры
Процедура Пауза()
ПятьСекунд = ТекущаяДата() + 5;
Пока ТекущаяДата() < ПятьСекунд Цикл
// Имитация задержки
КонецЦикла;
КонецПроцедуры
Здесь из интересного:
- Получение входящих параметров:
КоличествоДокументовДляЗагрузки = ПараметрыВыполнения.Контекст_КоличествоДокументовДляЗагрузки; ДатаДокументов = ПараметрыВыполнения.Контекст_ДатаДокументов;
- И самое важное:
ДлительныеОперации.СообщитьПрогресс(ПроцентВыполнения, СообщениеПрогресса);
Осталось создать форму обработки, из которой будет запускаться фоновое выполнение процедуры загрузки документов и отображаться прогресс выполнения. Добавляем основную форму и размещаем все реквизиты обработки:
Для формы на вкладке «Параметры» указываем два ключевых параметра:
- ДополнительнаяОбработкаСсылка (СправочникСсылка.ДополнительныеОтчетыИОбработки)
- ИдентификаторКоманды (Строка)
Затем добавим два реквизита формы:
- ПрогрессВыполнения (Число, 3, неотрицательное)
- СообщениеПрогресса (Строка)
Разместим добавленные реквизиты на форме. Для элемента реквизита «ПрогрессВыполнения» укажем вид поля «Индикатор» скроем заголовок и установим свойство «Отображать проценты»:
После индикатора прогресса расположим реквизит «СообщениеПрогресса» в виде поля надписи и скроем заголовок. Также установим свойства по растягиванию элемента по горизонтали:
И последний штрих – добавляем команду запуска фоновой загрузки документов и размещаем кнопку команды на форме:
С дизайном формы закончили. Теперь можно приступать к написанию кода. Создаем клиентский обработчик команды загрузить документы:
Созданный обработчик пока оставляем пустым:
#Область ОбработчикиКомандФормы
&НаКлиенте
Процедура ЗагрузитьДокументы(Команда)
КонецПроцедуры
#КонецОбласти
Для начала необходимо решить задачу запуска фонового выполнения загрузки документов. В фоновом задании необходимо вызвать функцию модуля обработки «ВыполнитьКоманду()», передать на вход идентификатор серверного метода + параметры дата и количество загружаемых документов.
Поскольку мы задействовали функционал дополнительных отчетов и обработок, то для обычного запуска выполнения команды можно воспользоваться программным интерфейсом «ДополнительныеОтчетыИОбработки.ВыполнитьКоманду()». На вход указанной функции передается ссылка на обработку в справочнике «ДополнительныеОтчетыИОбработки», строковый идентификатор серверного метода, а также дополнительные параметры выполнения (дата и количество документов).
А чтобы все это выполнить в фоновом задании воспользуемся программным интерфейсом «ДлительныеОперации.ВыполнитьФункцию()»
В модуль формы добавим функцию по запуску фоновой загрузки документов и вызов из клиентского обработчика кнопки:
#Область ОбработчикиКомандФормы
&НаКлиенте
Процедура ЗагрузитьДокументы(Команда)
// Запускаем фоновое задание загрузки документов
ДанныеЗадания = ЗапуститьФоновуюЗагрузкуДокументов();
КонецПроцедуры
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
&НаСервере
Функция ЗапуститьФоновуюЗагрузкуДокументов()
// Параметры для запуска фонового задания
ПараметрыВыполненияФоновогоЗадания = ДлительныеОперации.ПараметрыВыполненияФункции(УникальныйИдентификатор);
ПараметрыВыполненияФоновогоЗадания.ОжидатьЗавершение = 0;
ПараметрыВыполненияФоновогоЗадания.ЗапуститьВФоне = Истина;
ИдентификаторКомандыЗагрузкиДокументов = РеквизитФормыВЗначение("Объект").ИдентификаторСерверногоМетодаОбработки();
// см. ДополнительныеОтчетыИОбработки.ВыполнитьКоманду.ПараметрыКоманды
ПараметрыОбработкиЗагрузки = Новый Структура;
ПараметрыОбработкиЗагрузки.Вставить("ДополнительнаяОбработкаСсылка", Параметры.ДополнительнаяОбработкаСсылка);
ПараметрыОбработкиЗагрузки.Вставить("ИдентификаторКоманды", ИдентификаторКомандыЗагрузкиДокументов);
ПараметрыОбработкиЗагрузки.Вставить("Контекст_ДатаДокументов", Объект.ДатаДокументов);
ПараметрыОбработкиЗагрузки.Вставить("Контекст_КоличествоДокументовДляЗагрузки", Объект.КоличествоДокументовДляЗагрузки);
ИмяФункцииФоновогоЗадания = "ДополнительныеОтчетыИОбработки.ВыполнитьКоманду";
// Запуск фонового выполнения дополнительной обработки
ДанныеЗадания = ДлительныеОперации.ВыполнитьФункцию(ПараметрыВыполненияФоновогоЗадания,
ИмяФункцииФоновогоЗадания, ПараметрыОбработкиЗагрузки);
Возврат ДанныеЗадания;
КонецФункции
#КонецОбласти
Здесь все довольно очевидно. Чтобы сразу запустить и не дожидаться завершения фонового задания, устанавливаем параметры выполнения:
ПараметрыВыполненияФоновогоЗадания.ОжидатьЗавершение = 0;
ПараметрыВыполненияФоновогоЗадания.ЗапуститьВФоне = Истина;
Ссылка на дополнительную обработку хранится в ключевом параметре «ДополнительнаяОбработкаСсылка»:
Параметры.ДополнительнаяОбработкаСсылка
Идентификатор серверного метода загрузки документов получаем из экспортного метода модуля обработки:
ИдентификаторКомандыЗагрузкиДокументов = РеквизитФормыВЗначение("Объект").ИдентификаторСерверногоМетодаОбработки();
Дату и количество документов передаем из данных формы с ключами «Контекст_ДатаДокументов» и «Контекст_КоличествоДокументовДляЗагрузки»:
ПараметрыОбработкиЗагрузки.Вставить("Контекст_ДатаДокументов", Объект.ДатаДокументов);
ПараметрыОбработкиЗагрузки.Вставить("Контекст_КоличествоДокументовДляЗагрузки", Объект.КоличествоДокументовДляЗагрузки);
Напомню, данные параметры мы получаем в процедуре загрузки документов (см. модуль объекта обработки).
Теперь необходимо реализовать отслеживание прогресса и вывод данных через индикатор состояния выполнения обработки. В этом нам поможет программный интерфейс «ДлительныеОперацииКлиент.ОжидатьЗавершение()». В клиентском обработчике кнопки «Загрузить документы» после вызова функции запуска загрузки документов в фоне добавляем следующий код:
// Процедура обновления шкалы прогресса
ОповещениеОПрогрессе = Новый ОписаниеОповещения("ОбновитьПрогрессВыполнения", ЭтаФорма);
ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтаФорма);
ПараметрыОжидания.ВыводитьОкноОжидания = Ложь;
ПараметрыОжидания.ОповещениеОПрогрессеВыполнения = ОповещениеОПрогрессе;
// Выполнится после завершения фонового задания
ОповещениеОЗавершении = Новый ОписаниеОповещения("ОповеститьОЗавершенииЗагрузки", ЭтаФорма);
ДлительныеОперацииКлиент.ОжидатьЗавершение(ДанныеЗадания, ОповещениеОЗавершении, ПараметрыОжидания);
И две процедуры-обработчики оповещения:
&НаКлиенте
Процедура ОбновитьПрогрессВыполнения(ДанныеПрогресса, ДополнительныеПараметры) Экспорт
// Здесь обновляем шкалу прогресса
Если ДанныеПрогресса.Прогресс = Неопределено Тогда
Возврат;
КонецЕсли;
ПрогрессВыполнения = ДанныеПрогресса.Прогресс.Процент;
СообщениеПрогресса = ДанныеПрогресса.Прогресс.Текст;
КонецПроцедуры
&НаКлиенте
Процедура ОповеститьОЗавершенииЗагрузки(Задание, ДополнительныеПараметры) Экспорт
// А здесь оповещаем о завершении фонового задания
Если Задание.Статус = "Выполнено" Тогда
ПоказатьПредупреждение(, НСтр("ru = 'Загрузка завершена'"), 20);
Возврат;
ИначеЕсли Задание.Статус = "Ошибка" Тогда
ВызватьИсключение Задание.ПодробноеПредставлениеОшибки;
Иначе
Возврат;
КонецЕсли;
КонецПроцедуры
Из важного стоит обратить внимание на параметры ожидания:
ОповещениеОПрогрессе = Новый ОписаниеОповещения("ОбновитьПрогрессВыполнения", ЭтаФорма);
ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтаФорма);
ПараметрыОжидания.ВыводитьОкноОжидания = Ложь;
ПараметрыОжидания.ОповещениеОПрогрессеВыполнения = ОповещениеОПрогрессе;
Поскольку мы отслеживаем процесс выполнения самостоятельно, то окно ожидания нам не нужно. Параметр «ВыводитьОкноОжидания» отключаем.
Информацию о ходе выполнения нужно где-то получать и обрабатывать – указываем обработчик оповещения о прогрессе с именем процедуры, в которой реализовано отображение прогресса:
ОповещениеОПрогрессе = Новый ОписаниеОповещения("ОбновитьПрогрессВыполнения", ЭтаФорма);
…
ПараметрыОжидания.ОповещениеОПрогрессеВыполнения = ОповещениеОПрогрессе;
Напомню, что данные о ходе выполнения сообщает процедура «ДлительныеОперации.СообщитьПрогресс()» вызов которой мы выполняем в методе по загрузке документов за период в модуле объекта обработки.
Готово. Можно добавлять обработку в справочник и проверять:
Из рассмотренного примера можно выделить общую суть чтения прогресса на клиентской форме дополнительной обработки:
- Для передачи информации о ходе выполнения используем процедуру «ДлительныеОперации.СообщитьПрогресс()». Располагаем обращения к процедуре в основном методе команды серверного вызова модуля объекта обработки:
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ПараметрыВыполнения) Экспорт // Основной метод обработки ЗагрузитьДокументыЗаПериод(ПараметрыВыполнения); КонецПроцедуры Процедура ЗагрузитьДокументыЗаПериод(ПараметрыВыполнения) //... // Передаем информацию о прогрессе ДлительныеОперации.СообщитьПрогресс(ПроцентВыполнения, СообщениеПрогресса); КонецПроцедуры
- В основной форме создаем команду запуска фонового выполнения серверного метода обработки путем вызова функции «ДополнительныеОтчетыИОбработки.ВыполнитьКоманду()» через программный интерфейс «ДлительныеОперации.ВыполнитьФункцию()»:
// Обработчик команды &НаКлиенте Процедура ЗагрузитьДокументы(Команда) // Запускаем фоновое задание загрузки документов ДанныеЗадания = ЗапуститьФоновуюЗагрузкуДокументов(); //... КонецПроцедуры &НаСервере Функция ЗапуститьФоновуюЗагрузкуДокументов() //... ИмяФункцииФоновогоЗадания = "ДополнительныеОтчетыИОбработки.ВыполнитьКоманду"; // Запуск фонового выполнения дополнительной обработки ДанныеЗадания = ДлительныеОперации.ВыполнитьФункцию(ПараметрыВыполненияФоновогоЗадания, ИмяФункцииФоновогоЗадания, ПараметрыОбработкиЗагрузки); Возврат ДанныеЗадания; КонецФункции
- В параметрах ожидания завершения фонового задания отключаем «ВыводитьОкноОжидания» и создаем процедуру-обработчик, в которой будем обрабатывать информацию о прогрессе выполнения:
// Обработчик команды &НаКлиенте Процедура ЗагрузитьДокументы(Команда) // Запускаем фоновое задание загрузки документов ДанныеЗадания = ЗапуститьФоновуюЗагрузкуДокументов(); // Процедура обновления шкалы прогресса ОповещениеОПрогрессе = Новый ОписаниеОповещения("ОбновитьПрогрессВыполнения", ЭтаФорма); ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтаФорма); ПараметрыОжидания.ВыводитьОкноОжидания = Ложь; ПараметрыОжидания.ОповещениеОПрогрессеВыполнения = ОповещениеОПрогрессе; // Выполнится после завершения фонового задания ОповещениеОЗавершении = Новый ОписаниеОповещения("ОповеститьОЗавершенииЗагрузки", ЭтаФорма); ДлительныеОперацииКлиент.ОжидатьЗавершение(ДанныеЗадания, ОповещениеОЗавершении, ПараметрыОжидания); КонецПроцедуры // Обработчик обновления шкалы прогресса &НаКлиенте Процедура ОбновитьПрогрессВыполнения(ДанныеПрогресса, ДополнительныеПараметры) Экспорт //... КонецПроцедуры
Пример обработки прикреплен к данной публикации. Тестировалось на:
- БСП 3.1.6.100
- Управление торговлей (Демо) 11.5.12.256
Полезные ссылки:
- ДополнительныеОтчетыИОбработки.ВыполнитьКоманду()
- ДлительныеОперации.ВыполнитьФункцию()
- ДлительныеОперацииКлиент.ОжидатьЗавершение()
- ДлительныеОперации.СообщитьПрогресс()
Спасибо за внимание!
Проверено на следующих конфигурациях и релизах:
- 1С:Библиотека стандартных подсистем, редакция 3.1, релизы 3.1.6.100