Текст задачи:
В конфигурацию необходимо добавить справочник "Планерки" с реквизитами: начало встречи, окончание встречи и организатор (ссылка на спр. Физлица). В форме элемента реализовать список с участниками встречи (реализовать подбор незанятых на указанное время планерки сотрудников) с возможностью обновлять информацию об участниках без перезаписи самого элемента справочника. У каждого участника должна отображаться иконка, фамилия и должность.
Также организатор встречи должен выбираться из списка участников и после выбора выделяться в списке как организатор; в списке должна отображаться информация о том, кто из участников уже подтвердил свое участие на встрече (информация должна обновляться интерактивно – по кнопке).
ВАЖНО: количество реквизитов справочника ограничено списком из первого предложения. Запрещено изменять режим использования модальности (по умолчанию "не использовать").
Для упрощения буду использовать пустую конфигурацию, лишь добавлю справочник "ФизическиеЛица" и типовую картинку "КонтрагентФЛ2", которая пригодится нам для списка участников. Создаем справочник с указанными реквизитами и форму элемента. Поскольку сказано, что список участников на форме не может быть реквизитом, при этом нужна отметка "участия", интерактивное изменение представления сотрудника (организатор / не организатор) и картинка, то сразу же на ум приходит воспользоваться Списком значений. Добавляем на форму СписокЗначений "Участники", свойство реквизита "Тип значения" - СправочникСсылка.ФизическиеЛица. Поскольку нам все равно придется где-то хранить актуальные данные по участникам планерки, предлагаю создать независимый непериодический регистр сведений "СотрудникиНаПланерках"
(измерения "Планерка" и "Сотрудник" - ссылки на соответствующее справочники, ресурс - ПодтвердилУчастие (булево)).
Поскольку нам необходимо интерактивно изменять список на форме, добавляем две кнопки: "Подобрать участников" и "Обновить". Первая будет открывать окно подбора, требуемое по заданию, вторая – актуализировать информацию из регистра сведений. Для первой кнопки создаем клиентскую процедуру, в ней вызываем функцию, чтобы получить СписокЗначений доступных для выбора сотрудников. Выполняем контроль на пустой список и вызываем метод СпискаЗначений ПоказатьОтметкуЭлементов(). Данный метод откроет окно для множественного выбора из сформированного списка (если бы не было ограничения модальных окон, тогда можно было воспользоваться методом ОтметитьЭлементы() и обойтись без ОписанияОповещения):
[&НаКлиенте
Процедура ПодобратьУчастников(Команда)
СписокДоступныхУчастников = СписокДоступныхУчастников(Объект.ВремяНачала, Объект.ВремяОкончания, Участники, Объект.Ссылка);
Если СписокДоступныхУчастников.Количество() > 0 Тогда
Оповещение = Новый ОписаниеОповещения("ВыполнитьВыборИзСписка", ЭтотОбъект);
СписокДоступныхУчастников.ПоказатьОтметкуЭлементов(Оповещение, "Выберите участников планерки");
Иначе
ПоказатьПредупреждение(, "Все сотрудники заняты");
КонецЕсли;
КонецПроцедуры]
В серверную функцию мы передадим параметры, необходимые для получения запросом свободных сотрудников на время текущей встречи.
В функции запросом сначала отбираем всех занятых сотрудников на параллельных встречах, а затем формируем список всех сотрудников исключая занятых. Затем через выборку добавляем к уже выбранным ранее сотрудникам тех, которые доступны для выбора. Не забываем при этом подменять представление, чтобы отображать их должность. Для наглядности, в учебных целях еще можно отсортировать полученный список по представлению элементов. Вернемся к ОписаниюОповещения - его нужно обработать.
Создаем экспортную клиентскую процедуру ВыполнитьВыборИзСписка:
[&НаКлиенте
Процедура ВыполнитьВыборИзСписка(СписокСотрудников, Параметры) Экспорт
Если СписокСотрудников = Неопределено Тогда
Возврат;
КонецЕсли;
Для Каждого СтрокаСотрудника Из СписокСотрудников Цикл
ИскомыйУчастник = Участники.НайтиПоЗначению(СтрокаСотрудника.Значение);
Если СтрокаСотрудника.Пометка И ИскомыйУчастник = Неопределено Тогда //Добавляем отмеченных
Участники.Добавить(СтрокаСотрудника.Значение,СтрокаСотрудника.Представление,,СтрокаСотрудника.Картинка);
ИначеЕсли Не СтрокаСотрудника.Пометка И ИскомыйУчастник <> Неопределено Тогда //Удаляем неотмеченных
Участники.Удалить(ИскомыйУчастник);
КонецЕсли;
КонецЦикла;
КонецПроцедуры]
В ней мы перезаполняем список на форме, исходя из данных выбора. Теперь можно заняться Организатором. Нам потребуется событие элемента "НачалоВыборка". Создаем клиентскую процедуру "ОрганизаторНачалоВыбора". В ней отключаем стандартную обработку, чтобы не вызывать типовую форму выбора списка Физлиц, делаем проверку на заполненность списка участников и вызываем немодальный метод списка ПоказатьВыборЭлемента() для выбора организатора из перечня участников:
[&НаКлиенте
Процедура ОрганизаторНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
Если Участники.Количество() = 0 Тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Организатора можно будет выбрать после заполнения списка участников";
Сообщение.Сообщить();
Иначе
Оповещение = Новый ОписаниеОповещения("ОбработкаВыбораОрганизатора", ЭтотОбъект);
Участники.ПоказатьВыборЭлемента(Оповещение, "Выберите организатора планерки");
КонецЕсли;
КонецПроцедуры]
И снова требуется вызывать и обрабатывать оповещение. Для него создадим экспортную клиентскую процедуру "ОбработкаВыбораОрганизатора". В ней выбранный участник заполняет соответствующий реквизит "Организатор" и в списке методом НайтиПоЗначению() находим строчку этого участника и подменяем представление, добавив статус организатора мероприятия (а так же нужно не забыть затереть статус предыдущего организатора, если таковой был):
[&НаКлиенте
Процедура ОбработкаВыбораОрганизатора(ВыбранноеЗначение, Параметры) Экспорт
Если ВыбранноеЗначение = Неопределено Тогда
Возврат;
КонецЕсли;
ПодстрокаОрганизатор = " - организатор";
Если ЗначениеЗаполнено(Объект.Организатор) Тогда
СтарыйОрганизатор = Участники.НайтиПоЗначению(Объект.Организатор);
СтарыйОрганизатор.Представление = СтрЗаменить(СтарыйОрганизатор.Представление, ПодстрокаОрганизатор, ""); //снимаем старого организатора в списке
Объект.Организатор = ПредопределенноеЗначение("Справочник.ФизическиеЛица.ПустаяСсылка");
КонецЕсли;
ВыбранноеЗначение.Представление = ?(СтрНайти(ВыбранноеЗначение.Представление, ПодстрокаОрганизатор,НаправлениеПоиска.СКонца) = 0,
ВыбранноеЗначение.Представление + ПодстрокаОрганизатор,
ВыбранноеЗначение.Представление); //назначаем нового организатора в списке
Объект.Организатор = ВыбранноеЗначение.Значение;
КонецПроцедуры]
Теперь необходимо при записи справочника сохранять данные участников. Буду это делать в событии "ПослеЗаписи". Создаю соответствующую клиентскую процедуру и вызываю из нее не контекстную серверную:
[&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
ПослеЗаписиНаСервере(Объект.Ссылка, Участники.ВыгрузитьЗначения());
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ПослеЗаписиНаСервере(Планерка, УчастникиМассив)
НаборЗаписей = РегистрыСведений.СотрудникиНаПланерках.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Планерка.Установить(Планерка);
НаборЗаписей.Прочитать();
Для Каждого СтрокаНабора Из НаборЗаписей Цикл
Если УчастникиМассив.Найти(СтрокаНабора.Сотрудник) = Неопределено Тогда
НаборЗаписей.Удалить(СтрокаНабора);
КонецЕсли;
КонецЦикла;
МассивСотрудниковНабора = НаборЗаписей.ВыгрузитьКолонку("Сотрудник");
Для Каждого Участник Из УчастникиМассив Цикл
Если МассивСотрудниковНабора.Найти(Участник) = Неопределено Тогда
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Планерка = Планерка;
НоваяЗапись.Сотрудник = Участник;
КонецЕсли;
КонецЦикла;
НаборЗаписей.Записать();
КонецПроцедуры]
В процедурах получаем набор записей, удаляем неактуальные и добавляем новые, после чего записываем. Данные записываются, но теперь нужно видеть информацию о тех, кто подтвердил присутствие на встрече из формы элемента. Получать эту информацию пользователь будет по кнопке "Обновить" из РС "СотрудникиНаПланерках". Не сказано как именно пользователь подтверждает свое участие, поэтому буду симулировать этот процесс в ручную проставляю соответсвующий флажок в записях регистра. Обрабатываем нажатие кнопки, создаем процедуры "Обновить" и "ОбновитьНаСервере" с соответствующими директивами компиляции.
[&НаКлиенте
Процедура Обновить(Команда)
ОбновитьНаСервере();
КонецПроцедуры
&НаСервере
Процедура ОбновитьНаСервере()
КартинкаДляСписка = БиблиотекаКартинок.КонтрагентФЛ2;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СотрудникиНаПланерках.ПодтвердилУчастие,
| ФизическиеЛица.Ссылка,
| ФизическиеЛица.Должность,
| ФизическиеЛица.Представление
|ИЗ
| РегистрСведений.СотрудникиНаПланерках КАК СотрудникиНаПланерках
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ФизическиеЛица КАК ФизическиеЛица
| ПО СотрудникиНаПланерках.Сотрудник = ФизическиеЛица.Ссылка
|ГДЕ
| СотрудникиНаПланерках.Планерка = &Планерка";
Запрос.УстановитьПараметр("Планерка", Объект.Ссылка);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
ИскомыйУчастник = Участники.НайтиПоЗначению(Выборка.Ссылка);
Если ИскомыйУчастник = Неопределено Тогда
Представление = СтрШаблон("%1 (%2)",Выборка.Представление,Выборка.Должность);
Участники.Добавить(Выборка.Ссылка,Представление,Выборка.ПодтвердилУчастие,КартинкаДляСписка);
Иначе
ИскомыйУчастник.Пометка = Выборка.ПодтвердилУчастие;
КонецЕсли;
КонецЦикла;
КонецПроцедуры]
Для удобства "ПриСозданииНаСервере" формы тоже будем отображать актуальный данные по списку:
[&НаСервере
Процедура ПриСозданииНаСервере(Отказ)
ОбновитьНаСервере();
Если ЗначениеЗаполнено(Объект.Организатор) Тогда
Организатор = Участники.НайтиПоЗначению(Объект.Организатор);
Если Организатор <> Неопределено Тогда
Организатор.Представление = СтрШаблон("%1 - организатор", Организатор.Представление);
КонецЕсли;
КонецЕсли;
КонецПроцедуры]
Теперь попробуем протестировать функционал. Создам новую планерку, заполняем время проведения и жмем «Подобрать участников».
В открывшемся окне выберем директора и двух разработчиков.
Теперь, после переноса выбранных сотрудников в список на форму, можно выбрать Организатора встречи, пусть это будет директор.
После выбора Организатора у директора соответствующим образом меняется представление в списке
Запишем справочник и посмотрим на записи регистра сведений. Для учебных целей добавил гиперссылку на записи регистра связанные с текущим справочником, чтобы можно было изменить записи РС без выхода из формы справочника (свойство "Ведущее" у соответствующего измерения регистра). Пусть директор примет приглашение первым, перезапишем его запись, проставив флаг участия.
Вернемся на основную вкладку формы и нажмем Обновить. Флаг у директора успешно поставился. Аналогичный результат будет при повторном открытии формы элемента.
Если попытаться создать другую встречу с пересечением по времени, при подборе участников наложится отбор и отобразятся только свободные сотрудники.
Готово! В форме реализован функционал подбора участников встречи, используя только указанные в задании реквизиты. Конечно, воспользоваться ТаблицейЗначений было бы удобнее, но данный вариант может подойти например для АРМ интерфейсов высоконагруженных систем, где открытие списков выбора может занять длительное время или для ограничения функциональности сотрудника (минималистичный интерфейс позволит быстро обучить сотрудника).
В материале рассмотрели основные методы коллекции СпискаЗначений, для закрепления:
- ПоказатьОтметкуЭлементов() (ОтметитьЭлементы() если модально) — открывает интерактивное окно для проставления отметок списка значений
- ПоказатьВыборЭлемента() (ВыбратьЭлемент() если модально) — вызывает окно для интерактивного выбора одного из элементов списка значений
- Количество() — получает количество элементов списка значений
- НайтиПоЗначению() — осуществляет поиск элемента списка по его значению. Возвращает ЭлементСпискаЗначений или Неопределено
- Добавить() — добавляет новый элемент с возможностью указать значение, представление, отметку и картинку
- Удалить() — удаляет элемент из списка. В параметрах метода указывается либо сам элемент, либо его индекс.
- Скопировать() — создает на основании указанного списка значений новый список с данными исходного.
- ЗаполнитьПометки() — проставляет или снимает флаг у всех списка разом в зависимости от параметра метода.
- СортироватьПоПредставлению() — сортирует элементы списка по алфавиту в зависимости от параметра метода по убыванию или возрастанию.
Автор: Егор М., разработчик 1С.
*Приложенная конфигурация тестировалась на релизе платформы 8.3.17.1496.