Переход с обычных форм (ОФ) на управляемые (УФ) в рамках внедрения современных конфигураций семейства 1С:Предприятие 8.3 (таких как 1С:ERP, 1С:КА или 1С:УТ 11) часто вызывает шквал критики со стороны конечных пользователей. Одной из главных причин недовольства становится изменение привычного поведения поиска в списках, особенно в больших справочниках, таких как Номенклатура.
В этой статье мы подробно проанализируем, почему изменилось поведение платформы, выясним причины неудобства пользователей и разберем по шагам несколько практических способов реализации быстрого поиска «как в УПП» на управляемых формах.
---
Для того чтобы решить задачу, нам необходимо четко понимать физику процессов в обеих технологиях:
Давайте рассмотрим, как можно подружить требования эргономики пользователей с архитектурными особенностями управляемой платформы 1С 8.3.
---
Прежде чем приступать к сложному программированию, рассмотрим возможности, которые платформа 1С предоставляет «из коробки» в последних релизах версии 8.3. Разработчики 1С добавили специальные элементы — дополнения элемента формы для динамических списков.
Выполним простую настройку в конфигураторе:
Номенклатура.Список (динамический список).ПоложениеСтрокиПоиска в значение Вверху (или Авто).Как это работает на практике: Теперь пользователю не нужно предварительно щелкать мышкой в поле поиска. Находясь на любой строке списка, он может сразу начать вводить текст. Фокус ввода автоматически переместится в верхнее поле поиска, и список начнет фильтроваться.
Минусы штатного метода:
LIKE (ПОДОБНО).Если этот вариант категорически не устраивает пользователей, переходим к программным методам эмуляции поведения ОФ.
---
Этот способ позволяет сымитировать поведение обычных форм. Мы создадим на форме свое поле ввода для поиска. При изменении текста в этом поле мы будем программно находить нужную ссылку в базе данных и позиционировать курсор динамического списка на нее, не фильтруя сам список.
Разберем алгоритм по шагам и напишем соответствующий код.
Добавим на форму списка номенклатуры новое поле ввода. Назовем его ПолеБыстрогоПоиска (тип значения — Строка). Установим у него свойство КнопкаОчистки в значение Да.
Для добавленного поля создадим клиентский обработчик события АвтоПодбор или ПриИзменении. В данном примере рассмотрим обработчик АвтоПодбор, так как он срабатывает по мере ввода текста пользователем, что делает поиск «живым».
&НаКлиенте
Процедура ПолеБыстрогоПоискаАвтоПодбор(Элемент, Текст, ДанныеВыбора, Ожидание, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Чтобы не перегружать сервер частыми запросами при быстром наборе,
// анализируем длину введенного текста. Начинаем искать хотя бы от 3-х символов.
Если СтрДлина(Текст) < 3 Тогда
Возврат;
КонецЕсли;
// Вызываем серверную функцию для поиска подходящей ссылки
НайденнаяСсылка = НайтиНоменклатуруНаСервере(Текст);
Если ЗначениеЗаполнено(НайденнаяСсылка) Тогда
// Самый важный момент: переносим курсор списка на найденный элемент,
// при этом сам список НЕ фильтруется, сохраняя весь контекст!
Элементы.Список.ТекущаяСтрока = НайденнаяСсылка;
КонецЕсли;
КонецПроцедуры
Теперь нам нужно написать эффективный поисковый запрос на сервере. Чтобы поиск был быстрым, мы должны искать по индексированным полям (код, артикул или наименование с ограничением по началу строки).
&НаСервереБезКонтекста
Функция НайтиНоменклатуруНаСервере(Знач ТекстПоиска)
Запрос = Новый Запрос;
// Ищем товар, наименование которого НАЧИНАЕТСЯ с введенных символов.
// Это позволяет СУБД использовать индекс по наименованию.
Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| (Номенклатура.Наименование ПОДОБНО &ШаблонПоиска
| ИЛИ Номенклатура.Артикул ПОДОБНО &ШаблонПоиска)
| И НЕ Номенклатура.ЭтоГруппа
|УПОРЯДОЧИТЬ ПО
| Номенклатура.Наименование";
Запрос.УстановитьПараметр("ШаблонПоиска", ТекстПоиска + "%");
РезультатЗапроса = Запрос.Выполнить();
Если НЕ РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
Возврат Выборка.Ссылка;
КонецЕсли;
Возврат Справочники.Номенклатура.ПустаяСсылка();
КонецФункции
Преимущества данного метода: Полное визуальное соответствие поведению ОФ. Список не скрывается, фокус плавно прыгает на нужную строку по мере ввода символов.
Важное ограничение: Если в динамическом списке пользователем установлена сложная ручная сортировка (например, по реквизиту, который не совпадает с логикой нашего запроса УПОРЯДОЧИТЬ ПО), то курсор прыгнет на нужный элемент, но визуально он может оказаться в середине или в конце видимой области экрана, что дезориентирует пользователя. Для идеальной работы метода логика сортировки в запросе должна совпадать с текущей сортировкой динамического списка.
---
Этот метод не меняет логику поиска в самом списке, но кардинально решает проблему быстрого и безошибочного ввода номенклатуры в документы (в табличные части). Зачастую пользователи просят «поиск как в УПП» именно потому, что им неудобно подбирать товары в документы.
Мы можем переопределить стандартный поиск 1С при вводе строки в поле выбора документа. Для этого используется обработчик в модуле менеджера справочника Номенклатура.
Проанализируем ситуацию: по умолчанию 1С ищет совпадения по наименованию. Мы можем сделать поиск «умным»: если введены только цифры — искать строго по коду или артикулу, если введен текст — искать по первым буквам наименования.
Разберем программную реализацию в модуле менеджера справочника Номенклатура:
Процедура ОбработкаПолученияДанныхВыбора(ДанныеВыбора, Параметры, СтандартнаяОбработка)
// Отменяем стандартный поиск платформы, чтобы написать свой оптимизированный алгоритм
СтандартнаяОбработка = Ложь;
СтрокаПоиска = Параметры.СтрокаПоиска;
Если ПустаяСтрока(СтрокаПоиска) Тогда
Возврат;
КонецЕсли;
// Создаем таблицу значений для формирования результатов выбора
ТаблицаРезультатов = Новый ТаблицаЗначений;
ТаблицаРезультатов.Колонки.Добавить("Значение");
ТаблицаРезультатов.Колонки.Добавить("Представление");
Запрос = Новый Запрос;
// Проверяем, состоит ли строка поиска только из цифр (возможно, это код, артикул или штрихкод)
ТолькоЦифры = Истина;
Для Индекс = 1 По СтрДлина(СтрокаПоиска) Цикл
КодСимвола = КодСимвола(СтрокаПоиска, Индекс);
Если КодСимвола < 48 ИЛИ КодСимвола > 57 Тогда
ТолькоЦифры = Ложь;
Прервать;
КонецЕсли;
КонецЦикла;
Если ТолькоЦифры Тогда
// Оптимизированный поиск по числовым идентификаторам
Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 10
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Наименование + "" (Арт: "" + Номенклатура.Артикул + "")"" КАК Представление
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| (Номенклатура.Код ПОДОБНО &СтрокаПоиска
| ИЛИ Номенклатура.Артикул ПОДОБНО &СтрокаПоиска)
| И НЕ Номенклатура.ЭтоГруппа";
Иначе
// Быстрый поиск по началу наименования (с использованием индексов СУБД)
Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 15
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Наименование + "" (Арт: "" + Номенклатура.Артикул + "")"" КАК Представление
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Наименование ПОДОБНО &СтрокаПоискаНачало
| И НЕ Номенклатура.ЭтоГруппа";
КонецЕсли;
Запрос.УстановитьПараметр("СтрокаПоиска", СтрокаПоиска + "%");
Запрос.УстановитьПараметр("СтрокаПоискаНачало", СтрокаПоиска + "%");
Выгрузка = Запрос.Выполнить().Выгрузить();
СписокВыбора = Новый СписокЗначений;
Для Каждого Строка Из Выгрузка Цикл
СписокВыбора.Добавить(Строка.Ссылка, Строка.Представление);
КонецЦикла;
ДанныеВыбора = СписокВыбора;
КонецПроцедуры
Почему это эффективно: Мы полностью контролируем процесс поиска на уровне базы данных. Использование конструкции ПОДОБНО &СтрокаПоиска + "%" (процент только в конце шаблона) гарантирует, что SQL-сервер применит индекс по соответствующему полю, и выборка выполнится мгновенно, в отличие от полнотекстового поиска по середине слова.
---
Если справочник номенклатуры структурирован по алфавиту или пользователям важно быстро переходить к товарам на определенную букву (как это часто делалось визуально в ОФ), можно вывести на форму динамическую панель с алфавитом.
Давайте разберем, как реализовать этот эргономичный механизм:
Посмотрим на программную реализацию этого интерфейсного решения:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартноеОформление)
// Создаем группу для кнопок алфавита
ГруппаАлфавит = Элементы.Добавить("ГруппаАлфавит", Тип("ГруппаФормы"), Элементы.Индекс(Элементы.Список) - 1);
ГруппаАлфавит.Вид = ВидГруппыФормы.КоманднаяПанель;
// Заполняем кнопками-буквами
АлфавитСтрока = "АБВГДЕЖЗИКЛМНОПРСТУФХЦЧШЭЮЯ";
Для НомерСимвола = 1 По СтрДлина(АлфавитСтрока) Цикл
Буква = Сред(АлфавитСтрока, НомерСимвола, 1);
ИмяКоманды = "КомандаБуква_" + Буква;
ИмяКнопки = "КнопкаБуква_" + Буква;
// Добавляем команду формы
НоваяКоманда = Команды.Добавить(ИмяКоманды);
НоваяКоманда.Действие = "ОбработчикНажатияБуквы";
НоваяКоманда.Заголовок = Буква;
// Добавляем кнопку на панель
НоваяКнопка = Элементы.Добавить(ИмяКнопки, Тип("КнопкаФормы"), ГруппаАлфавит);
НоваяКнопка.ИмяКоманды = ИмяКоманды;
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура ОбработчикНажатияБуквы(Команда)
// Получаем букву из имени команды
ВыбраннаяБуква = Сред(Команда.Имя, СтрДлина("КомандаБуква_") + 1);
// Устанавливаем быстрый отбор по первой букве наименования
УстановитьОтборПоПервойБукве(ВыбраннаяБуква);
КонецПроцедуры
&НаСервере
Процедура УстановитьОтборПоПервойБукве(Буква)
// Очищаем предыдущие отборы по этому полю
ПолеКомпоновки = Новый ПолеКомпоновкиДанных("Наименование");
ГруппаОтбора = Список.КомпоновщикНастроек.Настройки.Отбор;
ЭлементыДляУдаления = Новый Массив;
Для Каждого ЭлементОтбора Из ГруппаОтбора.Элементы Цикл
Если ЭлементОтбора.ЛевоеЗначение = ПолеКомпоновки Тогда
ЭлементыДляУдаления.Добавить(ЭлементОтбора);
КонецЕсли;
КонецЦикла;
Для Каждого Элемент Из ЭлементыДляУдаления Цикл
ГруппаОтбора.Элементы.Удалить(Элемент);
КонецЦикла;
// Накладываем новый отбор вида: "Наименование ПОДОБНО Буква%"
Если ЗначениеЗаполнено(Буква) Тогда
НовыйЭлемент = ГруппаОтбора.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
НовыйЭлемент.ЛевоеЗначение = ПолеКомпоновки;
НовыйЭлемент.ВидСравнения = ВидСравненияКомпоновкиДанных.Подобно;
НовыйЭлемент.Использование = Истина;
НовыйЭлемент.ПравоеЗначение = Буква + "%";
КонецЕсли;
КонецПроцедуры
Результат: Данное решение позволяет пользователю одним кликом мыши (или нажатием горячей клавиши) мгновенно сократить список номенклатуры до конкретной буквы. Поиск внутри отфильтрованного по первой букве списка происходит на порядок быстрее и не нагружает сервер СУБД.
---
Мы проанализировали несколько различных подходов к организации быстрого поиска в управляемых формах 1С:ERP.
ТекущаяСтрока).ОбработкаПолученияДанныхВыбора (Способ 3) в модуле менеджера справочника.Комбинируя эти подходы, вы сможете сделать работу пользователей в новой системе 1С:ERP максимально комфортной, быстрой и избавленной от лишних задержек интерфейса.