diff --git a/.env.development b/.env.development
index c47ecb6..e409d34 100644
--- a/.env.development
+++ b/.env.development
@@ -7,4 +7,6 @@ VITE_APP_ENV = 'development'
# 若依管理系统/开发环境
VITE_APP_BASE_API = '/dev-api'
-VITE_PUBLIC_BASE_PATH=
+VITE_PUBLIC_BASE_PATH = ''
+
+VITE_APP_WS_API = 'ws://8.141.87.86:9018/'
diff --git a/.env.production b/.env.production
index 5d7eb08..8e31db1 100644
--- a/.env.production
+++ b/.env.production
@@ -8,4 +8,8 @@ VITE_APP_ENV = 'production'
VITE_APP_BASE_API = '/prod-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli
-VITE_BUILD_COMPRESS = gzip
\ No newline at end of file
+VITE_BUILD_COMPRESS = gzip
+
+VITE_PUBLIC_BASE_PATH = '/'
+
+VITE_APP_WS_API = ''
\ No newline at end of file
diff --git a/package.json b/package.json
index 0fe307e..06f885b 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,8 @@
},
"dependencies": {
"@element-plus/icons-vue": "2.0.10",
+ "@iamzzg/data-view": "^2.10.0",
+ "@jiaminghi/data-view": "^2.10.0",
"@vueup/vue-quill": "1.1.0",
"@vueuse/core": "9.5.0",
"axios": "0.27.2",
diff --git a/src/components/ZdScrollBoard/index.vue b/src/components/ZdScrollBoard/index.vue
new file mode 100644
index 0000000..9e8850b
--- /dev/null
+++ b/src/components/ZdScrollBoard/index.vue
@@ -0,0 +1,480 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/utils/websocket.js b/src/utils/websocket.js
new file mode 100644
index 0000000..d0f2278
--- /dev/null
+++ b/src/utils/websocket.js
@@ -0,0 +1,220 @@
+
+// websocket实例
+let wsObj = null
+// ws连接地址
+let wsUrl = null
+// let userId = null;
+// 是否执行重连 true/不执行 ; false/执行
+let lockReconnect = false
+// 重连定时器
+let wsCreateHandler = null
+// 连接成功,执行回调函数
+let messageCallback = null
+// 连接失败,执行回调函数
+let errorCallback = null
+// 发送给后台的数据
+let sendDatas = {}
+/**
+ * 发起websocket请求函数
+ * @param {string} url ws连接地址
+ * @param {Object} agentData 传给后台的参数
+ * @param {function} successCallback 接收到ws数据,对数据进行处理的回调函数
+ * @param {function} errCallback ws连接错误的回调函数
+ */
+export const connectWebsocket = (url = null, agentData, successCallback, errCallback) => {
+ //console.log(process.env);
+ if (!url) {
+ if (import.meta.env.VITE_APP_ENV == "production") {
+ wsUrl = `ws://${window.document.location.hostname}:9018/`
+ } else {
+ console.log(import.meta.env,'11111111');
+ wsUrl = import.meta.env.VITE_APP_WS_API
+ }
+
+ } else {
+ wsUrl = url
+ }
+ console.log('socket地址:',wsUrl);
+ createWebSoket()
+ messageCallback = successCallback
+ errorCallback = errCallback
+ sendDatas = agentData
+}
+
+// 手动关闭websocket (这里手动关闭会执行onclose事件)
+export const closeWebsocket = () => {
+ if (wsObj) {
+ writeToScreen('手动关闭websocket')
+ wsObj.close() // 关闭websocket
+ wsObj.onclose() // 关闭websocket(如果上面的关闭不生效就加上这一条)
+ // 关闭重连
+ lockReconnect = true
+ wsCreateHandler && clearTimeout(wsCreateHandler)
+ // 关闭心跳检查
+ heartCheck.stop()
+ }
+}
+
+// 创建ws函数
+const createWebSoket = () => {
+ if (typeof (WebSocket) === 'undefined') {
+ writeToScreen('您的浏览器不支持WebSocket,无法获取数据')
+ return false
+ }
+ // const host = window.location.host;
+ // userId = GetQueryString("userId");
+ // wsUrl = "ws://" + host + "/websoket" + userId;
+
+ try {
+ wsObj = new WebSocket(wsUrl)
+ initWsEventHandle()
+ } catch (e) {
+ writeToScreen('连接异常,开始重连')
+ reconnect()
+ }
+}
+
+const initWsEventHandle = () => {
+ try {
+ // 连接成功
+ wsObj.onopen = (event) => {
+ onWsOpen(event)
+ // heartCheck.start()
+ }
+
+ // 监听服务器端返回的信息
+ wsObj.onmessage = (event) => {
+ onWsMessage(event)
+ // heartCheck.start()
+ }
+
+ wsObj.onclose = (event) => {
+ writeToScreen('onclose执行关闭事件')
+ onWsClose(event)
+ }
+
+ wsObj.onerror = (event) => {
+ writeToScreen('onerror执行error事件,开始重连')
+ onWsError(event)
+ reconnect()
+ }
+ } catch (err) {
+ writeToScreen('绑定事件没有成功,开始重连')
+ reconnect()
+ }
+}
+
+const onWsOpen = (event) => {
+ writeToScreen('CONNECT')
+ // // 客户端与服务器端通信
+ // wsObj.send('我发送消息给服务端');
+ // 添加状态判断,当为OPEN时,发送消息
+ if (wsObj.readyState === wsObj.OPEN) { // wsObj.OPEN = 1
+ // 发给后端的数据需要字符串化
+ console.log('发送标识', sendDatas)
+ // wsObj.send(sendDatas)
+ }
+ if (wsObj.readyState === wsObj.CLOSED) { // wsObj.CLOSED = 3
+ writeToScreen('wsObj.readyState=3, ws连接异常,开始重连')
+ reconnect()
+ errorCallback()
+ }
+}
+const onWsMessage = (event) => {
+ if (event.data) {
+ messageCallback(event.data)
+ }
+ // const jsonStr = event.data
+ // writeToScreen('onWsMessage接收到服务器的数据: ', jsonStr)
+}
+const onWsClose = (event) => {
+ writeToScreen('DISCONNECT')
+ // e.code === 1000 表示正常关闭。 无论为何目的而创建, 该链接都已成功完成任务。
+ // e.code !== 1000 表示非正常关闭。
+ console.log('onclose event: ', event)
+ if (event && event.code !== 1000) {
+ writeToScreen('非正常关闭')
+ errorCallback()
+ // 如果不是手动关闭,这里的重连会执行;如果调用了手动关闭函数,这里重连不会执行
+ reconnect()
+ }
+}
+const onWsError = (event) => {
+ // writeToScreen('onWsError: ', event.data)
+ console.log(event);
+
+ errorCallback()
+}
+
+const writeToScreen = (massage) => {
+ console.log(massage)
+}
+
+// 重连函数
+const reconnect = () => {
+ if (lockReconnect) {
+ return
+ }
+ writeToScreen('3秒后重连')
+ lockReconnect = true
+ // 没连接上会一直重连,设置延迟避免请求过多
+ wsCreateHandler && clearTimeout(wsCreateHandler)
+ wsCreateHandler = setTimeout(() => {
+ writeToScreen('重连...' + wsUrl)
+ createWebSoket()
+ lockReconnect = false
+ writeToScreen('重连完成')
+ }, 3000)
+}
+
+// 从浏览器地址中获取对应参数
+// eslint-disable-next-line no-unused-vars
+const GetQueryString = (name) => {
+ let reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i')
+ // 获取url中 ? 符后的字符串并正则匹配
+ let r = window.location.search.substr(1).match(reg)
+ let context = ''
+ r && (context = r[2])
+ reg = null
+ r = null
+ return context
+}
+
+// 心跳检查(看看websocket是否还在正常连接中)
+const heartCheck = {
+ timeout: 60000,
+ timeoutObj: null,
+ serverTimeoutObj: null,
+ // 重启
+ reset() {
+ clearTimeout(this.timeoutObj)
+ clearTimeout(this.serverTimeoutObj)
+ this.start()
+ },
+ // 停止
+ stop() {
+ clearTimeout(this.timeoutObj)
+ clearTimeout(this.serverTimeoutObj)
+ },
+ // 开启定时器
+ start() {
+ this.timeoutObj && clearTimeout(this.timeoutObj)
+ this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj)
+ // 15s之内如果没有收到后台的消息,则认为是连接断开了,需要重连
+ this.timeoutObj = setTimeout(() => {
+ writeToScreen('心跳检查,发送ping到后台')
+ try {
+ const datas = { ping: true }
+ wsObj.send(JSON.stringify(datas))
+ } catch (err) {
+ writeToScreen('发送ping异常')
+ }
+ console.log('内嵌定时器this.serverTimeoutObj: ', this.serverTimeoutObj)
+ // 内嵌定时器
+ this.serverTimeoutObj = setTimeout(() => {
+ writeToScreen('没有收到后台的数据,重新连接')
+ reconnect()
+ }, 100)
+ }, this.timeout)
+ }
+}
diff --git a/src/views/screen/R_D_Environment/component/barChart.vue b/src/views/screen/R_D_Environment/component/barChart.vue
index 95f74a6..617f70a 100644
--- a/src/views/screen/R_D_Environment/component/barChart.vue
+++ b/src/views/screen/R_D_Environment/component/barChart.vue
@@ -35,11 +35,21 @@ const options = computed(() => {
padding: 10,
extraCssText: 'border-radius: 8px; box-shadow: 0 0 15px rgba(0, 0, 0, 0.5);'
},
+ backgroundColor: 'transparent',
+ legend: {
+ show: true,
+ data: ['目标产量', '实际产量'],
+ textStyle: {
+ color: '#fff',
+
+ },
+ },
xAxis: {
type: 'category',
- data: ['办公室1', '办公室2', '办公室3', '办公室4', '办公室5'],
+ data: ['102410', '102411', '102412', '102413', '102414', '102415', '102416', '102417'],
axisLabel: {
color: "#ffffff",
+ interval: 0,
},
axisLine: {
lineStyle: {
@@ -47,58 +57,29 @@ const options = computed(() => {
}
},
axisTick: {
- show: false
+ show: false,
}
},
- yAxis: [{
- name:'次',
- type: 'value',
- splitLine: {
- show: false,
- lineStyle: {
- color: '#1e90ff',
- type: 'dashed'
+ yAxis: [
+ {
+ type: 'value',
+ axisTick: {
+ show: false
}
},
- axisLabel: {
- color: "#ffffff"
- },
- axisLine: {
- lineStyle: {
- color: '#0091ea'
+ {
+ type: 'value',
+ axisTick: {
+ show: false
}
- },
- axisTick: {
- show: false
}
- }, {
- name:'kWh',
- type: 'value',
- splitLine: {
- show: false,
- lineStyle: {
- color: '#1e90ff',
- type: 'dashed'
- }
- },
- axisLabel: {
- color: "#ffffff"
- },
- axisLine: {
- lineStyle: {
- color: '#0091ea'
- }
- },
- axisTick: {
- show: false
- }
- }],
+ ],
series: [
{
- name: '开关次数',
- data: [106, 90, 25, 0, 35],
+ name: '目标产量',
+ data: [150, 105, 110, 80, 120, 100, 140, 180],
+ yAxisIndex: 0,
type: 'bar',
- barWidth: '20',
barCategoryGap: '10%',
showBackground: true,
itemStyle: {
@@ -109,8 +90,8 @@ const options = computed(() => {
x2: 1,
y2: 1,
colorStops: [
- { offset: 0, color: '#00c6ff' },
- { offset: 1, color: '#0072ff' }
+ { offset: 0, color: '#5aaef3' },
+ { offset: 1, color: '#1e90ff' }
]
},
borderRadius: [60, 60, 60, 60],
@@ -127,11 +108,10 @@ const options = computed(() => {
}
},
{
- name: '用电量',
- data: [210, 30, 110, 80, 120],
+ name: '实际产量',
yAxisIndex: 1,
+ data: [106, 90, 25, 80, 35, 100, 140, 172],
type: 'bar',
- barWidth: '20',
barCategoryGap: '10%',
showBackground: true,
itemStyle: {
@@ -142,12 +122,12 @@ const options = computed(() => {
x2: 1,
y2: 1,
colorStops: [
- { offset: 0, color: '#00c6ff' },
- { offset: 1, color: '#0072ff' }
+ { offset: 0, color: '#f8efd4' },
+ { offset: 1, color: '#fbdc7f' }
]
},
borderRadius: [60, 60, 60, 60],
- stroke: '#00c6ff',
+ stroke: '#ff6347',
lineWidth: 2
},
label: {
@@ -159,9 +139,8 @@ const options = computed(() => {
borderRadius: [60, 60, 60, 60],
}
},
-
],
- };;
+ }
});
diff --git a/src/views/screen/R_D_Environment/component/item.vue b/src/views/screen/R_D_Environment/component/item.vue
index 6e9c245..8cda8eb 100644
--- a/src/views/screen/R_D_Environment/component/item.vue
+++ b/src/views/screen/R_D_Environment/component/item.vue
@@ -35,9 +35,11 @@ const prop = defineProps({
color: #fff;
}
.pos-l {
+ // background: linear-gradient(to right, #102238 0%, transparent 100%);
background: url('/src/assets/images/box-title-l.png') no-repeat center center / 100% 100%;
}
.pos-r {
+ // background: linear-gradient(to left, #102238 0%, transparent 100%);
background: url('/src/assets/images/box-title-r.png') no-repeat center center / 100% 100%;
text-align: right;
padding-right: 25px;
diff --git a/src/views/screen/R_D_Environment/index.vue b/src/views/screen/R_D_Environment/index.vue
index ab1f4a4..548e2f0 100644
--- a/src/views/screen/R_D_Environment/index.vue
+++ b/src/views/screen/R_D_Environment/index.vue
@@ -20,10 +20,11 @@
-
-
-
+
+
+
+
{{ item.value + item.unit }}
{{ item.name }}
@@ -55,6 +56,8 @@
+
@@ -83,7 +86,9 @@ import SvgTVOC from './component/svgTVOC.vue';
import SvgShidu from './component/svgShidu.vue';
import SvgWendu from './component/svgWendu.vue';
import SvgYanwu from './component/svgYanwu.vue';
-import { getNoiseData,getTopData,getSensorDateHourByType } from '@/api/screen/R_D_Environment';
+import ZdScrollBoard from "@/components/ZdScrollBoard/index.vue";
+import { connectWebsocket, closeWebsocket } from '@/utils/websocket';
+import { getNoiseData, getTopData, getSensorDateHourByType } from '@/api/screen/R_D_Environment';
let noiseDataList = ref([
{
@@ -103,7 +108,7 @@ let sensor_list = reactive([
value: 20,
unit: '℃',
type: 'AirTemp_Reg',
- limit: 30,
+ limit: 40,
status: "true"
},
{
@@ -113,7 +118,7 @@ let sensor_list = reactive([
value: 20,
unit: '%',
type: 'AirHumi_Reg',
- limit: 30,
+ limit: 90,
status: "true"
},
{
@@ -123,7 +128,7 @@ let sensor_list = reactive([
value: 20,
unit: 'mg/m³',
type: 'CH2O',
- limit: 30,
+ limit: 0.08,
status: "true"
},
{
@@ -133,7 +138,7 @@ let sensor_list = reactive([
value: 20,
unit: 'mg/m³',
type: 'TVOC',
- limit: 30,
+ limit: 0.5,
status: "true"
},
{
@@ -142,7 +147,7 @@ let sensor_list = reactive([
component: SvgPm25,
value: 20,
unit: 'mg/m³',
- type:'HIGH_PM25_Reg',
+ type: 'HIGH_PM25_Reg',
limit: 30,
status: "true"
},
@@ -152,7 +157,7 @@ let sensor_list = reactive([
component: SvgPm10,
value: 20,
unit: 'mg/m³',
- type:'HIGH_PM10_Reg',
+ type: 'HIGH_PM10_Reg',
limit: 30,
status: "true"
},
@@ -162,8 +167,8 @@ let sensor_list = reactive([
component: SvgZaosheng,
value: 20,
unit: 'dB',
- type:'Noise_Reg',
- limit: 30,
+ type: 'Noise_Reg',
+ limit: 85,
status: "true"
},
{
@@ -172,8 +177,8 @@ let sensor_list = reactive([
component: SvgYanwu,
value: 20,
unit: 'mg/m³',
- type:'Smoke_Reg',
- limit: 30,
+ type: 'Smoke_Reg',
+ limit: 100,
status: "true"
}
])
@@ -181,11 +186,28 @@ let dustData = reactive({
pm25: 0,
pm10: 0,
})
+
+let zd_config = ref({
+ header: ['报警时间', '报警内容', '报警位置'],
+ rowNum: 4,
+ data: [
+ ['行1列1', '行1列2', '行1列3'],
+ ['行2列1', '行2列2', '行2列3'],
+ ['行3列1', '行3列2', '行3列3'],
+ ['行4列1', '行4列2', '行4列3'],
+ ['行5列1', '行5列2', '行5列3'],
+ ['行6列1', '行6列2', '行6列3'],
+ ['行7列1', '行7列2', '行7列3'],
+ ['行8列1', '行8列2', '行8列3'],
+ ['行9列1', '行9列2', '行9列3'],
+ ['行10列1', '行10列2', '行10列3']
+ ]
+})
//检测是否超标
function checkCb(item) {
if (item.status === 'false') {
return 'gray'
- }else if (item.value > item.limit) {
+ } else if (item.value > item.limit) {
return '#FF0000'
} else {
return '#469DE9'
@@ -205,7 +227,7 @@ function getNoiseDataList() {
function getTopDataList() {
getTopData().then(res => {
if (res.code === 200) {
- res.data.forEach(item =>{
+ res.data.forEach(item => {
let index = sensor_list.findIndex(sensor => sensor.type === item.type)
sensor_list[index].value = item.data
sensor_list[index].id = item.id
@@ -215,7 +237,7 @@ function getTopDataList() {
dustData.pm25 = item.data
} else if (item.type === 'HIGH_PM10_Reg') {
dustData.pm10 = item.data
-
+
}
})
@@ -233,9 +255,97 @@ function getSensorData(type) {
}
+//socket
+function getWebsocket(val) {
+ try {
+ let data = JSON.parse(val);
+
+ if (data.type == "HUMI_TEMP") {
+ let obj = data.msg;
+ if (obj.hasOwnProperty('temp')) {
+ let index = sensor_list.findIndex(sensor => sensor.type === 'AirTemp_Reg' && sensor.id === obj.temp.devId)
+ if (index !== -1) {
+ sensor_list[index].value = obj.temp.value
+ sensor_list[index].status = "true"
+ }
+
+ }
+ if (obj.hasOwnProperty('humi')) {
+ let index = sensor_list.findIndex(sensor => sensor.type === 'AirHumi_Reg' && sensor.id === obj.humi.devId)
+ if (index !== -1) {
+ sensor_list[index].value = obj.humi.value
+ sensor_list[index].status = "true"
+ }
+
+ }
+ }
+ if (data.type == "TVOC_CH2O") {
+ let obj = data.msg;
+ if (obj.hasOwnProperty('CH2O')) {
+ let index = sensor_list.findIndex(sensor => sensor.type === 'CH2O' && sensor.id === obj.CH2O.devId)
+ if (index !== -1) {
+ sensor_list[index].value = obj.CH2O.value
+ sensor_list[index].status = "true"
+ }
+
+ }
+ if (obj.hasOwnProperty('TVOC')) {
+ let index = sensor_list.findIndex(sensor => sensor.type === 'TVOC' && sensor.id === obj.TVOC.devId)
+ if (index !== -1) {
+ sensor_list[index].value = obj.TVOC.value
+ sensor_list[index].status = "true"
+ }
+
+ }
+ }
+ //粉尘
+ if (data.type == "dust") {
+ let obj = data.msg;
+
+
+ let index_pm25 = sensor_list.findIndex(sensor => sensor.type === 'HIGH_PM25_Reg' && sensor.id === obj.devId)
+ let index_pm10 = sensor_list.findIndex(sensor => sensor.type === 'HIGH_PM10_Reg' && sensor.id === obj.devId)
+ if (index_pm25 !== -1) {
+ sensor_list[index_pm25].value = obj.pm25
+ sensor_list[index_pm25].status = "true"
+ dustData.pm25 = obj.pm25
+ }
+ if (index_pm10 !== -1) {
+ sensor_list[index_pm10].value = obj.pm10
+ sensor_list[index_pm10].status = "true"
+ dustData.pm10 = obj.pm10
+ }
+ }
+ //噪音
+ if (data.type === "NOISE") {
+ let obj = data.msg;
+ let list_index = noiseDataList.value.findIndex(item => item.devId === obj.noise.devId)
+ if (list_index !== -1) {
+ noiseDataList.value[list_index].data = obj.noise.value
+ } else {
+ let index = sensor_list.findIndex(sensor => sensor.type === 'Noise_Reg' && sensor.id === obj.noise.devId)
+ if (index !== -1) {
+ sensor_list[index].value = obj.noise.value
+ sensor_list[index].status = "true"
+ }
+ }
+ }
+ } catch (err) {
+ console.log(err);
+ }
+}
+function errWebsocket(val) {
+ // console.log(val);
+}
+
+
onMounted(() => {
getNoiseDataList()
getTopDataList()
+
+
+
+ connectWebsocket(null, null, getWebsocket, errWebsocket);
});
@@ -274,7 +384,8 @@ onMounted(() => {
width: 410px;
height: 980px;
z-index: 2;
- background: url('/src/assets/images/preview-left.png') center center / 100% 100% no-repeat;
+ background: linear-gradient(to left, transparent 0%, rgba(15, 32, 54, 0.8) 50%, #102238 100%);
+ // background: url('/src/assets/images/preview-left.png') center center / 100% 100% no-repeat;
display: flex;
flex-direction: column;
justify-content: space-between;
@@ -329,7 +440,9 @@ onMounted(() => {
display: flex;
z-index: 2;
justify-content: space-between;
- background: url('/src/assets/images/preview-bottom.png') center center / 100% 100% no-repeat;
+
+ background: linear-gradient(to bottom, transparent 0%, rgba(15, 32, 54, 0.8) 50%, #102238 100%);
+ // background: url('/src/assets/images/preview-bottom.png') center center / 100% 100% no-repeat;
.cbox {
width: 48%;
@@ -349,7 +462,7 @@ onMounted(() => {
flex-direction: column;
justify-content: space-between;
align-items: center;
- background: url('/src/assets/images/preview-right.png') center center / 100% 100% no-repeat;
+ background: linear-gradient(to right, transparent 0%, rgba(15, 32, 54, 0.8) 50%, #102238 100%);
.rbox-item {
width: 100%;
diff --git a/vite.config.js b/vite.config.js
index 97fdf4e..72fe564 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -31,8 +31,8 @@ export default defineConfig(({ mode, command }) => {
proxy: {
// https://cn.vitejs.dev/config/#server-proxy
'/dev-api': {
- // target: 'http://192.168.10.98:9015',
- target: 'http://8.141.87.86:9015',
+ target: 'http://192.168.10.97:9015',
+ // target: 'http://8.141.87.86:9015',
// target: 'http://192.168.110.90:10393/mock/5ce74738-f63f-4d21-af85-b1d132c6f6fd',
changeOrigin: true,
rewrite: (p) => p.replace(/^\/dev-api/, '')