From 897524d4918c407dbaa32fc98e5c5867c70e4064 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期六, 28 三月 2026 14:54:24 +0800
Subject: [PATCH] 能耗成本核算-能耗成本趋势统计图展示修改

---
 src/views/costAccounting/energyCosts/index.vue |  880 ++++++++++++++++++++++++++++++++-------------------------
 1 files changed, 494 insertions(+), 386 deletions(-)

diff --git a/src/views/costAccounting/energyCosts/index.vue b/src/views/costAccounting/energyCosts/index.vue
index 5488bcc..c386ef3 100644
--- a/src/views/costAccounting/energyCosts/index.vue
+++ b/src/views/costAccounting/energyCosts/index.vue
@@ -18,11 +18,11 @@
                             @change="handleTypeChange">
               <el-radio-button label="day">鎸夋棩</el-radio-button>
               <el-radio-button label="month">鎸夋湀</el-radio-button>
+              <el-radio-button label="year">鎸夊勾</el-radio-button>
             </el-radio-group>
           </div>
         </div>
       </template>
-
       <div class="filter-layout">
         <el-form :model="searchForm"
                  :inline="true"
@@ -43,18 +43,18 @@
                          value="姘�" />
             </el-select>
           </el-form-item> -->
-          <el-form-item label="鑳借�楃敤閫�">
-            <el-select v-model="searchForm.type"
-                       placeholder=""
-                       clearable
-                       class="w-140"
-                       @change="handleQuery">
-              <el-option label="鐢熶骇"
-                         value="鐢熶骇" />
-              <el-option label="鍔炲叕"
-                         value="鍔炲叕" />
+          <!-- <el-form-item label="鑳借�楃敤閫�">
+            <el-select
+              v-model="searchForm.type"
+              placeholder=""
+              clearable
+              class="w-140"
+              @change="handleQuery"
+            >
+              <el-option label="鐢熶骇" value="鐢熶骇" />
+              <el-option label="鍔炲叕" value="鍔炲叕" />
             </el-select>
-          </el-form-item>
+          </el-form-item> -->
           <el-form-item label="鏃堕棿鑼冨洿">
             <el-date-picker v-if="statisticsType === 'day'"
                             v-model="searchForm.dateRange"
@@ -65,7 +65,7 @@
                             value-format="YYYY-MM-DD"
                             class="w-260"
                             @change="handleQuery" />
-            <el-date-picker v-else
+            <el-date-picker v-else-if="statisticsType === 'month'"
                             v-model="searchForm.monthRange"
                             type="monthrange"
                             range-separator="鑷�"
@@ -74,6 +74,16 @@
                             value-format="YYYY-MM"
                             class="w-260"
                             @change="handleQuery" />
+            <el-select v-else-if="statisticsType === 'year'"
+                       v-model="searchForm.selectedYear"
+                       placeholder="璇烽�夋嫨骞翠唤"
+                       class="w-260"
+                       @change="handleYearChange">
+              <el-option v-for="year in recentYears"
+                         :key="year"
+                         :label="year + '骞�'"
+                         :value="year" />
+            </el-select>
           </el-form-item>
         </el-form>
         <div class="filter-actions">
@@ -90,7 +100,6 @@
         </div>
       </div>
     </el-card>
-
     <!-- 鍥捐〃鍖哄煙 -->
     <div class="charts">
       <el-card class="panel-card"
@@ -104,11 +113,14 @@
                   @click="handleKpiClick('all')">
             <div class="kpi-left">
               <div class="kpi-label">鎬昏兘鑰楁垚鏈�</div>
-              <div class="kpi-value">楼{{ formatMoney(animatedOverview.totalCost) }}</div>
+              <div class="kpi-value">
+                楼{{ formatMoney(animatedOverview.totalEnergyCost) }}
+              </div>
               <div class="kpi-meta">
                 <span class="kpi-chip"
                       :class="kpiDelta.total.pct >= 0 ? 'up' : 'down'"
-                      v-if="kpiDelta.total.valid">{{ kpiDelta.total.pct >= 0 ? '+' : '' }}{{ kpiDelta.total.pct.toFixed(1) }}%</span>
+                      v-if="kpiDelta.total.valid">{{ kpiDelta.total.pct >= 0 ? "+" : ""
+                  }}{{ kpiDelta.total.pct.toFixed(1) }}%</span>
                 <svg class="kpi-spark"
                      viewBox="0 0 72 22"
                      aria-hidden="true">
@@ -130,10 +142,14 @@
                  @click.stop>
               <button class="kpi-action"
                       type="button"
-                      @click="copyKpi('totalCost')">澶嶅埗</button>
+                      @click="copyKpi('totalEnergyCost')">
+                澶嶅埗
+              </button>
               <button class="kpi-action"
                       type="button"
-                      @click="viewKpiDetails('all')">鏄庣粏</button>
+                      @click="viewKpiDetails('all')">
+                鏄庣粏
+              </button>
             </div>
           </button>
           <button class="kpi-item kpi-production"
@@ -142,11 +158,14 @@
                   @click="handleKpiClick('production')">
             <div class="kpi-left">
               <div class="kpi-label">鐢熶骇鑳借�楁垚鏈�</div>
-              <div class="kpi-value">楼{{ formatMoney(animatedOverview.productionCost) }}</div>
+              <div class="kpi-value">
+                楼{{ formatMoney(animatedOverview.productEnergyCost) }}
+              </div>
               <div class="kpi-meta">
                 <span class="kpi-chip"
                       :class="kpiDelta.production.pct >= 0 ? 'up' : 'down'"
-                      v-if="kpiDelta.production.valid">{{ kpiDelta.production.pct >= 0 ? '+' : '' }}{{ kpiDelta.production.pct.toFixed(1) }}%</span>
+                      v-if="kpiDelta.production.valid">{{ kpiDelta.production.pct >= 0 ? "+" : ""
+                  }}{{ kpiDelta.production.pct.toFixed(1) }}%</span>
                 <svg class="kpi-spark"
                      viewBox="0 0 72 22"
                      aria-hidden="true">
@@ -168,10 +187,14 @@
                  @click.stop>
               <button class="kpi-action"
                       type="button"
-                      @click="copyKpi('productionCost')">澶嶅埗</button>
+                      @click="copyKpi('productEnergyCost')">
+                澶嶅埗
+              </button>
               <button class="kpi-action"
                       type="button"
-                      @click="viewKpiDetails('production')">鏄庣粏</button>
+                      @click="viewKpiDetails('production')">
+                鏄庣粏
+              </button>
             </div>
           </button>
           <button class="kpi-item kpi-office"
@@ -180,11 +203,14 @@
                   @click="handleKpiClick('office')">
             <div class="kpi-left">
               <div class="kpi-label">鍔炲叕鑳借�楁垚鏈�</div>
-              <div class="kpi-value">楼{{ formatMoney(animatedOverview.officeCost) }}</div>
+              <div class="kpi-value">
+                楼{{ formatMoney(animatedOverview.officeEnergyCost) }}
+              </div>
               <div class="kpi-meta">
                 <span class="kpi-chip"
                       :class="kpiDelta.office.pct >= 0 ? 'up' : 'down'"
-                      v-if="kpiDelta.office.valid">{{ kpiDelta.office.pct >= 0 ? '+' : '' }}{{ kpiDelta.office.pct.toFixed(1) }}%</span>
+                      v-if="kpiDelta.office.valid">{{ kpiDelta.office.pct >= 0 ? "+" : ""
+                  }}{{ kpiDelta.office.pct.toFixed(1) }}%</span>
                 <svg class="kpi-spark"
                      viewBox="0 0 72 22"
                      aria-hidden="true">
@@ -206,10 +232,14 @@
                  @click.stop>
               <button class="kpi-action"
                       type="button"
-                      @click="copyKpi('officeCost')">澶嶅埗</button>
+                      @click="copyKpi('officeEnergyCost')">
+                澶嶅埗
+              </button>
               <button class="kpi-action"
                       type="button"
-                      @click="viewKpiDetails('office')">鏄庣粏</button>
+                      @click="viewKpiDetails('office')">
+                鏄庣粏
+              </button>
             </div>
           </button>
           <button class="kpi-item kpi-avg"
@@ -217,7 +247,10 @@
                   @click="handleKpiClick('all')">
             <div class="kpi-left">
               <div class="kpi-label">骞冲潎鎴愭湰</div>
-              <div class="kpi-value">楼{{ formatMoney(animatedOverview.avgCost) }} <span class="kpi-unit">/{{ statisticsType === 'day' ? '鏃�' : '鏈�' }}</span></div>
+              <div class="kpi-value">
+                楼{{ formatMoney(animatedOverview.averageEnergyCost) }}
+                <span class="kpi-unit">/{{ statisticsType === "day" ? "鏃�" : statisticsType === "month" ? "鏈�" : "骞�" }}</span>
+              </div>
               <div class="kpi-meta muted">鍩轰簬褰撳墠绛涢�変笌鏄庣粏缁熻</div>
             </div>
             <div class="kpi-icon">
@@ -229,14 +262,17 @@
                  @click.stop>
               <button class="kpi-action"
                       type="button"
-                      @click="copyKpi('avgCost')">澶嶅埗</button>
+                      @click="copyKpi('averageEnergyCost')">
+                澶嶅埗
+              </button>
               <button class="kpi-action"
                       type="button"
-                      @click="viewKpiDetails('all')">鏄庣粏</button>
+                      @click="viewKpiDetails('all')">
+                鏄庣粏
+              </button>
             </div>
           </button>
         </div>
-
         <div class="panel-head">
           <div class="segmented"
                role="tablist"
@@ -265,7 +301,6 @@
             </button>
           </div>
         </div>
-
         <transition name="lux-collapse">
           <div v-show="chartPanel === 'core'"
                class="panel-body">
@@ -281,10 +316,14 @@
                            @click.stop>
                         <button class="chart-tool"
                                 type="button"
-                                @click="downloadChart('cost', '鑳借�楁垚鏈秼鍔�')">涓嬭浇</button>
+                                @click="downloadChart('cost', '鑳借�楁垚鏈秼鍔�')">
+                          涓嬭浇
+                        </button>
                         <button class="chart-tool"
                                 type="button"
-                                @click="openBigChart('cost', '鑳借�楁垚鏈秼鍔�')">澶у浘</button>
+                                @click="openBigChart('cost', '鑳借�楁垚鏈秼鍔�')">
+                          澶у浘
+                        </button>
                       </div>
                     </div>
                   </template>
@@ -312,10 +351,14 @@
                            @click.stop>
                         <button class="chart-tool"
                                 type="button"
-                                @click="downloadChart('type', '鑳借�楃被鍨嬫垚鏈崰姣�')">涓嬭浇</button>
+                                @click="downloadChart('type', '鑳借�楃被鍨嬫垚鏈崰姣�')">
+                          涓嬭浇
+                        </button>
                         <button class="chart-tool"
                                 type="button"
-                                @click="openBigChart('type', '鑳借�楃被鍨嬫垚鏈崰姣�')">澶у浘</button>
+                                @click="openBigChart('type', '鑳借�楃被鍨嬫垚鏈崰姣�')">
+                          澶у浘
+                        </button>
                       </div>
                     </div>
                   </template>
@@ -335,7 +378,6 @@
             </el-row>
           </div>
         </transition>
-
         <transition name="lux-collapse">
           <div v-show="chartPanel === 'advanced'"
                class="panel-body">
@@ -352,10 +394,14 @@
                            @click.stop>
                         <button class="chart-tool"
                                 type="button"
-                                @click="downloadChart('purpose', '鑳借�楃敤閫旀垚鏈崰姣�')">涓嬭浇</button>
+                                @click="downloadChart('purpose', '鑳借�楃敤閫旀垚鏈崰姣�')">
+                          涓嬭浇
+                        </button>
                         <button class="chart-tool"
                                 type="button"
-                                @click="openBigChart('purpose', '鑳借�楃敤閫旀垚鏈崰姣�')">澶у浘</button>
+                                @click="openBigChart('purpose', '鑳借�楃敤閫旀垚鏈崰姣�')">
+                          澶у浘
+                        </button>
                       </div>
                     </div>
                   </template>
@@ -378,22 +424,26 @@
                          shadow="never">
                   <template #header>
                     <div class="chart-head">
-                      <span class="chart-title">鑳借�楀崟浠峰姣�</span>
+                      <span class="chart-title">鑳借�楃敤閲忓姣�</span>
                       <div class="chart-tools"
                            @click.stop>
                         <button class="chart-tool"
                                 type="button"
-                                @click="downloadChart('price', '鑳借�楀崟浠峰姣�')">涓嬭浇</button>
+                                @click="downloadChart('unit', '鑳借�楃敤閲忓姣�')">
+                          涓嬭浇
+                        </button>
                         <button class="chart-tool"
                                 type="button"
-                                @click="openBigChart('price', '鑳借�楀崟浠峰姣�')">澶у浘</button>
+                                @click="openBigChart('unit', '鑳借�楃敤閲忓姣�')">
+                          澶у浘
+                        </button>
                       </div>
                     </div>
                   </template>
-                  <div ref="priceChartWrap"
+                  <div ref="unitChartWrap"
                        class="chart-wrap"
                        v-loading="tableLoading">
-                    <div ref="priceChart"
+                    <div ref="unitChart"
                          class="chart-content"
                          v-show="hasTableData"></div>
                     <div class="chart-empty"
@@ -408,7 +458,6 @@
         </transition>
       </el-card>
     </div>
-
     <el-dialog v-model="bigChartVisible"
                :title="bigChartTitle"
                width="92%"
@@ -429,7 +478,6 @@
         </div>
       </template>
     </el-dialog>
-
     <!-- 鏁版嵁琛ㄦ牸 -->
     <el-card class="table-card"
              shadow="never">
@@ -447,7 +495,6 @@
           </div>
         </div>
       </template>
-
       <el-table :data="displayTableData"
                 v-loading="tableLoading"
                 stripe
@@ -461,11 +508,11 @@
                          label="搴忓彿"
                          width="60"
                          align="center" />
-        <el-table-column prop="timePeriod"
+        <el-table-column prop="meterReadingDate"
                          :label="timeColumnLabel"
                          align="center"
                          sortable="custom" />
-        <el-table-column prop="energyType"
+        <el-table-column prop="energyTyep"
                          label="鑳借�楃被鍨�"
                          width="100"
                          align="center"
@@ -473,8 +520,8 @@
                          :filter-method="filterEnergyType"
                          filter-placement="bottom-end">
           <template #default="scope">
-            <el-tag :type="getEnergyTypeType(scope.row.energyType)">
-              {{ scope.row.energyType }}
+            <el-tag :type="getEnergyTypeType(scope.row.energyTyep)">
+              {{ scope.row.energyTyep }}
             </el-tag>
           </template>
         </el-table-column>
@@ -486,25 +533,29 @@
                          :filter-method="filterEnergyPurpose"
                          filter-placement="bottom-end">
           <template #default="scope">
-            <el-tag :type="scope.row.type === '鐢熶骇' ? 'primary' : 'info'">
+            <el-tag :type="scope.row.type === '鐢熶骇' ? 'primary' : 'warning'">
               {{ scope.row.type }}
             </el-tag>
           </template>
         </el-table-column>
-        <el-table-column prop="consumption"
+        <el-table-column prop="dosage"
                          label="鐢ㄩ噺"
                          align="right">
           <template #default="scope">
-            <span class="consumption-value">{{ formatNumber(scope.row.consumption, 2) }}</span>
-            <span class="consumption-unit">{{ scope.row.unit }}</span>
+            <span class="unit-value">{{
+              formatNumber(scope.row.dosage, 2)
+            }}</span>
+            <span class="unit-unit">{{ scope.row.unit }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="price"
+        <el-table-column prop="unitPrice"
                          label="鍗曚环(鍏�)"
                          align="right"
                          sortable="custom">
           <template #default="scope">
-            <span class="price-value">{{ formatNumber(scope.row.price, 2) }}</span>
+            <span class="price-value">{{
+              formatNumber(scope.row.unitPrice, 2)
+            }}</span>
           </template>
         </el-table-column>
         <el-table-column prop="cost"
@@ -517,7 +568,6 @@
           </template>
         </el-table-column>
       </el-table>
-
       <div class="pagination-container">
         <el-pagination v-model:current-page="page.current"
                        v-model:page-size="page.size"
@@ -532,7 +582,15 @@
 </template>
 
 <script setup>
-  import { ref, reactive, onMounted, onUnmounted, computed, nextTick, watch } from "vue";
+  import {
+    ref,
+    reactive,
+    onMounted,
+    onUnmounted,
+    computed,
+    nextTick,
+    watch,
+  } from "vue";
   import { ElMessage } from "element-plus";
   import {
     Money,
@@ -544,14 +602,14 @@
   } from "@element-plus/icons-vue";
   import * as echarts from "echarts";
   // import { energyCostStatistics } from "@/api/costAccounting/energyCosts";
-  import { energyConsumptionDetailStatistics } from "@/api/energyManagement/energyType";
+  import { energyConsumptionDetailAccount } from "@/api/energyManagement/energyType";
   // 缁熻缁村害锛歞ay-鎸夋棩锛宮onth-鎸夋湀
   const statisticsType = ref("day");
 
   // 鎼滅储琛ㄥ崟
   const searchForm = reactive({
     // energyType: "",
-    type: "",
+    // type: "",
     dateRange: (() => {
       // 榛樿鏈�杩�7澶�
       const end = new Date();
@@ -566,39 +624,59 @@
       start.setMonth(start.getMonth() - 2);
       return [start.toISOString().slice(0, 7), end.toISOString().slice(0, 7)];
     })(),
+    selectedYear: new Date().getFullYear(), // 榛樿浠婂勾
+  });
+
+  // 鏈�杩戜竷骞�
+  const recentYears = computed(() => {
+    const currentYear = new Date().getFullYear();
+    const years = [];
+    for (let i = 6; i >= 0; i--) {
+      years.push(currentYear - i);
+    }
+    return years;
   });
 
   // 鏃堕棿鍒楁爣绛�
   const timeColumnLabel = computed(() => {
-    return statisticsType.value === "day" ? "鏃ユ湡" : "鏈堜唤";
+    if (statisticsType.value === "day") return "鏃ユ湡";
+    if (statisticsType.value === "month") return "鏈堜唤";
+    if (statisticsType.value === "year") return "骞翠唤";
+    return "鏃堕棿";
   });
 
   // 缁熻姒傝
   const overview = reactive({
-    totalCost: "0.00",
-    productionCost: "0.00",
-    officeCost: "0.00",
-    avgCost: "0.00",
+    totalEnergyCost: "0.00",
+    productEnergyCost: "0.00",
+    officeEnergyCost: "0.00",
+    averageEnergyCost: "0.00",
   });
 
   const selectedKpi = ref("all"); // all | production | office
   const animatedOverview = reactive({
-    totalCost: 0,
-    productionCost: 0,
-    officeCost: 0,
-    avgCost: 0,
+    totalEnergyCost: 0,
+    productEnergyCost: 0,
+    officeEnergyCost: 0,
+    averageEnergyCost: 0,
   });
 
   const formatMoney = v => {
     const n = Number.parseFloat(v);
     const value = Number.isFinite(n) ? n : 0;
-    return value.toLocaleString("zh-CN", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
+    return value.toLocaleString("zh-CN", {
+      minimumFractionDigits: 2,
+      maximumFractionDigits: 2,
+    });
   };
 
   const formatNumber = (v, digits = 2) => {
     const n = Number.parseFloat(v);
     if (!Number.isFinite(n)) return "--";
-    return n.toLocaleString("zh-CN", { minimumFractionDigits: digits, maximumFractionDigits: digits });
+    return n.toLocaleString("zh-CN", {
+      minimumFractionDigits: digits,
+      maximumFractionDigits: digits,
+    });
   };
 
   const animateNumber = (key, toValue, duration = 420) => {
@@ -618,10 +696,16 @@
   watch(
     () => ({ ...overview }),
     val => {
-      animateNumber("totalCost", Number.parseFloat(val.totalCost));
-      animateNumber("productionCost", Number.parseFloat(val.productionCost));
-      animateNumber("officeCost", Number.parseFloat(val.officeCost));
-      animateNumber("avgCost", Number.parseFloat(val.avgCost));
+      animateNumber("totalEnergyCost", Number.parseFloat(val.totalEnergyCost));
+      animateNumber(
+        "productEnergyCost",
+        Number.parseFloat(val.productEnergyCost)
+      );
+      animateNumber("officeEnergyCost", Number.parseFloat(val.officeEnergyCost));
+      animateNumber(
+        "averageEnergyCost",
+        Number.parseFloat(val.averageEnergyCost)
+      );
     },
     { deep: true, immediate: true }
   );
@@ -629,14 +713,16 @@
   // 琛ㄦ牸鏁版嵁
   const tableData = ref([]);
   const tableLoading = ref(false);
-  const hasTableData = computed(() => Array.isArray(tableData.value) && tableData.value.length > 0);
+  const hasTableData = computed(
+    () => Array.isArray(tableData.value) && tableData.value.length > 0
+  );
   const queryPulse = ref(false);
 
   const kpiSeries = computed(() => {
     const rows = Array.isArray(tableData.value) ? tableData.value : [];
     const byTime = new Map();
     for (const r of rows) {
-      const t = r?.timePeriod ?? "";
+      const t = r?.meterReadingDate ?? "";
       if (!t) continue;
       if (!byTime.has(t)) byTime.set(t, { total: 0, production: 0, office: 0 });
       const bucket = byTime.get(t);
@@ -646,7 +732,9 @@
       if (r?.type === "鐢熶骇") bucket.production += cost;
       if (r?.type === "鍔炲叕") bucket.office += cost;
     }
-    const times = Array.from(byTime.keys()).sort((a, b) => String(a).localeCompare(String(b)));
+    const times = Array.from(byTime.keys()).sort((a, b) =>
+      String(a).localeCompare(String(b))
+    );
     const total = times.map(t => byTime.get(t).total);
     const production = times.map(t => byTime.get(t).production);
     const office = times.map(t => byTime.get(t).office);
@@ -699,16 +787,17 @@
     handleKpiClick(key);
     nextTick(() => {
       const el = tableAnchor.value;
-      if (el?.scrollIntoView) el.scrollIntoView({ behavior: "smooth", block: "start" });
+      if (el?.scrollIntoView)
+        el.scrollIntoView({ behavior: "smooth", block: "start" });
     });
   };
 
   const copyKpi = async field => {
     const map = {
-      totalCost: animatedOverview.totalCost,
-      productionCost: animatedOverview.productionCost,
-      officeCost: animatedOverview.officeCost,
-      avgCost: animatedOverview.avgCost,
+      totalEnergyCost: animatedOverview.totalEnergyCost,
+      productEnergyCost: animatedOverview.productEnergyCost,
+      officeEnergyCost: animatedOverview.officeEnergyCost,
+      averageEnergyCost: animatedOverview.averageEnergyCost,
     };
     const raw = map[field];
     const text = `楼${formatMoney(raw)}`;
@@ -734,13 +823,13 @@
     if (key === "cost") return costChartInstance;
     if (key === "type") return typeChartInstance;
     if (key === "purpose") return purposeChartInstance;
-    if (key === "price") return priceChartInstance;
+    if (key === "unit") return unitChartInstance;
     return null;
   };
 
   const ensurePanelForChart = key => {
     if (key === "cost" || key === "type") chartPanel.value = "core";
-    if (key === "purpose" || key === "price") chartPanel.value = "advanced";
+    if (key === "purpose" || key === "unit") chartPanel.value = "advanced";
   };
 
   const downloadChart = (key, title) => {
@@ -756,9 +845,14 @@
       const purposePart = searchForm.type ? `_${searchForm.type}` : "";
       let rangePart = "";
       if (statisticsType.value === "day") {
-        if (searchForm.dateRange?.length === 2) rangePart = `_${searchForm.dateRange[0]}~${searchForm.dateRange[1]}`;
-      } else {
-        if (searchForm.monthRange?.length === 2) rangePart = `_${searchForm.monthRange[0]}~${searchForm.monthRange[1]}`;
+        if (searchForm.dateRange?.length === 2)
+          rangePart = `_${searchForm.dateRange[0]}~${searchForm.dateRange[1]}`;
+      } else if (statisticsType.value === "month") {
+        if (searchForm.monthRange?.length === 2)
+          rangePart = `_${searchForm.monthRange[0]}~${searchForm.monthRange[1]}`;
+      } else if (statisticsType.value === "year") {
+        if (searchForm.yearRange?.length === 2)
+          rangePart = `_${searchForm.yearRange[0]}~${searchForm.yearRange[1]}`;
       }
       a.download = `${title || "chart"}${typePart}${purposePart}${rangePart}.png`;
       a.click();
@@ -824,7 +918,7 @@
 
     const prop = sortState.prop;
     const direction = sortState.order === "ascending" ? 1 : -1;
-    const numFields = new Set(["price", "cost", "consumption"]);
+    const numFields = new Set(["price", "cost", "unit"]);
 
     return data.sort((a, b) => {
       const av = a?.[prop];
@@ -838,7 +932,9 @@
         return (aNum - bNum) * direction;
       }
 
-      return String(av ?? "").localeCompare(String(bv ?? ""), "zh-Hans-CN") * direction;
+      return (
+        String(av ?? "").localeCompare(String(bv ?? ""), "zh-Hans-CN") * direction
+      );
     });
   });
 
@@ -852,7 +948,7 @@
     { text: "鍔炲叕", value: "鍔炲叕" },
   ];
 
-  const filterEnergyType = (value, row) => row.energyType === value;
+  const filterEnergyType = (value, row) => row.energyTyep === value;
   const filterEnergyPurpose = (value, row) => row.type === value;
 
   // 鍒嗛〉
@@ -866,12 +962,12 @@
   const costChart = ref(null);
   const typeChart = ref(null);
   const purposeChart = ref(null);
-  const priceChart = ref(null);
+  const unitChart = ref(null);
 
   const costChartWrap = ref(null);
   const typeChartWrap = ref(null);
   const purposeChartWrap = ref(null);
-  const priceChartWrap = ref(null);
+  const unitChartWrap = ref(null);
 
   const tableAnchor = ref(null);
 
@@ -899,24 +995,32 @@
   let costChartInstance = null;
   let typeChartInstance = null;
   let purposeChartInstance = null;
-  let priceChartInstance = null;
+  let unitChartInstance = null;
 
   // 鍥捐〃鍖哄垏鎹細core | advanced | none锛堢偣鍑诲綋鍓嶉�変腑鍙敹璧凤級
   const chartPanel = ref("core");
 
   const ensureChartsReady = panel => {
     if (panel === "core") {
-      if (costChart.value && !costChartInstance) costChartInstance = echarts.init(costChart.value);
-      if (typeChart.value && !typeChartInstance) typeChartInstance = echarts.init(typeChart.value);
-      if (costChartInstance) updateCostChart();
-      if (typeChartInstance) updateTypeChart();
+      if (costChart.value && !costChartInstance) {
+        costChartInstance = echarts.init(costChart.value);
+        setTimeout(() => costChartInstance?.resize(), 50);
+      }
+      if (typeChart.value && !typeChartInstance) {
+        typeChartInstance = echarts.init(typeChart.value);
+        setTimeout(() => typeChartInstance?.resize(), 50);
+      }
       return;
     }
     if (panel === "advanced") {
-      if (purposeChart.value && !purposeChartInstance) purposeChartInstance = echarts.init(purposeChart.value);
-      if (priceChart.value && !priceChartInstance) priceChartInstance = echarts.init(priceChart.value);
-      if (purposeChartInstance) updatePurposeChart();
-      if (priceChartInstance) updatePriceChart();
+      if (purposeChart.value && !purposeChartInstance) {
+        purposeChartInstance = echarts.init(purposeChart.value);
+        setTimeout(() => purposeChartInstance?.resize(), 50);
+      }
+      if (unitChart.value && !unitChartInstance) {
+        unitChartInstance = echarts.init(unitChart.value);
+        setTimeout(() => unitChartInstance?.resize(), 50);
+      }
     }
   };
 
@@ -941,6 +1045,20 @@
     if (val !== "none") resizeChartsAfterExpand();
   });
 
+  // 鐩戝惉琛ㄦ牸鏁版嵁鍙樺寲锛岀‘淇濇暟鎹姞杞藉悗鍥捐〃姝g‘娓叉煋
+  watch(
+    tableData,
+    () => {
+      nextTick(() => {
+        updateCharts();
+        nextTick(() => {
+          handleResize();
+        });
+      });
+    },
+    { deep: true }
+  );
+
   // 鑾峰彇鑳借�楃被鍨嬫爣绛剧被鍨�
   const getEnergyTypeType = type => {
     const typeMap = {
@@ -962,6 +1080,33 @@
   // 鏇存柊鑳借�楁垚鏈秼鍔垮浘
   const updateCostChart = () => {
     const data = tableData.value;
+
+    // 鎸夋棩鏈熷垎缁勫苟鍚堝苟鏁版嵁
+    const groupedData = {};
+    data.forEach(item => {
+      const date = item.meterReadingDate;
+      if (!groupedData[date]) {
+        groupedData[date] = {
+          productionCost: 0,
+          officeCost: 0,
+        };
+      }
+      if (item.type === "鐢熶骇") {
+        groupedData[date].productionCost += parseFloat(item.cost) || 0;
+      } else if (item.type === "鍔炲叕") {
+        groupedData[date].officeCost += parseFloat(item.cost) || 0;
+      }
+    });
+
+    // 杞崲涓烘暟缁勫苟鎸夋棩鏈熸帓搴�
+    const mergedData = Object.entries(groupedData)
+      .map(([date, costs]) => ({
+        date,
+        productionCost: costs.productionCost,
+        officeCost: costs.officeCost,
+      }))
+      .sort((a, b) => new Date(a.date) - new Date(b.date));
+
     const option = {
       tooltip: {
         trigger: "axis",
@@ -970,7 +1115,8 @@
         borderColor: "#2f6fed",
         borderWidth: 1,
         textStyle: { color: "rgba(15, 23, 42, 0.92)" },
-        extraCssText: "box-shadow: 0 14px 40px rgba(15,23,42,.14); border-radius: 12px;",
+        extraCssText:
+          "box-shadow: 0 14px 40px rgba(15,23,42,.14); border-radius: 12px;",
       },
       legend: {
         data: ["鐢熶骇鑳借�楁垚鏈�", "鍔炲叕鑳借�楁垚鏈�"],
@@ -987,7 +1133,7 @@
       },
       xAxis: {
         type: "category",
-        data: data.map(item => item.timePeriod),
+        data: mergedData.map(item => item.date),
         axisLabel: {
           rotate: statisticsType.value === "day" ? 45 : 0,
           color: "rgba(15, 23, 42, 0.62)",
@@ -1007,7 +1153,7 @@
         {
           name: "鐢熶骇鑳借�楁垚鏈�",
           type: "bar",
-          data: data.map(item => (item.type === "鐢熶骇" ? item.cost : 0)),
+          data: mergedData.map(item => item.productionCost),
           itemStyle: {
             color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
               { offset: 0, color: "#409EFF" },
@@ -1022,7 +1168,7 @@
         {
           name: "鍔炲叕鑳借�楁垚鏈�",
           type: "bar",
-          data: data.map(item => (item.type === "鍔炲叕" ? item.cost : 0)),
+          data: mergedData.map(item => item.officeCost),
           itemStyle: {
             color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
               { offset: 0, color: "#67C23A" },
@@ -1049,10 +1195,10 @@
     const typeCosts = {};
 
     data.forEach(item => {
-      if (!typeCosts[item.energyType]) {
-        typeCosts[item.energyType] = 0;
+      if (!typeCosts[item.energyTyep]) {
+        typeCosts[item.energyTyep] = 0;
       }
-      typeCosts[item.energyType] += parseFloat(item.cost);
+      typeCosts[item.energyTyep] += parseFloat(item.cost);
     });
 
     const chartData = Object.entries(typeCosts).map(([name, value]) => ({
@@ -1068,7 +1214,8 @@
         borderColor: "#2f6fed",
         borderWidth: 1,
         textStyle: { color: "rgba(15, 23, 42, 0.92)" },
-        extraCssText: "box-shadow: 0 14px 40px rgba(15,23,42,.14); border-radius: 12px;",
+        extraCssText:
+          "box-shadow: 0 14px 40px rgba(15,23,42,.14); border-radius: 12px;",
       },
       legend: {
         orient: "horizontal",
@@ -1142,7 +1289,8 @@
         borderColor: "#2f6fed",
         borderWidth: 1,
         textStyle: { color: "rgba(15, 23, 42, 0.92)" },
-        extraCssText: "box-shadow: 0 14px 40px rgba(15,23,42,.14); border-radius: 12px;",
+        extraCssText:
+          "box-shadow: 0 14px 40px rgba(15,23,42,.14); border-radius: 12px;",
       },
       legend: {
         orient: "horizontal",
@@ -1179,26 +1327,26 @@
     purposeChartInstance.setOption(option);
   };
 
-  // 鏇存柊鑳借�楀崟浠峰姣斿浘
-  const updatePriceChart = () => {
+  // 鏇存柊鑳借�楃敤閲忓姣斿浘
+  const updateConsumptionChart = () => {
     const data = tableData.value;
-    const priceData = {};
+    const unitData = {};
 
     data.forEach(item => {
-      if (!priceData[item.energyType]) {
-        priceData[item.energyType] = {
+      if (!unitData[item.energyTyep]) {
+        unitData[item.energyTyep] = {
           鐢熶骇: 0,
           鍔炲叕: 0,
         };
       }
-      if (priceData[item.energyType].hasOwnProperty(item.type)) {
-        priceData[item.energyType][item.type] = parseFloat(item.price);
+      if (unitData[item.energyTyep].hasOwnProperty(item.type)) {
+        unitData[item.energyTyep][item.type] += parseFloat(item.dosage || 0);
       }
     });
 
-    const energyTypes = Object.keys(priceData);
-    const productionPrices = energyTypes.map(type => priceData[type].鐢熶骇);
-    const officePrices = energyTypes.map(type => priceData[type].鍔炲叕);
+    const energyTypes = Object.keys(unitData);
+    const productionConsumptions = energyTypes.map(type => unitData[type].鐢熶骇);
+    const officeConsumptions = energyTypes.map(type => unitData[type].鍔炲叕);
 
     const option = {
       tooltip: {
@@ -1208,10 +1356,11 @@
         borderColor: "#2f6fed",
         borderWidth: 1,
         textStyle: { color: "rgba(15, 23, 42, 0.92)" },
-        extraCssText: "box-shadow: 0 14px 40px rgba(15,23,42,.14); border-radius: 12px;",
+        extraCssText:
+          "box-shadow: 0 14px 40px rgba(15,23,42,.14); border-radius: 12px;",
       },
       legend: {
-        data: ["鐢熶骇鑳借�楀崟浠�", "鍔炲叕鑳借�楀崟浠�"],
+        data: ["鐢熶骇鑳借�楃敤閲�", "鍔炲叕鑳借�楃敤閲�"],
         top: 0,
         right: 10,
         textStyle: { color: "rgba(15, 23, 42, 0.62)" },
@@ -1232,7 +1381,7 @@
       },
       yAxis: {
         type: "value",
-        name: "鍗曚环(鍏�)",
+        name: "鐢ㄩ噺",
         nameTextStyle: { color: "rgba(15, 23, 42, 0.58)" },
         axisLabel: { color: "rgba(15, 23, 42, 0.58)" },
         axisLine: { show: false },
@@ -1240,9 +1389,9 @@
       },
       series: [
         {
-          name: "鐢熶骇鑳借�楀崟浠�",
+          name: "鐢熶骇鑳借�楃敤閲�",
           type: "bar",
-          data: productionPrices,
+          data: productionConsumptions,
           itemStyle: {
             color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
               { offset: 0, color: "#2f6fed" },
@@ -1252,9 +1401,9 @@
           },
         },
         {
-          name: "鍔炲叕鑳借�楀崟浠�",
+          name: "鍔炲叕鑳借�楃敤閲�",
           type: "bar",
-          data: officePrices,
+          data: officeConsumptions,
           itemStyle: {
             color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
               { offset: 0, color: "#16a34a" },
@@ -1265,7 +1414,7 @@
         },
       ],
     };
-    priceChartInstance.setOption(option);
+    unitChartInstance.setOption(option);
   };
 
   // 缁熻缁村害鍒囨崲
@@ -1279,7 +1428,7 @@
         start.toISOString().split("T")[0],
         end.toISOString().split("T")[0],
       ];
-    } else {
+    } else if (statisticsType.value === "month") {
       const end = new Date();
       const start = new Date();
       start.setMonth(start.getMonth() - 2);
@@ -1287,7 +1436,15 @@
         start.toISOString().slice(0, 7),
         end.toISOString().slice(0, 7),
       ];
+    } else if (statisticsType.value === "year") {
+      searchForm.selectedYear = new Date().getFullYear(); // 榛樿浠婂勾
     }
+    page.current = 1;
+    handleQuery();
+  };
+
+  // 骞翠唤閫夋嫨鍙樺寲
+  const handleYearChange = () => {
     page.current = 1;
     handleQuery();
   };
@@ -1304,10 +1461,15 @@
     const params = {
       days: 0,
       // energyType: searchForm.energyType || undefined,
-      type: searchForm.type || undefined,
-      // 椤圭洰鍐呭父鐢ㄥ垎椤靛弬鏁板懡鍚�
+      // type: searchForm.type || undefined,
       pageNum: page.current,
       pageSize: page.size,
+      state:
+        statisticsType.value === "day"
+          ? "鏃�"
+          : statisticsType.value === "month"
+          ? "鏈�"
+          : "骞�",
     };
 
     if (statisticsType.value === "day") {
@@ -1315,20 +1477,35 @@
         params.startDate = searchForm.dateRange[0];
         params.endDate = searchForm.dateRange[1];
       }
-    } else {
+    } else if (statisticsType.value === "month") {
       if (searchForm.monthRange && searchForm.monthRange.length === 2) {
         params.startDate = searchForm.monthRange[0] + "-01";
 
         // 缁撴潫鏃堕棿闇�瑕佸彇缁撴潫鏈堜唤鐨勬渶鍚庝竴澶╋紙渚嬪 2026-03 -> 2026-03-31锛�
-        const [endYearStr, endMonthStr] = String(searchForm.monthRange[1]).split("-");
+        const [endYearStr, endMonthStr] = String(searchForm.monthRange[1]).split(
+          "-"
+        );
         const endYear = Number(endYearStr);
         const endMonth = Number(endMonthStr); // 1-12
-        if (!Number.isNaN(endYear) && !Number.isNaN(endMonth) && endMonth >= 1 && endMonth <= 12) {
+        if (
+          !Number.isNaN(endYear) &&
+          !Number.isNaN(endMonth) &&
+          endMonth >= 1 &&
+          endMonth <= 12
+        ) {
           const lastDay = new Date(endYear, endMonth, 0).getDate(); // 涓嬩釜鏈堢0澶� = 鏈湀鏈�鍚庝竴澶�
-          params.endDate = `${endYearStr}-${endMonthStr}-${String(lastDay).padStart(2, "0")}`;
+          params.endDate = `${endYearStr}-${endMonthStr}-${String(
+            lastDay
+          ).padStart(2, "0")}`;
         } else {
           params.endDate = searchForm.monthRange[1] + "-01";
         }
+      }
+    } else if (statisticsType.value === "year") {
+      if (searchForm.selectedYear) {
+        const year = searchForm.selectedYear;
+        params.startDate = year + "-01-01";
+        params.endDate = year + "-12-31";
       }
     }
 
@@ -1344,39 +1521,36 @@
     }
 
     // 璋冪敤鎺ュ彛鑾峰彇鏁版嵁
-    energyConsumptionDetailStatistics(params)
+    energyConsumptionDetailAccount(params)
       .then(res => {
         if (res.code === 200) {
-          tableData.value = res.data.records || [];
-          page.total = res.data.total || 0;
+          const data = res.data;
+          overview.totalEnergyCost = data.totalEnergyCost || "0";
+          overview.productEnergyCost = data.productEnergyCost || "0";
+          overview.officeEnergyCost = data.officeEnergyCost || "0";
+          overview.averageEnergyCost = data.averageEnergyCost || "0";
 
-          // 鏇存柊缁熻姒傝鏁版嵁
-          if (res.data.overview) {
-            overview.totalCost = res.data.overview.totalCost || "0.00";
-            overview.productionCost = res.data.overview.productionCost || "0.00";
-            overview.officeCost = res.data.overview.officeCost || "0.00";
-            overview.avgCost = res.data.overview.avgCost || "0.00";
-          }
+          // 澶勭悊琛ㄦ牸鏁版嵁
+          tableData.value = data.energyConsumptionDetailDtoList || [];
+          page.total = tableData.value.length || 0;
         } else {
           ElMessage.error(res.message || "鑾峰彇鏁版嵁澶辫触");
           tableData.value = [];
           page.total = 0;
-          overview.totalCost = "0.00";
-          overview.productionCost = "0.00";
-          overview.officeCost = "0.00";
-          overview.avgCost = "0.00";
+          overview.totalEnergyCost = "0.00";
+          overview.productEnergyCost = "0.00";
+          overview.officeEnergyCost = "0.00";
+          overview.averageEnergyCost = "0.00";
         }
       })
       .catch(err => {
-        console.error("鑾峰彇鏁版嵁寮傚父锛�", err);
-        // 銆愬亣鏁版嵁锛圡ock锛夊凡绂佺敤銆戞帴鍙e紓甯告椂涓嶅啀鐢熸垚闅忔満鍋囨暟鎹紝閬垮厤璇敤鍒扮敓浜ф暟鎹摼璺�
         ElMessage.error("鑾峰彇鏁版嵁寮傚父");
         tableData.value = [];
         page.total = 0;
-        overview.totalCost = "0.00";
-        overview.productionCost = "0.00";
-        overview.officeCost = "0.00";
-        overview.avgCost = "0.00";
+        overview.totalEnergyCost = "0.00";
+        overview.productEnergyCost = "0.00";
+        overview.officeEnergyCost = "0.00";
+        overview.averageEnergyCost = "0.00";
       })
       .finally(() => {
         tableLoading.value = false;
@@ -1384,173 +1558,22 @@
       });
   };
 
-  // 銆愬亣鏁版嵁锛圡ock锛夊凡绂佺敤銆戝巻鍙蹭笂鐢ㄤ簬鎺ュ彛寮傚父鍏滃簳鐨勯殢鏈烘暟鎹敓鎴愰�昏緫锛岀幇宸叉暣浣撴敞閲婏紝閬垮厤璇敤浜庣敓浜с��
-  /*
-  // 鐢熸垚鍋囨暟鎹�
-  const generateMockData = () => {
-    if (statisticsType.value === "day") {
-      // 鐢熸垚鏈�杩�7澶╃殑鍋囨暟鎹�
-      const mockData = [];
-      const today = new Date();
-
-      for (let i = 6; i >= 0; i--) {
-        const date = new Date(today);
-        date.setDate(date.getDate() - i);
-        const dateStr = date.toISOString().split("T")[0];
-
-        // 鐢熶骇鑳借�楁暟鎹�
-        mockData.push({
-          timePeriod: dateStr,
-          energyType: "鐢�",
-          type: "鐢熶骇",
-          consumption: (Math.random() * 1000 + 500).toFixed(2),
-          unit: "kWh",
-          price: "0.85",
-          cost: (Math.random() * 850 + 425).toFixed(2),
-        });
-        mockData.push({
-          timePeriod: dateStr,
-          energyType: "姘�",
-          type: "鐢熶骇",
-          consumption: (Math.random() * 500 + 200).toFixed(2),
-          unit: "m鲁",
-          price: "3.50",
-          cost: (Math.random() * 1750 + 700).toFixed(2),
-        });
-        mockData.push({
-          timePeriod: dateStr,
-          energyType: "姘�",
-          type: "鐢熶骇",
-          consumption: (Math.random() * 300 + 100).toFixed(2),
-          unit: "m鲁",
-          price: "2.80",
-          cost: (Math.random() * 840 + 280).toFixed(2),
-        });
-
-        // 鍔炲叕鑳借�楁暟鎹�
-        mockData.push({
-          timePeriod: dateStr,
-          energyType: "鐢�",
-          type: "鍔炲叕",
-          consumption: (Math.random() * 200 + 100).toFixed(2),
-          unit: "kWh",
-          price: "0.85",
-          cost: (Math.random() * 170 + 85).toFixed(2),
-        });
-        mockData.push({
-          timePeriod: dateStr,
-          energyType: "姘�",
-          type: "鍔炲叕",
-          consumption: (Math.random() * 50 + 20).toFixed(2),
-          unit: "m鲁",
-          price: "3.50",
-          cost: (Math.random() * 175 + 70).toFixed(2),
-        });
-      }
-
-      tableData.value = mockData;
-      page.total = mockData.length;
-    } else {
-      // 鐢熸垚鏈�杩�3涓湀鐨勫亣鏁版嵁
-      const mockData = [];
-      const today = new Date();
-
-      for (let i = 2; i >= 0; i--) {
-        const date = new Date(today);
-        date.setMonth(date.getMonth() - i);
-        const monthStr = date.toISOString().slice(0, 7);
-
-        // 鐢熶骇鑳借�楁暟鎹�
-        mockData.push({
-          timePeriod: monthStr,
-          energyType: "鐢�",
-          type: "鐢熶骇",
-          consumption: (Math.random() * 30000 + 15000).toFixed(2),
-          unit: "kWh",
-          price: "0.85",
-          cost: (Math.random() * 25500 + 12750).toFixed(2),
-        });
-        mockData.push({
-          timePeriod: monthStr,
-          energyType: "姘�",
-          type: "鐢熶骇",
-          consumption: (Math.random() * 15000 + 6000).toFixed(2),
-          unit: "m鲁",
-          price: "3.50",
-          cost: (Math.random() * 52500 + 21000).toFixed(2),
-        });
-        mockData.push({
-          timePeriod: monthStr,
-          energyType: "姘�",
-          type: "鐢熶骇",
-          consumption: (Math.random() * 9000 + 3000).toFixed(2),
-          unit: "m鲁",
-          price: "2.80",
-          cost: (Math.random() * 25200 + 8400).toFixed(2),
-        });
-
-        // 鍔炲叕鑳借�楁暟鎹�
-        mockData.push({
-          timePeriod: monthStr,
-          energyType: "鐢�",
-          type: "鍔炲叕",
-          consumption: (Math.random() * 6000 + 3000).toFixed(2),
-          unit: "kWh",
-          price: "0.85",
-          cost: (Math.random() * 5100 + 2550).toFixed(2),
-        });
-        mockData.push({
-          timePeriod: monthStr,
-          energyType: "姘�",
-          type: "鍔炲叕",
-          consumption: (Math.random() * 1500 + 600).toFixed(2),
-          unit: "m鲁",
-          price: "3.50",
-          cost: (Math.random() * 5250 + 2100).toFixed(2),
-        });
-      }
-
-      tableData.value = mockData;
-      page.total = mockData.length;
-    }
-
-    // 鏇存柊缁熻姒傝鏁版嵁
-    calculateOverview();
-  };
-  */
-
-  // 銆愬亣鏁版嵁锛圡ock锛夊凡绂佺敤銆戜笌 generateMockData 閰嶅鐨勫墠绔眹鎬昏绠楋紙浠呬緵鍋囨暟鎹睍绀猴級锛岀幇宸叉敞閲�
-  /*
-  // 璁$畻缁熻姒傝鏁版嵁
-  const calculateOverview = () => {
-    let totalCost = 0;
-    let productionCost = 0;
-    let officeCost = 0;
-
-    tableData.value.forEach(item => {
-      const cost = parseFloat(item.cost);
-      totalCost += cost;
-      if (item.type === "鐢熶骇") {
-        productionCost += cost;
-      } else if (item.type === "鍔炲叕") {
-        officeCost += cost;
-      }
-    });
-
-    overview.totalCost = totalCost.toFixed(2);
-    overview.productionCost = productionCost.toFixed(2);
-    overview.officeCost = officeCost.toFixed(2);
-    overview.avgCost = (totalCost / tableData.value.length).toFixed(2);
-  };
-  */
-
   // 鏇存柊鎵�鏈夊浘琛�
   const updateCharts = () => {
     nextTick(() => {
+      // 纭繚 core 闈㈡澘鐨勫浘琛ㄥ缁堝垵濮嬪寲锛堝洜涓洪粯璁ゆ樉绀虹殑鏄� core锛�
+      ensureChartsReady("core");
+
+      // 鍚屾椂涔熷垵濮嬪寲褰撳墠鍙闈㈡澘鐨勫浘琛�
+      if (chartPanel.value === "advanced") {
+        ensureChartsReady("advanced");
+      }
+
+      // 鏇存柊鎵�鏈夊凡鍒濆鍖栫殑鍥捐〃
       if (costChartInstance) updateCostChart();
       if (typeChartInstance) updateTypeChart();
       if (purposeChartInstance) updatePurposeChart();
-      if (priceChartInstance) updatePriceChart();
+      if (unitChartInstance) updateConsumptionChart();
     });
   };
 
@@ -1566,7 +1589,7 @@
         start.toISOString().split("T")[0],
         end.toISOString().split("T")[0],
       ];
-    } else {
+    } else if (statisticsType.value === "month") {
       const end = new Date();
       const start = new Date();
       start.setMonth(start.getMonth() - 2);
@@ -1574,6 +1597,8 @@
         start.toISOString().slice(0, 7),
         end.toISOString().slice(0, 7),
       ];
+    } else if (statisticsType.value === "year") {
+      searchForm.selectedYear = new Date().getFullYear(); // 榛樿浠婂勾
     }
     page.current = 1;
     handleQuery();
@@ -1602,7 +1627,7 @@
     costChartInstance && costChartInstance.resize();
     typeChartInstance && typeChartInstance.resize();
     purposeChartInstance && purposeChartInstance.resize();
-    priceChartInstance && priceChartInstance.resize();
+    unitChartInstance && unitChartInstance.resize();
   };
 
   onMounted(() => {
@@ -1672,9 +1697,16 @@
     --lux-radius-sm: 12px;
 
     padding: 18px 22px 24px;
-    background:
-      radial-gradient(1200px 420px at 20% 0%, rgba(47, 111, 237, 0.10), transparent 55%),
-      radial-gradient(900px 380px at 90% 10%, rgba(22, 163, 74, 0.06), transparent 55%),
+    background: radial-gradient(
+        1200px 420px at 20% 0%,
+        rgba(47, 111, 237, 0.1),
+        transparent 55%
+      ),
+      radial-gradient(
+        900px 380px at 90% 10%,
+        rgba(22, 163, 74, 0.06),
+        transparent 55%
+      ),
       linear-gradient(180deg, var(--lux-bg) 0%, #ffffff 58%);
   }
 
@@ -1710,7 +1742,7 @@
   }
 
   .filter-form {
-    flex: 1 1 auto;
+    flex: 0.1 1 auto;
     min-width: 0;
   }
 
@@ -1724,7 +1756,7 @@
 
     &:hover {
       transform: translateY(-1px);
-      box-shadow: 0 10px 22px rgba(15, 23, 42, 0.10);
+      box-shadow: 0 10px 22px rgba(15, 23, 42, 0.1);
       filter: saturate(1.02);
     }
 
@@ -1745,7 +1777,7 @@
 
   /* 鏌ヨ鍖烘帶浠剁粺涓�鐨偆 */
   :deep(.filter-card .el-form-item__label) {
-    color: rgba(15, 23, 42, 0.70);
+    color: rgba(15, 23, 42, 0.7);
     font-weight: 650;
   }
 
@@ -1753,20 +1785,21 @@
   :deep(.filter-card .el-select__wrapper) {
     border-radius: 12px;
     box-shadow: none;
-    border: 1px solid rgba(15, 23, 42, 0.10);
+    border: 1px solid rgba(15, 23, 42, 0.1);
     background: rgba(255, 255, 255, 0.82);
-    transition: border-color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease;
+    transition: border-color 0.18s ease, box-shadow 0.18s ease,
+      transform 0.18s ease;
   }
 
   :deep(.filter-card .el-input__wrapper:hover),
   :deep(.filter-card .el-select__wrapper:hover) {
-    border-color: rgba(47, 111, 237, 0.20);
+    border-color: rgba(47, 111, 237, 0.2);
     transform: translateY(-1px);
   }
 
   :deep(.filter-card .is-focus .el-input__wrapper),
   :deep(.filter-card .is-focus .el-select__wrapper) {
-    border-color: rgba(47, 111, 237, 0.30);
+    border-color: rgba(47, 111, 237, 0.3);
     box-shadow: 0 0 0 3px rgba(47, 111, 237, 0.14);
   }
 
@@ -1888,7 +1921,7 @@
     background: rgba(255, 255, 255, 0.9);
     backdrop-filter: blur(10px);
     min-height: 78px;
-    transition: box-shadow 0.20s ease, transform 0.20s ease, border-color 0.20s ease;
+    transition: box-shadow 0.2s ease, transform 0.2s ease, border-color 0.2s ease;
 
     &:hover {
       transform: translateY(-1px);
@@ -1937,23 +1970,43 @@
   }
 
   .metric-total {
-    background: linear-gradient(135deg, rgba(47, 111, 237, 0.12), rgba(47, 111, 237, 0.02));
+    background: linear-gradient(
+      135deg,
+      rgba(47, 111, 237, 0.12),
+      rgba(47, 111, 237, 0.02)
+    );
 
     .metric-right {
-      background: linear-gradient(135deg, var(--lux-primary), var(--lux-primary-2));
+      background: linear-gradient(
+        135deg,
+        var(--lux-primary),
+        var(--lux-primary-2)
+      );
     }
   }
 
   .metric-production {
-    background: linear-gradient(135deg, rgba(22, 163, 74, 0.12), rgba(22, 163, 74, 0.02));
+    background: linear-gradient(
+      135deg,
+      rgba(22, 163, 74, 0.12),
+      rgba(22, 163, 74, 0.02)
+    );
 
     .metric-right {
-      background: linear-gradient(135deg, var(--lux-success), rgba(22, 163, 74, 0.65));
+      background: linear-gradient(
+        135deg,
+        var(--lux-success),
+        rgba(22, 163, 74, 0.65)
+      );
     }
   }
 
   .metric-office {
-    background: linear-gradient(135deg, rgba(144, 147, 153, 0.14), rgba(144, 147, 153, 0.03));
+    background: linear-gradient(
+      135deg,
+      rgba(144, 147, 153, 0.14),
+      rgba(144, 147, 153, 0.03)
+    );
 
     .metric-right {
       background: linear-gradient(135deg, #909399, #b1b3b8);
@@ -1961,10 +2014,18 @@
   }
 
   .metric-avg {
-    background: linear-gradient(135deg, rgba(245, 158, 11, 0.12), rgba(245, 158, 11, 0.02));
+    background: linear-gradient(
+      135deg,
+      rgba(245, 158, 11, 0.12),
+      rgba(245, 158, 11, 0.02)
+    );
 
     .metric-right {
-      background: linear-gradient(135deg, var(--lux-warning), rgba(245, 158, 11, 0.62));
+      background: linear-gradient(
+        135deg,
+        var(--lux-warning),
+        rgba(245, 158, 11, 0.62)
+      );
     }
   }
 
@@ -1993,7 +2054,7 @@
       filter: saturate(1.02);
     }
     35% {
-      filter: saturate(1.10);
+      filter: saturate(1.1);
     }
     100% {
       filter: saturate(1.02);
@@ -2009,7 +2070,8 @@
     border-radius: 14px;
     border: 1px solid rgba(15, 23, 42, 0.08);
     background: rgba(255, 255, 255, 0.86);
-    transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
+    transition: transform 0.18s ease, box-shadow 0.18s ease,
+      border-color 0.18s ease;
     min-height: 68px;
     text-align: left;
     cursor: pointer;
@@ -2021,7 +2083,7 @@
 
   .kpi-item:hover {
     transform: translateY(-1px);
-    box-shadow: 0 16px 40px rgba(15, 23, 42, 0.10);
+    box-shadow: 0 16px 40px rgba(15, 23, 42, 0.1);
     border-color: rgba(47, 111, 237, 0.18);
   }
 
@@ -2029,9 +2091,16 @@
     content: "";
     position: absolute;
     inset: 0;
-    background:
-      radial-gradient(520px 140px at 20% 0%, rgba(255, 255, 255, 0.65), transparent 60%),
-      radial-gradient(620px 180px at 90% 40%, rgba(47, 111, 237, 0.10), transparent 55%);
+    background: radial-gradient(
+        520px 140px at 20% 0%,
+        rgba(255, 255, 255, 0.65),
+        transparent 60%
+      ),
+      radial-gradient(
+        620px 180px at 90% 40%,
+        rgba(47, 111, 237, 0.1),
+        transparent 55%
+      );
     opacity: 0;
     transform: translateX(-8%) translateY(-2%);
     transition: opacity 0.22s ease, transform 0.42s cubic-bezier(0.16, 1, 0.3, 1);
@@ -2051,7 +2120,7 @@
     background: linear-gradient(
       135deg,
       rgba(47, 111, 237, 0.18),
-      rgba(255, 255, 255, 0.0),
+      rgba(255, 255, 255, 0),
       rgba(22, 163, 74, 0.14)
     );
     opacity: 0;
@@ -2069,17 +2138,15 @@
   }
 
   .kpi-item:focus-visible {
-    box-shadow:
-      0 16px 44px rgba(15, 23, 42, 0.10),
+    box-shadow: 0 16px 44px rgba(15, 23, 42, 0.1),
       0 0 0 3px rgba(47, 111, 237, 0.18);
     border-color: rgba(47, 111, 237, 0.22);
   }
 
   .kpi-item.selected {
     border-color: rgba(47, 111, 237, 0.22);
-    box-shadow:
-      0 16px 44px rgba(15, 23, 42, 0.10),
-      inset 0 0 0 1px rgba(47, 111, 237, 0.10);
+    box-shadow: 0 16px 44px rgba(15, 23, 42, 0.1),
+      inset 0 0 0 1px rgba(47, 111, 237, 0.1);
   }
 
   .kpi-left {
@@ -2131,13 +2198,13 @@
   }
 
   .kpi-chip.up {
-    border-color: rgba(22, 163, 74, 0.20);
+    border-color: rgba(22, 163, 74, 0.2);
     color: rgba(22, 163, 74, 0.96);
     background: rgba(22, 163, 74, 0.06);
   }
 
   .kpi-chip.down {
-    border-color: rgba(239, 68, 68, 0.20);
+    border-color: rgba(239, 68, 68, 0.2);
     color: rgba(239, 68, 68, 0.96);
     background: rgba(239, 68, 68, 0.06);
   }
@@ -2146,7 +2213,7 @@
     width: 72px;
     height: 22px;
     opacity: 0.9;
-    filter: drop-shadow(0 8px 16px rgba(15, 23, 42, 0.10));
+    filter: drop-shadow(0 8px 16px rgba(15, 23, 42, 0.1));
   }
 
   .kpi-actions {
@@ -2173,11 +2240,12 @@
     font-weight: 650;
     padding: 4px 8px;
     border-radius: 999px;
-    border: 1px solid rgba(15, 23, 42, 0.10);
+    border: 1px solid rgba(15, 23, 42, 0.1);
     background: rgba(255, 255, 255, 0.78);
     color: rgba(15, 23, 42, 0.78);
     cursor: pointer;
-    transition: background-color 0.16s ease, border-color 0.16s ease, transform 0.16s ease;
+    transition: background-color 0.16s ease, border-color 0.16s ease,
+      transform 0.16s ease;
   }
 
   .kpi-action:hover {
@@ -2200,7 +2268,7 @@
     height: 240px;
     display: grid;
     place-items: center;
-    background: rgba(255, 255, 255, 0.70);
+    background: rgba(255, 255, 255, 0.7);
     border-radius: 12px;
     position: absolute;
     inset: 0;
@@ -2213,8 +2281,11 @@
 
   :deep(.big-chart-dialog .el-dialog__header) {
     padding: 14px 16px;
-    background:
-      radial-gradient(900px 240px at 10% 0%, rgba(47, 111, 237, 0.10), transparent 55%),
+    background: radial-gradient(
+        900px 240px at 10% 0%,
+        rgba(47, 111, 237, 0.1),
+        transparent 55%
+      ),
       rgba(255, 255, 255, 0.92);
     border-bottom: 1px solid rgba(15, 23, 42, 0.06);
   }
@@ -2248,7 +2319,7 @@
     display: flex;
     align-items: center;
     gap: 8px;
-    opacity: 0.0;
+    opacity: 0;
     transform: translateY(-2px);
     transition: opacity 0.16s ease, transform 0.16s ease;
   }
@@ -2274,11 +2345,12 @@
     font-weight: 650;
     padding: 4px 8px;
     border-radius: 10px;
-    border: 1px solid rgba(15, 23, 42, 0.10);
+    border: 1px solid rgba(15, 23, 42, 0.1);
     background: rgba(255, 255, 255, 0.78);
     color: rgba(15, 23, 42, 0.78);
     cursor: pointer;
-    transition: background-color 0.16s ease, border-color 0.16s ease, transform 0.16s ease;
+    transition: background-color 0.16s ease, border-color 0.16s ease,
+      transform 0.16s ease;
   }
 
   .chart-tool:hover {
@@ -2314,31 +2386,55 @@
   }
 
   .kpi-total {
-    background: linear-gradient(135deg, rgba(47, 111, 237, 0.10), rgba(255, 255, 255, 0.86));
+    background: linear-gradient(
+      135deg,
+      rgba(47, 111, 237, 0.1),
+      rgba(255, 255, 255, 0.86)
+    );
   }
   .kpi-total .kpi-icon {
     background: linear-gradient(135deg, var(--lux-primary), var(--lux-primary-2));
   }
 
   .kpi-production {
-    background: linear-gradient(135deg, rgba(22, 163, 74, 0.10), rgba(255, 255, 255, 0.86));
+    background: linear-gradient(
+      135deg,
+      rgba(22, 163, 74, 0.1),
+      rgba(255, 255, 255, 0.86)
+    );
   }
   .kpi-production .kpi-icon {
-    background: linear-gradient(135deg, var(--lux-success), rgba(22, 163, 74, 0.65));
+    background: linear-gradient(
+      135deg,
+      var(--lux-success),
+      rgba(22, 163, 74, 0.65)
+    );
   }
 
   .kpi-office {
-    background: linear-gradient(135deg, rgba(100, 116, 139, 0.10), rgba(255, 255, 255, 0.86));
+    background: linear-gradient(
+      135deg,
+      rgba(100, 116, 139, 0.1),
+      rgba(255, 255, 255, 0.86)
+    );
   }
   .kpi-office .kpi-icon {
     background: linear-gradient(135deg, #64748b, #94a3b8);
   }
 
   .kpi-avg {
-    background: linear-gradient(135deg, rgba(245, 158, 11, 0.10), rgba(255, 255, 255, 0.86));
+    background: linear-gradient(
+      135deg,
+      rgba(245, 158, 11, 0.1),
+      rgba(255, 255, 255, 0.86)
+    );
   }
   .kpi-avg .kpi-icon {
-    background: linear-gradient(135deg, var(--lux-warning), rgba(245, 158, 11, 0.62));
+    background: linear-gradient(
+      135deg,
+      var(--lux-warning),
+      rgba(245, 158, 11, 0.62)
+    );
   }
 
   .panel-card {
@@ -2393,10 +2489,13 @@
   }
 
   .segmented.no-active {
-    background:
-      radial-gradient(900px 220px at 20% 0%, rgba(47, 111, 237, 0.06), transparent 55%),
+    background: radial-gradient(
+        900px 220px at 20% 0%,
+        rgba(47, 111, 237, 0.06),
+        transparent 55%
+      ),
       rgba(15, 23, 42, 0.03);
-    border-color: rgba(15, 23, 42, 0.10);
+    border-color: rgba(15, 23, 42, 0.1);
   }
 
   .segmented-indicator {
@@ -2406,14 +2505,15 @@
     width: calc(50% - 4px);
     height: calc(100% - 8px);
     border-radius: 13px;
-    background: linear-gradient(180deg, rgba(47, 111, 237, 0.10), rgba(255, 255, 255, 0.82));
+    background: linear-gradient(
+      180deg,
+      rgba(47, 111, 237, 0.1),
+      rgba(255, 255, 255, 0.82)
+    );
     border: 1px solid rgba(47, 111, 237, 0.18);
-    box-shadow:
-      0 14px 30px rgba(15, 23, 42, 0.10),
+    box-shadow: 0 14px 30px rgba(15, 23, 42, 0.1),
       0 1px 0 rgba(255, 255, 255, 0.65) inset;
-    transition:
-      transform 0.36s cubic-bezier(0.16, 1, 0.3, 1),
-      opacity 0.20s ease;
+    transition: transform 0.36s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.2s ease;
     pointer-events: none;
     will-change: transform;
     z-index: 1;
@@ -2436,7 +2536,8 @@
     border: 1px solid transparent;
     background: transparent;
     cursor: pointer;
-    transition: transform 0.16s ease, color 0.16s ease, background-color 0.16s ease;
+    transition: transform 0.16s ease, color 0.16s ease,
+      background-color 0.16s ease;
   }
 
   .segmented-item:hover {
@@ -2487,7 +2588,8 @@
     background: var(--lux-card);
     backdrop-filter: blur(10px);
     box-shadow: var(--lux-shadow-soft);
-    transition: box-shadow 0.22s ease, transform 0.22s ease, border-color 0.22s ease;
+    transition: box-shadow 0.22s ease, transform 0.22s ease,
+      border-color 0.22s ease;
 
     &:hover {
       transform: translateY(-2px);
@@ -2518,12 +2620,13 @@
     background: var(--lux-card);
     backdrop-filter: blur(10px);
     box-shadow: var(--lux-shadow-soft);
-    transition: box-shadow 0.22s ease, transform 0.22s ease, border-color 0.22s ease;
+    transition: box-shadow 0.22s ease, transform 0.22s ease,
+      border-color 0.22s ease;
 
     &:hover {
       transform: translateY(-1px);
       box-shadow: var(--lux-shadow);
-      border-color: rgba(15, 23, 42, 0.10);
+      border-color: rgba(15, 23, 42, 0.1);
     }
   }
 
@@ -2531,12 +2634,12 @@
     width: 100%;
   }
 
-  .consumption-value {
+  .unit-value {
     font-weight: bold;
     color: var(--lux-primary);
   }
 
-  .consumption-unit {
+  .unit-unit {
     font-size: 12px;
     color: var(--lux-muted);
     margin-left: 2px;
@@ -2570,8 +2673,11 @@
   }
 
   :deep(.lux-table .el-table__header-wrapper) {
-    background:
-      linear-gradient(180deg, rgba(15, 23, 42, 0.04) 0%, rgba(15, 23, 42, 0.02) 100%);
+    background: linear-gradient(
+      180deg,
+      rgba(15, 23, 42, 0.04) 0%,
+      rgba(15, 23, 42, 0.02) 100%
+    );
   }
 
   :deep(.lux-table th.el-table__cell) {
@@ -2595,10 +2701,12 @@
   }
 
   :deep(.lux-table .el-table__row:hover) {
-    box-shadow: inset 3px 0 0 rgba(47, 111, 237, 0.30);
+    box-shadow: inset 3px 0 0 rgba(47, 111, 237, 0.3);
   }
 
-  :deep(.lux-table .el-table__body tr.el-table__row--striped > td.el-table__cell) {
+  :deep(
+      .lux-table .el-table__body tr.el-table__row--striped > td.el-table__cell
+    ) {
     background: rgba(15, 23, 42, 0.018);
   }
 
@@ -2658,4 +2766,4 @@
     max-height: 600px;
     opacity: 1;
   }
-</style>
\ No newline at end of file
+</style>

--
Gitblit v1.9.3