|
@@ -1,5 +1,5 @@
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
-import { onMounted, ref } from 'vue';
|
|
|
|
|
|
+import { ref } from 'vue';
|
|
import VChart from 'vue-echarts';
|
|
import VChart from 'vue-echarts';
|
|
import { LineChart, PieChart } from 'echarts/charts';
|
|
import { LineChart, PieChart } from 'echarts/charts';
|
|
import {
|
|
import {
|
|
@@ -35,9 +35,10 @@ const list: number[] = [];
|
|
|
|
|
|
interface Props {
|
|
interface Props {
|
|
data: MonitoringPointData;
|
|
data: MonitoringPointData;
|
|
|
|
+ monitoringId?: number;
|
|
}
|
|
}
|
|
|
|
|
|
-const emit = defineEmits(['editorClick']);
|
|
|
|
|
|
+const emit = defineEmits(['editorClick', 'historicalDataClick']);
|
|
|
|
|
|
const props = defineProps<Props>();
|
|
const props = defineProps<Props>();
|
|
|
|
|
|
@@ -51,48 +52,53 @@ const getCurvedData = () => {
|
|
return list;
|
|
return list;
|
|
};
|
|
};
|
|
|
|
|
|
-const maxValue = 20;
|
|
|
|
|
|
+const getColor = (value: number) => {
|
|
|
|
+ if (props.data.status === 1) {
|
|
|
|
+ if (value === 1) {
|
|
|
|
+ return '#32BAC0';
|
|
|
|
+ } else if (value === 2) {
|
|
|
|
+ return 'rgba(50,186,192,0.15)';
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (props.data.status === 2 || props.data.status === 3) {
|
|
|
|
+ if (value === 1) {
|
|
|
|
+ return '#F56C6C';
|
|
|
|
+ } else if (value === 2) {
|
|
|
|
+ return 'rgba(245,108,108,0.15)';
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (props.data.status === 0 || props.data.status === -1 || !props.data.status) {
|
|
|
|
+ if (value === 1) {
|
|
|
|
+ return '#999';
|
|
|
|
+ } else if (value === 2) {
|
|
|
|
+ return 'rgba(153,153,153,0.15)';
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
|
|
const option = ref({
|
|
const option = ref({
|
|
- backgroundColor: 'rgba(50, 186, 192, 0.15)',
|
|
|
|
- grid: {
|
|
|
|
- left: '5%',
|
|
|
|
- right: '5%',
|
|
|
|
- top: '5%',
|
|
|
|
- bottom: '5%',
|
|
|
|
- containLabel: true,
|
|
|
|
- backgroundColor: 'rgba(50,186,192,0.15)',
|
|
|
|
- borderRadius: 8,
|
|
|
|
- },
|
|
|
|
|
|
+ backgroundColor: getColor(2),
|
|
|
|
+
|
|
xAxis: {
|
|
xAxis: {
|
|
show: false, // 隐藏 X 轴
|
|
show: false, // 隐藏 X 轴
|
|
type: 'category',
|
|
type: 'category',
|
|
- data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
|
|
|
|
|
|
+ boundaryGap: false, // 关闭首尾留白
|
|
},
|
|
},
|
|
yAxis: {
|
|
yAxis: {
|
|
- type: 'value',
|
|
|
|
- // max: maxValue, // 设置 Y 轴最大值
|
|
|
|
- axisLine: { show: false }, // 隐藏轴线
|
|
|
|
- axisTick: { show: false }, // 隐藏刻度
|
|
|
|
- position: 'left',
|
|
|
|
- axisLabel: {
|
|
|
|
- show: true,
|
|
|
|
- color: '#666',
|
|
|
|
- formatter(value: number) {
|
|
|
|
- // 只显示最大值标签
|
|
|
|
- return value === maxValue ? value : '';
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- splitLine: {
|
|
|
|
- show: false, // 关闭默认分割线
|
|
|
|
- },
|
|
|
|
|
|
+ type: 'value', // 数值轴
|
|
|
|
+ min: 0, // 最小值
|
|
|
|
+ max: 100, // 最大值
|
|
|
|
+ interval: 20, // 刻度间隔
|
|
|
|
+ show: false, // 隐藏 X 轴
|
|
},
|
|
},
|
|
series: [
|
|
series: [
|
|
{
|
|
{
|
|
type: 'line',
|
|
type: 'line',
|
|
data: getCurvedData(),
|
|
data: getCurvedData(),
|
|
symbol: 'none', // 不显示数据点
|
|
symbol: 'none', // 不显示数据点
|
|
- color: '#32BAC0',
|
|
|
|
|
|
+ color: getColor(1),
|
|
lineStyle: {
|
|
lineStyle: {
|
|
width: 2,
|
|
width: 2,
|
|
},
|
|
},
|
|
@@ -100,41 +106,69 @@ const option = ref({
|
|
// 添加最大值虚线
|
|
// 添加最大值虚线
|
|
silent: true,
|
|
silent: true,
|
|
symbol: 'none',
|
|
symbol: 'none',
|
|
- label: { show: false },
|
|
|
|
|
|
+
|
|
lineStyle: {
|
|
lineStyle: {
|
|
type: 'dashed',
|
|
type: 'dashed',
|
|
- color: '#333',
|
|
|
|
|
|
+ color: 'rgba(151,151,151,0.5)',
|
|
width: 1,
|
|
width: 1,
|
|
},
|
|
},
|
|
|
|
+ label: {
|
|
|
|
+ show: true, // 必须开启标签
|
|
|
|
+ position: 'insideStartTop', // 标签位置(左侧上方)
|
|
|
|
+ formatter: '{c}°C', // 显示值({c} 会自动替换为 yAxis 的值)
|
|
|
|
+ color: 'rgba(0,0,0,0.5)', // 文字颜色
|
|
|
|
+ verticalAlign: 'bottom', // 垂直对齐方式
|
|
|
|
+ offset: [-6, 0], // 微调位置 [水平偏移, 垂直偏移]
|
|
|
|
+ fontSize: '10px',
|
|
|
|
+ },
|
|
data: [
|
|
data: [
|
|
{
|
|
{
|
|
- yAxis: maxValue, // 在最大值位置画线
|
|
|
|
|
|
+ yAxis: props.data.tempUpper, // 在最大值位置画线
|
|
},
|
|
},
|
|
],
|
|
],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
],
|
|
],
|
|
|
|
+ // 关键配置:调整 grid 边距
|
|
|
|
+ grid: {
|
|
|
|
+ top: 20, // 上边距为0
|
|
|
|
+ right: 8, // 右边距为0
|
|
|
|
+ bottom: 8, // 下边距为0
|
|
|
|
+ left: 8, // 左边距为0
|
|
|
|
+ containLabel: false, // 不包含坐标轴标签区域
|
|
|
|
+ },
|
|
});
|
|
});
|
|
|
|
|
|
-onMounted(() => {});
|
|
|
|
const editorMonitoring = (id: number) => {
|
|
const editorMonitoring = (id: number) => {
|
|
emit('editorClick', id);
|
|
emit('editorClick', id);
|
|
};
|
|
};
|
|
|
|
+
|
|
|
|
+const addHistoricalData = (data: MonitoringPointData) => {
|
|
|
|
+ emit('historicalDataClick', data);
|
|
|
|
+};
|
|
</script>
|
|
</script>
|
|
|
|
|
|
<template>
|
|
<template>
|
|
- <div class="line-chart-content">
|
|
|
|
|
|
+ <div :class="monitoringId === data.id ? 'line-chart-content choose-content-border' : 'line-chart-content'">
|
|
<AFlex justify="space-between" align="center">
|
|
<AFlex justify="space-between" align="center">
|
|
<div class="line-chart-header-text">{{ data.name }}</div>
|
|
<div class="line-chart-header-text">{{ data.name }}</div>
|
|
<SvgIcon class="line-chart-header-icon" @click="editorMonitoring(data.id)" name="adjustment" />
|
|
<SvgIcon class="line-chart-header-icon" @click="editorMonitoring(data.id)" name="adjustment" />
|
|
</AFlex>
|
|
</AFlex>
|
|
- <div style="width: 172px; height: 94px; margin-top: 12px">
|
|
|
|
- <VChart class="chart" :option="option" />
|
|
|
|
|
|
+ <div @click="addHistoricalData(data)" class="chart-container" style="cursor: pointer">
|
|
|
|
+ <VChart class="chart chart-bgc" :option="option" />
|
|
</div>
|
|
</div>
|
|
<AFlex justify="space-between" align="center" class="line-chart-footer">
|
|
<AFlex justify="space-between" align="center" class="line-chart-footer">
|
|
<AFlex align="center">
|
|
<AFlex align="center">
|
|
- <AFlex justify="center" align="center" class="line-chart-footer-div">
|
|
|
|
- <SvgIcon class="line-chart-icon" name="temperature"
|
|
|
|
|
|
+ <AFlex
|
|
|
|
+ justify="center"
|
|
|
|
+ align="center"
|
|
|
|
+ class="line-chart-footer-div"
|
|
|
|
+ :style="`background:${props.data.status === 0 || props.data.status === -1 || !props.data.status ? '#F0F0F0' : '#f2fcf9'}`"
|
|
|
|
+ >
|
|
|
|
+ <SvgIcon
|
|
|
|
+ class="line-chart-icon"
|
|
|
|
+ :style="`color:${props.data.status === 0 || props.data.status === -1 || !props.data.status ? '#999' : '#32BAC0'}`"
|
|
|
|
+ name="temperature"
|
|
/></AFlex>
|
|
/></AFlex>
|
|
<div>
|
|
<div>
|
|
<span class="line-chart-footer-text">{{ data.temperature }}</span>
|
|
<span class="line-chart-footer-text">{{ data.temperature }}</span>
|
|
@@ -142,8 +176,15 @@ const editorMonitoring = (id: number) => {
|
|
</div>
|
|
</div>
|
|
</AFlex>
|
|
</AFlex>
|
|
<AFlex align="center">
|
|
<AFlex align="center">
|
|
- <AFlex justify="center" align="center" class="line-chart-footer-div"
|
|
|
|
- ><SvgIcon class="line-chart-icon" name="humidity"
|
|
|
|
|
|
+ <AFlex
|
|
|
|
+ justify="center"
|
|
|
|
+ align="center"
|
|
|
|
+ class="line-chart-footer-div"
|
|
|
|
+ :style="`background:${props.data.status === 0 || props.data.status === -1 || !props.data.status ? '#F0F0F0' : '#f2fcf9'}`"
|
|
|
|
+ ><SvgIcon
|
|
|
|
+ class="line-chart-icon"
|
|
|
|
+ :style="`color:${props.data.status === 0 || props.data.status === -1 || !props.data.status ? '#999' : '#32BAC0'}`"
|
|
|
|
+ name="humidity"
|
|
/></AFlex>
|
|
/></AFlex>
|
|
<div>
|
|
<div>
|
|
<span class="line-chart-footer-text">{{ data.humidity }}</span>
|
|
<span class="line-chart-footer-text">{{ data.humidity }}</span>
|
|
@@ -155,9 +196,23 @@ const editorMonitoring = (id: number) => {
|
|
</template>
|
|
</template>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
<style lang="scss" scoped>
|
|
|
|
+/* 确保图表区域继承光标样式 */
|
|
|
|
+.chart-container :deep(canvas) {
|
|
|
|
+ cursor: pointer !important;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.chart-bgc {
|
|
|
|
+ width: 172px;
|
|
|
|
+ height: 94px;
|
|
|
|
+ margin-top: 12px; /* 关键:隐藏图表溢出部分 */
|
|
|
|
+ overflow: hidden;
|
|
|
|
+ cursor: pointer;
|
|
|
|
+ border-radius: 8px; /* 圆角 */
|
|
|
|
+}
|
|
|
|
+
|
|
.line-chart-icon {
|
|
.line-chart-icon {
|
|
font-size: 16px;
|
|
font-size: 16px;
|
|
- color: var(--antd-color-primary-hover);
|
|
|
|
|
|
+ color: #32bac0;
|
|
}
|
|
}
|
|
|
|
|
|
.line-chart-footer-unit {
|
|
.line-chart-footer-unit {
|
|
@@ -211,4 +266,12 @@ const editorMonitoring = (id: number) => {
|
|
border-radius: 8px;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 6px 0 rgb(0 0 0 / 10%);
|
|
box-shadow: 0 2px 6px 0 rgb(0 0 0 / 10%);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+.choose-content-border {
|
|
|
|
+ border: 2px solid var(--antd-color-primary-hover);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.line-chart-content:hover {
|
|
|
|
+ border: 2px solid var(--antd-color-primary-hover);
|
|
|
|
+}
|
|
</style>
|
|
</style>
|