В "Первой Форме" есть возможность отобразить на диаграмме Ганта некоторый набор задач, имеющих отношение к какой-то исходной задаче. Например, диаграмма может отображать все задачи и подзадачи проекта или все активности по клиенту (продажи, проекты, взаимодействия, договоры, коммерческие предложения и пр). Текущая дата отображается на диаграмме красной чертой.
Пример диаграммы Ганта в Проектном управлении
Пример диаграммы Ганта в Таймлайне задачи
Пример диаграммы Ганта в качестве представления задачи
Реализация
Для вывода диаграммы нужно настроить две публикации пакетов действий:
1. Публикация, которая описывает структуру данных.
2. Публикация, которая возвращает данные.
Пусть в нашем примере название первой публикации — gnt-structure, название второй публикации — gnt-data.
Интерфейс диаграммы Ганта вызывается следующим образом
~/spa/gantt/gnt-structure?taskId=' + taskId
где ~ — адрес приложения "Первая Форма", gnt-structure — название публикации, возвращающей структуру данных, а taskId — номер исходной задачи.
|
1. Публикация, описывающая структуру данных
В нашем примере это публикация gnt-structure.
Входящих параметров у публикации нет.
Тип запроса — GET.
Пакет содержит единственное действие HTTP ответ, которое возвращает результат в формате JSON.
Структура тела ответа
Ключи
|
Описание
|
dataUrl
|
строка вызова второй публикации
|
columns
|
|
массив столбцов левой части диаграммы Ганта в формате JSON. Для каждого столбца могут быть указаны:
|
type
|
тип столбца. В структуре данных обязательно должен быть один столбец с типом name — это столбец с названием задачи, он участвует в построении иерархии. Для остальных столбцов тип не указывается
|
field
|
название поля (так, как оно возвращается в публикации с данными)
|
text
|
название столбца, как оно будет отображаться в шапке
|
width
|
фиксированная ширина столбца в пикселях
|
minWidth
|
минимальная ширина столбца в пикселях
|
flex
|
вес столбца в адаптивном интерфейсе (при построении диаграммы из общей ширины окна вычитается фиксированная ширина столбцов (width), а оставшееся место делится между остальными столбцами в соответствии с их весом — столбец с весом 2 будет вдвое шире, чем с весом 1)
|
locked
|
признак закрепленного столбца (1 или 0),
|
hidden
|
признак скрытого столбца (1 или 0). Отображение скрытых столбцов может быть включено пользователем с помощью контекстного меню
|
align
|
выравнивание текста в столбце (left, right или center)
|
|
format
|
строка с форматом для даты (например, "dd.MM.yy")
|
Пример тела ответа
{
"dataUrl": "/app/v1.2/api/publications/action/gantt-data",
"columns": [
{ "field": "realTaskId", "text":"Номер задачи", "width": 150 },
{ "type": "name", "field": "name", "text":"Задача", "width": 250 },
{ "field": "SubcatName", "text":"Категория", "width": 250 },
{ "field": "startDate", "text":"Дата начала", "width": 100, "hidden": 1 },
{ "field": "endDate", "text":"Дата окончания", "width": 100, "hidden": 1 }
]
}
|
2. Публикация, возвращающая данные
В нашем примере это публикация gnt-data.
Если у диаграммы Ганта есть корневая задача (например, проект, для которого отбираются подзадачи), тогда номер корневой задачи передается во входящем параметре taskId. Если корневой задачи нет, то входящий параметр не нужен.
Входящий параметр (если он есть) должен называться именно taskId (название регистрозависимое)
|
Тип запроса — GET.
Пакет содержит единственное действие HTTP ответ, которое возвращает результат в формате JSON. Тело ответа формируется с помощью смарт-выражения.
Структура тела ответа
Ключи
|
Описание
|
tasks
|
|
список записей. Обычно каждая запись содержит информацию о задаче. Также в списке могут содержаться группирующие записи, например, объединяющие задачи из одного раздела или категории (см. скриншоты выше)
|
rows
|
|
|
id
|
уникальный идентификатор
|
name
|
название задачи/категории
|
startDate
|
дата и время начала задачи
|
endDate
|
дата и время окончания задачи
|
urlToOpen
|
(необязательное поле) ссылка, которая будет открываться в модальном окне по клику на соответствующую полосу диаграммы Ганта. Например, строка вида '/maintaskform.aspx?taskid=ID_задачи'
|
...
|
Структура может также содержать любые дополнительные информационные поля, такие как Заказчик, Исполнители, Категория, Статус, Приоритет и пр.
|
children
|
массив записей, дочерних для данной записи, с тем же составом полей. У этих дочерних записей могут быть свои вложенные массивы children, и таким образом выстраивается иерархия задач
|
dependencies
|
|
массив зависимостей по срокам между задачами. Если зависимости не установлены, возвращается пустой массив
|
rows
|
|
Пример смарт-выражения, возвращающего данные
DECLARE @resTasks NVARCHAR(MAX);
DECLARE @headId INT;
SELECT @headId = CAST(JSON_VALUE(@eventParam0, '$.queryString.taskId') as int);
SET @resTasks = (
SELECT
DISTINCT t.Description AS name,
'subcat-' + CAST(t.SubcatId AS VARCHAR(20)) + '-task-' + CAST(t.TaskId AS VARCHAR(50)) AS id,
children.*
FROM Tasks t
OUTER APPLY (
SELECT
'subcat-' + CAST(t2.SubcatId AS VARCHAR(20)) + '-task-' + CAST(t2.TaskId AS VARCHAR(50)) AS id,
t2.TaskId AS realTaskId,
t2.Description AS name,
t2.CreatedTask AS startDate,
t2.OrderedTime AS endDate,
'/maintaskform.aspx?taskid=' + CAST(t2.TaskId AS VARCHAR(20)) AS url,
sc.Description AS subcatName
FROM Tasks t2
INNER JOIN Subcategories AS sc ON t2.SubcatID = sc.SubcatID
WHERE t2.ParentTaskId = t.TaskId
) children
WHERE t.TaskID = @headId
FOR JSON AUTO
)
DECLARE @res NVARCHAR(MAX) = '{"tasks": {"rows": ' + @resTasks + '}, "dependecies": {"rows":[]}}';
SELECT @res
|
Пример тела ответа
{
"tasks": {
"rows": [
{
"name": "Подготовка обучения",
"id": "subcat-2610-task-678783",
"children": [
{
"id": "subcat-2610-task-678784",
"realTaskId": 678784,
"name": "Подготовка аудитории",
"startDate": "2020-07-31T05:33:48.327",
"endDate": "2020-08-12T16:00:00",
"url": "/maintaskform.aspx?taskid=678784",
"subcatName": "Задачи и поручения"
},
{
"id": "subcat-2611-task-678785",
"realTaskId": 678785,
"name": "Оплата аренды",
"startDate": "2020-07-31T05:33:52.907",
"endDate": "2020-08-04T16:00:00",
"url": "/maintaskform.aspx?taskid=678785",
"subcatName": "Платежи"
}
]
}
]
},
"dependecies": {
"rows": []
}
}
|
Для формирования тела ответа можно использовать хранимую процедуру Timeline, которая поставляется вместе с платформой. Она отбирает все задачи, подчиненные по отношению к исходной (корневой) задаче, а также все задачи, где исходная выбрана в ДП Lookup.
Входящие параметры процедуры Timeline
Параметры
|
Описание
|
@XmlParam
|
|
структура данных в формате XML. Она содержит корневой элемент root с вложенными элементами:
|
TaskID
|
элемент содержит один атрибут:
|
|
include
|
строка с номером исходной (корневой) задачи
|
SortOrder
|
элемент содержит атрибуты:
|
|
rootCatID
|
ID категории, задачи из которой должны выводиться на диаграмме Ганта
|
SortOrder
|
порядковый номер для сортировки задач в итоговом списке (чем меньше порядковый номер, тем выше будут отображаться задачи из данной категории на диаграмме Ганта)
|
Options
|
элемент содержит атрибуты:
|
|
StripHtmlTags
|
1 если из текста задач надо удалять html теги, 0 если не надо
|
MakeJsonHumanReadable
|
1 если итоговый JSON надо преображать к более удобному для чтения виду, 0 если не надо
|
@OutFormat
|
формат, в котором возвращаются данные. Возможные значения: 'json', 'json2', 'resultset', 'print'
|
@IncludeDictionaries
|
определяет, необходимо ли вести отбор данных по справочным категориям (тип категории в общих настройках установлен как Справочник)
1 - вести отбор, 0 - не вести
|
Пример смарт-выражения с вызовом Timeline
DECLARE
@rootTaskID INT = JSON_VALUE(@eventParam0, '$.queryString.taskId'),
@procParams XML;
SET @procParams = N'<root>
<TaskID include="' + CAST(@rootTaskID AS VARCHAR(20)) + '"/>
<SortOrder rootCatID="11" SortOrder="1" />
<SortOrder rootCatID="22" SortOrder="2" />
<SortOrder rootCatID="33" SortOrder="3" />
<Options StripHtmlTags="0" MakeJsonHumanReadable="0"/>
</root>';
EXEC dbo.Timeline @XmlParam = @procParams, @OutFormat = 'json2', @IncludeDictionaries = 0
В параметре @eventParam0 передается JSON с входящим параметром публикации, т.е. с номером исходной задачи.
|
Полезные ссылки
Обращение к объектам из адресной строки браузера
Публикации