折线图dashboard\big\LineIndex.vue
折线图dashboard\big\lineChart.vue 后续:lineChart.vue里面暂时用生成的数据可视化后面可以改成向后端请求数据 这里折线图新加了一个页面,所以影响了前端路由 顺便完善了一下index.vue
This commit is contained in:
parent
b357bc793c
commit
30520ffafa
@ -125,4 +125,7 @@ src/
|
||||
│ └── routerView/ #路由视图
|
||||
```
|
||||
重要的文件
|
||||
G:\Projects\VueProject\SamATV\src\views\common
|
||||
src/views/common/dashboard/big/index.vue dashboard仪表盘
|
||||
|
||||
前端路由:G:\Projects\VueProject\SamATV\src\router\route.ts
|
||||
|
@ -19,7 +19,7 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
|
||||
path: '/home', name: 'home',
|
||||
component: () => import('/@/views/common/dashboard/atv/index.vue'),
|
||||
meta: {
|
||||
title: 'message.router.home',
|
||||
title: '首页',
|
||||
isLink: '', isHide: false, isKeepAlive: true,
|
||||
isAffix: true, isIframe: false,
|
||||
roles: ['admin', 'common'], icon: 'fa fa-home',
|
||||
@ -33,7 +33,16 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
|
||||
path: '/big', name: 'grafana',
|
||||
component: () => import('/@/views/common/dashboard/big/index.vue'),
|
||||
meta: {
|
||||
title: 'message.router.bigscreen', isIframe: false, isLink: '/big',
|
||||
title: '数据监测', isIframe: false, isLink: '/big',
|
||||
isHide: false, isKeepAlive: false, isAffix: false,
|
||||
roles: ['admin'], icon: 'fa fa-window-restore'
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/line', name: 'line',
|
||||
component: () => import('/@/views/common/dashboard/big/LineIndex.vue'),
|
||||
meta: {
|
||||
title: '具体传感器', isIframe: false, isLink: '/line',
|
||||
isHide: false, isKeepAlive: false, isAffix: false,
|
||||
roles: ['admin'], icon: 'fa fa-window-restore'
|
||||
},
|
||||
@ -42,7 +51,7 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
|
||||
path: '/set_config', name: 'config',
|
||||
component: () => import('/@/views/common/dashboard/config_page/index.vue'),
|
||||
meta: {
|
||||
title: 'message.router.set_config', isIframe: false, isLink: '/set_config',
|
||||
title: '配置管理', isIframe: false, isLink: '/set_config',
|
||||
isHide: false, isKeepAlive: false, isAffix: false,
|
||||
roles: ['admin'], icon: 'fa fa-window-restore'
|
||||
},
|
||||
|
204
src/views/common/dashboard/big/LineIndex.vue
Normal file
204
src/views/common/dashboard/big/LineIndex.vue
Normal file
@ -0,0 +1,204 @@
|
||||
<template>
|
||||
<div className="home">
|
||||
<!-- 这个单选框不知道为啥一直有问题-->
|
||||
<!-- <div class="mb-2 ml-4">-->
|
||||
<!-- <el-radio-group v-model="picRadio">-->
|
||||
<!-- <el-radio value="1" size="large">温度监测图</el-radio>-->
|
||||
<!-- <el-radio value="2" size="large">湿度监测图</el-radio>-->
|
||||
<!-- <el-radio value="3" size="large">应力监测图</el-radio>-->
|
||||
<!-- </el-radio-group>-->
|
||||
<!-- </div>-->
|
||||
<!-- 查询时间范围和按钮 -->
|
||||
<div className="form-container">
|
||||
<el-form-item label="可视化类型:" className="form-item">
|
||||
<el-select
|
||||
v-model="typeValue"
|
||||
placeholder="Select"
|
||||
size="large"
|
||||
style="width: 130px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in typeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="查询时间范围:" className="form-item">
|
||||
<el-date-picker
|
||||
v-model="timeValue"
|
||||
type="datetimerange"
|
||||
range-separator="到"
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
@change="handleDateChange"
|
||||
style="width: 380px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="光栅编号范围:" className="form-item">
|
||||
<el-input-number
|
||||
v-model="gratingIdMin"
|
||||
:min="1"
|
||||
:max="1399"
|
||||
@change="updateSeries"
|
||||
placeholder="最小值"
|
||||
style="width: 150px;"
|
||||
/>
|
||||
<span style="margin: 0 5px;"> - </span>
|
||||
<el-input-number
|
||||
v-model="gratingIdMax"
|
||||
:min="1"
|
||||
:max="1400"
|
||||
@change="updateSeries"
|
||||
placeholder="最大值"
|
||||
style="width: 150px;"
|
||||
/>
|
||||
<el-cascader
|
||||
v-model="value"
|
||||
:options="options"
|
||||
style="width: 150px; margin-left: 10px;"
|
||||
placeholder="其他选项"
|
||||
@change="handleOtherChange"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div className="heatmap-container"></div>
|
||||
<line-chart
|
||||
:gratingIdArray="gratingIdArray"
|
||||
:timeRange="timeValue"
|
||||
:time-granularity="value[1]"
|
||||
:picType="typeValue"
|
||||
/>
|
||||
<!-- 折线图-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from "axios";
|
||||
import LineChart from "/@/views/common/dashboard/big/lineChart.vue"; // 导入折线图组件
|
||||
|
||||
export default {
|
||||
components: { LineChart },
|
||||
data() {
|
||||
return {
|
||||
typeValue: "temperature", // 类型
|
||||
typeOptions: [
|
||||
{
|
||||
value: "temperature",
|
||||
label: "温度监测图",
|
||||
},
|
||||
{
|
||||
value: "humidity",
|
||||
label: "湿度监测图",
|
||||
},
|
||||
{
|
||||
value: "stress",
|
||||
label: "应力监测图",
|
||||
}
|
||||
],
|
||||
// picType: "temperature", // 可视化类型
|
||||
timeValue: [], // 时间范围
|
||||
gratingIdMin: 1, // 光栅编号最小值
|
||||
gratingIdMax: 12, // 光栅编号最大值
|
||||
gratingIdArray: [], // 光栅编号数组
|
||||
value: [], // 级联选择器的值
|
||||
options: [
|
||||
{
|
||||
value: "timeGranularity",
|
||||
label: "时间粒度",
|
||||
children: [
|
||||
{
|
||||
value: "hour",
|
||||
label: "每小时",
|
||||
},
|
||||
{
|
||||
value: "quarterHour",
|
||||
label: "每15分钟",
|
||||
},
|
||||
{
|
||||
value: "minute",
|
||||
label: "每分钟",
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleDateChange() {
|
||||
console.log("选中的时间范围:", this.timeValue);
|
||||
},
|
||||
// 验证输入的光栅编号范围是否合法
|
||||
updateSeries() {
|
||||
if (this.gratingIdMax - this.gratingIdMin < 0) {
|
||||
this.$message.error("请输入正确的光栅编号范围!");
|
||||
}
|
||||
else if (this.gratingIdMax - this.gratingIdMin >=20) {
|
||||
this.$message.error( "请选择20个以内的光栅!");
|
||||
}
|
||||
else{
|
||||
// 生成连续光栅编号的数组
|
||||
this.gratingIdArray = Array.from(
|
||||
{ length: this.gratingIdMax - this.gratingIdMin + 1 },
|
||||
(_, i) => this.gratingIdMin + i
|
||||
)
|
||||
}
|
||||
},
|
||||
// 设置默认的时间范围和光栅编号范围,触发的生命周期:beforeMount()
|
||||
setDefaultXYRange() {
|
||||
// 设置默认时间范围为最近 1 天
|
||||
const now = new Date();
|
||||
const oneDayAgo = new Date();
|
||||
oneDayAgo.setDate(now.getDate() - 1);
|
||||
|
||||
this.timeValue = [oneDayAgo, now];
|
||||
// 设置默认光栅编号范围为 1 到 12
|
||||
this.gratingIdMin = 1;
|
||||
this.gratingIdMax = 12;
|
||||
// 自动触发默认查询
|
||||
this.gratingIdArray = Array.from(
|
||||
{ length: this.gratingIdMax - this.gratingIdMin + 1 },
|
||||
(_, i) => this.gratingIdMin + i
|
||||
)
|
||||
},
|
||||
handleOtherChange(value) {
|
||||
console.log("级联选择器的值:", value);
|
||||
console.log("时间粒度:", value[1]);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
beforeMount() {
|
||||
this.setDefaultXYRange();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.home {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
display: flex;
|
||||
align-items: center; /* 垂直居中对齐 */
|
||||
flex-wrap: wrap; /* 当屏幕宽度不足时自动换行 */
|
||||
margin-top: 10px; /* 与顶部的间距 */
|
||||
margin-bottom: 10px; /* 和 iframe 的间距 */
|
||||
margin-left: 10px;
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-right: 10px; /* 按钮和输入框之间的间距 */
|
||||
}
|
||||
|
||||
</style>
|
@ -61,7 +61,6 @@
|
||||
placeholder="其他选项"
|
||||
@change="handleOtherChange"
|
||||
/>
|
||||
<!-- <el-button type="primary" @click="updateXYRange" style="margin: 0 30px;">查询</el-button>-->
|
||||
</el-form-item>
|
||||
</div>
|
||||
<!-- 热力图的容器 -->
|
||||
@ -72,12 +71,14 @@
|
||||
:picType="typeValue"
|
||||
/>
|
||||
<div class="heatmap-container"></div>
|
||||
<!-- 折线图-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from "axios";
|
||||
import Heatmap from "/@/views/common/dashboard/big/heatmap.vue"; // 导入热力图组件
|
||||
import LineChart from "/@/views/common/dashboard/big/lineChart.vue"; // 导入折线图组件
|
||||
|
||||
export default {
|
||||
components: { Heatmap },
|
||||
@ -135,20 +136,6 @@ export default {
|
||||
}
|
||||
},
|
||||
// 更新时间范围和光栅编号范围
|
||||
updateXYRange() {
|
||||
// 检查是否选择了时间范围
|
||||
if (this.timeValue.length !== 2) {
|
||||
this.$message.error("请选择完整的时间范围!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.gratingIdMax - this.gratingIdMin < 9) {
|
||||
this.$message.error("至少选择10个光栅!");
|
||||
return;
|
||||
}
|
||||
const from = new Date(this.timeValue[0]).getTime(); // 开始时间的时间戳
|
||||
const to = new Date(this.timeValue[1]).getTime(); // 结束时间的时间戳
|
||||
},
|
||||
setDefaultXYRange() {
|
||||
// 设置默认时间范围为最近 1 天
|
||||
const now = new Date();
|
||||
@ -160,7 +147,6 @@ export default {
|
||||
this.gratingIdMin = 1;
|
||||
this.gratingIdMax = 12;
|
||||
// 自动触发默认查询
|
||||
this.updateXYRange();
|
||||
},
|
||||
handleOtherChange(value) {
|
||||
console.log("级联选择器的值:", value);
|
||||
|
225
src/views/common/dashboard/big/lineChart.vue
Normal file
225
src/views/common/dashboard/big/lineChart.vue
Normal file
@ -0,0 +1,225 @@
|
||||
<template>
|
||||
<div ref="chartContainer" style="width: 100%; height: 800px;"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
import { markRaw } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'LineChart',
|
||||
props: {
|
||||
timeRange: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},// 时间范围
|
||||
gratingIdArray: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},// 光栅编号数组
|
||||
timeGranularity: {
|
||||
type: String,
|
||||
default: 'hour'
|
||||
},// 时间粒度
|
||||
picType: {
|
||||
type: String,
|
||||
default: 'temperature'
|
||||
}// 可视化类型
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chart: null,
|
||||
seriesData: [] // 存储折线图数据
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.initChart();
|
||||
},
|
||||
watch: {
|
||||
// 深度监听 timeRange 变化
|
||||
timeRange: {
|
||||
handler() {
|
||||
this.initChart();
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
// 深度监听 gratingIdArray 变化
|
||||
gratingIdArray: {
|
||||
handler() {
|
||||
this.initChart();
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
// 监听 timeGranularity 变化
|
||||
timeGranularity() {
|
||||
this.initChart();
|
||||
},
|
||||
// 监听 picType 变化
|
||||
picType() {
|
||||
this.initChart();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initChart() {
|
||||
// 先销毁旧的 ECharts 实例
|
||||
if (this.chart) {
|
||||
this.chart.dispose();
|
||||
}
|
||||
console.log("picType:", this.picType);
|
||||
// 获取 DOM 元素
|
||||
const chartDom = this.$refs.chartContainer;
|
||||
// 重新初始化 ECharts 实例
|
||||
this.chart = markRaw(echarts.init(chartDom));
|
||||
console.log('timeGranularity:', this.timeGranularity);
|
||||
// 生成时间范围数据
|
||||
let timeData = [];
|
||||
if (this.timeGranularity === 'quarterHour') {
|
||||
timeData = this.generateQuarterHourData();
|
||||
//console.log('timeData:', timeData);
|
||||
} else if (this.timeGranularity === 'minute') {
|
||||
timeData = this.generateMinuteData();
|
||||
//console.log('timeData:', timeData);
|
||||
} else {
|
||||
timeData = this.generateHourData();
|
||||
//console.log('timeData:', timeData);
|
||||
}
|
||||
// 请求光栅数据
|
||||
this.seriesData = this.getGatingData(this.gratingIdArray.length, timeData.length);
|
||||
// 配置折线图选项
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: function (params) {
|
||||
// params 是当前坐标轴位置所有系列的数据数组
|
||||
let tip = `<div style="font-size: 14px;">${params[0].name}</div>`; // x轴时间
|
||||
tip += params.map(item => {
|
||||
return `<div style="color: ${item.color}; margin: 4px 0;">${item.seriesName}: ${item.value}</div>`;
|
||||
}).join('');
|
||||
return tip;
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: this.$props.gratingIdArray.map(id => `光栅 ${id}`)
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
toolbox: {
|
||||
feature: {
|
||||
saveAsImage: {}
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: timeData
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: this.seriesData
|
||||
};
|
||||
|
||||
console.log('seriesData:', this.seriesData);
|
||||
// 使用配置项显示图表
|
||||
// console.log('option:', option)
|
||||
// console.log('Legend Data:', option.legend.data);
|
||||
// console.log('Series Names:', option.series.map(s => s.name));
|
||||
this.chart.setOption(option);
|
||||
},
|
||||
// 生成按小时划分的时间点数组
|
||||
generateHourData() {
|
||||
const [start, end] = this.timeRange;
|
||||
const startTime = new Date(start);
|
||||
const endTime = new Date(end);
|
||||
const timeData = [];
|
||||
const currentTime = new Date(startTime);
|
||||
while (currentTime < endTime) {
|
||||
timeData.push(currentTime.toLocaleString());
|
||||
currentTime.setHours(currentTime.getHours() + 1);
|
||||
}
|
||||
return timeData;
|
||||
},
|
||||
// 生成按照 15 分钟划分的时间点数组
|
||||
generateQuarterHourData() {
|
||||
const [start, end] = this.timeRange;
|
||||
const startTime = new Date(start);
|
||||
const endTime = new Date(end);
|
||||
const timeData = [];
|
||||
const currentTime = new Date(startTime);
|
||||
while (currentTime < endTime) {
|
||||
timeData.push(currentTime.toLocaleString());
|
||||
currentTime.setMinutes(currentTime.getMinutes() + 15);
|
||||
}
|
||||
return timeData;
|
||||
},
|
||||
// 生成按照 1 分钟划分的时间点数组
|
||||
generateMinuteData() {
|
||||
const [start, end] = this.timeRange;
|
||||
const startTime = new Date(start);
|
||||
const endTime = new Date(end);
|
||||
const timeData = [];
|
||||
const currentTime = new Date(startTime);
|
||||
while (currentTime < endTime) {
|
||||
timeData.push(currentTime.toLocaleString());
|
||||
currentTime.setMinutes(currentTime.getMinutes() + 1);
|
||||
}
|
||||
return timeData;
|
||||
},
|
||||
// 生成光栅编号数据
|
||||
// 向后端请求数据,参数就看props,处理后的数据和data格式一样即可
|
||||
getGatingData(rows, cols) {
|
||||
let data = [];
|
||||
console.log('cols:', cols, 'rows:', rows);
|
||||
for (let i = 0; i < rows; i++) {
|
||||
let oneLine = [];
|
||||
for (let j = 0; j < cols; j++) {
|
||||
oneLine.push(Math.floor(Math.random() * 100));
|
||||
}
|
||||
data.push(oneLine);
|
||||
}
|
||||
console.log("data", data);
|
||||
return this.processSeriesData(data);
|
||||
},
|
||||
// 处理后端返回的数据,将二维数组转换为 ECharts 所需的格式
|
||||
// processSeriesData(seriesData) {
|
||||
// const rows = seriesData.length;
|
||||
// const cols = seriesData[0].length;
|
||||
// const data = [];
|
||||
// let legendData = this.gratingIdArray.map(id => `光栅 ${id}`);
|
||||
// for (let i = 0; i < rows; i++) {
|
||||
// let oneLine = {};
|
||||
// oneLine['name'] = legendData[i];
|
||||
// oneLine['type'] = 'line';
|
||||
// // oneLine['stack'] = 'Total';
|
||||
// oneLine['data'] = seriesData[i];
|
||||
// data.push(oneLine);
|
||||
// }
|
||||
//
|
||||
// return data;
|
||||
// }
|
||||
processSeriesData(data) {
|
||||
const legendData = this.gratingIdArray.map(id => `光栅 ${id}`);
|
||||
return data.map((rowData, index) => ({
|
||||
name: legendData[index],
|
||||
type: 'line',
|
||||
// 删除 stack: 'Total'
|
||||
data: rowData
|
||||
}));
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.chart) {
|
||||
this.chart.dispose();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 组件样式 */
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user