Собственно, нужно получить некие данные с внешнего API, и потом нарисовать их на странице раздела. Прошу подсказки, в какую сторону смотреть и двигаться. В Академии есть пример с добавлением строки-приветствия. Однако, совсем не понятен принцип работы кода с примера. Документация по Terrasoft Javascript API так же не понятна. Прошу подсказки, куда смотреть и в какую сторону двигаться.

Нравится

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

Если сервер API предоставляет специализированные заголовки CORS то в Вашем распоряжении вся мощь JavaScript в клиентской схеме, делайте запросы (н/п используя инструментарий используемой библиотеки Ext.JS AJAX), обрабатывайте ответы - устанавливайте атрибуты для заполнения полей и т.д.

Если сервер API не предоставляет специализированные заголовки CORS то в данном случае Вам придется писать код C# (Здесь я сильно не подскажу что да как, веб-сервис что-то там такое есть)
После чего можете например по websocket протоколу пробросить события с данными в клиентские карточки (как это сделать обсуждалось вот здесь)

"Севостьянов Илья Сергеевич" написал:Если сервер API не предоставляет специализированные заголовки CORS то в данном случае Вам придется писать код C#

Из js вызываете сервис. В сервисе обычные post/get запросы с помощь System.Web. Получаете ответ от сервера, делаете return, в js-коллбеке проходит ответ в json-строке. Сериализуете, обрабатываете далее как угодно

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

Использование ES6 в JavaScript модулях и клиентских схемах?
Собственно пробовал ли кто ? или может у оф.представителей есть рекомендации/предостережения на этот счет.
Уж больно много возможностей предоставляет новый стандарт, и фактически полностью поддерживается мажорными версиями всех популярных браузеров - ну как минимум в части:
promise, yield, именованных аргументов функций и значений по умолчанию, деструктуризация массивов и объектов и т.д.

Нравится

9 комментариев

Здравствуйте, в системных требованиях все еще значится IE11:
https://academy.terrasoft.ua/documents/marketing/7-8/sistemnye-trebovan…
А следовательно в рамках ядра и схем системы не может быть ни промисов, ни большинства других фишек ES6.
Вы конечно можете начать использовать в своих доработках любые вещи из ES6, но тем самым ограничите доступ к системе соответствующими браузерами.
Таблица поддержки ES6 браузерами:
https://kangax.github.io/compat-table/es6/

IE11... будь он неладен :)
Ну гипотетически с версии 7.10 - появляется полноценная выгрузка модулей в ФС и их комбэк (еще не пробовали но в release notes - есть)
Это позволяет подключить к делу Babel, не известно как он дружит с AMD-нотацией конечно, надо попробовать "бабельнуть"
Вот собственно пример:
Исходный код схемы использующей ES6

define("KmProjects1Page", ["TestMixin"], function(TestMixin) {
	return {
		entitySchemaName: "KmProjects",
		details: /**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/,
		diff: /**SCHEMA_DIFF*/[]/**SCHEMA_DIFF*/,
		attributes: {
			"TestAttrDefinition": {
				"dataValueType": Terrasoft.DataValueType.BOOLEAN,
				"value": false,
				"dependencies": [
					{
						"columns": ["Test"],
						"methodName": "TestMethod"
					}
				]
			}
		},
		methods: {
			"testES6Usage": function() {
			  // Expression bodies
        var odds = evens.map(v => v + 1);
        var nums = evens.map((v, i) => v + i);
        var pairs = evens.map(v => ({even: v, odd: v + 1}));
 
        // Statement bodies
        nums.forEach(v => {
          if (v % 5 === 0)
            fives.push(v);
        });
 
        // Lexical this
        var bob = {
          _name: "Bob",
          _friends: [],
          printFriends() {
            this._friends.forEach(f =>
              console.log(this._name + " knows " + f));
          }
        }
 
        //classes
        class SkinnedMesh extends THREE.Mesh {
          constructor(geometry, materials) {
            super(geometry, materials);
 
            this.idMatrix = SkinnedMesh.defaultMatrix();
            this.bones = [];
            this.boneMatrices = [];
            //...
          }
          update(camera) {
            //...
            super.update();
          }
          get boneCount() {
            return this.bones.length;
          }
          set matrixType(matrixType) {
            this.idMatrix = SkinnedMesh[matrixType]();
          }
          static defaultMatrix() {
            return new THREE.Matrix4();
          }
        }
 
        //promise
        let promise = new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve("result");
          }, 1000);
        });
        promise.then(
            result => {
              alert("Fulfilled: " + result);
            },
            error => {
              alert("Rejected: " + error);
            }
          )
			}
		},
		mixins: {
			TestMixin: "Terrasoft.TestMixin"
		},
		rules: {}
	};
});

После обработки Babel

"use strict";
 
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
 
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
 
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
 
define("KmProjects1Page", ["TestMixin"], function (TestMixin) {
  return {
    entitySchemaName: "KmProjects",
    details: /**SCHEMA_DETAILS*/{} /**SCHEMA_DETAILS*/
    , diff: /**SCHEMA_DIFF*/[] /**SCHEMA_DIFF*/
    , attributes: {
      "TestAttrDefinition": {
        "dataValueType": Terrasoft.DataValueType.BOOLEAN,
        "value": false,
        "dependencies": [{
          "columns": ["Test"],
          "methodName": "TestMethod"
        }]
      }
    },
    methods: {
      "testES6Usage": function testES6Usage() {
        // Expression bodies
        var odds = evens.map(function (v) {
          return v + 1;
        });
        var nums = evens.map(function (v, i) {
          return v + i;
        });
        var pairs = evens.map(function (v) {
          return { even: v, odd: v + 1 };
        });
 
        // Statement bodies
        nums.forEach(function (v) {
          if (v % 5 === 0) fives.push(v);
        });
 
        // Lexical this
        var bob = {
          _name: "Bob",
          _friends: [],
          printFriends: function printFriends() {
            var _this = this;
 
            this._friends.forEach(function (f) {
              return console.log(_this._name + " knows " + f);
            });
          }
        };
 
        //classes
 
        var SkinnedMesh = function (_THREE$Mesh) {
          _inherits(SkinnedMesh, _THREE$Mesh);
 
          function SkinnedMesh(geometry, materials) {
            _classCallCheck(this, SkinnedMesh);
 
            var _this2 = _possibleConstructorReturn(this, _THREE$Mesh.call(this, geometry, materials));
 
            _this2.idMatrix = SkinnedMesh.defaultMatrix();
            _this2.bones = [];
            _this2.boneMatrices = [];
            //...
            return _this2;
          }
 
          SkinnedMesh.prototype.update = function update(camera) {
            //...
            _THREE$Mesh.prototype.update.call(this);
          };
 
          SkinnedMesh.defaultMatrix = function defaultMatrix() {
            return new THREE.Matrix4();
          };
 
          _createClass(SkinnedMesh, [{
            key: "boneCount",
            get: function get() {
              return this.bones.length;
            }
          }, {
            key: "matrixType",
            set: function set(matrixType) {
              this.idMatrix = SkinnedMesh[matrixType]();
            }
          }]);
 
          return SkinnedMesh;
        }(THREE.Mesh);
 
        //promise
 
 
        var promise = new Promise(function (resolve, reject) {
          setTimeout(function () {
            resolve("result");
          }, 1000);
        });
        promise.then(function (result) {
          alert("Fulfilled: " + result);
        }, function (error) {
          alert("Rejected: " + error);
        });
      }
    },
    mixins: {
      TestMixin: "Terrasoft.TestMixin"
    },
    rules: {}
  };
});

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

PS: Единственное, что для полного счастья надо бы подключить полифил от Babel, и вот кстати вопрос - как в рамках идеологии системы корректно подключать JS-либы ?

"Севостьянов Илья Сергеевич" написал:выгрузка модулей в ФС

Это было и раньше, но для on-site.
"Севостьянов Илья Сергеевич" написал:корректно подключать JS-либы

Через define, к примеру схема: jQuery, там в теле дефайна просто функция которая сама себя и вызывает, обогащая глобальный контекст либой JQuery, в глобальную переменную $
Так что полифилы можно подключить примерно таким же способом, т.к. они обогащают глобальный контекст.
В схеме где нужна будет данная логика, схему либы необходимо будет подключать в блок зависимостей:
define("ContactPageV2", ["JQuery"], function() { ... Либо в ините, через реквайр:
require(["jQuery"], function() {});
Так же через define можно делать либы что возвращают объект, но с этим думаю понятно.
define("ContactPageV2", ["MyLib"], function(myLib) { ...
require(["MyLib"], function(myLib) {});

"Максим Шевченко" написал:Это было и раньше, но для on-site.

В каком формате ?

Мы изначально сильно болели этой темой начиная работать еще с 7.8
Задавали вопрос в саппорт, вот нам как раз про "весенний релиз" - обещали, ну вот в 7.10 появилось в релиз-нотах.

Если это можно сделать для 7.8, 7.9 - прошу поделиться HowTo ? (Т.к. проекты есть и вряд ли они прям быстро сейчас все пообновляются)

PS: Можно было чекаутить/чекинить из SVN в ФС - но это то еще удовольствие особенно в части работы со схемами объектов и Бизнес процессами, да и метаданных тьма, абсолютно не ясно что там от чего зависит, т.к. судя по истории комитов в SVN из приложения просто работа с кодом схем иногда приводит к изменению каких-то метаданных и т.д.

"Севостьянов Илья Сергеевич" написал: каком формате ?

Я имел в виду useFileContent, для он-сайт, выгружает схемы в ФС, и позволяет разрабатывать прямо там, вот инструкция: https://academy.terrasoft.ru/documents/technic-sdk/7-9/rabota-s-klients…

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

"Севостьянов Илья Сергеевич" написал:ну это только схемы, причем "скопом" без иерархического какого либо деления, что не есть удобно - это раз, во-вторых это никоим образом не позволяет в виде файлов опять же деплоить на прод... вообщем годится только для выгрузки сорцов по сути.

Скоро будет документация по ФС в 7.10:
http://www.community.terrasoft.ru/forum/topic/25319

Будет с иерархией, но тоже только для on-site.

Ну я так понимаю будет возможность пакеты заворачивать в zip/gz и сетапить.
На демочке уже засекли занятные новые опции:

Я так понимаю речь как раз идет про пакеты выгружаемые в ФС.
Но засетапить их можно будет я так понимаю и в cloud версии ?

Здравствуйте, Илья.

Да, для сайтов on-demand также доступна данная функция. В версии 7.10 пользователи могут самостоятельно устанавливать пакеты.

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

Версия приложения 7.8

Тривиальнейшая для любой многопользовательской системы задача:
"Разграничивать UI функциональность на основе принадлежности текущего пользователя к группе/роли и т.д."
Как правило в системах имеется API/функционал для получения/проверки этой информации.
Как быть с BPMOnline и кодом исполняющимся в клиентских схемах (JavaScript).
Пример юзкейса: Показывать кнопку только пользователям одного OU или FU, а стало быть осуществлять проверку при инициализации по данным текущего юзера.

Все что пока что удалось найти это:

this.Terrasoft.SysValue


Из этого объекта можем получить ряд информации, на любом этапе выполнения кода.
PS: В исходных кодах (Правда 7.9, возможно в 7.8 - еще не было) обнаружено также частое использование
Terrasoft.CurrentUser
// его свойств userType, contactId и т.д.

Но в моем случае он постоянно undefined

Далее в исходниках и на этом форуме пытался найти функционал который так или иначе использует значения Id-шника пользователя для получения списка его OU и FU
Я прямо таки вижу какой ни будь

Terrasoft.util.getUserOrganizationUnits(UserId);
Terrasoft.util.getUserFunctionalityUnits(UserId);

Но ничего подобного найти пока не удается.
Неужели действительно вспомогательных средств для определения Организационных юнитов и Функциональных ролей текущего пользователя, да и пользователя в принципе в системе не предусмотрено, и единственный способ это ESQ-запрос в соответствующие таблицы БД ?

Нравится

6 комментариев

Здравствуйте, Илья.

Получить Id текущего пользователя возможно следующим кодом:

Terrasoft.core.enums.SysValue.CURRENT_USER.value

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

"Севостьянов Илья Сергеевич" написал:единственный способ это ESQ-запрос в соответствующие таблицы БД ?

Ага. Самое обидное - запрос с коллбэком и приходится каждый раз изворачиваться.
Кстати в приведённом кейсе все относительно легко делается.

А где, в каких таблицах что лежит, что-то я запутался...
SysAdminUnits - содержит в себе и пользователей и орг роли вперемешку.
В каких таблицах соотношение самих пользователей к OU не ясно
Есть некая SysAdminUnitsInRole
Может кто ни будь прояснить:
1) В какой таблице хранятся сами пользователи ?
2) В какой таблице хранятся Организационные юниты ?
3) В какой таблице хранятся Функциональные роли ?
5) В каких таблицах определяется принадлежность пользователя или OU к FR и и т.д.?

Илья, названия таблиц в единственном числе: SysAdminUnit, SysAdminUnitInRole.

SysAdminUnit — хранятся и пользователи, и роли всех видов. Тип записи задаётся числом в поле SysAdminUnitTypeValue. Расшифровку чисел можно посмотреть в таблице SysAdminUnitType. 4 — пользователь, 5 — портальный, 6 — функциональная, 0, 1, 2, 3 — разные организационные.

SysAdminUnitInRole — вхождение пользователей в роли. В записи две ссылки на SysAdminUnit, в полях SysAdminUnitId и SysAdminUnitRoleId указаны, соответственно, пользователь и роль.

Для всех кто будет озадачен этой проблемой, выкладываю решение, чтобы вы не тратили свое драгоценное время.
Миксин-модуль "UserUtilsMixin"

define("UserUtilsMixin", ["UserUtilsMixinResources"],
	function(resources) {
		Ext.define("Terrasoft.configuration.mixins.UserUtilsMixin", {
			"alternateClassName": "Terrasoft.UserUtilsMixin",
			"getRelAU": function(UserId, callback) {
				var esq = Ext.create("Terrasoft.EntitySchemaQuery", {
					rootSchemaName: "SysUserInRole"
				});
				var filter = this.Terrasoft.createColumnFilterWithParameter(
					this.Terrasoft.ComparisonType.EQUAL,
					"SysUser",
					UserId
				);
				esq.filters.addItem(filter);
				esq.addColumn("SysRole");
				esq.addColumn("[SysAdminUnit:Id:SysRole].Name", "AuName");
				esq.addColumn("[SysAdminUnit:Id:SysRole].ParentRole", "Parent");
				esq.addColumn("[SysAdminUnit:Id:SysRole].[SysAdminUnitType:Value:SysAdminUnitTypeValue].Name", "AuType");
				esq.getEntityCollection((function(response) {
					if (response && response.success) {
						var resultObject = {
							FuncRoles: [],
							OrgUnits: [],
							Organizations: []
						};
						response.collection.each(function(item) {
							var wrapObj = {
								name: item.values.AuName,
								id: item.values.SysRole.value,
								parentAU: item.values.Parent
							};
							var type = item.values.AuType;
							if (type === "Division") {
								resultObject.OrgUnits.push(wrapObj);
							} else if (type === "Функциональная роль") {
								resultObject.FuncRoles.push(wrapObj);
							} else if (type === "Organization") {
								resultObject.Organizations.push(wrapObj);
							}
						});
						this.callback(resultObject);
					}
				}).bind({"callback": callback}), this);
			}
		});
	});

Расширяет текущий набор методов (схемы куда данный миксин будет подключен), методом
getRelAU (user_id, callback);
user_id - [color=red](String)[/color] [color=green][Обязательный][/color] идентификатор Id пользователя информацию по Административным юнитам которого требуется получить.
callback - [color=red](Function)[/color] [color=green][Обязательный][/color] коллбек, принимающий один аргумент, в котором будет содержаться результирующий объект, см. структуру результирующего объекта далее
пример вызова:

	this.getRelAU(
             Terrasoft.core.enums.SysValue.CURRENT_USER.value, 
             function(result) {
		console.log(result);
             }
        )

Результирующий объект:

в нем "Функциональные роли":

в нем "Организационные юниты":

и "Организации":

Пользуйтесь на здоровье :)
PS: В идеале надо иерархическую информацию полностью до корня по FU и OU собирать, но это подзапросы (тяжело по перфомансу и все таки наверное это частный случай) в текущем варианте вытягиваются данные по прямому родителю - обычно этого достаточно.

в отдельной теме разместил обновленный вариант миксина.

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

Как осуществить вызов метода, другого, заведомо известного модуля/схемы ?

Например вызвать метод addRecord некоей детали на странице карточки - из кода метода который забинжен на кнопку верхнего горизонтального меню этой карточки.

Побочный вопрос: Как вообще доступаться до других модулей/схем без использования событийной модели, ведь модули и их методы - однозначно каким-то образом все в текущем окружении присутствуют, где в глобальном объекте находятся хранилище моделей и объекты загруженных модулей?

Нравится

5 комментариев

Добрый день.

Для данной цели Вам необходимо воспользоваться сообщениями sandbox. Данная тема подробно обсуждалось тут.

Подскажите, в клиентской схеме можно описать специальный конфигурационный объект messages, а как быть с модулями, у них иная структура AMD модуля.
Допустим я хочу использовать модуль-миксин.
В конфигураторе в структуре модуля модно добавить события (Messages).

насколько я понимаю - описать событие в коде самого модуля нельзя ?

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

Как же так получается ?
В модуле объявляется событие, но подключив этот модуль к карточке - объявленные в нем события не доступны для публикации ?

Здравствуйте, Илья.

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

Подскажите, почему даже если указать в зависимостях схемы модуль в котором объявлено "сообщение",
скажем некий модуль AksQuestionMessages

define("AksQuestionMessages", [], function() {
	return {
		messages: {
			"AddNewEmailFromCaseAskQuestion": {
				mode: this.Terrasoft.MessageMode.BROADCAST,
				direction: this.Terrasoft.MessageDirectionType.PUBLISH
			}
		}
	};
});

Далее в зависимостях схемы подключаем данный модуль - и все равно при попытке публикации сообщения в любом методе карточки - получаем ошибку про необъявленное сообщение.
Каким же образом наследуются сообщения ?
Неужели единственный способ это объявлять их непосредственно в коде схемы или ее замещающего объекта ?

Сам отвечаю на свой вопрос - для этого существует специальный метод, разместить его вызов следует в момент инициализации схемы, т.е. в методе "init":

this.sandbox.registerMessages(AksQuestionMessages.messages);

в приведенном примере - AksQuestionMessages это некий модуль из зависимостей текущей схемы,

define("CasePage", ["AksQuestionMessages", "AskQuestionMixin", "css!AskQuestionCSS"], function(AksQuestionMessages) {
	return {
		entitySchemaName: "Case",
...

messages - соответственно его конфигурационный объект с событиями.

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

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

Добрый день.
На ContactPage есть деталь ContactCommunication.
Необходимо при удаления средства связи перемещать его в временную
таблицу, удалив из ContactCommunication

Подскажите как лучше это сделать.
p.s.Думали отловить удаленный элемент(ы) с детали.
Не получилось это сделать. Метод this.get("DeletedItems") в
методе save детали не возвращает values удаленных елементов.

Нравится

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

Вижу два пути
- тяжелый реализация на уровне субд - триггером;
- простой процесс со стартовым сигналом удаление записи

"Александр Кудряшов" написал:

Вижу два пути

- тяжелый реализация на уровне субд - триггером;

- простой процесс со стартовым сигналом удаление записи

- Вес запроса зависит от его реализации:smile:
- Не получится. Необходимо определить процесс на событие "Перед удалением записи" непосредственно в объекте ContactCommunication.

"Демьяник Алексей" написал:Не получится

получится
ставите сигнал, получаете идентификатор, затем чтение данных из СредствСвязиКонтакта с id= идентификатору из первого элемента. А потом делайте с результатом чтения данных что хотите. Проверил на 7.7.0 - создал по факту удаления активность с заголовком = удаленному номеру :)
Для удаления номера использовал действие "удалить" в детали (см скрин)
Просто доверьтесь bpmonline :)

"Демьяник Алексей" написал:Необходимо определить процесс на событие "Перед удалением записи" непосредственно в объекте ContactCommunication.

это кстати тоже отличный вариант, но мозг измученный клиентским кодом его сразу не рассмотрел

Всем спасибо за советы.
Сделал через триггер, так как другой вариант через бизнес процесс для меня сложнее)

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

Коллеги, приветствую.

Есть некоторый код простого клиентского модуля, который должен показать простую карточку с текстовым полем и кнопками "Отмена" и "Далее".

 

define("UsrPlanningTasksForCustomer", ["CustomProcessPageV2Utilities"], function() {
        return {
                entitySchemaName: "Contact",
                mixins: {
                        BaseProcessViewModel: "Terrasoft.CustomProcessPageV2Utilities"
                },
                attributes: {
                        "Employee": {
                        caption: { "bindTo": "Resources.Strings.EmployeeCaption" },
                        dataValueType: Terrasoft.DataValueType.TEXT
                        }
                },
                details: {
                },
                methods: {
                        getHeader: function() {
                                return this.get("Resources.Strings.PageHeaderCaption");
                        },
                        onMyCancelButtonClick: function() {
                                this.set("Result", "RejectedByCustomer");
                                this.acceptProcessElement();
                        },
                        onNextButtonClick: function() {
                                this.set("Result", "Next");
                                this.acceptProcessElement();
                        }
                },
                diff:
                [
                       
                        {
                                "operation": "remove",
                                "name": "DelayExecutionButton"
                        },
                        {
                                "operation": "remove",
                                "name": "actions"
                        },
                        {
                                "operation": "remove",
                                "name": "SaveButton"
                        },
                        {
                                "operation": "remove",
                                "name": "CancelButton"
                        },
                        {
                                "operation": "remove",
                                "name": "DiscardChangesButton"
                        },
                        {
                                "operation": "remove",
                                "name": "ViewOptionsButton"
                        },
                        {
                                "operation": "remove",
                                "name": "PrintButton"
                        },
                        {
                                "operation": "remove",
                                "name": "CloseButton"
                        },
                       
                        {
                                "operation": "insert",
                                "parentName": "LeftContainer",
                                "propertyName": "items",
                                "name": "MyCancelButton",
                                "values": {
                                        caption: { "bindTo": "Resources.Strings.MyCancelButton" },
                                        itemType: Terrasoft.ViewItemType.BUTTON,
                                        classes: {textClass: "actions-button-margin-right"},
                                        style: Terrasoft.controls.ButtonEnums.style.RED,
                                        click: {bindTo: "onMyCancelButtonClick"}
                                }
                        },
                        {
                                "operation": "insert",
                                "parentName": "LeftContainer",
                                "propertyName": "items",
                                "name": "NextButton",
                                "values": {
                                        caption: { "bindTo": "Resources.Strings.NextButtonCaption" },
                                        itemType: Terrasoft.ViewItemType.BUTTON,
                                        classes: {textClass: "actions-button-margin-right"},
                                        style: Terrasoft.controls.ButtonEnums.style.GREEN,
                                        click: {bindTo: "onNextButtonClick"}
                                }
                        },
                       
                        {
                        "operation": "insert",
                        "parentName": "Header",
                        "name": "DataGroup",
                        "propertyName": "items",
                        "values": {
                                itemType: Terrasoft.ViewItemType.CONTROL_GROUP,
                                items: [],
                                "caption": {"bindTo": "Resources.Strings.DataGroupCaption"},
                                "layout": { "column": 18, "row": 0, "colSpan": 18 },
                                controlConfig: {collapsed: false}
                        }
                        },
                        {
                        "operation": "insert",
                        "name": "TopCenterInfoBlock",
                        "parentName": "DataGroup",
                        "propertyName": "items",
                        "values": {
                                "layout": { "column": 0, "row": 0 },//, "colSpan": 15 },
                                "itemType": Terrasoft.ViewItemType.GRID_LAYOUT,
                                "items": []
                        }                                      
                ]
        };
});

 

Собственно, кнопки "Отмена" и "Далее" отображаются, но не отображается мое текстовое поле и, ко всему, появляются ряд полей, которые я не определял, как то "Продукт", "Прайс-лист", "Цена", "Валюта", "Налог".

Как удалить преднастроенные элементы и отобразить текстовое поле?

Был бы весьма признателен за информацию.

Спасибо.

--
С уважением, Алексей Быков.

Нравится

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

Так, собственно, как текстовое поле добавить примерно понял - нужно добавить соответствующий атрибут и в блоке diff определить контейнер, в него вложить метку и само поле:

attributes: {
	"EmployeeTextField": {
		caption: { "bindTo": "Resources.Strings.EmployeeCaption" },
		dataValueType: Terrasoft.DataValueType.TEXT
	}
}
...
 
diff:
[
	...
	{
		"operation": "insert",
		"parentName": "ProductGeneralInfoBlock",
		"propertyName": "items",
		"name": "PlanningBlock",
		"values": {
			"itemType": this.Terrasoft.ViewItemType.GRID_LAYOUT,
			"layout": { "column": 1, "row": 2, "colSpan": 24 },
			"items": []
		}
	},
	{
		"operation": "insert",
		"parentName": "PlanningBlock",
		"name": "EmployeeLabel",
		"propertyName": "items",
		"values": {
			"itemType": this.Terrasoft.ViewItemType.LABEL,
			"caption": { "bindTo": "Reources.Strings.EmployeeCaption" },
			"layout": { "column": 0, "row": 0, "colSpan": 2 }
		 }
	},
	{
		"operation": "insert",
		"parentName": "PlanningBlock",
		"propertyName": "items",
		"name": "EmployeeTextField",
		"values": {
			"itemType": this.Terrasoft.ViewItemType.TEXT,
			"layout": { "column": 2, "row": 0, "colSpan": 20 }
		}
	}
]

Но как удалить преднастроенные поля?

По всей видимости, нужно пронаследоваться от пустой схемы...

Да, нужно указать родительский объект "Базовая схема карточки ( NUI )"

Думаю как то так.
{
"operation": "remove",
"name": "PlanningBlock"

},

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

Здравствуйте.
Мастером деталей создал деталь на основе существующего объекта. По окончанию работы мастера в пакете Custom были созданы деталь и страница для редактирования детали. Добавил эту деталь на вкладку на странице, на которой деталь должна присутствовать. При визуализации страницы деталь отображается, но при нажатии на кнопку "Добавить" в детали вместо окна её редактирования появляется индикатор, состоящий из строки "Загрузка" и вращающегося колёсика слева от строки и эта картинка может присутствовать на экране сколько угодно долго. И деталь и окно её редактирования находятся в пакете Custom. Скажите, пожалуйста, из-за чего не срабатывает вывод окна редактирования детали при нажатии на "Добавить"?
Деталь построена на основе террасофтовского объекта ContactCareer.
В файле прикрепляю сообщение об ошибке, которое выводится в консоли отладчика браузера.

Нравится

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

Добрый день, Евгений.
Предоставьте, пожалуйста, оба кода: [Схемы детали] и [Карточки редактирования детали].

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

Здравствуйте.
У меня есть страница для ввода параметров поиска. Страница не привязана ни к какому объекту. Значения из её полей передаются в параметры бизнес-процесса, выполняющего поиск. Как мне с помощью функции asyncValidate из BasePageV2 проверить, что на моей странице поиска заполнены все поля?

Нравится

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

Здравствуйте, Евгений!

Для поля Вы можете использовать свойство enable: true. Этот признак сделает поле обязательным для заполнения. Таким образом Вы сможете осуществить валидацию на заполнения полей значениями.

Алексей, у меня в ТЗ указано, в частности, условие, что заполнение любого из полей не обязательно. Поэтому, я и прошу показать мне как проверить заполнение полей с помощью asyncValidate. Моя страница унаследована от модуля "Базовая схема карточки" из пакета NUI. К этому посту я прикрепил текстовый файл, содержащий Javascript страницы.

Евгений, добрый день!

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

asyncValidate: function(callback, scope) {
	this.callParent([function(response) {
		if (!this.validateResponse(response)) {
			return;
		}
		Terrasoft.chain(
			function(next) {
				this.myValidationMethod(function(response) {
					if (this.validateResponse(response)) {
						next();
					}
				}, this);
			},
			function() {
				callback.call(scope, response);
			},
			this);
		}, this]);
},

Спасибо.

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

В BPMonline 7.6 написал на Javascript модуль детали. В качестве родительской схемы модуль имеет схему "Базовая схема детали с реестром". Нужно зарегистрировать написанную мной деталь в справочнике деталей. Как это сделать в BPMonline 7.6. ?

Нравится

5 комментариев

Добрый день, создайте деталь на основе существующего объекта с помощью соответствующего мастера, о котором можно почитать в SDK:
Создание детали.

После этого деталь можно будет использовать на страницах, о чем вы тоже можете почитать в разделе SDK:
Настройка детали

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

Извините, пожалуйста, но мне хотелось бы знать, как регистрировать в БД деталь, которая была полностью написана вручную ?
И второе - если я с помощью мастера деталей создал деталь в пакете Custom, а затем, в свойствах этой детали, изменил пакет на другой, находящийся одним уровнем выше чем Custom, то регистрация детали, выполненная мастером при её создании, останется действительной ?

1. Я конечно рекомендую пользоваться мастером, а потом менять содержимое модуля, во избежание человеческого фактора и ради облегчения работы. Т.к. мастер, к примеру, сразу установит необходимые привязки на закладку данных.
Но если есть такая необходимость, можете зарегистрировать деталь в таблице SysDetail:

INSERT INTO SysDetail(Caption, DetailSchemaUId, EntitySchemaUId)
VALUES('Имя детали', 'B9956976-1FF5-4352-9534-AD87CA7EEA04', '080C9917-7EC9-42E5-86FF-75A683D4F124')

Где Caption - Имя детали;
DetailSchemaUId - UId детали;
EntitySchemaUId - UId объекта в котором деталь хранит свои данные.

2. Да, мастер раздела может брать детали из любых пакетов.

Спасибо.

из-за того что мастер глючит, как и вся BPM рекомендовать бессмысленно. если человек задал вопрос, значит он столкнулся именно с багом всей среды. У меня версия 7.10 и она глючит, не сохраняет детали, не сохраняет страницы в дизайнере. 

 

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

Здравствуйте.
Задаю здесь вопрос, т.к. в не нашёл описания таких вещей в SDK. Проблема заключается в следующем. Мне нужно (в BPMonline 7.6) разместить на странице две детали - одну справа от другой на одном уровне по горизонтали. Я пробовал определить на странице два группы следующим образом:

diff: [{
        "operation": "insert",
        "parentName": "Leftcontainer",
        "name": "MonthlyIncomesGroup",
        "propertyName": "items",
        "values": {
                itemType: Terrasoft.ViewItemType.CONTROL_GROUP,
                items: [],
                caption: {
                        "bindTo": "Resources.Strings.MonthlyIncomesGroupCaption"
                },
                controlConfig: {
                        collapsed: false
                }
        }
},
{
        "operation": "insert",
        "parentName": "RightContainer",
        "name": "MonthlyExpensesGroup",
        "propertyName": "items",
        "values": {
                itemType: Terrasoft.ViewItemType.CONTROL_GROUP,
                items: [],
                caption: {
                        "bindTo": "Resources.Strings.MonthlyExpensesGroupCaption"
                },
                controlConfig: {
                        collapsed: false
                }
        }
}
]

чтобы потом разместить в каждой из этих групп по одной детали. После запуска страницы, группа (с заголовком "ЕЖЕМЕСЯЧНЫЕ ДОХОДЫ") , размещённая в Leftcontainer позиционируется ниже, чем группа (с заголовком "ЕЖЕМЕСЯЧНЫЕ РАСХОДЫ") , размещённая в RightContainer, а мне нужно, чтобы они были на одном уровне по горизонтали. Кроме того, группа, размещённая в RightContainer слишком сильно смещена вправо, а мне нужно, чтобы она находилась ближе к левой группе. В вложенном файле прилагаю экранный снимок того, как эти группы сейчас размещены на экране. Как мне разместить две детали рядом на странице, чтобы одна была справа от другой и чтобы они были на одном уровне по горизонтали ?

Нравится

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

Евгений добрый день!!!

как я вам и писал ранее, для реализации вашей задачи требуется поподробнее познакомиться с разметкой Bootstrap, так же требуется поподробнее познакомиться с CSS 3.0, Для реализации вашей задачи действительно требуется создать в разметке 2 Контейнера, назвать их "Левый" и "Правый", а остальное, поведение и размещение контейнеров на странице вы делаете с помощью CSS стилей. Так же советую разобраться для начала со стандартными страницами "BasePageV2", "BaseSectionV2", какие уже стандартные контейнеры размещаются на странице, какие уже стандартные стили применены к данным контейнерам. И когда вы уже будите создавать свои 2 контейнера, вы будите понимать внутрь каких существующих контейнеров разместить свои, какие стандартные стили можно использовать, и какие свои требуется дописать.

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

Здравствуйте, Михаил. Я наследую свою страницу от "Базовая схема карточки (BasePageV2)" из пакета NUI. Я выбрал "Базовая схема карточки" в свойстве "Родительский объект" для моей страницы, когда её создавал. Если вы, как пишете, подготовите пример для моего случая, то буду вам очень благодарен.

Здравствуйте, Евгений!

Можно попробовать следующий вариант:
1) Сделать группу полей на нужной вкладке
2) Разместить на данной группе полей два Ваших контейнера, указав, их на одной строке и длиною строки [0;12] и [13;24] соответственно.

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