За основу взята статья Виталия Барилко //infostart.ru/public/336564/
Изучая возможность создания универсального конструктора процессов в самописной конфигурации, естественно первой же мыслью было использовать родные бизнес процессы платформы с подменой карты маршрута. И самая первая сложность - как при создании карты маршрута на стороне клиента суметь понять ее состав и связи.
Привожу полный код модуля, отвечающий за логику работы, и пример его использования.
#Область ПрограммныйИнтерфейс
Функция ПолучитьОписаниеЭлементовГрафическойСхемы() Экспорт
// значения itemType
Результат = Новый Соответствие;
Результат.Вставить(0, "Декорация");
Результат.Вставить(1, "Линия");
Результат.Вставить(2, "Старт");
Результат.Вставить(3, "Завершение");
Результат.Вставить(4, "Условие");
Результат.Вставить(5, "Действие");
Результат.Вставить(6, "Выбор варианта");
Результат.Вставить(7, "Разделение");
Результат.Вставить(8, "Слияние");
Результат.Вставить(9, "Точка обработки");
Результат.Вставить(10, "Вложенный бизнес-процесс");
Возврат Результат;
КонецФункции
Функция ПолучитьXMLГрафическойСхемы(ГрафическаяСхема) Экспорт
Результат = "";
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
Сериализатор = Новый СериализаторXDTO(ФабрикаXDTO);
Сериализатор.ЗаписатьXML(ЗаписьXML, ГрафическаяСхема, НазначениеТипаXML.Явное);
Результат = ЗаписьXML.Закрыть();
Возврат Результат;
КонецФункции
Функция ПолучитьDOMГрафическойСхемы(ГрафическаяСхема) Экспорт
Результат = Неопределено;
XMLГрафическойСхемы = ПолучитьXMLГрафическойСхемы(ГрафическаяСхема);
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(XMLГрафическойСхемы);
ПостроительDOM = Новый ПостроительDOM;
Результат = ПостроительDOM.Прочитать(ЧтениеXML);
Возврат Результат;
КонецФункции
Функция ПолучитьГрафическуюСхемуИзXML(СтрокаXML) Экспорт
Результат = Неопределено;
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(СтрокаXML);
Сериализатор = Новый СериализаторXDTO(ФабрикаXDTO);
Результат = Сериализатор.ПрочитатьXML(ЧтениеXML);
Возврат Результат;
КонецФункции
Функция ПолучитьГрафическуюСхемуИзDOM(ДокументDOM) Экспорт
Результат = Неопределено;
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
ЗаписьDOM = Новый ЗаписьDOM();
ЗаписьDOM.Записать(ДокументDOM.ДочерниеУзлы[0] , ЗаписьXML);
XMLГрафическойСхемы = ЗаписьXML.Закрыть();
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(XMLГрафическойСхемы);
Сериализатор = Новый СериализаторXDTO(ФабрикаXDTO);
Результат = Сериализатор.ПрочитатьXML(ЧтениеXML);
Возврат Результат;
КонецФункции
Функция НайтиЭлементПоЗначениюСвойства(ДокументDOM, ИмяСвойства, Значение) Экспорт
Результат = Неопределено;
СписокЭлементовDOM = ДокументDOM.ПолучитьЭлементыПоИмени(ИмяСвойства);
Для Каждого Элемент Из СписокЭлементовDOM Цикл
Если Элемент.ТекстовоеСодержимое = Значение Тогда
Результат = Элемент.РодительскийУзел;
Прервать;
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
Функция ПолучитьЗначениеСвойстваЭлемента(ЭлементDOM, ИмяСвойства) Экспорт
СписокЭлементовDOM = ЭлементDOM.ПолучитьЭлементыПоИмени(ИмяСвойства);
Если СписокЭлементовDOM.Количество() = 1 Тогда
Возврат СписокЭлементовDOM[0].ТекстовоеСодержимое;
Иначе
Возврат Неопределено;
КонецЕсли;
КонецФункции
Процедура УстановитьЗначениеСвойстваЭлемента(ЭлементDOM, ИмяСвойства, Значение) Экспорт
СписокЭлементовDOM = ЭлементDOM.ПолучитьЭлементыПоИмени(ИмяСвойства);
Если СписокЭлементовDOM.Количество() = 1 Тогда
СписокЭлементовDOM[0].ТекстовоеСодержимое = Значение;
КонецЕсли;
КонецПроцедуры
#КонецОбласти
Хранить карту маршрута будем в справочнике БизнесПроцессы в реквизите КартаМаршрутаXML.
Форма элемента справочника имеет следующую структуру:
#Область ОбработчикиСобытийФормы
&НаКлиенте
Процедура ПриОткрытии(Отказ)
Если ЗначениеЗаполнено(Объект.КартаМаршрутаXML) Тогда
ГрафическаяСхема = УниверсальныеКартыМаршрутовКлиентСервер.ПолучитьГрафическуюСхемуИзXML(Объект.КартаМаршрутаXML);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
Объект.КартаМаршрутаXML = УниверсальныеКартыМаршрутовКлиентСервер.ПолучитьXMLГрафическойСхемы(ГрафическаяСхема);
КонецПроцедуры
#КонецОбласти
#Область ОбработчикиСобытийГрафическойСхемы
&НаКлиенте
Процедура ГрафическаяСхемаПриИзменении(Элемент)
Модифицированность = Истина;
ОписаниеЭлементов = УниверсальныеКартыМаршрутовКлиентСервер.ПолучитьОписаниеЭлементовГрафическойСхемы();
ИдентификаторыЭлементов = Новый Массив;
// пример работы с DOM графической схемы
ДокументDOM = УниверсальныеКартыМаршрутовКлиентСервер.ПолучитьDOMГрафическойСхемы(ГрафическаяСхема);
// каждый элемент схемы "item" представлен свойством "itemType"
СписокЭлементовDOM = ДокументDOM.ПолучитьЭлементыПоИмени("itemType");
Для Каждого Элемент Из СписокЭлементовDOM Цикл
ТипЭлемента = Число(Элемент.ТекстовоеСодержимое);
Если ТипЭлемента = 0
ИЛИ ТипЭлемента = 1 Тогда
// декорации и линии пропускаем
Продолжить;
КонецЕсли;
УзелТочкиМаршрута = Элемент.РодительскийУзел;
// каждый элемент схемы имеет itemId
ИдентификаторЭлемента = Число(УниверсальныеКартыМаршрутовКлиентСервер.ПолучитьЗначениеСвойстваЭлемента(УзелТочкиМаршрута, "itemId"));
// заполняеем перечень текущих идентификаторов
ИдентификаторыЭлементов.Добавить(ИдентификаторЭлемента);
// находим, есть ли данный узел в точках маршрута
ПараметрыОтбора = Новый Структура("ИдентификаторЭлемента", ИдентификаторЭлемента);
РезультатПоиска = Объект.ТочкиМаршрута.НайтиСтроки(ПараметрыОтбора);
Если РезультатПоиска.Количество() = 0 Тогда
НоваяСтрока = Объект.ТочкиМаршрута.Добавить();
НоваяСтрока.ИдентификаторЭлемента = ИдентификаторЭлемента;
НоваяСтрока.ТипЭлемента = ТипЭлемента;
НоваяСтрока.ТипЭлементаПредставление = ОписаниеЭлементов[ТипЭлемента];
НоваяСтрока.Наименование = УниверсальныеКартыМаршрутовКлиентСервер.ПолучитьЗначениеСвойстваЭлемента(УзелТочкиМаршрута, "content");
КонецЕсли;
// пример, код установки красной линии (текущее действие в запущенном БП)
Если ТипЭлемента = 5 Тогда
// данные свойства нашел опытным путем, может что и не так, но работает...
УниверсальныеКартыМаршрутовКлиентСервер.УстановитьЗначениеСвойстваЭлемента(УзелТочкиМаршрута, "passageState", "2");
УниверсальныеКартыМаршрутовКлиентСервер.УстановитьЗначениеСвойстваЭлемента(УзелТочкиМаршрута, "isAddrZoneDivideValid", "true");
УниверсальныеКартыМаршрутовКлиентСервер.УстановитьЗначениеСвойстваЭлемента(УзелТочкиМаршрута, "addrZoneDivideYPos", "16");
КонецЕсли;
КонецЦикла;
ГрафическаяСхема = УниверсальныеКартыМаршрутовКлиентСервер.ПолучитьГрафическуюСхемуИзDOM(ДокументDOM);
// удалим из таблицы точек маршрута те элементы, которые удалили на схеме
СтрокиКУдалению = Новый Массив;
Для Каждого СтрокаТЧ Из Объект.ТочкиМаршрута Цикл
Если ИдентификаторыЭлементов.Найти(СтрокаТЧ.ИдентификаторЭлемента) = Неопределено Тогда
СтрокиКУдалению.Добавить(СтрокаТЧ);
КонецЕсли;
КонецЦикла;
Для Каждого СтрокаТЧ Из СтрокиКУдалению Цикл
Объект.ТочкиМаршрута.Удалить(СтрокаТЧ);
КонецЦикла;
КонецПроцедуры
#КонецОбласти
#Область ОбработчикиСобытийЭлементовТаблицыФормыТочкиМаршрута
&НаКлиенте
Процедура ТочкиМаршрутаНаименованиеПриИзменении(Элемент)
ТекущиеДанные = Элементы.ТочкиМаршрута.ТекущиеДанные;
ИдентификаторЭлемента = Строка(ТекущиеДанные.ИдентификаторЭлемента);
ДокументDOM = УниверсальныеКартыМаршрутовКлиентСервер.ПолучитьDOMГрафическойСхемы(ГрафическаяСхема);
УзелТочкиМаршрута = УниверсальныеКартыМаршрутовКлиентСервер.НайтиЭлементПоЗначениюСвойства(ДокументDOM, "itemId", ИдентификаторЭлемента);
УниверсальныеКартыМаршрутовКлиентСервер.УстановитьЗначениеСвойстваЭлемента(УзелТочкиМаршрута, "content", ТекущиеДанные.Наименование);
ГрафическаяСхема = УниверсальныеКартыМаршрутовКлиентСервер.ПолучитьГрафическуюСхемуИзDOM(ДокументDOM);
КонецПроцедуры
#КонецОбласти
Пример работы:
В файлах приложил демо конфигурацию примера.