Выделение цветом в Расписании активностей при определенных условиях

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

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

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.

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