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: