美文网首页
node-red 可视化探索

node-red 可视化探索

作者: 码代码的小公举 | 来源:发表于2023-06-16 10:28 被阅读0次
    • node-red的基础使用不讲了,百度有较多资料,跟着官网也可以写个简单的自定义组件
    • 这里主要讲的是如何将复杂的组件输出成一个 独立的html页面并于vue框架结合形成一个友好的频繁交互页面
    • 第一:创建一个”config“类型的配置项,从而创建一个websocket长连接,进行频繁的数据交换
    • 第二:创建一个html文件,引入vue,写一个漂亮一些的可视化页面
    • 第三:创建一个组件,提供一些node服务,并关联上你写的websocket服务,启动你的html页面
    配置socket
    选择配置
    流程
    产生url 创建的菜单 my-com
    image.png
    image.png image.png
    • ui文件夹是组件加入后需要公开的文件
    • mycom 是自定义组件
    • socket 是长链接配置
    • 下面上代码
    • mycom.html
    <!-- 注册 -->
    <script type="text/javascript">
        RED.nodes.registerType('my-com', {
            category: 'my', // 分类
            color: '#a6bbcf', // 背景颜色
            defaults: {
                name: { value: "我的组件" },
                socket: { value: '', type: "my-socket" }
            },
            inputs: 1, // 上游:输入 0 或者 1
            outputs: 1, // 输出至下游 0 或者 more
            icon: 'fa fa-anchor', // 标签
            label: function () {
                return this.name;
            }
        }); 
    </script>
    <!-- 配置窗口 -->
    <script type="text/html" data-template-name="my-com">
        <div class="form-row">
            <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
            <input type="text" id="node-input-name" placeholder="Name"/>
        </div>
        <div class="form-row">
            <label for="node-input-socket"><i class="fa fa-globe"></i> <span>socket服务</span></label>
            <input type="text" id="node-input-socket">
        </div>
    </script>
    <!-- hover提示 -->
    <script type="text/html" data-help-name="my-com">
        <p>码代码的小公举</p>
    </script>
    
    • mycom.js
    • socket.html
    <!-- 注册节点 -->
    <script type="text/javascript">
        RED.nodes.registerType('my-socket', {
            category: 'config', // 节点类型:配置,设置类
            defaults: {
                name: { value: "my-socket" },
                port: { value: '1881', required: true }
            },
            label: function () {
                return this.name;
            }
        });
    </script>
    <!-- 展示内容 -->
    <script type="text/html" data-template-name="my-socket">
        <div class="form-row">
            <label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
            <input type="text" id="node-config-input-name" placeholder="Name" />
        </div>
        <div class="form-row">
            <label for="node-config-input-port"><i class="fa fa-tag"></i> Port</label>
            <input type="text" id="node-config-input-port" placeholder="Port"/>
        </div>
    </script>
    

    *socket.js

    module.exports = function (RED) {
        "use strict";
        const webServer = require('ws').Server;
        function mySocket(n) {
            RED.nodes.createNode(this, n);
            const node = this;
            node.port = n.port;
            node.statusText = 'init';
            const wss = new webServer({ port: node.port }, () => {
                node.statusText = 'start';
            });
            wss.on('connection', (ws) => {
                console.log('connected')
                node.statusText = 'connected';
                node.ws = ws;
                ws.send('connected');
                ws.on('message', (data) => {
                    try {
                        const { code, nodeId } = JSON.parse(data.toString());
                        const node = RED.nodes.getNode(nodeId);
                        node.start = false;
                        let timmer;
                        if (code == 'test') {
                            // 持续检测
                            if (node.start) {
                                return;
                            }
                            node.start = true;
                            const loop = () => {
                                if (node.start) {
                                    node.getWorks().then((res) => {
                                        ws.send(JSON.stringify({ code: 'test', payload: res }))
                                    })
                                    timmer = setTimeout(loop, 100);
                                } else {
                                    clearTimeout(timmer);
                                    timmer = null;
                                    
                                }
                            }
                            loop();
                        } else if (code == 'stop') {
                            node.start = false;
                            ws.send(JSON.stringify({ code: 'stop', payload: 'stoped' }))
                        }
                    } catch (err) {
    
                    }
                });
                ws.on('close', () => {
                    node.statusText = '浏览器断开连接';
                    console.log('closed')
                })
            });
            wss.on('close', () => {
                node.statusText = 'closed';
                console.log('closed')
            })
            wss.on('error', (error) => {
                if (error.toString().indexOf('already') > -1 ) {
                    console.log('已启动')
                    return;
                }
                console.log(error)
                node.statusText = 'error';
            })
        }
        RED.nodes.registerType("my-socket", mySocket);
    }
    
    
    • ui.html
    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8">
        <title>码代码的小公举</title>
        <script src="./vue.js"></script>
        <style>
            * {
                padding: 0;
                margin: 0;
            }
    
            #app {
                margin: 40px;
                height: 200px;
                line-height: 26px;
            }
    
            .items {
                margin: 10px;
            }
    
            th,td {
                width: 300px;
            }
    
            button {
                width: 100%;
                height: 40px;
                background: #3872e0;
                border-radius: 4px;
                color: #fff;
                border: 1px solid #3872e0;
                font-size: 16px;
                cursor: pointer;
            }
        </style>
    </head>
    
    <body>
        <div id='app'>
            <div class='box'>
                <div style="padding: 0 10px; margin-bottom: 10px;">
                    <button v-show="!loading" @click="handlerCheck">开始检测</button>
                    <button v-show="loading" @click="handlerStopCheck">停止检测</button>
                </div>
                <div class="items">
                    <table border="1">
                        <tr>
                            <th>name</th>
                            <th>mac</th>
                            <th>family</th>
                            <th>netmask</th>
                            <th>address</th>
                        </tr>
                        <tr v-for="w of works" class="item">
                            <td>{{w.name}}</td>
                            <td>{{w.mac}}</td>
                            <td>{{w.family}}</td>
                            <td>{{w.netmask}}</td>
                            <td>{{w.address}}</td>
                        </tr>
                    </table>
                </div>
            </div>
        </div>
    
        <script>
            const params = {};
            try {
                const arr = location.search.split('?')[1].split('&');
                arr.forEach(i => {
                    const obj = i.split('=');
                    params[obj[0]] = obj[1];
                })
            } catch (err) {
    
            }
            const id = params.id;
            const port = params.port;
            console.log(id, port)
            const { createApp } = Vue
            const HelloVueApp = {
                data() {
                    return {
                        loading: false, // 检测按钮
                        works: [],
                    }
                },
                mounted() {
                    const ws = new WebSocket(`ws://localhost:${port}`);
                    ws.addEventListener('open', (event) => {
                        console.log('WebSocket connected!');
                        this.connected = true; // 连接成功
                    });
                    ws.addEventListener('message', ({ data }) => {
                        try {
                            const { code, payload } = JSON.parse(data);
                            console.log(payload)
                            if (code == 'start') {
                                this.works = payload;
                            } else if (code == 'stop') {
                                // this.works = [];
                            }
                        } catch (err) { }
                    });
                    ws.addEventListener('close', (event) => {
                        console.log('WebSocket disconnected!');
                        this.connected = false;
                    });
                    this.ws = ws;
                },
                methods: {
                    handlerCheck() {
                        this.loading = true;
                        this.ws.send(JSON.stringify({ code: 'start', id }))
                    },
                    handlerStopCheck() {
                        this.loading = false;
                        this.ws.send(JSON.stringify({ code: 'stop', id }))
                    }
                }
            }
    
            Vue.createApp(HelloVueApp).mount('#app')
        </script>
    </body>
    
    </html>
    
    • port是配置的所以需要传递过去给html
    • id是获取node能力所需要的
    • html可以自由扩展发挥,项目化也是可以的,node-red作为配置以及服务器使用
    • vue.js 是vue 3 官网下载的
    • 写的毕竟粗糙
    • 发布之后的打开url:http://127.0.0.1:1880/ui.html?id={config.id}&port={socket.port} 查看

    相关文章

      网友评论

          本文标题:node-red 可视化探索

          本文链接:https://www.haomeiwen.com/subject/yjelydtx.html