Добрый день, Коллеги!

Получил задачу подключения иерархического отображения записей в гриде.

Однако столкнулся со следующей трудностью:

Контейнер, в котором отображается реестр представляет из себя:

"operation": "insert",
"name": "DataGrid",
"parentName": "gridContainer",
"propertyName": "items",
"values": {
		"itemType": Terrasoft.ViewItemType.CONTAINER,
		"className": "Terrasoft.ContainerList"
........
}

Судя по описанию класса сам по себе он не поддерживает иерархию

Однако, существует расширение класса "HierarchicalContainerList"

Возникают следующие вопросы:

1) Актуален ли класс HierarchicalContainerList на текущий момент. Если ли примеры его явного использования? Сможет ли он поддержать иерархическую структуру?

2) При попытке обращения к нему в виде:

"generator": "ConfigurationItemGenerator.generateHierarchicalContainerList"

Не совсем понимаю как именно задать нужные свойства

nestedItemsAttributeName и nestedItemsContainerId:

generateHierarchicalContainerList: function(config, generatorConfig) {
			var containerListConfig = this.generateContainerList(config, generatorConfig);
			containerListConfig.className = "Terrasoft.HierarchicalContainerList";
			Ext.merge(containerListConfig, {
				nestedItemsAttributeName: config.nestedItemsAttributeName,
				nestedItemsContainerId: config.nestedItemsContainerId
			});
			return containerListConfig;
		}

Могу предположить что в nestedItemsAttributeName должно быть наименование колонки, хранящей id родительской записи.

А вот nestedItemsContainerId, не совсем понятно. Похоже что этот атрибут должен принимать сам Id родительской записи.

 

Коллеги, буду благодарен за любую информацию, спасибо!

Нравится

6 комментариев
Лучший ответ

Титаев Александр Николаевич,

Насколько я понял, то вся суть проблемы именно в том, что подбор продуктов использует не Grid, а ContainerList.

 

Реализовывал такую же задачу, но не нашел, как сделать ContainerList иерархичестим. Я полностью менял контрол страницы подбора из ContainerList на Grid а точнее на HierarchialGrid.







Функционал рабочий, но есть некрасивые моменты, когда активна строка для изменения значений.







Поэтому, если найдете решение, как сделать красиво, то буду благодарен за совет, как сделать лучше.

 

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

 

Для реализации древовидных реестров есть дополнение, но оно платное. Вот обсуждение с тех времён, когда ещё было бесплатным.

 

Также есть тема с примером самостоятельной реализации, но очень старая, не уверен, что сходу заработает на нынешних версиях.

 

В «коробке» есть древовидная деталь структуры проекта, реализованная в схеме ProjectStructureDetailV2:

{
	"operation": "merge",
	"name": "DataGrid",
	"values": {
		"id": "StructureGrid",
		"type": "listed",
		"hierarchical": true,
		"sortColumnDirection": {"bindTo": "disableGridSorting"},
		"hierarchicalColumnName": "ParentId",
		"updateExpandHierarchyLevels": {
			"bindTo": "onExpandHierarchyLevels"
		},
		"expandHierarchyLevels": {
			"bindTo": "expandHierarchyLevels"
		},

Там же приведены функции onExpandHierarchyLevels, clearExpandHierarchyLevels, removeExpandHierarchyLevel и другие, реализующие логику древовидности.

Зверев Александр,

Спасибо за подсказку! Да, со схемами и сервисами детали ознакамливался в процессе анализа.

Однако вся суть в том, что иерархия должна ложиться на страницу продуктового каталога (подбор товаров), где используются как раз другие классы, да и друагя логика получения коллекции, подгружаемой в Grid.

Дополнение или очевидное задание иерархии при использовании "Terrasoft.ContainerList" на сколько я понял, не возможно (уже пробовал).

Буду думать как выходить из ситуации. Ещё раз спасибо!

 

Титаев Александр Николаевич,

Насколько я понял, то вся суть проблемы именно в том, что подбор продуктов использует не Grid, а ContainerList.

 

Реализовывал такую же задачу, но не нашел, как сделать ContainerList иерархичестим. Я полностью менял контрол страницы подбора из ContainerList на Grid а точнее на HierarchialGrid.







Функционал рабочий, но есть некрасивые моменты, когда активна строка для изменения значений.







Поэтому, если найдете решение, как сделать красиво, то буду благодарен за совет, как сделать лучше.

 

Не уверен, но если дело только в ширине выпирающей выделенной записи, это может быть задано в CSS этого элемента. Посмотрите, какие этому элементу страницы добавляются свойства и в какой схеме с CSS они записаны. Возможно, красивее получится путём их правки.

Зверев Александр,

Да. CSS поможет с этим.

Но мне не нравится чекбокс так же. В контейнерлисте были видны сразу все чекбоксы и отмечал, что мне нужно. А в гриде просто Да/Нет видно. И только при активации строки появляется чекбокс.

А это изначать было важной частью моего функционала, чтобы можно было быстро выбирать записи чекбоксами. 

То-есть сейчас нужно активировать запись и только потом выбрать галочкой.

Вроде незначительно, но для пользователя менее удобно

Владислав, галочки и да/нет в реестре обсуждались тут, также ранее заведена идея об этом.

Показать все комментарии

Вопрос такой, нужна функциональность NuGet пакета "System.IdentityModel.Tokens.Jwt", а именно "JwtSecurityTokenHandler" для того что бы из полученного JWT Token (при интеграции с другой системой) получить время создания и время окончания действия Token?

В примерах для написания Unit тестов указано, что установить NuGet пакет можно в проект "Terrasoft.Configuration.Tests.csproj", но это будет на сколько я понимаю только для проекта где мы ставим его, а как сделать что бы это еще и в пакете установилось на продуктивную среду?

Нравится

3 комментария

На сколько я разобрался, то самый безопасный способ установить NuGet пакет сторонний это создать пакет-проект, так как он создает отдельную dll и потом через интерфейс помет быть использован в конфигурации. Установка NuGet пакета в основную конфигурацию думаю не имеет смысла так как через пакет перенести это не удастся. Ну и забыл указать что все это я нашел что работает через утилиту clio. Если кому надо то у меня сохранилась запись вебинара с описаниями и примером создания такого пакета-проекта. Может кто еще варианты знает?

Александр, Nuget-пакет подключить к приложению нельзя, но можно извлечь из пакета нужную библиотеку и загрузить в конфигурацию как внешнюю библиотеку.

Nuget-пакет — это обычный zip-архив, который содержит в себе стандартизированый файл, описывающий содержимое пакета, благодаря чему с ним может работать пакетный менеджер.

 

Информация о потребности возможности добавить Nuget-пакет в приложение уже зарегистрирована.

Зверев Александр,

 используя clio есть возможность установки Nuget пакетов, но меня интересовало именно для переноса в пакете на другую среду. Видимо вариант с пакетом-проектом единственный сейчас

Показать все комментарии

Здравствуйте,

 

Для бизнес-процесса создал служебный справочник с настройками.

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

Процесс валится у пользователей в связи с тем, что у них нет прав доступа на операцию CanManageLookups.

Как можно продолжить процесс с изменением/добавлением значений только в этом справочнике, не раздавая при этом доступ к CanManageLookups?

Нравится

4 комментария

Добрый день.

 

Проверка по правам доступа на операцию CanManageLookups выполняется для всех объектов, которые унаследованы от BaseLookup (Базовый справочник).

 

Можно попробовать сменить родителя у объекта Вашего справочника на BaseObject (Базовый объект).

В этом случае не забудьте добавить поля Name и Description, которые есть в базовом справочнике, но нет в базовом объекте.

 

Внесение таких изменений лучше выполнять на тестовой версии.

Алла, зачем менять родителя, просто во встроенном БП справочника перезатереть пустой функцию проверки CheckCanManageLookups.

public override void CheckCanManageLookups() {
}

Так сделано у ряда коробочных справочников, например, у Department.

Зверев Александр,

Да, согласна. В данном случае твое решение является оптимальным.

Зверев Александр,

Александр, спасибо за ответ. Буду пробовать в это направлении.

 

Алла Савельева,

Алла, ваш вариант тоже подходит, так как использование справочника было лишь номинальным и для удобства администрирования - поля Name и Desc мне не нужны, так как используются поля других справочников: Account + 2 поля Int.

Показать все комментарии

В статье простейшее модальное окно разъяснено как создать и использовать окно в схеме страницы. У меня такой вопрос. Возврат результата из модального окна выполнен в subscribeSandboxEvents страницы ContactPageV2. При обработке в методе подписки не доступны атрибуты страницы привязанные к контенту на странице. Какой есть способ присвоить значение по закрытию окна в поле на странице?

Нравится

3 комментария

Есть ли возможность в диалоговом окне применить свои методы? В моих методах сложная логика заполнения полей асинхронно вызванным апи.

А пример модального окна по ссылке выше присвоения arg.test какому нибудь контролу не содержит. У меня this.set... выдает ошибку 'this.Set is not a function' из метода subscribe.SanboxEvents

В качестве модального окна можно применять любое, но с ограничениями (например,нельзя открывать другие модальные окна, поэтому выбор из справочника реализован только в выпадающих списках). По поводу set, сложно сказать, не видя того, что Вы делали. Например, в WizardWarningModalBoxPage для этого создали атрибуты, прибиндили их к визуальным компонентам и меняли значения уже им:

 

"AdditionalInfo": {
	dataValueType: Terrasoft.DataValueType.TEXT,
	size: 500,
	value: ""
}
...
this.set("AdditionalInfo", moduleInfo.additionalInfo);
...
"items": [
			{
		"name": "AdditionalInfo",
		"itemType": Terrasoft.ViewItemType.LABEL,
		"caption": {
			"bindTo": "AdditionalInfo"
		},
		"isMultiline": true
	}
]

 

Показать все комментарии

Доброго времени суток.

Не могу сравнить два значения времени в процессе.

Задача для примера, есть ещё другие похожие задачи с этой же темой.

В текстовый параметр бизнес-процесса подставляется текст "Доброе утро", "Добрый день" и т.д. в зависимости от текущего времени. Время проверяется в соответствии с созданным справочником (унаследованный от базового), где используются колонки [Название], [Время от] (тип время) и [Время до] (тип время). Наполнение:

Доброе утро | 07:00 | 11:30

Добрый день | 11:30 | 17:30

Добрый вечер | 17:30 | 22:00

 

Что я хочу сделать: процессом Читаем данные справочника, где [Текущее время] => [Время от] И [Текущее время] < [Время до], вычитать текстовое поле Название.

В чём моя проблема: в процессе, в элементе Чтение данных, в фильтре у полей с типом Время нет параметров < = или >. Есть только = или !=, Заполнено или Не заполнено. У полей Дата/Время всё нормально есть любой вид сравнения.

Вопрос-бонус: поле с типом Время могу сравнивать только с заранее записанным Параметром процесса, а динамически указать Текущее время не могу, как это с Дата/Время указывается Текущая дата и время.

Изображение удалено.

Версия 7.13.0, Sales, Marketing, CustomerCenter Enterprise OnSite.

Нравится

2 комментария

Здравствуйте!

 

Данную задачу можно решить через элемент "Задание-сценарий", в котором построить select или esq запрос с необходимыми Вам фильтрами. 

 

UserConnection userConnection = Get&lt;UserConnection&gt;("UserConnection");
var esq = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "UsrTestLookUp");
esq.AddColumn("Name");
esq.AddColumn("UsrTimeOn");
esq.AddColumn("UsrTimeTo");
var esqTimeOnFilter = esq.CreateFilterWithParameters(FilterComparisonType.Less, "UsrTimeOn", DateTime.Now.TimeOfDay);
var esqTimeToFilter = esq.CreateFilterWithParameters(FilterComparisonType.Greater, "UsrTimeTo", DateTime.Now.TimeOfDay);
esq.Filters.Add(esqTimeOnFilter);
esq.Filters.Add(esqTimeToFilter);
EntityCollection entityCollection = esq.GetEntityCollection(UserConnection);
if (entityCollection.IsNotEmpty()) {
        foreach (var name in entityCollection) {
        	var param1 = name.GetTypedColumnValue&lt;string&gt;("Name");
        	Set ("ProcessSchemaParameter1", param1);
        }
    }
/* или через select 
var select =
    (Select)new Select(userConnection)
        .Column("Name").As("Text")
    .From("UsrTestLookUp").WithHints(Hints.NoLock)
    .Where("UsrTimeOn").IsLess(Column.Parameter(DateTime.Now.TimeOfDay))
    .And("UsrTimeTo").IsGreater(Column.Parameter(DateTime.Now.TimeOfDay));
 
string sql = select.GetSqlText();
Set ("ProcessSchemaParameter1", sql);
using (var dbExecutor = userConnection.EnsureDBConnection()) {
    using (IDataReader dataReader = select.ExecuteReader(dbExecutor)) {
        while (dataReader.Read()) {
            string Name = dataReader.GetColumnValue&lt;string&gt;("Text");
            Set ("ProcessSchemaParameter1", Name);
        }
    }
}*/
return true;

 

Заричный Антон,

Здравствуйте.

 

Спасибо за предложенный вами вариант, он подошёл и отработал как и была поставлена задача.

Для тех, кто вдруг ещё ищет, итоговый вариант у меня получился следующим:

UserConnection userConnection = Get&lt;UserConnection&gt;("UserConnection");
var timenow = Get&lt;DateTime&gt;("CurrentTime"); // Параметр в процессе с типом Дата/Время
var esq = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "TsiCCCustomerGreetingOnDaytime"); // Название справочника
esq.AddColumn("Name"); // Колонка "Название" в справочнике (где написано Добрый день/утро/вечер и т.п.)
esq.AddColumn("TsiCCCustomerGreetingTimeFrom"); // Колонка справочника Время от
esq.AddColumn("TsiCCCustomerGreetingTimeTo"); // Колонка справочника Время до
 
var esqTimeOnFilter = esq.CreateFilterWithParameters(FilterComparisonType.Less, "TsiCCCustomerGreetingTimeFrom", timenow); // Колонка справочника Время от.
var esqTimeToFilter = esq.CreateFilterWithParameters(FilterComparisonType.Greater, "TsiCCCustomerGreetingTimeTo", timenow); // Колонка справочника Время до
// В одном из двух фильтров желательно указать равенство, чтобы не было ошибок, т.е. LessOrEqual или GreaterOrEqual соответственно, в зависимости от ваших потребностей
 
esq.Filters.Add(esqTimeOnFilter);
esq.Filters.Add(esqTimeToFilter);
EntityCollection entityCollection = esq.GetEntityCollection(UserConnection);
if (entityCollection.IsNotEmpty()) {
	foreach (var name in entityCollection) {
		var paramValue = name.GetTypedColumnValue&lt;string&gt;("Name");  // Колонка "Название"
		Set ("TimeOfDayText", paramValue);  // Название параметра в процессе для записи текста сообщения
	}
}
return true;

 

Показать все комментарии

Не получается связать кнопку с действием по клику, когда используется создание вью и вью модели в собственном модуле. Прошу помочь

 

Возврат функции модуля getView() содержит коллекцию кнопок (Terrasoft.Button) в массиве viewItems :

return this.Ext.create("Terrasoft.Container", {
                    id: "ModuleContainer",
                    selectors: {wrapEl: "#moduleContainer"},
                    classes: {wrapClassName: ["main-container-style"]},
                    items: viewItems});

Возврат функции модуля getViewModel(); В methods viewModel :

methods : {
onButtonClick: function () {
Terrasoft.showInformation("test");
}

В методе render модуля

render: function(renderTo) {
                var view = this.getView();
                var viewModel = this.getViewModel();
                view.bind(viewModel);
                view.render(renderTo);
         }

На странице создается контейнер и кнопка без реакции на клик.

Нравится

3 комментария

примеры по созданию кнопок есть в папке \Terrasoft.WebApp\Resources\ui\demo\button в конфигурации

Здравствуйте. Вцелом код выглядит правильно.

Убедитесь, что при добавлении кнопки( в diff), на событие onclick есть байндинг на ваш метод onButtonClick:

click: {bindTo: "onButtonClick"}

Demchenko Olha, Это модуль в который контент помещается на уровне объектов, то есть контент образуется при вызове вью динамически, без использования отдельной страницы вью где есть раздел diff 

Показать все комментарии

Имею в наличии замещающую схему раздела базы знаний.

define("PortalKnowledgeBaseSection", ["HtmlEditModule", "PortalKnowledgeBaseSectionStructure", "PortalKnowledgeBaseSectionResources", "ckeditor-base", "jQuery"],
function (HtmlEditModule, structure, resources) {
    return {
        /* #region  Схема. */
        entitySchemaName: "KnowledgeBase",
        /* #endregion */
        //...
        /* #region  Методы. */
        methods: {
        //...
            /* #region  Клик по кнопке "Полноэкранный режим". */
            onFullscreenModeClick: function () {
                let control = structure;  // ok
                let schema = structure.schema;  // ok
                let rightPanel = structure.schema.rightPanel;  // ok
                // let find = structure.schema.rightPanel.find("ckeditor");  // not ok
                // let item = structure.schema.rightPanel.items[itemIndex];  // not ok
                // //перебором ищем нужный контрол по имени
                // while (item.name !== "...") {
                // ...
                // }
                let editor = $("#MyFieldHtmlEdit-html-edit"); // ok
                // htmlEdit.height(200);
                //...
                let editor = this.editor;  // not ok
                if (editor) {
                    editor.execCommand("maximize");
                }
            },
            /* #endregion */
        },
        /* #endregion */
    };
});

Вопрос: Не получается получить доступ к контролу "ckeditor", для последующей передачи в него команды максимизации окна.

Нравится

2 комментария

Добрый день.

Я рекомендую вам использовать вместо jquery:

let editor = $("#MyFieldHtmlEdit-html-edit");

 

Нашу конструкцию, получения компонента:

var container = Ext.getCmp("MyFieldHtmlEdit")

И у данного контейнера есть свойство editor которым уже можно свободно оперировать.



Самый простой пример - зайдите на страничку редактирования KnowledgeBase и в консоль выполните следующую команду:Ext.getCmp("KnowledgeBasePageV2NotesHtmlEdit").editor.execCommand("maximize")

Григорьев Михаил Алексеевич,

Спасибо, это то, что нужно.

// KnowledgeBasePageV2NotesHtmlEdit - обычная версия 
// PortalKnowledgeBasePageNotesHtmlEdit - портальная версия
var container = Ext.getCmp("PortalKnowledgeBasePageNotesHtmlEdit")
if (container &amp;&amp; container.editor) {
  container.editor.execCommand("maximize");
}

 

Показать все комментарии

Добрый вечер, Коллеги.

У кого-нибудь возникала на странице еще "одна страница с полями" (см. скрин внизу)

В мастере разделов нижней страницы нет.

Изображение удалено.

Нравится

2 комментария
Лучший ответ

На странице описано поле(в diff),  у которого неправильно указан родительский контейнер

Похоже на деталь "Связи". Вы делали новую страницу на основе Активности?

На странице описано поле(в diff),  у которого неправильно указан родительский контейнер

Показать все комментарии

Как проще всего вызвать я. карты в своем модальном окне? Окно сейчас сделал по кнопке в разделе.

Карты должны вызываться отправкой запроса, подключаются так:

<head>
    <script src="https://api-maps.yandex.ru/2.1/?apikey=API-ключ&lang=ru_RU" type="text/javascript">
    </script>
</head>

для карт существует условие полной загрузки на странице DOM-элементов, контейнера куда разместится карта, перед выполнением вызова самой карты:

В качестве контейнера может использоваться любой HTML-элемент блочного типа (например, элемент div). Карта заполнит этот элемент полностью.
 
<body>
    <div id="map" style="width: 600px; height: 400px"></div>
</body>

Я пытался подключить карты в отдельном модуле, но не знаю как в модуле сделать вызов чтобы появился новый класс ymaps.

Может быть знаете путь?

Нравится

3 комментария

Вопрос добавления JS по внешнему адресу обсуждался тут.

Кстати, в маркете есть несколько дополнений по работе с «Яндекс-картами», они бесплатные, можно установить и проверить, как они решили.

А ещё на днях писал о способе добавить код на все страницы.

так добавление js по внешнему адресу не подходит для решения. Код карт высылается в ответ на Get запрос с ключом к Api. Способ конечно есть. Надо создать новый визуальный модуль. В нем создать вью модель, в которой в секцию metods поместить вызов ссылки к апи по ajax. Затем можно конструкцию ymaps  использовать в дальнейшем. Во вью модель поместить свою логику работы с картами по документации Яндекса и связать со вью. Решение с маркетплейса подсказало этот ход.

 

У меня есть вопрос. В каком методе кода из примера ниже мне вызвать логику моего модуля, чтобы карты открылись в модальном окне?

https://community.terrasoft.ru/articles/prosteyshee-modalnoe-okno-modal…;

Если у Вас уже есть окно с картами и нужно открыть его как модальное, см. тут.

Показать все комментарии

Добрый день.

Поставлена задача - регулярно пополнять раздел Продукты из прайслистов + в каждый продукт добавлять фото.

Фото хранятся 

1. в отдельных файлах (в структурированных папках) 

2. в файлах excel

3. в 1С

 

Коллеги, у кого есть опыт массовой загрузки файлов в карточки продуктов?

Спасибо.

 

Видела подобную тему двухгодичной давности ИМПОРТ ФОТО ИЗ EXCEL

Есть ли подвижки?

 

Нравится

1 комментарий

Марина, стандартного решения, скорее всего, нет.

Тем более, Вы хотите загружать из трёх разнотипных мест: ФС, Excel и 1С. Для каждого нужно искать или разрабатывать свои инструменты.

 

Для файлов, проверьте возможности дополнения «File manager», там упоминается работа с галереями фото продуктов.

 

По Excel — сомневаюсь, что такое стандартно будет, нужно смотреть либо в строну встроенных скриптов на Бейсике, либо разбирать формат файла или использовать библиотеки для работы с ним. Кстати, xlsx  — это просто zip-архив, если файл переименовать и распаковать в папку, все картинки там будут.

 

С системой 1С тоже есть несколько интеграций, нужно смотреть их возможности.

 

Показать все комментарии