Разработка
03
Сен
3

jsTree и иерархия Подразделений

Много, много лет назад я запилил аддон (http://mmcrm.ru/?p=1477), который выводил на странице иерархию Подразделений. А при клике на Подразделении в соседнем iFrame’е отображалась карточка самого Подразделения. Тогда для этого решения я использовал ASP.NET. Сейчас эта технология устарела, поэтому попробуем обновить решение с использованием более современных технологий: JS, jQuery и jsTree (jQuery плагин).

Приступим:

  • Импортируйте в CRM следующие Веб-ресурсы:
  • Создайте в CRM два HTML Веб-ресурса:
    • businessunit.html
      <!DOCTYPE html>
      
      <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
      <head>
          <meta charset="utf-8" />
          <title></title>
          <style>
              body { margin:0 }
      
              #divL {
                  float: left;
                  width: 30%;
                  height: 95vh;
              }
              
              #divR {
                  float: right;
                  width: 70%;
                  height: 95vh;
              }
      
              iframe {
                  width: 100%;
                  height: 95vh;
                  border: 0px;
              }
          </style>
      </head>
      <body>
          <div id="divL">
              <iframe id="iframe_left" src="/WebResources/new_businessunit_left.html"></iframe>
          </div>
          <div id="divR">
              <iframe id="iframe_right"></iframe>
          </div>
      </body>
      </html>
      

      Здесь у нас простая страница содержащая два iFrame’а: в левом выводится собственно дерево Подразделений (формируемое страницей приведенной ниже), а в правом отображается карточка Подразделения (при клике на заголовке Подразделения в дереве);

    • businessunit_left.html
      <!DOCTYPE html>
      
      <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
      <head>
          <meta charset="utf-8" />
          <title>businessunit</title>
          <style>
      
          </style>
          <link rel="stylesheet" href="/WebResources/new_style.min.css" />
          <script src="/WebResources/ClientGlobalContext.js.aspx" type="text/javascript"></script>
          <script src="/WebResources/new_jquery.min.js"></script>
          <script src="/WebResources/new_jstree.min.js"></script>
          <script>
              $(function () {
                  arr = [];
                  
                  // Запрашиваем Подразделения CRM 
                  $.ajax({
                      type: "GET",
                      contentType: "application/json; charset=utf-8",
                      datatype: "json",
                      url: Xrm.Page.context.getClientUrl() + "/XRMServices/2011/OrganizationData.svc/BusinessUnitSet?$select=BusinessUnitId,Name,ParentBusinessUnitId&$filter=Name ne 'superfirma'&$top=1000",
                      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 id = results[i].BusinessUnitId;
                              var name = results[i].Name;
                              var parentBusinessUnitId = results[i].ParentBusinessUnitId;
                              var parentId = "#";
                              if (parentBusinessUnitId.Name != "superfirma") { // за исключением головного Подразделения
                                  parentId = parentBusinessUnitId.Id;
                              };
      
                              // Помещаем Подразделение и ссылку на головное Подразделение в массив
                              var obj = { id: id, parent: parentId, text: name };
                              arr.push(obj);
                          }
                      },
                      error: function (xhr, textStatus, errorThrown) {
                          alert(textStatus + " " + errorThrown);
                      }
                  });
      
                  // Формируем "дерево" Подразделений
                  $('#jstree_div').jstree({
                      'core': {
                          'themes': {
                              'name': 'proton',
                              'responsive': true
                          },
                          'data': arr // В качестве исходного материала для построения дерева передаем сформированный массив Подразделений
                      }
                  }).on('changed.jstree', function (e, data) {
                      // При клике на подразделении открываем его карточку в отдельном iFrame'е
                      var businessunitId = data.instance.get_node(data.selected[0]).id;
                      var url = "http://crm2015/superfirma/main.aspx?etn=businessunit&pagetype=entityrecord&id=" + businessunitId;
                      parent.window.document.getElementById('iframe_right').src = url;
      
                      // Обрабатываем артефакты отображения карточки Подразделения в iFrame'е (убираем пустые пространства)
                      sleep();
                  });
              });
      
              function sleep() {
                  var crmContentPanel = parent.window.document.getElementById('iframe_right').contentWindow.document.getElementById('crmContentPanel');
                  if (crmContentPanel) {
                      crmContentPanel.style.top = 0;
                  } else {
                      setTimeout(sleep, 500);
                  }            
              }
          </script>
      </head>
      <body>
          <div id="jstree_div"></div>
      </body>
      </html>
      

      Что тут у нас есть:

      • Сначала подключаем внешние ресурсы;
      • Запрашиваем Подразделения в CRM и помещаем их в массив. При этом исключаем из запроса головное подразделение;
      • Помещаем возвращенные Подразделения в массив в специальном формате (который может «скушать» jsTree);
      • Формируем «дерево» передавая на входе массив Подразделений;
      • Также у нас тут есть обработчик клика на заголовке Подразделения в дереве и обработчик некорректного отображения Подразделения в iFrame’е.
  • Выгрузите SiteMap и добавьте в CRM кнопку, ведущую к Веб-ресурсу businessunit.html. Примерно такого вида:
    <SubArea Id="businessunit" Icon="$webresource:new_businessunit.png" Url="$webresource:new_businessunit.html" Title="Business Unit" />
    

Можно тестить 🙂



Комментарии (3)
  • Fedor 03.09.2015

    Приветсвую.
    Спасибо за блог и за труд. Просто кладезь уникальной информации.

    В связи с переходом на CRM 2015 возникла проблема. Если выставить «new rendering» в настройках, никак не получается получить доступ через javascript к Quick View’s и к sub-grid’s. Они явно изменили DOM.
    Не пробовали? У кого-то получилось?
    Спасибо.

  • slivka_83 03.09.2015

    Добрый день.
    Данная настройка появится на локальных серверах только осень, с выходом апдейта 1 (а онлайн я не использую). Поэтому пока с ней не приходилось работать.

  • Fedor 03.09.2015

    Да, это новая штучка. Они передвинули iFrame и все наши custom script засунули в ClientApiWrapper.
    Не знаю, можно вставлять здесь линки или нет.
    https://community.dynamics.com/crm/b/develop1/archive/2015/05/24/turbo-forms-get-your-javascript-ready-for-crm2015-update-1

    «Since your custom JavaScript is now running in the context of the ClientApiWrapper (rather than the content IFRAME) any reference to window methods such as window.openStdWin or window.location.href will fail. In order to access these objects you will need to reference parent.window.»

*

code