feat(监控): 添加过程跟踪组件及主页面集成
添加TrackMeasure组件用于展示过程跟踪数据,包括入口、炉温、涂层和出口数据的实时监控图表 组件支持WebSocket连接、数据实时更新、图表切换和响应式布局 在主页面中集成该组件并设置相关数据绑定
This commit is contained in:
489
apps/l2/src/components/TrackMeasure/index.vue
Normal file
489
apps/l2/src/components/TrackMeasure/index.vue
Normal file
@@ -0,0 +1,489 @@
|
|||||||
|
<template>
|
||||||
|
<div class="process-monitor">
|
||||||
|
<!-- 控制区 -->
|
||||||
|
<div class="control-bar">
|
||||||
|
<div class="chart-selector">
|
||||||
|
<label>图表视图:</label>
|
||||||
|
<select v-model="currentChart" @change="handleChartChange">
|
||||||
|
<option v-for="chart in chartTypes" :key="chart.value" :value="chart.value">
|
||||||
|
{{ chart.label }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="connection-status" :class="{ connected: isConnected }">
|
||||||
|
连接状态:{{ isConnected ? '已连接' : '连接中...' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 图表展示区 -->
|
||||||
|
<div class="chart-container">
|
||||||
|
<h3 class="chart-title">{{ currentChartLabel }}</h3>
|
||||||
|
<div ref="chartDom" class="chart"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ProcessTrackMonitor',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// WebSocket相关(固定为track_measure)
|
||||||
|
socket: null,
|
||||||
|
isConnected: false,
|
||||||
|
|
||||||
|
// 图表相关
|
||||||
|
chartTypes: [
|
||||||
|
{ value: 'entry', label: '入口数据监控' },
|
||||||
|
{ value: 'furnace', label: '炉温数据监控' },
|
||||||
|
{ value: 'coat', label: '涂层数据监控' },
|
||||||
|
{ value: 'exit', label: '出口数据监控' }
|
||||||
|
],
|
||||||
|
currentChart: 'entry', // 默认显示入口数据图表
|
||||||
|
chartInstance: null, // 当前图表实例
|
||||||
|
|
||||||
|
// 图表数据存储
|
||||||
|
chartData: {
|
||||||
|
entry: {
|
||||||
|
time: [],
|
||||||
|
tensionPorBr1: [],
|
||||||
|
tensionBr1Br2: [],
|
||||||
|
tensionBr2Br3: [],
|
||||||
|
stripSpeed: []
|
||||||
|
},
|
||||||
|
furnace: {
|
||||||
|
time: [],
|
||||||
|
phFurnaceTemperatureActual: [],
|
||||||
|
nof1FurnaceTemperatureActual: [],
|
||||||
|
nof1FurnaceTemperatureSet: []
|
||||||
|
},
|
||||||
|
coat: {
|
||||||
|
time: [],
|
||||||
|
avrCoatingWeightTop: [],
|
||||||
|
avrCoatingWeightBottom: [],
|
||||||
|
airKnifePressure: [],
|
||||||
|
stripSpeedTmExit: []
|
||||||
|
},
|
||||||
|
exit: {
|
||||||
|
time: [],
|
||||||
|
tensionBr8Br9: [],
|
||||||
|
tensionBr9Tr: [],
|
||||||
|
speedExitSection: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
maxDataPoints: 30 // 最多显示的数据点数量
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 当前图表标题
|
||||||
|
currentChartLabel() {
|
||||||
|
const chart = this.chartTypes.find(item => item.value === this.currentChart);
|
||||||
|
return chart ? chart.label : '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 初始化图表
|
||||||
|
this.initChart();
|
||||||
|
// 建立WebSocket连接(固定为track_measure)
|
||||||
|
this.connectWebSocket();
|
||||||
|
// 监听窗口大小变化
|
||||||
|
window.addEventListener('resize', this.handleWindowResize);
|
||||||
|
},
|
||||||
|
unmounted() {
|
||||||
|
// 清理资源
|
||||||
|
this.disconnectWebSocket();
|
||||||
|
this.destroyChart();
|
||||||
|
window.removeEventListener('resize', this.handleWindowResize);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 初始化当前图表
|
||||||
|
initChart() {
|
||||||
|
// 先销毁已有实例
|
||||||
|
this.destroyChart();
|
||||||
|
|
||||||
|
// 初始化新图表
|
||||||
|
if (this.$refs.chartDom) {
|
||||||
|
this.chartInstance = echarts.init(this.$refs.chartDom);
|
||||||
|
this.chartInstance.setOption(this.getChartOption());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 根据当前图表类型获取配置
|
||||||
|
getChartOption() {
|
||||||
|
const baseOption = {
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
tooltip: { trigger: 'axis' },
|
||||||
|
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
data: this.chartData[this.currentChart].time,
|
||||||
|
axisLine: { lineStyle: { color: '#666' } },
|
||||||
|
axisLabel: { color: '#b0b0b0' }
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
axisLine: { lineStyle: { color: '#666' } },
|
||||||
|
axisLabel: { color: '#b0b0b0' },
|
||||||
|
splitLine: { lineStyle: { color: 'rgba(255, 255, 255, 0.1)' } }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 不同图表的系列配置
|
||||||
|
switch (this.currentChart) {
|
||||||
|
case 'entry':
|
||||||
|
return {
|
||||||
|
...baseOption,
|
||||||
|
legend: {
|
||||||
|
data: ['入口张力1', '入口张力2', '入口张力3', '带钢速度'],
|
||||||
|
textStyle: { color: '#e0e0e0' }
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{ name: '入口张力1', type: 'line', data: this.chartData.entry.tensionPorBr1, smooth: true, lineStyle: { width: 2 } },
|
||||||
|
{ name: '入口张力2', type: 'line', data: this.chartData.entry.tensionBr1Br2, smooth: true, lineStyle: { width: 2 } },
|
||||||
|
{ name: '入口张力3', type: 'line', data: this.chartData.entry.tensionBr2Br3, smooth: true, lineStyle: { width: 2 } },
|
||||||
|
{ name: '带钢速度', type: 'line', data: this.chartData.entry.stripSpeed, smooth: true, lineStyle: { width: 2 } }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
case 'furnace':
|
||||||
|
return {
|
||||||
|
...baseOption,
|
||||||
|
legend: {
|
||||||
|
data: ['PH炉实际温度', 'NOF1炉实际温度', 'NOF1炉设定温度'],
|
||||||
|
textStyle: { color: '#e0e0e0' }
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{ name: 'PH炉实际温度', type: 'line', data: this.chartData.furnace.phFurnaceTemperatureActual, smooth: true, lineStyle: { width: 2 } },
|
||||||
|
{ name: 'NOF1炉实际温度', type: 'line', data: this.chartData.furnace.nof1FurnaceTemperatureActual, smooth: true, lineStyle: { width: 2 } },
|
||||||
|
{ name: 'NOF1炉设定温度', type: 'line', data: this.chartData.furnace.nof1FurnaceTemperatureSet, smooth: true, lineStyle: { width: 2, type: 'dashed' } }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
case 'coat':
|
||||||
|
return {
|
||||||
|
...baseOption,
|
||||||
|
legend: {
|
||||||
|
data: ['顶部平均涂层重量', '底部平均涂层重量', '气刀压力', '出口速度'],
|
||||||
|
textStyle: { color: '#e0e0e0' }
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{ name: '顶部平均涂层重量', type: 'line', data: this.chartData.coat.avrCoatingWeightTop, smooth: true, lineStyle: { width: 2 } },
|
||||||
|
{ name: '底部平均涂层重量', type: 'line', data: this.chartData.coat.avrCoatingWeightBottom, smooth: true, lineStyle: { width: 2 } },
|
||||||
|
{ name: '气刀压力', type: 'line', data: this.chartData.coat.airKnifePressure, smooth: true, lineStyle: { width: 2 } },
|
||||||
|
{ name: '出口速度', type: 'line', data: this.chartData.coat.stripSpeedTmExit, smooth: true, lineStyle: { width: 2 } }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
case 'exit':
|
||||||
|
return {
|
||||||
|
...baseOption,
|
||||||
|
legend: {
|
||||||
|
data: ['出口张力1', '出口张力2', '出口速度'],
|
||||||
|
textStyle: { color: '#e0e0e0' }
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{ name: '出口张力1', type: 'line', data: this.chartData.exit.tensionBr8Br9, smooth: true, lineStyle: { width: 2 } },
|
||||||
|
{ name: '出口张力2', type: 'line', data: this.chartData.exit.tensionBr9Tr, smooth: true, lineStyle: { width: 2 } },
|
||||||
|
{ name: '出口速度', type: 'line', data: this.chartData.exit.speedExitSection, smooth: true, lineStyle: { width: 2 } }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
default:
|
||||||
|
return baseOption;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 处理窗口大小变化
|
||||||
|
handleWindowResize() {
|
||||||
|
if (this.chartInstance) {
|
||||||
|
this.chartInstance.resize();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 销毁当前图表
|
||||||
|
destroyChart() {
|
||||||
|
if (this.chartInstance) {
|
||||||
|
this.chartInstance.dispose();
|
||||||
|
this.chartInstance = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 建立WebSocket连接(固定连接track_measure)
|
||||||
|
connectWebSocket() {
|
||||||
|
// 先断开现有连接
|
||||||
|
this.disconnectWebSocket();
|
||||||
|
|
||||||
|
this.isConnected = false;
|
||||||
|
const url = 'ws://140.143.206.120:18081/websocket?type=track_measure';
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.socket = new WebSocket(url);
|
||||||
|
|
||||||
|
this.socket.onopen = () => {
|
||||||
|
console.log('WebSocket连接已建立(track_measure)');
|
||||||
|
this.isConnected = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.socket.onmessage = (event) => {
|
||||||
|
this.processData(event.data);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.socket.onerror = (error) => {
|
||||||
|
console.error('WebSocket错误:', error);
|
||||||
|
this.isConnected = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.socket.onclose = (event) => {
|
||||||
|
console.log(`WebSocket连接已关闭: ${event.code} - ${event.reason}`);
|
||||||
|
this.isConnected = false;
|
||||||
|
|
||||||
|
// 自动重连(非主动关闭)
|
||||||
|
if (event.code !== 1000) {
|
||||||
|
setTimeout(() => this.connectWebSocket(), 3000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('建立WebSocket连接失败:', error);
|
||||||
|
setTimeout(() => this.connectWebSocket(), 3000);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 断开WebSocket连接
|
||||||
|
disconnectWebSocket() {
|
||||||
|
if (this.socket) {
|
||||||
|
this.socket.close(1000, '主动关闭');
|
||||||
|
this.socket = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 处理图表切换
|
||||||
|
handleChartChange() {
|
||||||
|
this.initChart();
|
||||||
|
},
|
||||||
|
|
||||||
|
// 处理接收到的数据
|
||||||
|
processData(data) {
|
||||||
|
try {
|
||||||
|
const parsedData = JSON.parse(data);
|
||||||
|
this.processTrackMeasureData(parsedData);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('数据解析错误:', error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 处理track_measure类型数据
|
||||||
|
processTrackMeasureData(data) {
|
||||||
|
// 获取当前时间标签(分:秒.毫秒)
|
||||||
|
const now = new Date();
|
||||||
|
const timeLabel = `${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}.${now.getMilliseconds().toString().slice(0, 2)}`;
|
||||||
|
|
||||||
|
// 处理入口数据
|
||||||
|
if (data.appMeasureEntryMessage) {
|
||||||
|
this.addDataPoint('entry', timeLabel, {
|
||||||
|
tensionPorBr1: data.appMeasureEntryMessage.tensionPorBr1,
|
||||||
|
tensionBr1Br2: data.appMeasureEntryMessage.tensionBr1Br2,
|
||||||
|
tensionBr2Br3: data.appMeasureEntryMessage.tensionBr2Br3,
|
||||||
|
stripSpeed: data.appMeasureEntryMessage.stripSpeed
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理炉温数据
|
||||||
|
if (data.appMeasureFurnaceMessage) {
|
||||||
|
this.addDataPoint('furnace', timeLabel, {
|
||||||
|
phFurnaceTemperatureActual: data.appMeasureFurnaceMessage.phFurnaceTemperatureActual,
|
||||||
|
nof1FurnaceTemperatureActual: data.appMeasureFurnaceMessage.nof1FurnaceTemperatureActual,
|
||||||
|
nof1FurnaceTemperatureSet: data.appMeasureFurnaceMessage.nof1FurnaceTemperatureSet
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理涂层数据
|
||||||
|
if (data.appMeasureCoatMessage) {
|
||||||
|
this.addDataPoint('coat', timeLabel, {
|
||||||
|
avrCoatingWeightTop: data.appMeasureCoatMessage.avrCoatingWeightTop,
|
||||||
|
avrCoatingWeightBottom: data.appMeasureCoatMessage.avrCoatingWeightBottom,
|
||||||
|
airKnifePressure: data.appMeasureCoatMessage.airKnifePressure,
|
||||||
|
stripSpeedTmExit: data.appMeasureCoatMessage.stripSpeedTmExit
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理出口数据
|
||||||
|
if (data.appMeasureExitMessage) {
|
||||||
|
this.addDataPoint('exit', timeLabel, {
|
||||||
|
tensionBr8Br9: data.appMeasureExitMessage.tensionBr8Br9,
|
||||||
|
tensionBr9Tr: data.appMeasureExitMessage.tensionBr9Tr,
|
||||||
|
speedExitSection: data.appMeasureExitMessage.speedExitSection
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新当前显示的图表
|
||||||
|
this.updateCurrentChart();
|
||||||
|
},
|
||||||
|
|
||||||
|
// 添加数据点到对应图表数据
|
||||||
|
addDataPoint(chartType, time, values) {
|
||||||
|
// 添加时间标签
|
||||||
|
this.chartData[chartType].time.push(time);
|
||||||
|
|
||||||
|
// 添加各项数据
|
||||||
|
Object.keys(values).forEach(key => {
|
||||||
|
if (this.chartData[chartType][key] !== undefined) {
|
||||||
|
this.chartData[chartType][key].push(values[key]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 保持数据点数量在maxDataPoints以内
|
||||||
|
if (this.chartData[chartType].time.length > this.maxDataPoints) {
|
||||||
|
this.chartData[chartType].time.shift();
|
||||||
|
|
||||||
|
Object.keys(values).forEach(key => {
|
||||||
|
if (this.chartData[chartType][key] !== undefined) {
|
||||||
|
this.chartData[chartType][key].shift();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 更新当前显示的图表
|
||||||
|
updateCurrentChart() {
|
||||||
|
if (this.chartInstance) {
|
||||||
|
this.chartInstance.setOption({
|
||||||
|
xAxis: { data: this.chartData[this.currentChart].time },
|
||||||
|
series: this.getSeriesData()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取当前图表的系列数据
|
||||||
|
getSeriesData() {
|
||||||
|
switch (this.currentChart) {
|
||||||
|
case 'entry':
|
||||||
|
return [
|
||||||
|
{ data: this.chartData.entry.tensionPorBr1 },
|
||||||
|
{ data: this.chartData.entry.tensionBr1Br2 },
|
||||||
|
{ data: this.chartData.entry.tensionBr2Br3 },
|
||||||
|
{ data: this.chartData.entry.stripSpeed }
|
||||||
|
];
|
||||||
|
|
||||||
|
case 'furnace':
|
||||||
|
return [
|
||||||
|
{ data: this.chartData.furnace.phFurnaceTemperatureActual },
|
||||||
|
{ data: this.chartData.furnace.nof1FurnaceTemperatureActual },
|
||||||
|
{ data: this.chartData.furnace.nof1FurnaceTemperatureSet }
|
||||||
|
];
|
||||||
|
|
||||||
|
case 'coat':
|
||||||
|
return [
|
||||||
|
{ data: this.chartData.coat.avrCoatingWeightTop },
|
||||||
|
{ data: this.chartData.coat.avrCoatingWeightBottom },
|
||||||
|
{ data: this.chartData.coat.airKnifePressure },
|
||||||
|
{ data: this.chartData.coat.stripSpeedTmExit }
|
||||||
|
];
|
||||||
|
|
||||||
|
case 'exit':
|
||||||
|
return [
|
||||||
|
{ data: this.chartData.exit.tensionBr8Br9 },
|
||||||
|
{ data: this.chartData.exit.tensionBr9Tr },
|
||||||
|
{ data: this.chartData.exit.speedExitSection }
|
||||||
|
];
|
||||||
|
|
||||||
|
default:
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.process-monitor {
|
||||||
|
padding: 20px;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
background-color: #3f4449;
|
||||||
|
color: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-selector {
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #4a4f55;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-selector label {
|
||||||
|
margin-right: 10px;
|
||||||
|
color: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-selector select {
|
||||||
|
padding: 5px 10px;
|
||||||
|
border: 1px solid #5d6268;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #555a60;
|
||||||
|
color: #e0e0e0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connection-status {
|
||||||
|
padding: 8px 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #4a4f55;
|
||||||
|
color: #ffd700;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connection-status.connected {
|
||||||
|
color: #32cd32;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
background-color: #4a4f55;
|
||||||
|
border-radius: 6px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-title {
|
||||||
|
margin-top: 0;
|
||||||
|
color: #f0f0f0;
|
||||||
|
font-size: 18px;
|
||||||
|
border-bottom: 1px solid #5d6268;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart {
|
||||||
|
width: 100%;
|
||||||
|
height: 400px; /* 增大图表高度提升可读性 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式调整 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.control-bar {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connection-status {
|
||||||
|
margin-left: 0;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart {
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -47,6 +47,17 @@
|
|||||||
/>
|
/>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-card>
|
||||||
|
<div slot="header"><span>过程跟踪</span></div>
|
||||||
|
<TrackMeasure
|
||||||
|
v-loading="measureLoading"
|
||||||
|
:columns="measureColumns"
|
||||||
|
:data="measureData"
|
||||||
|
tableHeight="300px"
|
||||||
|
/>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -59,10 +70,11 @@ import MiniTable from "./components/MiniTable.vue";
|
|||||||
import { getLogDataPage } from "@/api/l2/log";
|
import { getLogDataPage } from "@/api/l2/log";
|
||||||
import { getRollHistorytList } from '@/api/l2/roller'
|
import { getRollHistorytList } from '@/api/l2/roller'
|
||||||
import { listPlan } from "@/api/l2/plan";
|
import { listPlan } from "@/api/l2/plan";
|
||||||
|
import TrackMeasure from "@/components/TrackMeasure/index.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Index",
|
name: "Index",
|
||||||
components: { CurrentTime, HomeMain, MiniTable },
|
components: { CurrentTime, HomeMain, MiniTable, TrackMeasure },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
featureCards: [
|
featureCards: [
|
||||||
|
|||||||
Reference in New Issue
Block a user