From 9a80cedfe0efbdb46567a3dc82b9779a47e3a855 Mon Sep 17 00:00:00 2001 From: lucky Date: Tue, 15 Dec 2020 14:20:20 +0800 Subject: [PATCH 1/3] RFID --- src/components/LoadCells/LoadCells.styl | 51 ++++++++++++++++++++++++ src/components/LoadCells/LoadCells.vue | 52 +------------------------ 2 files changed, 52 insertions(+), 51 deletions(-) create mode 100644 src/components/LoadCells/LoadCells.styl diff --git a/src/components/LoadCells/LoadCells.styl b/src/components/LoadCells/LoadCells.styl new file mode 100644 index 0000000..6e077c9 --- /dev/null +++ b/src/components/LoadCells/LoadCells.styl @@ -0,0 +1,51 @@ +.box { + width: 88%; + left: 6%; + position: relative; +} + +.title { + font-size: 17px; + color: #C8CED5; + letter-spacing: 2px; +} + +.number { + height: 80%; + position: absolute; + right: 0; + bottom: 0; +} + +.number .num_item { + background: url('~assets/cz-bg.png') no-repeat bottom left; + background-size: auto 90%; + position: relative; + top: -6px; + left: 2px; +} + +.number span { + display: inline-block; + position: relative; + top: -8px; + left: 2px; + font-size: 38px; + font-style: oblique; + font-weight: 400; + letter-spacing: 18px; + height: 100%; +} + +@media (max-width: 1500px) { + .title { + font-size: 12px; + letter-spacing: 0; + } + + .number span { + top: -8px; + font-size: 23px; + letter-spacing: 16px; + } +} diff --git a/src/components/LoadCells/LoadCells.vue b/src/components/LoadCells/LoadCells.vue index 1dfffab..cc7a415 100644 --- a/src/components/LoadCells/LoadCells.vue +++ b/src/components/LoadCells/LoadCells.vue @@ -70,55 +70,5 @@ export default { From a061e582977f9ead3ce5a3b424f6b362b3e14a87 Mon Sep 17 00:00:00 2001 From: lucky Date: Tue, 15 Dec 2020 14:22:44 +0800 Subject: [PATCH 2/3] RFID --- src/components/RFID/RFID.vue | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/RFID/RFID.vue b/src/components/RFID/RFID.vue index b560fa1..a03461c 100644 --- a/src/components/RFID/RFID.vue +++ b/src/components/RFID/RFID.vue @@ -1,7 +1,12 @@ diff --git a/src/config/api-user.js b/src/config/api-user.js index 5c5f290..3056438 100644 --- a/src/config/api-user.js +++ b/src/config/api-user.js @@ -7,20 +7,7 @@ import axios from 'axios'; let { proxyUrl, msgUrl } = require('@/config/setting'); const tall = `${proxyUrl}/tall/v1.0`; -// console.log('tall: ', tall); const users = `${tall}/users`; -// 用户登录 -export const signIn = params => axios.post(`${users}/signin`, params); - -// 注册 -export const signUp = params => axios.post(`${users}/signup`, params); - -// 图片验证码 -export const getPicCode = () => axios.get(`${users}/code`); - -// 发送验证码 -export const getSmscode = params => axios.get(`${users}/smscode`, params); - -// 通过手机号修改密码 -export const changePassword = params => axios.post(`${users}/password`, params); +// 查找用户详细信息 +export const getUserId = params => axios.get(`${users}/userId`, params); diff --git a/src/mixins/socket.js b/src/mixins/socket.js new file mode 100644 index 0000000..033a4d0 --- /dev/null +++ b/src/mixins/socket.js @@ -0,0 +1,213 @@ +import { WS_BASE_URL } from 'config/api'; +import { mapGetters, mapMutations } from 'vuex'; + +let connected = false; // socket 是否连接 +let socket = null; // websocket 实例 +let lockSocket = false; +let socketMsgQueue = []; // socket消息队列 +let prevTimestamp = 0; // 上次收到消息的时间戳 +let sendHeartTimer = null; // 💓的timer计时器 + +const mixin = { + // computed: mapGetters('home', ['projectId']), + + mounted() { + socket ? socket.close() : this.initSocket(); + }, + + methods: { + ...mapMutations('messages', [ + 'messagesAdd', + 'messagesAddWeight', + 'messagesAddRfid', + 'messagesAddWeighSensor1', + 'messagesAddWeighSensor2', + 'messagesAddWeighSensor3', + 'messagesAddWeighSensor4', + 'messagesAddVibrationSensor', + 'messagesAddThrombolyticDose', + 'messagesAddBolusDose', + 'messagesAddMaintenanceDose', + ]), + // ...mapMutations('home', ['increaseProjectsRingNum']), + + // 初始化websocket + initSocket() { + if (lockSocket) return; + lockSocket = true; + // const token = sessionStorage.getItem('anyringToken'); + // if (!token) return; + if ('WebSocket' in window) { + socket = new WebSocket(WS_BASE_URL); + socket.onopen = this.websocketOpen; + socket.onmessage = this.websocketOnMessage; + socket.onclose = this.websocketClose; + socket.onerror = this.websocketError; + } else { + this.$message.error('当前浏览器不支持 websocket'); + } + lockSocket = false; + }, + + /** + * 处理收到的消息内容 + * @param {object} item 单个消息体对象 + */ + handleMessagesData(item) { + const data = JSON.parse(item.data); + console.log('data: ', data); + switch (data.type) { + case 'ChannelStatus': // 认证消息 + this.handleAuthMessage(data); + break; + case 1: // 体重 + // 收到同步消息 + // 把消息添加到store 的消息栈中 + this.messagesAddWeight(data); + break; + case 2: // RFID + this.messagesAddRfid(data); + break; + case 3: // 称重传感器一 + this.messagesAddWeighSensor1(data); + break; + case 4: // 称重传感器二 + this.messagesAddWeighSensor2(data); + break; + case 5: // 称重传感器三 + this.messagesAddWeighSensor3(data); + break; + case 6: // 称重传感器四 + this.messagesAddWeighSensor4(data); + break; + case 7: // 震动传感器 + this.messagesAddVibrationSensor(data); + break; + case 8: // 溶栓剂量(总量) + this.messagesAddThrombolyticDose(data); + break; + case 9: // 团注剂量 + this.messagesAddBolusDose(data); + break; + case 10: // 维持剂量 + this.messagesAddMaintenanceDose(data); + break; + default: + break; + } + }, + + /** + * 收到ws 消息 + * @param {object} res 收到的消息数据 + */ + async websocketOnMessage(res) { + try { + prevTimestamp = Date.now(); + // console.warn('message: ', res, new Date().toLocaleString()); + if (res && res.data && JSON.parse(res.data)) { + const resData = JSON.parse(res.data); + const { messageSet, ackId } = resData; + // 处理消息体对象 + messageSet.forEach(item => this.handleMessagesData(item)); + // console.log('ackId', ackId); + // 有ackId 发送ack + ackId && this.sendSocketMessage({ type: 'Ack', data: { ackId } }); + } + } catch (error) { + console.error('error: ', error); + } + }, + + // 打开socket + websocketOpen() { + // console.warn('socket 打开成功', new Date().toLocaleString()); + connected = true; + prevTimestamp = Date.now(); + this.auth(); + for (let i = 0; i < socketMsgQueue.length; i += 1) { + this.sendSocketMessage(socketMsgQueue[i]); + } + socketMsgQueue = []; + }, + + // 发送消息 + sendSocketMessage(data) { + // console.warn('send:', data, new Date().toLocaleString()); + if (connected) { + if (socket.readyState === 1) { + socket.send(JSON.stringify({ toDomain: 'Server', data: JSON.stringify(data) })); + } + } else { + socketMsgQueue.push(data); + } + }, + + // 关闭socket + websocketClose(e) { + // console.warn(e); + connected = false; + if (sendHeartTimer) clearInterval(sendHeartTimer); + // console.warn('close:', connected, new Date().toLocaleString()); + if (!e || e.code !== 1005) { + socket.close(); + } + + setTimeout(() => { + // connected 在这里的作用是: + // 在发生重连 但是还没连上之前 不要再次重连 + this.initSocket(); + }, 300); + }, + + // 连接失败 + websocketError() { + console.warn('error = ', connected); + }, + + // websocket发送token进行认证 + auth() { + // const token = sessionStorage.getItem('anyringToken'); + // if (!token) return; + const userId = '1338747522436435968'; + const data = { type: 'Auth', data: { userId }, major: 1, minor: 1 }; + this.sendSocketMessage(data); + }, + + // 心跳检测 + sendHeart() { + if (sendHeartTimer) clearInterval(sendHeartTimer); + sendHeartTimer = setInterval(() => { + if (Date.now() - prevTimestamp >= 15000) { + this.sendSocketMessage({ type: 'Ping' }); + + if (Date.now() - prevTimestamp > 20000) { + // console.warn('手动断开'); + socket.close(); + } + } + }, 5000); + }, + + /** + * 处理auth认证返回的ChannelStatus消息 + * @param {object} data 消息内容对象 + */ + handleAuthMessage(data) { + if (data.data.authed) { + // 认证成功 + this.sendHeart(); + } else { + this.$message.error('消息系统认证失败, 请重新登录'); + // 清除掉本地无用的token + sessionStorage.removeItem('anyringToken'); + socket = null; + setTimeout(() => { + this.$router.push('/user/login'); + }, 1000); + } + }, + }, +}; + +export default mixin; diff --git a/src/store/actions.js b/src/store/actions.js deleted file mode 100644 index 7ecf322..0000000 --- a/src/store/actions.js +++ /dev/null @@ -1,143 +0,0 @@ -import axios from 'axios'; -import { message } from 'ant-design-vue'; -import { getSmscode, getPicCode, signIn, changePassword, signUp, getUserId } from 'config/api-user'; - -const actions = { - /** - * sendCode 发送验证码 - * @param {any} commit - * @param {object} params 提交的数据 - * @param {string} params.phone 手机号 - */ - async sendCode({ commit }, params) { - try { - const res = await getSmscode({ params }); - const { code, msg, data } = res.data; - if (code === 200) { - return data; - } else { - message.error(msg || '发送失败'); - throw msg; - } - } catch (error) { - throw error || '发送失败'; - } - }, - - /** - * sendPicCode 获取图片验证码 - * @param {any} commit - * @param {object} params 提交的数据 - */ - async sendPicCode({ commit }) { - try { - const res = await getPicCode(); - const { code, msg, data } = res.data; - if (code === 200) { - commit('setPicCode', data); - return data; - } else { - throw msg; - } - } catch (error) { - throw error || '获取失败'; - } - }, - - /** - * signIn 登录 - * @param {any} commit - * @param {string} identifier 身份标识 手机号 用户名 - * @param {string} credential 身份凭证 验证码 密码 - * @return {Promise} result 服务器返回信息 - */ - async signIn({ commit }, params) { - const hideLoading = message.loading('登录中', 0); - try { - const res = await signIn(params); - const { code, msg, data } = res.data; - if (code === 200) { - commit('sign', data.token); - commit('setUser', data); - hideLoading(); - message.success('登录成功'); - return data; - } else { - hideLoading(); - throw msg || '登录失败'; - } - } catch (error) { - hideLoading(); - throw error || '登录失败'; - } - }, - - /** - * 修改密码 忘记密码 - * @param {any} commit - * @param {object} params 要提交的参数 - */ - async changePassword({ commit }, params) { - try { - const res = await changePassword(params); - const { code, msg, data } = res.data; - if (code === 200) { - message.success('修改密码成功'); - return data; - } else { - throw msg || '修改密码失败'; - } - } catch (error) { - throw error || '修改密码失败'; - } - }, - - /** - * singUp 注册新用户 - * @param {any} commit - * @param {object} params 提交的数据 - * @param {string} params.account 用户名 - * @param {string} params.password 密码 - * @param {string} params.phone 手机号 - * @param {string} params.smsCode 验证码 - */ - async signUp({ commit }, params) { - try { - const res = await signUp(params); - const { code, msg, data } = res.data; - if (code === 200) { - commit('sign', data.token); - commit('setUser', data); - message.success('注册成功'); - return data; - } else { - throw msg || '注册失败'; - } - } catch (error) { - throw error || '注册失败'; - } - }, - - /** - * 通过userId获取token - * @param {any} commit - * @param {object} params 提交的参数 - */ - // async getUserId({ commit }, params) { - // try { - // const res = await getUserId({ params }); - // const { code, msg, data } = res.data; - // if (code === 200) { - // commit('sign', data.token); - // commit('setUser', data); - // return data; - // } else { - // throw msg; - // } - // } catch (error) { - // throw error || '获取个人信息失败'; - // } - // }, -}; - -export default actions; diff --git a/src/store/index.js b/src/store/index.js index b97fc4b..7dd359a 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1,16 +1,13 @@ -import Vue from "vue"; -import Vuex from "vuex"; -import mutations from './mutations'; -import actions from './actions'; -import state from './state'; -import getters from './getters'; +/* + * Copyright (c) 2019. + * author: wally + * email: 18603454788@163.com + */ -Vue.use(Vuex); - -const store = new Vuex.Store({ - state, - mutations, - actions, -}); +import Vue from 'vue'; +import Vuex from 'vuex'; +import home from './modules/home/index'; +import messages from './modules/messages/index'; -export default store; +Vue.use(Vuex); +export default new Vuex.Store({ modules: { home, messages } }); diff --git a/src/store/modules/home/actions.js b/src/store/modules/home/actions.js new file mode 100644 index 0000000..1b9113f --- /dev/null +++ b/src/store/modules/home/actions.js @@ -0,0 +1,28 @@ +import axios from 'axios'; +import { message } from 'ant-design-vue'; +import { getUserId } from 'config/api-user'; + +const actions = { + /** + * 通过userId获取token + * @param {any} commit + * @param {object} params 提交的参数 + */ + async getUserId({ commit }, params) { + try { + const res = await getUserId({ params }); + const { code, msg, data } = res.data; + if (code === 200) { + commit('sign', data.token); + commit('setUser', data); + return data; + } else { + throw msg; + } + } catch (error) { + throw error || '获取个人信息失败'; + } + }, +}; + +export default actions; diff --git a/src/store/getters.js b/src/store/modules/home/getters.js similarity index 100% rename from src/store/getters.js rename to src/store/modules/home/getters.js diff --git a/src/store/modules/home/index.js b/src/store/modules/home/index.js new file mode 100644 index 0000000..149de4f --- /dev/null +++ b/src/store/modules/home/index.js @@ -0,0 +1,6 @@ +import mutations from './mutations'; +import actions from './actions'; +import getters from './getters'; +import state from './state'; + +export default { namespaced: true, state, getters, mutations, actions }; diff --git a/src/store/mutations.js b/src/store/modules/home/mutations.js similarity index 100% rename from src/store/mutations.js rename to src/store/modules/home/mutations.js diff --git a/src/store/state.js b/src/store/modules/home/state.js similarity index 100% rename from src/store/state.js rename to src/store/modules/home/state.js diff --git a/src/store/modules/messages/actions.js b/src/store/modules/messages/actions.js new file mode 100644 index 0000000..61da9cc --- /dev/null +++ b/src/store/modules/messages/actions.js @@ -0,0 +1,7 @@ +import http from 'axios'; +import { message } from 'ant-design-vue'; +import {} from 'config/api'; + +const actions = {}; + +export default actions; diff --git a/src/store/modules/messages/getters.js b/src/store/modules/messages/getters.js new file mode 100644 index 0000000..56c8c75 --- /dev/null +++ b/src/store/modules/messages/getters.js @@ -0,0 +1,3 @@ +const getters = {}; + +export default getters; diff --git a/src/store/modules/messages/index.js b/src/store/modules/messages/index.js new file mode 100644 index 0000000..91969b1 --- /dev/null +++ b/src/store/modules/messages/index.js @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2019. + * author: wally + * email: 18603454788@163.com + */ +import mutations from './mutations'; +import actions from './actions'; +import getters from './getters'; +import state from './state'; + +export default { namespaced: true, state, getters, mutations, actions }; diff --git a/src/store/modules/messages/mutations.js b/src/store/modules/messages/mutations.js new file mode 100644 index 0000000..2ba1ebe --- /dev/null +++ b/src/store/modules/messages/mutations.js @@ -0,0 +1,173 @@ +const mutations = { + /** + * 初始化消息栈 + * @param {object} state + * @param {string} type + * type: + * syncMessages 同步消息栈 + * checkMessages 交付物消息栈 + * faultMessages 故障消息 未处理消息栈 + * faults 所有的故障消息栈 + */ + messagesInit(state, type) { + const messages = localStorage.getItem(type) ? JSON.parse(localStorage.getItem(type)) : []; + state[type] = messages; + }, + + /** + * 将新 消息添加到 消息栈 最前边 + * @param { object } state + * @param { object } data + * data: message, type + * message 消息对象 + * type: + * syncMessages 同步消息栈 + * checkMessages 交付物消息栈 + * faultMessages 故障消息 未处理消息栈 + * faults 所有的故障消息栈 + * + * cache: boolean true 本地存储 false 不存储 + */ + messagesAdd(state, data) { + const messages = state[data.type]; + if (messages.length > 0) { + const result = messages.find(msg => msg.id === data.message.id); + if (result) return; + } + messages.unshift(data.message); + // eslint-disable-next-line no-param-reassign + state[data.type] = messages; + if (data.cache) { + localStorage.setItem(data.type, JSON.stringify(messages)); + } + }, + + /** + * 通过消息id移除指定 同步 消息 + * @param { object } state + * @param { object } data + * data: messageId, type + * messageId: 要移除的消息的messageId + * type: + * syncMessages 同步消息栈 + * checkMessages 交付物消息栈 + * faultMessages 故障消息 未处理消息栈 + * faults 所有的故障消息栈 + * cache: boolean true 本地存储 false 不存储 + */ + messagesRemoveById(state, data) { + const messages = state[data.type]; + const index = messages.findIndex(msg => msg.id === data.messageId); + if (index < 0) return; + messages.splice(index, 1); + // eslint-disable-next-line no-param-reassign + state[data.type] = messages; + if (data.cache) { + localStorage.setItem(data.type, JSON.stringify(messages)); + } + }, + + /** + * 清除指定type的消息 + * @param {any} state + * @param {object} data + * data: type, cache + */ + messagesClear(state, data) { + state[data.type] = []; + if (data.cache) { + localStorage.removeItem(data.type); + } + }, + + /** + * 添加体重消息 + * @param {*} state + * @param {*} data + */ + messagesAddWeight(state, data) { + state.weightMessage = data; + }, + + /** + * 添加RFID消息 + * @param {*} state + * @param {*} data + */ + messagesAddRfid(state, data) { + state.rfidMessage = data; + }, + + /** + * 添加称重传感器一消息 + * @param {*} state + * @param {*} data + */ + messagesAddWeighSensor1(state, data) { + state.weighSensor1 = data; + }, + + /** + * 添加称重传感器二消息 + * @param {*} state + * @param {*} data + */ + messagesAddWeighSensor2(state, data) { + state.weighSensor2 = data; + }, + + /** + * 添加称重传感器三消息 + * @param {*} state + * @param {*} data + */ + messagesAddWeighSensor3(state, data) { + state.weighSensor3 = data; + }, + + /** + * 添加称重传感器四消息 + * @param {*} state + * @param {*} data + */ + messagesAddWeighSensor4(state, data) { + state.weighSensor4 = data; + }, + + /** + * 添加震动传感器消息 + * @param {*} state + * @param {*} data + */ + messagesAddVibrationSensor(state, data) { + state.vibrationSensor = data; + }, + + /** + * 添加溶栓剂量(总量)消息 + * @param {*} state + * @param {*} data + */ + messagesAddThrombolyticDose(state, data) { + state.thrombolyticDose = data; + }, + + /** + * 添加团注剂量消息 + * @param {*} state + * @param {*} data + */ + messagesAddBolusDose(state, data) { + state.bolusDose = data; + }, + + /** + * 添加维持剂量消息 + * @param {*} state + * @param {*} data + */ + messagesAddMaintenanceDose(state, data) { + state.maintenanceDose = data; + }, +}; +export default mutations; diff --git a/src/store/modules/messages/state.js b/src/store/modules/messages/state.js new file mode 100644 index 0000000..3a86c92 --- /dev/null +++ b/src/store/modules/messages/state.js @@ -0,0 +1,15 @@ +const state = { + syncMessages: [], // 同步消息 + weightMessage: null, // 体重 + rfidMessage: null, // RFID + weighSensor1: null, // 称重传感器一 + weighSensor2: null, // 称重传感器二 + weighSensor3: null, // 称重传感器三 + weighSensor4: null, // 称重传感器四 + vibrationSensor: null, // 震动传感器 + thrombolyticDose: null, // 溶栓剂量(总量) + bolusDose: null, // 团注剂量 + maintenanceDose: null, // 维持剂量 +}; + +export default state; diff --git a/src/views/Index/Index.vue b/src/views/Index/Index.vue index 79575af..33c2628 100644 --- a/src/views/Index/Index.vue +++ b/src/views/Index/Index.vue @@ -125,9 +125,12 @@ import LoadCells from 'components/LoadCells/LoadCells.vue'; import RFID from 'components/RFID/RFID.vue'; import FastEd from 'components/FastEd/FastEd.vue'; import Panel from 'components/Panel/Panel.vue'; +import socketMixin from '@/mixins/socket'; + export default { name: 'Index', components: { Statistics, Duration, Sensor, LoadCells, RFID, FastEd, Panel }, + mixins: [socketMixin], data() { return { nowTime: new Date(),