Как реализовать выбор даты с относительными периодами на управляемой форме 1С?

Программист 1С v8.3 (Управляемые формы) 1С:Документооборот IT и автоматизация бизнеса
← На главную

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

Разберем по шагам, какие инструменты платформы «1С:Предприятие 8.3» позволяют решить данную задачу, как устроен специализированный тип данных и как правильно организовать хранение выбранных настроек в базе данных.

Особенности платформенного типа «СтандартнаяДатаНачала»

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

Рассмотрим структуру данного объекта. У него есть два ключевых свойства:

  1. Вариант — содержит значение системного перечисления ВариантСтандартнойДатыНачала (например, НачалоЭтогоДня, НачалоЭтойНедели, НачалоЭтогоМесяца, НачалоЭтогоГода, ПроизвольнаяДата и другие).
  2. Дата — результирующее календарное значение. Если выбран вариант ПроизвольнаяДата, то свойство содержит явно введенную пользователем дату. Если выбран любой относительный вариант, платформа рассчитывает и возвращает актуальную дату на текущий момент времени.

Способ 1. Использование реквизита формы типа «СтандартнаяДатаНачала»

Проанализируем базовый сценарий реализации интерфейса, полностью повторяющего поведение отбора СКД.

Пошаговый порядок действий в конфигураторе:

  1. Открываем нужную управляемую форму.
  2. На вкладке Реквизиты добавляем новый реквизит формы (например, с именем ПериодОтчета или ДатаФильтра).
  3. В свойствах реквизита в поле Тип указываем тип СтандартнаяДатаНачала.
  4. Перетаскиваем созданный реквизит в дерево элементов формы. Платформа автоматически создаст элемент управления Поле ввода.

В пользовательском режиме такое поле ввода предоставляет стандартную кнопку выбора. При нажатии на нее открывается системное выпадающее меню со списком предустановленных относительных значений. Если пользователь выбирает конкретную дату, он переключается в режим произвольной даты и выбирает значение из календаря.

Посмотрим на пример программной инициализации реквизита при открытии формы:


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

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


&НаСервере
Процедура ВыполнитьОбработкуДанных()
    ФактическаяДата = ДатаФильтра.Дата;
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Данные.Ссылка КАК Ссылка
        |ИЗ
        |   Документ.ВходящийДокумент КАК Данные
        |ГДЕ
        |   Данные.Дата >= &ДатаНачала";
    Запрос.УстановитьПараметр("ДатаНачала", ФактическаяДата);
    // Выполнение запроса...
КонецПроцедуры

Хранение значения в базе данных

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

  1. Хранение только рассчитанного момента времени: если пользователю достаточно сохранить саму дату, реквизит объекта или настройки создается со стандартным типом Дата. При записи в него помещается значение РеквизитФормы.Дата. При этом при следующем открытии формы значение восстановится как конкретная дата, а не как динамический сдвиг.
  2. Хранение относительного алгоритма в виде строки: если требуется, чтобы при каждом открытии формы дата сдвигалась (например, оставалась «Началом этого месяца»), имя варианта сохраняют в строковом реквизите.

Разберем пример сохранения и восстановления относительного варианта через строковое представление перечисления:


&НаСервере
Процедура СохранитьНастройкуВРеквизитСтроки(СтроковыйРеквизит)
    СтроковыйРеквизит = XMLСтрока(ДатаФильтра.Вариант);
КонецПроцедуры

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

Также объект СтандартнаяДатаНачала поддерживает сериализацию XDTO, благодаря чему структуру можно сохранить в реквизит с типом ХранилищеЗначения или преобразовать в XML через СериализаторXDTO.

Способ 2. Обычное поле даты со списком быстрого выбора

Если нет необходимости использовать отдельный составной объект платформы, аналогичное поведение можно смоделировать на стандартном реквизите типа Дата. Для этого у поля ввода на форме настраивается список выбора:

  1. У элемента формы включаем свойство РежимВыбораИзСписка в значение Истина или настраиваем кнопку выбора.
  2. Заполняем свойство элемента СписокВыбора текстовыми представлениями периодов.
  3. В обработчике ПриИзменении рассчитываем фактическую дату с помощью стандартных встроенных функций.

Посмотрим на пример заполнения списка выбора и вычисления значений:


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    Элементы.ПолеДата.СписокВыбора.Очистить();
    Элементы.ПолеДата.СписокВыбора.Добавить("НачалоДня", "Начало этого дня");
    Элементы.ПолеДата.СписокВыбора.Добавить("НачалоНедели", "Начало этой недели");
    Элементы.ПолеДата.СписокВыбора.Добавить("НачалоМесяца", "Начало этого месяца");
КонецПроцедуры

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

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

← На главную