更新
This commit is contained in:
parent
e91fcab0c8
commit
1a1a3a9129
@ -37,7 +37,9 @@ export default {
|
||||
this.outputData.push(item.outputNum)
|
||||
this.goodRateData.push(item.goodRate)
|
||||
})
|
||||
this.$nextTick(()=>{
|
||||
this.initChart();
|
||||
})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@ -281,4 +283,4 @@ export default {
|
||||
.qhd-chart-tooltip * {
|
||||
color: #fff !important;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
@ -1,17 +1,20 @@
|
||||
<template>
|
||||
<div ref='dataBoardBoxB' class='dataBoardBoxB'>
|
||||
<div id="dataBoardBox" class='dataBoardBox' style="width: 1920px;height: 1080px;" :style="{ transform: 'scale(' + scaleNum + ')' }">
|
||||
<div ref="dataBoardBoxB" class="dataBoardBoxB">
|
||||
<div
|
||||
id="dataBoardBox"
|
||||
class="dataBoardBox"
|
||||
style="width: 1920px; height: 1080px"
|
||||
:style="{ transform: 'scale(' + scaleNum + ')' }">
|
||||
<DataBoardHeader
|
||||
:is-full-screen="isFullScreen"
|
||||
@screenfullChange="screenfullChange"
|
||||
/>
|
||||
<LeftTop :dataObj='dataObj'/>
|
||||
<LeftBottom :dataObj='dataObj'/>
|
||||
<CenterTop :scaleNum='scaleNum' :dataObj='dataObj'/>
|
||||
<CenterBottomL :dataObj='dataObj'/>
|
||||
<CenterBottomR :dataObj='dataObj'/>
|
||||
<RightTop :dataObj='dataObj'/>
|
||||
<RightBottom :dataObj='dataObj'/>
|
||||
@screenfullChange="screenfullChange" />
|
||||
<LeftTop :dataObj="dataObj" />
|
||||
<LeftBottom :dataObj="dataObj" />
|
||||
<CenterTop :scaleNum="scaleNum" :dataObj="dataObj" />
|
||||
<CenterBottomL :dataObj="dataObj" />
|
||||
<CenterBottomR :dataObj="dataObj" />
|
||||
<RightTop :dataObj="dataObj" />
|
||||
<RightBottom :dataObj="dataObj" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -28,212 +31,249 @@ import RightBottom from './components/RightBottom.vue';
|
||||
import { debounce } from '@/utils/debounce';
|
||||
import screenfull from 'screenfull';
|
||||
import { getAccessToken } from '@/utils/auth';
|
||||
import store from "@/store";
|
||||
import store from '@/store';
|
||||
export default {
|
||||
name: 'DataBoard',
|
||||
components: { DataBoardHeader,LeftTop,LeftBottom,CenterTop,CenterBottomL,CenterBottomR,RightTop,RightBottom },
|
||||
components: {
|
||||
DataBoardHeader,
|
||||
LeftTop,
|
||||
LeftBottom,
|
||||
CenterTop,
|
||||
CenterBottomL,
|
||||
CenterBottomR,
|
||||
RightTop,
|
||||
RightBottom,
|
||||
},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
isFullScreen: false,
|
||||
scaleNum: 0.8,
|
||||
dataObj:{},
|
||||
sseReader: null, // 保存流读取器
|
||||
abortController: null, // 用于中止 fetch 请求
|
||||
retryCount: 0, // 当前重试次数
|
||||
isDestroyed: false // 标记组件是否已销毁
|
||||
dataObj: {},
|
||||
sseReader: null, // 保存流读取器
|
||||
abortController: null, // 用于中止 fetch 请求
|
||||
retryCount: 0, // 当前重试次数
|
||||
isDestroyed: false, // 标记组件是否已销毁
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
},
|
||||
this.init();
|
||||
},
|
||||
mounted() {
|
||||
this.boxReset = debounce(() => {
|
||||
this.resetSize()
|
||||
}, 300)
|
||||
this.boxReset()
|
||||
window.addEventListener('resize', () => {
|
||||
this.boxReset()
|
||||
})
|
||||
this.getData()
|
||||
this.boxReset = debounce(() => {
|
||||
this.resetSize();
|
||||
}, 300);
|
||||
this.boxReset();
|
||||
window.addEventListener('resize', () => {
|
||||
this.boxReset();
|
||||
});
|
||||
this.getData();
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.closeSSE();
|
||||
},
|
||||
destroyed() {
|
||||
window.removeEventListener('resize', this.boxReset);
|
||||
},
|
||||
this.closeSSE();
|
||||
},
|
||||
destroyed() {
|
||||
window.removeEventListener('resize', this.boxReset);
|
||||
},
|
||||
computed: {
|
||||
sidebarOpened() {
|
||||
return this.$store.state.app.sidebar.opened
|
||||
}
|
||||
return this.$store.state.app.sidebar.opened;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
sidebarOpened(newVal, oldVal) {
|
||||
this.boxReset()
|
||||
}
|
||||
this.boxReset();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async getData() {
|
||||
let _this = this;
|
||||
if (_this.isDestroyed) return;
|
||||
const url = process.env.VUE_APP_BASE_API+'/admin-api/monitoring/message/subscribe/'+store.getters.userId+'-'+Date.now();
|
||||
const token = getAccessToken()
|
||||
const url =
|
||||
process.env.VUE_APP_BASE_API +
|
||||
'/admin-api/monitoring/message/subscribe/' +
|
||||
store.getters.userId +
|
||||
'-' +
|
||||
Date.now();
|
||||
const token = getAccessToken();
|
||||
const headers = new Headers({
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'text/event-stream'
|
||||
});
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'text/event-stream',
|
||||
});
|
||||
try {
|
||||
// 创建中止控制器
|
||||
this.abortController = new AbortController();
|
||||
// 发起 fetch 请求(替换为你的接口地址)
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: headers,
|
||||
signal: _this.abortController.signal // 绑定中止信号
|
||||
});
|
||||
// 创建中止控制器
|
||||
this.abortController = new AbortController();
|
||||
// 发起 fetch 请求(替换为你的接口地址)
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: headers,
|
||||
signal: _this.abortController.signal, // 绑定中止信号
|
||||
});
|
||||
|
||||
// 获取流读取器
|
||||
_this.sseReader = response.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
// 获取流读取器
|
||||
_this.sseReader = response.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
let buffer = '';
|
||||
let receivedBytes = 0;
|
||||
|
||||
// 持续读取流数据
|
||||
while (true) {
|
||||
const { done, value } = await _this.sseReader.read();
|
||||
if (done) {
|
||||
console.log('SSE 连接正常关闭');
|
||||
_this.handleReconnect(); // 触发重连
|
||||
break;
|
||||
}
|
||||
// 处理 SSE 事件数据
|
||||
const data = decoder.decode(value);
|
||||
console.log('收到消息:', data);
|
||||
if (_this.isValidData(data)){
|
||||
_this.upDateMsg(data);
|
||||
// 持续读取流数据
|
||||
while (true) {
|
||||
const { done, value } = await _this.sseReader.read();
|
||||
if (done) {
|
||||
console.log('SSE 连接正常关闭');
|
||||
_this.handleReconnect(); // 触发重连
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// 主动中止的请求不报错
|
||||
if (error.name === 'AbortError') return;
|
||||
console.error('SSE 连接异常:', error);
|
||||
_this.handleReconnect(); // 触发重连
|
||||
}
|
||||
// const data = decoder.decode(value);
|
||||
// console.log('收到消息:', data);
|
||||
|
||||
receivedBytes += value.length;
|
||||
console.log(
|
||||
`收到数据块: ${value.length} 字节, 累计: ${receivedBytes} 字节`
|
||||
);
|
||||
const chunk = decoder.decode(value, { stream: true });
|
||||
buffer += chunk;
|
||||
|
||||
// 处理完整的消息
|
||||
const messages = buffer.split('\n\n'); // SSE 消息以双换行分隔
|
||||
buffer = messages.pop() || ''; // 保留最后一个不完整的消息
|
||||
|
||||
for (const message of messages) {
|
||||
if (_this.isValidData(message)) {
|
||||
// console.log('完整 SSE 消息:', message);
|
||||
_this.upDateMsg(message);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理 SSE 事件数据
|
||||
// const data = decoder.decode(value);
|
||||
// console.log('收到消息:', data);
|
||||
// if (_this.isValidData(data)){
|
||||
// _this.upDateMsg(data);
|
||||
// }
|
||||
}
|
||||
} catch (error) {
|
||||
// 主动中止的请求不报错
|
||||
if (error.name === 'AbortError') return;
|
||||
console.error('SSE 连接异常:', error);
|
||||
_this.handleReconnect(); // 触发重连
|
||||
}
|
||||
},
|
||||
closeSSE() {
|
||||
this.isDestroyed = true; // 标记销毁
|
||||
if (this.abortController) {
|
||||
this.abortController.abort(); // 中止 fetch 请求
|
||||
}
|
||||
if (this.sseReader) {
|
||||
this.sseReader.cancel(); // 关闭流读取器
|
||||
this.sseReader = null;
|
||||
}
|
||||
console.log('SSE 连接已强制关闭');
|
||||
},
|
||||
this.isDestroyed = true; // 标记销毁
|
||||
if (this.abortController) {
|
||||
this.abortController.abort(); // 中止 fetch 请求
|
||||
}
|
||||
if (this.sseReader) {
|
||||
this.sseReader.cancel(); // 关闭流读取器
|
||||
this.sseReader = null;
|
||||
}
|
||||
console.log('SSE 连接已强制关闭');
|
||||
},
|
||||
handleReconnect() {
|
||||
if (this.isDestroyed) return;
|
||||
// 指数退避策略(最大重试 5 次)
|
||||
const maxRetries = 5;
|
||||
if (this.retryCount < maxRetries) {
|
||||
const delay = Math.pow(2, this.retryCount) * 1000;
|
||||
setTimeout(() => {
|
||||
this.retryCount++;
|
||||
this.initSSE();
|
||||
}, delay);
|
||||
} else {
|
||||
console.error('SSE 重连次数已达上限');
|
||||
}
|
||||
},
|
||||
isValidData (data) {
|
||||
return data.trim().startsWith('data:{') && !data.includes('heartbeat');
|
||||
if (this.isDestroyed) return;
|
||||
// 指数退避策略(最大重试 5 次)
|
||||
const maxRetries = 5;
|
||||
if (this.retryCount < maxRetries) {
|
||||
const delay = Math.pow(2, this.retryCount) * 1000;
|
||||
setTimeout(() => {
|
||||
this.retryCount++;
|
||||
this.initSSE();
|
||||
}, delay);
|
||||
} else {
|
||||
console.error('SSE 重连次数已达上限');
|
||||
}
|
||||
},
|
||||
isValidData(data) {
|
||||
return data.trim().startsWith('data:{') && !data.includes('heartbeat');
|
||||
},
|
||||
upDateMsg(data) {
|
||||
const jsonStr = data.replace(/^data:/, '').trim();
|
||||
console.log('jsonStr', jsonStr);
|
||||
const jsonStr = data.replace(/^data:/, '').trim();
|
||||
console.log('jsonStr', jsonStr);
|
||||
|
||||
try {
|
||||
const dataObj = JSON.parse(jsonStr);
|
||||
this.dataObj = dataObj
|
||||
console.log('dataObj',this.dataObj)
|
||||
this.dataObj = dataObj;
|
||||
console.log('dataObj', this.dataObj);
|
||||
} catch (e) {
|
||||
console.error('JSON 解析失败:', e);
|
||||
}
|
||||
},
|
||||
change() {
|
||||
this.isFullScreen = screenfull.isFullscreen
|
||||
},
|
||||
this.isFullScreen = screenfull.isFullscreen;
|
||||
},
|
||||
init() {
|
||||
if (!screenfull.isEnabled) {
|
||||
this.$message({
|
||||
message: 'you browser can not work',
|
||||
type: 'warning'
|
||||
})
|
||||
return false
|
||||
}
|
||||
screenfull.on('change', this.change)
|
||||
},
|
||||
destroy() {
|
||||
if (!screenfull.isEnabled) {
|
||||
this.$message({
|
||||
message: 'you browser can not work',
|
||||
type: 'warning'
|
||||
})
|
||||
return false
|
||||
}
|
||||
screenfull.off('change', this.change)
|
||||
},
|
||||
if (!screenfull.isEnabled) {
|
||||
this.$message({
|
||||
message: 'you browser can not work',
|
||||
type: 'warning',
|
||||
});
|
||||
return false;
|
||||
}
|
||||
screenfull.on('change', this.change);
|
||||
},
|
||||
destroy() {
|
||||
if (!screenfull.isEnabled) {
|
||||
this.$message({
|
||||
message: 'you browser can not work',
|
||||
type: 'warning',
|
||||
});
|
||||
return false;
|
||||
}
|
||||
screenfull.off('change', this.change);
|
||||
},
|
||||
// 全屏
|
||||
screenfullChange() {
|
||||
if (!screenfull.isEnabled) {
|
||||
this.$message({
|
||||
message: 'you browser can not work',
|
||||
type: 'warning'
|
||||
})
|
||||
return false
|
||||
}
|
||||
screenfull.toggle(this.$refs.dataBoardBoxB)
|
||||
},
|
||||
screenfullChange() {
|
||||
if (!screenfull.isEnabled) {
|
||||
this.$message({
|
||||
message: 'you browser can not work',
|
||||
type: 'warning',
|
||||
});
|
||||
return false;
|
||||
}
|
||||
screenfull.toggle(this.$refs.dataBoardBoxB);
|
||||
},
|
||||
resetSize() {
|
||||
const dataBoardBox = document.getElementById('dataBoardBox')
|
||||
const rw = parseFloat(window.innerWidth)
|
||||
const rh = parseFloat(window.innerHeight)
|
||||
const bw = parseFloat(dataBoardBox.style.width)
|
||||
const bh = parseFloat(dataBoardBox.style.height)
|
||||
let wx = 0
|
||||
let hy = 0
|
||||
if (screenfull.isFullscreen) {
|
||||
wx = rw / bw
|
||||
hy = rh / bh
|
||||
} else {
|
||||
if (this.$store.state.app.sidebar.opened) {
|
||||
wx = (rw - 283) / bw
|
||||
} else {
|
||||
wx = (rw - 88) / bw
|
||||
}
|
||||
hy = (rh - 150) / bh
|
||||
}
|
||||
this.scaleNum = wx < hy ? wx : hy
|
||||
},
|
||||
const dataBoardBox = document.getElementById('dataBoardBox');
|
||||
const rw = parseFloat(window.innerWidth);
|
||||
const rh = parseFloat(window.innerHeight);
|
||||
const bw = parseFloat(dataBoardBox.style.width);
|
||||
const bh = parseFloat(dataBoardBox.style.height);
|
||||
let wx = 0;
|
||||
let hy = 0;
|
||||
if (screenfull.isFullscreen) {
|
||||
wx = rw / bw;
|
||||
hy = rh / bh;
|
||||
} else {
|
||||
if (this.$store.state.app.sidebar.opened) {
|
||||
wx = (rw - 283) / bw;
|
||||
} else {
|
||||
wx = (rw - 88) / bw;
|
||||
}
|
||||
hy = (rh - 150) / bh;
|
||||
}
|
||||
this.scaleNum = wx < hy ? wx : hy;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dataBoardBoxB {
|
||||
width: 100%;
|
||||
height: calc(100vh - 150px);
|
||||
position: relative;
|
||||
.dataBoardBoxB {
|
||||
width: 100%;
|
||||
height: calc(100vh - 150px);
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
.dataBoardBox {
|
||||
position: absolute;
|
||||
transform-origin: 16px 8px;
|
||||
font-size: 16px;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
background: url('../../../assets/images/dataBoard/background.png') no-repeat;
|
||||
background-size: cover;
|
||||
background-position: 0 0;
|
||||
overflow: auto;
|
||||
.dataBoardBox {
|
||||
position: absolute;
|
||||
transform-origin: 16px 8px;
|
||||
font-size: 16px;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
background: url('../../../assets/images/dataBoard/background.png') no-repeat;
|
||||
background-size: cover;
|
||||
background-position: 0 0;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user