добрый день!

столкнулся со след проблемой:

1. в пакете название секции "Секция 12"

2. устанавливаю этот пакет в другую среду креатио, добавляю секцию в раздел

3. меняю название секции в пакете на "Секция 13" в оригинальной среде

4. устанавливаю пакет в другую среду, где уже был установлен пред пакет (обновление пакета)

5. название секции все еще "Секция 12"

 

удаление старого пакета и установка нового после не помогает, название так и остается старое. если зайти в свойста страницы, то там названия секции правильное - Секция 13.

 

с чем это может быть связано? сталкиваюсь уже не первый раз

спасибо!

Нравится

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

Добрый день!



Вам нужно в пакете найти данные с этим разделом. У них будет название типа SysModule_SectionManager_ и дальше набор символов.

К сожалению, так сложно найти - можно примерно определить по дате создания.

И в этих данных нужно указать Force update для колонки Title и обновить данные.

 

Владимир

Добрый день!



Вам нужно в пакете найти данные с этим разделом. У них будет название типа SysModule_SectionManager_ и дальше набор символов.

К сожалению, так сложно найти - можно примерно определить по дате создания.

И в этих данных нужно указать Force update для колонки Title и обновить данные.

 

Владимир

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

Добрый день! Есть задача скрывать кнопку "Печать" на странице записи в зависимости от некоторых условий. Были внесены изменения в страницу объекта с подключением миксина PrintReportUtilities, при перезагрузке страницы логика скрытия отрабатывает корректно. Но когда открытие страницы происходит через секцию, кнопка все равно отображается, не смотря на то что код на странице отрабатывает и скрывает её. Какие изменения нужно внести в секцию, что бы кнопка так же была скрыта?

Нравится

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

Илья, здравствуйте!

 

Вы изменили логику отображения кнопки "Печать" на странице, но дополнительно её нужно добавить в схеме раздела (Section), чтобы при открытии из раздела в совмещённом режиме логика также работала. В diff схемы BaseDataView есть элемент с названием "CombinedModePrintButton", который выводится при открытии в совмещённом режиме.

Пример с изменением страницы в совмещённом режиме есть в статье на академии, которую можно найти по ссылке:

https://academy.terrasoft.ua/docs/developer/elements_and_components/bas…

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

Добрый день!

 

Есть задача по реализации кнопки-меню с динамическим списком. Нужно создать кнопку по типу Actions или Print.

Я создала метод, который выбирает из списка нужные пункты и добавляет их как пункты меню:

attributes: {
	"ButtonMenu": {dataValueType: this.Terrasoft.DataValueType.COLLECTION},
},
methods: {
	init: function() {
		this.callParent(arguments);
		this.initMenuItems();
	},
initMenuItems:function(){
	var esq = this.Ext.create("Terrasoft.EntitySchemaQuery", {
		rootSchemaName: "MyList"
	});
	esq.addColumn("Caption");
	esq.filters.add("Section", this.Terrasoft.createColumnFilterWithParameter(this.Terrasoft.ComparisonType.EQUAL, "Section.Id", "f7856ad3-fa4c-4106-9a6c-d8dcd87331eb"));
	esq.execute(function (response) {
	        if (!response.success) {
		       return;
	        }
	        var actionMenuItems = Ext.create("Terrasoft.BaseViewModelCollection");
		response.collection.each(function(item) {
 
			var isVisible = this.getVisibility(item.get("Caption"));
			actionMenuItems.addItem(this.getButtonMenuItem({
				"Caption": item.get("Caption"),
				"Click": {bindTo: "callMyProcess"},
				"Enabled": isVisible
			}));
		},this);
		this.set("ButtonMenu", actionMenuItems);
	},this);			
}
},
		diff: /**SCHEMA_DIFF*/[
			{
                "operation": "insert",
                "parentName": "LeftContainer",
                "propertyName": "items",
                "name":"MenuButton",
                "values": {
                    "itemType": Terrasoft.ViewItemType.BUTTON,
                    "style": Terrasoft.controls.ButtonEnums.style.GREEN,
                    "caption": "Test",
                    "menu": {
                        "items": {"bindTo": "ButtonMenu"}
                    }
                }
            }
		]/**SCHEMA_DIFF*/

Когда я вызываю мой метод в методе init страницы раздела, то поставленная задача выполняется. НО портится стиль всех остальных кнопок списков, добавляя стрелку пролистывания как в большие, так и в маленькие списки:

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

 

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

 

Что сделано не правильно?

Подскажите, пожалуйста, как решить данную задачу.

 

Заранее спасибо.

Нравится

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

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

 

Реализовал Ваш пример на тестовом сайте, но подобной проблемы не наблюдаю. Похоже, что проблема не в предоставленном коде, а в чем-то другом. Просьба обратиться в техническую поддержку и указать ссылку на сайт, где реализован пример (или предоставить пакет). 

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

Доброго времени! 



У меня интересная задача)

Необходимо сменить ответственного у нескольких записей продаж.



Задача:

1. Поставить фильтр (допустим выдало 100 записей)

2. Нажать "Выбрать все" (показано что выбрано 100)

3. Снять 1 галочку (показано что выбрано 99)

4. Нажать "Изменить ответственного"



Методы:

var selectedRows = this.getSelectedItems();

var selectedRows = this.get("SelectedRows");



Возвращают Id только отображенных записей (29)!



Как получить ожидаемые 99 Id записей?

Нравится

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

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

Когда загружается реестр посылается один запрос (который оптимизирован и загружает не все записи, а 30 – если у вас 100000 записей то не будет накладки по производительности). Когда вы нажимаете «Выбирать все», то не произойдет загрузки всех записей(оптимизация описанная выше), а отправится отдельный запрос который просто вернет количество и обновит название кнопки (при дебаге в network это видно). Чтобы добиться требуемого результата нужно самостоятельно посылать запрос.

Тоже столкнулся с такой проблемой. Самое простое решение, которое я нашел - это использовать функцию, возвращающую запрос на получение записей для экспорта:

                    var esq = this.getExportToExcelEsq();

                    esq.rowCount = -1;

                    esq.getEntityCollection(function (response) {...}, this);

Можно посмотреть, как она работает и заменить её своей. Результатом запроса будут все выделенные записи (99 в Вашем случае).

 

Поправка: в 7.12.2 функция, возвращающая запрос, переехала, теперь так:

var esq = this.getGridDataInitializedEsq(true);

esq.rowCount = -1;

...

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

Добрый день.

Необходимо установить сортировку данных пользовательского раздела по умолчанию по определённому полю объекта.

В BaseSectionV2 используются атрибуты: "sortColumn", "SortColumnIndex", "GridSortDirection".

Так же в свойствах объекта есть свойство "Сортировка в списках".

Но установка значений этих атрибутов и свойства не решила задачу.

Прошу подсказать как решить данный кейс

Нравится

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

Добрый день

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

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

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

Нравится

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

Просто в странице в методе init описан onEntityInitialized, а в разделе - нет. Как вариант можно заместить базовую схему страницы и написать что-то своё:

init: function(callback, scope) {
	var performanceManagerLabel = "";
	if (scope && scope.hasOwnProperty("sandbox")) {
		performanceManagerLabel = scope.sandbox.id;
	} else if (this && this.hasOwnProperty("sandbox")) {
		performanceManagerLabel = this.sandbox.id;
	}
	performanceManager.start(performanceManagerLabel + "_Init");
	this.callParent([function() {
		Terrasoft.chain(
			this.checkAvailability,
			this.initViewModelValuesFromSysSettings,
			this.initActiveViewSettingsProfile,
			this.initData,
			this.initLeftSectionContainerSize,
			function(next) {
				this.canUseWizard(function(result) {
					this.set("CanUseWizard", result);
				}, this);
				this.checkCanManageAnalytics();
				this.initSectionFiltersCollection();
				this.initSortActionItems();
				this.initDataViews();
				this.initActionButtonMenu("Separate", this.getSectionActions());
				this.initSectionViewOptionsButtonMenu(this.getViewOptions());
				this.initDcmActionsDashboardVisibility(function() {
					this.initCanUseDcmDesigner();
				}, this);
				this.initEditPages();
				this.initCardContainer();
				this.initContextHelp();
				this.initAddRecordButtonParameters();
				this.initFolders();
				this.initRowCount();
				this.initIsPageable();
				this.initIsActionButtonsContainerVisible();
				this.initUpdateAction();
				this.initResetAction();
				this.subscribeInitFilterFromStorage();
				this.initActionsButtonHeaderMenuItemCaption();
				this.subscribeSandboxEvents();
				this.mixins.GridUtilities.init.call(this);
				this.subscribeIsCardVisibleChange();
				this.subscribeGetRunProcessesProperties();
				this.initRunProcessButtonMenu(false);
				this.subscribeCanShowTags();
				this.initActionsButtonCaption();
				this.subscibeOnMultiSelectChange();
				this.subscibeOnSelectedRowsChange();
				this.initTags(this.entitySchemaName);
				this.initSectionHeaderContainerVisibility();
				next();
			},
			function(next) {
				this.onSectionInitialized();
				next();
			},
			function() {
				performanceManager.stop(performanceManagerLabel + "_Init");
				performanceManager.start(performanceManagerLabel + "_BeforeRender");
				callback.call(scope);
			}, this);
		this.initHelpUrl(this.Terrasoft.emptyFn, this);
		this.initPrintButtonsMenu(this.Terrasoft.emptyFn, this);
	}, this]);
},
onSectionInitialized: function() {
	debugger;
}

Но работать будет немного криво (пр.: у меня при остановке на дебагере в "GridData" валяется пустая коллекция. Инициализируется она, видимо, позже). Посмотрите, может вам подойдёт.

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

Добрый день.
Стоит задача сделать аналог фиксированного фильтра "Ответственный" в р. Контрагенты.
Фильтрация происходит по детали "Сервисы контрагента".
Фильтр в AccountSectionV2:

 initFixedFiltersConfig: function() {
                    var fixedFilterConfig = {
                        entitySchema: this.entitySchema,
                                                        filters: [
                             {
                                                                        name: "AccountServiceItem",
                                                                        caption: resources.localizableStrings.AccountServiceItemFilterCaption, //"Cервисы контрагента"
                                                                        dataValueType: this.Terrasoft.DataValueType.LOOKUP,
                                    //filter: this.getAccountServiceFixedFilter,
                                                                        appendFilter: this.getAccountServiceFixedFilter,
                                                                        columnName:"UsrServiceItem",
                                    //defValue: null,
                                    referenceSchemaName:"UsrAccountServiceItem",
                                    markerValue: "AccountServiceItemFixedFilterBtn",
                                    buttonImageConfig: resources.localizableImages.AccountServiceItemFilterImage,//путь к картинке Сервисов
                                    hint: "",
                                                                    appendCurrentContactMenuItem : false,
                                    addNewFilterCaption : resources.localizableStrings.AccountServiceItemAddNewFilterCaption, //"Выбрать сервисы",
                                    isCustomFilter: true //нужен для запуска пользовательской логики построения фильтра
                                }
                            ]
                    };
                    this.set("FixedFilterConfig", fixedFilterConfig);
                },

                getAccountServiceFixedFilter: function(filterInfo){
                    //Фильтр по детали AccountServiceItem
                    debugger;
                    var filter;
                    if (!Ext.isEmpty(filterInfo.value) && filterInfo.value.length > 0) {
                        filter = Terrasoft.createColumnInFilterWithParameters(
                                                        "[UsrAccountServiceItem:UsrAccount:Id].UsrServiceItem.Id", filterInfo.value);
               
                    }
                    return filter;

                }

Создал замещающий клиентский модуль FixedFilterViewModelV2 (см. прикреплённый файл).

Фильтр работает, НО после перехода между разделами фильтр перестаёт работать, хотя getAccountServiceFixedFilter отрабатывает и контейнер фиксированного фильтра отображается.

Подскажите, кто сталкивался с подобной задачей, что я упустил из виду.
Версия 7.8.0.1005_CustomerCenter

Нравится

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

Коллега, вот же есть идеальная статья по созданию быстрого фильтра - https://academy.terrasoft.ru/documents/technic-sdk/7-7-0/kak-dobavit-v-…

Иначе нужно дебажиться

Илья, в указанной статье показан пример добавления стандартных фильтров.
Мне же нужен фильтр по аналогии с фильтром "Ответственный".
Он реализован, но не срабатывает после перехода между разделами, как я писал выше

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

Может проблема в асинхронности вызова - фиксированные фильтры раздела приходят после загрузки реестра?

Однако, Фильтр "Ответственный" в разделе Активности отрабатывает корректно. А я делал по его аналогии.

Предоставьте, пожалуйста, листинг AccountSectionV2.

"Демьяник Алексей" написал:Предоставьте, пожалуйста, листинг AccountSectionV2.

В NUI.ActivitySectionV2 переопределен метод init():

				init: function(callback, scope) {
					this.set("SelectedRows", []);
					this.initFiltersUpdateDelay();
					this.registerGetIsVisibleEmailPageButtonsHandler();
					this.initScheduleGridData();
					this.initSchedulerFloatItemsCollection();
					this.initSchedulerTimeScaleLookupValue();
					this.initMailBoxSyncSettings();
/* вот здесь вызывается метод, который фильтрует записи*/
					this.initFixedFiltersConfig();
					this.initIntervalMenuItems();
					this.callParent([function() {
						this.initSchedulerItemsAmountPerPage(function() {
							callback.call(scope);
						}.bind(this));
					}, this]);
					var sysSettings = ["BuildType"];
					Terrasoft.SysSettings.querySysSettings(sysSettings, function() {
						var buildType = Terrasoft.SysSettings.cachedSettings.BuildType &&
							Terrasoft.SysSettings.cachedSettings.BuildType.value;
						this.set("canUseSyncFeaturesByBuildType", buildType !==
						ConfigurationConstants.BuildType.Public);
					}, this);
					this.initGoogleSyncExists();
					this.initGoogleCalendarLog();
				},

Предполагаю, что Ваш метод не вызывается на init раздела (судя по листингу кода). Отсюда - раздел не фильтруется.

Вызывается, т.к. я переопределил и FixedFilterViewModelV2 (файл прикреплён в первом посте) и добавил свой функционал в метод init (см. блок строк 416-432).

Здравствуйте,
советую не трогать фиксированные фильтры, и воспользоваться решением, предоставленным тут:
http://www.community.terrasoft.ua/forum/topic/15943#comment-60027
По факту это будет то же самое, лукап в панеле фильтров, завязанный на атрибут (вирутальный) по изменению которого вы будете накладывать любую доп. фильтрацию на раздел.
Проверил все на 7.8. работает, и багов при переходе между разделами так же не заметил. Вот пример для раздела контрагентов, фильтрую по значению лукапа с типом город, по детали адреса контрагентов:

Сама замещающая страница секции контрагентов:

define("AccountSectionV2", ["BaseFiltersGenerateModule", "css!UsrMyFilterStyle"], function(BaseFiltersGenerateModule) {
	return {
		entitySchemaName: "Account",
		details: /**SCHEMA_DETAILS*/{
		}/**SCHEMA_DETAILS*/,
		diff: /**SCHEMA_DIFF*/[
			{
				"operation": "insert",
				"name": "MyFilterContainer",
				"parentName": "LeftGridUtilsContainer",
				"propertyName": "items",
				"index": 0,
				"values": {
					"id": "MyFilterContainer",
					"itemType": this.Terrasoft.ViewItemType.CONTAINER,
					"items": []
				}
			},
			{
				"operation": "insert",
				"parentName": "MyFilterContainer",
				"propertyName": "items",
				"name": "UsrCityFilter",
				"values": {
					"bindTo": "UsrCityFilter",
					"caption": "City"
				}
			}
		]/**SCHEMA_DIFF*/,
		attributes: {
			"UsrCityFilter": {
				"dataValueType": Terrasoft.DataValueType.LOOKUP,
				"type": Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
				isLookup: true,
				caption: "City",
				referenceSchemaName: "City"
			}
		},
		mixins: {
			LookupQuickAddMixin: "Terrasoft.LookupQuickAddMixin"
		},
		methods: {
 
			onLookupChange: function(newValue, columnName) {
				this.callParent(arguments);
				if (columnName === "UsrCityFilter") {
					this.set("UsrCityFilter", newValue);
					this.onUsrCityFilterChanged();
				}
			},
 
			onUsrCityFilterChanged: function() {
				this.reloadGridData();
			},
 
			initQueryFilters: function(esq) {
				this.callParent(arguments);
 
				var usrCityFilter = this.get("UsrCityFilter");
 
				if (usrCityFilter && usrCityFilter.value) {
					esq.filters.add("UsrCityFilter", this.Terrasoft.createColumnFilterWithParameter(
						this.Terrasoft.ComparisonType.EQUAL, "[AccountAddress:Account:Id].City", usrCityFilter.value));
				} else {
					esq.filters.removeByKey("UsrCityFilter");
				}
			}
 
		}
	};
});

Дополнительные стили для расположения фильтра в том же ряду что и базовые (UsrMyFilterStyle):

#MyFilterContainer {
	display: inline-block;
	float: left;
	position: relative;
	padding-top: 5px;
}
 
#AccountSectionV2UsrCityFilterContainer_Label {
	max-width: 3em;
	min-width: 3em;
}
 
#AccountSectionV2UsrCityFilterContainer_Control {
	width: auto;
}

Результат:

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

Здравствуйте, развивая идею с фильтрацией в initQueryFilters: доработайте поле выбора пользовательским методом открытия формы подбора, примеров справочников с мультивыбором в системе достаточно, можно поискать по ключевому слову «multiSelect: true».
К примеру, в «EmailPageV2» такие есть:

Для контрола «текст» там задается иконка выбора и обработчик её нажатия:

"controlConfig": {
   "className": "Terrasoft.TextEdit",
   "rightIconClasses": ["custom-right-item", "lookup-edit-right-icon"],
   "rightIconClick": {
      "bindTo": "openRecepientLookupEmail"
   }
}

Потом в методе открывается своя форма подбора с мультивыбором, мультивыбор задается в конфиге:

getLookupConfig: function(columnName) {
   var scope = this;
   var callback = function(args) {
      scope.onLookupSelected(args);
   };
   return {
      config: {
         entitySchemaName: "VwRecepientEmail",
         columnName: columnName,
         columns: ["ContactId"],
         filters: Terrasoft.createColumnIsNotNullFilter("ContactId"),
         multiSelect: true
      },
      callback: callback
   };
},

Результат обрабатывается колбеком onLookupSelected
В теле которого само «текстовое» представление фильтра заполняется перечислением выбранных значений с произвольным разделителем, в примере EmailPageV2 это точка с запятой.

Далее, параллельно, в обработчике выбора запишите список значений в атрибут типа «массив», и в методе initQueryFilters стройте группу фильтров, в которые через логическое ИЛИ помещайте выбранные значения. Все, мультивыбор есть, фильтрация с ИЛИ по выбранным значениям есть. Да задача достаточно массивная и требует навыков разработчика, готовый большой пример быстро не написать. Но алгоритм приблизительно таков как я описал в дополнение к предыдущему комментарию. Если где-то возникнут точечные трудности и вопросы, задавайте, постараюсь помочь.

Илья, спасибо. Сам дошёл до этого варианта. Но при этом плывёт вёрстка и контейнер с фильтрами накладывается на фиксированные фильтры. + при переходе м/у разделами фильтр обнуляется.

На данный момент с фильтром есть две проблемы:
1.После перехода между разделами фильтр очищается. Как сохранить наполнение фильтра?
2. При открытии справочного поля необходима сортировка наполнения справочника. При открытии справочника я передаю в config массив:

sortedColumns:  [{
  name:"Name",
  orderPosition: 0,
  orderDirection: Terrasoft.OrderDirection.ASC
}]

В LookupPageViewModule.initSelectSorting сортировка применяется, однако в GridProfileHelper.initSelectSorting применяется стандартная сортировка по полю для отображения. По умолчанию для справочника это и есть поле Name, т.о. два правила сортировки применяются к одному и тому же полю. В итоге справочник не отсортирован. Как отключить стандартную сортировку?

1. Создать таблицу для кеша значений фильтрации, с колонкой «Ид пользователя», и текстовой строкой, в которую будете при onLookupChange новой фильтрации писать JSON массив значений поля сортировки (в том числе при очистке фильтра, в кеш писать тоже пустой JSON массив), а в «initQueryFilters» проверять таблицу кеша через esq запрос. Если в атрибуте пусто, а в кеше отличный от пустого JSON, восстанавливаете сохраненную в кеше фильтрацию.

2. Приоритет отдается сортировке, сохраненной в профиле, следовательно, либо очистить профиль, и тогда предсохраненной сортировки не останется, будет работать ваша, либо переписывать метод «initSelectSorting» в «GridProfileHelper», проверяя наличие в колонках из select атрибутов “orderDirection”, и если таковые есть, вовсе не применять к этим колонкам сортировку из «profileSortedColumns», но этим вы напрочь запретите пользователю изменить порядок сортировки через кнопку «Вид» -> «Сортировка», в форме выбора лукапа, для полей, сортировка которых передана программно. В общем, если решите замещать «GridProfileHelper», то часть коробочного функционала вы потеряете.

"Мотков Илья" написал:1. Создать таблицу для кеша значений фильтрации, с колонкой «Ид пользователя», и текстовой строкой, в которую будете при onLookupChange новой фильтрации писать JSON массив значений поля сортировки (в том числе при очистке фильтра, в кеш писать тоже пустой JSON массив), а в «initQueryFilters» проверять таблицу кеша через esq запрос. Если в атрибуте пусто, а в кеше отличный от пустого JSON, восстанавливаете сохраненную в кеше фильтрацию.

А разве стандартые фильтры (как быстрые, так и фиксированные) используют таблицу для кэша? Можно подробней о вашем варианте?

QuickFilterModule используют StorageUtilities, что по сути, что-то вроде document.scope в своем пространстве и с методами для хранения по группам, или по ключам. Можете использовать такой кеш, это решит вашу проблему с переходом по разделам. Но при повторном логине, или в другом браузере ваши фильтры слетят в ноль, и при установке будут жить в рамках сеанса.

FolderFilters, FixedFilters, TagFilters так же сохраняются в профиль, то есть, в таблицу в базе данных SysProfileData, к примеру:
SELECT * FROM SysProfileData WHERE [Key] = 'ActivitySectionV2GridDataViewFilters'

Это решает сохранение фильтров даже при выходе и заходе в приложение. В зависимости от того что вам необходимо, используйте первый или второй подход. Храните информацию в document.scope или в StorageUtilities. Либо создавайте свою таблицу для кеша и пишите в неё. Либо можете писать в SysProfileData, только используйте для этого свой уникальный ключ.

P.S. почитайте saveFilter в BaseSectionV2

Спасибо Илья!

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