Реализация представления (дополнительного реестра) в разделе
Задача: необходимо реализовать возможность переключения реестра в разделе. То есть, находясь в разделе "Контрагенты" переключать реестры с физическими и юридическими лицами, причём у каждого реестра свои определенные колонки.
Решение состоит из 2х частей:
- Добавить кнопки переключения между представлениями
- Собственно сделать страницы представлений
Добавление кнопок переключения реестров в раздел
Подготовлены спрайты кнопок:
Размер 30*60. Смысл в том, чтобы при наведении мыши фон кнопки съезжал на 30 пикселей, и как бы подсвечивался. Создан модуль, назвать, например SmrCustomButtonsCSS и определить LESS:
.blue-button-wrapper { width: 30px; height: 30px; padding: 0px; margin: 0px 5px 0px 5px; } .blue-button-image { display: inline; background-position: 0px 0px; width: 30px; height: 30px; padding: 0px; margin: 0px; } .blue-button-image:hover { display: inline; background-position: 0px -30px; } .blue-button-pressed { display: inline; background-position: 0px -30px; width: 30px; height: 30px; padding: 0px; margin: 0px; }
Создана замещающая страница "AccountSectionV2":
define("AccountSectionV2", ["ConfigurationConstants", "css!SmrCustomButtonsCSS"], function(ConfigurationConstants) { return { entitySchemaName: "Account", attributes: { }, methods: { showLegalView: function(){ this.sandbox. publish( "PushHistoryState", { hash : "SectionModuleV2/LegalAccountSectionV2" }); }, showIndividualView: function(){ this.sandbox. publish( "PushHistoryState", { hash : "SectionModuleV2/IndividualAccountSectionV2" }); }, showAllView: function(){ this.sandbox. publish( "PushHistoryState", { hash : "SectionModuleV2/AccountSectionV2" }); }, isSwitchButtonsContainerVisible: function() { var isCardVisible = this.get("IsCardVisible"); return !isCardVisible; } }, diff: /**SCHEMA_DIFF*/[ { "operation": "insert", "name": "SwitchViewButtonsContainer", "parentName": "ActionButtonsContainer", "propertyName": "items", "values": { "itemType": Terrasoft.ViewItemType.CONTAINER, "visible": { "bindTo": "isSwitchButtonsContainerVisible" }, "items": [] } }, { "operation": "insert", "parentName": "SwitchViewButtonsContainer", "propertyName": "items", "name": "SwitchToAllDataView", "values": { "layout": { "column": 23, "row": 0, "colSpan": 1, "rowSpan": 1 }, "itemType": Terrasoft.ViewItemType.BUTTON, "style": Terrasoft.controls.ButtonEnums.style.TRANSPARENT, //"iconAlign": Terrasoft.controls.ButtonEnums.iconAlign.RIGHT, iconAlign: Terrasoft.controls.ButtonEnums.iconAlign.TOP, pressed: {bindTo: "LegalGridActive"}, "imageConfig": { "source": Terrasoft.ImageSources.SOURCE_CODE_SCHEMA, "params": { "schemaName": "SmrCustomButtonsCSS", "resourceItemName": "GridDataViewIconBlue" } }, classes: { wrapperClass: "blue-button-wrapper", imageClass: "blue-button-pressed" }, "click": {"bindTo": "showAllView"} } }, { "operation": "insert", "parentName": "SwitchViewButtonsContainer", "propertyName": "items", "name": "SwitchToPersonalDataView", "values": { "layout": { "column": 23, "row": 0, "colSpan": 1, "rowSpan": 1 }, "itemType": Terrasoft.ViewItemType.BUTTON, "style": Terrasoft.controls.ButtonEnums.style.TRANSPARENT, //"iconAlign": Terrasoft.controls.ButtonEnums.iconAlign.RIGHT, iconAlign: Terrasoft.controls.ButtonEnums.iconAlign.TOP, pressed: {bindTo: "LegalGridActive"}, "imageConfig": { "source": Terrasoft.ImageSources.SOURCE_CODE_SCHEMA, "params": { "schemaName": "SmrCustomButtonsCSS", "resourceItemName": "GridPersonalDataViewIconBlue" } }, classes: { wrapperClass: "blue-button-wrapper", imageClass: "blue-button-image" }, "click": {"bindTo": "showIndividualView"} } }, { "operation": "insert", "parentName": "SwitchViewButtonsContainer", "propertyName": "items", "name": "SwitchToLegalDataView", "values": { "layout": { "column": 23, "row": 0, "colSpan": 1, "rowSpan": 1 }, "itemType": Terrasoft.ViewItemType.BUTTON, "style": Terrasoft.controls.ButtonEnums.style.TRANSPARENT, //"iconAlign": Terrasoft.controls.ButtonEnums.iconAlign.RIGHT, iconAlign: Terrasoft.controls.ButtonEnums.iconAlign.TOP, pressed: {bindTo: "LegalGridActive"}, "imageConfig": { "source": Terrasoft.ImageSources.SOURCE_CODE_SCHEMA, "params": { "schemaName": "SmrCustomButtonsCSS", "resourceItemName": "GridLegalDataViewIconBlue" } }, classes: { wrapperClass: "blue-button-wrapper", imageClass: "blue-button-image", pressedClass: "blue-button-pressed" }, "click": {"bindTo": "showLegalView"} } } ]/**SCHEMA_DIFF*/ }; } );
Страницы разделов
Созданы 2 страницы разделов. Код для реестра физических лиц:
define("IndividualAccountSectionV2", ["ConfigurationConstants", "css!SmrCustomButtonsCSS"], function(ConfigurationConstants) { return { entitySchemaName: "Account", methods: { /** * Инициализирует фильтры экземпляра запроса * @protected * @overridden * @param {Terrasoft.EntitySchemaQuery} esq Запрос, в котором будут инициированы фильтры */ initQueryFilters: function (esq) { this.callParent(arguments); esq.filters.removeByKey("ClientType"); esq.filters.add("ClientType", this.Terrasoft.createColumnFilterWithParameter( this.Terrasoft.ComparisonType.EQUAL, "SmrClientType.Id", "80FD3F74-0AF4-4F8A-9F0B-F626E4F05147")); }, /** * Возвращает представления раздела по умолчанию. * Реестр, Аналитика не создаётся * @overridden * @return {Object} Представления раздела по умолчанию */ getDefaultDataViews: function() { var gridDataView = { name: this.get("GridDataViewName"), caption: this.getDefaultGridDataViewCaption(), icon: this.getDefaultGridDataViewIcon() }; var analyticsDataView = { }; return { "GridDataView": gridDataView, "AnalyticsDataView": analyticsDataView }; }, /** * Получает пункты меню кнопки "Вид" * @overridden * @virtual * @return {Terrasoft.BaseViewModelCollection} Возвращает пункты меню кнопки "Вид" */ getViewOptions: function() { var viewOptions = this.Ext.create("Terrasoft.BaseViewModelCollection"); viewOptions.addItem(this.getButtonMenuItem({ "Caption": {"bindTo": "Resources.Strings.SortMenuCaption"}, "Items": this.get("SortColumns") })); viewOptions.addItem(this.getButtonMenuItem({ "Caption": {"bindTo": "Resources.Strings.OpenGridSettingsCaption"}, "Click": {"bindTo": "openGridSettings"} })); return viewOptions; } }, diff: /**SCHEMA_DIFF*/[ { "operation": "merge", "name": "SwitchToAllDataView", "values": { classes: { wrapperClass: "blue-button-wrapper", imageClass: "blue-button-image" } } }, { "operation": "merge", "name": "SwitchToPersonalDataView", "values": { classes: { wrapperClass: "blue-button-wrapper", imageClass: "blue-button-pressed" } } }, { "operation": "merge", "name": "SwitchToLegalDataView", "values": { classes: { wrapperClass: "blue-button-wrapper", imageClass: "blue-button-image" } } } ]/**SCHEMA_DIFF*/ }; } );
Код страницы для реестра юридических лиц:
define("LegalAccountSectionV2", ["RightUtilities", "ConfigurationConstants", "css!SmrCustomButtonsCSS"], function (RightUtilities, ConfigurationConstants) { return { entitySchemaName: "Account", attributes: {}, messages: {}, methods: { /** * Инициализирует фильтры экземпляра запроса * @protected * @overridden * @param {Terrasoft.EntitySchemaQuery} esq Запрос, в котором будут инициированы фильтры */ initQueryFilters: function (esq) { this.callParent(arguments); esq.filters.removeByKey("ClientType"); esq.filters.add("ClientType", this.Terrasoft.createColumnFilterWithParameter( this.Terrasoft.ComparisonType.EQUAL, "SmrClientType.Id", "DD4E6E34-21D3-4F09-A417-6FC4116876B5")); }, /** * Возвращает представления раздела по умолчанию. * Реестр, Аналитика не создаётся * @overridden * @return {Object} Представления раздела по умолчанию */ getDefaultDataViews: function() { var gridDataView = { name: this.get("GridDataViewName"), caption: this.getDefaultGridDataViewCaption(), icon: this.getDefaultGridDataViewIcon() }; var analyticsDataView = { }; return { "GridDataView": gridDataView, "AnalyticsDataView": analyticsDataView }; }, /** * Получает пункты меню кнопки "Вид" * @overridden * @virtual * @return {Terrasoft.BaseViewModelCollection} Возвращает пункты меню кнопки "Вид" */ getViewOptions: function() { var viewOptions = this.Ext.create("Terrasoft.BaseViewModelCollection"); viewOptions.addItem(this.getButtonMenuItem({ "Caption": {"bindTo": "Resources.Strings.SortMenuCaption"}, "Items": this.get("SortColumns") })); viewOptions.addItem(this.getButtonMenuItem({ "Caption": {"bindTo": "Resources.Strings.OpenGridSettingsCaption"}, "Click": {"bindTo": "openGridSettings"} })); return viewOptions; } }, diff: /**SCHEMA_DIFF*/[ { "operation": "merge", "name": "SwitchToAllDataView", "values": { classes: { wrapperClass: "blue-button-wrapper", imageClass: "blue-button-image" } } }, { "operation": "merge", "name": "SwitchToPersonalDataView", "values": { classes: { wrapperClass: "blue-button-wrapper", imageClass: "blue-button-image" } } }, { "operation": "merge", "name": "SwitchToLegalDataView", "values": { classes: { wrapperClass: "blue-button-wrapper", imageClass: "blue-button-pressed" } } } ]/**SCHEMA_DIFF*/ }; });
Что нужно отметить в этих страницах:
/** * Инициализирует фильтры экземпляра запроса * @protected * @overridden * @param {Terrasoft.EntitySchemaQuery} esq Запрос, в котором будут инициированы фильтры */ initQueryFilters: function (esq) { this.callParent(arguments); esq.filters.removeByKey("ClientType"); esq.filters.add("ClientType", this.Terrasoft.createColumnFilterWithParameter( this.Terrasoft.ComparisonType.EQUAL, "SmrClientType.Id", "DD4E6E34-21D3-4F09-A417-6FC4116876B5")); }
Мы переопределяем метод для установки фильтрации записей (например, только физические лица).
Также, переопределяем методы getDefaultDataViews и getViewOptions, чтобы скрыть функции, которые не работают в новых реестрах (почему - не было времени разбираться).
Проблемы
В представлениях (дополнительных реестрах) не работают некоторые функции, а именно аналитика и некоторые действия из меню "Вид".
P.S.: Очень ждем возможности использовать такую возможность базовыми средствами, кейсов много - это и деление на сотрудники/контакты и физ/юр лица. В ситуациях, когда набор колонок одинаковый, конечно рекомендуется пользоваться стандартными динамическими группами.
Кстати, а кейс ведения физических и юридических лиц в Контрагентах давно стал практикой?
Это практика при условиях, что:
- Клиенту нужно смотреть суммарную разнообразную аналитику по всем клиентам физики+юрики, создаваемую через стандартные средства (в представлении "Аналитика")
- Клиента бесит, когда ему каждый раз заходя в раздел Контакты, нужно отфильтровывать своих сотрудников и сотрудников подрядчиков, чтобы поработать с клиентами:smile:
Александр, золотой вы человек :twisted:
Как раз ломал голову как бы не убить кучу времени и реализовать представления с переключением, а тут пример живой.
Рад помочь, для этого и нужно комьюнити:smile:. Если есть еще вопросы в стиле "В 3ке это делалось в 5 кликов аналитиком, а как это сделать это в 7ке?" - спрашивайте, наверняка найдем проектное решения в закромах, пусть и не всегда очевидное:lol:
"Александр Свистунов" написал:спрашивайте, наверняка найдем проектное решения в закромах
Я ж воспользуюсь :)
Case: отфильтровать в разделе Счета все счета, к которым прикреплен продукт = "ххх". То есть фильтр по вхождению некой информации в деталь - аналогично в любом разделе. Так как штатно доступны только фильтры по детали с агрегатной функцией, то видимо надо как-то добавлять свой фильтр?
В 3х это делалось через модификацию sq_, в 5х вроде как вообще работало штатно через обратные связи.
Раздел итоги элемент список не предлагать :) там делается посредством списка на основании Продукт в счете - пробовал, работает.
Александр, если я правильно понял ваш Кейс, то это делается через подобный фильтр
"Толмачев Дмитрий Юрьевич" написал:делается через подобный фильтр
Вот только сейчас сумел поменять count на exists - после того как выбрал хоть какую-то колонку при фильтрации по связанной таблице.
Именно это и было нужно, спасибо
Ну вот как надо было догадаться сначала выбрать произвольное поле типа Количество, чтобы попасть обратно в настройки фильтра... Идем и ищем (с)
Чтобы темы не плодить... товарищи, как бы попроще скрыть из меню Edit, Copy и особенно Delete для детали, основанной на вьюшке?
Деталь самодельная, родитель BaseGridDetailV2.
Александр,
Для решения вашей задачи достаточно переопределить функцию addRecordOperationsMenuItems на созданной вами странице реестра
methods: { /** * @overridden */ addRecordOperationsMenuItems: Ext.emptyFn //... }
"Толмачев Дмитрий Юрьевич" написал:Ext.emptyFn
Спасибо, попробую так.
Я ее нашел, только наивно переопределял как
addRecordOperationsMenuItems: function() { }
То есть пытался заполнить "ничем"...
А я где-то такую функцию нашёл
getAddRecordButtonVisible: function() { return false; },
Добрый день!
Александр, спасибо за предоставленной пример, остался один непонятный для меня момент, какие действия нужно выполнить, что бы новая страница раздела (например, IndividualAccountSectionV2) стала доступна по URL "http://localhost/0/Nui/ViewModule.aspx#SectionModuleV2/IndividualAccoun…"?
Сергей,
Если навскидку, то достаточно чтобы в качестве родительской страницы использовалась страница "Базовая схема раздела".
В данном случае, насколько я помню, у страниц LegalAccountSectionV2 и IndividualAccountSectionV2 в качестве родительской использовалась "AccountSectionV2", т.к. по сути это дочерние ветки.
Александр, большое спасибо за то что делитесь отличным материалом!
В процессе его изучения и использования появилось несколько вопросов. Буду очень благодарен за любой совет или помощь.
1. Правильно ли я понимаю, что через свойства Diff:
pressed: {bindTo: "LegalGridActive"},
и
classes: { wrapperClass: "blue-button-wrapper", imageClass: "blue-button-image", pressedClass: "blue-button-pressed" },
Вы указываете, будет ли элемент содержать класс "blue-button-pressed" ?
Если да, то что в этом случае должна возвращать функция "LegalGridActive" - true или false?
У меня на версии 7.7 не получилось сделать так, чтобы к елементу "прицепился" мой класс указанный в pressedClass (как у Вашем примере: pressedClass: "blue-button-pressed"). Вместо него появился "дефолтный" класс - t-btn-pressed.
вот код DIFF:
{ "operation": "insert", "parentName": "SignButtonsContainer", "propertyName": "items", "name": "SignBtnVip", "values": { "itemType": Terrasoft.ViewItemType.BUTTON, "caption": {"bindTo": "sign_Vip"}, "hint": {"bindTo": "Resources.Strings.sign_Vip"}, "imageConfig" : {"bindTo": "Resources.Images.sign_vip_Image"}, //"click": {"bindTo": "onVipButtonClick"}, pressed : {bindTo : "VipButtonPressed"}, classes : { wrapperClass : "sign-btn", imageClass : "sign-img", pressedClass : "sign-img-pressed" }, "visible": true } },
В итоге вместо ожидаемого css-класса "sign-img-pressed" - появляется "t-btn-pressed". Не могу понять что я сделал не так...
2. Можно ли какимто образом отключить для моего елемента генерацию стандрартных css-классов?
(для элемента Terrasoft.ViewItemType.BUTTON сгенерировались - t-btn-wrapper, t-btn-no-text-padding, t-btn-style-default )
3. Глобальный вопрос - не могли бы Вы подсказать, какой подход можно применить для того, чтобы можно было динамически (например по кнопочке) добавлять или удалять указанные кастомные css-классы для элемента?
В целом, очень хорошо что в 7-ке есть возможность подключать свои css-стили, это очень удобно, но вот генерация самих классов для элемента происходит немного не очевидно... :smile: