Добро пожаловать, Гость
Вам необходимо зарегистрироваться перед тем, как пытататься написать сообщение.

Имя пользователя
  

Пароль
  





Поиск по сообществам

(Расширенный поиск)

Статистика сообществ
» Участники: 119
» Последний участник: Michaelbum
» Темы сообществ: 42
» Сообщения сообществ: 68

Полная статистика

Пользователи в сети
Сейчас 2 пользователей в сети.
» 0 Участник(-ов) | 2 Гость(-ей)

Последние темы
Щось легке та змістовне у...
Сообщество: Динамические приложения в WINNUM Platform
Последнее сообщение: StacyBoape
Вчера, 09:39 AM
» Ответы: 0
» Просмотры: 2
Каталог перевірених украї...
Сообщество: Динамические приложения в WINNUM Platform
Последнее сообщение: Michgat
05-02-2026, 06:57 PM
» Ответы: 0
» Просмотры: 10
Добавление тега в 3D
Сообщество: Динамические приложения в WINNUM Platform
Последнее сообщение: Lamantur
04-30-2026, 09:51 AM
» Ответы: 0
» Просмотры: 7
Получение параметров из а...
Сообщество: Динамические приложения в WINNUM Platform
Последнее сообщение: Lamantur
04-21-2026, 11:53 AM
» Ответы: 0
» Просмотры: 28
Как получить документацию...
Сообщество: Динамические приложения в WINNUM Platform
Последнее сообщение: Lamantur
09-24-2025, 09:28 AM
» Ответы: 1
» Просмотры: 440
Панель с кнопками для 3D ...
Сообщество: Динамические приложения в WINNUM Platform
Последнее сообщение: nponyatov
09-19-2025, 09:32 AM
» Ответы: 0
» Просмотры: 503
Панель с кнопками для 3D ...
Сообщество: Динамические приложения в WINNUM Platform
Последнее сообщение: nponyatov
09-19-2025, 08:31 AM
» Ответы: 0
» Просмотры: 461
Добавление библиотеки в п...
Сообщество: Динамические приложения в WINNUM Platform
Последнее сообщение: Lamantur
08-22-2025, 07:18 AM
» Ответы: 0
» Просмотры: 393
WinnumAjaxAuthHandler - П...
Сообщество: Динамические приложения в WINNUM Platform
Последнее сообщение: Lamantur
05-27-2025, 09:15 AM
» Ответы: 0
» Просмотры: 506
Эффективность работы опер...
Сообщество: Динамические приложения в WINNUM Platform
Последнее сообщение: Сергей Борисов
04-28-2025, 01:18 PM
» Ответы: 1
» Просмотры: 569

 
Information Убрать все всплывающие подсказки
Автор: Lamantur - 03-18-2025, 08:42 AM - Сообщество: Динамические приложения в WINNUM Platform - Нет ответов

Всем хорошего дня!

У меня тут всего одна строчка, но может быть очень полезна, чтобы не искать по просторам интернета:


Код:
document.querySelectorAll('[title]').forEach(element => element.removeAttribute('title'));


Если вы хотите, чтобы все подсказки исчезли на всей странице, то удалите их сразу после загрузки страницы. Так вы сразу избавитесь от всплывающих надписей, таких как "Контейнер(Пустой)" и т.д.

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

   

По этой же причине они появятся снова после перезапуска, если их стереть из поля ввода атрибута.

А уже при запуске приложения их можно удалить все одной командой, например так:

Код:
function loadResoursesProcessor(){
    document.querySelectorAll('[title]').forEach(element => element.removeAttribute('title'));
// Остальной код
}

Распечатать этот элемент

Photo График работы оборудования
Автор: Lamantur - 02-20-2025, 01:05 PM - Сообщество: Динамические приложения в WINNUM Platform - Нет ответов

Добрый день, уважаемые коллеги!
Сегодня мы будем делать график загрузки оборудования полностью своими руками:
   

К этому графику можно добавить временную шкалу и сделать его полноценным отчетом.

У данного метода есть как преимущества, так и недостатки.
Главное преимущество - это точность расположения элементов. Кроме того самостоятельное рисование  позволяет создать абсолютно любой график с любыми временными промежутками и отрезками, варьировать размеры и цвета, а так же дает понимание того как этот график строится.

Недостаток в том, что все погрешности измерений, если они предусмотрены - видны на таком графике, т.к. он привязывается ко временным отрезкам, а не относительным величинам, можно увидеть небольшие изменения тегов, в 1 пиксель, из-за чего будут сливаться цвета.
В этой функции мы используем  " getPriorityTagDuration " для получения всех временных отрезков тегов исходя из их приоритетности. 
В результате мы получаем временные коды в миллисекундах, что дает возможность пересчитать местоположение и ширину закрашенной области. Для подсказки при наведении используем <title> в svg. Кроме того график можно обрезать и растягивать, если нужно разбить его на несколько смен, или сделать подробный график - как в стандартном приложении, для этого не нужно вызывать функцию для каждого часа. она не даст более точный результат, промежутка может быть не видно на графике, только потому, что он меньше пикселя шириной.
Ниже код функции и пример ее вызова:
appid - id приложения, можно увидеть в адресной строке
id - id html элемента, куда вставлять график
from - время от - указывается в закодированном виде, можно использовать baseSdkUtils.encode("20.02.2025 00:00:00");
to - baseSdkUtils.encode("20.02.2025 23:00:00");
product - id продукта, т.е. станка - oid - в карточке станка в адресной строке - "WNProduct"

Код:
/********************************* Процесс рисования графика **************************************/
// createBarCart( 'winnum.org.app.WNApplicationInstance:10', 'E8857FA3-F16B-423A-B043-2A353BDFE480', '19.02.2025%2019%3A30%3A00', '20.02.2025%2007%3A30%3A00', 'winnum.org.product.WNProduct:80' );

function createBarCart(appid, id, from, to, product){
var fromYMDformat = from.split("%")[0].split(".")[2] + "-" + from.split("%")[0].split(".")[1] + "-" + from.split("%")[0].split(".")[0];
var toYDMformat = to.split("%")[0].split(".")[2] + "-" + to.split("%")[0].split(".")[1] + "-" + to.split("%")[0].split(".")[0];
let yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
var dd = yesterday.getDate();
var mm = yesterday.getMonth() + 1;
var yyyy = yesterday.getFullYear();
if(dd<10){ dd = "0" + dd;}
if(mm<10){ mm = "0" + mm;}
var thisday = dd+"."+mm+"."+yyyy;

var today = new Date();
var td=today.getDate();
var tm = today.getMonth() + 1;
var ty = today.getFullYear();
var todaydmy = ty+"-"+tm+"-"+td;
var realtoday = td+"."+tm+"."+ty;
var yesterdaydmy = thisday.split('.')[2] + "-" + thisday.split('.')[1] + "-" + thisday.split('.')[0];

var startOfDayY = new Date(baseSdkUtils.decode(from).split(".")[2].split(" ")[0], baseSdkUtils.decode(from).split(".")[1] - 1, baseSdkUtils.decode(from).split(".")[0], baseSdkUtils.decode(from).split(" ")[1].split(":")[0], baseSdkUtils.decode(from).split(" ")[1].split(":")[1], baseSdkUtils.decode(from).split(" ")[1].split(":")[2]);
var startOfDayMs = Number(startOfDayY.getTime());

var endtOfDayY = new Date(baseSdkUtils.decode(to));
var endOfDayMs = endtOfDayY.getTime();
var arrayForDraw = [];
var tagColorSet = {};

baseSdkUtils.service.WNApplicationHelper.getTag(appid,function(data){
    for (var i = 0; i < data.getElementsByTagName('item').length; i++){
       var item = data.getElementsByTagName('item')[i];
       var tagDescription = baseSdkUtils.decode(item.getAttribute('tagName'));
       var tagColor = baseSdkUtils.decode(item.getAttribute('tagColor'));
       tagColorSet[tagDescription] = tagColor;
    }

    baseSdkUtils.service.WNApplicationTagHelper.getPriorityTagDuration(appid, product, fromYMDformat, toYDMformat, function(data){
        if ( baseSdkUtils.isSuccess(data) ){
            var str = '<svg viewBox="0 0 100 2">';
            for (var i = 0; i < data.getElementsByTagName('item').length; i++){
                var item = data.getElementsByTagName('item')[i];
                var timems = item.getAttribute('timeData');
                var tagName = baseSdkUtils.decode(item.getAttribute('TAG'));
                var startTime = baseSdkUtils.decode(item.getAttribute('START'));
                var endTime = baseSdkUtils.decode(item.getAttribute('END'));
                var now = new Date();
                var nowMs = now.getTime();
                            var x1 = (Number(timems.split(',')[0]) - startOfDayMs)/864000;
                            if(x1 < 0) x1 = 0;
                           
                            var x2 = (Number(timems.split(',')[1]) - startOfDayMs)/864000;
                            if( Number( timems.split(',')[1] ) >=  nowMs){
                                x2 = (nowMs - startOfDayMs)/864000;
                               
                            }
                            var start = baseSdkUtils.decode(item.getAttribute('START'));
                            var end = baseSdkUtils.decode(item.getAttribute('END'));
                            var serial = baseSdkUtils.decode(item.getAttribute('SERIAL_NUMBER'));
                            var duration = baseSdkUtils.decode(item.getAttribute('DURATION'));
                           
                            var colorTag = '#FFFFFF';
                           
                            for(var key in tagColorSet){
                               
                                if(tagName == key){
                               
                                    colorTag = tagColorSet[key];
                                }
                               
                            }
                           
                           if(x2 >= 0){
                                        str = str + '<polyline points="'+ x1 +',100 '+ x2 +',100 '+ x2 +',0 '+ x1 +',0" fill="'+ colorTag +'"><title>' + tagName +" "+ startTime.split(" ")[1].split(".")[0] +" - "+ endTime.split(" ")[1].split(".")[0] + '</title></polyline>';
                                }
            }
           
            str = str + "</svg>"
           
            document.getElementById(id).innerHTML = str;

           
        }
    });
});

}


Структура <SVG> дает возможность построить векторное изображение, а это значит, что вы можете увеличивать его, приближать или растянуть, качество при этом не упадет.
Вы можете задать свои цвета вместо конструкции  ColorTag, назначив их явно, тогда не придется искать их среди возможных тегов этого приложения, но они будут статичны.
График можно обновлять и сделать его онлайн. Cool
Huh В самом начале функции определяется множество переменных, это связано с необходимостью получения сегодняшнего и вчерашнего дня, чтобы можно было создавать график за текущую и предшествующую смены. Если вам не нужны привязки к текущим моментам, вы можете пользоваться  getPriorityTagDuration сразу, при том время в ней - начала и конца указывать с точностью до суток. Да такой график можно построить за 3 суток сразу. Но помните, что это не длительные отчеты - чем больше данных - тем дольше ждать ответа, а значит между вызовами нужны паузы.

Распечатать этот элемент

Lightbulb Выбор объекта
Автор: Lamantur - 01-21-2025, 12:23 PM - Сообщество: Динамические приложения в WINNUM Platform - Нет ответов

Как сделать полноценное меню с выбором объекта?

.bmp   Точечный рисунок.bmp (Размер: 2.01 KB / Загрузок: 36)

Готовое решение:
1. Скачать файл objectSelector.html в медиабиблиотеку приложения
2. Поместить файл html в контейнер как обычно:  $('#id').load(baseSdkUtils.the.media_url + '/ objectSelector.html');
3. Выбранные объекты доступны в элементе: document.getElementById('objectSelectorResult').value

----------------
Теперь подробнее:
objectSelector.html

Код:
<div class="col-lg-12 col-md-12 col-sm-8 col-xs-8 input-group wn-float-left">
<span tabindex="-1" style="cursor:help; min-width: 35px; max-width: 35px;" class="input-group-addon" id="basic-addon__object_selector_" data-trigger="focus" data-container="body" data-toggle="popover" data-placement="top" title="" data-content="Список выбранных объектов, которые связаны с приложением" data-original-title="Список объектов">
<span class="glyphicon glyphicon-plane"></span>
</span>
<input id="objectSelectorResult" type="hidden" value="">
<input winnum-field-id="_object_selector_" id="selectedObjects" winnum-field-type="text_reference" type="text" class="form-control" aria-describedby="basic-addon__object_selector_" placeholder="" winnum-field-required="true" style="padding: 6px 12px; cursor: text !important;" disabled="" title="">
<span alt="Выбрать" title="Выбрать" onclick="javascript:
baseUtils.openWindow(
'/' + baseUtils.getValue('appId') + '/views/objects/select/appInstanceProductSelector.jsp?appid='+ window.location.href.split('appid=')[1] + '&amp;callerId=callBackFunction',
'',true,500,500
);
" style="cursor:pointer;" class="input-group-addon btn btn-success">
<span class="glyphicon glyphicon-filter" aria-hidden="true"></span>
</span>
<span alt="Отменить выбор" title="Отменить выбор" onclick="javascript:
        console.log(document.getElementById('objectSelectorResult').value);
        document.getElementById('selectedObjects').value='';
        document.getElementById('selectedObjects').setAttribute('title', '');
        document.getElementById('objectSelectorResult').value='';
        document.getElementById('selectedObjects_removeBtn').setAttribute('style','cursor:pointer; display:none;');
      " id="selectedObjects_removeBtn" style="cursor:pointer; display:none;" class="input-group-addon btn btn-danger">
    <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</span>
<span style="cursor:help;" tabindex="-1" class="input-group-addon" id="basic-addon__object_selector_" data-trigger="focus" data-container="body" data-toggle="popover" data-placement="top" title="" data-content="Данное поле является обязательным для заполнения." data-original-title="Внимание - обязательное поле">
*
</span>
<script>
function callBackFunction(oids, count){
    if ( oids && count ){
        if ( count < 0 ){
            oids = '';
            count = 0;
        }
        document.getElementById('objectSelectorResult').value=oids;
        if ( count > 0 ){
            document.getElementById('selectedObjects').value = baseUtils.nls('Selected ') + count + baseUtils.nls(' objects');
        }else{
            document.getElementById('selectedObjects').value= baseUtils.nls('No objects selected');
        }
        document.getElementById('selectedObjects').setAttribute('title', document.getElementById('selectedObjects').value);
        document.getElementById('selectedObjects_removeBtn').setAttribute('style','cursor:pointer;');
    }
}
</script>
</div>


Скрипт в самом контейнере, можно прописать вызов html там же где и manifest.js, либо создать отдельный скрипт, уже без загрузки js:

Код:
$(window).ready(function(){
    loadResources();
});
function loadResources(){
    var oid = '';
    var appid = '';
    baseSdkUtils.the = {};
    baseSdkUtils.service.WNFactory.getPersistable(baseApplicationDesignerUtils.getAppid(), function(data){
        if ( !baseSdkUtils.isSuccess(data) ){
            alert('Error: ' + baseSdkUtils.decode(data.innerHTML));
            console.warn(baseSdkUtils.decode(data.innerHTML));
            return;
        }
        /******* Случай, когда код выполняется в приложении ******/
        if ( data.getElementsByTagName('item').length > 0 ){
            oid = data.getElementsByTagName('item')[0].getAttribute('ApplicationInfo__classNameA15');
            oid += ':';
            appid = data.getElementsByTagName('item')[0].getAttribute('ApplicationInfo__idA15');
            oid += appid;
        }
        /****** Случай, когда код выполняется в редакторе ********/
        else{
            oid = baseApplicationDesignerUtils.oid;
            appid = oid.split(':')[1];
        }
        /****** Создание структуры для хранения атрибутов ********/
            baseSdkUtils.the.appoid = baseApplicationDesignerUtils.getAppid();
            baseSdkUtils.the.appid = appid;
            baseSdkUtils.the.oid = oid;
            baseSdkUtils.the.media_url = '/' + baseSdkUtils.appId + '/resources/themes/current/images/app/ui/designer/media/' + appid + '/';       
        /**** Загрузка контента html в контейнер  myid **********/
            $('#myid').load(baseSdkUtils.the.media_url + '/ objectSelector.html');
        /**** Загрузка js ****************************************/
            jQuery.ajax({
                url: baseSdkUtils.the.media_url + 'manifest.js',
                dataType: 'script',
                success: function(){ loadResourcesProcessor(); },
                async: true
            });
    });
}
   



Файлы вложений
.html   objectSelector.html (Размер: 3.31 KB / Загрузок: 5)
Распечатать этот элемент

Wink Монополия
Автор: wnadmin - 12-05-2024, 12:21 PM - Сообщество: Динамические приложения в WINNUM Platform - Ответы (1)

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

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

Код:
<div id="card1"></div>

В поле скрипт указываем:

Код:
var pid = '2';
var appid = '17';
setTimeout(function(){
    baseUtils.injectIntoPage('/Winnum/views/pages/app/agw.jsp?rpc=winnum.views.pages.app.cnc.dashboard.HomePage&men=printSingleProduct&appid=' + appid + '&pid=' + pid + '&show_product_img=1&view=0','card1',true);
}, 1000);

,где pid - идентификатор оборудования, appid - идентификатор приложения

В результате получаем:

   

И таким же образом можно добавить столько карточек на одну страницу, сколько хочется  Heart

Распечатать этот элемент

Photo Временная шкала
Автор: Lamantur - 11-14-2024, 02:57 PM - Сообщество: Динамические приложения в WINNUM Platform - Ответы (1)

Код:
// Создать векторную шкалу времени в зависимости от смены
// 1 аргумент - класс
// 2 аргумент - время начала смены
// generateTimeline("class", 20);
//h графикa  = 94,864%, и отступить от левого края 12px
function generateTimeline(c, start){
    var elements = document.getElementsByClassName(c);
    var e;
    for(let ii=0; ii<elements.length; ii++){
        e = elements[ii];
        var str = '<line y1=40% x1=1px y2=40% x2=94.864% style=\'stroke:black;stroke-width:0.2%\' />';
        var text, res;
        var all_h = e.getBoundingClientRect().height;
        var all_w = e.getBoundingClientRect().width;
        var textsize = all_h/2;
        for(var i=0;i<=6;i++){
            // Делим на 12 частей
            let t = i*7.9*2;
            let s = t;
            let timeText = i*2 + start;
            if(timeText > 23) timeText = i*2 - 4;
            str = str + '<line y1=40% x1=' +s+ '% y2=0% x2=' +s+ '% style=\'stroke:black;stroke-width:0.3%\' />';
            text = text + "<text y=100% x=" +t+ "% class=\'small\'>" +timeText+ ":00</text>";
        }
        res = "<svg style = 'width:100%;height:100%;margin-left: 12px;' >" +str+ "</svg>";
        var ret = "<svg width = 100% height = 100%>" +text+ "</svg>";
        var d = "<div style = 'width:100%;height:100%;display:grid'>"+res+ret+"</div>";
        e.innerHTML = d;
    }
}
   

Распечатать этот элемент

  Эффективность работы операторов
Автор: Lamantur - 09-13-2024, 02:49 PM - Сообщество: Динамические приложения в WINNUM Platform - Ответы (1)

В приложении файл для экспорта приложения, анализирующее работу операторов.
1. Должен быть подключен сигнал с именем оператора. Указать сигнал можно в коде. 
2. Данные берутся из приложения 1 - Работа под нагрузкой.
3. Приложение работает с сигналами, поэтому при выборе длительного периода формирование отчета занимает время, но все равно строится.
4. При построении таблиц используется встроенная функция baseUtils.createTable

.zip   Эффективность операторов.zip (Размер: 7.85 KB / Загрузок: 11)

Изменяя параметры в функции  createTable можно изменить внешний вид таблицы.

КПД - это параметр, характеризующий загруженность оператора на конкретном станке - определяется временем регистрации, деленном на время выполнения программы станка.



Файлы вложений Эскизы(ов)
   
Распечатать этот элемент

  График работы оборудования на chart.js v4
Автор: Сергей Соловьев - 09-06-2024, 12:54 PM - Сообщество: Динамические приложения в WINNUM Platform - Ответы (2)

Во вложении пример приложения с использованием chart.js v4 и дополнительных плагинов для графика работы оборудования. Для версии платформы 5.4.5 и выше.



Файлы вложений
.zip   DayWorkChart.zip (Размер: 48.08 KB / Загрузок: 21)
Распечатать этот элемент

Lightbulb Telegram Bot для получения последнего бюллетеня
Автор: lunula - 08-03-2024, 12:09 PM - Сообщество: Интеграция WINNUM Platform с другими информационными системами - Нет ответов

Всем привет!

Недавно в WINNUM Platform появился новый функционал - бюллетени, в следствии чего захотелось его дополнить.

Ниже представлен код на C# с использованием .NET 6 и библиотекой Telegram.Bot 18.0.0, который позволяет на любой сгенерированный бот в telegram отправлять последнюю бюллетень полученную от publisher:

Код:
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Telegram.Bot;
using Telegram.Bot.Exceptions;
using Telegram.Bot.Polling;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
using Telegram.Bot.Types.InputFiles;
using Telegram.Bot.Types.ReplyMarkups;

class PublisherBot
{
    private static ITelegramBotClient botClient;

    static async Task Main(string[] args)
    {
        botClient = new TelegramBotClient("5687077362:AAExWWUSdtVLmjYsKqnND7o6CoqFx****"); //bot_token

        var cts = new CancellationTokenSource();

        var receiverOptions = new ReceiverOptions
        {
            AllowedUpdates = Array.Empty<UpdateType>() // получение всех типов обновлений
        };

        botClient.StartReceiving(
            HandleUpdateAsync,
            HandleErrorAsync,
            receiverOptions,
            cancellationToken: cts.Token
        );

        Console.WriteLine("Бот запущен и работает. Нажмите Enter, чтобы выйти.");
        Console.ReadLine();

        cts.Cancel();
    }

    static async Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken)
    {
        if (update == null) return;

        if (update.Message != null)
        {
            var message = update.Message;
            if (message.Text != null)
            {
                if (message.Text.Equals("/start"))
                {
                    await SendWelcomeMessageAsync(message.Chat.Id);
                }
            }
        }
        else if (update.CallbackQuery != null)
        {
            var callbackQuery = update.CallbackQuery;
            if (callbackQuery.Data != null && callbackQuery.Data.Equals("get_file"))
            {
                await SendLatestPdfFileAsync(callbackQuery.Message.Chat.Id);
            }
        }
    }

    static async Task SendWelcomeMessageAsync(long chatId)
    {
        var button = InlineKeyboardButton.WithCallbackData("Получить файл", "get_file");

        var keyboard = new InlineKeyboardMarkup(new[] { new[] { button } });

        await botClient.SendTextMessageAsync(chatId, "Нажмите кнопку ниже, чтобы получить последний бюллетень:", replyMarkup: keyboard);
    }

    static async Task SendLatestPdfFileAsync(long chatId)
    {
        string directoryPath = @"C:\\Winnum\\WinnumPlatform\\publisher\\cache\\temp"; // Путь до temp у publisher
        var latestPdfFile = GetLatestPdfFile(directoryPath);

        if (latestPdfFile != null)
        {
            try
            {
                using var stream = new FileStream(latestPdfFile.FullName, FileMode.Open, FileAccess.Read, FileShare.Read);
                var inputOnlineFile = new InputOnlineFile(stream, latestPdfFile.Name);
                await botClient.SendDocumentAsync(chatId, inputOnlineFile);
            }
            catch (Exception e)
            {
                Console.WriteLine($"Ошибка при отправке файла: {e.Message}");
                await botClient.SendTextMessageAsync(chatId, "Ошибка при отправке файла.");
            }
        }
        else
        {
            await botClient.SendTextMessageAsync(chatId, "Нет доступных бюллетеней.");
        }
    }

    static FileInfo GetLatestPdfFile(string directoryPath)
    {
        var directory = new DirectoryInfo(directoryPath);
        if (!directory.Exists) return null;

        return directory.GetFiles("*.pdf")
            .OrderByDescending(f => f.LastWriteTime)
            .FirstOrDefault();
    }

    static Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken)
    {
        var errorMessage = exception switch
        {
            ApiRequestException apiRequestException
                => $"Telegram API Error:\n[{apiRequestException.ErrorCode}]\n{apiRequestException.Message}",
            _ => exception.ToString()
        };

        Console.WriteLine(errorMessage);
        return Task.CompletedTask;
    }
}

На данный момент сделан bild под windows (скриншот во вложении) и протестирована работа бота(скриншот во вложении).

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

Во вложении .zip архив проекта без bild под Windows, так как с ним он просто слишком большой и не отправляется.

Для тех кто будет продолжать работать с проектом подмечу, важно использовать .NET 6 и выше, так как библиотека поддерживает работу от 6 версии и очень важно использовать версию библиотеки 18.0.0 , так как при работе с 19 версией будут проблемы с пространством имен Telegram.Bot.Types.ImputFiles в следствии чего будет невозможна работа с ImputOnlineFile.



Файлы вложений Эскизы(ов)
       

.zip   TelegramBotWinnum.zip (Размер: 514.97 KB / Загрузок: 6)
Распечатать этот элемент

Question Как создать параметры для своего приложения с помощью хэлперов?
Автор: Сергей Борисов - 07-29-2024, 10:56 AM - Сообщество: Разработка собственных приложений в WINNUM Platform - Нет ответов

Добрый день!

В процессе разработки собственных приложений на JAVA, используя Winnum.SDK, появилась необходимость создания параметров и групп параметров для управления поведением приложения. У всех стандартных приложений имеются свои параметры и группы параметров, которые доступны по адресу:

Код:
http://127.0.0.1/Winnum/views/administration/parameters/list.jsp?cid=winnum.org.app.WNApplicationInstance:1&mode=yes

Подскажите, пожалуйста, как правильно создавать свои параметры, группы параметров и вложенные группы в группу параметров с использованием хэлперов Winnum.SDK.

Распечатать этот элемент

  Повторяющиеся сигналы
Автор: Lamantur - 07-16-2024, 11:36 AM - Сообщество: Динамические приложения в WINNUM Platform - Ответы (1)

Повторяющийся сигнал - это сигнал, который записывается автоматически с определенным интервалом и значением. Такие сигналы могут быть использованы для ввода ручных значений. Рассмотрим вариант использования, в котором стоит задача авторизовать пользователя, привязав его к определенному изделию и снять авторизацию когда это потребуется. Альтернативой этому может быть любой вводимый пользователем сигнал, например текущая операция или причина простоя.
Для работы с повторяемыми сигналами существует системный робот Repeatable Signal Worker. В настройках этого робота можно указать интервал для повторения всех сигналов.
 Для контроля и управления всеми повторяющимися сигналами достаточно перейти в Настройки>Администрирование>Повторяющиеся сигналы.
В WINNUM JavaScriptSDK для работы с управляемыми сигналами предусмотрены следующие функции:

Код:
baseSdkUtils.service.WNRepeatableSignalHelper.createRepeatableSignal(uuid, prefix, signal, counter, function(data) {})
Создание нового повторяемого сигнала. Если повторяемый сигнал с заданными параметрами уже есть, то он будет остановлен и использован
Параметр uuid – UUID продукта
Параметр qualifiedPrefix – блокчайн префикс (допускается только кодировка ASCII) - Допустимо оставить пустым
Параметр qualifiedName – квалифицированное имя сигнала (допускается только кодировка ASCII)
counter - тип используемого счетчика, если сигнал используется не для счетчиков указывается "",

baseSdkUtils.service.WNRepeatableSignalHelper.startRepeatableSignal(oid, value, function(data) {})
Запуск созданного заранее повторяемого сигнала
Параметр oid – идентификатор повторяемого сигнала (class name: id), его можно найти в адресной строке при открытии информации о повторяемом сигнале.
Параметр value – повторяемое значение

baseSdkUtils.service.WNRepeatableSignalHelper.stopRepeatableSignal(oid, function(data) {})
Остановка повторяемого сигнала
Параметр oid – идентификатор повторяемого сигнала (class name: id), его можно найти в адресной строке при открытии информации о повторяемом сигнале.

baseSdkUtils.service.WNRepeatableSignalHelper.getRepeatableSignal(uuid, function(data) {})
Получение перечня повторяемых сигналов по UUID продукта
Параметр uuid – UUID продукта

Для проверки действия функции достаточно вызвать ее, а полученный ответ записать в консоль:
Код:
baseSdkUtils.service.WNRepeatableSignalHelper.createRepeatableSignal(uuid, "", "A100", "", function(data) {console.log(data)})
После этого можно проверить, что в списке повторяемых сигналов появилось новое значение. 
Важные моменты:
1. Управлять повторяемыми сигналами может только Администратор Устройств или Администратор в Организации.
2. Создавая повторяемый сигнал - не создайте его на месте реального сигнала с тем же именем. В этом случае сигнал будет подмешивать значения в приходящий сигнал.
3. Чтобы увидеть сигнал на устройстве нужно создать Шаблон Объекта Данных, назначить его Шаблону Устройств и Прикрепить этот Шаблон Устройств к Шаблону Изделий (на ваше усмотрение как именно организовать Шаблон Изделия).

Создать и запустить:
Код:
function createSignalOperator(uuid, signal, value){
    baseSdkUtils.service.WNRepeatableSignalHelper.createRepeatableSignal(uuid, "", signal ,"",function(data){
         for(var i = 0; i < data.getElementsByTagName('item').length ; i++ ) {
            var item = data.getElementsByTagName('item')[i];
            var oid = baseSdkUtils.decode(item.getAttribute("id"));
           
            baseSdkUtils.service.WNRepeatableSignalHelper.startRepeatableSignal(oid, value);
         }
    });
}


Во вложении шаблон, который позволяет назначать станкам операторов в виде повторяющегося сигнала. Для этого получаем список установленных и доступных пользователю приложений - их выведем в виде выпадающего списка, оттуда сразу берем список станков и запускаем вывод значений сигналов в таблицу:
Код:
function getApplication(){
   
    baseSdkUtils.service.WNApplicationHelper.getApplicationInstance('', function (data){
        if ( baseSdkUtils.isSuccess(data) ){
            var namesApp = [];
            var idApp = [];
            for (var i = 0; i < data.getElementsByTagName('item').length; i++){
                var item = data.getElementsByTagName('item')[i];
                var name = baseSdkUtils.decode(item.getAttribute('name'));
                namesApp.push(name);
                var id = item.getAttribute('id');
                idApp.push(id);
            }
            uniqueNames = new Set(namesApp);
            uniqueId = new Set(idApp);
            var ApplicationNames = Array.from(uniqueNames);
            var ApplicationID = Array.from(uniqueId);
           
            for(s=0;s<ApplicationNames.length;s++){ApplicationNames[s]='<option value=\'' + ApplicationID[s] + '\'>' + ApplicationNames[s] + '</option>';}
            ApplicationNames.sort();
            document.getElementById('appid').innerHTML = ApplicationNames.join("");
            var yourSelect = document.getElementById( "appid" );
            var _appid_ = yourSelect.value;
            //console.log(_appid_);
            startFunction(_appid_);
           
            baseSdkUtils.service.WNApplicationHelper.getProduct(_appid_, function(data){
                if ( baseSdkUtils.isSuccess(data) ){
                   
                   
                   
                    for(var i = 0; i < data.getElementsByTagName('item').length ; i++ ) {
                        var item = data.getElementsByTagName('item')[i];
                        var product_UUID = item.getAttribute('ProductUUID');
                       
                        setTimeout(getRSignal, 200 * (i), product_UUID, i);
                    }
                }
            });
           
        }
    });
}

.zip   Авторизация операторов R5.zip (Размер: 8.52 KB / Загрузок: 6)

Распечатать этот элемент