Как установить отбор по пользователю в списках документов на разных страницах формы

Программист 1С v8.3 (Обычные формы)
← На главную

При разработке интерфейсов в «1С:Предприятие 8» (особенно в режиме обычных форм) часто возникает задача ограничить видимость данных в списках документов. Типичный сценарий — когда на одной форме расположены несколько закладок (страниц), и на каждой из них находится свой список документов (например, заказы, счета, реализации). Нам необходимо сделать так, чтобы текущий пользователь видел только те документы, где он указан как ответственный. В этой статье мы подробно разберем, как реализовать такой функционал программно.

Постановка задачи и анализ стандартного подхода

Рассмотрим ситуацию: у нас есть форма с объектом типа Панель, на которой размещено несколько страниц. На каждой странице находится элемент управления ТабличноеПоле, данные которого связаны с различными списками документов. Нам нужно применить отбор по полю Ответственный, используя значение из ПараметрыСеанса.ТекущийПользователь.

Стандартный код для установки отбора в процедуре ПередОткрытием выглядит следующим образом:


Процедура ПередОткрытием(Отказ, СтандартнаяОбработка)
    
    // Установка отбора для основного списка формы
    ЭтаФорма.ДокументСписок.Отбор.Ответственный.ВидСравнения = ВидСравнения.Равно;
    ЭтаФорма.ДокументСписок.Отбор.Ответственный.Значение = ПараметрыСеанса.ТекущийПользователь;
    ЭтаФорма.ДокументСписок.Отбор.Ответственный.Использование = Истина;
    
    // Запретим пользователю менять отбор вручную через настройку списка
    ЭлементыФормы.ДокументСписок.НастройкаОтбора.Ответственный.Доступность = Ложь;
    
КонецПроцедуры

Проанализируем проблему: если на форме несколько независимых списков документов (разные реквизиты формы типа ДокументСписок.ИмяДокумента), то обращение напрямую к ДокументСписок сработает только для одного, основного списка. Если мы хотим управлять отборами на разных страницах, нам нужно определить, какой именно список сейчас активен или инициализировать их все сразу.

Решение 1: Использование события ПриСменеСтраницы

Этот метод наиболее гибок, если списки на страницах тяжелые и мы хотим устанавливать отбор только в тот момент, когда пользователь переключается на конкретную закладку. Мы воспользуемся событием панели ПриСменеСтраницы. Это позволит нам динамически определять, какая страница активирована, и обращаться к соответствующему элементу управления.

Разберем по шагам, как это реализовать:

  1. Перейдем в свойства панели, на которой расположены ваши страницы.
  2. Найдем событие ПриСменеСтраницы и создадим обработчик.
  3. Внутри обработчика напишем логику выбора списка.

Процедура ОсновнаяПанельПриСменеСтраницы(Элемент, ТекущаяСтраница)
    
    // Получаем имя текущей страницы
    ИмяСтраницы = ТекущаяСтраница.Имя;
    
    // В зависимости от имени страницы устанавливаем отбор для нужного списка
    Если ИмяСтраницы = "СтраницаЗаказы" Тогда
        
        Отбор = ЭлементыФормы.СписокЗаказов.Отбор;
        УстановитьОтборПоОтветственному(Отбор);
        
    ИначеЕсли ИмяСтраницы = "СтраницаРеализации" Тогда
        
        Отбор = ЭлементыФормы.СписокРеализаций.Отбор;
        УстановитьОтборПоОтветственному(Отбор);
        
    КонецЕсли;
    
КонецПроцедуры

Процедура УстановитьОтборПоОтветственному(ОбъектОтбора)
    
    Если ОбъектОтбора.Найти("Ответственный") <> Неопределено Тогда
        ОбъектОтбора.Ответственный.ВидСравнения = ВидСравнения.Равно;
        ОбъектОтбора.Ответственный.Значение = ПараметрыСеанса.ТекущийПользователь;
        ОбъектОтбора.Ответственный.Использование = Истина;
    КонецЕсли;
    
КонецПроцедуры

В данном примере мы создали вспомогательную процедуру УстановитьОтборПоОтветственному, чтобы не дублировать код для каждого списка. Это делает код чище и удобнее для поддержки.

Решение 2: Массовая инициализация всех списков при открытии

Если списков не слишком много (например, 3-5), и они не перегружают систему, лучше всего установить отборы один раз в процедуре ПриОткрытии или ПередОткрытием. Это гарантирует, что пользователь не увидит лишних данных даже на секунду при переключении вкладок.

Проанализируем пример кода, который перебирает все необходимые списки на форме:


Процедура ПриОткрытии()
    
    // Массив имен реквизитов формы, которые являются списками документов
    СписокРеквизитов = Новый Массив;
    СписокРеквизитов.Добавить("ДокументСписокЗаказы");
    СписокРеквизитов.Добавить("ДокументСписокСчета");
    СписокРеквизитов.Добавить("ДокументСписокРеализации");
    
    Для Каждого ИмяСписка Из СписокРеквизитов Цикл
        
        ТекущийСписок = ЭтаФорма[ИмяСписка];
        ТекущийСписок.Отбор.Ответственный.Установить(ПараметрыСеанса.ТекущийПользователь);
        
        // Запрет изменения отбора пользователем через элементы формы
        // Находим элемент управления, связанный с этим списком
        Для Каждого ЭлементУправления Из ЭлементыФормы Цикл
            Если ЭлементУправления.Данные = ИмяСписка Тогда
                ЭлементУправления.НастройкаОтбора.Ответственный.Доступность = Ложь;
            КонецЕсли;
        КонецЦикла;
        
    КонецЦикла;
    
КонецПроцедуры

Важный момент: Мы использовали метод Установить() для объекта отбора. Это сокращенная запись, которая одновременно устанавливает значение, вид сравнения «Равно» и включает использование отбора.

Особенности работы с «Обычными формами» и производительность

При программной установке отборов важно помнить о нескольких технических нюансах:

  1. Индексация полей: Чтобы отбор работал быстро, поле Ответственный в соответствующих документах должно быть индексировано. Проверьте это в конфигураторе: свойство реквизита «Индексировать» должно иметь значение «Индексировать» или «Индексировать с дополнительным упорядочиванием». Без индекса при каждом переключении страницы система будет выполнять полный просмотр таблицы базы данных, что приведет к задержкам.
  2. Свойства связи: В обычных формах у элементов управления типа ТабличноеПоле есть свойства связи. Если вы вынесете поле выбора ответственного в шапку формы, вы можете связать списки с этим полем через свойство «Связь по значению». В этом случае 1С будет фильтровать списки автоматически при изменении значения в шапке без написания кода в ПриСменеСтраницы.

Различия с «Управляемыми формами» (v8.3)

Если вы работаете в современной конфигурации на управляемых формах, подход будет принципиально иным. Вместо ДокументСписок там используется ДинамическийСписок. Отбор в нем устанавливается через коллекцию КомпоновкаДанных.Настройки.Отбор.

Рассмотрим пример для управляемых форм, так как многие современные системы сочетают в себе элементы разных подходов:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Установка фиксированного отбора, который пользователь не сможет удалить
    ЭлементОтбора = СписокЗаказов.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Ответственный");
    ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
    ЭлементОтбора.ПравоеЗначение = ПараметрыСеанса.ТекущийПользователь;
    ЭлементОтбора.Использование = Истина;
    ЭлементОтбора.РежимОтображения = РежимОтображенияЭлементаОтбораКомпоновкиДанных.Недоступный;
    
КонецПроцедуры

В управляемом интерфейсе событие ПриАктивизацииСтраницы (аналог ПриСменеСтраницы) выполняется на клиенте, а установка отборов требует серверного вызова. Поэтому в управляемых формах крайне рекомендуется устанавливать все отборы сразу при создании формы на сервере, чтобы избежать лишних клиент-серверных вызовов при навигации по вкладкам.

Безопасность данных: Программный отбор vs RLS

Выясним важную деталь: программная установка отбора в форме — это инструмент удобства, а не безопасности. Если ваша задача — запретить менеджеру видеть чужие заказы по соображениям конфиденциальности, программного кода в форме недостаточно. Продвинутый пользователь сможет обойти этот отбор через консоль запросов или обработку «Групповая обработка справочников и документов».

Для реального ограничения прав доступа следует использовать механизм RLS (Record Level Security). В этом случае ограничение прописывается в роли пользователя на уровне метаданных. Тогда система сама, на уровне SQL-запроса, будет добавлять условие ГДЕ Ответственный = &ТекущийПользователь. В этом случае никакие дополнительные манипуляции с ПриСменеСтраницы не потребуются — списки во всей программе всегда будут показывать только разрешенные записи.

Итоги

Мы проанализировали ситуацию и выяснили, что для решения задачи на обычных формах наиболее эффективным является использование события ПриСменеСтраницы для динамической настройки или перебор коллекции ЭлементыФормы при открытии для статической настройки всех списков. Выбор конкретного метода зависит от количества данных и требований к производительности вашего решения.

← На главную