#Область ОбработчикиСобытийФормы
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ЦиклОбмена = Параметры.ЦиклОбмена;
ПечатныеДокументы = Параметры.ПечатныеДокументы;
ВидПечати = Параметры.ВидПечати;
ЭтоВебКлиент = Параметры.ЭтоВебКлиент;
сохрКоличествоКопий = ХранилищеОбщихНастроек.Загрузить("ПредварительныйПросмотрПечатныхФорм_ПредпросмотрПечатныхЛистовКоличествоКопий");
Если сохрКоличествоКопий = Неопределено ИЛИ сохрКоличествоКопий = 0 Тогда
КоличествоКопий = 1;
Иначе
КоличествоКопий = сохрКоличествоКопий;
КонецЕсли;
КонтекстЭДОСервер = ДокументооборотСКО.ПолучитьОбработкуЭДО();
Сведения = КонтекстЭДОСервер.СведенияПоОтправляемымОбъектам(ЦиклОбмена.Предмет);
СтраницаЖурнала = Сведения.СтраницаЖурнала;
Если СтраницаЖурнала = Перечисления.СтраницыЖурналаОтчетность.Отчеты Тогда
Заголовок = НСтр("ru = 'Печать протоколов'");
Иначе
Заголовок = НСтр("ru = 'Печать квитанций'");
КонецЕсли;
ЕстьТранспортноеСообщение = Ложь;
ВсегоОдинДокумент = ПечатныеДокументы.Количество() = 1;
Для Каждого ПечатныйДокумент Из ПечатныеДокументы Цикл
НовСтр2 = СписокОбъектовДляПечати.Добавить();
НовСтр2.Объект = ПечатныйДокумент.Представление;
Если ПечатныйДокумент.Значение <> Неопределено Тогда
ГУИД = Новый УникальныйИдентификатор;
Если ТипЗнч(ПечатныйДокумент.Значение) = Тип("Структура") Тогда
ЕстьТранспортноеСообщение = Истина;
ТранспортноеСообщение = ПечатныйДокумент.Значение.Отправка;
ЭтоВходящийДокумент = ТипЗнч(ТранспортноеСообщение.Получатель) = Тип("СправочникСсылка.Организации");
НовСтр2.ТабличныйДокумент = ПоместитьВоВременноеХранилище(ПечатныйДокумент.Значение.ТабДок, ГУИД);
НовСтр2.ИмяФайлаБезРасширения = ИмяФайлаБезРасширения(ПечатныйДокумент.Представление, Сведения);
НовСтр2.ПорядковыйНомер = КонтекстЭДОСервер.ПорядковыйНомерСообщенияВЦиклеОбмена(ЦиклОбмена, ТранспортноеСообщение);
НовСтр2.Направление = ?(ЭтоВходящийДокумент, 1, 2);
НовСтр2.Пометка = ЭтоВходящийДокумент ИЛИ ВсегоОдинДокумент;
Иначе
НовСтр2.ТабличныйДокумент = ПоместитьВоВременноеХранилище(ПечатныйДокумент.Значение, ГУИД);
НовСтр2.ИмяФайлаБезРасширения = ИмяФайлаБезРасширения(ПечатныйДокумент.Представление, Сведения);
НовСтр2.Пометка = Истина;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Если НЕ ЕстьТранспортноеСообщение ИЛИ ВсегоОдинДокумент Тогда
Элементы.ГруппаКнопок.Видимость = Ложь;
Элементы.Пометка.Видимость = Ложь;
Элементы.СписокЛистов.ПутьКДаннымКартинкиСтроки = "";
КонецЕсли;
СписокОбъектовДляПечати.Сортировать("ПорядковыйНомер");
СоответствиеЛистовСписку = Новый Структура;
Если ПечатныеДокументы.Количество() = 1 Тогда
ЭтаФорма.Заголовок = ПечатныеДокументы[0].Представление;
Элементы.СписокЛистов.Видимость = Ложь;
ОсвежитьВыбранныйЛист(НовСтр2.ТабличныйДокумент, 0);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПриОткрытии(Отказ)
Если СписокОбъектовДляПечати.Количество() = 0 Тогда
ПоказатьПредупреждение(,"Нет протоколов для печати");
Отказ = Истина;
Возврат;
КонецЕсли;
Если ВидПечати = "ПечататьСразу" Тогда
Отказ = Истина;
Возврат;
КонецЕсли;
Элементы.СписокЛистов.ТекущаяСтрока =
СписокОбъектовДляПечати[СписокОбъектовДляПечати.Количество()-1].ПолучитьИдентификатор();
КонецПроцедуры
#КонецОбласти
#Область ОбработчикиСобытийЭлементовШапкиФормы
#КонецОбласти
#Область ОбработчикиСобытийЭлементовТаблицыФормы
&НаКлиенте
Процедура ИтоговаяТаблицаОбработкаРасшифровки(Элемент, Расшифровка, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
Если ЗначениеЗаполнено(ЦиклОбмена) Тогда
ОписаниеОповещения = Новый ОписаниеОповещения("ИтоговаяТаблицаОбработкаРасшифровкиЗавершение", ЭтотОбъект, Расшифровка);
ДокументооборотСКОКлиент.ПолучитьКонтекстЭДО(ОписаниеОповещения);
КонецЕсли;
КонецПроцедуры
#КонецОбласти
#Область ОбработчикиКомандФормы
&НаКлиенте
Процедура ВыбратьВсе(Команда)
Для каждого Строка Из СписокОбъектовДляПечати Цикл
Строка.Пометка = Истина;
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура УбратьВсе(Команда)
Для каждого Строка Из СписокОбъектовДляПечати Цикл
Строка.Пометка = Ложь;
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура ВсеВходящие(Команда)
Для каждого Строка Из СписокОбъектовДляПечати Цикл
Строка.Пометка = Строка.Направление = 1;
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура ВсеИсходящие(Команда)
Для каждого Строка Из СписокОбъектовДляПечати Цикл
Строка.Пометка = Строка.Направление = 2;
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура КомандаПечать(Команда)
СохранитьНастройки();
Для Каждого Эл Из СписокОбъектовДляПечати Цикл
Если НЕ Эл.Пометка Тогда
Продолжить;
КонецЕсли;
Для Сч = 1 По КоличествоКопий Цикл
ЭлТабличныйДокумент = ПолучитьИзВременногоХранилища(Эл.ТабличныйДокумент);
ЭлТабличныйДокумент.КоличествоЭкземпляров = 1;
ЭлТабличныйДокумент.ЭкземпляровНаСтранице = 1;
ЭлТабличныйДокумент.Автомасштаб = Истина;
ЭлТабличныйДокумент.Напечатать();
КонецЦикла;
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура КомандаВФорматеMicrosoftExcel(Команда)
ВыгрузитьНаДиск(ТипФайлаТабличногоДокумента.XLS);
КонецПроцедуры
&НаКлиенте
Процедура КомандаВВидеТабличныхДокументов(Команда)
ВыгрузитьНаДиск(ТипФайлаТабличногоДокумента.MXL);
КонецПроцедуры
&НаКлиенте
Процедура КомандаВФорматеAdobePDF(Команда)
ВыгрузитьНаДиск(ТипФайлаТабличногоДокумента.PDF);
КонецПроцедуры
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
&НаСервере
Функция ИмяФайлаБезРасширения(Представление, Сведения)
ПодстрокиИмени = Новый Массив;
ПодстрокиИмени.Добавить(Представление);
ПодстрокиИмени.Добавить(Сведения.Наименование);
Если ЗначениеЗаполнено(Сведения.ПредставлениеПериода) Тогда
ПодстрокиИмени.Добавить(Сведения.ПредставлениеПериода);
Иначе
ПодстрокиИмени.Добавить(Формат(Сведения.Дата, "ДФ=dd.MM.yyyy"));
КонецЕсли;
ИмяФайлаБезРасширения = СтрСоединить(ПодстрокиИмени, " - ");
ИмяФайлаБезРасширения = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла(ИмяФайлаБезРасширения, "_");
Возврат ИмяФайлаБезРасширения;
КонецФункции
&НаКлиенте
Процедура СписокЛистовПриАктивизацииСтроки(Элемент)
ОтключитьОбработчикОжидания("СписокЛистовПриАктивизацииСтрокиЗавершение");
ПодключитьОбработчикОжидания("СписокЛистовПриАктивизацииСтрокиЗавершение", 0.1, Истина);
КонецПроцедуры
&НаКлиенте
Процедура СписокЛистовПриАктивизацииСтрокиЗавершение()
Элемент = Элементы.СписокЛистов;
Если Элемент.ТекущиеДанные <> Неопределено И ЗначениеЗаполнено(Элемент.ТекущиеДанные.ТабличныйДокумент) Тогда
ОсвежитьВыбранныйЛист(Элемент.ТекущиеДанные.ТабличныйДокумент, Элементы.СписокЛистов.ТекущаяСтрока);
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура СохранитьНастройки()
ХранилищеОбщихНастроек.Сохранить("ПредварительныйПросмотрПечатныхФорм_ПредпросмотрПечатныхЛистовКоличествоКопий",, КоличествоКопий);
КонецПроцедуры
&НаСервере
Процедура ОсвежитьВыбранныйЛист(АдресТД, ИДСтроки=0)
Если ЗначениеЗаполнено(АдресТД) Тогда
ВыводимыйТаблДок = ПолучитьИзВременногоХранилища(АдресТД);
ВыводимыйТаблДок.ОриентацияСтраницы = ВыводимыйТаблДок.ОриентацияСтраницы;
ВыводимыйТаблДок.АвтоМасштаб = Истина;
ВыводимыйТаблДок.ТолькоПросмотр = Ложь;
ВыводимыйТаблДок.ПолеСверху = ВыводимыйТаблДок.ПолеСверху;
ВыводимыйТаблДок.ПолеСнизу = ВыводимыйТаблДок.ПолеСнизу;
ВыводимыйТаблДок.ПолеСправа = ВыводимыйТаблДок.ПолеСправа;
ВыводимыйТаблДок.ПолеСлева = ВыводимыйТаблДок.ПолеСлева;
ИтоговаяТаблица = ВыводимыйТаблДок;
Иначе
Если ЭтоВебКлиент Тогда
Элементы.ИтоговаяТаблица.ТолькоПросмотр = Истина;
ТД = Новый ТабличныйДокумент;
КолСтрокВГруппе = СписокОбъектовДляПечати.Количество();
Отступ = 10;
Интервал = 16;
ШиринаРисунка = 24;
ВысотаРисунка = 30;
РисунковВСтроке = 4;
ТД.Область().ЦветФона = Новый Цвет(255, 251, 240);
Для Инд = 0 По КолСтрокВГруппе - 1 Цикл
ТекСтр = СписокОбъектовДляПечати[Инд];
ТекТаблДок = ПолучитьИзВременногоХранилища(ТекСтр.ТабличныйДокумент);
НовРис = ТД.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Текст);
НовРис.Узор = ТипУзораТабличногоДокумента.Сплошной;
НовРис.ЦветФона = Новый Цвет(255, 255, 205);
Если ТекТаблДок.ОриентацияСтраницы = ОриентацияСтраницы.Портрет Тогда
НовРис.Ширина = ШиринаРисунка;
НовРис.Высота = ВысотаРисунка;
Иначе
НовРис.Ширина = ВысотаРисунка;
НовРис.Высота = ШиринаРисунка;
КонецЕсли;
НовРис.Лево = Отступ + ((Инд % РисунковВСтроке) * (ШиринаРисунка + Интервал)) + Цел((ШиринаРисунка + Интервал - НовРис.Ширина) / 2);
НовРис.Верх = Отступ + ((Цел(Инд / РисунковВСтроке)) * (ВысотаРисунка + Интервал)) + Цел((ВысотаРисунка + Интервал - НовРис.Высота) / 2);
КоличествоЛистовВсего = ТекТаблДок.КоличествоСтраниц();
ТекстЛистовВсего = Формат(КоличествоЛистовВсего, "ЧГ=")
+ " "
+ СтрЗаменить(ЧислоПрописью(КоличествоЛистовВсего, "НП=Истина, НД=Ложь", "лист, листа, листов, м, , , , ,0"),
ЧислоПрописью(КоличествоЛистовВсего, "НП=Ложь, НД=Ложь", " , , , , , , , ,0"),
"");
НовРис.Текст = ТекСтр.Объект + Символы.ПС + "(" + ТекстЛистовВсего + ")";
НовРис.ГоризонтальноеПоложение = ГоризонтальноеПоложение.Центр;
НовРис.ВертикальноеПоложение = ВертикальноеПоложение.Центр;
НовРис.Имя = "Лист" + Формат(Инд, "ЧН=0; ЧГ=");
Если СоответствиеЛистовСписку.Свойство(НовРис.Имя) Тогда
СоответствиеЛистовСписку.Удалить(НовРис.Имя);
КонецЕсли;
СоответствиеЛистовСписку.Вставить(НовРис.Имя, ТекСтр.ПолучитьИдентификатор());
НовРис.Защита = Истина;
КонецЦикла;
Иначе
Элементы.ИтоговаяТаблица.ТолькоПросмотр = Истина;
ТД = Новый ТабличныйДокумент;
КолСтрокВГруппе = СписокОбъектовДляПечати.Количество();
Отступ = 10;
Интервал = 16;
ШиринаРисунка = 24;
ВысотаРисунка = 30;
РисунковВСтроке = 4;
ТД.Область().ЦветФона = Новый Цвет(255, 251, 240);
Для Инд = 0 По КолСтрокВГруппе - 1 Цикл
ТекСтр = СписокОбъектовДляПечати[Инд];
ТекТаблДок = ПолучитьИзВременногоХранилища(ТекСтр.ТабличныйДокумент);
НовРис = ТД.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Текст);
НовРис.Узор = ТипУзораТабличногоДокумента.Сплошной;
НовРис.ЦветФона = Новый Цвет(255, 255, 205);
Если ТекТаблДок.ОриентацияСтраницы = ОриентацияСтраницы.Портрет Тогда
НовРис.Ширина = ШиринаРисунка;
НовРис.Высота = ВысотаРисунка;
Иначе
НовРис.Ширина = ВысотаРисунка;
НовРис.Высота = ШиринаРисунка;
КонецЕсли;
НовРис.Лево = Отступ + ((Инд % РисунковВСтроке) * (ШиринаРисунка + Интервал)) + Цел((ШиринаРисунка + Интервал - НовРис.Ширина) / 2);
НовРис.Верх = Отступ + ((Цел(Инд / РисунковВСтроке)) * (ВысотаРисунка + Интервал)) + Цел((ВысотаРисунка + Интервал - НовРис.Высота) / 2);
НовРис.ГиперСсылка = Истина;
КоличествоЛистовВсего = ТекТаблДок.КоличествоСтраниц();
ТекстЛистовВсего = Формат(КоличествоЛистовВсего, "ЧГ=")
+ " "
+ СтрЗаменить(ЧислоПрописью(КоличествоЛистовВсего, "НП=Истина, НД=Ложь", "лист, листа, листов, м, , , , ,0"),
ЧислоПрописью(КоличествоЛистовВсего, "НП=Ложь, НД=Ложь", " , , , , , , , ,0"),
"");
НовРис.Текст = ТекСтр.Объект + Символы.ПС + "(" + ТекстЛистовВсего + ")";
НовРис.ГоризонтальноеПоложение = ГоризонтальноеПоложение.Центр;
НовРис.ВертикальноеПоложение = ВертикальноеПоложение.Центр;
НовРис.Имя = "Лист" + Формат(Инд, "ЧН=0; ЧГ=");
Если СоответствиеЛистовСписку.Свойство(НовРис.Имя) Тогда
СоответствиеЛистовСписку.Удалить(НовРис.Имя);
КонецЕсли;
СоответствиеЛистовСписку.Вставить(НовРис.Имя, ТекСтр.ПолучитьИдентификатор());
НовРис.Защита = Истина;
НовЛиния = ТД.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Прямая);
НовЛиния.Линия = Новый Линия(ТипЛинииРисункаТабличногоДокумента.Сплошная, 2);
НовЛиния.ГиперСсылка = Истина;
Если ТекТаблДок.ОриентацияСтраницы = ОриентацияСтраницы.Портрет Тогда
НовЛиния.Ширина = ШиринаРисунка - 0.3;
НовЛиния.Высота = 0.01;
Иначе
НовЛиния.Ширина = ВысотаРисунка - 0.3;
НовЛиния.Высота = 0.01;
КонецЕсли;
НовЛиния.Лево = НовРис.Лево + 0.3;
НовЛиния.Верх = НовРис.Верх + НовРис.Высота;
НовЛиния.Имя = "ЛНПН" + Формат(Инд, "ЧН=0; ЧГ=");
НовЛиния = ТД.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Прямая);
НовЛиния.Линия = Новый Линия(ТипЛинииРисункаТабличногоДокумента.Сплошная, 2);
НовЛиния.ГиперСсылка = Истина;
Если ТекТаблДок.ОриентацияСтраницы = ОриентацияСтраницы.Портрет Тогда
НовЛиния.Ширина = 0.01;
НовЛиния.Высота = ВысотаРисунка - 0.3;
Иначе
НовЛиния.Ширина = 0.01;
НовЛиния.Высота = ШиринаРисунка - 0.3;
КонецЕсли;
НовЛиния.Лево = НовРис.Лево + НовРис.Ширина;
НовЛиния.Верх = НовРис.Верх + 0.3;
НовЛиния.Имя = "ПНПВ" + Формат(Инд, "ЧН=0; ЧГ=");
КонецЦикла;
КонецЕсли;
ИтоговаяТаблица = ТД;
Элементы.ИтоговаяТаблица.ТолькоПросмотр = Истина;
КонецЕсли;
КонецПроцедуры
&НаСервере
Функция ПолучитьМассивОписанийФайловВыгрузки(ВФормате)
СоответствиеФорматаРасширению = Новый Соответствие;
СоответствиеФорматаРасширению.Вставить(ТипФайлаТабличногоДокумента.MXL, "mxl");
СоответствиеФорматаРасширению.Вставить(ТипФайлаТабличногоДокумента.XLS, "xls");
СоответствиеФорматаРасширению.Вставить(ТипФайлаТабличногоДокумента.PDF, "pdf");
МассивОписаний = Новый Массив;
Номер = 0;
Для Каждого Эл Из СписокОбъектовДляПечати Цикл
Если Эл.Пометка Тогда
Номер = Номер + 1;
ИмяОбъктаБезДвоеточий = Эл.ИмяФайлаБезРасширения;
КороткоеИмяФайла = Формат(Номер, "ЧГ=0") + ". " + ИмяОбъктаБезДвоеточий + "." + СоответствиеФорматаРасширению[ВФормате];
ФайлТабличногоДокумента = ПолучитьИмяВременногоФайла();
ТабличныйДокумент = ПолучитьИзВременногоХранилища(Эл.ТабличныйДокумент);
ТабличныйДокумент.Автомасштаб = Истина;
ТабличныйДокумент.Записать(ФайлТабличногоДокумента, ВФормате);
ГУИД = Новый УникальныйИдентификатор;
ДанныеФайла = Новый ДвоичныеДанные(ФайлТабличногоДокумента);
Адрес = ПоместитьВоВременноеХранилище(ДанныеФайла, ГУИД);
ОписаниеФайла = Новый ОписаниеПередаваемогоФайла(КороткоеИмяФайла, Адрес);
МассивОписаний.Добавить(ОписаниеФайла);
КонецЕсли;
КонецЦикла;
Возврат МассивОписаний;
КонецФункции
&НаКлиенте
Процедура ВыгрузитьНаДиск(ВФормате)
ОписаниеОповещения = Новый ОписаниеОповещения("ВыгрузитьНаДискЗавершение", ЭтотОбъект, ВФормате);
ДокументооборотСКОКлиент.ПолучитьКонтекстЭДО(ОписаниеОповещения);
КонецПроцедуры
&НаКлиенте
Функция КоличествоВыбранныхТабличныхДокументов()
Кол = 0;
Для Каждого Стр Из СписокОбъектовДляПечати Цикл
Кол = Кол + ?(Стр.Пометка, 1, 0);
КонецЦикла;
Возврат Кол;
КонецФункции
&НаСервереБезКонтекста
Функция ТранспортноеСообщениеСУказаннымВложением(ЦиклОбмена, ИмяВложения)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ РАЗЛИЧНЫЕ
| СодержимоеТранспортныхКонтейнеров.ТранспортноеСообщение
|ИЗ
| РегистрСведений.СодержимоеТранспортныхКонтейнеров КАК СодержимоеТранспортныхКонтейнеров
|ГДЕ
| СодержимоеТранспортныхКонтейнеров.ТранспортноеСообщение.ЦиклОбмена = &ЦиклОбмена
| И СодержимоеТранспортныхКонтейнеров.ИмяФайла = &ИмяФайла";
Запрос.УстановитьПараметр("ИмяФайла", ИмяВложения);
Запрос.УстановитьПараметр("ЦиклОбмена", ЦиклОбмена);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
Возврат ВыборкаДетальныеЗаписи.ТранспортноеСообщение;
КонецЦикла;
КонецФункции
&НаКлиенте
Процедура ВыгрузитьНаДискЗавершение(Результат, ВФормате) Экспорт
КонтекстЭДОКлиент = Результат.КонтекстЭДО;
Если КонтекстЭДОКлиент = Неопределено Тогда
Возврат;
КонецЕсли;
Если КоличествоВыбранныхТабличныхДокументов() = 0 Тогда
ПоказатьПредупреждение(,"Выберите листы в дереве печатаемых листов!");
Иначе
МассивОписанийПолучаемыеФайлы = ПолучитьМассивОписанийФайловВыгрузки(ВФормате);
#Если ВебКлиент Тогда
ЭтоВеб = Истина;
#Иначе
ЭтоВеб = Ложь;
#КонецЕсли
Если ЭтоВеб ИЛИ МассивОписанийПолучаемыеФайлы.Количество() > 1 Тогда
ОперацииСФайламиЭДКОКлиент.СохранитьФайлы(МассивОписанийПолучаемыеФайлы);
Иначе
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение);
Диалог.Заголовок = "Сохранение протокола";
Диалог.ПредварительныйПросмотр = Истина;
Шаблон = "Файл в формате (*.%1)|*.%1";
Фильтр = СтрШаблон(Шаблон, НРег(Строка(ВФормате)));
Диалог.Фильтр = Фильтр;
ОписаниеОповещения = Новый ОписаниеОповещения();
НачатьПолучениеФайлов(ОписаниеОповещения, МассивОписанийПолучаемыеФайлы, Диалог);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ИтоговаяТаблицаОбработкаРасшифровкиЗавершение(Результат, Расшифровка) Экспорт
КонтекстЭДОКлиент = Результат.КонтекстЭДО;
Если КонтекстЭДОКлиент = Неопределено Тогда
Возврат;
КонецЕсли;
ТранспортноеСообщение = ТранспортноеСообщениеСУказаннымВложением(ЦиклОбмена, Расшифровка);
Если ЗначениеЗаполнено(ТранспортноеСообщение) Тогда
КонтекстЭДОКлиент.ПоказатьПротоколПриложениеПФР(ТранспортноеСообщение, Расшифровка);
КонецЕсли;
КонецПроцедуры
#КонецОбласти