Skill v1.0.1
currentAutomated scan100/1001 files
version: "1.0.1" name: form-patterns description: Паттерны модуля формы (клиент-серверное взаимодействие). Этот навык учит агента правильно писать код модулей управляемых форм 1С.
Паттерны модуля формы (клиент-серверное взаимодействие)
Ключевой принцип: Минимизировать количество и объём серверных вызовов. Каждый вызов &НаСервере — сетевой round-trip + сериализация полного контекста формы.
Правило 1: Иерархия директив — предпочитайте безконтекстные вызовы
Порядок предпочтения (от лучшего к худшему)
1. &НаКлиентеНаСервереБезКонтекста — чистые вычисления, обе среды2. &НаСервереБезКонтекста — обращение к БД, без контекста формы3. &НаСервере — нужен доступ к реквизитам формы4. &НаКлиенте — интерактивная логика (диалоги, навигация)
Правило принятия решения
Нужно ли обращаться к базе данных?├── Нет → &НаКлиенте или &НаКлиентеНаСервереБезКонтекста└── Да →Нужен ли доступ к реквизитам формы?├── Нет → &НаСервереБезКонтекста (передаём только параметры)└── Да → &НаСервере (передаётся весь контекст)
// Чистое вычисление — обе среды&НаКлиентеНаСервереБезКонтекстаФункция РассчитатьСумму(Количество, Цена, СтавкаНДС)СуммаБезНДС = Количество * Цена;СуммаНДС = СуммаБезНДС * СтавкаНДС / 100;Возврат СуммаБезНДС + СуммаНДС;КонецФункции// Нужны данные из БД, но НЕ нужны реквизиты формы&НаСервереБезКонтекстаФункция ПолучитьДанныеНоменклатуры(НоменклатураСсылка)Возврат ОбщегоНазначения.ЗначенияРеквизитовОбъекта(НоменклатураСсылка,"Наименование, ЕдиницаИзмерения, СтавкаНДС, Цена");КонецФункции// Нужен доступ к реквизитам формы&НаСервереПроцедура ПересчитатьИтогиНаСервере()Объект.СуммаДокумента = Объект.Товары.Итог("Сумма");Объект.СуммаНДС = Объект.Товары.Итог("СуммаНДС");КонецПроцедуры
Правило 2: Минимизация серверных вызовов — батчинг данных
Каждый серверный вызов ~100 мс (сериализация + round-trip + десериализация). Три вызова = 300 мс задержки. Один вызов, возвращающий все данные, = 100 мс.
&НаКлиентеПроцедура КонтрагентПриИзменении(Элемент)ДанныеЗаполнения = ПолучитьДанныеЗаполненияПоКонтрагенту(Объект.Контрагент, Объект.Дата);Объект.Договор = ДанныеЗаполнения.Договор;Объект.Организация = ДанныеЗаполнения.Организация;Объект.Валюта = ДанныеЗаполнения.Валюта;КурсВалюты = ДанныеЗаполнения.Курс;КонецПроцедуры&НаСервереБезКонтекстаФункция ПолучитьДанныеЗаполненияПоКонтрагенту(КонтрагентСсылка, ДатаДокумента)Результат = Новый Структура;РеквизитыКонтрагента = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(КонтрагентСсылка, "ДоговорПоУмолчанию, ОсновнаяОрганизация");Результат.Вставить("Договор", РеквизитыКонтрагента.ДоговорПоУмолчанию);Результат.Вставить("Организация", РеквизитыКонтрагента.ОсновнаяОрганизация);Если ЗначениеЗаполнено(РеквизитыКонтрагента.ДоговорПоУмолчанию) ТогдаВалютаДоговора = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(РеквизитыКонтрагента.ДоговорПоУмолчанию, "ВалютаВзаиморасчетов");Результат.Вставить("Валюта", ВалютаДоговора);Результат.Вставить("Курс", РаботаСКурсамиВалют.ПолучитьКурсВалюты(ВалютаДоговора, ДатаДокумента));ИначеРезультат.Вставить("Валюта", Неопределено);Результат.Вставить("Курс", 1);КонецЕсли;Возврат Результат;КонецФункции
Правило 3: ДанныеФормыВЗначение / ЗначениеВДанныеФормы
На сервере формы данные объекта — не настоящий объект, а ДанныеФормы*. Для вызова методов модуля объекта нужно преобразование.
| Сценарий | Нужно преобразование? | |
|---|---|---|
| Чтение реквизитов формы | Нет — Объект.Реквизит работает напрямую | |
| Вызов методов модуля объекта | Да | |
| Передача объекта в общий модуль | Да — общие модули работают с настоящими объектами |
&НаСервереПроцедура ЗаполнитьПоУмолчаниюНаСервере()ДокументОбъект = РеквизитФормыВЗначение("Объект");ДокументОбъект.ЗаполнитьТоварыПоУмолчанию();// ОБЯЗАТЕЛЬНО: преобразовать обратно, иначе изменения не отразятся на форме!ЗначениеВРеквизитФормы(ДокументОбъект, "Объект");КонецПроцедуры
Типичная ошибка — забыли ЗначениеВРеквизитФормы
// ПЛОХО: изменения потеряны!&НаСервереПроцедура ЗаполнитьНаСервере()ДокументОбъект = РеквизитФормыВЗначение("Объект");ДокументОбъект.ЗаполнитьТаблицу();// ЗАБЫЛИ: ЗначениеВРеквизитФормы(ДокументОбъект, "Объект");КонецПроцедуры
Правило 4: Обработчики событий формы — порядок и назначение
Порядок событий при открытии формы
1. ПриСозданииНаСервере — форма создаётся на сервере, данные загружены2. ПриОткрытии — форма отобразилась на клиенте
Порядок событий при записи
1. ПередЗаписьюНаКлиенте — клиент: можно отменить (Отказ = Истина)2. ПередЗаписьюНаСервере — сервер: последняя проверка3. ПриЗаписиНаСервере — сервер: в той же транзакции4. ПослеЗаписиНаСервере — сервер: обновление формы5. ПослеЗаписи — клиент: оповещение
&НаСервереПроцедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)Если Параметры.Свойство("ЗначенияЗаполнения") ТогдаЗаполнитьЗначенияСвойств(Объект, Параметры.ЗначенияЗаполнения);КонецЕсли;Элементы.ГруппаСклад.Видимость = (Объект.ВидОперации <>Перечисления.ВидыОпераций.Услуга);ОбновитьСписокВыбораДоговоров();КонецПроцедуры// ПередЗаписьюНаКлиенте — проверки, требующие подтверждения пользователя&НаКлиентеПроцедура ПередЗаписью(Отказ, ПараметрыЗаписи)Если Объект.СуммаДокумента > 1000000 ТогдаЕсли Не ПараметрыЗаписи.Свойство("ПодтверждениеСуммы") ТогдаОтказ = Истина;ПоказатьВопрос(Новый ОписаниеОповещения("ПослеПодтвержденияСуммы", ЭтотОбъект, ПараметрыЗаписи),НСтр("ru = 'Сумма документа превышает 1 000 000. Продолжить?'"),РежимДиалогаВопрос.ДаНет);КонецЕсли;КонецЕсли;КонецПроцедуры// ПослеЗаписи — оповещения на клиенте&НаКлиентеПроцедура ПослеЗаписи(ПараметрыЗаписи)Оповестить("Запись_РеализацияТоваровУслуг",Новый Структура("Ссылка", Объект.Ссылка), ЭтотОбъект);КонецПроцедуры
Правило 5: Динамические списки — настройка и оптимизация
Динамический список автоматически реализует пагинацию, поиск, сортировку.
&НаСервереПроцедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)// Отборы через КомпоновкаДанных (пользователь сможет изменять)ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(СписокДокументов,"Организация",Организация,ВидСравненияКомпоновкиДанных.Равно,,ЗначениеЗаполнено(Организация));КонецПроцедуры
Произвольный запрос для динамического списка
СписокДокументов.ПроизвольныйЗапрос = Истина;СписокДокументов.ТекстЗапроса ="ВЫБРАТЬ| Реализация.Ссылка,| Реализация.Дата,| Реализация.Номер,| Реализация.Контрагент,| Реализация.СуммаДокумента,| ЕСТЬNULL(Задолженность.СуммаОстаток, 0) КАК ОстатокЗадолженности|ИЗ| Документ.РеализацияТоваровУслуг КАК Реализация| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ВзаиморасчетыСКонтрагентами.Остатки КАК Задолженность| ПО Реализация.Контрагент = Задолженность.Контрагент| И Реализация.Договор = Задолженность.Договор|{ГДЕ| Реализация.Дата >= &ДатаНачала}";
Правила: не загружайте все данные; отборы через КомпоновкуДанных, не через WHERE; не используйте УПОРЯДОЧИТЬ ПО в произвольном запросе.
Правило 6: Условное оформление — программная настройка
&НаСервереПроцедура УстановитьУсловноеОформление()УсловноеОформление.Элементы.Очистить();ЭлементУО = УсловноеОформление.Элементы.Добавить();ЭлементОтбора = ЭлементУО.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ДатаОплаты");ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Меньше;ЭлементОтбора.ПравоеЗначение = ТекущаяДатаСеанса();ЭлементОтбора.Использование = Истина;ЭлементОтбора2 = ЭлементУО.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));ЭлементОтбора2.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Оплачен");ЭлементОтбора2.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;ЭлементОтбора2.ПравоеЗначение = Ложь;ЭлементОтбора2.Использование = Истина;ЭлементУО.Оформление.УстановитьЗначениеПараметра("ЦветФона", WebЦвета.МисттиРоуз);ПолеОформления = ЭлементУО.Поля.Элементы.Добавить();ПолеОформления.Поле = Новый ПолеКомпоновкиДанных("СписокДокументов");КонецПроцедуры
Правило 7: Асинхронные диалоги вместо модальных
Модальные вызовы (Предупреждение(), Вопрос()) запрещены в веб-клиенте. Используйте ОписаниеОповещения.
Стандарт ИТС: «Ограничения на использование модальных методов».
&НаКлиентеПроцедура УдалитьСтрокуТоваров(Команда)Если Элементы.Товары.ТекущаяСтрока = Неопределено ТогдаВозврат;КонецЕсли;ПоказатьВопрос(Новый ОписаниеОповещения("ПослеПодтвержденияУдаления", ЭтотОбъект),НСтр("ru = 'Удалить выбранную строку?'"),РежимДиалогаВопрос.ДаНет,,КодВозвратаДиалога.Нет);КонецПроцедуры&НаКлиентеПроцедура ПослеПодтвержденияУдаления(Результат, ДополнительныеПараметры) ЭкспортЕсли Результат = КодВозвратаДиалога.Да ТогдаОбъект.Товары.Удалить(Элементы.Товары.ТекущаяСтрока);КонецЕсли;КонецПроцедуры
Правило 8: Открытие форм и обработка результата
&НаКлиентеПроцедура ОткрытьФормуПодбораТоваров(Команда)ПараметрыФормы = Новый Структура;ПараметрыФормы.Вставить("Организация", Объект.Организация);ПараметрыФормы.Вставить("Склад", Объект.Склад);ПараметрыФормы.Вставить("Дата", Объект.Дата);ПараметрыФормы.Вставить("МножественныйВыбор", Истина);ОткрытьФорму("Обработка.ПодборТоваров.Форма",ПараметрыФормы,ЭтотОбъект,,,,Новый ОписаниеОповещения("ПослеПодбораТоваров", ЭтотОбъект));КонецПроцедуры&НаКлиентеПроцедура ПослеПодбораТоваров(РезультатПодбора, ДополнительныеПараметры) ЭкспортЕсли РезультатПодбора = Неопределено ТогдаВозврат;КонецЕсли;Для Каждого ДанныеТовара Из РезультатПодбора ЦиклНоваяСтрока = Объект.Товары.Добавить();ЗаполнитьЗначенияСвойств(НоваяСтрока, ДанныеТовара);КонецЦикла;Модифицированность = Истина;КонецПроцедуры
Правило 9: Управление видимостью — группировать изменения
Все изменения видимости/доступности — в одном серверном вызове, чтобы избежать «дёрганья» интерфейса.
&НаСервереПроцедура УправлениеВидимостью()ЭтоУслуга = Объект.ВидОперации = Перечисления.ВидыОпераций.Услуга;Элементы.Склад.Видимость = НЕ ЭтоУслуга;Элементы.ТоварыКоличество.Видимость = НЕ ЭтоУслуга;Элементы.ТоварыЕдиницаИзмерения.Видимость = НЕ ЭтоУслуга;Элементы.ГруппаДоставка.Видимость = НЕ ЭтоУслуга;Элементы.Контрагент.ТолькоПросмотр = Объект.Проведен;КонецПроцедуры&НаКлиентеПроцедура ВидОперацииПриИзменении(Элемент)УправлениеВидимостью(); // Один серверный вызов для всех измененийКонецПроцедуры
Правило 10: Работа с табличными частями — пересчёт на клиенте если возможно
// Изменение количества — пересчёт суммы на клиенте&НаКлиентеПроцедура ТоварыКоличествоПриИзменении(Элемент)ТекущаяСтрока = Элементы.Товары.ТекущиеДанные;ТекущаяСтрока.Сумма = РассчитатьСумму(ТекущаяСтрока.Количество, ТекущаяСтрока.Цена, ТекущаяСтрока.СтавкаНДС);КонецПроцедуры// Изменение номенклатуры — нужен сервер для получения данных&НаКлиентеПроцедура ТоварыНоменклатураПриИзменении(Элемент)ТекущаяСтрока = Элементы.Товары.ТекущиеДанные;ДанныеНоменклатуры = ПолучитьДанныеНоменклатуры(ТекущаяСтрока.Номенклатура);ТекущаяСтрока.ЕдиницаИзмерения = ДанныеНоменклатуры.ЕдиницаИзмерения;ТекущаяСтрока.Цена = ДанныеНоменклатуры.Цена;ТекущаяСтрока.СтавкаНДС = ДанныеНоменклатуры.СтавкаНДС;ТекущаяСтрока.Сумма = РассчитатьСумму(ТекущаяСтрока.Количество, ТекущаяСтрока.Цена, ТекущаяСтрока.СтавкаНДС);КонецПроцедуры
Правило 11: Оповещения между формами
// Форма документа — после записи&НаКлиентеПроцедура ПослеЗаписи(ПараметрыЗаписи)Оповестить("Запись_РеализацияТоваровУслуг",Новый Структура("Ссылка, Проведен", Объект.Ссылка, Объект.Проведен),ЭтотОбъект);КонецПроцедуры// Форма списка — обработка оповещения&НаКлиентеПроцедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)Если ИмяСобытия = "Запись_РеализацияТоваровУслуг" ТогдаЭлементы.Список.Обновить();КонецЕсли;КонецПроцедуры
Правило 12: Передаваемые типы данных между клиентом и сервером
Типы, передаваемые свободно
Примитивные (Строка, Число, Дата, Булево), Ссылки, Перечисления, Структура, Соответствие, Массив, ФиксированныеКоллекции, ХранилищеЗначения.
Типы, НЕ передаваемые (серверные)
| Тип | Альтернатива | |
|---|---|---|
| ТаблицаЗначений | ДанныеФормыКоллекция (через реквизиты формы) | |
| ДеревоЗначений | ДанныеФормыДерево (через реквизиты формы) | |
| ОбъектМетаданных | Передавать ИмяМетаданных (строку) | |
| Запрос, РезультатЗапроса | Передавать результат (структура/массив) |
depends_on: []