趋势图开发完成
This commit is contained in:
parent
cf83cdeb1d
commit
f18274a5f3
48
src/utils/base64.js
Normal file
48
src/utils/base64.js
Normal file
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Base64 解码
|
||||
* @param {string} base64Str - base64编码的字符串
|
||||
* @param {boolean} toArray - 是否转换为数组
|
||||
* @returns {string|Array} 解码后的字符串或数组
|
||||
*/
|
||||
export function base64Decode(base64Str, toArray = false) {
|
||||
try {
|
||||
// Check if input is valid
|
||||
if (!base64Str || typeof base64Str !== 'string') {
|
||||
return toArray ? [] : ''
|
||||
}
|
||||
|
||||
// Remove any whitespace and validate base64 string
|
||||
const cleanStr = base64Str.replace(/\s/g, '')
|
||||
if (!cleanStr.match(/^[A-Za-z0-9+/]*={0,2}$/)) {
|
||||
return toArray ? [] : ''
|
||||
}
|
||||
|
||||
const decodedStr = decodeURIComponent(escape(window.atob(cleanStr)))
|
||||
if (toArray) {
|
||||
try {
|
||||
return JSON.parse(decodedStr)
|
||||
} catch (e) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
return decodedStr
|
||||
} catch (e) {
|
||||
console.error('Base64解码失败:', e)
|
||||
return toArray ? [] : ''
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base64 编码
|
||||
* @param {string|Array} data - 需要编码的字符串或数组
|
||||
* @returns {string} base64编码后的字符串
|
||||
*/
|
||||
export function base64Encode(data) {
|
||||
try {
|
||||
const str = typeof data === 'string' ? data : JSON.stringify(data)
|
||||
return window.btoa(unescape(encodeURIComponent(str)))
|
||||
} catch (e) {
|
||||
console.error('Base64编码失败:', e)
|
||||
return ''
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ export const useMqtt = () => {
|
||||
})
|
||||
|
||||
client.value.on('connect', () => {
|
||||
console.log('MQTT 连接成功')
|
||||
// console.log('MQTT 连接成功')
|
||||
connected.value = true
|
||||
|
||||
// 连接成功后,订阅所有待订阅的主题
|
||||
@ -30,12 +30,13 @@ export const useMqtt = () => {
|
||||
})
|
||||
|
||||
client.value.on('message', (topic, message) => {
|
||||
// console.log('收到消息:', topic, JSON.parse(message.toString()))
|
||||
messageData.value[topic] = message.toString()
|
||||
|
||||
// 执行对应主题的回调函数
|
||||
// 执行该主题的所有回调函数
|
||||
if (messageCallbacks.value[topic]) {
|
||||
messageCallbacks.value[topic](JSON.parse(message.toString()))
|
||||
messageCallbacks.value[topic].forEach(callback => {
|
||||
callback(JSON.parse(message.toString()))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -43,11 +44,16 @@ export const useMqtt = () => {
|
||||
const subscribe = (topic, callback) => {
|
||||
// 存储回调函数
|
||||
if (callback) {
|
||||
messageCallbacks.value[topic] = callback
|
||||
if (!messageCallbacks.value[topic]) {
|
||||
messageCallbacks.value[topic] = []
|
||||
}
|
||||
messageCallbacks.value[topic].push(callback)
|
||||
}
|
||||
|
||||
if (!connected.value) {
|
||||
pendingSubscriptions.value.push(topic)
|
||||
if (!pendingSubscriptions.value.includes(topic)) {
|
||||
pendingSubscriptions.value.push(topic)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
29
src/utils/time.js
Normal file
29
src/utils/time.js
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 将时间戳数组转换为时间数组
|
||||
* @param {string|Array} timestampArray - 时间戳数组或字符串
|
||||
* @param {string} format - 时间格式,默认 'HH:mm:ss'
|
||||
* @returns {Array} 格式化后的时间数组
|
||||
*/
|
||||
export function timestampArrayToTime(timestampArray, format = 'HH:mm:ss') {
|
||||
// 如果是字符串,先转换为数组
|
||||
const timestamps = typeof timestampArray === 'string'
|
||||
? JSON.parse(timestampArray)
|
||||
: timestampArray
|
||||
|
||||
if (!Array.isArray(timestamps)) {
|
||||
console.error('输入必须是数组或可解析为数组的字符串')
|
||||
return []
|
||||
}
|
||||
|
||||
return timestamps.map(timestamp => {
|
||||
const date = new Date(timestamp * 1000) // 转换为毫秒
|
||||
|
||||
const formatObj = {
|
||||
HH: String(date.getHours()).padStart(2, '0'),
|
||||
mm: String(date.getMinutes()).padStart(2, '0'),
|
||||
ss: String(date.getSeconds()).padStart(2, '0')
|
||||
}
|
||||
|
||||
return format.replace(/(HH|mm|ss)/g, match => formatObj[match])
|
||||
})
|
||||
}
|
@ -184,6 +184,7 @@ watch(
|
||||
() => props.formData,
|
||||
(newVal) => {
|
||||
if (props.title === '编辑' && Object.keys(newVal).length > 0) {
|
||||
console.log(newVal,'newVal')
|
||||
Object.keys(form).forEach(key => {
|
||||
if (key === 'userIdList') {
|
||||
form[key] = Array.isArray(newVal[key]) ? [...newVal[key]] : []
|
||||
@ -201,6 +202,7 @@ defineExpose({
|
||||
visible
|
||||
})
|
||||
onMounted(() => {
|
||||
console.log('999')
|
||||
getDeviceTypeList()
|
||||
})
|
||||
</script>
|
||||
|
@ -1,207 +1,137 @@
|
||||
<template>
|
||||
<div class="dual-channel-chart">
|
||||
<div class="chart-title">{{ title }}</div>
|
||||
<div ref="chartRef" style="height: 200px"></div>
|
||||
</div>
|
||||
<div ref="chartRef" style="width: 100%; height: 400px;"></div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import * as echarts from 'echarts'
|
||||
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
chartData: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const chartRef = ref(null)
|
||||
let chart = null
|
||||
let myChart = null
|
||||
|
||||
// const initChart = () => {
|
||||
// chart = echarts.init(chartRef.value)
|
||||
// const option = {
|
||||
// grid: {
|
||||
// top: 30,
|
||||
// right: 10,
|
||||
// bottom: 20,
|
||||
// left: 40
|
||||
// },
|
||||
// legend: {
|
||||
// data: ['a通道', 'b通道'],
|
||||
// right: 0,
|
||||
// top: 0
|
||||
// },
|
||||
// xAxis: {
|
||||
// type: 'value',
|
||||
// min: 0,
|
||||
// max: 100
|
||||
// },
|
||||
// yAxis: {
|
||||
// type: 'value',
|
||||
// min: 0,
|
||||
// max: 10000
|
||||
// },
|
||||
// series: [
|
||||
// {
|
||||
// name: 'a通道',
|
||||
// type: 'line',
|
||||
// data: props.chartData.a,
|
||||
// color: '#ff4444',
|
||||
// smooth: true
|
||||
// },
|
||||
// {
|
||||
// name: 'b通道',
|
||||
// type: 'line',
|
||||
// data: props.chartData.b,
|
||||
// color: '#67c23a',
|
||||
// smooth: true
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// chart = echarts.init(chartRef.value)
|
||||
// chart.setOption(option)
|
||||
// }
|
||||
const initChart = () => {
|
||||
const option = {
|
||||
grid: {
|
||||
left: '10%', // 增加左边距
|
||||
left: '5%',
|
||||
right: '5%',
|
||||
top: '10%', // 增加顶部边距
|
||||
bottom: '10%', // 增加底部边距
|
||||
bottom: '10%',
|
||||
top: '10%',
|
||||
containLabel: true
|
||||
},
|
||||
legend: {
|
||||
data: ['a通道', 'b通道'],
|
||||
right: 10,
|
||||
top: 0
|
||||
},
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
min: 0,
|
||||
max: 90,
|
||||
interval: 15,
|
||||
axisLine: {
|
||||
show: true
|
||||
},
|
||||
splitLine: { // 添加网格线
|
||||
min: 15,
|
||||
max: 120,
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: 'dashed'
|
||||
type: 'dashed',
|
||||
color: '#ddd'
|
||||
}
|
||||
},
|
||||
axisLabel: { // 调整标签样式
|
||||
margin: 12, // 增加标签与轴线的距离
|
||||
formatter: '{value}'
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
min: 0,
|
||||
max: 9000,
|
||||
interval: 1500,
|
||||
axisLine: {
|
||||
show: true
|
||||
},
|
||||
splitLine: { // 添加网格线
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: 'dashed'
|
||||
}
|
||||
},
|
||||
axisLabel: { // 调整标签样式
|
||||
margin: 16, // 增加标签与轴线的距离
|
||||
formatter: '{value}'
|
||||
}
|
||||
max: 48000,
|
||||
interval: 8000
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: 'a通道',
|
||||
// 红色曲线
|
||||
type: 'line',
|
||||
data: generateData('a'),
|
||||
data: generateBowlData(true),
|
||||
smooth: true,
|
||||
symbol: 'none',
|
||||
lineStyle: {
|
||||
color: '#ff4444',
|
||||
width: 2
|
||||
},
|
||||
smooth: true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'b通道',
|
||||
// 绿色曲线
|
||||
type: 'line',
|
||||
data: generateData('b'),
|
||||
data: generateBowlData(false),
|
||||
smooth: true,
|
||||
symbol: 'none',
|
||||
lineStyle: {
|
||||
color: '#67c23a',
|
||||
color: '#44ff44',
|
||||
width: 2
|
||||
},
|
||||
smooth: true
|
||||
}
|
||||
},
|
||||
{
|
||||
// 竖直虚线 1
|
||||
type: 'line',
|
||||
markLine: {
|
||||
symbol: ['none', 'none'],
|
||||
data: [{ xAxis: 30 }],
|
||||
lineStyle: {
|
||||
type: 'dashed',
|
||||
color: '#44ff44'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
// 竖直虚线 2
|
||||
type: 'line',
|
||||
markLine: {
|
||||
symbol: ['none', 'none'],
|
||||
data: [{ xAxis: 45 }],
|
||||
lineStyle: {
|
||||
type: 'dashed',
|
||||
color: '#44ff44'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
// 竖直虚线 3
|
||||
type: 'line',
|
||||
markLine: {
|
||||
symbol: ['none', 'none'],
|
||||
data: [{ xAxis: 60 }],
|
||||
lineStyle: {
|
||||
type: 'dashed',
|
||||
color: '#44ff44'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
chart = echarts.init(chartRef.value)
|
||||
chart.setOption(option)
|
||||
myChart = echarts.init(chartRef.value)
|
||||
myChart.setOption(option)
|
||||
}
|
||||
const generateData = (type) => {
|
||||
|
||||
// 生成碗状曲线数据
|
||||
const generateBowlData = (isRed) => {
|
||||
const data = []
|
||||
for (let i = 0; i <= 90; i++) {
|
||||
let value
|
||||
if (i < 45) {
|
||||
value = type === 'a' ? 8500 : 7500
|
||||
} else if (i >= 45 && i < 60) {
|
||||
// 下降段
|
||||
const progress = (i - 45) / 15
|
||||
value = type === 'a' ?
|
||||
8500 - (8000 * progress) :
|
||||
7500 - (7000 * progress)
|
||||
} else if (i >= 60 && i < 75) {
|
||||
// 上升段
|
||||
const progress = (i - 60) / 15
|
||||
value = type === 'a' ?
|
||||
500 + (8000 * progress) :
|
||||
500 + (7000 * progress)
|
||||
const offset = isRed ? -2000 : 0
|
||||
|
||||
for (let x = 15; x <= 120; x++) {
|
||||
let y
|
||||
if (x < 30) {
|
||||
y = 45000 + offset
|
||||
} else if (x < 45) {
|
||||
y = 45000 + offset - Math.pow((x - 30) * 2500, 0.9)
|
||||
} else if (x < 60) {
|
||||
y = 6000 + offset
|
||||
} else if (x < 75) {
|
||||
y = 6000 + offset + Math.pow((x - 60) * 2500, 0.9)
|
||||
} else {
|
||||
value = type === 'a' ? 8500 : 7500
|
||||
y = 45000 + offset
|
||||
}
|
||||
data.push([i, value])
|
||||
data.push([x, y])
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initChart()
|
||||
window.addEventListener('resize', () => chart?.resize())
|
||||
window.addEventListener('resize', () => myChart?.resize())
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', () => chart?.resize())
|
||||
chart?.dispose()
|
||||
window.removeEventListener('resize', () => myChart?.resize())
|
||||
myChart?.dispose()
|
||||
})
|
||||
const resize = () => {
|
||||
nextTick(() => {
|
||||
chart?.resize()
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
resize
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dual-channel-chart {
|
||||
width: 100%;
|
||||
//height: 100%;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
padding: 15px;
|
||||
|
||||
.chart-title {
|
||||
margin-bottom: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</script>
|
@ -4,14 +4,14 @@
|
||||
<div class="title">趋势图</div>
|
||||
<div class="subtitle">近 30min 数据</div>
|
||||
<div class="actions">
|
||||
<el-dropdown>
|
||||
<el-dropdown @command="handleCommand">
|
||||
<el-button type="primary">
|
||||
冷直径
|
||||
{{ currentOption.label }}
|
||||
<el-icon class="el-icon--right"><CaretBottom /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-for="(item,index) in options" :key="index">{{item.label}}</el-dropdown-item>
|
||||
<el-dropdown-item v-for="(item,index) in options" :key="index" :command="item">{{item.label}}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
@ -25,43 +25,64 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import {ref, onMounted, onUnmounted, watch} from 'vue'
|
||||
import { CaretBottom, Refresh } from '@element-plus/icons-vue'
|
||||
import * as echarts from 'echarts'
|
||||
// import { getRealtimeData } from '@/api/scanner'
|
||||
|
||||
const props = defineProps({
|
||||
realData: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
datetime:[],
|
||||
WtOSC: [],
|
||||
WtINS:[],
|
||||
WtISC: [],
|
||||
EccentricityINS: [],
|
||||
EccentricityOSC: [],
|
||||
EccentricityISC: [],
|
||||
DmCORE: [],
|
||||
DmALL: []
|
||||
})
|
||||
}
|
||||
})
|
||||
const options = [
|
||||
{ label: '导体直径', value: 'DmCORE' },
|
||||
{ label: '热外径', value: 'DmALL' },
|
||||
{ label: '内屏蔽层偏心度', value: 'EccentricityISC' },
|
||||
{ label: '内屏层均值', value: 'WtISC' },
|
||||
{ label: '外屏蔽层偏心度', value: 'EccentricityOSC' },
|
||||
{ label: '外屏层均值', value: 'WtOSC' },
|
||||
{ label: '绝缘层偏心度', value: 'EccentricityINS' },
|
||||
{ label: '绝缘层均值', value: 'WtINS' }
|
||||
]
|
||||
const currentOption = ref(options[0])
|
||||
const chartRef = ref(null)
|
||||
let myChart = null
|
||||
let timer = null
|
||||
|
||||
const selectedType = ref('coldDiameter')
|
||||
const options = [
|
||||
{ label: '冷直径', value: 'coldDiameter' },
|
||||
{ label: '热外径', value: 'hotDiameter' },
|
||||
{ label: '内屏蔽层偏心度', value: 'eccentricity' },
|
||||
{ label: '内屏蔽厚度', value: 'ovality' },
|
||||
{ label: '外屏蔽层偏心度', value: 'thickness' },
|
||||
{ label: '外屏蔽层厚度', value: 'innerDiameter' },
|
||||
{ label: '绝缘层偏心度', value: 'outerDiameter' },
|
||||
{ label: '绝缘层厚度', value: 'surfaceQuality' }
|
||||
]
|
||||
const mockData = {
|
||||
times: ['13:21', '13:22', '13:23', '13:24', '13:25', '13:26', '13:27', '13:28', '13:29', '13:30',
|
||||
'13:31', '13:32', '13:33', '13:34', '13:35', '13:36', '13:37', '13:38', '13:39', '13:40', '13:41'],
|
||||
values: [3.2, 3.1, 3.3, 3.2, 3.4, 3.3, 3.5, 3.6, 3.4, 3.3, 3.2, 3.4, 3.3, 3.2, 3.1, 3.0, 3.2, 2.8, 3.5, 3.6, 3.4]
|
||||
const handleCommand = (command) => {
|
||||
currentOption.value = command
|
||||
initChart()
|
||||
}
|
||||
watch(() => props.realData,(newValue) => {
|
||||
console.log(newValue,'====3')
|
||||
})
|
||||
const initChart = () => {
|
||||
console.log(myChart,'myChart')
|
||||
if (myChart) {
|
||||
myChart.dispose()
|
||||
}
|
||||
// 确保DOM已经渲染完成
|
||||
nextTick(() => {
|
||||
myChart = echarts.init(chartRef.value)
|
||||
const currentData = props.realData[currentOption.value.value] || []
|
||||
const maxValue = Math.max(...currentData) || 0
|
||||
const minValue = Math.min(...currentData) || 0
|
||||
const valueRange = maxValue - minValue
|
||||
|
||||
console.log(currentOption.value,'===currentOption.value')
|
||||
console.log(props.realData[currentOption.value.value],'props.realData[currentOption.value]')
|
||||
const option = {
|
||||
grid: {
|
||||
left: '0%',
|
||||
right: '0%',
|
||||
left: '40',
|
||||
right: '40',
|
||||
bottom: '15%',
|
||||
top: '10%',
|
||||
containLabel: true
|
||||
@ -69,17 +90,25 @@ const initChart = () => {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: mockData.times,
|
||||
data: props.realData.datetime,
|
||||
axisLabel: {
|
||||
interval: 2,
|
||||
margin: 12 // 增加标签与轴线的距离
|
||||
interval: 'auto', // 显示所有标签
|
||||
margin:20,
|
||||
formatter: (value) => {
|
||||
// 只显示时分秒
|
||||
return value.split(' ')[1] || value
|
||||
},
|
||||
textStyle: {
|
||||
fontSize: 12,
|
||||
textAlign: 'left'
|
||||
}
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
min: 0,
|
||||
max: 5,
|
||||
interval: 1,
|
||||
min: Math.floor(minValue - valueRange * 0.1), // 最小值向下取整并留出 10% 空间
|
||||
max: Math.ceil(maxValue + valueRange * 0.1), // 最大值向上取整并留出 10% 空间
|
||||
interval: Math.ceil(valueRange / 5),
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
type: 'dashed'
|
||||
@ -93,8 +122,15 @@ const initChart = () => {
|
||||
padding: [0, 0, 0, 40] // 调整单位文字位置
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: (params) => {
|
||||
const data = params[0]
|
||||
return `${data.axisValue}<br/>${currentOption.value.label}: ${data.value}`
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
data: mockData.values,
|
||||
data: props.realData[currentOption.value.value],
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
areaStyle: {
|
||||
@ -123,52 +159,20 @@ const initChart = () => {
|
||||
symbol: 'none'
|
||||
}]
|
||||
}
|
||||
|
||||
myChart.setOption(option)
|
||||
})
|
||||
}
|
||||
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const res = await getRealtimeData({
|
||||
type: selectedType.value,
|
||||
minutes: 30
|
||||
})
|
||||
if (res.code === 200) {
|
||||
myChart.setOption({
|
||||
xAxis: {
|
||||
data: res.data.times
|
||||
},
|
||||
series: [{
|
||||
data: res.data.values
|
||||
}]
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取数据失败', error)
|
||||
}
|
||||
}
|
||||
|
||||
// const refreshData = () => {
|
||||
// // fetchData()
|
||||
// }
|
||||
|
||||
// watch(() => selectedType.value, () => {
|
||||
// // fetchData()
|
||||
// })
|
||||
const refreshData = () => {
|
||||
currentOption.value = options[0]
|
||||
initChart()
|
||||
}
|
||||
onMounted(() => {
|
||||
initChart()
|
||||
// fetchData()
|
||||
// 每分钟刷新一次
|
||||
// timer = setInterval(fetchData, 60000)
|
||||
window.addEventListener('resize', () => myChart?.resize())
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
// clearInterval(timer)
|
||||
window.removeEventListener('resize', () => myChart?.resize())
|
||||
myChart?.dispose()
|
||||
})
|
||||
|
@ -13,9 +13,9 @@ const props = defineProps({
|
||||
chartData: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
arm1: [],
|
||||
arm2: [],
|
||||
times: []
|
||||
SCANNER1: [],
|
||||
SCANNER2: [],
|
||||
datetime: []
|
||||
})
|
||||
}
|
||||
})
|
||||
@ -32,31 +32,34 @@ const initChart = () => {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: (params) => {
|
||||
const time = params[0].axisValue
|
||||
return `${time}<br/>
|
||||
扫描臂1: ${params[0].data}<br/>
|
||||
扫描臂2: ${params[1].data}`
|
||||
const datetime = params[0].axisValue
|
||||
return `${datetime}<br/>
|
||||
SCANNER1: ${params[0].data}<br/>
|
||||
SCANNER1: ${params[1].data}`
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: ['扫描臂1', '扫描臂2'],
|
||||
data: ['SCANNER1', 'SCANNER2'],
|
||||
right: 0,
|
||||
top: 0
|
||||
},
|
||||
grid: {
|
||||
left: 60, // 增加左边距
|
||||
right: 30, // 增加右边距
|
||||
left: 20,
|
||||
right: 30,
|
||||
top: 40,
|
||||
bottom: 40,
|
||||
containLabel: true // 确保刻度标签显示完整
|
||||
bottom: 60, // 增加底部空间
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: props.chartData.times,
|
||||
data: props.chartData.datetime,
|
||||
axisLabel: {
|
||||
formatter: (value) => {
|
||||
return value.substring(11, 19)
|
||||
interval: 'auto', // 显示所有标签
|
||||
rotate: 45, // 标签旋转45度
|
||||
margin: 8,
|
||||
textStyle: {
|
||||
fontSize: 10
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -78,9 +81,9 @@ const initChart = () => {
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '扫描臂1',
|
||||
name: 'SCANNER1',
|
||||
type: 'line',
|
||||
data: props.chartData.arm1,
|
||||
data: props.chartData.SCANNER1,
|
||||
itemStyle: {
|
||||
color: '#f56c6c'
|
||||
},
|
||||
@ -90,9 +93,9 @@ const initChart = () => {
|
||||
smooth: true
|
||||
},
|
||||
{
|
||||
name: '扫描臂2',
|
||||
name: 'SCANNER2',
|
||||
type: 'line',
|
||||
data: props.chartData.arm2,
|
||||
data: props.chartData.SCANNER2,
|
||||
itemStyle: {
|
||||
color: '#67c23a'
|
||||
},
|
||||
|
@ -243,53 +243,10 @@
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="proxy.$t('equipment.trendChart')" name="four">
|
||||
<RealtimeChart ref="realtimeChartRef" />
|
||||
<RealtimeChart ref="realtimeChartRef" :real-data="trendData" v-if="activeThreeName === 'four'"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
<!-- <div class="chart-box chart-bottom-right">-->
|
||||
<!-- <div class="header">-->
|
||||
<!-- <div>-->
|
||||
<!-- <span>{{proxy.$t('equipment.imagePage')}}</span>-->
|
||||
<!-- <span class="time">{{ currentTime }}</span>-->
|
||||
<!-- </div>-->
|
||||
<!-- <el-divider/>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="imagePage-container">-->
|
||||
<!-- <div class="imagePage-left">-->
|
||||
<!-- <DataTable :table-data="tableData" />-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="charts">-->
|
||||
<!-- <div class="controls">-->
|
||||
<!-- <el-button-group>-->
|
||||
<!-- <el-button type="primary" plain class="switch-btn" @click="handleImagePagePrev"><el-icon><ArrowLeft /></el-icon></el-button>-->
|
||||
<!-- <el-button type="primary" plain class="switch-btn switch" @click="handleImagePageNext"><el-icon><ArrowRight /></el-icon></el-button>-->
|
||||
<!-- <el-button type="primary" plain class="switch-btn switch" @click="handleRefresh"><el-icon><Refresh /></el-icon></el-button>-->
|
||||
<!-- </el-button-group>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div v-if="showImagePageRed">-->
|
||||
<!-- <CurveChart ref="bowlCurvePageRef" :title="chartTitle.left" :color="colorRed"/>-->
|
||||
<!-- <CurveChart ref="bowlCurvePageRef" :title="chartTitle.right" :color="colorRed"/>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div v-if="showImagePageGreen">-->
|
||||
<!-- <CurveChart ref="bowlCurvePageRef" :title="chartTitle.left" :color="colorGreen"/>-->
|
||||
<!-- <CurveChart ref="bowlCurvePageRef" :title="chartTitle.right" :color="colorGreen"/>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div v-if="showImagePageRedGreen">-->
|
||||
<!-- <DualChannelChart-->
|
||||
<!-- title="扫描臂1"-->
|
||||
<!-- ref="dualChart1PageRef"-->
|
||||
<!-- :chart-data="arm1ChartData"-->
|
||||
<!-- />-->
|
||||
<!-- <DualChannelChart-->
|
||||
<!-- title="扫描臂2"-->
|
||||
<!-- ref="dualChart2PageRef"-->
|
||||
<!-- :chart-data="arm2ChartData"-->
|
||||
<!-- />-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
<!-- 历史数据弹框-->
|
||||
<HistoryDataDialog
|
||||
@ -317,7 +274,9 @@ import HistoryDataDialog from './common/HistoryDataDialog.vue';
|
||||
import {ElMessageBox, ElMessage} from "element-plus";
|
||||
import { useMqtt } from '@/utils/mqttClient.js';
|
||||
import {useRoute} from 'vue-router';
|
||||
import AddMonitorData from './common/AddMonitorData.vue'
|
||||
import AddMonitorData from './common/AddMonitorData.vue';
|
||||
import { base64Decode, base64Encode } from '@/utils/base64'
|
||||
import { timestampArrayToTime } from '@/utils/time'
|
||||
const deviceShowStatus = ref('')
|
||||
const {
|
||||
connected,
|
||||
@ -327,7 +286,8 @@ const {
|
||||
disconnect,
|
||||
publish
|
||||
} = useMqtt()
|
||||
const clientId = ref('vue-client-' + Math.random().toString(16).substring(2, 8))
|
||||
// const clientId = ref('lkk' + Math.random().toString(16).substring(2, 8))
|
||||
const clientId = ref('lkk40a9bc')
|
||||
const deviceInfo = ref({})
|
||||
const deviceData = ref(null)
|
||||
const deviceMode = ref(null)
|
||||
@ -349,6 +309,17 @@ const currentIndex = ref(0)
|
||||
const showHistory = ref(false)
|
||||
const mode = ref('normal')
|
||||
const realtimeChartRef = ref(null)
|
||||
const trendData = ref({
|
||||
datetime:[],
|
||||
WtOSC: [],
|
||||
WtINS:[],
|
||||
WtISC: [],
|
||||
EccentricityINS: [],
|
||||
EccentricityOSC: [],
|
||||
EccentricityISC: [],
|
||||
DmCORE: [],
|
||||
DmALL: []
|
||||
})
|
||||
const dualChart1Ref = ref(null)
|
||||
const dualChart2Ref = ref(null)
|
||||
const dualChart1PageRef = ref(null)
|
||||
@ -387,16 +358,9 @@ const middleLayerData = ref([9.52, 9.95, 10.53, 11.04, 11.34, 11.15, 9.66, 10.40
|
||||
const outerLayerData = ref([1.15, 1.19, 1.21, 1.17, 1.05, 0.96, 1.06, 0.79])
|
||||
// 温度数据
|
||||
const temperatureData = ref({
|
||||
arm1: [33, 46, 57, 24, 48, 51, 33],
|
||||
arm2: [11, 24, 39, 13, 48, 41, 33],
|
||||
times: [
|
||||
'2023-01-01 09:00:00',
|
||||
'2023-01-01 10:00:00',
|
||||
'2023-01-01 11:00:00',
|
||||
'2023-01-01 12:00:00',
|
||||
'2023-01-01 13:00:00',
|
||||
'2023-01-01 14:00:00'
|
||||
]
|
||||
SCANNER1: [],
|
||||
SCANNER2: [],
|
||||
datetime: []
|
||||
})
|
||||
const deviceStatus = ref({})
|
||||
const addMonitorRef = ref(null)
|
||||
@ -520,10 +484,10 @@ const generateData = (type) => {
|
||||
}
|
||||
// 标签页切换
|
||||
const handleClick = (tab, event) => {
|
||||
// console.log(tab.props.label,'----')
|
||||
console.log(deviceStatus.value,'===')
|
||||
nextTick(() => {
|
||||
nextTick(async() => {
|
||||
if(tab.props.label === '趋势图') {
|
||||
await sendDeviceTrend()
|
||||
realtimeChartRef.value?.resize()
|
||||
}
|
||||
if(tab.props.label === '图像预览') {
|
||||
@ -542,15 +506,6 @@ const handleNext = () => {
|
||||
currentIndex.value++
|
||||
}
|
||||
}
|
||||
// 设备信息
|
||||
const paramsHandle = () => {
|
||||
showBtn.value = !showBtn.value
|
||||
}
|
||||
// 参数设定按钮
|
||||
const handleSettingUpdate = ({ key, value }) => {
|
||||
console.log('更新设置:', key, value)
|
||||
// 调用接口更新设置
|
||||
}
|
||||
// 图像预览
|
||||
const handleDataUpdate = (data) => {
|
||||
console.log('数据更新:', data)
|
||||
@ -662,11 +617,10 @@ const initSubscribe = () => {
|
||||
deviceShowStatus.value = proxy.$t('common.offline')
|
||||
}
|
||||
})
|
||||
// 发设备温度
|
||||
|
||||
// 计算数据
|
||||
subscribe(`v1/cpy/${deviceInfo.value?.deviceCode}/calculation`, (message) => {
|
||||
// console.log('计算数据:', message)
|
||||
console.log('计算数据:', message)
|
||||
// deviceData.value = message
|
||||
// if(message){
|
||||
// deviceMode.value = message.global_dev.device.sports_mode
|
||||
@ -674,21 +628,68 @@ const initSubscribe = () => {
|
||||
// xRayStatus.value = message.scanner1.xray.enable_status
|
||||
// }
|
||||
})
|
||||
publish(`v1/cpy/1/request`, JSON.stringify({
|
||||
method: 'temperature',
|
||||
}))
|
||||
// try {
|
||||
// publish(`v1/cpy/1/request`, JSON.stringify({
|
||||
// method: 'temperature',
|
||||
// }))
|
||||
// ElMessage.success('发送命令成功')
|
||||
//
|
||||
// } catch (error) {
|
||||
// ElMessage.error('发送命令失败')
|
||||
// }
|
||||
// subscribe(`v1/cpy/${clientId.value}/receive`, (message) => {
|
||||
// console.log('设备温度:', message)
|
||||
// })
|
||||
//图像预览
|
||||
subscribe(`v1/cpy/${deviceInfo.value?.deviceCode}/collect`, (message) => {
|
||||
console.log('图像预览数据:', message)
|
||||
// deviceData.value = message
|
||||
// if(message){
|
||||
// deviceMode.value = message.global_dev.device.sports_mode
|
||||
// console.log(deviceMode.value)
|
||||
// xRayStatus.value = message.scanner1.xray.enable_status
|
||||
// }
|
||||
})
|
||||
|
||||
}
|
||||
// 设备温度
|
||||
const sendDeviceTemperature = async () => {
|
||||
try {
|
||||
await publish(`v1/cpy/1/request`, JSON.stringify({
|
||||
method: 'temperature',
|
||||
cid: clientId.value,
|
||||
duration: 60,
|
||||
}))
|
||||
ElMessage.success('发送命令成功')
|
||||
subscribe(`v1/cpy/${clientId.value}/receive`, (message) => {
|
||||
console.log('设备温度:', message)
|
||||
if(message.method === 'temperature') {
|
||||
temperatureData.value.SCANNER1 = base64Decode(message.SCANNER1,true)
|
||||
temperatureData.value.SCANNER2 = base64Decode(message.SCANNER1,true)
|
||||
temperatureData.value.datetime = timestampArrayToTime(base64Decode(message.datetime,true))
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
ElMessage.error('发送命令失败')
|
||||
}
|
||||
}
|
||||
// 趋势图
|
||||
const sendDeviceTrend = async () => {
|
||||
try {
|
||||
await publish(`v1/cpy/1/request`, JSON.stringify({
|
||||
method: 'trend',
|
||||
cid: clientId.value,
|
||||
duration: 30,
|
||||
filters:'WtOSC'
|
||||
}))
|
||||
ElMessage.success('发送命令成功')
|
||||
subscribe(`v1/cpy/${clientId.value}/receive`, (message) => {
|
||||
console.log('趋势数据:', message)
|
||||
if(message.method === 'trend') {
|
||||
trendData.value.datetime = base64Decode(message.datetime,true)
|
||||
trendData.value.WtOSC = base64Decode(message.WtOSC,true)
|
||||
trendData.value.WtINS = base64Decode(message.WtINS,true)
|
||||
trendData.value.WtISC = base64Decode(message.WtISC,true)
|
||||
trendData.value.EccentricityINS = base64Decode(message.EccentricityINS,true)
|
||||
trendData.value.EccentricityOSC = base64Decode(message.EccentricityOSC,true)
|
||||
trendData.value.EccentricityISC = base64Decode(message.EccentricityISC,true)
|
||||
trendData.value.DmCORE = base64Decode(message.DmCORE,true)
|
||||
trendData.value.DmALL = base64Decode(message.DmALL,true)
|
||||
console.log(trendData.value,'==')
|
||||
}
|
||||
|
||||
})
|
||||
} catch (error) {
|
||||
ElMessage.error('发送命令失败')
|
||||
}
|
||||
}
|
||||
// 获取设备详细信息
|
||||
const getDeviceDetail = async () => {
|
||||
@ -701,11 +702,13 @@ const getDeviceDetail = async () => {
|
||||
}
|
||||
}
|
||||
onMounted(async() => {
|
||||
mqttConnect()
|
||||
if(route.query.id) {
|
||||
deviceId.value= route.query.id;
|
||||
await getDeviceDetail()
|
||||
}
|
||||
mqttConnect()
|
||||
await sendDeviceTemperature()
|
||||
await sendDeviceTrend()
|
||||
generateData()
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
|
@ -447,12 +447,14 @@ const handleUpdate = async(row) => {
|
||||
if(res.code === 200) {
|
||||
dialog.title = proxy.$t('button.edit')
|
||||
dialog.visible = true
|
||||
dialog.form.deviceName = res.data.deviceName
|
||||
dialog.form.deviceCode = res.data.deviceCode
|
||||
dialog.form.deviceModel = res.data.deviceModel
|
||||
dialog.form.customerId = res.data.customerId
|
||||
dialog.form.userIdList = res.data.userIdList
|
||||
dialog.form.id = res.data.id
|
||||
// dialog.form.deviceName = res.data.deviceName
|
||||
// dialog.form.deviceCode = res.data.deviceCode
|
||||
// dialog.form.deviceModel = res.data.deviceModel
|
||||
// dialog.form.customerId = res.data.customerId
|
||||
// dialog.form.userIdList = res.data.userIdList
|
||||
// dialog.form.id = res.data.id
|
||||
dialog.form = {...res.data}
|
||||
console.log(dialog.form,'dialog.form')
|
||||
} else {
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user