aBin 5 years ago
parent
commit
1e5205137a
  1. 4
      .env.development
  2. 4
      .env.production
  3. 11
      src/App.vue
  4. 51
      src/components/LoadCells/LoadCells.styl
  5. 52
      src/components/LoadCells/LoadCells.vue
  6. 9
      src/components/RFID/RFID.vue
  7. 17
      src/config/api-user.js
  8. 213
      src/mixins/socket.js
  9. 143
      src/store/actions.js
  10. 25
      src/store/index.js
  11. 28
      src/store/modules/home/actions.js
  12. 0
      src/store/modules/home/getters.js
  13. 6
      src/store/modules/home/index.js
  14. 0
      src/store/modules/home/mutations.js
  15. 0
      src/store/modules/home/state.js
  16. 7
      src/store/modules/messages/actions.js
  17. 3
      src/store/modules/messages/getters.js
  18. 11
      src/store/modules/messages/index.js
  19. 173
      src/store/modules/messages/mutations.js
  20. 15
      src/store/modules/messages/state.js
  21. 3
      src/views/Index/Index.vue

4
.env.development

@ -1,10 +1,10 @@
VUE_APP_MODE=development
VUE_APP_NODE_ENV=development
VUE_APP_SCENE=greenvalley
VUE_APP_SCENE=wisdomcar
VUE_APP_BASE_URL=http://test.tall.wiki/
VUE_APP_API_URL=http://test.tall.wiki/gateway
VUE_APP_PROXY_URL=/gateway
VUE_APP_PUBLIC_PATH=/greenvalley
VUE_APP_PUBLIC_PATH=/wisdomcar
VUE_APP_MSG_URL=wss://test.tall.wiki/websocket/message/v4.0/ws
VUE_APP_TITLE=盐湖区人民医院数字看板
VUE_APP_DESCRIPTION=盐湖区人民医院数字看板

4
.env.production

@ -1,10 +1,10 @@
VUE_APP_MODE=production
VUE_APP_NODE_ENV=production
VUE_APP_SCENE=greenvalley
VUE_APP_SCENE=wisdomcar
VUE_APP_BASE_URL=http://www.sxwikionline.com/
VUE_APP_API_URL=http://www.sxwikionline.com/gateway
VUE_APP_PROXY_URL=/gateway
VUE_APP_PUBLIC_PATH=/greenvalley
VUE_APP_PUBLIC_PATH=/wisdomcar
VUE_APP_MSG_URL=wss://www.tall.wiki/websocket/message/v4.0/ws
VUE_APP_TITLE=盐湖区人民医院数字看板
VUE_APP_DESCRIPTION=盐湖区人民医院数字看板

11
src/App.vue

@ -7,6 +7,7 @@
</template>
<script>
import { mapState, mapActions, mapMutations } from 'vuex';
import zh_CN from 'ant-design-vue/lib/locale-provider/zh_CN';
export default {
@ -14,6 +15,16 @@ export default {
data() {
return { zh_CN };
},
computed: mapState('home', ['anyringToken']),
created() {
const userId = '1338747522436435968';
const params = { userId };
this.getUserId(params);
},
methods: mapActions('home', ['getUserId']),
};
</script>

51
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;
}
}

52
src/components/LoadCells/LoadCells.vue

@ -70,55 +70,5 @@ export default {
</script>
<style lang="stylus" scoped >
.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;
}
}
@import './LoadCells.styl';
</style>

9
src/components/RFID/RFID.vue

@ -1,7 +1,12 @@
<template>
<div class="flex-1 flex-column rfid">
<div :key="i + 1" v-for="(lists, i) in newArr" v-show="i === num">
<div :class="`list${index + 1} ${item.active ? 'active' : ''}`" :key="index" class="list" v-for="(item, index) in lists">
<div :key="i + 1" v-for="(arr, i) in newArr" v-show="i === num">
<div
:class="`list${index + 1} ${item.active ? 'active' : ''}`"
:key="index"
class="list"
v-for="(item, index) in arr"
>
<span>{{ item.name }}</span>
</div>
</div>

17
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);

213
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;

143
src/store/actions.js

@ -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;

25
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 } });

28
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;

0
src/store/getters.js → src/store/modules/home/getters.js

6
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 };

0
src/store/mutations.js → src/store/modules/home/mutations.js

0
src/store/state.js → src/store/modules/home/state.js

7
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;

3
src/store/modules/messages/getters.js

@ -0,0 +1,3 @@
const getters = {};
export default getters;

11
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 };

173
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;

15
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;

3
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(),

Loading…
Cancel
Save