Здравствуйте! Мне нужно, чтобы в Расписании выделялись цветом те задачи, которые имеют в заголовке слово "Свободно".

Если реализовать через такой код

define("ActivitySectionV2", [],
    function () {
        return {
            // Название схемы раздела.
            entitySchemaName: "Activity",
                details: /**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/,
                diff: /**SCHEMA_DIFF*/[]/**SCHEMA_DIFF*/,
            methods: {
                // Переопределение базового метода, который модифицирует строку данных перед загрузкой в реестр.
                prepareResponseCollectionItem: function (item) {
                    this.callParent(arguments);
                    item.customStyle = null;
                    var running = item.get("Title");
                    //Если условие подходит, меняем цвет записи на темно-серый, а фон на светло-зеленый.
                    if (running.indexOf('Свободно')+1) {
                        item.customStyle = {
                            'color': "darkgrey",
                            'background': "#D8FBC2"
                        }
                    }
                }
            }
        };
    });


то в разделе активность поменяла свой цвет а вот в расписании не поменяла.

 

Как сделать так чтобы в расписании активность поменяла свой цвет если в заголовке есть слово "Свободно"?
Версия BpmOnline sales commerce 7.8.3.1978

Нравится

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

Извините за оффтопик.
Не делали бы вы для раскраски реестров парсинг текста заголовка, ляжет и погибнет у вас система как объемы данных нарастут... это же неиндексируемое поле, да еще поиск по тексту...
Тут бы признак сделать типа булевского поля, и по нему обрабатывать. А булевское поле заполнять например тем самым парсингом названия при сохранении активности.

по теме
посмотрите в ActivitySectionV2 поиском по тексту "FontColor" -найдете в diff описание конфига для отображения элементов расписания. Возможно поможет замещение и замена bindto для fontcolor на новый атрибут... но это предположение :)

Раскраска активностей в расписании

Описание таска

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

Анализ

Таблица расписания определена внутри пакета NUI в модуле ActivitySectionV2, как элемент в объекте diff с именем Schedule. В данный элемент вложен объект itemBindingConfig, который отвечает за привязку свойств активности к каждому из элементов расписания. В данном случае нас интересуют два значения, а именно: background, устанавливающий цвет фона элемента расписания и fontColor, определяющий цвет текста на нём.
Привязанные методы (то, что идёт после bindTo, например, getScheduleItemTitle) определяются внутри пакета UIv2 в модуле ActivitySectionGridRowViewModel. Привязанные поля есть ничто иное, как загруженные из базы данных поля схемы Activity, список которых определяется внутри модуля ActivitySectionV2 в методе getGridDataColumns. Обратите внимание, что по умолчанию background и fontColor привязаны к полям, которых нет в схеме Activity (Background и FontColor соотвественно).
Внутренняя логика поведения элемента расписания определена в файле schedule-item.js (класс Terrasoft.controls.ScheduleItem). После анализа этого кода становится ясно, что в случае, если background определён, то CSS стиль элемента меняется, в противном случае – нет. То же касается и fontColor:

if (background && isSelected) {
   out.push('<div style="background: ' + background + ';" class="' + schedulerItemStatusClasses[status] +
      " " + schedulerItemStatusClasses[0] + '">');
} else if (background && !isSelected) {
   out.push('<div style="background: ' + background + ';" class="' + schedulerItemStatusClasses[status] +
      '">');
} else if (!background && isSelected) {
   out.push('<div class="' + schedulerItemStatusClasses[status] + " " + schedulerItemStatusClasses[0] +
      '">');
} else {
   out.push('<div class="' + schedulerItemStatusClasses[status] + '">');
}

Также можно заметить ещё одну особенность. Свойства background и fontColor не применяется для элементов, выделенных пользователем нажатием мыши:

…
itemBodyEl.setStyle({
   "backgroundColor": (isSelected) ? "" : this.background,
   "color": (isSelected) ? "" : this.fontColor
});

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

Реализация

Шаг 1. Добавление справочника.
Первым шагом будет добавление справочника ActivitySchedulerColor. Дадим ему заголовок «Цвет активности в расписании» и добавим следующие поля:

  • ActivityPriority с типом Справочник, который ссылается на «Приоритет активности».
  • BackgroundColor с типом Строка
  • FontColor с типом Строка

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

Шаг 2. Добавление хелпера.
Далее необходимо добавить клиентский модуль, который будет загружать значения цветов из добавленного нами справочника и возвращать конкретные цвета по Id приоритета:

define("ActivitySectionGridRowHelper", ["terrasoft"], function(Terrasoft) {
    var activitySchedulerColor = {};
 
    //Возвращает соответствующие priorityId цвета из справочника ActivitySchedulerColor
    //Перед вызовом этого метода, необходимо загрузить данные из справочника методом loadActivitySchedulerColors
    function getActivitySchedulerColor(priorityId) {
        return activitySchedulerColor[priorityId];
    }
 
    //Загружает данные из справочника ActivitySchedulerColor (Цвета активностей)
    function loadActivitySchedulerColors() {
        var esq = Ext.create("Terrasoft.EntitySchemaQuery", {rootSchemaName: "ActivitySchedulerColor"});
        esq.addColumn("ActivityPriority", "ActivityPriority");
        esq.addColumn("BackgroundColor", "BackgroundColor");
        esq.addColumn("FontColor", "FontColor");
        esq.getEntityCollection(function(response) {
            Terrasoft.each(response.collection.collection.items, function(item) {
                activitySchedulerColor[item.values.ActivityPriority.value] = {
                    "backgroundColor":item.values.BackgroundColor,
                    "fontColor":item.values.FontColor
                };
            }, this);
        });
    }
 
    return {
        GetActivitySchedulerColor: getActivitySchedulerColor,
        LoadActivitySchedulerColors: loadActivitySchedulerColors
    };
});

Шаг 3. Замещение модуля ActivitySectionV2.
Следующим шагом будет переопределение схемы ActivitySectionV2. Здесь нужно изменить привязку значений для таблицы расписания, добавить поле Priority в выборку данных для таблицы расписания и вызвать из хелпера метод loadActivitySchedulerColors:

define("ActivitySectionV2", ["ActivitySectionGridRowHelper"],
    function(ActivitySectionGridRowHelper) {
        return {
            entitySchemaName: "Activity",
            details: /**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/,
            diff: /**SCHEMA_DIFF*/[
                {
                    "operation": "merge",
                    "name": "Schedule",
                    "values": {
                        "itemBindingConfig": {
                            "itemId": {"bindTo": "Id"},
                            "title": {"bindTo": "getScheduleItemTitle"},
                            "changeTitle": {"bindTo": "onTitleChanged"},
                            "startDate": {"bindTo": "StartDate"},
                            "changeStartDate": {"bindTo": "onStartDateChanged"},
                            "dueDate": {"bindTo": "DueDate"},
                            "changeDueDate": {"bindTo": "onDueDateChanged"},
                            "status": {"bindTo": "getScheduleItemStatus"},
                            "changeStatus": {"bindTo": "onStatusChanged"},
                            "background": {"bindTo": "getBackground"},
                            "fontColor": {"bindTo": "getFontColor"},
                            "isBold": {"bindTo": "IsBold"},
                            "isItalic": {"bindTo": "IsItalic"},
                            "isUnderline": {"bindTo": "IsUnderline"},
                            "markerValue": {"bindTo": "getScheduleItemHint"}
                        }
                    }
                }
            ]/**SCHEMA_DIFF*/,
            methods: {
                getGridDataColumns: function() {
                    var baseGridDataColumns = this.callParent(arguments);
                    var gridDataColumns = {
                        "Account": {path: "Account"},
                        "StartDate": {path: "StartDate"},
                        "DueDate": {path: "DueDate"},
                        "ShowInScheduler": {path: "ShowInScheduler"},
                        "Status": {path: "Status"},
                        "Status.Finish": {path: "Status.Finish"},
                        "ProcessElementId": {
                            path: "ProcessElementId",
                            dataValueType: 0
                        },
                        "Priority": {path: "Priority"}
                    };
                    return Ext.apply(baseGridDataColumns, gridDataColumns);
                },
                init: function () {
                    this.callParent(arguments);
                    ActivitySectionGridRowHelper.LoadActivitySchedulerColors();
                }
            }
        };
    });


Шаг 4. Замещение модуля ActivitySectionGridRowViewModel.

В данный модуль нам необходимо добавить два метода getBackground и getFontColor, к которым мы привязали значения полей background и fontColor. Однако, так как все методы объявлены внутри Ext.define, придётся копировать весь код модуля:

define("ActivitySectionGridRowViewModel", ["ext-base", "terrasoft", "ActivitySectionGridRowHelper","BaseSectionGridRowViewModel"],
    function(Ext, Terrasoft, ActivitySectionGridRowHelper) {
 
        /**
         * @class Terrasoft.configuration.ActivitySectionGridRowViewModel
         */
        Ext.define("Terrasoft.configuration.ActivitySectionGridRowViewModel", {
            extend: "Terrasoft.BaseSectionGridRowViewModel",
            alternateClassName: "Terrasoft.ActivitySectionGridRowViewModel",
 
            /**
             * Возвращает значение всплывающей подсказки для элемента в расписании.
             * @return {String} Значение всплывающей подсказки для элемента в расписании.
             */
            getScheduleItemHint: function() {
                var timeFormat = Terrasoft.Resources.CultureSettings.timeFormat;
                var startDate = Ext.Date.format(this.get("StartDate"), timeFormat);
                var dueDate = Ext.Date.format(this.get("DueDate"), timeFormat);
                var title = this.get("Title");
                var account = this.get("Account");
                var accountDisplayValue = (account) ? account.displayValue + ": " : "";
                return Ext.String.format("{0}-{1} {2}{3}", startDate, dueDate, accountDisplayValue, title);
            },
 
            /**
             * Возвращает статус элемента расписания.
             * @return {Terrasoft.ScheduleItemStatus} Статус элемента расписания.
             */
            getScheduleItemStatus: function() {
                var isFinished = this.get("Status.Finish");
                var dueDate = this.get("DueDate");
                if (dueDate <= new Date() && !isFinished) {
                    return Terrasoft.ScheduleItemStatus.OVERDUE;
                } else if (isFinished) {
                    return Terrasoft.ScheduleItemStatus.DONE;
                }
                return Terrasoft.ScheduleItemStatus.NEW;
            },
 
            /**
             * Возвращает значение заголовка элемента в расписании.
             * @return {String} Значение заголовка элемента в расписании.
             */
            getScheduleItemTitle: function() {
                var title = this.get("Title");
                var account = this.get("Account");
                var accountDisplayValue = (account) ? account.displayValue + ": " : "";
                return Ext.String.format("{0}{1}", accountDisplayValue, title);
            },
 
            /**
             * inheritdoc Terrasoft.BaseGridRowViewModel#getEntitySchemaQuery
             */
            getEntitySchemaQuery: function() {
                var esq = this.callParent(arguments);
                if (!esq.columns.contains("Status.Finish")) {
                    esq.addColumn("Status.Finish");
                }
                return esq;
            },
 
            /**
             * inheritdoc Terrasoft.BaseViewModel#setColumnValues
             */
            setColumnValues: function(entity) {
                this.set("Status.Finish", entity.get("Status.Finish"));
                this.callParent(arguments);
            },
 
            /**
             * Обрабатывает событие изменения поля "Начало".
             * @protected
             * @param {Date} date Новое значение даты.
             */
            onStartDateChanged: function(date) {
                this.set("StartDate", date);
                this,
                this.saveEntity(Terrasoft.emptyFn, this);
            },
 
            /**
             * Обрабатывает событие изменения поля "Завершение".
             * @protected
             * @param {Date} date Новое значение даты.
             */
            onDueDateChanged: function(date) {
                this.set("DueDate", date);
                this.saveEntity(Terrasoft.emptyFn, this);
            },
 
            /**
             * Обрабатывает событие изменения поля "Заголовок".
             * @protected
             */
            onTitleChanged: Terrasoft.emptyFn,
 
            /**
             * Обрабатывает событие изменения поля "Состояние".
             * @protected
             */
            onStatusChanged: Terrasoft.emptyFn,
            getBackground: function() {
                var priority = this.get("Priority");
                var activitySchedulerColor = ActivitySectionGridRowHelper.GetActivitySchedulerColor(priority.value);
                var backgroundColor = activitySchedulerColor.backgroundColor;
                return backgroundColor;
            },
            getFontColor: function() {
                var priority = this.get("Priority");
                var activitySchedulerColor = ActivitySectionGridRowHelper.GetActivitySchedulerColor(priority.value);
                var fontColor = activitySchedulerColor.fontColor;
                return fontColor;
            }
        });
 
        return Terrasoft.ActivitySectionGridRowViewModel;
    });

Результат

В результате должно получится что-то вроде:

Для активности «Развернуть стенд» указан приоритет для которого не указан цвет в справочнике ActivitySchedulerColor. Соответственно, для него работает стандартная логика и он окрашивается в соответствии со своим статусом и временем.
Для приоритетов активностей «Позвонить клиенту» и «Написать Hello, World!» в справочнике ActivitySchedulerColor указан цвет, и они окрашиваются по добавленной логике.

Добрый день.

При реализации данного таска на шаге:

Шаг 4. Замещение модуля ActivitySectionGridRowViewModel.

появилась ошибка: "Замещение модулей запрещено".

Хотя в настройке модуля параметр "Запретить замещение" не установлен.

Можете подсказать, в чём может быть причина?

С 2016 года архитектура системы изменилась. Модули замещать запрещено, начиная с версии 7.13.1.

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

Подскажите, пожалуйста, как добавить свойство ENUM для справочника который находится в детали с редактируемым реестром. (рис.1)

Нравится

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

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

Добрый день!

В детали с редактируемым реестром свойства редактируемого реестра настраиваются в секции "values": {}
Здесь описываются свойства listedConfig": {} и/или "tiledConfig": {}, где в массиве "items": [] описываются отображаемые в гриде колонки, например вот так:

"items": [{
"name": "AttributeListedGridColumn",
"bindTo": "Attribute",
"type": Terrasoft.GridCellType.LOOKUP,
"position": {
"column": 1,
"colSpan": 16
}
}]

Для того, чтобы справочное поле объекта (не виртуальное) отображалось выпадающим списком, нужно заместить соответствующий объект, в замещенном объекте настроить отображение нужного справочного поля в виде списка. Для этого открыть замещенный объект для редактирования и для выбранной колонки типа "Справочник" установить галочку напротив "Список".
Исходя из представленного скриншота, Вы хотите сделать именно это.
Свойство ENUM имеет смысл добавлять, если в дальнейшем предполагается работать со значениями из справочника, как с константами.

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

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

Здравствуйте. Случайно удалил деталь Адрес доставки из раздела Заказы. Теперь не могу вернуть эту деталь обратно. Помогите пожалуйста восстановить данную деталь
Благодарю

Нравится

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

Дмитрий, если Вы удалили деталь в мастере, то для восстановления достаточно открыть замещенную схему «OrderPageV2» и в секции diff убрать операцию «remove» соответствующей детали (см. скриншот).

"Вильшанский Дмитрий" написал:

Дмитрий, если Вы удалили деталь в мастере, то для восстановления достаточно открыть замещенную схему «OrderPageV2» и в секции diff убрать операцию «remove» соответствующей детали (см. скриншот).

Здравствуйте, Дмитрий.
Большое спасибо за помощь. Деталь вернулась обратно.
Благодарю

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

Происходит после создания нового объекта и наследования от базового справочника. Как исправить?

Нравится

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

Добрый день!
При 1-м входе пользователя в BPM открывается окно с показом видеоролика. Можно ли как-нибудь сделать самому похожее окно со своим содержимым и показать его пользователю?

Нравится

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

Если вас интересует полноэкранное окно с видео, как при первом старте системы, то почитайте схему «WelcomeScreen» в конфигурации. И её вызов в схеме ConfigurationViewModule, метод loadWelcomeScreen.
Если вас интересует просто модальное окно, с любым содержимым, посмотрите в эту тему: http://www.community.terrasoft.ru/forum/topic/17970#comment-63544

"Максим Шевченко" написал:

Если вас интересует полноэкранное окно с видео, как при первом старте системы, то почитайте схему «WelcomeScreen» в конфигурации. И её вызов в схеме ConfigurationViewModule, метод loadWelcomeScreen.

Если вас интересует просто модальное окно, с любым содержимым, посмотрите в эту тему: http://www.community.terrasoft.ru/forum/topic/17970#comment-63544


Спасибо!

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

Обнаружена ошибки в версиях 7.8.х
При попытке привязать данные к пакету - данные по колонке Name подвязываются с пустым значением. Остальные поля подвязываются без проблем. Подобные данные были обнаружены и в базовых пакетах. Например данные пакета Base.

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

данные в базе

данные в пакете

Но в некоторых случаях колонка подвязывается. С чем связано пока не ясно.
Например на Версии 7.8.0.1434 всё подвязывается, кажется, без проблем...

Нравится

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

Здравствуйте, Вячеслав!

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

Подобное поведение наблюдается на множестве сайтов различных версий и билдов. Нет ли какой-то обобщенной рекомендации как исправить? Сайтов у нас много и по каждому сайту обращаться техподдержку будет долго и не удобно.
Или хотя-бы подскажите в какую сторону смотреть? Пробовали заполнять значениями таблицу *Lcz - результата не дало.

Здравствуйте, Вячеслав!

Благодарим Вас, что поставили нас в известность. Действительно, плавающую ошибку воспроизвели. Скорее всего, ошибка связана с локализациями. Передали на нашу команду R&D для решения, как только проблема будет исправлена, мы Вас уведомим.

Здорово! Спасибо, будем ждать.

Здравствуйте, Вячеслав.

Исправления попадут в релиз 7.9.1 (ориентировочная дата выхода - конец декабря).

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

Добрый день!

Смотря на стандартные макросы для ПФ Word я увидел, что в них есть параметр arguments, который даже используется. Так вот у меня вопрос, как из ПФ Word передать в макрос аргументы?

Нравится

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

Сразу после имени макроса ставьте вертикальную полоску | и за ней любая строка, эта строка попадет в переменную arguments
к примеру:
column[#Macros|myparam#]

"Максим Шевченко" написал:

Сразу после имени макроса ставьте вертикальную полоску | и за ней любая строка, эта строка попадет в переменную arguments

к примеру:

column[#Macros|myparam#]

Спасибо!

Максим Шевченко,

возможно ли похожим способом передать аргументы для шаблона email сообщения?

Айдар, здравствуйте!

К сожалению, примеров кейсов с добавлением аргументов в макрос для шаблонов Email-сообщений у нас нет. Инструкцию по созданию макросов Вы можете найти на Академии: https://academy.terrasoft.ru/documents/technic-sdk/7-11/dobavlenie-obrabotchika-makrosa-v-shablone-email-soobshcheniya

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

При выборе контрагента и открывающемся Lookup окне, заголовок ставится "Основные сферы деятельности" причем подобное воспроизводится во всех разделах.

Кто то сталкивался с подобным? В какую сторону копать вообще?
1

Нравится

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

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

Кэш и редис чистились, конечно. Нет с остальными сущностями нормально, более того в мултисправочнике, вроде Клиент в продаже при выборе Контрагент отображается нормально

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

Вопрос снят, кто то создал справочник и назвал его Основные сферы деятельности, подвязан на объект Контрагент

Интересный эффект получился :)

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

Нужно добавить любое поле, к примеру, "Дата". Делаю по документации не получается:
-Создаю замещающий объект в пакете customer;
-Выбираю Контрагента как родительский объект;
-Публикую;
-Создаю замещающий клиентский объект;
А в родительском объекте не знаю что выбрать

Нравится

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

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

"Алексей Сахоров" написал:-Создаю замещающий клиентский объект;
А в родительском объекте не знаю что выбрать

по контексту - замещающий клиентский модуль все же...
Родителем указываете то, что хотели заместить, если карточка раздела Контрагента то AccountPageV2 (Страница редактирования контрагента)

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

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

Нравится

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

Действие на кнопке вызывает из BaseSectionV2 в итоге метод onActiveRowAction.
Он в свою очередь вызывает метод deleteRecords() из GridUtilitiesV2.
В теории я бы в замещающем модуле section вашего раздела переопределил метод родительский onActiveRowAction так, чтобы он вызывал при нажатии кнопки с тэгом "delete" ваш новый метод, подобный deleteRecords(), но с нужной вам проверкой. А по результатам проверки нужно будет окно поднять, тут похожее обсуждалось

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

Александр теория понятна, нашел все эти методы
проблема с написанием кода, можете скинуть какой нибудь пример в плане переопределения
и где раcположить коды в моем модуле section?

Так то не теория )

"Евдокимов Евгений" написал:где раcположить коды в моем модуле section

В блоке methods вашего замещающего клиентского модуля section.
По аналогии с оригинальным пишем свой метод onActiveRowAction, в нем вызываем свой brand_new_deleteRecords().
brand_new_deleteRecords() также пишем в methods своего модуля.
Если время будет попробую код набросать...

"Александр Кудряшов" написал:Если время будет попробую код набросать...

все получилось, спасибо!

"Евдокимов Евгений" написал:все получилось, спасибо!

Ну вот и хорошо ))

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