Документация COREmanager

Моя первая панель

Введение

COREmanager предоставляет широкий набор функций для создания практически любой панели. В этом примере будет создаваться панель отображающая список пациентов.

Начало

Подготовка:

Скачайте и установите последнюю версию COREmanager. Она должна быть доступна по адресу https://ip-адрес:1500/core. По умолчанию COREmanager устанавливается в каталог /usr/local/mgr5/. Вся дальнейшая работа будет вестись относительно пути установки по умолчанию.

Для удобства сборки и настройки мы создадим нашу панель в каталоге src/.

Обратите внимание!
Для автоматизации процесса сборки мы рекомендуем помещать все проекты связанные с COREmanager в каталог src/.

Создайте каталог mypanel и перейдите в него.

Создайте типовой Makefile следующего вида:

LIB += mypanel
LANGS += ru en
mypanel_SOURCES = mypanel.cpp
mypanel_LDADD = -lbase

include ../isp.mk

О том, как собирать собственный модуль смотрите по ссылке.

Создайте в этом же каталоге файл mypanel.cpp:

#include <api/module.h>

using namespace  isp_api;

MODULE_INIT(mypanel,"") {
}

Перейдите в консоль и выполните команду:

make install 

После выполнения этой команды каталоге /usr/local/mgr5/lib появится файл mypanel.so. Всё, что осталось это перейти в корень каталога /usr/local/mgr5 и установить панель с помощью команды:

bin/core mypanel install

Панель готова. Теперь откройте браузер  и перейдите по адресу: https://ip-адрес:1500/mypanel

Расширение функционала панели

Расширение функционала можно условно разбить на несколько этапов:

  1. Описание меню и настроек интерфейса (фаил mypanel.xml).
  2. Перевод меню (mypanel_msg_ru.xml).
  3. Реализация событий и действий в коде.

Описание меню и настроек интерфейса

Детальное описание настроек меню вы найдёте в статье XML.

При запуске панель подключает меню по умолчанию, описанное в файле core.xml и своё меню. Для описания интерфейса панели и меню создайте в каталоге etc/xml файлы mypanel.xml и mypanel_msg_ru.xml. Файл mypanel.xml описывает логическую структуру интерфейса, а файл mypanel_msg_ru.xml хранит названия меню на русском языке.

Обратите внимание!
Имена файлов могут быть любыми, но мы рекомендуем создавать файлы со следующими именами имяпанели.xml и имяпанели_msg_язык.xml

Для созданной панели добавьте своё главное меню Очередь и подменю: Список пациентов (будет выводить список всех записанных на приём) и Последний (будет отображать форму с именем последнего записавшегося пациента).

И так файл mypanel.xml будет иметь следующий вид:

 <?xml version="1.0" encoding="UTF-8"?>
<mgrdata>
  <mainmenu level="registered" name="">
    <node name="Stack" first="yes">
      <node name="pacientlist"/>
      <node name="showlast"/>
      <node name="myreport"/>
    </node>
  </mainmenu>

  <metadata name="showlast" type="form">
    <form title="LastPacient">
      <field name="LastPacient">
        <input type="text" name="lastpacient" readonly="yes"/>
      </field>
    </form>
  </metadata>

  <metadata name="pacientlist" type="list" key="index" keyname="index">
    <toolbar>
      <toolbtn func="pacientlist.edit" type="new" default="yes" img="t-new" name="new"/>
      <toolbtn func="pacientlist.edit" type="edit" img="t-edit" name="edit"/>
      <toolbtn func="pacientlist.delete" type="group" img="t-delete" name="delete"/>
    </toolbar>
    <coldata>
      <col name="index" type="data" sort="alpha" sorted="desc" hide ="yes" />
      <col name="date" type="data" sort="alpha" sorted="desc"/>
      <col name="pacientname" type="data" sort="alpha"/>
    </coldata>
  </metadata>

  <metadata name="pacientlist.edit" type="form">
    <form title="addPacient">
      <field name="uname">
        <input type="text" name="uname"/>
      </field>
      <field name="ulastname">
        <input type="text" name="ulastname"/>
      </field>
      <field name="rdate">
        <input type="text" name="rdate" date="text"/>
      </field>
    </form>
  </metadata>

  <metadata name="myreport" type="report" level="registered" firstrun="yes">
     <text name="title"/>
     <band name="report" headcolor="#f4d0bc">
        <diagram label="report" data="count" type="pie"/>
        <col name="uname" type="data" total="count" sort="alpha" link="no"/>
      </band>
   </metadata>

</mgrdata>

Текстовые сообщения

Файл mypanel_msg_ru.xml обязательно должен быть создан и заполнен, иначе у вас не будет названий в пунктах меню.

Пример файла mypanel_msg_ru.xml:

<?xml version="1.0" encoding="UTF-8"?>
<mgrdata>
<lang name="ru">
  <messages name="desktop">
    <msg name="menu_showlast">Последний</msg>
    <msg name="menu_Stack">Очередь</msg>
    <msg name="menu_pacientlist">Список больных</msg>
    <msg name="menu_myreport">Отчёт</msg>
  </messages>

  <messages name="showlast">
    <msg name="title">Последний больной</msg>
    <msg name="LastPacient">Имя последнего на голову больного.</msg>
    <msg name="Last">Версия</msg>
  </messages>

  <messages name="pacientlist">
    <msg name="title">Список больных</msg>
    <msg name="date">Дата и время записи</msg>
    <msg name="pacientname">Имя больного</msg>
    <msg name="short_new">Добавить</msg>
    <msg name="short_delete">Удалить</msg>
    <msg name="short_edit">Редактировать</msg>
  </messages>

  <messages name="pacientlist.edit">
    <msg name="title">Добавить</msg>
    <msg name="uname">Имя больного</msg>
    <msg name="ulastname">Фамилия больного</msg>
    <msg name="rdate">Дата приёма</msg>
  </messages>

  <messages name="myreport">
    <msg name="title">Отчёт</msg>
    <msg name="uname">Имя больного</msg>
    <msg name="ulastname">Фамилия больного</msg>
    <msg name="rdate">Дата приёма</msg>
  </messages>

</lang>
</mgrdata>

Если у вас не отображается какое-то меню, значит у вас ошибка в файле перевода.

Реализация событий и действий

В COREmanager существует ряд классов упрощающих работу с обработкой событий, в данном примере будут использоваться:

  • FormAction;
  • StdListAction.

В COREmanager есть несколько готовых классов упрощающих работу со списками, например StdListAction. В этом классе автоматически создаётся действие ИмяДействия.delete, которое можно использовать лишь описав использование соответствующей функции в xml файле. Стоит отметить, что данное действие вызывается для выделенной группы элементов поочерёдно. Например: на панели инструментов списка создана кнопка Удалить, которая вызывает функцию pacientlist.delete. В коде нет созданного отдельного действия для обработки этой кнопки, так как в классе ActionPacientList автоматически создаётся действие с именем pacientlist.delete. Всё что нужно — это переопределить метод Del(Session &ses, const string &elid) и при нажатии на кнопку Удалить действие pacientlist.delete вызовется автоматически. Ключевым полем для списка является индекс — в массиве переменная elid будет содержать индекс удаляемого элемента. Если в списке выделить две строки и нажать кнопку Удалить то метод Del() вызовется поочередно для каждого элемента.

Также автоматически создаётся действие с именем pacientlist.edit. Причём для Добавления и Редактирования записи будет вызываться одно и тоже действие. При нажатии на кнопку Редактировать или Добавить вызовется метод Get(Session &ses, const string &elid), если была нажата кнопка Редактирорвать, то elid будет содержать праметр ключевого поля выделенной строки. В данном случае это будет индекс элемента в массиве. При нажатии на кнопку Добавить elid = "", по этому признаку можно определить дальнейшее поведение при заполнении формы. При нажатии на кнопку Ок, формы Редактирования или Добавления, вызовется метод Set(Session &ses, const string &elid) или New(Session &ses). Код нашего класса:

#include <api/action.h>
#include <classes.h>
#include <mgr/mgrdate.h>
#include <mgr/mgrstr.h>

class ActionPacientList : public  StdListAction {
public:

ActionPacientList() : StdListAction("pacientlist", MinLevel(lvRegistered)) {}

void Get(Session &ses, const string &elid) const {
        if (elid=="") {
            DateTime date;
            ses.NewNode("rdate",date.AsDate());
        } else {
            ses.NewNode("rdate",_users::Instance().userAt(str::Int(elid))->date().AsDate());
            ses.NewNode("uname",_users::Instance().userAt(str::Int(elid))->name());
            ses.NewNode("ulastname",_users::Instance().userAt(str::Int(elid))->LastName());
        }
    }
    void Set(Session &ses, const string &elid) const {
         user * new_user = _users::Instance().userAt(str::Int(elid));
         new_user->setLastName(ses.Param("ulastname"));
         new_user->setName(ses.Param("uname"));
         new_user->setDateTime(DateTime(ses.Param("rdate")+" 00:00:00"));
         _users::Instance().save();
    }
    void New(Session &ses) const {
        user * new_user = new user;
        new_user->setName(ses.Param("uname"));
        new_user->setLastName(ses.Param("ulastname"));
        new_user->setDateTime(DateTime(ses.Param("rdate")+" 00:00:00"));
        _users::Instance().AddUser(new_user);
    }
    void Del(Session &ses, const string &elid) const {
        _users::Instance().RemoveUser(str::Int(elid));
    }

    void List(Session& ses) const {
        for (int i = 0; i < _users::Instance().count(); ++i) {
           ses.NewElem();
           ses.AddChildNode("index",str::Str(i));
           ses.AddChildNode("pacientname", _users::Instance().userAt(i)->name()+" "+_users::Instance().userAt(i)->LastName());
           ses.AddChildNode("date", _users::Instance().userAt(i)->date().AsDate());
       }
    }
};

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

class ActionShowLast : public FormAction {
public:
    ActionShowLast() : FormAction("showlast", MinLevel(lvRegistered)) {}
    //Обработка события при показе формы
    void Get(Session &ses, const string &elid) const {
        int index = _users::Instance().count()-1;
        std::string lastName = _users::Instance().userAt(index)->name() + " "+_users::Instance().userAt(index)->LastName();
        ses.NewTag("lastpacient",lastName);
    }
};