Prechádzať zdrojové kódy

feat(views): 添加智慧电表总览页面

- 新增智慧电表总览页面,包含电表列表、搜索功能、图表展示等
- 实现电表数据的分页加载、新增、编辑和删除功能
- 添加电表用电量的年度和月度图表展示
- 实现电表用电量的实时监控和节能建议功能
nahida 8 mesiacov pred
rodič
commit
e07b78a23e
1 zmenil súbory, kde vykonal 981 pridanie a 0 odobranie
  1. 981 0
      src/views/zhdb/dbzl.vue

+ 981 - 0
src/views/zhdb/dbzl.vue

@@ -0,0 +1,981 @@
+<script setup lang="ts">
+import { nextTick, onMounted, reactive, ref } from 'vue'
+import { clientGet, clientPost } from '@/utils/request.ts'
+import type { BaseResponse, PaginationResponse } from '@/utils/type.ts'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import {
+  Activity,
+  BarChart3,
+  Calendar,
+  Clock,
+  Delete,
+  Edit,
+  Plus,
+  Power,
+  RefreshCw,
+  Search,
+  TrendingUp,
+  Zap
+} from 'lucide-vue-next'
+import * as echarts from 'echarts'
+
+interface ElectricItem {
+  id: number
+  companyName: string
+  electricNumber: string
+  createTime: string
+}
+
+interface ElectricListResponse extends BaseResponse {
+  data: PaginationResponse<ElectricItem>
+}
+
+interface ElectricResponse extends BaseResponse {
+  data: ElectricItem
+}
+
+interface YearData extends BaseResponse {
+  data: {
+    allYearData: number,
+    meterMonthDataList: number[]
+  }
+}
+
+interface MonthData extends BaseResponse {
+  data: {
+    allMonthData: number,
+    meterDayDataList: number[]
+  }
+}
+
+interface DayData extends BaseResponse {
+  data: {
+    dayData: number
+  }
+}
+
+const tableData = ref<ElectricItem[]>([])
+const loading = ref(false)
+const dialogVisible = ref(false)
+const dialogTitle = ref('新增电表')
+const isEdit = ref(false)
+const selectedIds = ref<number[]>([])
+const formRef = ref()
+
+// 图表对话框相关
+const chartDialogVisible = ref(false)
+const currentElectricNumber = ref('')
+const currentCompanyName = ref('')
+const chartLoading = ref(false)
+
+// 图表实例引用
+const yearChartRef = ref()
+const monthChartRef = ref()
+
+// 图表数据
+const chartData = reactive({
+  year: new Date().getFullYear(),
+  month: new Date().getMonth() + 1,
+  yearData: {
+    total: 0,
+    monthlyData: [] as number[]
+  },
+  monthData: {
+    total: 0,
+    dailyData: [] as number[]
+  },
+  dayData: {
+    total: 0
+  }
+})
+
+// 分页数据
+const pagination = reactive({
+  pageNum: 1,
+  pageSize: 10,
+  total: 0
+})
+
+// 搜索表单
+const searchForm = reactive({
+  companyName: '',
+  electricNumber: ''
+})
+
+// 表单数据
+const formData = reactive({
+  id: 0,
+  companyName: '',
+  electricNumber: ''
+})
+
+// 表单验证规则
+const formRules = {
+  companyName: [
+    { required: true, message: '请输入公司名称', trigger: 'blur' }
+  ],
+  electricNumber: [
+    { required: true, message: '请输入电表编号', trigger: 'blur' }
+  ]
+}
+
+const getList = async () => {
+  loading.value = true
+  try {
+    const arr: {
+      value?: string,
+      column: string,
+      type: string
+    }[] = []
+
+    arr.push({
+      column: 'create_time',
+      type: 'orderByDesc'
+    })
+
+    if (searchForm.companyName) {
+      arr.push({
+        value: searchForm.companyName,
+        column: 'company_name',
+        type: 'like'
+      })
+    }
+
+    if (searchForm.electricNumber) {
+      arr.push({
+        value: searchForm.electricNumber,
+        column: 'electric_number',
+        type: 'like'
+      })
+    }
+
+    const params = {
+      pageNum: pagination.pageNum,
+      pageSize: pagination.pageSize,
+      conditionJson: encodeURIComponent(JSON.stringify(arr))
+    }
+
+    const res = await clientGet<typeof params, ElectricListResponse>('/infrared/companyElectric/findByPage', {
+      params
+    })
+
+    if (res.code !== 200) {
+      ElMessage.error(res.msg)
+      return
+    }
+
+    tableData.value = res.data.records
+    pagination.total = res.data.total
+  } catch (error) {
+    console.error(error)
+    ElMessage.error('获取数据失败')
+  } finally {
+    loading.value = false
+  }
+}
+
+// API 函数
+const getElectricYears = async (electricNumber: string, year: number) => {
+  const res = await clientGet<{
+    meterNumber: string,
+    year: number
+  }, YearData>('/infrared/infraredReadingMeter/selectByYearAndMonthData', {
+    params: {
+      meterNumber: electricNumber,
+      year
+    }
+  })
+  if (res.code !== 200) {
+    ElMessage.error(res.msg)
+    return null
+  }
+  return res.data
+}
+
+const getElectricMonth = async (electricNumber: string, year: number, month: number) => {
+  const res = await clientGet<{
+    meterNumber: string,
+    year: number,
+    month: number
+  }, MonthData>('/infrared/infraredReadingMeter/selectByYearAndMonthWithDayData', {
+    params: {
+      meterNumber: electricNumber,
+      year,
+      month
+    }
+  })
+  if (res.code !== 200) {
+    ElMessage.error(res.msg)
+    return null
+  }
+  return res.data
+}
+
+const getElectricDay = async (electricNumber: string) => {
+  const res = await clientGet<{
+    meterNumber: string
+  }, DayData>('/infrared/infraredReadingMeter/selectTodayNewestData', {
+    params: {
+      meterNumber: electricNumber
+    }
+  })
+  if (res.code !== 200) {
+    ElMessage.error(res.msg)
+    return null
+  }
+  return res.data
+}
+
+// 点击电表编号显示图表
+const handleShowChart = async (row: ElectricItem) => {
+  currentElectricNumber.value = row.electricNumber
+  currentCompanyName.value = row.companyName
+  chartDialogVisible.value = true
+
+  await loadChartData()
+}
+
+// 加载图表数据
+const loadChartData = async () => {
+  chartLoading.value = true
+
+  try {
+    // 并行加载三种数据
+    const [yearResult, monthResult, dayResult] = await Promise.all([
+      getElectricYears(currentElectricNumber.value, chartData.year),
+      getElectricMonth(currentElectricNumber.value, chartData.year, chartData.month),
+      getElectricDay(currentElectricNumber.value)
+    ])
+
+    if (yearResult) {
+      chartData.yearData.total = yearResult.allYearData
+      chartData.yearData.monthlyData = yearResult.meterMonthDataList
+    }
+
+    if (monthResult) {
+      chartData.monthData.total = monthResult.allMonthData
+      chartData.monthData.dailyData = monthResult.meterDayDataList
+    }
+
+    if (dayResult) {
+      chartData.dayData.total = dayResult.dayData
+    }
+
+    // 等待DOM更新后初始化图表
+    await nextTick()
+    initCharts()
+  } catch (error) {
+    console.error('加载图表数据失败:', error)
+    ElMessage.error('加载图表数据失败')
+  } finally {
+    chartLoading.value = false
+  }
+}
+
+// 初始化图表
+const initCharts = () => {
+  initYearChart()
+  initMonthChart()
+}
+
+// 初始化年度图表
+const initYearChart = () => {
+  if (!yearChartRef.value) return
+
+  const chart = echarts.init(yearChartRef.value)
+  const months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
+
+  const option = {
+    title: {
+      text: `${chartData.year}年度用电量统计`,
+      subtext: `总用电量: ${chartData.yearData.total} kWh`,
+      left: 'center'
+    },
+    tooltip: {
+      trigger: 'axis',
+      formatter: '{b}: {c} kWh'
+    },
+    xAxis: {
+      type: 'category',
+      data: months
+    },
+    yAxis: {
+      type: 'value',
+      name: '用电量 (kWh)'
+    },
+    series: [{
+      name: '月度用电量',
+      type: 'bar',
+      data: chartData.yearData.monthlyData,
+      itemStyle: {
+        color: '#409EFF'
+      }
+    }]
+  }
+
+  chart.setOption(option)
+}
+
+// 初始化月度图表
+const initMonthChart = () => {
+  if (!monthChartRef.value) return
+
+  const chart = echarts.init(monthChartRef.value)
+  const days = Array.from({ length: chartData.monthData.dailyData.length }, (_, i) => `${i + 1}日`)
+
+  const option = {
+    title: {
+      text: `${chartData.year}年${chartData.month}月用电量统计`,
+      subtext: `总用电量: ${chartData.monthData.total} kWh`,
+      left: 'center'
+    },
+    tooltip: {
+      trigger: 'axis',
+      formatter: '{b}: {c} kWh'
+    },
+    xAxis: {
+      type: 'category',
+      data: days
+    },
+    yAxis: {
+      type: 'value',
+      name: '用电量 (kWh)'
+    },
+    series: [{
+      name: '日用电量',
+      type: 'line',
+      data: chartData.monthData.dailyData,
+      smooth: true,
+      itemStyle: {
+        color: '#67C23A'
+      }
+    }]
+  }
+
+  chart.setOption(option)
+}
+
+// 计算用电量等级
+const getPowerLevel = (value: number) => {
+  if (value < 50) return { level: 'low', color: '#67C23A', text: '节能' }
+  if (value < 100) return { level: 'medium', color: '#E6A23C', text: '正常' }
+  return { level: 'high', color: '#F56C6C', text: '偏高' }
+}
+
+// 年份/月份变化时重新加载数据
+const handleYearChange = async () => {
+  await loadChartData()
+}
+
+const handleMonthChange = async () => {
+  const monthResult = await getElectricMonth(currentElectricNumber.value, chartData.year, chartData.month)
+  if (monthResult) {
+    chartData.monthData.total = monthResult.allMonthData
+    chartData.monthData.dailyData = monthResult.meterDayDataList
+    await nextTick()
+    initMonthChart()
+  }
+}
+
+// 其他原有函数保持不变
+const add = async (item: { companyName: string, electricNumber: string }) => {
+  const res = await clientPost<{
+    companyName: string,
+    electricNumber: string
+  }, BaseResponse>('/infrared/companyElectric/save', {
+    companyName: item.companyName,
+    electricNumber: item.electricNumber
+  })
+  if (res.code !== 200) {
+    ElMessage.error(res.msg)
+    return false
+  }
+  ElMessage.success('新增成功')
+  getList()
+  return true
+}
+
+const edit = async (item: { id: number, companyName: string, electricNumber: string }) => {
+  const res = await clientPost<{
+    id: number,
+    companyName: string,
+    electricNumber: string
+  }, BaseResponse>('/infrared/companyElectric/update', {
+    id: item.id,
+    companyName: item.companyName,
+    electricNumber: item.electricNumber
+  })
+  if (res.code !== 200) {
+    ElMessage.error(res.msg)
+    return false
+  }
+  ElMessage.success('修改成功')
+  getList()
+  return true
+}
+
+const deleteBatch = async (ids: string[]) => {
+  const res = await clientPost<string, BaseResponse>('/infrared/companyElectric/deleteBatch', JSON.stringify(ids))
+  if (res.code !== 200) {
+    ElMessage.error(res.msg)
+    return
+  }
+  ElMessage.success('删除成功')
+  getList()
+}
+
+const getById = async (id: number) => {
+  const res = await clientGet<null, ElectricResponse>('/infrared/companyElectric/getById/' + id)
+  if (res.code !== 200) {
+    ElMessage.error(res.msg)
+    return null
+  }
+  return res.data
+}
+
+const handleSearch = () => {
+  pagination.pageNum = 1
+  getList()
+}
+
+const handleReset = () => {
+  Object.assign(searchForm, {
+    companyName: '',
+    electricNumber: ''
+  })
+  pagination.pageNum = 1
+  getList()
+}
+
+const handleAdd = () => {
+  dialogTitle.value = '新增电表'
+  isEdit.value = false
+  Object.assign(formData, {
+    id: 0,
+    companyName: '',
+    electricNumber: ''
+  })
+  dialogVisible.value = true
+}
+
+const handleEdit = async (row: ElectricItem) => {
+  dialogTitle.value = '编辑电表'
+  isEdit.value = true
+  const data = await getById(row.id)
+  if (data) {
+    Object.assign(formData, data)
+    dialogVisible.value = true
+  }
+}
+
+const handleDelete = (row: ElectricItem) => {
+  ElMessageBox.confirm('确定要删除这条记录吗?', '提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning'
+  }).then(() => {
+    deleteBatch([row.id.toString()])
+  })
+}
+
+const handleBatchDelete = () => {
+  if (selectedIds.value.length === 0) {
+    ElMessage.warning('请选择要删除的记录')
+    return
+  }
+
+  ElMessageBox.confirm(`确定要删除选中的 ${selectedIds.value.length} 条记录吗?`, '提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning'
+  }).then(() => {
+    deleteBatch(selectedIds.value.map(id => id.toString()))
+    selectedIds.value = []
+  })
+}
+
+const handleSelectionChange = (selection: ElectricItem[]) => {
+  selectedIds.value = selection.map(item => item.id)
+}
+
+const handlePageChange = (page: number) => {
+  pagination.pageNum = page
+  getList()
+}
+
+const handleSizeChange = (size: number) => {
+  pagination.pageSize = size
+  pagination.pageNum = 1
+  getList()
+}
+
+const handleSubmit = async () => {
+  if (!formRef.value) return
+
+  try {
+    await formRef.value.validate()
+    let success = false
+
+    if (isEdit.value) {
+      success = await edit(formData)
+    } else {
+      success = await add(formData)
+    }
+
+    if (success) {
+      dialogVisible.value = false
+    }
+  } catch (error) {
+    console.error('表单验证失败', error)
+  }
+}
+
+onMounted(() => {
+  getList()
+})
+</script>
+
+<template>
+  <div class="p-6 bg-gray-50 min-h-screen">
+    <!-- 页面标题 -->
+    <div class="mb-6">
+      <h1 class="text-2xl font-bold text-gray-800 mb-2">智慧电表总览</h1>
+      <p class="text-gray-600">管理公司电表信息</p>
+    </div>
+
+    <!-- 搜索区域 -->
+    <div class="bg-white p-4 rounded-lg shadow-sm mb-4">
+      <el-form :model="searchForm" inline class="search-form">
+        <el-form-item label="公司名称">
+          <el-input
+            v-model="searchForm.companyName"
+            placeholder="请输入公司名称"
+            clearable
+            class="w-200px"
+          />
+        </el-form-item>
+        <el-form-item label="电表编号">
+          <el-input
+            v-model="searchForm.electricNumber"
+            placeholder="请输入电表编号"
+            clearable
+            class="w-200px"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">
+            <Search class="w-4 h-4 mr-1" />
+            搜索
+          </el-button>
+          <el-button @click="handleReset">
+            <RefreshCw class="w-4 h-4 mr-1" />
+            重置
+          </el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+
+    <!-- 操作区域 -->
+    <div class="bg-white p-4 rounded-lg shadow-sm">
+      <div class="flex justify-between items-center mb-4">
+        <div class="flex gap-2">
+          <el-button type="primary" @click="handleAdd">
+            <Plus class="w-4 h-4 mr-1" />
+            新增电表
+          </el-button>
+          <el-button
+            type="danger"
+            :disabled="selectedIds.length === 0"
+            @click="handleBatchDelete"
+          >
+            <Delete class="w-4 h-4 mr-1" />
+            批量删除
+          </el-button>
+        </div>
+        <div class="text-sm text-gray-500">
+          共 {{ pagination.total }} 条记录
+        </div>
+      </div>
+
+      <!-- 数据表格 -->
+      <el-table
+        :data="tableData"
+        :loading="loading"
+        @selection-change="handleSelectionChange"
+        stripe
+        class="w-full"
+      >
+        <el-table-column type="selection" width="55" />
+        <el-table-column prop="id" label="ID" width="80" />
+        <el-table-column prop="companyName" label="公司名称" min-width="200" />
+        <el-table-column prop="electricNumber" label="电表编号" min-width="150">
+          <template #default="{ row }">
+            <el-button
+              type="primary"
+              text
+              @click="handleShowChart(row)"
+              class="p-0 h-auto font-normal"
+            >
+              <BarChart3 class="w-4 h-4 mr-1" />
+              {{ row.electricNumber }}
+            </el-button>
+          </template>
+        </el-table-column>
+        <el-table-column prop="createTime" label="创建时间" width="180">
+          <template #default="{ row }">
+            {{ row.createTime ? new Date(row.createTime).toLocaleString() : '-' }}
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="150" fixed="right">
+          <template #default="{ row }">
+            <el-button
+              type="primary"
+              size="small"
+              text
+              @click="handleEdit(row)"
+            >
+              <Edit class="w-3 h-3 mr-1" />
+              编辑
+            </el-button>
+            <el-button
+              type="danger"
+              size="small"
+              text
+              @click="handleDelete(row)"
+            >
+              <Delete class="w-3 h-3 mr-1" />
+              删除
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 分页 -->
+      <div class="flex justify-center mt-4">
+        <el-pagination
+          v-model:current-page="pagination.pageNum"
+          v-model:page-size="pagination.pageSize"
+          :page-sizes="[10, 20, 50, 100]"
+          :total="pagination.total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handlePageChange"
+        />
+      </div>
+    </div>
+
+    <!-- 新增/编辑弹窗 -->
+    <el-dialog
+      v-model="dialogVisible"
+      :title="dialogTitle"
+      width="500px"
+      :close-on-click-modal="false"
+    >
+      <el-form
+        :model="formData"
+        :rules="formRules"
+        ref="formRef"
+        label-width="100px"
+        class="dialog-form"
+      >
+        <el-form-item label="公司名称" prop="companyName">
+          <el-input
+            v-model="formData.companyName"
+            placeholder="请输入公司名称"
+            clearable
+          />
+        </el-form-item>
+        <el-form-item label="电表编号" prop="electricNumber">
+          <el-input
+            v-model="formData.electricNumber"
+            placeholder="请输入电表编号"
+            clearable
+          />
+        </el-form-item>
+      </el-form>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="dialogVisible = false">取消</el-button>
+          <el-button type="primary" @click="handleSubmit">
+            {{ isEdit ? '更新' : '新增' }}
+          </el-button>
+        </div>
+      </template>
+    </el-dialog>
+
+    <!-- 图表全屏对话框 -->
+    <el-dialog
+      v-model="chartDialogVisible"
+      :title="`${currentCompanyName} - ${currentElectricNumber} 用电情况分析`"
+      fullscreen
+      :close-on-click-modal="false"
+    >
+      <div v-loading="chartLoading" class="chart-container">
+        <!-- 控制面板 -->
+        <div class="flex items-center justify-between mb-6 p-4 bg-gray-50 rounded-lg">
+          <div class="flex items-center gap-4">
+            <div class="flex items-center gap-2">
+              <Calendar class="w-4 h-4" />
+              <span>年份:</span>
+              <el-select v-model="chartData.year" @change="handleYearChange" class="w-32">
+                <el-option
+                  v-for="year in [2021, 2022, 2023, 2024, 2025]"
+                  :key="year"
+                  :label="year"
+                  :value="year"
+                />
+              </el-select>
+            </div>
+            <div class="flex items-center gap-2">
+              <Clock class="w-4 h-4" />
+              <span>月份:</span>
+              <el-select v-model="chartData.month" @change="handleMonthChange" class="w-32">
+                <el-option
+                  v-for="month in 12"
+                  :key="month"
+                  :label="`${month}月`"
+                  :value="month"
+                />
+              </el-select>
+            </div>
+          </div>
+          <div class="text-sm text-gray-600">
+            电表编号: {{ currentElectricNumber }}
+          </div>
+        </div>
+
+        <!-- 今日用电量卡片区域 -->
+        <div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-6">
+          <!-- 今日用电量主卡片 -->
+          <el-card class="today-power-card" shadow="hover">
+            <template #header>
+              <div class="flex items-center justify-between">
+                <div class="flex items-center gap-2">
+                  <div class="p-2 rounded-lg bg-blue-100">
+                    <Zap class="w-5 h-5 text-blue-600" />
+                  </div>
+                  <span class="font-semibold text-gray-700">今日用电量</span>
+                </div>
+                <el-tag
+                  :type="getPowerLevel(chartData.dayData.total).level === 'low' ? 'success' : getPowerLevel(chartData.dayData.total).level === 'medium' ? 'warning' : 'danger'"
+                  size="small">
+                  {{ getPowerLevel(chartData.dayData.total).text }}
+                </el-tag>
+              </div>
+            </template>
+            <div class="text-center py-4">
+              <div class="text-4xl font-bold mb-2" :style="{ color: getPowerLevel(chartData.dayData.total).color }">
+                {{ chartData.dayData.total }}
+              </div>
+              <div class="text-lg text-gray-500 mb-4">kWh</div>
+              <div class="flex items-center justify-center gap-2 text-sm text-gray-600">
+                <Activity class="w-4 h-4" />
+                <span>实时监控</span>
+              </div>
+            </div>
+          </el-card>
+
+          <!-- 月度对比卡片 -->
+          <el-card shadow="hover">
+            <template #header>
+              <div class="flex items-center gap-2">
+                <div class="p-2 rounded-lg bg-green-100">
+                  <TrendingUp class="w-5 h-5 text-green-600" />
+                </div>
+                <span class="font-semibold text-gray-700">本月累计</span>
+              </div>
+            </template>
+            <div class="py-4">
+              <div class="text-2xl font-bold text-green-600 mb-2">
+                {{ chartData.monthData.total }}
+              </div>
+              <div class="text-sm text-gray-500 mb-3">kWh</div>
+              <div class="flex items-center justify-between text-xs">
+                <span class="text-gray-600">日均用电</span>
+                <span class="font-medium">{{ (chartData.monthData.total / new Date().getDate()).toFixed(1) }} kWh</span>
+              </div>
+            </div>
+          </el-card>
+
+          <!-- 年度对比卡片 -->
+          <el-card shadow="hover">
+            <template #header>
+              <div class="flex items-center gap-2">
+                <div class="p-2 rounded-lg bg-purple-100">
+                  <Power class="w-5 h-5 text-purple-600" />
+                </div>
+                <span class="font-semibold text-gray-700">年度累计</span>
+              </div>
+            </template>
+            <div class="py-4">
+              <div class="text-2xl font-bold text-purple-600 mb-2">
+                {{ chartData.yearData.total }}
+              </div>
+              <div class="text-sm text-gray-500 mb-3">kWh</div>
+              <div class="flex items-center justify-between text-xs">
+                <span class="text-gray-600">月均用电</span>
+                <span class="font-medium">{{ (chartData.yearData.total / 12).toFixed(1) }} kWh</span>
+              </div>
+            </div>
+          </el-card>
+        </div>
+
+        <!-- 用电量趋势分析卡片 -->
+        <el-card class="mb-6" shadow="hover">
+          <template #header>
+            <div class="flex items-center gap-2">
+              <div class="p-2 rounded-lg bg-orange-100">
+                <BarChart3 class="w-5 h-5 text-orange-600" />
+              </div>
+              <span class="font-semibold text-gray-700">
+                用电量趋势分析
+                <el-tooltip>
+                  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none"
+                       stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
+                       class="lucide lucide-shield-question-mark-icon lucide-shield-question-mark"><path
+                    d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z" /><path
+                    d="M9.1 9a3 3 0 0 1 5.82 1c0 2-3 3-3 3" /><path d="M12 17h.01" /></svg>
+                  <template #content>
+                    50KW/h以下为节能用电<br />
+                    50KW/h以上为正常<br />
+                    100KW/h以上为偏高<br />
+                    预计月度为当日用电量乘以30
+                  </template>
+                </el-tooltip>
+              </span>
+            </div>
+          </template>
+          <div class="grid grid-cols-1 md:grid-cols-3 gap-4 py-4">
+            <div class="text-center p-4 bg-gray-50 rounded-lg">
+              <div class="text-lg font-semibold text-gray-700 mb-1">今日状态</div>
+              <div class="text-sm" :style="{ color: getPowerLevel(chartData.dayData.total).color }">
+                {{ getPowerLevel(chartData.dayData.total).text }}用电
+              </div>
+            </div>
+            <div class="text-center p-4 bg-gray-50 rounded-lg">
+              <div class="text-lg font-semibold text-gray-700 mb-1">预计月度</div>
+              <div class="text-sm text-blue-600">
+                {{ (chartData.dayData.total * 30).toFixed(0) }} kWh
+              </div>
+            </div>
+            <div class="text-center p-4 bg-gray-50 rounded-lg">
+              <div class="text-lg font-semibold text-gray-700 mb-1">节能建议</div>
+              <div class="text-sm text-green-600">
+                {{ chartData.dayData.total < 50 ? '保持良好' : chartData.dayData.total < 100 ? '适度节能' : '加强管控'
+                }}
+              </div>
+            </div>
+          </div>
+        </el-card>
+
+        <!-- 图表网格 -->
+        <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
+          <!-- 年度用电量图表 -->
+          <el-card shadow="hover">
+            <template #header>
+              <div class="flex items-center gap-2">
+                <BarChart3 class="w-4 h-4 text-blue-600" />
+                <span class="font-semibold">年度用电量统计</span>
+              </div>
+            </template>
+            <div ref="yearChartRef" class="w-full h-96"></div>
+          </el-card>
+
+          <!-- 月度用电量图表 -->
+          <el-card shadow="hover">
+            <template #header>
+              <div class="flex items-center gap-2">
+                <TrendingUp class="w-4 h-4 text-green-600" />
+                <span class="font-semibold">月度用电量统计</span>
+              </div>
+            </template>
+            <div ref="monthChartRef" class="w-full h-96"></div>
+          </el-card>
+        </div>
+      </div>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="chartDialogVisible = false">关闭</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<style scoped>
+.search-form .el-form-item {
+  margin-bottom: 0;
+}
+
+.dialog-footer {
+  text-align: right;
+}
+
+.chart-container {
+  min-height: 600px;
+}
+
+.today-power-card {
+  background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
+  border: none;
+}
+
+.today-power-card :deep(.el-card__body) {
+  padding: 16px;
+}
+
+/* UnoCSS 样式补充 */
+.w-200px {
+  width: 200px;
+}
+
+.w-32 {
+  width: 8rem;
+}
+
+.h-96 {
+  height: 24rem;
+}
+
+.grid {
+  display: grid;
+}
+
+.grid-cols-1 {
+  grid-template-columns: repeat(1, minmax(0, 1fr));
+}
+
+.gap-6 {
+  gap: 1.5rem;
+}
+
+.gap-4 {
+  gap: 1rem;
+}
+
+.gap-2 {
+  gap: 0.5rem;
+}
+
+@media (min-width: 768px) {
+  .md\:grid-cols-3 {
+    grid-template-columns: repeat(3, minmax(0, 1fr));
+  }
+}
+
+@media (min-width: 1024px) {
+  .lg\:grid-cols-2 {
+    grid-template-columns: repeat(2, minmax(0, 1fr));
+  }
+
+  .lg\:grid-cols-3 {
+    grid-template-columns: repeat(3, minmax(0, 1fr));
+  }
+
+  .lg\:col-span-2 {
+    grid-column: span 2 / span 2;
+  }
+}
+</style>