This commit is contained in:
hzz 2024-11-22 16:58:50 +08:00
parent 849a38795c
commit 482f6392a6
9 changed files with 881 additions and 79 deletions

View File

@ -7,4 +7,6 @@ VITE_APP_ENV = 'development'
# 若依管理系统/开发环境 # 若依管理系统/开发环境
VITE_APP_BASE_API = '/dev-api' VITE_APP_BASE_API = '/dev-api'
VITE_PUBLIC_BASE_PATH= VITE_PUBLIC_BASE_PATH = ''
VITE_APP_WS_API = 'ws://8.141.87.86:9018/'

View File

@ -9,3 +9,7 @@ VITE_APP_BASE_API = '/prod-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli # 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip VITE_BUILD_COMPRESS = gzip
VITE_PUBLIC_BASE_PATH = '/'
VITE_APP_WS_API = ''

View File

@ -16,6 +16,8 @@
}, },
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "2.0.10", "@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", "@vueup/vue-quill": "1.1.0",
"@vueuse/core": "9.5.0", "@vueuse/core": "9.5.0",
"axios": "0.27.2", "axios": "0.27.2",

View File

@ -0,0 +1,480 @@
<template>
<div class="zd-scroll-board" :ref="ref">
<div class="header" v-if="header.length && mergedConfig" :style="`background-color: ${mergedConfig.headerBGC};`">
<div class="header-item" v-for="(headerItem, i) in header" :key="`${headerItem}${i}`" :style="`
height: ${mergedConfig.headerHeight}px;
line-height: ${mergedConfig.headerHeight}px;
width: ${widths[i]}px;
`" :align="aligns[i]" v-html="headerItem" />
</div>
<div v-if="mergedConfig" class="rows"
:style="`height: ${height - (header.length ? mergedConfig.headerHeight : 0)}px;`">
<div class="row-item" v-for="(row, ri) in rows" :key="`${row.toString()}${row.scroll}`" :style="`
height: ${heights[ri]}px; line-height: ${heights[ri]}px;
background-color: ${mergedConfig[row.rowIndex % 2 === 0 ? 'evenRowBGC' : 'oddRowBGC']};`">
<div class="ceil" :class="{'ceil-wrap':wraps[ci]}" v-for="(ceil, ci) in row.ceils" :key="`${ceil}${ri}${ci}`"
:style="`width: ${widths[ci]}px;justify-content:${wraps[ci]?align_hash[aligns[ci]]:''}`" :align="aligns[ci]" v-html="ceil"
@click="emitEvent('click', ri, ci, row, ceil)" @mouseenter="handleHover(true, ri, ci, row, ceil)"
@mouseleave="handleHover(false)" />
</div>
</div>
</div>
</template>
<script>
import autoResize from '@jiaminghi/data-view/lib/mixin/autoResize'
import { deepMerge } from '@jiaminghi/charts/lib/util/index'
import { deepClone } from '@jiaminghi/c-render/lib/plugin/util'
export default {
name: 'ZdScrollBoard',
mixins: [autoResize],
props: {
config: {
type: Object,
default: () => ({})
}
},
data() {
return {
ref: 'scroll-board',
align_hash: {
left: 'flex-start',
center: 'center',
right: 'flex-end',
justify: 'space-between'
},
defaultConfig: {
/**
* @description Board header
* @type {Array<String>}
* @default header = []
* @example header = ['column1', 'column2', 'column3']
*/
header: [],
/**
* @description Board data
* @type {Array<Array>}
* @default data = []
*/
data: [],
/**
* @description Row num
* @type {Number}
* @default rowNum = 5
*/
rowNum: 5,
/**
* @description Header background color
* @type {String}
* @default headerBGC = '#00BAFF'
*/
headerBGC: '#00BAFF',
/**
* @description Odd row background color
* @type {String}
* @default oddRowBGC = '#003B51'
*/
oddRowBGC: '#003B51',
/**
* @description Even row background color
* @type {String}
* @default evenRowBGC = '#003B51'
*/
evenRowBGC: '#0A2732',
/**
* @description Scroll wait time
* @type {Number}
* @default waitTime = 2000
*/
waitTime: 2000,
/**
* @description Header height
* @type {Number}
* @default headerHeight = 35
*/
headerHeight: 35,
/**
* @description Column width
* @type {Array<Number>}
* @default columnWidth = []
*/
columnWidth: [],
/**
* @description Column align
* @type {Array<String>}
* @default align = []
* @example align = ['left', 'center', 'right']
*/
align: [],
/**
* @description Show index
* @type {Boolean}
* @default index = false
*/
index: false,
/**
* @description index Header
* @type {String}
* @default indexHeader = '#'
*/
indexHeader: '#',
/**
* @description Carousel type
* @type {String}
* @default carousel = 'single'
* @example carousel = 'single' | 'page'
*/
carousel: 'single',
/**
* @description Pause scroll when mouse hovered
* @type {Boolean}
* @default hoverPause = true
* @example hoverPause = true | false
*/
hoverPause: true
},
mergedConfig: null,
header: [],
rowsData: [],
rows: [],
widths: [],
heights: [],
avgHeight: 0,
aligns: [],
//
wraps: [],
animationIndex: 0,
animationHandler: '',
updater: 0,
needCalc: false
}
},
watch: {
// config () {
// console.log("");
// const { stopAnimation, calcData } = this
// stopAnimation()
// this.animationIndex = 0
// calcData()
// }
config: {
handler(newValue, oldValue) {
const { stopAnimation, calcData } = this
stopAnimation()
this.animationIndex = 0
calcData()
},
deep: true
}
},
methods: {
handleHover(enter, ri, ci, row, ceil) {
const { mergedConfig, emitEvent, stopAnimation, animation } = this
if (enter) { emitEvent('mouseover', ri, ci, row, ceil) } else {
this.$emit('mouseend')
}
if (!mergedConfig.hoverPause) return
if (enter) {
stopAnimation()
} else {
animation(true)
}
},
afterAutoResizeMixinInit() {
const { calcData } = this
calcData()
},
onResize() {
const { mergedConfig, calcWidths, calcHeights } = this
if (!mergedConfig) return
calcWidths()
calcHeights()
},
calcData() {
const { mergeConfig, calcHeaderData, calcRowsData } = this
mergeConfig()
calcHeaderData()
calcRowsData()
const { calcWidths, calcHeights, calcAligns } = this
calcWidths()
calcHeights()
calcAligns()
const { animation } = this
animation(true)
},
mergeConfig() {
let { config, defaultConfig } = this
this.mergedConfig = deepMerge(deepClone(defaultConfig, true), config || {})
},
calcHeaderData() {
let { header, index, indexHeader } = this.mergedConfig
if (!header.length) {
this.header = []
return
}
header = [...header]
if (index) header.unshift(indexHeader)
this.header = header
},
calcRowsData() {
let { data, index, headerBGC, rowNum } = this.mergedConfig
if (index) {
data = data.map((row, i) => {
row = [...row]
const indexTag = `<span class="index" style="background-color: ${headerBGC};">${i + 1}</span>`
row.unshift(indexTag)
return row
})
}
data = data.map((ceils, i) => ({ ceils, rowIndex: i }))
const rowLength = data.length
if (rowLength > rowNum && rowLength < 2 * rowNum) {
data = [...data, ...data]
}
data = data.map((d, i) => ({ ...d, scroll: i }))
this.rowsData = data
this.rows = data
},
calcWidths() {
const { width, mergedConfig, rowsData } = this
const { columnWidth, header } = mergedConfig
const usedWidth = columnWidth.reduce((all, w) => all + w, 0)
let columnNum = 0
if (rowsData[0]) {
columnNum = rowsData[0].ceils.length
} else if (header.length) {
columnNum = header.length
}
const avgWidth = (width - usedWidth) / (columnNum - columnWidth.length)
const widths = new Array(columnNum).fill(avgWidth)
this.widths = deepMerge(widths, columnWidth)
},
calcHeights(onresize = false) {
const { height, mergedConfig, header } = this
const { headerHeight, rowNum, data } = mergedConfig
let allHeight = height
if (header.length) allHeight -= headerHeight
const avgHeight = allHeight / rowNum
this.avgHeight = avgHeight
if (!onresize) this.heights = new Array(data.length).fill(avgHeight)
},
calcAligns() {
const { header, mergedConfig } = this
const columnNum = header.length
let aligns = new Array(columnNum).fill('left')
let wraps = new Array(columnNum).fill(false)
const { align,wrap } = mergedConfig
this.aligns = deepMerge(aligns, align)
this.wraps = deepMerge(wraps, wrap)
},
async animation(start = false) {
const { needCalc, calcHeights, calcRowsData } = this
if (needCalc) {
calcRowsData()
calcHeights()
this.needCalc = false
}
let { avgHeight, animationIndex, mergedConfig, rowsData, animation, updater } = this
const { waitTime, carousel, rowNum } = mergedConfig
const rowLength = rowsData.length
if (rowNum >= rowLength) return
if (start) {
await new Promise(resolve => setTimeout(resolve, waitTime))
if (updater !== this.updater) return
}
const animationNum = carousel === 'single' ? 1 : rowNum
let rows = rowsData.slice(animationIndex)
rows.push(...rowsData.slice(0, animationIndex))
this.rows = rows.slice(0, carousel === 'page' ? rowNum * 2 : rowNum + 1)
this.heights = new Array(rowLength).fill(avgHeight)
await new Promise(resolve => setTimeout(resolve, 300))
if (updater !== this.updater) return
this.heights.splice(0, animationNum, ...new Array(animationNum).fill(0))
animationIndex += animationNum
const back = animationIndex - rowLength
if (back >= 0) animationIndex = back
this.animationIndex = animationIndex
this.animationHandler = setTimeout(animation, waitTime - 300)
},
stopAnimation() {
const { animationHandler, updater } = this
this.updater = (updater + 1) % 999999
if (!animationHandler) return
clearTimeout(animationHandler)
},
emitEvent(type, ri, ci, row, ceil) {
const { ceils, rowIndex } = row
this.$emit(type, {
row: ceils,
ceil,
rowIndex,
columnIndex: ci
})
},
updateRows(rows, config, animationIndex) {
const { mergedConfig, animationHandler, animation } = this
this.mergedConfig = {
...mergedConfig,
data: [...rows],
...config
}
this.needCalc = true
if (typeof animationIndex === 'number') this.animationIndex = animationIndex
if (!animationHandler) animation(true)
}
},
destroyed() {
const { stopAnimation } = this
stopAnimation()
}
}
</script>
<style scoped>
.zd-scroll-board {
position: relative;
width: 100%;
height: 100%;
color: #fff;
}
.zd-scroll-board .text {
padding: 0 10px;
box-sizing: border-box;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.zd-scroll-board .header {
display: flex;
flex-direction: row;
font-size: 15px;
}
.zd-scroll-board .header .header-item {
padding: 0 10px;
box-sizing: border-box;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
transition: all 0.3s;
}
.zd-scroll-board .rows {
overflow: hidden;
}
.zd-scroll-board .rows .row-item {
display: flex;
font-size: 14px;
transition: all 0.3s;
}
.zd-scroll-board .rows .ceil {
padding: 0 10px;
box-sizing: border-box;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.zd-scroll-board .rows .ceil-wrap {
display: flex;
line-height: normal;
white-space: normal;
flex-wrap: wrap;
align-items: center;
}
.zd-scroll-board .rows .index {
border-radius: 3px;
padding: 0px 3px;
}
</style>

220
src/utils/websocket.js Normal file
View File

@ -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)
}
}

View File

@ -35,11 +35,21 @@ const options = computed(() => {
padding: 10, padding: 10,
extraCssText: 'border-radius: 8px; box-shadow: 0 0 15px rgba(0, 0, 0, 0.5);' 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: { xAxis: {
type: 'category', type: 'category',
data: ['办公室1', '办公室2', '办公室3', '办公室4', '办公室5'], data: ['102410', '102411', '102412', '102413', '102414', '102415', '102416', '102417'],
axisLabel: { axisLabel: {
color: "#ffffff", color: "#ffffff",
interval: 0,
}, },
axisLine: { axisLine: {
lineStyle: { lineStyle: {
@ -47,58 +57,29 @@ const options = computed(() => {
} }
}, },
axisTick: { axisTick: {
show: false show: false,
} }
}, },
yAxis: [{ yAxis: [
name:'次', {
type: 'value', type: 'value',
splitLine: { axisTick: {
show: false, show: false
lineStyle: {
color: '#1e90ff',
type: 'dashed'
} }
}, },
axisLabel: { {
color: "#ffffff" type: 'value',
}, axisTick: {
axisLine: { show: false
lineStyle: {
color: '#0091ea'
} }
},
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: [ series: [
{ {
name: '开关次数', name: '目标产量',
data: [106, 90, 25, 0, 35], data: [150, 105, 110, 80, 120, 100, 140, 180],
yAxisIndex: 0,
type: 'bar', type: 'bar',
barWidth: '20',
barCategoryGap: '10%', barCategoryGap: '10%',
showBackground: true, showBackground: true,
itemStyle: { itemStyle: {
@ -109,8 +90,8 @@ const options = computed(() => {
x2: 1, x2: 1,
y2: 1, y2: 1,
colorStops: [ colorStops: [
{ offset: 0, color: '#00c6ff' }, { offset: 0, color: '#5aaef3' },
{ offset: 1, color: '#0072ff' } { offset: 1, color: '#1e90ff' }
] ]
}, },
borderRadius: [60, 60, 60, 60], borderRadius: [60, 60, 60, 60],
@ -127,11 +108,10 @@ const options = computed(() => {
} }
}, },
{ {
name: '用电量', name: '实际产量',
data: [210, 30, 110, 80, 120],
yAxisIndex: 1, yAxisIndex: 1,
data: [106, 90, 25, 80, 35, 100, 140, 172],
type: 'bar', type: 'bar',
barWidth: '20',
barCategoryGap: '10%', barCategoryGap: '10%',
showBackground: true, showBackground: true,
itemStyle: { itemStyle: {
@ -142,12 +122,12 @@ const options = computed(() => {
x2: 1, x2: 1,
y2: 1, y2: 1,
colorStops: [ colorStops: [
{ offset: 0, color: '#00c6ff' }, { offset: 0, color: '#f8efd4' },
{ offset: 1, color: '#0072ff' } { offset: 1, color: '#fbdc7f' }
] ]
}, },
borderRadius: [60, 60, 60, 60], borderRadius: [60, 60, 60, 60],
stroke: '#00c6ff', stroke: '#ff6347',
lineWidth: 2 lineWidth: 2
}, },
label: { label: {
@ -159,9 +139,8 @@ const options = computed(() => {
borderRadius: [60, 60, 60, 60], borderRadius: [60, 60, 60, 60],
} }
}, },
], ],
};; }
}); });
</script> </script>

View File

@ -35,9 +35,11 @@ const prop = defineProps({
color: #fff; color: #fff;
} }
.pos-l { .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%; background: url('/src/assets/images/box-title-l.png') no-repeat center center / 100% 100%;
} }
.pos-r { .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%; background: url('/src/assets/images/box-title-r.png') no-repeat center center / 100% 100%;
text-align: right; text-align: right;
padding-right: 25px; padding-right: 25px;

View File

@ -20,9 +20,10 @@
</div> </div>
<div class="ct-box"> <div class="ct-box">
<div class="ct-sensor"> <div class="ct-sensor">
<div class="sensor-item" v-for="item in sensor_list"> <!-- :style="{color:item.status == 'true'?'#469DE9':'gray'}" --> <div class="sensor-item" v-for="item in sensor_list">
<component style="width: 75px;height: 75px;margin-top: 10px;" :is="item.component" <!-- :style="{color:item.status == 'true'?'#469DE9':'gray'}" -->
:value="item.value" :color="checkCb(item)" :unit="item.unit" /><!-- item.status == 'true'?'#469DE9':'gray' --> <component style="width: 75px;height: 75px;margin-top: 10px;" :is="item.component" :value="item.value"
:color="checkCb(item)" :unit="item.unit" /><!-- item.status == 'true'?'#469DE9':'gray' -->
<div style="margin: 10px 0">{{ item.value + item.unit }}</div> <div style="margin: 10px 0">{{ item.value + item.unit }}</div>
<div>{{ item.name }}</div> <div>{{ item.name }}</div>
@ -55,6 +56,8 @@
</div> </div>
<div class="rbox-item"> <div class="rbox-item">
<ItemVue title="告警信息" pos="right"> <ItemVue title="告警信息" pos="right">
<ZdScrollBoard ref="devList" :config="zd_config"
:style="{ width: '100%', height: '260px', 'padding-top': '10px' }" />
</ItemVue> </ItemVue>
</div> </div>
</div> </div>
@ -83,7 +86,9 @@ import SvgTVOC from './component/svgTVOC.vue';
import SvgShidu from './component/svgShidu.vue'; import SvgShidu from './component/svgShidu.vue';
import SvgWendu from './component/svgWendu.vue'; import SvgWendu from './component/svgWendu.vue';
import SvgYanwu from './component/svgYanwu.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([ let noiseDataList = ref([
{ {
@ -103,7 +108,7 @@ let sensor_list = reactive([
value: 20, value: 20,
unit: '℃', unit: '℃',
type: 'AirTemp_Reg', type: 'AirTemp_Reg',
limit: 30, limit: 40,
status: "true" status: "true"
}, },
{ {
@ -113,7 +118,7 @@ let sensor_list = reactive([
value: 20, value: 20,
unit: '%', unit: '%',
type: 'AirHumi_Reg', type: 'AirHumi_Reg',
limit: 30, limit: 90,
status: "true" status: "true"
}, },
{ {
@ -123,7 +128,7 @@ let sensor_list = reactive([
value: 20, value: 20,
unit: 'mg/m³', unit: 'mg/m³',
type: 'CH2O', type: 'CH2O',
limit: 30, limit: 0.08,
status: "true" status: "true"
}, },
{ {
@ -133,7 +138,7 @@ let sensor_list = reactive([
value: 20, value: 20,
unit: 'mg/m³', unit: 'mg/m³',
type: 'TVOC', type: 'TVOC',
limit: 30, limit: 0.5,
status: "true" status: "true"
}, },
{ {
@ -142,7 +147,7 @@ let sensor_list = reactive([
component: SvgPm25, component: SvgPm25,
value: 20, value: 20,
unit: 'mg/m³', unit: 'mg/m³',
type:'HIGH_PM25_Reg', type: 'HIGH_PM25_Reg',
limit: 30, limit: 30,
status: "true" status: "true"
}, },
@ -152,7 +157,7 @@ let sensor_list = reactive([
component: SvgPm10, component: SvgPm10,
value: 20, value: 20,
unit: 'mg/m³', unit: 'mg/m³',
type:'HIGH_PM10_Reg', type: 'HIGH_PM10_Reg',
limit: 30, limit: 30,
status: "true" status: "true"
}, },
@ -162,8 +167,8 @@ let sensor_list = reactive([
component: SvgZaosheng, component: SvgZaosheng,
value: 20, value: 20,
unit: 'dB', unit: 'dB',
type:'Noise_Reg', type: 'Noise_Reg',
limit: 30, limit: 85,
status: "true" status: "true"
}, },
{ {
@ -172,8 +177,8 @@ let sensor_list = reactive([
component: SvgYanwu, component: SvgYanwu,
value: 20, value: 20,
unit: 'mg/m³', unit: 'mg/m³',
type:'Smoke_Reg', type: 'Smoke_Reg',
limit: 30, limit: 100,
status: "true" status: "true"
} }
]) ])
@ -181,11 +186,28 @@ let dustData = reactive({
pm25: 0, pm25: 0,
pm10: 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) { function checkCb(item) {
if (item.status === 'false') { if (item.status === 'false') {
return 'gray' return 'gray'
}else if (item.value > item.limit) { } else if (item.value > item.limit) {
return '#FF0000' return '#FF0000'
} else { } else {
return '#469DE9' return '#469DE9'
@ -205,7 +227,7 @@ function getNoiseDataList() {
function getTopDataList() { function getTopDataList() {
getTopData().then(res => { getTopData().then(res => {
if (res.code === 200) { if (res.code === 200) {
res.data.forEach(item =>{ res.data.forEach(item => {
let index = sensor_list.findIndex(sensor => sensor.type === item.type) let index = sensor_list.findIndex(sensor => sensor.type === item.type)
sensor_list[index].value = item.data sensor_list[index].value = item.data
sensor_list[index].id = item.id sensor_list[index].id = item.id
@ -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(() => { onMounted(() => {
getNoiseDataList() getNoiseDataList()
getTopDataList() getTopDataList()
connectWebsocket(null, null, getWebsocket, errWebsocket);
}); });
</script> </script>
@ -274,7 +384,8 @@ onMounted(() => {
width: 410px; width: 410px;
height: 980px; height: 980px;
z-index: 2; 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; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
@ -329,7 +440,9 @@ onMounted(() => {
display: flex; display: flex;
z-index: 2; z-index: 2;
justify-content: space-between; 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 { .cbox {
width: 48%; width: 48%;
@ -349,7 +462,7 @@ onMounted(() => {
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
align-items: center; 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 { .rbox-item {
width: 100%; width: 100%;

View File

@ -31,8 +31,8 @@ export default defineConfig(({ mode, command }) => {
proxy: { proxy: {
// https://cn.vitejs.dev/config/#server-proxy // https://cn.vitejs.dev/config/#server-proxy
'/dev-api': { '/dev-api': {
// target: 'http://192.168.10.98:9015', target: 'http://192.168.10.97:9015',
target: 'http://8.141.87.86:9015', // target: 'http://8.141.87.86:9015',
// target: 'http://192.168.110.90:10393/mock/5ce74738-f63f-4d21-af85-b1d132c6f6fd', // target: 'http://192.168.110.90:10393/mock/5ce74738-f63f-4d21-af85-b1d132c6f6fd',
changeOrigin: true, changeOrigin: true,
rewrite: (p) => p.replace(/^\/dev-api/, '') rewrite: (p) => p.replace(/^\/dev-api/, '')