Node.js专题Node.js移动端

Node.js+MongDB+高德地图开发设备管理系统

2017-05-17  本文已影响1141人  danieldai

前言:

最近根据朋友需求,需要开发一个设备管理系统,该系统的主要功能是对设备进行地图上的信息展示,根据地理位置添加路口信息,对不同的路口添加数量不等的设备信息,设备发生故障并进行申请。
    考虑node.js中许多现有的模块使用起来确实便捷,再配合前台json交互,由于数据格式的多样性和操作的便捷性选用了MongoDB作为存储数据库。

相关工具:

一、系统效果展示

1.1、系统登录界面:

(图片验证码)


login.png

1.2、地图展示界面:

(从MongoDB获取数据分类展示、左键弹窗,右键弹出菜单)


地图展示.png

(分页展示数据列表,和地图展示在同一界面,地图有折叠效果,便于查看数据列表)


数据列表.png
(点击列表按钮,查看路口详细信息)
路口详情页面.png

1.3、添加地点界面:

(添加路口信息,可以从地图上选取经纬度,动态录入到经纬度输入框中)

添加路口信息.png 添加路口的设备信息.png

1.4、设备报障界面:

(用户提交报障信息,提交后添加一条报障记录,并修改路口信息标志位)


设备报障处理.png

二、网站整体结构

(express+mongoose+bootstrap+layui)

项目结构图.png

1.1、服务端

1.1、前端展示

三、主要功能

四、开发流程

五、前端页面部分代码说明:

//前端验证码展示代码
<div class="layui-input-block"><!--图片验证码,点击图片实现刷新-->
                            ![](http://localhost/captcha)
                            <input type="text" name="captcha" id="captcha" style="width: 60%" autocomplete="off" placeholder="请输入验证码" class="layui-input">
                        </div>
//服务端校验验证码错误后,实现验证码自动刷新
if(result.status==="captcha error"){
                            layer.msg('验证码错误,请重新录入验证码');
                            /*自动刷新图片*/
                            $('#img').click();
                        }
//分析navbar.js实现子菜单向右偏离40px
/*style="padding-left: 40px;设置子菜单向右偏离*/
ulHtml += '<a href="javascript:;" style="padding-left: 40px;" data-url="' + data[i].children[j].href + '">';
//5.4.1 先添加一个按钮,其中是layui提供的向上指示的箭头。
<div class="layui-form-item">
                        <a href="javascript:;" class="layui-btn layui-btn-small layui-btn-danger" id="fold" style="height: 24px">
                            <i class="layui-icon" ></i>
                        </a>
</div>
//js隐藏和关闭地图div,并且修改按钮的样式,点击折叠和展开地图。(foldType是全局的折叠和展开的标志位)
                $('#fold').on('click', function() {
                    if(foldType==="0"){
                        foldType="1";
                        $('#container').hide(1000);
                        $('#fold').html("<i class='layui-icon' id='fold_type'></i>");
                    }else if(foldType==="1"){
                        foldType="0"
                        $('#container').show(1000);
                        $('#fold').html("<i class='layui-icon' id='fold_type'></i>");
                    }
                });
//页面1:打开弹窗代码,动态拼接参数。
layer.open({
                        type: 2,
                        title: '报障信息',
                        shadeClose: true,
                        shade: 0.8,
                        area: ['1050px', '600px'],
    content:'admin_lukou_add_warn.html?lukou_id='+lukou_id,//根据id查看某一个路口详情。
//页面2操作完成以后,通过end实现页面刷新。
                        end:function() {
                            getData("1");
                        }
                    });
//页面2:通过js获取页面1传过来的参数。
 //获取链接中参数的函数(例如:http://localhost/index?username=admin,获取username的值admin)
    $.getUrlParam = function (name) {
               var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
               var r = window.location.search.substr(1).match(reg);
               if (r != null) return unescape(r[2]); return null;
                }
         lukou_id = $.getUrlParam('lukou_id');
//从后台获取数据函数,获取根据区获取数据
                function getData(curr){
                    $.post("/lukous",{addressCode:addressCode,curr:curr},function(result){
                        //重新获取的时候需要清空地图上的marker信息
                        map.remove(markers);
                        //拼接html内容
                        var tabContent="";
                        //获取后台json数据
                        var mydata=result.data;
                        for(var i=0;i<mydata.length;i++){
                            if(mydata[i].lukouStatus=="0"){
                                /*添加蓝色地图markers表示正常*/
                                marker = new AMap.Marker({
                                    map: map,
                                    /*进行序号排序*/
                                    icon: 'http://webapi.amap.com/theme/v1.3/markers/n/mark_b'+((curr-1)*10+i+1)+'.png',
                                    position: [mydata[i].jingdu, mydata[i].weidu],
                                });
                            }else{
                                /*添加红色地图markers表示出错*/
                                marker = new AMap.Marker({
                                    map: map,
                                    /*进行序号排序*/
                                    icon: 'http://webapi.amap.com/theme/v1.3/markers/n/mark_r'+((curr-1)*10+i+1)+'.png',
                                    position: [mydata[i].jingdu, mydata[i].weidu],
                                });

                            }
                            if(mydata[i].lukouStatus=="0"){
                                statusStr='<p>路口状态:正常 </p>';
                            }if(mydata[i].lukouStatus=="1"){
                                statusStr='<p>路口状态:<span style="color: red">维护中</span> </p>';
                            }if(mydata[i].lukouStatus=="2"){
                                statusStr='<p>路口状态:<span style="color: red">发生故障</span> </p>';
                            }
                            marker._id=mydata[i]._id;
                            marker.status=mydata[i].lukouStatus;

                            //设置点击鼠标左键弹出信息窗体的内容
                            marker.content = '<p>路口名称:' +mydata[i].lukouName + '</p>'+
                                            '<p>维护人员:' +mydata[i].maintenanceMan + '</p>'+
                                            '<p>联系电话:'+mydata[i].maintenancePhone +'</p>'+
                                            '<p>设备数量:'+mydata[i].deviceInfo.length +'</p>'+statusStr;
                            //点击左键
                            marker.on('click', markerClick);
                            //绑定鼠标右击事件——弹出右键菜单
                            marker.on('rightclick', function(e) {
                                //创建右键菜单
                                var contextMenu = new AMap.ContextMenu();
                                //菜单1
                                contextMenu.addItem("设备报障", function() {
                                    if(e.target.status=="0"){
                                        layer.open({
                                            type: 2,
                                            title: '报障信息',
                                            shadeClose: true,
                                            shade: 0.8,
                                            area: ['1050px', '600px'],
                                            content:'admin_lukou_add_warn.html?lukou_id='+ e.target._id,//根据id查看某一个路口详情target是指所点击的marker对象。
                                            end:function() {
                                                getData("1");
                                            }
                                        });
                                    }else{
                                        layer.msg("该设备非正常,无需报障!");
                                    }
                                }, 0);
                                //菜单2
                                contextMenu.addItem("状态检测", function() {
                                    /*测试接口是否联通*/
                                    layer.msg('批量测试该路口所有设备是否在线...', {
                                        icon: 16
                                        ,shade: 0.01
                                    });
                                    setTimeout(function(){
                                        layer.msg('测试全部通过...');
                                    }, 2000);
                                }, 1);
                                //菜单3
                                contextMenu.addItem("参数设置", function() {
                                    /*批量设置*/
                                    layer.open({
                                        type: 2,
                                        title: '设备参数批量设置',
                                        shadeClose: true,
                                        shade: 0.8,
                                        area: ['900px', '700px'],
                                        //将路口id和设备id都传过去
                                        content: 'admin_lukou_device_batch_setting.html?lukou_id='+e.target._id
                                    });
                                }, 2);
                                //打开弹出菜单
                                contextMenu.open(map, e.lnglat);
                            });


                            if(mydata[i].lukouStatus=="0"){
                                lukouStatusStr='<p>正常 </p>';
                                problemStr='<td><span class="layui-btn layui-btn-primary layui-btn-mini" style="background-color: #6666cc;color: #ffffff">去报障</span></td>';
                            }if(mydata[i].lukouStatus=="1"){
                                lukouStatusStr='<p style="color: red">维护中 </p>';
                                problemStr='<td><span>否</span></td>';
                            }if(mydata[i].lukouStatus=="2"){
                                lukouStatusStr='<p style="color: red">发生故障 </p>';
                                problemStr='<td><span>否</span></td>';
                            }
                            //将marker装入集合中
                            markers.push(marker);
                            //兴趣点自适应居中显示
                            map.setFitView();
                            /*添加到地图markers*/
                            var tempStr='<tr id='+mydata[i]._id+'>'+
                                    '<td>'+((curr-1)*10+i+1)+'</td>'+
                                    '<td>'+mydata[i].lukouName+'</td>'+
                                    '<td>'+lukouStatusStr+'</td>'+
                                    '<td>'+mydata[i].maintenanceMan+'</td>'+
                                    '<td>'+mydata[i].maintenancePhone+'</td>'+ problemStr+
                                    '<td>'+
                                    '<span class="layui-btn layui-btn-normal layui-btn-mini">设备信息</span>'+
                                    '</td>'+
                                    '<td>'+
                                    '<span class="layui-btn layui-btn-danger layui-btn-mini">删除</span>'+
                                    '</td>'+
                                    '</tr>'
                            tabContent=tabContent+tempStr;
                        }

                        //添加窗体监听事件
                        function markerClick(e) {
                            infoWindow.setContent(e.target.content);
                            infoWindow.open(map, e.target.getPosition());
                            // 设置缩放级别和中心点
                            map.setZoomAndCenter(13, e.target.getPosition());
                        }

                        //将拼接好的数据填入#tabContent中
                        $("#tabContent").html(tabContent);

                        //显示分页
                        laypage({
                            cont: 'page', //容器。值支持id名、原生dom对象,jquery对象。【如该容器为】:<div id="page1"></div>
                            pages: result.pages, //通过后台拿到的总页数
                            curr: curr || 1, //当前页
                            jump: function(obj, first){ //触发分页后的回调
                                if(!first){ //点击跳页触发函数自身,并传递当前页:obj.curr
                                    getData(obj.curr);
                                }
                            }
                        });
                    });
                };



##六、后端部分代码说明
- 6.1、路口信息与不定数量的设备信息管理,先添加路口信息,在根据路口信息添加设备信息(二级文档,Mongoose修改二级文档操作,向主文档添加子文档是是push操作)。

exports.addDeviceByLukouId= function(req, res) {
var lukou_id=req.body.lukou_id;
var deviceNumber=req.body.deviceNumber;
var deviceOne=req.body.deviceOne;
var deviceOneIp=req.body.deviceOneIp;
var deviceTwo=req.body.deviceTwo;
var deviceTwoIp=req.body.deviceTwoIp;
// 向自文档中添加数据
var conditions ={_id : lukou_id};
var update ={$push : {deviceInfo:{deviceNumber:deviceNumber,
deviceOne:deviceOne,
deviceOneIp:deviceOneIp,
deviceTwo:deviceTwo,
deviceTwoIp:deviceTwoIp}
}};
Lukou.update(conditions, update, function(error){
if(error) {
res.json({"status":"error"});
} else {
//查找所有柱子信息
Lukou.findOne({_id:lukou_id},function(err,doc){
if(err){
res.json({"status":"error"});
}else{
res.json({"status":"success","data":doc.deviceInfo})
}
});
}
});
};

- 6.2、eventproxy解决node.js异步回调问题,实现批量修改信息。  

//文件头部引入异步操作模块
var EventProxy = require('eventproxy');
var ep = new EventProxy();


//路口设备批量设置
exports.updateBatchDeviceByDeviceId= function(req, res) {
console.log("pi liang she zhi");
var lukou_id=req.body.lukou_id;
var startTime=req.body.startTime;
var endTime=req.body.endTime;
var team1_am=req.body.team1_am;
var team1_pm=req.body.team1_pm;
var team2_am=req.body.team2_am;
var team2_pm=req.body.team2_pm;
var team3_am=req.body.team3_am;
var team3_pm=req.body.team3_pm;
var team4_am=req.body.team4_am;
var team4_pm=req.body.team4_pm;
var team5_am=req.body.team5_am;
var team5_pm=req.body.team5_pm;
var team6_am=req.body.team6_am;
var team6_pm=req.body.team6_pm;

var volume=req.body.volume;
var normalVolume=req.body.normalVolume;
var bigVolume=req.body.bigVolume;

Lukou.findOne({_id:lukou_id},function(err,doc){
    if(err){
        res.json({"status":"error"});
    }else{

        //循环添加后执行。
        ep.after('data_save', doc.deviceInfo.length, function () {
            // 在所有文件的异步执行结束后将被执行
            res.json({"status":"success"});
        });

        for(var i=0;i<doc.deviceInfo.length;i++){
                console.log("find success"+doc.deviceInfo[i].deviceOne);
                doc.deviceInfo[i].startTime=startTime;
                doc.deviceInfo[i].endTime=endTime;
                doc.deviceInfo[i].team1_am=team1_am;
                doc.deviceInfo[i].team1_pm=team1_pm;
                doc.deviceInfo[i].team2_am=team2_am;
                doc.deviceInfo[i].team2_pm=team2_pm;
                doc.deviceInfo[i].team3_am=team3_am;
                doc.deviceInfo[i].team3_pm=team3_pm;
                doc.deviceInfo[i].team4_am=team4_am;
                doc.deviceInfo[i].team4_pm=team4_pm;
                doc.deviceInfo[i].team5_am=team5_am;
                doc.deviceInfo[i].team5_pm=team5_pm;
                doc.deviceInfo[i].team6_am=team6_am;
                doc.deviceInfo[i].team6_pm=team6_pm;
                doc.deviceInfo[i].volume=volume;
                doc.deviceInfo[i].normalVolume=normalVolume;
                doc.deviceInfo[i].bigVolume=bigVolume;
                doc.save(function(err){
                    if(err){
                        res.json({"status":"error"});
                    }else{
                        console.log("save success");
                        ep.emit('data_save');
                    }
                });
        }
    }
});

};


##七、最后 

[layui地址](http://www.layui.com/)
[项目github地址](https://github.com/dpc761218914/Device_Management)

感谢浏览...
上一篇下一篇

猜你喜欢

热点阅读