При разработке различных конфигураций мы у себя в команде часто сталкиваемся с необходимостью простого и быстрого размещения большого количества реквизитов метаданных (справочников, документов) на форму, обычно это касается различных настроечных опций или параметров. Конечно, можно вручную их разместить на форму или программно (динамически) создать элементы управляемой формы, но это все варианты, которые загромождают форму, усложняют пользовательскую работу с ней. А главное зачем, если решение давно было придумано - размещение реквизитов в виде дерева (TreeView). Дерево позволяет структурировать параметры/опции/настройки/реквизиты, удобно с ними работать. А ещё будет так - добавил в метаданные реквизит и он уже сразу доступен в 1С:Предприятие для редактирования/просмотра пользователю/администратору.
Как же подобное организовано в типовых? Например, в типовой Розница, редакция 2.3 для подобного используется - ПланВидовХарактеристик: НастройкиПользователей, Справочник: Пользователей и регистр сведений: НастройкиПользователей. Там это обусловлено тем, что необходимо для пересечения Магазин, Пользователь определить его настройки. Однако, в случае, если у Вас настройки только для пользователя или только для магазина, то смысла использовать ПВХ нет, оно только усложняет запросы (в предлагаемом решении вся информация хранится в одном справочнике/документе, следовательно и запрос выполняется только к одной таблице).
Итак, сразу покажем результат универсального механизма из нашей подсистемы EDIbot (быстрое создание реактивных веб приложений/B2B-порталов/сайтов/Dashboard), который достигнем кодом публикации:
Рассмотрим по шагам, как такое Вам сделать в конфигурации:
1. Вы как обычно создаете/добавляете реквизиты метаданных к Вашему объекту, НО в стандартном поле "Комментарий" указываете Имя группы реквизита. Причем для создания подгрупп имя группы можно указать с точкой, например, "Общие.Масштабирование", вот пример:
2. Далее, добавляем Дерево значений в реквизиты формы и размещаем его на форме
3. Заполняем наше дерево на клиенте, в процедуре при открытии:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
ЗаполнитьДеревоПараметров(_ВебАппСеанса.ПолучитьСписокРеквизитовДереваПараметров("Справочники._ВебАппСтраницы"));
КонецПроцедуры
4. Как видно, мы передаем нашей функции по заполнению реквизиты для построения дерева, опишем эту функцию: ПолучитьСписокРеквизитовДереваПараметров и как раз именно здесь мы будем использовать наш комментарий к реквизиту метаданных как структуру дерева (группы/подгруппы).
Функция ПолучитьСписокРеквизитовДереваПараметров(ИмяМД) экспорт
Реквизиты = Новый Структура();
МД = Вычислить("Метаданные."+ИмяМД);
Для Каждого Реквизит Из МД.Реквизиты Цикл
Если ПустаяСтрока(Реквизит.Комментарий) Тогда
Продолжить;
КонецЕсли;
Реквизиты.Вставить(Реквизит.Имя, Новый Структура("Группа, ИмяПараметра, Представление, Подсказка, Тип", Реквизит.Комментарий, Реквизит.Имя, Реквизит.Синоним, Реквизит.Подсказка, Реквизит.Тип));
КонецЦикла;
Возврат Реквизиты;
КонецФункции
5. Теперь все готово, чтобы описать нашу процедуру по заполнению дерева:
&НаКлиенте
Процедура ЗаполнитьДеревоПараметров(Реквизиты)
ИндексДереваПараметров = Новый Соответствие();
ДеревоПараметров = ДеревоПараметровФорма.ПолучитьЭлементы();
ДеревоПараметров.Очистить();
Для Каждого Элемент Из Реквизиты Цикл
Реквизит = Элемент.Значение;
Если ПустаяСтрока(Реквизит.Группа) Тогда
Продолжить;
КонецЕсли;
ДобавитьПараметрВДерево(ДеревоПараметров, Реквизит);
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Функция ДобавитьПараметрВДерево(ДеревоПараметров, Реквизит)
МассивСвойств = СтрРазделить(Реквизит.Группа, ".");
ГруппаДерева = ДеревоПараметров;
Для Ном=0 По МассивСвойств.Количество()-1 Цикл
ИмяГруппы = МассивСвойств[Ном];
СтрокаДерева = ИндексДереваПараметров.Получить(ИмяГруппы);
Если СтрокаДерева=Неопределено Тогда
СтрокаДерева = ГруппаДерева.Добавить();
СтрокаДерева.ИмяПараметра = ИмяГруппы;
СтрокаДерева.Представление = ИмяГруппы;
СтрокаДерева.ЭтоГруппа = Истина;
ИндексДереваПараметров.Вставить(ИмяГруппы, СтрокаДерева);
КонецЕсли;
ГруппаДерева = СтрокаДерева.ПолучитьЭлементы();
КонецЦикла;
НоваяСтрока = ГруппаДерева.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, Реквизит);
НоваяСтрока.ЗначениеПараметра = Объект[Реквизит.ИмяПараметра];
ИндексДереваПараметров.Вставить(Реквизит.ИмяПараметра, НоваяСтрока);
Возврат НоваяСтрока;
КонецФункции
Известно, что объект типа ДанныеФормыДерево не имеет функции Найти или НайтиСтроки, а обход дерева дорогостоящая операция, поэтому в функции ДобавитьПараметрВДерево мы используем индексацию строк дерева формы по параметру (добавляем в соответствие ИндексДереваПараметров соответствие строки дерева имени параметра).
Итак, мы с Вами сделали вывод всех наших реквизитов на управляемую форму, у которых заполнено поле "Комментарий" (т.е. реквизит отнесен к какой-либо группе дерева настроек).
Теперь возникает вопрос, а как редактировать особо сложные реквизиты, как сделать сохранение реквизитов в базу данных?
Для сохранения изменений, сделанных на форме, в объект мы с Вами добавим обработку события ПриИзменении значения параметра:
&НаКлиенте
Процедура ДеревоПараметровФормаЗначениеПараметраПриИзменении(Элемент)
СтрокаТЧ = Элементы.ДеревоПараметровФорма.ТекущиеДанные;
Если СтрокаТЧ=Неопределено Тогда
Возврат;
КонецЕсли;
Объект[СтрокаТЧ.ИмяПараметра] = СтрокаТЧ.ЗначениеПараметра;
Если СтрокаТЧ.ИмяПараметра="РабочийКаталог" Тогда
ОбновитьПовторноИспользуемыеЗначения();
Записать();
ИначеЕсли СтрокаТЧ.ИмяПараметра="СпособМасштабирования" И СтрокаТЧ.ЗначениеПараметра="font-size" Тогда
УстановитьЗначениеПараметра("ЦельМасштабирования", "");
КонецЕсли;
КонецПроцедуры
Как видно, в процедуре мы устанавливаем ЦельМасштабирования, равное пустому значению при значении СпособМасштабирования="font-size" с помощью функции УстановитьЗначениеПараметра, вот ее код:
&НаКлиенте
Процедура УстановитьЗначениеПараметра(ИмяПараметра, ЗначениеПараметра)
СтрокаДерева = ИндексДереваПараметров.Получить(ИмяПараметра);
Если СтрокаДерева=Неопределено Тогда
Возврат;
КонецЕсли;
СтрокаДерева.ЗначениеПараметра = ЗначениеПараметра;
Объект[ИмяПараметра] = ЗначениеПараметра;
КонецПроцедуры
Обратите внимание, как это было реализовано: здесь мы опять использовали быстрый поиск строки дерева формы по имени параметра.
А для обработки каких-то специфических реквизитов, например, выбор каталога добавляем обработку события НачалоВыбора
&НаКлиенте
Процедура ДеревоПараметровФормаЗначениеПараметраНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
СтрокаТЧ = Элементы.ДеревоПараметровФорма.ТекущиеДанные;
Если СтрокаТЧ=Неопределено Тогда
Возврат;
КонецЕсли;
Если СтрокаТЧ.ИмяПараметра="РабочийКаталог" Тогда
ВыборКаталога(Элемент, СтрокаТЧ.ИмяПараметра);
КонецЕсли;
КонецПроцедуры
Однако, бывает, что нужно решить еще одну задачку - ограничить те типы, которые пользователь может выбирать при редактировании значения параметра.
Например, выбор из определенного списка или ограничение доступности изменения реквизитов при определенных условиях.
Будем реализовывать это с помощью обработки события ПередНачаломИзменения:
&НаКлиенте
Процедура ДеревоПараметровФормаПередНачаломИзменения(Элемент, Отказ)
СтрокаТЧ = Элементы.ДеревоПараметровФорма.ТекущиеДанные;
Если СтрокаТЧ=Неопределено Тогда
Возврат;
КонецЕсли;
Если НЕ Элемент.ТекущийЭлемент.Имя="ДеревоПараметровФормаЗначениеПараметра" Тогда
Отказ = Истина;
Возврат;
КонецЕсли;
Реквизиты = _ВебАппСеанса.ПолучитьСписокРеквизитовДереваПараметров("Справочники._ВебАппСтраницы");
Элемент.ТекущийЭлемент.ОграничениеТипа = Реквизиты[СтрокаТЧ.ИмяПараметра].Тип;
Элемент.ТекущийЭлемент.РежимВыбораИзСписка = Ложь;
Элемент.ТекущийЭлемент.КнопкаВыбора = Истина;
Элемент.ТекущийЭлемент.СписокВыбора.Очистить();
Если СтрокаТЧ.ИмяПараметра="СпособМасштабирования" Тогда
Элемент.ТекущийЭлемент.РежимВыбораИзСписка = Истина;
Элемент.ТекущийЭлемент.СписокВыбора.Добавить("scale");
Элемент.ТекущийЭлемент.СписокВыбора.Добавить("font-size");
ИначеЕсли СтрокаТЧ.ИмяПараметра="ЦельМасштабирования" Тогда
Отказ = НЕ (Объект.СпособМасштабирования="scale");
ИначеЕсли СтрокаТЧ.ИмяПараметра="Актуальность" Тогда
Отказ = Истина;
ИначеЕсли СтрокаТЧ.ИмяПараметра="ВывестиНаРабочийСтол" Тогда
Элемент.ТекущийЭлемент.РежимВыбораИзСписка = Истина;
_ОбщегоНазначенияКлиентСервер.СкопироватьСписок(Элемент.ТекущийЭлемент.СписокВыбора, _ВебАппДанныеСеанса.СписокСтраницРабочегоСтола());
КонецЕсли;
КонецПроцедуры
Ну вот теперь точно всё - мы сделали универсальный механизм для вывода любого количества реквизитов метаданных с автоматической их группировкой, возможностью редактирования, а также сложной обработкой их зависимостей между собой.
Надеюсь, моя публикация была Вам полезна и сэкономит Ваше время, ссылка на все публикации SizovE.
Подписывайтесь на мой канал (наверху), будет много интересного бесплатного контента :)