update
This commit is contained in:
parent
849a38795c
commit
482f6392a6
@ -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/'
|
||||
|
@ -9,3 +9,7 @@ VITE_APP_BASE_API = '/prod-api'
|
||||
|
||||
# 是否在打包时开启压缩,支持 gzip 和 brotli
|
||||
VITE_BUILD_COMPRESS = gzip
|
||||
|
||||
VITE_PUBLIC_BASE_PATH = '/'
|
||||
|
||||
VITE_APP_WS_API = ''
|
@ -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",
|
||||
|
480
src/components/ZdScrollBoard/index.vue
Normal file
480
src/components/ZdScrollBoard/index.vue
Normal 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
220
src/utils/websocket.js
Normal 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)
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
},
|
||||
yAxis: [{
|
||||
name:'次',
|
||||
type: 'value',
|
||||
splitLine: {
|
||||
show: false,
|
||||
lineStyle: {
|
||||
color: '#1e90ff',
|
||||
type: 'dashed'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#ffffff"
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#0091ea'
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
}
|
||||
}, {
|
||||
name:'kWh',
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
splitLine: {
|
||||
show: false,
|
||||
lineStyle: {
|
||||
color: '#1e90ff',
|
||||
type: 'dashed'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#ffffff"
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#0091ea'
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
}
|
||||
}],
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
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],
|
||||
}
|
||||
},
|
||||
|
||||
],
|
||||
};;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -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;
|
||||
|
@ -20,9 +20,10 @@
|
||||
</div>
|
||||
<div class="ct-box">
|
||||
<div class="ct-sensor">
|
||||
<div class="sensor-item" v-for="item in sensor_list"> <!-- :style="{color: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 class="sensor-item" v-for="item in sensor_list">
|
||||
<!-- :style="{color: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>{{ item.name }}</div>
|
||||
@ -55,6 +56,8 @@
|
||||
</div>
|
||||
<div class="rbox-item">
|
||||
<ItemVue title="告警信息" pos="right">
|
||||
<ZdScrollBoard ref="devList" :config="zd_config"
|
||||
:style="{ width: '100%', height: '260px', 'padding-top': '10px' }" />
|
||||
</ItemVue>
|
||||
</div>
|
||||
</div>
|
||||
@ -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
|
||||
@ -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);
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -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%;
|
||||
|
@ -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/, '')
|
||||
|
Loading…
Reference in New Issue
Block a user