Разработка
14
Окт
2

TimelineJS

В CRM имеется календарик… Довольно скучный 🙂 и не менявшийся уже лет эдак 100 🙂

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

Приступим:

  • Импортируйте в CRM следующие Веб-ресурсы:
  • Создайте HTML Веб-ресурс timeline.html с таким кодом:
    <!DOCTYPE html
    
    <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>timeline</title>
        <link rel="stylesheet" type="text/css" href="/WebResources/new_timeline.css">
        <script type="text/javascript" src="/WebResources/new_jquery.min.js"></script>
        <script type="text/javascript" src="/WebResources/new_timeline.min.js"></script>
        <script type="text/javascript" src="/WebResources/new_storyjs.embed.js"></script>
        <script type="text/javascript" src="/WebResources/ClientGlobalContext.js.aspx"></script>
        <script>
            $(function () {
                activitys = [];
                var today = new Date();
                var datetime = "datetime'" + today.getFullYear() + "-" + (today.getMonth() + 1) + "-" + today.getDate() + "T00:00:00.000Z'";
                var currentUserId = Xrm.Page.context.getUserId().replace("{", "").replace("}", "").toLowerCase();
    
                // Запрашиваем Действия CRM
                $.ajax({
                    type: "GET",
                    contentType: "application/json; charset=utf-8",
                    datatype: "json",
                    url: Xrm.Page.context.getClientUrl() + "/XRMServices/2011/OrganizationData.svc/ActivityPointerSet?$select=ActivityId,ActivityTypeCode,Description,RegardingObjectId,ScheduledEnd,ScheduledStart,StatusCode,Subject,activitypointer_activity_parties/PartyId&$expand=activitypointer_activity_parties&$filter=(StateCode/Value eq 3 or StateCode/Value eq 0) and (ScheduledStart ge " + datetime + " or ScheduledEnd ge " + datetime + ") and OwnerId/Id eq guid'" + currentUserId + "'&$top=100",
                    beforeSend: function (XMLHttpRequest) {
                        XMLHttpRequest.setRequestHeader("Accept", "application/json");
                    },
                    async: false,
                    success: function (data, textStatus, xhr) {
                        var results = data.d.results;
                        for (var i = 0; i < results.length; i++) {
    
                            var ActivityTypeCode = results[i].ActivityTypeCode;
                            // Отбираем только Звонки, Встречи и Задачи
                            if (!(ActivityTypeCode == "appointment" || ActivityTypeCode == "phonecall" || ActivityTypeCode == "task"))
                                return;
    
                            // Формируем описание
                            if (!results[i].Description || results[i].Description == "") {
                                var Description = "_";
                            } else {
                                var Description = results[i].Description;
                            }
    
                            // Формируем поле В отношении
                            if (results[i].RegardingObjectId.Name && results[i].RegardingObjectId.Name != null) {
                                var RegardingObject = "<a target=\"_blank\" href=\"http://crm2015/superfirma/main.aspx?etn=" + results[i].RegardingObjectId.LogicalName + "&pagetype=entityrecord&id=%7B" + results[i].RegardingObjectId.Id + "%7D\">" + results[i].RegardingObjectId.Name + "</a>";
                            } else {
                                var RegardingObject = "_";
                            }
    
                            // Формируем дату Действия
                            if (results[i].ActivityTypeCode == "appointment") {
                                // Для Встреч заполняем интервал
                                var ScheduledStart = parseDate(results[i].ScheduledStart);
                                var ScheduledEnd = parseDate(results[i].ScheduledEnd);
                            } else {
                                // Для Звонков и Задач только срок
                                var ScheduledStart = parseDate(results[i].ScheduledEnd);
                                var ScheduledEnd = "";
                            }
    
                            // Формируем участников действия
                            var partiesList = "";
                            
                            var partiesArr = results[i].activitypointer_activity_parties.results;
                            for (var z = 0; z < partiesArr.length; z++) {
                                // Исключяем текущего Ответственного и значение из поля В отношении
                                if (partiesArr[z].PartyId.Id != currentUserId && partiesArr[z].PartyId.Id != results[i].RegardingObjectId.Id) {
                                    partiesList += "<a target=\"_blank\" href=\"http://crm2015/superfirma/main.aspx?etn=" + partiesArr[z].PartyId.LogicalName + "&pagetype=entityrecord&id=%7B" + partiesArr[z].PartyId.Id + "%7D\">" + partiesArr[z].PartyId.Name + "</a>, ";
                                }
                            }
                            if (partiesList != "") {
                                var partiesList = partiesList.slice(0, -2);
                            } else {
                                var partiesList = "_";
                            }
                            
                            // Помещаем найденные Действия в массив
                            var obj = {
                                startDate: ScheduledStart,
                                endDate: ScheduledEnd,
                                headline: results[i].Subject,
                                text: "<a target=\"_blank\" href=\"http://crm2015/superfirma/main.aspx?etn=" + ActivityTypeCode + "&pagetype=entityrecord&id=%7B" + results[i].ActivityId + "%7D\">Открыть</a>",
                                tag: getActivityType(ActivityTypeCode),
                                asset: {
                                    media: Description,
                                    thumbnail: getActivityIcon(ActivityTypeCode),
                                    credit: "В отношении: " + RegardingObject,
                                    caption: "Усчастники: " + partiesList
                                }
                            };
                            activitys.push(obj);
                        }
                    },
                    error: function (xhr, textStatus, errorThrown) {
                        alert(textStatus + " " + errorThrown);
                    }
                });
    
                var tomorrow = new Date();
                tomorrow.setDate(tomorrow.getDate() + 1);
    
                // Формируем заголовок Timeline и помещяем в него данные
                storyjs_json_data = {
                    "timeline":
                    {
                        "headline": "Календарь CRM",
                        "type": "default",
                        "text": "<p>Выберите Действие, которое хотите просмотреть...</p>",
                        "date": activitys,
                        "era": [ // Подсвечиваем текущую дату
                            {
                                "startDate": today.getFullYear() + "," + (today.getMonth() + 1) + "," + today.getDate(),
                                "endDate": tomorrow.getFullYear() + "," + (tomorrow.getMonth() + 1) + "," + tomorrow.getDate()
                            }
                        ]
                    }
                }
    
                // Инициируем создание Timeline
                createStoryJS({
                    type: 'timeline',
                    width: '100%',
                    height: '500',
                    source: storyjs_json_data,
                    embed_id: 'my-timeline',
                    lang: 'ru'
                });
            });
    
            // Парсим дату возвращаемую CRM
            function parseDate(dt) {
                var formatDate = "";
    
                if (dt) {
                    dt = dt.replace("/Date(", "");
                    dt = dt.replace(")/", "");
                    var date = new Date(parseInt(dt, 10));
                    formatDate = date.getFullYear() + "," + (date.getMonth() + 1) + "," + date.getDate() + "," + date.getHours() + "," + date.getMinutes() + "," + date.getSeconds();
                }
    
                return formatDate;
            };
    
            // Переводим название типа Действия
            function getActivityType(at) {
                var type = "";
                switch (at) {
                    case "appointment": type = "Встречи"
                        break
                    case "phonecall": type = "Звонки"
                        break
                    case "task": type = "Задачи"
                        break
                }
                return type;
            }
    
            // Возвращаем иконку соответствующую типу Действия
            function getActivityIcon(at) {
                var iconURL = "";
                switch (at) {
                    case "appointment": iconURL = "http://crm2015/_imgs/ico_16_4201.gif"
                        break
                    case "phonecall": iconURL = "http://crm2015/_imgs/ico_16_4210.gif"
                        break
                    case "task": iconURL = "http://crm2015/_imgs/ico_16_4212.gif"
                        break
                }
                return iconURL;
            }
            
        </script>
    </head>
    <body>
        <div id="my-timeline"></div>
    </body>
    </html>
    

    Что тут происходит:

    • Подключаем необходимые ресурсы;
    • С помощью REST-запроса отбираем будущие активные Действия текущего пользователя;
    • По очереди обрабатываем возвращённые записи и форматируем их данные до необходимого состояния;
    • Отформатированные данные помещаем в специальный массив и объект, после чего инициируем создание TimelineJS.
  • Вынести HTML Веб-ресурс timeline.html куда-нибудь в CRM: на панель навигации или на Панель мониторинга…

Смотрим…

З.Ы.

  1. Для данного примера я отбирал данные из объекта ActivityPointer (который является родительским для всех Действий). Если же расширить пример и отбирать данные из конкретных объектов (task или phonecall), то можно построить более индивидуальный календарь для каждого из типов Действий;
  2. Важным отличием TimelineJS от стандартного календаря является то, что Вы можете изменять его в определенных пределах, редактируя исходные файлы фреймворка.



Комментарии (2)

*

code