Эта публикация предназначена ABAP-разработчикам в SAP ERP и всем им сочувствующим.
Часть1

Не все знают, что в ALV-отчет можно добавить красивый заголовок на HTML.
Результат будет похож на это:


А что если бы хотим нарисовать нечто свое?
Например:


Добро пожаловать под кат.

Поехали!

Я не нашел в инете, какой-либо инфы, и решил придумать нечто свое.
Стандартный заголовок рисуется примерно так:
FORM do_html_top_of_page USING p_do TYPE REF TO cl_dd_document.

*----------------------------------------------------------------------*
* .DATA
*----------------------------------------------------------------------*
  DATA: ta      TYPE REF TO cl_dd_table_element,
              col1  TYPE REF TO cl_dd_area,
              col2  TYPE REF TO cl_dd_area,
              col3  TYPE REF TO cl_dd_area,
              text   TYPE sdydo_text_element,
              str     TYPE string,
              rows TYPE int4.

  DEFINE add_column.
    call method ta->add_column
      exporting
        heading = text
      importing
        column  = &1.
    clear text.
  END-OF-DEFINITION.

  DEFINE add_text.
    call method &1->add_text
      exporting
        text = text.
    clear text.
  END-OF-DEFINITION.

  str = 'Параметры отчета:'.
  CALL METHOD p_do->add_table
    EXPORTING
      with_heading    = 'X'
      no_of_columns   = 2
      width           = '30%'
      with_a11y_marks = 'X'
      a11y_label      = str
    IMPORTING
      table           = ta.

  text = 'Параметры отчета:'.
  add_column: col1.

  text = 'Значения'.
  add_column: col2.

  text = 'Заказ'.
  add_text: col1.
  text = gv_aufnr.
  add_text: col2.

  CALL METHOD ta->new_row.
  ADD 1 TO rows.
  
ENDFORM.                    "do_html_top_of_page




Что-бы свое было универсально и легко подключалось,
в любой отчет, в котором возможны HTML-заголовки,
обернем это дело в функциональный модуль:


FORM do_html_top_of_page
*&---------------------------------------------------------------------*
                  USING p_do TYPE REF TO cl_dd_document.
*&---------------------------------------------------------------------*

  DATA lt_html TYPE TABLE OF zparam WITH HEADER LINE.

  lt_html-param = 'Важность'.
  lt_html-value = 'Высокая'.
  APPEND lt_html.

  lt_html-param = 'Материал'.
  lt_html-value = 'Все'.
  APPEND lt_html.

  lt_html-param = 'Период'.
  lt_html-value = '01.01.2015 - 01.03.2016'.
  APPEND lt_html.

  CALL FUNCTION 'Z_FM_FORM_HTML_TAB'
    EXPORTING
      it_param    = lt_html[]
      iv_type      = 'DARK'
    CHANGING
      dd_document = p_do.

ENDFORM.



Структура zparam проста:
PARAM CHAR100
VALUE CHAR100

В ФМ:
сначала заполняем CSS часть,
потом создаем таблицу на HTML,
в конце добавляем в dd_document или его область, если она есть на входе

Функциональный модуль:
FUNCTION z_fm_form_html_tab.
*"----------------------------------------------------------------------
*"*"Локальный интерфейс:
*"  IMPORTING
*"     REFERENCE(IT_PARAM) TYPE  ZTPARAM
*"     REFERENCE(IV_TYPE) TYPE  CHAR10
*"  CHANGING
*"     REFERENCE(DD_DOCUMENT) TYPE REF TO  CL_DD_DOCUMENT
*"     REFERENCE(DD_AREA) TYPE REF TO  CL_DD_AREA OPTIONAL
*"----------------------------------------------------------------------

  DATA lt_html TYPE TABLE OF sdydo_html_line WITH HEADER LINE.

  DEFINE add_tag.
    lt_html = &1.
    append lt_html.
  END-OF-DEFINITION.

  DEFINE conc_tag_line.
    concatenate '<td>' &1 '</td>' into lt_html.
    append lt_html.
  END-OF-DEFINITION.

*"----------------------------------------------------------------------
* Добавим CSS
*"----------------------------------------------------------------------

  add_tag '<html>'.

  add_tag '<style type="text/css">'.

  CASE iv_type.

    WHEN 'DARK'.

      add_tag 'table {'.
      add_tag 'font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;'.
      add_tag 'font-size: 12px;'.
      add_tag 'border-collapse: collapse;'.
      add_tag 'text-align: center;}'.
      add_tag 'th, td:first-child {'.
      add_tag 'background: #252F48;'.
      add_tag 'color: white;'.
      add_tag 'padding: 1px 1px;}'.
      add_tag 'th, td {'.
      add_tag 'border-style: solid;'.
      add_tag 'border-width: 0 1px 1px 0;'.
      add_tag 'border-color: white;}'.
      add_tag 'td { background: #CAD4D6;}'.
      add_tag 'th:first-child, td:first-child {'.
      add_tag 'text-align: left;}'.

    WHEN 'ZEBRA'.

      add_tag 'table {'.
      add_tag 'border-spacing: 0;'.
      add_tag 'empty-cells: hide;}'.
      add_tag 'td {'.
      add_tag 'padding: 3px 3px;'. "5
      add_tag 'text-align: center;'.
      add_tag 'border-bottom: 1px solid #F4EEE8;'.
      add_tag 'transition: all 0.5s linear;}'.
      add_tag 'td:first-child {'.
      add_tag 'text-align: left;'.
      add_tag 'color: #3D3511;'.
      add_tag 'font-weight: bold;}'.
      add_tag 'th {'.
      add_tag 'padding: 3px 3px;'. "5
      add_tag 'color: #3D3511;'.
      add_tag 'border-bottom: 1px solid #F4EEE8;'.
      add_tag 'border-top-left-radius: 10px;'.
      add_tag 'border-top-right-radius: 10px;}'.
      add_tag 'td:nth-child(even)'.
      add_tag ' {background: #F6D27E;}'.
      add_tag 'td:nth-child(odd)'.
      add_tag ' {background: #D1C7BF;}'.
      add_tag 'th:nth-child(even)  {'.
      add_tag 'background: #F6D27E;}'.
      add_tag 'th:nth-child(odd)'.
      add_tag '  {background: #D1C7BF;}'.
      add_tag '.round-top {'.
      add_tag 'border-top-left-radius: 10px;}'.
      add_tag '.round-bottom {'.
      add_tag 'border-bottom-left-radius: 10px;}'.
      add_tag 'tr:hover td{'.
      add_tag 'background: #D1C7BF;'.
      add_tag 'font-weight: bold;}'.


  ENDCASE.

  add_tag '</style>'.

*"----------------------------------------------------------------------
* Добавим HTML
*"----------------------------------------------------------------------

  add_tag '<table>'.

  add_tag '<tr>'.
  add_tag '<th>Параметры отчета: </th>'.
  add_tag '<th>Значение: </th>'.
  add_tag '</tr>'.

  DATA ls_param LIKE LINE OF it_param.
  LOOP AT it_param INTO ls_param.

    add_tag '<tr>'.
    conc_tag_line: ls_param-param.
    conc_tag_line: ls_param-value.
    add_tag '</tr>'.

  ENDLOOP.

  add_tag '</table>'.

  add_tag '</html>'.

*"----------------------------------------------------------------------
* Добавим HTML в область или документ
*"----------------------------------------------------------------------

  IF dd_area IS NOT INITIAL.
    dd_area->add_static_html( table_with_html = lt_html[] ).
  ELSE.
    dd_document->add_static_html( table_with_html = lt_html[] ).
  ENDIF.


ENDFUNCTION.



Напомню получим:


Минус решения, если у пользователя повышенные настройки безопасности в IE, CSS оформление выводится не будет. Всем спасибо.

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


  1. occam
    26.01.2016 20:58
    -2

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


  1. ivanbolhovitinov
    27.01.2016 07:26

    О вкусах можно спорить бесконечно.

    Я предпочитаю попроще


    1. Endrews
      27.01.2016 08:37

      Иван, буду благодарен, если напишите, как регулировать высоту HTML-заголовка. Как-то смотрел, ничего не нашел и забил. Если параметров не много, можно и сузить, а если много расширить. А так авто-высота.

      По второму пункту согласен, надо подумать, что с этим можно сделать, пока в голову не приходило.


      1. ivanbolhovitinov
        27.01.2016 09:02

        Насчет высоты: У меня нет готового ответа. Надо экспериментировать, смотреть исходники самого ALV и обёрток, которые вы используете (видимо REUSE_ALV_GRID_DISPLAY_LVC).
        Навскидку:
        Высота рассчитывается внутри.
        Логика у него внутри скорее всего простая (потому что высота регулируется внутри абапа, а у него нет встроенного браузера с линейкой).
        ШТМЛ который вы генерируете содержит неожиданные ходы, которая его логика не предусматривает

        Варианты:

        • Находите код, который считает высоту, делаете выводы
        • С самого начала пишете свой враппер на ALV, с вашей логикой, блэкджеком и комбобоксами
        • Экспериментально подсовывая разный ШТМЛ выясняете что на него влияет
        • Смотрите какой ШТМЛ по факту делают стандартные реализации, например через cl_salv_form_layout_grid, сравниваете со своим


  1. ivanbolhovitinov
    27.01.2016 09:15

    По коду.
    Между макросами (define) и любой формой модуляризации кода (подпрограммы, функции, методы) лежит пропасть. Когда-то я давно думал, что макросы — удобный способ не писать слова PERFORM и USING, или какие-то ещё. Это не так.
    Вы уверены, что вы действительно хотите ходить такими путями?


    1. Endrews
      27.01.2016 09:50

      Да макрос удобен. Только не надо в него заворачивать слишком сложные конструкции.

      Вот например код, смотрится органично, на мой взгляд
        DEFINE calc_1milliage.
          perform calc_one_milliage
               using
                 <fs_data>-equnr
                 &1
               changing
                 &2
                 &3.
          add_line: &1 &2 &3.
        END-OF-DEFINITION.
      
          IF lv_read EQ 'X'.
            READ TABLE st_s835 WITH KEY sernr = <fs_data>-equnr
                                        sptag = <fs_data>-gstrp.
            IF sy-subrc IS INITIAL.
              <fs_data>-treml = st_s835-treml.
              <fs_data>-tacml = st_s835-tacml.
            ELSE.
              calc_1milliage: <fs_data>-gstrp <fs_data>-treml <fs_data>-tacml.
            ENDIF.
          ELSE.
            calc_1milliage: <fs_data>-gstrp <fs_data>-treml <fs_data>-tacml.
          ENDIF.
      
      ..
      
          IF lv_read EQ 'X'.
            READ TABLE st_s835 WITH KEY sernr = <fs_data>-equnr
                                        sptag = <fs_data>-dtnrp.
            IF sy-subrc IS INITIAL.
              <fs_data>-tacpp  = st_s835-tacml.
            ELSE.
              calc_1milliage: <fs_data>-dtnrp lv_treml <fs_data>-tacpp.
            ENDIF.
          ELSE.
            calc_1milliage: <fs_data>-dtnrp lv_treml <fs_data>-tacpp.
          ENDIF.
      


    1. Endrews
      27.01.2016 09:58

      Или например очень удобно
      METHOD set_col_names .
      
          DATA lr_columns TYPE REF TO cl_salv_columns.
          DATA: lr_column TYPE REF TO cl_salv_column.
      
          lr_columns = gr_rep->get_columns( ).
          lr_columns->set_optimize( abap_true ).
      
      * Установим тексты
      
          set_names: 'SERNR'  'Вагон'      'Вагон'          'Номер вагона'.
          set_names: 'SELEC'  'Выбор'      'Выбор'          'Выбор'.
          set_names: 'ICON'   'Статус'     'Статус'         'Статус'.
      ... А ведь колонок быть может быть очень много ))
      ENDMETHOD.
      ...
      DEFINE set_names.
      
            try.
                lr_column = lr_columns->get_column( &1 ).
                lr_column->set_short_text( &2 ).
                lr_column->set_medium_text( &3 ).
                lr_column->set_long_text( &4 ).
              catch cx_salv_not_found.
            endtry.
      
      END-OF-DEFINITION.
      



  1. kanikeev
    27.01.2016 09:42

    Даа, вы тот еще извращенец…
    ABAP — язык бизнес-логики, для красивостей лучше смотреть в сторону bsp, webdynpro или sapui5.

    Хотя, что это я? Сам на прошлой неделе верстал html-письма на нем-родимом :)


    1. Endrews
      27.01.2016 09:46

      Да-да, месье знает толк в извращениях


    1. kanikeev
      27.01.2016 10:04
      -1

      раздутыйкакиндюкабапер mode on*

      Куски html/css/шаблоны я храню в SO10 текстах — так проще потом править.
      Ваш набор css/html можно было просто загнать в текст и заменой placeholder'ов подставить нужные значения.

      Смесь переводимых текстов (параметры отчета) и непероводимых (th) в одном значении — это фу.

      Объявление переменных в теле кода, а не в начале — фу (тут так принято). Тогда уж лучше использовать inline объявление, если версия позволяет.

      раздутыйкакиндюкабапер mode off*

      Не оценивайте мое брюзжание как критику. Дерзайте. Учитесь. Делитесь опытом.


      1. Endrews
        27.01.2016 10:11

        Про SO10 не думал, возможно вариант, но редактирую не часто, сделал CSS-стиль и забыл
        Вообще css/html — не большой спец, поэтому тут надо добавлять)


        1. ivanbolhovitinov
          27.01.2016 10:31

          А я бы не стал SO10 использовать, оно зависит от языка, в контексте это не факт. Его потом ещё и переносить надо. SMW0 предпочтительней, это объекты разработки на общих условиях.


          1. kanikeev
            30.01.2016 09:26
            -1

            Я все равно за SO10.
            * Многоязычность — то, что надо, так как работаю в многоязычных системах.
            * Текст можно поменять прямо в заблокированном для изменений продуктиве при необходимости (не будем спорить на тему безопасность против удобства). Я пишу код, а уж что там функциональщик занесет — его дело.


    1. occam
      28.01.2016 17:07
      -1

      Бизнес-логика в современном понимании и ABAP — это примерно как оснащение зайца стоп-сигналами :-D


      1. kanikeev
        30.01.2016 09:31
        -1

        Очень образно, но не совсем понятно, в чем особенность современного понимания бизнес-логики, и чем для этого не годится ABAP.


        1. occam
          31.01.2016 20:51
          -1

          Особенность, Lieber Sapper, всего лишь в том, что когда в форме 2-НДФЛ появится возможность не заполнять поле ИНН, тогда у пользователя 1С эта опция появится by design, а вот пользователь SAP «побежит» в отдел методологии с просьбой «need update, please!!» Аналогично с появлением формы 6-НДФЛ etc.etc.etc. Не кажется ли Вам, что бегать к аналитикам по любому новому «чиху» госорганов, которые случаются еженедельно, — это очень и очень далеко от логичного бизнеса и бизнес-логики в том числе?


          1. occam
            31.01.2016 20:58
            -1

            А ключевой смысл в том, что без оперативной методологической поддержки надстройка над учетной системой, маркетологически решающая все бизнес-задачи, на самом деле предстваляется бесполезным форком кобола, так?


            1. kanikeev
              01.02.2016 00:34
              -1

              Ваш личный неудачный опыт работы с SAP не является отсутствием оперативной методологической поддержки.


              1. occam
                01.02.2016 07:22

                Позвольте спросить, Вы инженер или маркетолог :-D Если первое, то можно ли увидеть гарантии присутствия оперативной Методологической поддержки силами вендора?

                И не казалось ли Вам, что ЛЮБОЙ проект по внедрению эсэйпи на 80-90% делается, развивается и поддерживается людьми Заказчика, либо папочка с лицензиями просто пылится на полке у CFO/CIO/CAO? Аналогично: Oracle и AX.


                1. kanikeev
                  01.02.2016 11:45

                  Я — консультант.

                  Ваш термин Оперативная методологическая поддержка слишком расплывчат и под него отлично подходит поддержка со стороны SAP.
                  Да — это не миф, да — я с нии работал, да — они помогают. Не совсем доволен их скоростью работы — но об этом уже написал.

                  По поводу 80-90% — это так. Так просто намного дешевле. А разве 1С сами всегда все внедряют и подерживают?

                  И опять повторю свой вопрос. Какое отношение имеют ваши претензии к вендору к языку программирования?


          1. kanikeev
            01.02.2016 00:32
            -1

            Хм… Наверное, я давно не работал с 1С. Во времена семерки тоже ничего не появлялось автоматом — приходили мальчики/девочки и накатывали обновления/пилили конфигурацию. В этом смысле просто те же самые аналитики бегали в бухгалтерию.

            Не кажется ли вам, что слишком частые чихи госорганов не являются недостатком программного комплекса, и уж тем более языка программирования. Держите также в уме, что 1C работает исключительно на российский рынок с его реалиями, а SAP — на мировой, и российский далеко не является приоритетным. Это к тому, что на ежедневные чихи каждого ведомства разных государств реагировать сложнее.

            Ну это то, что касается программного комплекса, а то, что касается именно языка — не увидел ни одного аргумента.


  1. horosho
    27.01.2016 10:41
    +1

    Шел 2016 год…


  1. whydrae
    27.01.2016 11:20
    -2

    Я бы на вашем месте занимался экспериментами над таблицами в UI5 (sap.ui.table.Table, sap.ui.table.AnalyticalTable) и соответсвующей обвязкой oData и т.п… Альзо, макросы большой не-не и вызывают дикую боль при отладке старых программ. ФМники и перформы уже тоже не советуют использовать, вместо них лучше писать классы и методы (п.с. говорю с колокольники стандарта и гайдлайнов официальных. Другое дело — легаси).


    1. kanikeev
      30.01.2016 09:32

      Согласен с вами.