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/DeviceCountCard.vue | 131 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 131 insertions(+), 0 deletions(-)
diff --git a/src/views/iot/home/components/DeviceCountCard.vue b/src/views/iot/home/components/DeviceCountCard.vue
new file mode 100644
index 0000000..5514eff
--- /dev/null
+++ b/src/views/iot/home/components/DeviceCountCard.vue
@@ -0,0 +1,131 @@
+<template>
+ <el-card class="chart-card" shadow="never" :loading="loading">
+ <template #header>
+ <div class="flex items-center">
+ <span class="text-base font-medium text-gray-600">璁惧鏁伴噺缁熻</span>
+ </div>
+ </template>
+ <div v-if="loading && !hasData" class="h-[240px] flex justify-center items-center">
+ <el-empty description="鍔犺浇涓�..." />
+ </div>
+ <div v-else-if="!hasData" class="h-[240px] flex justify-center items-center">
+ <el-empty description="鏆傛棤鏁版嵁" />
+ </div>
+ <div v-else ref="deviceCountChartRef" class="h-[240px]"></div>
+ </el-card>
+</template>
+
+<script lang="ts" setup>
+import * as echarts from 'echarts/core'
+import { PieChart } from 'echarts/charts'
+import { CanvasRenderer } from 'echarts/renderers'
+import { TooltipComponent, LegendComponent } from 'echarts/components'
+import { LabelLayout } from 'echarts/features'
+import { IotStatisticsSummaryRespVO } from '@/api/iot/statistics'
+import type { PropType } from 'vue'
+
+/** 銆愯澶囨暟閲忋�戠粺璁″崱鐗� */
+defineOptions({ name: 'DeviceCountCard' })
+
+const props = defineProps({
+ statsData: {
+ type: Object as PropType<IotStatisticsSummaryRespVO>,
+ required: true
+ },
+ loading: {
+ type: Boolean,
+ default: false
+ }
+})
+
+const deviceCountChartRef = ref()
+
+/** 鏄惁鏈夋暟鎹� */
+const hasData = computed(() => {
+ if (!props.statsData) return false
+
+ const categories = Object.entries(props.statsData.productCategoryDeviceCounts || {})
+ return categories.length > 0 && props.statsData.deviceCount !== -1
+})
+
+/** 鍒濆鍖栧浘琛� */
+const initChart = () => {
+ // 濡傛灉娌℃湁鏁版嵁锛屽垯涓嶅垵濮嬪寲鍥捐〃
+ if (!hasData.value) return
+ // 纭繚 DOM 鍏冪礌瀛樺湪涓斿凡娓叉煋
+ if (!deviceCountChartRef.value) {
+ console.warn('鍥捐〃DOM鍏冪礌涓嶅瓨鍦�')
+ return
+ }
+
+ echarts.use([TooltipComponent, LegendComponent, PieChart, CanvasRenderer, LabelLayout])
+ try {
+ const chart = echarts.init(deviceCountChartRef.value)
+ chart.setOption({
+ tooltip: {
+ trigger: 'item'
+ },
+ legend: {
+ top: '5%',
+ right: '10%',
+ align: 'left',
+ orient: 'vertical',
+ icon: 'circle'
+ },
+ series: [
+ {
+ name: 'Access From',
+ type: 'pie',
+ radius: ['50%', '80%'],
+ avoidLabelOverlap: false,
+ center: ['30%', '50%'],
+ label: {
+ show: false,
+ position: 'outside'
+ },
+ emphasis: {
+ label: {
+ show: true,
+ fontSize: 20,
+ fontWeight: 'bold'
+ }
+ },
+ labelLine: {
+ show: false
+ },
+ data: Object.entries(props.statsData.productCategoryDeviceCounts).map(
+ ([name, value]) => ({
+ name,
+ value
+ })
+ )
+ }
+ ]
+ })
+ return chart
+ } catch (error) {
+ console.error('鍒濆鍖栧浘琛ㄥけ璐�:', error)
+ return null
+ }
+}
+
+/** 鐩戝惉鏁版嵁鍙樺寲 */
+watch(
+ () => props.statsData,
+ () => {
+ // 浣跨敤 nextTick 纭繚 DOM 宸叉洿鏂�
+ nextTick(() => {
+ initChart()
+ })
+ },
+ { deep: true }
+)
+
+/** 缁勪欢鎸傝浇鏃跺垵濮嬪寲鍥捐〃 */
+onMounted(async () => {
+ // 浣跨敤 nextTick 纭繚 DOM 宸叉洿鏂�
+ await nextTick(() => {
+ initChart()
+ })
+})
+</script>
--
Gitblit v1.8.0