Перейти к содержанию

Модули

Начинать написание скрипта необходимо с объявления локальной переменной, которой присваивается вызов модуля.

local varName = require ("moduleName")

Чтение и запись

Для чтения и записи значений тегов в скрипте необходимо вызвать модуль, соответствующий типу выполняемой функции.

local tagApi = require("simplight.api.channels")            -- вызов модуля асинхронных функций чтения/записи 
local async = require("async")                              -- вызов модуля асинхронного выполнения функций
local tagApiSync = require("simplight.api.channels.sync")   -- вызов модуля синхронных функций чтения/записи (вызывать модуль async не требуется)

read

read(tagName: string): Channel

Принимает имя тега в виде строки и возвращает объект типа Channel, содержащий все основные данные о теге.

Объект Channel содержит следующие основные поля:

Поле Тип данных Описание
id
int64
Уникальный идентификатор тега в системе
name
string
Имя тега
value
any
Текущее значение тега (может быть числом, булевым значением, строкой и т.д.)
quality
uint16
Код качества данных, указывающий на достоверность значения
highScale
float
Максимальное значение диапазона шкалы тега
lowScale
float
Минимальное значение диапазона шкалы тега
loLoAlarm
float
Нижнее пороговое значение аварийного события
loAlarm
float
Нижнее пороговое значение предупредительного события
hiAlarm
float
Верхнее пороговое значение предупредительного события
hiHiAlarm
float
Верхнее пороговое значение аварийного события
alarmStatus
enum AlarmStatus
Текущий статус аварии для данного тега

Пример:
Прочитать нижнее пороговое значение предупредительного события и текущее значение тега temp 1.

local async = require("async")
local tagApi = require("simplight.api.channels")

async(function()
  local tag = await(tagApi.read("temp 1"))
  print("{ loAlarm: "..tag.loAlarm..", value: "..tag.value.." }")
end)
local tagApi = require("simplight.api.channels.sync")

local tag = tagApi.read("temp 1")
print("{ loAlarm: "..tag.loAlarm..", value: "..tag.value.." }")

readValue

readValue(tagName: string): any

Возвращает текущее значение тега по его имени. Это упрощенная версия функции read, которая возвращает только значение, без других атрибутов тега.

Возвращаемое значение:

Поле Тип данных Описание
value
any
Текущее значение тега (может быть числом, булевым значением, строкой и т.д.)

Пример:
Прочитать значение тега temp 2.

local async = require("async")
local tagApi = require("simplight.api.channels")

async(function()
  local tag = await(tagApi.readValue("temp 2"))
  print(tag)
end)
local tagApi = require("simplight.api.channels.sync")

local tag = tagApi.readValue("temp 2")
print(tag)

readMany

readMany(tagNames: string[]): Channel

Позволяет за один запрос получить данные (значение, качество, атрибуты тревог и т.д.) для списка тегов. Принимает массив имен тегов и возвращает объект типа Channel, содержащий все основные данные о теге.

Объект Channel содержит следующие основные поля:

Поле Тип данных Описание
id
int64
Уникальный идентификатор тега в системе
name
string
Имя тега
value
any
Текущее значение тега (может быть числом, булевым значением, строкой и т.д.)
quality
uint16
Код качества данных, указывающий на достоверность значения
highScale
float
Максимальное значение диапазона шкалы тега
lowScale
float
Минимальное значение диапазона шкалы тега
loLoAlarm
float
Нижнее пороговое значение аварийного события
loAlarm
float
Нижнее пороговое значение предупредительного события
hiAlarm
float
Верхнее пороговое значение предупредительного события
hiHiAlarm
float
Верхнее пороговое значение аварийного события
alarmStatus
enum AlarmStatus
Текущий статус аварии для данного тега

Пример:
Прочитать значения тегов temp 1, temp 2, temp 3, temp 4.

local async = require("async")
local tagApi = require("simplight.api.channels")

async(function()
    local tags = await(tagApi.readMany({"temp 1", "temp 2", "temp 3", "temp 4"}))
    for k, tag in ipairs(tags) do
        print("{Тег: " ..tag.name.." = " ..tag.value.." }")
    end
end)
local tagApi = require("simplight.api.channels.sync")

local tags = tagApi.readMany({"temp 1", "temp 2", "temp 3", "temp 4"})
for k, tag in ipairs(tags) do
    print("{Тег: " ..tag.name.." = " ..tag.value.." }")
end

write

write(tagName: string, value: any, quality: uint16)

Записывает данные в тег на сервере. Функция принимает имя целевого тега, значение и признак качества, которые необходимо записать.

Запись качества в физический тег можно опустить.

Поле Тип данных Описание
name
string
Имя тега
value
any
Текущее значение тега (может быть числом, булевым значением, строкой и т.д.)
quality
uint16
Код качества данных, указывающий на достоверность значения

Пример:
Записать значение (177) и признака качества (0xC0 — хорошее качество) в тег temp 3.

local async = require("async")
local tagApi = require("simplight.api.channels")

async(function()
    await(tagApi.write("temp 3", 177, 0xC0))
end)
local tagApi = require("simplight.api.channels.sync")

tagApi.write("temp 3", 177, 0xC0)

writeMany

writeMany(req: WriteChannelRequest)

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

В функцию передается аргумент в виде таблицы values со значениями нескольких тегов.

Поле Тип данных Описание
name
string
Имя тега
value
any
Текущее значение тега (может быть числом, булевым значением, строкой и т.д.)
quality
uint16
Код качества данных, указывающий на достоверность значения

Пример:
Записать значение и признака качества (0xC0 — хорошее качество) в теги temp 1, temp 2, temp 3, temp 4.

local async = require("async")
local tagApi = require("simplight.api.channels")

async(function()
    await(tagApi.writeMany({
      values={
        { name="temp 1", value=101, quality = 0xC0  },
        { name="temp 2", value=202, quality = 0xC0  },
        { name="temp 3", value=303, quality = 0xC0  },
        { name="temp 4", value=404, quality = 0xC0  },
      }
    }))
end)
local tagApi = require("simplight.api.channels.sync")

tagApi.writeMany({
  values={
    { name="temp 1", value=102, quality = 0xC0  },
    { name="temp 2", value=203, quality = 0xC0  },
    { name="temp 3", value=304, quality = 0xC0  },
    { name="temp 4", value=405, quality = 0xC0  },
  }})

Временные метки

Модуль time предоставляет функции для работы с временными значениями. Система использует Unix timestamp (временная метка) в миллисекундах, отсчитываемый от начала эпохи Unix (1 января 1970 года, 00:00:00 UTC). Все временные метки относятся к часовому поясу UTC (всемирное координированное время). Для работы с временными метками в скрипте, необходимо соответствующим образом оформить вызов:

local time = require("time")      -- вызов модуля работы с временными метками Unix timestamp

from

from(tp: TimeParts): number

Конвертирует детализированное представление даты и времени в единую числовую временную метку в формате UTC. Возвращает число в виде Unix timestamp.

В качестве аргумента принимает таблицу TimeParts со следующими обязательными полями:

Поле Тип данных Описание
year
number
Год (четыре цифры)
month
number
Месяц (1-12)
day
number
День месяца (1-31)
hour
number
Час (0-23)
min
number
Минуты (0-59)
sec
number
Секунды(0-59)
msec
number
Миллисекунды(0-999)

Пример:
Вернуть временную метку для даты 13.02.1981 и времени 04:30:45.500.

local time = require("time")

local timestamp = time.from({
    year = 1981,
    month  = 02,
    day    = 13,
    hour   = 04,
    min    = 30,
    sec    = 45,
    msec   = 500
})
print("timestamp is:", timestamp)

now

now(): number

Возвращает временную метку, сформированную по текущим значениям времени системы в виде Unix timestamp.

Пример:
Вернуть текущую временную метку сервера.

local time = require("time")

local now = time.now()
print("current timestamp is:", now)

toString

toString(timestamp: number): string

Преобразует временную метку в удобочитаемую строку с датой и временем.

Пример:
Вернуть текущую дату и время сервера в виде строки.

local time = require("time")

local nowStamp = time.now()
local nowString = time.toString(nowStamp)
print("current time is:", nowString)

toTable

toTable(timestamp: number): TimeParts

Выполняет обратное преобразование, разбирая единую временную метку на отдельные компоненты (год, месяц, день и т.д.).

Пример:
Вернуть значение текущего месяца и года сервера.

local time = require("time")

local nowStamp = time.now()
local nowTable = time.toTable(nowStamp)
print("current month and year:",nowTable.month, nowTable.year)

Архивные данные

Для работы с значениями тегов в базе данных необходимо вызвать соответствующий модуль:

local momentApi = require("moments")          -- вызов модуля для работы с значениями тегов в базе данных

getRange

getRange(options: GetOptions): []Moment

Получает архивные данные тега за указанный временной интервал.

В качестве аргумента передается таблица GetOptions:

Поле Тип данных Описание
channelName
string
Имя тега, для которого запрашивается история
start
timestamp
Начальная временная метка
ending
timestamp
Конечная временная метка

Возвращаемое значение — массив Moment:

Поле Тип данных Описание
t
timestamp
Временная метка записи
q
quality
Качество значения в момент записи
v
any
Значение тега в момент записи

Пример:
Необходимо выполнить анализ значений и признака качества тега "Напряжение" из базы данных за последние две минуты.

local momentApi = require("moments")
local async = require("async")
local time = require("time")


async(function()
    local ending = time.now()               
    local start = ending - 2 * 60 * 1000    

    local ms =  await(momentApi.getRange({
      channelName = "Напряжение",
      start = start,
      ending = ending,
    }))

    for _, m in ipairs(ms) do
      print(("{t: %d, v: %s, q: %d}"):format(m.t, m.v, m.q))
    end
end)

getMin

getMin(options: GetOptions): number|nil

Вычисляет минимальное значение тега за указанный временной интервал на основе архивных данных. Если в указанном интервале нет архивных записей, функция возвращает nil.

В качестве аргумента передается таблица GetOptions:

Поле Тип данных Описание
channelName
string
Имя тега, для которого запрашивается история
start
timestamp
Начальная временная метка
ending
timestamp
Конечная временная метка

getMax

getMax(options: GetOptions): number|nil

Вычисляет максимальное значение тега за указанный временной интервал на основе архивных данных. Если в указанном интервале нет архивных записей, функция возвращает nil.

В качестве аргумента передается таблица GetOptions:

Поле Тип данных Описание
channelName
string
Имя тега, для которого запрашивается история
start
timestamp
Начальная временная метка
ending
timestamp
Конечная временная метка

getAverage

getAverage(options: GetOptions): number|nil

Вычисляет среднее арифметическое значение тега за указанный временной интервал на основе архивных данных. Если в указанном интервале нет архивных записей, функция возвращает nil.

В качестве аргумента передается таблица GetOptions:

Поле Тип данных Описание
channelName
string
Имя тега, для которого запрашивается история
start
timestamp
Начальная временная метка
ending
timestamp
Конечная временная метка

save

save(ms: []TagMoment)

Сохраняет массив значений тегов в базу данных с текущей временной меткой.

В качестве аргумента передается массив TagMoment:

Поле Тип данных Описание
tagName
string
Имя тега, для которого сохраняется значение
value
any
Значение для сохранения в архив (может быть числом, строкой, булевым значением)

Пример:
Сохранить значения тегов в базе данных с указанием одинаковой метки времени. Этот подход может быть использован для формирования отчета на основе временной метки.

local async = require("async")
local momentApi = require("moments")
local tagApi = require("simplight.api.channels")
local events = require("simp-events")

local function doAction()
  return async(function()
    local currentTag = await(tagApi.read("Ток"))
    local voltageTag = await(tagApi.read("Напряжение"))
    local powerTag = await(tagApi.read("Мощность"))

    await(momentApi.save({
      {
        tagName = "Ток",
        value = currentTag.value,
      },
      {
        tagName = "Напряжение",
        value = voltageTag.value,
      },
      {
        tagName = "Мощность",
        value = powerTag.value,
      }
    }))
  end):catch(function(err)
    print("doAction: ", err)
  end)
end

events.on("channelWrite", function(event)
  for _, w in ipairs(event.writes) do
    if w.name == "Действия.СделатьЗапись" then
      doAction()
    end
  end
end)

Битовые операции

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

local bitop = require("bitop")
Функция Описание
band(x: number; y: number): number Побитовое И над числами x и y
bor(x: number; y: number): number Побитовое ИЛИ над числами x и y
bxor(x: number; y: number): number Побитовое исключающее ИЛИ над числами x и y
bnot(x: number): number Побитовое НЕ над числом x
lshift(x: number; n: number): number Побитовое смещение влево числа x на n бит
rshift(x: number; n: number): number Побитовое логическое смещение вправо числа x на n бит
arshift(x: number; n: number): number Побитовое арифметическое смещение вправо числа x на n бит
getBit(x: number; bit: number): number Возвращает 0 либо 1 в зависимости установлен ли бит bit в числе x*
setOnBit(x: number; bit: number): number Возвращает число с установленным битом bit полученным от числа x*
setOffBit(x: number; bit: number): number Возвращает число со снятым битом bit полученным от числа x*

*Нумерация битов осуществляется справа налево, начиная с 1

Пример:
Выполнить операцию побитового И числел x и y.

local bitop = require("bitop")

local x = 5
local y = 6
local bitAnd = bitop.band(x, y)      
print(bitAnd)                            

Файловая система

Для работы с файловой системой на сервере необходимо вызвать модуль:

local fs = require("fs")

appendFile

appendFile(filename: string; content: string)

Функция предназначена для последовательной записи данных в файл. Она открывает указанный файл и добавляет переданный контент в его конец, не изменяя уже существующее содержимое. В случае отсутствия файла по указанному пути, он будет создан автоматически.

Пример:
Создать каталог fsData, разместить в нем файл file.txt и в файл добавить строку "init message".

local fs = require("fs")

local basePath = "C:/SimpLight projects/fsData/file.txt"

fs.appendFile(basePath, "test message")

readFile

readFile(filename: string, options: table)

Получает доступ к содержимому файла, расположенного по указанному пути.

Пример:
Вычитать из файла file.txt его содержимое.

local async = require("async")
local fs = require("fs")

local basePath = "C:/SimpLight projects/fsData/file.txt"

async(function()
    local content = await(fs.readFile(basePath))
    print(content)
end)

writeFile

writeFile(filename: string, content: string)

Перезаписывает содержимое файла, расположенного по указанному пути.

Пример:
Полностью перезаписать содержимое файла file.txt.

local fs = require("fs")

local basePath = "C:/SimpLight projects/fsData/file.txt"

fs.writeFile(basePath, "new message")

mkdir

mkdir(path: string, options: MkdirOptions)

Создаёт каталог по пути path. В качестве аргумента принимает путь каталога и таблицу MkdirOptions:

Поле Тип данных Описание
recursive
bool
Необходимо установить в true для создания вложенных каталогов
local async = require("async")
local fs = require("fs")

local basePath = "C:/SimpLight projects/fsData"

async(function()
    await(fs.mkdir(basePath .. "/new_folder/new_subfolder", { recursive = true }))
end)

copyFile

copyFile(srcFilename, newFileName: string; failIfExists: bool)

Копирует указанный файл в новое местоположение. Флаг failIfExists позволяет прервать операцию, если файл уже существует.

Возвращаемое значение:

  • true — файл успешно создан и скопирован.
  • false — файл с указанным именем уже существует.
local async = require("async")
local fs = require("fs")

local basePath = "C:/SimpLight projects/fsData"

async(function()
    await(fs.copyFile(basePath .. "/file.txt", basePath .. "/new_folder/2.txt", true))
end)

existsFile

existsFile(path: string)

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

Возвращаемое значение:

  • true — файл существует.
  • false — файл не существует.

Пример:
Проверить наличие файла file.txt по указанному пути.

local async = require("async")
local fs = require("fs")

async(function()
    local file_exist = await(fs.existsFile("C:/SimpLight projects/fsData/file.txt" ))
    print(file_exist)
end)

existsDir

existsDir(path: string)

Определяет наличие каталога по указанному пути.

Возвращаемое значение:

  • true — каталог существует.
  • false — каталог не существует.

Пример:
Проверить наличие каталога fsData по указанному пути.

local async = require("async")
local fs = require("fs")

async(function()
    local dir_exist = await(fs.existsDir("C:/SimpLight projects/fsData" ))
    print(dir_exist)
end)

Пути

Для работы с путями в файловой системе на сервере необходимо вызвать модуль:

local path = require("path")

dirname

dirname(path: string): string

Возвращает имя каталога по указанному пути.

local path = require("path")
local async = require("async")

async(function()
    local dir = await(path.dirname("C:/SimpLight projects/fsData/"))
print("Имя каталога: ", dir)
end)

basename

basename(path: string; suffix: string): string

Возвращает последнюю часть указанного пути. Если указать suffix, то он будет удален с конца строки.

local async = require("async")
local path = require("path")

local basePath = "C:/SimpLight projects/fsData"

async(function()
    local last_path = await(path.basename(basePath, "ta")) -- исключение суффикса "ta" из строки пути
print("Последняя часть пути: ", last_path)             --> fsDa
end)

extname

extname(path: string): string

Возвращает расширение файла по указанному пути.

local path = require("path")
local async = require("async")

async(function()
    local ext = await(path.extname("C:/SimpLight projects/fsData/file.txt"))
print("Расширение файла: ", ext)
end)

join

join(paths: []string): string

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

local path = require("path")
local async = require("async")

local basePath = "C:/SimpLight projects/fsData"

async(function()
    local conc_path = await(path.join({basePath, "file.txt"}))
    print(conc_path)
end)

События

Модуль для обработки системных событий в реальном времени. Для работы с событиями в скрипте, необходимо сделать вызов модуля:

local events = require("simp-events")

channelChanges

changes: ChannelChange[]

Получает уведомления об изменениях значений всех тегов в системе.

Поля ChannelChange:

Поле Тип данных Описание
channelID
int64
Идентификатор тега
name
string
Имя тега
quality
uint16
Код качества данных, указывающий на достоверность значения
value
any
Новое значение тега
alarmStatus
enum alarmStatus
Текущий статус аварии для данного тега

Пример:
Необходимо производить расчет потребляемой мощности при каждом изменении значений тегов Ток и Напряжение.

local events = require("simp-events")                       -- вызов модуля для работы с событиями
local tagApi = require("simplight.api.channels")            -- вызов модуля асинхронных функций чтения/записи 
local async = require("async")                              -- вызов модуля асинхронного выполнения функций

local function doVoltageAmperageChange()                    -- объявление функции вычисления мощности
  async(function()    
    local voltageTag = await(tagApi.read("Напряжение"))     -- извлечение значения тега "Напряжение"
    local amperageTag = await(tagApi.read("Ток"))           -- извлечение значения тега "Ток"

    local power = voltageTag.value * amperageTag.value      -- рассчет значения тега "Мощность"
    await(tagApi.write("Мощность", power, 0xC0))            -- запись рассчитанного значения в тег
  end):catch(function(err)                                  -- обработка возможных ошибок
    print("ошибка", err)
  end)
end

events.on("channelChanges", function(event)                 -- подпишемся на событие channelChanges
  for _, c in ipairs(event.changes) do
    if c.name == "Напряжение" or c.name == "Ток" then       -- если произошли изменения значений в тегах "Напряжение" или "Ток"
      doVoltageAmperageChange()                             -- вызываем функцию вычисления мощности
    end
  end
end)

channelWrite

ChannelWriteEvent

Получает уведомления о записях значений во все теги системы.

Структура события:

  • caller: EventCaller — информация об инициаторе записи.
  • writes: WriteValue[ ] — массив записываемых значений.

Поля EventCaller:

Поле Тип данных Описание
connID
string
Идентификатор соединения
userName
string
Имя пользователя

Поля WriteValue:

Поле Тип данных Описание
channelID
int64
Уникальный идентификатор тега
name
string
Имя тега
quality
uint16
Качество для записи
value
any
Значение для записи

Пример:
Необходимо установить новые значения мощности для насосов Pump1 и Pump2 в случае записи в тег Действия.ОбновитьПеременные.

local events = require("simp-events")                     -- вызов модуля для работы с событиями
local tagApi = require("simplight.api.channels")          -- вызов модуля асинхронных функций чтения/записи 
local async = require("async")                            -- вызов модуля асинхронного выполнения функций

local function doActionUpdateVarsWrite()                  -- объявление функции обновления значений тегов "Pump1.FeedPower" и "Pump2.FeedPower"
  async(function()
    await(tagApi.write("Pump1.FeedPower", 100, 0xC0))     -- запись значения 100 и признака качества в тег "Pump1.FeedPower"
    await(tagApi.write("Pump2.FeedPower", 75, 0xC0))      -- запись значения 75 и признака качества в тег "Pump2.FeedPower"
  end)
end

events.on("channelWrite", function(event)                 -- подпишемся на событие channelWrite, чтобы отслеживать запись в теги
  for _, write in ipairs(event.writes) do
    if write.name == "Действия.ОбновитьПеременные" then   -- если произошла запись значения в тег "Действия.ОбновитьПеременные"
      doActionUpdateVarsWrite()                           -- вызываем функцию обновления значений тегов 
    end
  end
end)

Глобальные переменные

Предоставляет постоянное хранилище типа "ключ-значение" на локальном диске (HDD/SSD) для скриптов. Объект localStorage позволяет сохранять строковые данные между запусками скриптов и перезагрузками системы. Использование объекта не требует вызова модуля.

setItem

setItem(key: string, value: string)

Метод сохраняет строковое значение по указанному ключу.

localStorage:setItem("supplyWaterTemp", "label")  

getItem

getItem(key: string): (string | nil)

Метод получает значение по указанному ключу.

local x = localStorage:getItem("supplyWaterTemp")
print(x)  --> напечатает label

removeItem

removeItem(key: string)

Метод удаляет пару "ключ-значение" по указанному ключу.

localStorage:removeItem("supplyWaterTemp")
print(x)  --> напечатает nil

clear

clear()

Метод clear() полностью очищает хранилище, удаляя все сохраненные пары "ключ-значение".

localStorage:clear()

getNumberDef

getNumberDef(key: string, default: number): number

Возвращает числовое значение по указанному ключу key. Если значение отсутствует, то по умолчанию возвращается значение default.

local v = localStorage:getNumberDef("Valve", 0)
v = v + 10

Отчеты

reports

buildReport(options: ReportBuildOptions)

В качестве аргумента в функцию передается структура параметров:

ReportBuildOptions
  • templatePath: string — путь к файлу шаблона отчета в системе.
  • variables: ReportBuildVariables — пользовательские переменные для подстановки в шаблон.
  • dataSources: ReportBuildDataSources — настройки источников данных отчета.
  • actions: ReportBuildActions — действия после формирования отчета.

Таблица пользовательских переменных (ключ-значение).

{[name: string]: any}

  • Ключ — имя переменной (строка).
  • Значение — любое значение (строка, число, дата и т.д.).

Настройки источников данных отчета.

{[dataSourceName: string]: ChangeDataSourceParams | PeriodDataSourceParams}

  • Ключ — имя источника данных в шаблоне (строка).
  • Значение — параметры для источника данных одного из двух типов.

ChangeDataSourceParams:

Параметры для источников данных, основанных на изменениях.

  • start: time — начало временного диапазона (опционально).
  • end: time — конец временного диапазона (опционально).

PeriodDataSourceParams:

Параметры для источников данных с периодической выборкой.

  • start: time — начало временного диапазона (опционально).
  • end: time — конец временного диапазона (опционально).
  • interval: time — интервал между выборками в миллисекундах (опционально).

Действия, выполняемые после успешного формирования отчета.

  • print: PrintActionOptions — параметры для печати отчета (опционально).
  • save: SaveActionOptions — параметры для сохранения отчета в файл (опционально).
  • show: ShowActionOptions — параметры для показа отчета пользователям (опционально).

PrintActionOptions:

  • enabled: boolean — включить ли печать отчета.
  • targetUsers: []string — массив имен пользователей, которым доступна печать.

SaveActionOptions:

  • filepath: string — путь для сохранения файла отчета.

ShowActionOptions:

  • enabled: boolean — включить ли показ отчета.
  • targetUsers: []string — массив имен пользователей, которым будет показан отчет.

Пример: