vuejs、eggjs、mqtt全栈式开发设备管理系统
vuejs、eggjs、mqtt全栈式开发简单设备管理系统
业余时间用eggjs、vuejs开发了一个设备管理系统,通过mqtt协议上传设备数据至web端实时展现,包含设备参数分析、发送设备报警等模块。收获还是挺多的,特别是vue的学习,这里简单记录一下:
源码地址:https://github.com/caiya/vuejs-admin,写文不易,有帮助的话麻烦给个star,感谢!
技术栈
前端:vue、vuex、vue-router、element-ui、axios、mqttjs
后端:eggjs、mysql、sequlize、restful、oauth2.0、mqtt、jwt
- 用户模块(用户管理,用户增删改查)
- 设备模块(设备管理、设备参数监控、设备参数记录、设备类别管理、参数管理等)
- 授权模块(引入OAuth2.0授权服务,方便将接口以OAuth提供第三方)
- 消息模块(用户申请帮助消息、设备参数告警消息等)
效果图(对一个后端css永远是内伤)
登录页:
主页:
设备页:
设备参数监控页:
前台
项目结构
前端使用vue-cli脚手架构建,基本目录结构如下:
main.js入口
vue项目的入口文件,这里主要是引入iconfont、element-ui、echarts、moment、vuex等模块。
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' import { axios } from './http/base' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' import './assets/fonts/iconfont.css' import ECharts from 'vue-echarts/components/ECharts' // import ECharts modules manually to reduce bundle size import 'echarts/lib/chart/line' import 'echarts/lib/component/tooltip' // register component to use Vue.component('chart', ECharts) import store from './store' import moment from 'moment' Vue.prototype.$moment = moment Vue.use(ElementUI) // 引入mqtt import './mq' Vue.config.productionTip = false // 挂载到prototype上面,确保组件中可以直接使用this.axios // Vue.prototype.axios = axios /* eslint-disable no-new */ new Vue({ el: '#app', router, store, components: { App }, template: '<App/>' })
注意:
1、引入比较大的模块比如echarts时,尽量手动按需进行模块导入,节省打包文件大小 2、一般通过将模块比如moment挂载到Vue的prototype上面,这样就可以在任意vue组件中使用*this.$moment*进行moment操作了 3、iconfont是阿里的图标样式,下载下来后放入assets中再引入即可
vuex引入
vuex引入的时候采用了模块话引入,入口文件代码为:
import Vue from 'vue' import Vuex from 'vuex' import user from './modules/user' import devArgsMsg from './modules/devArgsMsg' Vue.use(Vuex) export default new Vuex.Store({ modules: { user, devArgsMsg } })
其中user、devArgsMsg为两个独立模块,这样分模块引入可以避免项目过大结构不清晰的问题。其中user.js模块代码:
import * as TYPES from '../mutation.types' const state = { userInfo: JSON.parse(localStorage.getItem('userInfo') || '{}'), token: localStorage.getItem('token') || '' } const actions = { } const mutations = { [TYPES.LOGIN]: (state, loginData) => { state.userInfo = loginData.user state.token = loginData.token localStorage.setItem('userInfo', JSON.stringify(loginData.user)) localStorage.setItem('token', loginData.token) }, [TYPES.LOGOUT]: state => { state.userInfo = {} state.token = '' localStorage.removeItem('userInfo') localStorage.removeItem('token') } } const getters = { } export default { state, actions, mutations, getters }
关于mutations.type.js:
// 各种mutation类型 // 用户模块 export const LOGOUT = 'LOGOUT' export const LOGIN = 'LOGIN' // 设备模块 export const SETDEVARGSMSG = 'setDevArgsMsg'
注意:
1、mutations的名称定义时遵循官方,一般定义为常量 2、state的数据只有通过mutation才能操作,不能直接在组件中设置state,否则无效 3、mutation中的操作都是同步操作,异步操作或网络请求或同时多个mutation操作可以放入action中进行 4、用户信息、登录token一般放入h5的localStorage,这样刷新页面保证关键数据不丢失 5、vuex中的getters相当于state的计算属性,监听state数据变动时可以使用getters
vue-router路由模块
路由模块基本使用:
import Vue from 'vue' import Router from 'vue-router' import store from '../store' Vue.use(Router) const router = new Router({ mode: 'history', routes: [ { path: '/', name: 'Login', component: resolve => require(['@/views/auth/Login'], resolve) }, { path: '', // 默认地址为登录页 name: '', component: resolve => require(['@/views/auth/Login'], resolve) }, { path: '/main', name: '', component: resolve => require(['@/views/Main'], resolve), meta: { requireAuth: true, // 添加该字段,表示进入这个路由是需要登录的 nav: '欢迎页' }, children: [{ path: 'user', component: resolve => require(['@/views/user/List'], resolve), name: 'UserList', meta: { requireAuth: true, nav: '用户管理', activeItem: '1-1' }, }, { path: 'user/setting/:userId?', name: 'UserSetting', component: resolve => require(['@/views/user/Setting'], resolve), meta: { requireAuth: true, nav: '资料设置', activeItem: '1-2' }, }, { path: 'device', component: resolve => require(['@/views/device/List'], resolve), name: 'Device', meta: { requireAuth: true, nav: '设备列表', activeItem: '3-1' }, },{ path: 'device/edit/:devId?', component: resolve => require(['@/views/device/Edit'], resolve), name: