Введение
COREmanager предоставляет широкий набор функций для создания практически любой панели. В этом примере будет создаваться панель отображающая список пациентов.
Начало
Подготовка:
Скачайте и установите последнюю версию COREmanager. Она должна быть доступна по адресу https://ip-адрес:1500/core. По умолчанию COREmanager устанавливается в каталог /usr/local/mgr5/. Вся дальнейшая работа будет вестись относительно пути установки по умолчанию.
Для удобства сборки и настройки мы создадим нашу панель в каталоге 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
Расширение функционала панели
Расширение функционала можно условно разбить на несколько этапов:
- Описание меню и настроек интерфейса (фаил mypanel.xml).
- Перевод меню (mypanel_msg_ru.xml).
- Реализация событий и действий в коде.
Описание меню и настроек интерфейса
Детальное описание настроек меню вы найдёте в статье XML.
При запуске панель подключает меню по умолчанию, описанное в файле core.xml и своё меню. Для описания интерфейса панели и меню создайте в каталоге etc/xml файлы mypanel.xml и mypanel_msg_ru.xml. Файл mypanel.xml описывает логическую структуру интерфейса, а файл mypanel_msg_ru.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);
}
};