Quellcode durchsuchen

feat(components): 初步添加“折线图”组件

wangshun vor 2 Monaten
Ursprung
Commit
37c79797e3
1 geänderte Dateien mit 214 neuen und 0 gelöschten Zeilen
  1. 214 0
      src/components/LineChart.vue

+ 214 - 0
src/components/LineChart.vue

@@ -0,0 +1,214 @@
+<script setup lang="ts">
+import { onMounted, ref } from 'vue';
+import VChart from 'vue-echarts';
+import { LineChart, PieChart } from 'echarts/charts';
+import {
+  DatasetComponent,
+  GridComponent,
+  LegendComponent,
+  MarkLineComponent,
+  TitleComponent,
+  TooltipComponent,
+  TransformComponent,
+} from 'echarts/components';
+import { use } from 'echarts/core';
+import { CanvasRenderer } from 'echarts/renderers';
+
+import SvgIcon from './SvgIcon.vue';
+
+import type { MonitoringPointData } from '@/types';
+
+use([
+  CanvasRenderer,
+  TitleComponent,
+  DatasetComponent,
+  TransformComponent,
+  TooltipComponent,
+  LegendComponent,
+  GridComponent,
+  LineChart,
+  PieChart,
+  MarkLineComponent,
+]);
+
+const list: number[] = [];
+
+interface Props {
+  data: MonitoringPointData;
+}
+
+const emit = defineEmits(['editorClick']);
+
+const props = defineProps<Props>();
+
+const getCurvedData = () => {
+  if (props.data.tempData) {
+    props.data.tempData.forEach((item) => {
+      list.push(item.value);
+    });
+  }
+
+  return list;
+};
+
+const maxValue = 20;
+
+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,
+  },
+  xAxis: {
+    show: false, // 隐藏 X 轴
+    type: 'category',
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
+  },
+  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, // 关闭默认分割线
+    },
+  },
+  series: [
+    {
+      type: 'line',
+      data: getCurvedData(),
+      symbol: 'none', // 不显示数据点
+      color: '#32BAC0',
+      lineStyle: {
+        width: 2,
+      },
+      markLine: {
+        // 添加最大值虚线
+        silent: true,
+        symbol: 'none',
+        label: { show: false },
+        lineStyle: {
+          type: 'dashed',
+          color: '#333',
+          width: 1,
+        },
+        data: [
+          {
+            yAxis: maxValue, // 在最大值位置画线
+          },
+        ],
+      },
+    },
+  ],
+});
+
+onMounted(() => {});
+const editorMonitoring = (id: number) => {
+  emit('editorClick', id);
+};
+</script>
+
+<template>
+  <div class="line-chart-content">
+    <AFlex justify="space-between" align="center">
+      <div class="line-chart-header-text">{{ data.name }}</div>
+      <SvgIcon class="line-chart-header-icon" @click="editorMonitoring(data.id)" name="adjustment" />
+    </AFlex>
+    <div style="width: 172px; height: 94px; margin-top: 12px">
+      <VChart class="chart" :option="option" />
+    </div>
+    <AFlex justify="space-between" align="center" class="line-chart-footer">
+      <AFlex align="center">
+        <AFlex justify="center" align="center" class="line-chart-footer-div">
+          <SvgIcon class="line-chart-icon" name="temperature"
+        /></AFlex>
+        <div>
+          <span class="line-chart-footer-text">{{ data.temperature }}</span>
+          <span class="line-chart-footer-unit">℃</span>
+        </div>
+      </AFlex>
+      <AFlex align="center">
+        <AFlex justify="center" align="center" class="line-chart-footer-div"
+          ><SvgIcon class="line-chart-icon" name="humidity"
+        /></AFlex>
+        <div>
+          <span class="line-chart-footer-text">{{ data.humidity }}</span>
+          <span class="line-chart-footer-unit">%</span>
+        </div>
+      </AFlex>
+    </AFlex>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.line-chart-icon {
+  font-size: 16px;
+  color: var(--antd-color-primary-hover);
+}
+
+.line-chart-footer-unit {
+  font-size: 12px;
+  font-style: normal;
+  font-weight: 400;
+  line-height: 20px;
+  color: rgb(0 0 0 / 85%);
+  text-align: left;
+}
+
+.line-chart-footer-text {
+  font-size: 16px;
+  font-style: normal;
+  font-weight: 500;
+  line-height: 28px;
+  color: rgb(0 0 0 / 85%);
+  text-align: left;
+}
+
+.line-chart-footer-div {
+  width: 30px;
+  height: 30px;
+  background: #f2fcf9;
+  border-radius: 8px;
+}
+
+.line-chart-footer {
+  margin-top: 12px;
+}
+
+.line-chart-header-icon {
+  cursor: pointer;
+}
+
+.line-chart-header-text {
+  font-size: 16px;
+  font-style: normal;
+  font-weight: 400;
+  line-height: 24px;
+  color: rgb(0 0 0 / 85%);
+  text-align: left;
+}
+
+.line-chart-content {
+  width: 204px;
+  height: 204px;
+  padding: 16px;
+  margin: 2px 4px 14px;
+  background: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 6px 0 rgb(0 0 0 / 10%);
+}
+</style>