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

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

Реализовал следующий код:

define("BaseAddressPageV2", ["BusinessRuleModule"], function(BusinessRuleModule) {
    return {
        diff: /**SCHEMA_DIFF*/[
            {
                "operation": "merge",
                "name": "Address",
                "values": {
                    "bindTo": "Address",
                    "controlConfig": {
                        "focus": {"bindTo": "onAddressFocused"},
                        "blur": {"bindTo": "onAddressBlur"}
                    }
                }
            }
        ]/**SCHEMA_DIFF*/,
        methods: {
            onAddressFocused: function(config) {
                                this.showAddressMask(config.scope, true);
            },
            onAddressBlur: function(config) {
                                this.showAddressMask(config.scope, false);
            },
            showAddressMask: function(scope, isShow) {
                if (isShow) {
                    var AddressMaskMessage = this.get("Resources.Strings.AddressMaskMessage");                  
                    scope.showValidationMessage(AddressMaskMessage);              
                } else {
                    scope.showValidationMessage("");
                }
            }
        }
    };
});

При фокусе и потере фокуса события срабатывают, но после выполнения функции showValidationMessage, подсмотренной в baseedit.js, сообщение не появляется.

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

Нравится

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

а в scope у вас что? showValidationMessage - это метод контрола, на странице такого нет.
а лучше попробуйте сами отладиться

Андрей, в приложение файл config.txt с копией дерева config из консоли.

Насколько я понимаю при подписке на focus контрола, в функцию передается объект со стандартной функцией applyHighlight(она тоже срабатывает, т.к. синяя рамка отрисовываеться) которая подписана на focus контрола и scope(сам контрол).

В файле можно увидеть что в прототипе scope(контрола) есть функция showValidationMessage.
Т.е. я вызываю функцию контрола showValidationMessage, но ничего не появляется.

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

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

Функция showValidationMessage должна выполняться в контексте Terrasoft.BaseEdit.

В данном случае обработчик фокуса не содержит аргументов, т.е. scope – пустой.

"Павел Баштовой" написал:Функция showValidationMessage должна выполняться в контексте Terrasoft.BaseEdit.

В данном случае обработчик фокуса не содержит аргументов, т.е. scope – пустой


содержит, в т.ч. и TextEdit, в котором метод showValidationMessage присутствует, но не работает

"Дашкевич К." написал:Т.е. я вызываю функцию контрола showValidationMessage, но ничего не появляется.

Пожалуйста, уточните, что происходит при вызове этой функции, есть ли ошибки?

Также проблема может быть связана с пустым AddressMaskMessage.

"Павел Баштовой" написал:
Дашкевич К. пишет:

Т.е. я вызываю функцию контрола showValidationMessage, но ничего не появляется.

Пожалуйста, уточните, что происходит при вызове этой функции, есть ли ошибки?

Также проблема может быть связана с пустым AddressMaskMessage.

Ошибок нет, функция выполняется, но текст не выводиться.
Можно поподробнее про AddressMaskMessage.

Исходя из реализованного Вами кода, AddressMaskMessage это локализованная строка, отвечающая за выводимое в строке валидации значение. И в случае, если его значение пустое, то выводить будет нечего.

Нет, даже если выводить текст напрямую, он не выводиться.

Зато с помощью функции showValidationMessage, получается менять текст, уже выведенный с помощью стандартного механизма валидации.
Проблема в том что функция showValidationMessage выводит текст в элемент с классом class="base-edit-validation", но не отображает его style visibility=hidden. Буду искать функцию которая отвечает за его отображение.
Может подскажите как из моего контекста изменить style элемента компонента TextEdit.

Можно попробовать переопределить класс, добавив .AddClass.

Также можно вызвать SetValidationInfo c параметром isValid="true", в baseedit.js

Павел, спасибо за наводку в SetValidationInfo нашел функцию отображения контейнера с текстом валидации.

В итоге выглядит так:

define("BaseAddressPageV2", ["BusinessRuleModule"], function(BusinessRuleModule) {
    return {
        diff: /**SCHEMA_DIFF*/[
            {
                "operation": "merge",
                "name": "Address",
                "values": {
                    "bindTo": "Address",
                    "controlConfig": {
                        "focus": {"bindTo": "onAddressFocused"},
                        "blur": {"bindTo": "onAddressBlur"}
                    }
                }
            }
        ]/**SCHEMA_DIFF*/,
        methods: {
            onAddressFocused: function(config) {
                this.showAddressMask(config.scope, true);
            },
            onAddressBlur: function(config) {
                this.showAddressMask(config.scope, false);
            },
            showAddressMask: function(scope, isShow) {
                var AddressMaskMessage = this.get("Resources.Strings.AddressMaskMessage");
                var validationEl = scope.getValidationEl();
                validationEl.setVisible(isShow);
                scope.showValidationMessage(isShow ? AddressMaskMessage : "");
            }
        }
    };
});
Показать все комментарии

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

Нравится

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

Здравствуйте, Олег!

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

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

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

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

Текст хранимой процедуры:
EXEC [dbo].[tsp_RegisterPage]
@ModuleEntityName = N'SxProdAndServItem',
@PageName = N'SxProdAndServItemPage',
@TypeColumnUId = NULL,
@TypeValue = NULL,
@AddMenuCaptionRus = NULL,
@AddMenuCaptionEng = NULL,
@CardHeaderCaptionRus = NULL,
@CardHeaderCaptionEng = NULL

Я имел ввиду кнопку добавления записи справочника(здесь страницы редактирования нет):

Здесь справочник, для которого я регистрировал страницу:

Здравствуйте, во первых при выполнении хранимой процедуры вам необходимо было указывать имена:

@AddMenuCaptionRus = 'добавить товар\услугу',
@AddMenuCaptionEng = 'добавить товар\услугу',
@CardHeaderCaptionRus = 'товар\услуга',
@CardHeaderCaptionEng = 'товар\услуга'

Без них страница реестра не сможет дать имя кнопке добавления на странице списка.
Во вторых, необходимо добавить и страницу реестра и указать ее в свойствах справочника, согласно инструкции:
kartochkaireestrdlyaspravochnikovv7.5.doc

Спасибо, Вы очень помогли!

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

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

В разделе контрагенты по действию открываю справочник выбора контакта:

var lookup = {
        config: {
                entitySchemaName: "Contact",
                columnName: "Owner",
                multiSelect: false              
        },
        callback: this.lookoupOwnerCallback
};
lookup.config.actionsButtonVisible = false;
LookupUtilities.Open(this.sandbox, lookup.config, lookup.callback, this, null, false, false);

Работает нормально, без ошибок.
Далее добавляю фильтрацию (в config добавляю свойство filters):
var lookup = {
        config: {
                entitySchemaName: "Contact",
                columnName: "Owner",
                multiSelect: false,
                filters: [
                        function () {
                                debugger
                                var filterGroup = Ext.create("Terrasoft.FilterGroup");
                                filterGroup.add("IsOurType",
                                        Terrasoft.createColumnFilterWithParameter(
                                                Terrasoft.ComparisonType.EQUAL,
                                                "Type",
                                                "60733efc-f36b-1410-a883-16d83cab0980"));
                                return filterGroup;
                        }
                ]              
        },
        callback: this.lookoupOwnerCallback
};
lookup.config.actionsButtonVisible = false;
LookupUtilities.Open(this.sandbox, lookup.config, lookup.callback, this, null, false, false);

Возникает ошибка. Код фильтра взял из атрибута Owner страницы редактирования(т.е. там он работает и данные фильтруются), но при его использовании в описанном примере возникает ошибка, причем debugger не вызывается. Подскажите правильный синтаксис добавления фильтра при открытии справочника с помощью LookupUtilities.

Ошибка из консоли: "Uncaught TypeError: a.on is not a function"

Нравится

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

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

Пример решения этой задачи есть на SDK.

"Демьяник Алексей" написал:

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

Пример решения этой задачи есть на SDK.

Алексей, по статье в SDK я создавал фильтр для колонки Owner страницы редактирования контрагента и там он работает, но если этот же фильтр применять при открытии справочника контактов с помощью LookupUtilities вне страницы редактирования (в моем случае в разделе контрагента) фильтр не работает выпадает ошибка, подробно описал выше.

Изменил объявление справочника:

var lookup = {
	config: {
		entitySchemaName: "Contact",
		columnName: "UsrOwnerOPKA",
		multiSelect: false,
		lookupListConfig: {
			filters: [
				function () {
					debugger
					var filterGroup = Ext.create("Terrasoft.FilterGroup");
					filterGroup.add("IsOurType", Terrasoft.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, "Type", "60733efc-f36b-1410-a883-16d83cab0980")); 
				}
			]
		}
	},
	callback: this.changeOwner
};

После этого ошибки нет, но и фильтры не работают, функция не вызываеться.

в filters ставьте не массив, а саму функцию

"Андросов Дмитрий" написал:

в filters ставьте не массив, а саму функцию

Не помогло.

В filters передал Terrasoft.FilterGroup и заработало:

var filterGroup = Ext.create("Terrasoft.FilterGroup");
filterGroup.add("IsOurType",
   Terrasoft.createColumnFilterWithParameter(
   Terrasoft.ComparisonType.EQUAL,
   "Type",
   "60733efc-f36b-1410-a883-16d83cab0980"));
 
var lookup = {
        config: {
                entitySchemaName: "Contact",
                columnName: "Owner",
                multiSelect: false,
                filters: filterGroup         
        },
        callback: this.lookoupOwnerCallback
};
lookup.config.actionsButtonVisible = false;
LookupUtilities.Open(this.sandbox, lookup.config, lookup.callback, this, null, false, false);

так у вас функция ничего не возвращает)). Ваш вариант не будет работать, если в фильтре будет использовать в качестве значения параметра какая-то переменная - он будет создан один раз и использоваться всегда в первоначальном виде.

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

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

Доброго времени суток!
Каким образом можно сменить подпись уведомления о новой визе в ком. панели? Чтоб выводилось в формате, к примеру: Заявка [номер], [цель], [получатель].

Нравится

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

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

На примере раздела "Заказы" логика реализована в OrderVisaNotificationProvider. Вам необходимо заместить логику этой схемы.

В заказах в ком. панель выводится номер заказа. Мне же нужно выводить туда сформированную строку на основе еще 3х полей, которые добавить в запрос в VisaNotificationProvider не получится.

Уже разобрался. Формирую строку в БП, записываю в цель визы, и вывожу в ком. панель вместо имени объекта.

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

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

При переносе данных таблицы SysAdminUnit(Объект администрирования) из одно приложение в другое (приложения идентичны) возникает ошибка:
"The transaction ended in the trigger. The batch has been aborted. @Terrasoft.Core, SysAdminUnitSchema.Exception.InvalidRootType"

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

Нравится

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

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

Попробуйте отключить триггер TRSysAdminUnitRoot (пакет Base) и затем попробовать переместить данные.

Только перед этим протестируйте или сделаейте копию БД/приложения.

"Мотков Илья" написал:

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

Попробуйте отключить триггер TRSysAdminUnitRoot (пакет Base) и затем попробовать переместить данные.

Только перед этим протестируйте или сделаейте копию БД/приложения.

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

Спасибо за решение.



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



Отключать триггер, наверное можно "Before saving package", а вот когда включать?



И второй вопрос - почему импорт SysAdminUnit выполняется так долго (50 минут, хотя в данных всего около 20 ролей и 10 пользователей)? Может быть, можно ещё что-то отключить и выполнить единоразово после всего импорта?

 

2020-10-29 17:19:06,697 [5] INFO NT AUTHORITY\SYSTEM InstallZipPackage LogInfo - Lookup values "States_Provinces" from package "Exactly.Data" installed
2020-10-29 18:05:40,163 [5] INFO NT AUTHORITY\SYSTEM InstallZipPackage LogInfo - Lookup values "SysAdminUnit" from package "Exactly.Data" installed

 

Ну, наверно, если отключать на «Before», то включать на «After». Такой вариант тоже есть:

А что может так сильно тормозить этот импорт?

 

Всё, что угодно, например, ещё какие-то триггеры, которые не отключили (и, возможно, отключать и не стоит). Попробуйте посмотреть в SQL-профайлере на отрабатывающие запросы.

 

Тщательно протестировали. Триггер не отключается перед установкой почему-то на Before...

Ясно. Выходит, сначала идёт AfterPackage и уже затем AfterSchemaData.

Но при этом иногда стала появляться такая ошибка из того же триггера:

 @Terrasoft.Core,SysAdminUnitSchema.Exception.RootAlreadyExists



То есть, кажется, он успевает включиться до того, как данные начинают импортироваться (пробовали и After package saved, и After Schema data saved.

 

Если убрать включение триггера, то всё проходит без ошибок. Но кто тогда будет включать триггер?

Судя по RootAlreadyExists, ругается на какую-то конкретную запись, которую считает корневой. Всё ли правильно в залитом? А если в скрипте перед включением триггера задержку вставить?

Да, сначала даже подумал, что в пакете какие-то записи с пустым ParentRoleId. Но посмотрел - нет таких.

Возможно, что при импорте данных что-то дёргает уже существующие All employees, и потому срабатывает триггер.



Сейчас видим, что, в принципе, триггер относительно бесполезный (если администратор не начнёт ничего рушить), потому можно его вообще отключить.

Насчёт задержки была мысль, но тут второй непонятный вопрос - иногда эти данные SysAdminUnit импортируются 5 минут, иногда час, иногда два... И это при том, что их штук 20 всего.



Но после импорта SysAdminUnit и SysUserInRole хорошо бы запустить процедуру tsp_ActualizeAdminUnitInRole. Но пока тоже не совсем понятно, куда её воткнуть...

	IF (TG_OP = 'INSERT' OR TG_OP = 'UPDATE') AND TG_WHEN = 'AFTER' THEN
		IF (NEW."ParentRoleId" IS NULL AND NEW."SysAdminUnitTypeValue" < 4) THEN 
 
			IF (NEW."SysAdminUnitTypeValue" > 0) THEN
				RAISE '@Terrasoft.Core,SysAdminUnitSchema.Exception.InvalidRootType';
				ROLLBACK;
			END IF;
 
			SELECT COUNT("Id") INTO RecordsCount FROM "SysAdminUnit"
				WHERE "ParentRoleId" IS NULL
					AND "SysAdminUnitTypeValue" < 4
					AND "SysAdminUnit"."Id" <> NEW."Id";
 
			IF (RecordsCount > 1) THEN
				RAISE '@Terrasoft.Core,SysAdminUnitSchema.Exception.RootAlreadyExists';
				ROLLBACK;
			END IF;
 
		END IF;
	END IF;

 

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

 

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

 

Вероятно, ту функцию актуализации, которую хотите запустить, нужно тоже на одном из «After...».

 

Идея по невозможности заливки в SysAdminUnit уже заведена, как обходное решение рекомендуется в пакете скриптами включать-выключать триггер.

 

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

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

Доброго времени суток.
Подскажите как правильно подменить профиль в разделе? Замещал ф-ии getActiveViewSettingsProfileKey
и getProfileKey. Нужный профиль подгружает, но записи не отображаются. В настройках колонок отображаются нужные, и только после сохранения появляется список записей.

Нравится

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

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

Опишите, пожалуйста, задачу, которую Вы пытаетесь решить?

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

Олег, добрый день!

Попробуйте при инициализации Вашего раздела получить значение нужного профиля по коду из базы и установить полученное значение в атрибут "Profile" модели раздела. Далее при инициализации колонок реестра (метод initQueryColumns схемы GridUtilitiesV2) вызывается метод getProfileColumns, который должен получить из данного атрибута корректный набор колонок.

Обратите внимание, что перед установкой значения в атрибут "Profile" его необходимо декодировать в объект с помощью Terrasoft.decode.

"Лабьяк Олег Игоревич" написал:

Олег, добрый день!

Попробуйте при инициализации Вашего раздела получить значение нужного профиля по коду из базы и установить полученное значение в атрибут "Profile" модели раздела...


Я использую getActiveViewSettingsProfileKey и getProfileKey, которые возвращают нужный мне ключ, и в Profile попадает нужный мне профиль. Метод getProfileColumns возвращает нужные колонки.
Проблема в columnBindings. Это "Объект, описывающий связи колонок реестра со свойствами или методами модели". И там хранятся связи изначальных колонок. Метод getRow() ("Метод получения данных модели через механизм привязки") пытается получить колонки из columnBindings по названиям колонок из профиля, который я подгружаю. Естественно они не совпадают.
Проблему частично решает метод reloadGridColumnsConfig, если вызвать его в getActiveViewGridSettingsProfile. И тогда в columnBindings попадают нужные связи. Но если зайти в настройки колонок и, не сохраняя их, нажать отмену - раздел не грузится, а в columnBindings снова попадают старые связи.

Олег, свойство columnBindings формируется по конфигурации колонок вью-модели схемы раздела, которая генерируется только один раз в момент инициализации. Поэтому для получения актуальных связей придётся перегенерировать вью-модель. Другого решения я, к сожалению, не нашёл:

init: function() {
	if (/* условие, по которому необходимо подменять профиль */) {
		this.viewModel = null;
	}
	this.callParent(arguments);
}

Таким способом решить проблему у меня не вышло. Но благодаря Вам я пошел в нужном направлении (по цепочке генерации вью-модели). В итоге вышел на getProfileKey() в SectionModuleV2, что проблему решило. Спасибо огромное!

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

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

var config = {
    entitySchemaName: "SxSupply",
    multiSelect: false,
    columns: ["SxName", "SxShipping"]
};
var groupType = this.Terrasoft.createColumnIsNullFilter(
    "SxShipping");
config.filters = groupType;
this.openLookup(config, this.addSupplyCallback, this);

Вопрос: что необходимо добавить в config чтобы скрыть эту кнопку?

Нравится

6 комментариев
var config = {
						entitySchemaName: "SysAdminUnit",
						multiSelect: true,
						columns: ["Contact", "Name"],
						hideActions: true, // вот оно
						filters: filters
					}

но это коснется не только добавления, но и Изменения, и Удаления

Если требуется закрыть только Добавление - проще будет воспользоваться правами

"Андросов Дмитрий" написал:hideActions: true

А можно скрыть Добавление только определенных типов записей? (здесь в Добавить выбирается тип)

тут потребуются приемы из категории ниндзюцу по замещению толи LookupPage, толи LookupPageViewGenerator, толи LookupPageViewModelGenerator

Здравствуйте, Владимир!

Пример можно посмотреть в разделе "Активности" в версии 7.6.0+. Там несколько страниц редактирования, но в разделе доступны не все.

"Демьяник Алексей Олегович" написал:Пример можно посмотреть в разделе "Активности" в версии 7.6.0+. Там несколько страниц редактирования, но в разделе доступны не все.

С разделом разобрались. Теперь вопрос насчёт окна lookup.
Если я выбираю из списка документов с типом "акт", то должен создавать только акты

Владимир, добрый день!

Попробуйте перед вызовом this.openLookup(config, this.addSupplyCallback, this); в свойство excludedTypes объекта config передавать массив уникальных идентификаторов карточек редактирования, которые не должны отображаться в меню добавления:

config.excludedTypes = ["39b28624-98e6-df11-971b-001d60e938c6","e72d71bc-fe0e-4173-9902-0f0f220beacb"];
this.openLookup(config, this.addSupplyCallback, this);
Показать все комментарии

Доброго времени суток!
Подскажите где хранится имя первичной колонки для отображения?
Получить ее путем Terrasoft.[moduleName].primaryDisplayColumn.name невозможно, т.к. нахожусь я в другом разделе.

Нравится

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

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

Используйте Terrasoft.[moduleName].primaryDisplayColumn.columnPath. Для этого объект [moduleName] должен быть загружен на клиент. Для загрузки объекта на клиент require(["Activity"], function(schema))

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

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

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

Создал БП UsrTestChangeRight, содержащий только элемент "Изменить права доступа". Запуская процесс вручную, через раздел "Библиотека процессов", он отрабатывает и в таблицу SysAccountRight добавляются записи.
Но если запускать процесс используя AppScheduler, он завершается без ошибок (появляется запись в журнале процессов) но записи в таблице SysAccountRight не добавляются. Запуск происходит при сохранении контрагента, пробовал использовать элемент "Изменить права доступа" напрямую в событийном подпроцессе замещающей схемы, но там нет возможности открыть окно настроек этого элемента.
Код запуска через AppScheduler:

Dictionarystring, object> parameters = new Dictionarystring, object>();
AppScheduler.ScheduleImmediateProcessJob("TestChangeRight", "Account", "UsrTestChangeRight", "Default", "Supervisor", parameters);

Подскажите пожалуйста, в чем может быть проблема?
И какие еще есть способы запустить БП из серверного кода, с передачей параметров?

Насколько я понимаю когда БП запускается через AppScheduler, не получиться получить UserConnetion, какие есть альтернативы UserConnetion, для того что бы подобный код работал:

StoredProcedure SomeProcedure= new StoredProcedure(UserConnection, "SomeProcedure") as StoredProcedure;
SomeProcedure.PackageName = UserConnection.DBEngine.SystemPackageName;
SomeProcedure.Execute();
return true;

Нравится

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

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

Как-то все смешалось.
UserConnection берется пользователя, указанного в параметре userName. Вы точно передаете корректные параметры в процесс?

По вызову хранимой процедуры из элемента "Задание-сценарий". Корректный вызов следующий:
StoredProcedure SomeProcedure = new StoredProcedure(UserConnection, "SomeProcedure") as StoredProcedure;
SomeProcedure.Execute();

Также Вы можете задавать права доступа непосредственно из процедурой SomeProcedure, вызвав ее из процесса, передавая в нее нужные параметры, например, Id записи. Код элемента "Задание-сценарий":

var Id=new.Guid("e24018bf-4ef6-49ef-a331-4fdb6b742e4c");
StoredProcedure SomeProcedure = new StoredProcedure(UserConnection, "SomeProcedure")
.WithParameter("Id", Id) as StoredProcedure;
SomeProcedure.Execute();
return true;

Алексей, со второй частью понятно. А что насчет первой "не отрабатывает элемент процесса "Изменить права доступа", при запуске процесса используя AppScheduler" и какие еще есть способы запустить БП из серверного кода, с передачей параметров?

Как вариант вызвать процесс через вебсервис. Более подробно описано здесь.

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

Добрый день!
Подскажите, как в планировании зафиксировать шапку таблицы, чтоб она не уезжала при прокрутке.
Также интересует, как добавить столбцы, которые также будут фиксированы?

Нравится

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

Добрый день, Александр!

Детализируйте, пожалуйста, свой запрос, желательно с использованием скриншотов.

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