From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目

---
 src/views/iot/home/components/MessageTrendCard.vue |  227 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 227 insertions(+), 0 deletions(-)

diff --git a/src/views/iot/home/components/MessageTrendCard.vue b/src/views/iot/home/components/MessageTrendCard.vue
new file mode 100644
index 0000000..1d2d4c5
--- /dev/null
+++ b/src/views/iot/home/components/MessageTrendCard.vue
@@ -0,0 +1,227 @@
+<template>
+  <el-card class="chart-card" shadow="never" :loading="loading">
+    <template #header>
+      <div class="flex items-center justify-between">
+        <span class="text-base font-medium text-gray-600">娑堟伅閲忕粺璁�</span>
+        <div class="flex flex-wrap items-center gap-4">
+          <el-form-item label="鏃堕棿鑼冨洿" class="!mb-0">
+            <el-date-picker
+              v-model="queryParams.times"
+              :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+              :shortcuts="defaultShortcuts"
+              class="!w-240px"
+              end-placeholder="缁撴潫鏃ユ湡"
+              start-placeholder="寮�濮嬫棩鏈�"
+              type="daterange"
+              value-format="YYYY-MM-DD HH:mm:ss"
+              @change="handleQuery"
+            />
+          </el-form-item>
+          <el-form-item label="鏃堕棿闂撮殧" class="!mb-0">
+            <el-select
+              v-model="queryParams.interval"
+              class="!w-120px"
+              placeholder="闂撮殧绫诲瀷"
+              @change="handleQuery"
+            >
+              <el-option
+                v-for="dict in getIntDictOptions(DICT_TYPE.DATE_INTERVAL)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+        </div>
+      </div>
+    </template>
+    <div v-if="loading && !hasData" class="h-[300px] flex justify-center items-center">
+      <el-empty description="鍔犺浇涓�..." />
+    </div>
+    <div v-else-if="!hasData" class="h-[300px] flex justify-center items-center">
+      <el-empty description="鏆傛棤鏁版嵁" />
+    </div>
+    <div v-else ref="messageChartRef" class="h-[300px]"></div>
+  </el-card>
+</template>
+
+<script lang="ts" setup>
+import * as echarts from 'echarts/core'
+import { LineChart } from 'echarts/charts'
+import { CanvasRenderer } from 'echarts/renderers'
+import { GridComponent, LegendComponent, TooltipComponent } from 'echarts/components'
+import { UniversalTransition } from 'echarts/features'
+import {
+  StatisticsApi,
+  IotStatisticsDeviceMessageSummaryByDateRespVO,
+  IotStatisticsDeviceMessageReqVO
+} from '@/api/iot/statistics'
+import { formatDate, beginOfDay, endOfDay, defaultShortcuts } from '@/utils/formatTime'
+import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
+
+/** 娑堟伅瓒嬪娍缁熻鍗$墖 */
+defineOptions({ name: 'MessageTrendCard' })
+
+const messageChartRef = ref()
+const loading = ref(false)
+const messageData = ref<IotStatisticsDeviceMessageSummaryByDateRespVO[]>([])
+
+const queryParams = reactive<IotStatisticsDeviceMessageReqVO>({
+  interval: 1, // DAY, 鏃�
+  times: [
+    // 榛樿鏄剧ず鏈�杩戜竴鍛ㄧ殑鏁版嵁
+    formatDate(beginOfDay(new Date(new Date().getTime() - 3600 * 1000 * 24 * 7))),
+    formatDate(endOfDay(new Date(new Date().getTime() - 3600 * 1000 * 24)))
+  ]
+}) // 鏌ヨ鍙傛暟
+
+// 鏄惁鏈夋暟鎹�
+const hasData = computed(() => {
+  return messageData.value && messageData.value.length > 0
+})
+
+// 澶勭悊鏌ヨ鎿嶄綔
+const handleQuery = () => {
+  fetchMessageData()
+}
+
+// 鑾峰彇娑堟伅缁熻鏁版嵁
+const fetchMessageData = async () => {
+  loading.value = true
+  try {
+    messageData.value = await StatisticsApi.getDeviceMessageSummaryByDate(queryParams)
+
+    // 浣跨敤 nextTick 纭繚鏁版嵁鏇存柊鍚庨噸鏂版覆鏌撳浘琛�
+    await nextTick()
+    initChart()
+  } catch (error) {
+    console.error('鑾峰彇娑堟伅缁熻鏁版嵁澶辫触:', error)
+    messageData.value = []
+  } finally {
+    loading.value = false
+  }
+}
+
+// 鍒濆鍖栧浘琛�
+const initChart = () => {
+  // 妫�鏌ユ槸鍚︽湁鏁版嵁鍙互缁樺埗
+  if (!hasData.value) return
+  // 纭繚 DOM 鍏冪礌瀛樺湪涓斿凡娓叉煋
+  if (!messageChartRef.value) {
+    console.warn('鍥捐〃 DOM 鍏冪礌涓嶅瓨鍦�')
+    return
+  }
+
+  // 閰嶇疆鍥捐〃
+  echarts.use([
+    LineChart,
+    CanvasRenderer,
+    GridComponent,
+    LegendComponent,
+    TooltipComponent,
+    UniversalTransition
+  ])
+  try {
+    const chart = echarts.init(messageChartRef.value)
+    chart.setOption({
+      tooltip: {
+        trigger: 'axis',
+        backgroundColor: 'rgba(255, 255, 255, 0.9)',
+        borderColor: '#E5E7EB',
+        textStyle: {
+          color: '#374151'
+        }
+      },
+      legend: {
+        data: ['涓婅娑堟伅閲�', '涓嬭娑堟伅閲�'],
+        textStyle: {
+          color: '#374151',
+          fontWeight: 500
+        }
+      },
+      grid: {
+        left: '3%',
+        right: '4%',
+        bottom: '3%',
+        containLabel: true
+      },
+      xAxis: {
+        type: 'category',
+        boundaryGap: false,
+        data: messageData.value.map((item) => item.time),
+        axisLine: {
+          lineStyle: {
+            color: '#E5E7EB'
+          }
+        },
+        axisLabel: {
+          color: '#6B7280'
+        }
+      },
+      yAxis: {
+        type: 'value',
+        axisLine: {
+          lineStyle: {
+            color: '#E5E7EB'
+          }
+        },
+        axisLabel: {
+          color: '#6B7280'
+        },
+        splitLine: {
+          lineStyle: {
+            color: '#F3F4F6'
+          }
+        }
+      },
+      series: [
+        {
+          name: '涓婅娑堟伅閲�',
+          type: 'line',
+          smooth: true,
+          data: messageData.value.map((item) => item.upstreamCount),
+          itemStyle: {
+            color: '#3B82F6'
+          },
+          lineStyle: {
+            width: 2
+          },
+          areaStyle: {
+            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+              { offset: 0, color: 'rgba(59, 130, 246, 0.2)' },
+              { offset: 1, color: 'rgba(59, 130, 246, 0)' }
+            ])
+          }
+        },
+        {
+          name: '涓嬭娑堟伅閲�',
+          type: 'line',
+          smooth: true,
+          data: messageData.value.map((item) => item.downstreamCount),
+          itemStyle: {
+            color: '#10B981'
+          },
+          lineStyle: {
+            width: 2
+          },
+          areaStyle: {
+            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+              { offset: 0, color: 'rgba(16, 185, 129, 0.2)' },
+              { offset: 1, color: 'rgba(16, 185, 129, 0)' }
+            ])
+          }
+        }
+      ]
+    })
+    return chart
+  } catch (error) {
+    console.error('鍒濆鍖栧浘琛ㄥけ璐�:', error)
+    return null
+  }
+}
+
+/** 缁勪欢鎸傝浇鏃跺垵濮嬪寲 */
+onMounted(() => {
+  fetchMessageData()
+})
+</script>

--
Gitblit v1.8.0