Настройка скриптового модуля приложения "Интерактивная доска" 1.0 — 1.2.4
Встроенное приложение "Интерактивная доска" версии ниже 2.4.0 может быть несовместимо с версией системы.
Рекомендуется обновить встроенное приложение на последнюю версию.
Описание настройки
Скриптовый модуль описывает логику формирования интерактивных досок в зависимости от места размещения контента со встроенным приложением (карточка сотрудника или карточка команды). Интерактивная доска представляет собой набор столбцов, на которых размещены плашки с описанием запросов.
Скриптовый модуль может использоваться с настройками по умолчанию.
Примеры возможных изменений:
- Изменить настройки и названия столбцов на интерактивной доске в разрезе статусов.
- Изменить названия столбцов на интерактивной доске в разрезе времени дедлайна.
- Изменить набор атрибутов на плашке запроса.
Изменить часть настроек скриптового модуля можно самостоятельно или по запросу в службу технической поддержки NAUMEN.
Место настройки в интерфейсе
Интерфейс администратора. Раздел "Настройка системы" → "Каталог скриптов и модулей" → "Каталог модулей".
Форма редактирования модуля, см. Редактирование модуля.
Выполнение настройки
Интерактивная доска запросы команды в разрезе статусов
Функция Agile формирует доску, на которой отображаются запросы команды с разделением запросов по статусам и предоставляется возможностью менять статусы непосредственно на доске, перетаскивая запросы между столбцами.
Возможные изменения:
- изменить название столбца, соответствующей статусу;
- использовать несколько статусов для отображения в одном столбце;
- добавить новые столбцы или скрыть существующие.
def Agile(subjectUuid, userUuid = null) {
generateBoard([
// формируем список в виде объектов системы
tasks: utils.find('serviceCall', ['responsibleTeam':subjectUuid, 'removed':false, 'state':op.not('closed')]),
// columns: определяем столбцы. В разрезе статусов можно использовать несколько статусов на колонку
columns: [
new KanboardColumn('Новые', 'registered'),
new KanboardColumn('В работе', 'inprogress'),
new KanboardColumn('Ожидание', 'waitClientAnswer'),
new KanboardColumn('Выполнена', 'resolved')
]
] as KanboardConfiguration, smrmTaskPropertiesExtractor) //Если не указан атрибут, то при перетаскивании меняется статус
}
Интерактивная доска запросы сотрудника в разрезе статусов
Функция AgileForEmployee формирует доску, на которой отображаются запросы в ответственности сотрудника с разделением запросов по статусам и предоставляется возможностью менять статусы непосредственно на доске, перетаскивая запросы между столбцами.
Возможные изменения:
- изменить название столбцами, соответствующей статусу;
- использовать несколько статусов для отображения в одном столбце;
- добавить новые столбцы или скрыть существующие.
def AgileForEmployee(subjectUuid, userUuid = null) {
generateBoard([
// формируем список в виде объектов системы, будут отображаться элементами на доске
tasks: utils.find('serviceCall', ['responsibleEmployee':subjectUuid, 'removed':false, 'state':op.not('closed')]),
// columns: определяем столбцы
columns: [
new KanboardColumn('Новые', 'registered'),
new KanboardColumn('В работе', 'inprogress'),
new KanboardColumn('Ожидание', 'waitClientAnswer'),
new KanboardColumn('Выполнена', 'resolved')
]
] as KanboardConfiguration, smrmTaskPropertiesExtractor) //Если не указан атрибут, то при перетаскивании меняется статус
}
Интерактивная доска запросы команды в разрезе ответственных
Функция ZagruzhennostSotrudnikov1 формирует доску, на которой отображаются запросы команды с разделением запросов по ответственным и предоставляется возможностью распределять задачи по участникам команды непосредственно на доске, перетаскивая запросы между столбцами.
На доске первой отображается столбца "Без ответственного", затем отдельные столбцы для каждого участника команды.
Возможные изменения:
- изменить название столбцы "Без ответственного".
def ZagruzhennostSotrudnikov1(subjectUuid, userUuid = null) {
generateBoard([
// это список задач в виде объектов системы (не только список UUID-ов!)
tasks: utils.find('serviceCall', ['responsibleTeam':subjectUuid, 'removed':false, 'state':op.not('closed')]),
// columns: определяем столбцы, в данном случае это участники команды. Т.к. доска теперь в разрезе атрибута, задаваемого руками, каждая колонка должна иметь ровно один статус, чтобы можно было перенести в нее объект
columns: [new KanboardColumn('Без ответственного', [null] as String[])] // первая колонка будет содержать запросы без ответственного сотрудника
+ utils.find('employee$employee', [teams:op.isNotNull()]) // находим всех сотрудников из текущей команды и для каждого создаем колонку
.grep { subjectUuid in it.teams*.UUID }
.collect { new KanboardColumn(it.title, it.UUID) }
] as KanboardConfiguration, smrmTaskPropertiesExtractorForEmployees, 'responsibleEmployee') //При перетаскивании меняем ответственного
// дополнительный аргумент указывает на код атрибута, который будет редактироваться при переносе задач из колонки в колонку
Интерактивная доска запросы команды в разрезе срока дедлайна
Функция TeamZadachiSRazbivkoiPoSrokam формирует доску, на которой отображаются запросы команды с разделением запросов по оставшемуся времени на решение.
Интерактивная доска разделена на столбцы: "Дедлайн не задан" (запросы, у которых не задано время решения), "Дедлайн наступил" (запросы, у которых уже наступил дедлайн), пять столбцов с ближайшими датами (отображаются запросы, у которых дедлайн наступит в ближайшие пять дней. Каждая дата в отдельном столбце), "Более 5 дней"(отображаются запросы, у которых дата дедлайна дальше 5 дней)
Возможные изменения:
- изменить название столбцов "Дедлайн не задан", "Дедлайн наступил" и "Более 5 дней".
def TeamZadachiSRazbivkoiPoSrokam(subjectUuid, userUuid = null) {
def now = new Date()
def e = smrmTaskPropertiesExtractorForDeadlines
def tasks = utils.find('serviceCall', ['responsibleTeam':subjectUuid, 'removed':false, 'state':op.not('closed')])
gson.toJson([
columns: [
[
title: 'Дедлайн не задан',
id: UUID.randomUUID(),
statuses: [null],
tasks: tasks.grep { it.deadLineTime == null }
.collect {task -> [
id: e.id(task),
title: e.title(task),
description: e.description(task),
deadline: e.deadline(task),
status: e.status(task),
assignee: [
title: e.assignee.title(task),
avatarUrl: e.assignee.avatarUrl(task)
] as KanboardAssignee,
category: [
title: e.category.title(task),
color: e.category.color(task),
iconUrl: e.category.iconUrl(task)
] as KanboardCategory
] as KanboardTask}
],
[
title: 'Дедлайн наступил!',
id: UUID.randomUUID(),
statuses: [],
tasks: tasks.grep { it.deadLineTime != null && compareDatesWithoutTimePart(it.deadLineTime, now) < 0 }
.collect {task -> [
id: e.id(task),
title: e.title(task),
description: e.description(task),
deadline: e.deadline(task),
status: e.status(task),
assignee: [
title: e.assignee.title(task),
avatarUrl: e.assignee.avatarUrl(task)
] as KanboardAssignee,
category: [
title: e.category.title(task),
color: e.category.color(task),
iconUrl: e.category.iconUrl(task)
] as KanboardCategory
] as KanboardTask}
]
] +
(0..4).collect { now + it }
.collect {
[
title: new java.text.SimpleDateFormat("dd.MM.yyyy").format(it),
id: UUID.randomUUID(),
statuses: [new java.text.SimpleDateFormat("yyyy.MM.dd").format(it)],
tasks: tasks.grep { task -> task.deadLineTime != null && compareDatesWithoutTimePart(task.deadLineTime, it) == 0 }
.collect {task -> [
id: e.id(task),
title: e.title(task),
description: e.description(task),
deadline: e.deadline(task),
status: e.status(task),
assignee: [
title: e.assignee.title(task),
avatarUrl: e.assignee.avatarUrl(task)
] as KanboardAssignee,
category: [
title: e.category.title(task),
color: e.category.color(task),
iconUrl: e.category.iconUrl(task)
] as KanboardCategory
] as KanboardTask}
]
} +
[
[
title: 'Более 5 дней',
id: UUID.randomUUID(),
statuses: [],
tasks: tasks.grep { it.deadLineTime != null && compareDatesWithoutTimePart(it.deadLineTime, now + 5) >= 0 }
.collect { task -> [
id: e.id(task),
title: e.title(task),
description: e.description(task),
deadline: e.deadline(task),
status: e.status(task),
assignee: [
title: e.assignee.title(task),
avatarUrl: e.assignee.avatarUrl(task)
] as KanboardAssignee,
category: [
title: e.category.title(task),
color: e.category.color(task),
iconUrl: e.category.iconUrl(task)
] as KanboardCategory
] as KanboardTask}
]
],
attributeCodeForEditing: 'deadLineTime'
] as Kanboard)
}
Интерактивная доска запросы сотрудника в разрезе срока дедлайна
Функция MoiZadachiSRazbivkoiPoSrokam формирует доску, на которой отображаются запросы команды с разделением запросов по оставшемуся времени на решение.
Интерактивная доска разделена на столбцы: "Дедлайн не задан" (запросы, у которых не задано время решения), "Дедлайн наступил" (запросы, у которых уже наступил дедлайн), пять столбцов с ближайшими датами (отображаются запросы, у которых дедлайн наступит в ближайшие пять дней. Каждая дата в отдельном столбце), "Более 5 дней"(отображаются запросы, у которых дата дедлайна дальше 5 дней).
Возможные изменения:
- изменить название столбцов "Дедлайн не задан", "Дедлайн наступил" и "Более 5 дней".
def MoiZadachiSRazbivkoiPoSrokam(subjectUuid, userUuid = null) {
def now = new Date()
def e = smrmTaskPropertiesExtractorForDeadlines
def tasks = utils.find('serviceCall', ['responsibleEmployee':subjectUuid, 'removed':false, 'state':op.not('closed')])
gson.toJson([
columns: [
[
title: 'Дедлайн не задан',
id: UUID.randomUUID(),
statuses: [null],
tasks: tasks.grep { it.deadLineTime == null }
.collect {task -> [
id: e.id(task),
title: e.title(task),
description: e.description(task),
deadline: e.deadline(task),
status: e.status(task),
assignee: [
title: e.assignee.title(task),
avatarUrl: e.assignee.avatarUrl(task)
] as KanboardAssignee,
category: [
title: e.category.title(task),
color: e.category.color(task),
iconUrl: e.category.iconUrl(task)
] as KanboardCategory
] as KanboardTask}
],
[
title: 'Дедлайн наступил!',
id: UUID.randomUUID(),
statuses: [],
tasks: tasks.grep { it.deadLineTime != null && compareDatesWithoutTimePart(it.deadLineTime, now) < 0 }
.collect {task -> [
id: e.id(task),
title: e.title(task),
description: e.description(task),
deadline: e.deadline(task),
status: e.status(task),
assignee: [
title: e.assignee.title(task),
avatarUrl: e.assignee.avatarUrl(task)
] as KanboardAssignee,
category: [
title: e.category.title(task),
color: e.category.color(task),
iconUrl: e.category.iconUrl(task)
] as KanboardCategory
] as KanboardTask}
]
] +
(0..4).collect { now + it }
.collect {
[
title: new java.text.SimpleDateFormat("dd.MM.yyyy").format(it),
id: UUID.randomUUID(),
statuses: [new java.text.SimpleDateFormat("yyyy.MM.dd").format(it)],
tasks: tasks.grep { task -> task.deadLineTime != null && compareDatesWithoutTimePart(task.deadLineTime, it) == 0 }
.collect {task -> [
id: e.id(task),
title: e.title(task),
description: e.description(task),
deadline: e.deadline(task),
status: e.status(task),
assignee: [
title: e.assignee.title(task),
avatarUrl: e.assignee.avatarUrl(task)
] as KanboardAssignee,
category: [
title: e.category.title(task),
color: e.category.color(task),
iconUrl: e.category.iconUrl(task)
] as KanboardCategory
] as KanboardTask}
]
} +
[
[
title: 'Более 5 дней',
id: UUID.randomUUID(),
statuses: [],
tasks: tasks.grep { it.deadLineTime != null && compareDatesWithoutTimePart(it.deadLineTime, now + 5) >= 0 }
.collect { task -> [
id: e.id(task),
title: e.title(task),
description: e.description(task),
deadline: e.deadline(task),
status: e.status(task),
assignee: [
title: e.assignee.title(task),
avatarUrl: e.assignee.avatarUrl(task)
] as KanboardAssignee,
category: [
title: e.category.title(task),
color: e.category.color(task),
iconUrl: e.category.iconUrl(task)
] as KanboardCategory
] as KanboardTask}
]
],
attributeCodeForEditing: 'deadLineTime'
] as Kanboard)
}
Параметры плашки запроса
За набор параметров объекта, отображаемого на плашке, отвечает функция generateBoard.
def generateBoard(KanboardConfiguration configuration, KanboardTaskPropertiesExtractor e, String attributeCodeForEditing = null) {
gson.toJson([
columns: configuration.columns.collect { column ->
def columnCopy = column.clone()
configuration.tasks
.grep { task -> e.status(task) in columnCopy.statuses }
.each { task ->
columnCopy << ([
id: e.id(task),
title: e.title(task),
description: e.description(task),
deadline: e.deadline(task),
status: e.status(task),
assignee: [
title: e.assignee.title(task),
avatarUrl: e.assignee.avatarUrl(task),
urlToCard: e.assignee.urlToCard(task)
] as KanboardAssignee,
category: [
title: e.category.title(task),
color: e.category.color(task),
iconUrl: e.category.iconUrl(task)
] as KanboardCategory
] as KanboardTask)
}
return columnCopy
},
attributeCodeForEditing: attributeCodeForEditing
] as Kanboard)
}
В KanboardTaskPropertiesExtractor задается соответствие между параметрами приложения и атрибутами объектов SMP. Число и тип атрибутов статичны и должны соответствовать классу KanboardTask, другие параметры добавить нельзя.
Определение параметров происходит следующим образом: id({t->t.UUID}), где
- id — код в приложении;
- t — объект из списка tasks;
- UUID — код атрибута объекта.
Возможные изменения:
- переопределить соответствие между параметрами приложения и атрибутами объектов SMP.
// Для уменьшения объема кода можно выносить общие части extractor в переменную. Далее просто переопределять нужные свойства
@Field def defaultSmrmTaskPropertiesExtractorBuilder = KanboardTaskPropertiesExtractor.builder()
.id({t->t?.UUID}) // Идентификатор объекта, тип String
.title({t->t?.shortDescr}) // Тема объекта, тип String
.description({t->api.string?.htmlToText(t?.descriptionRTF)}) // Описание объекта - тип String
.deadline({t->t?.deadLineTime}) // Регламентное время решения - тип Date
.status({t->t?.state}) // Статус объекта - в разрезе статусов это код статуса, в разрезе любых других атрибутов это строковое представление, которое будет передано в REST-запросе на редактирование при переносе объекта в колонку
.assigneeTitle({t->t?.responsible?.title}) // Имя ответственного - тип String
.assigneeAvatarUrl({t ->
t.responsible?.getMain()?.hasProperty('image') && !t?.responsible?.image?.isEmpty()
? generateFileDownloadUrl(t?.responsible?.image[0].UUID)
: '' // Аватарка ответственного - ссылка на файл изображения
})
.categoryTitle({t->t?.system_icon?.title}) // Название иконки - тип String
.categoryColor({t->t?.priority?.color?.string ?: ''}) // Цвет бокоовой плашки элемента - тип String
.categoryIconUrl({t->generateFileDownloadUrl(t?.system_icon ? t?.system_icon?.icon[0]?.UUID : null)}) // Иконка - ссылка на файл изображения
@Field KanboardTaskPropertiesExtractor smrmTaskPropertiesExtractor = defaultSmrmTaskPropertiesExtractorBuilder.build()