Bläddra i källkod

价格配置、自动抄表、用能报表

learshaw 7 månader sedan
förälder
incheckning
c5e2e28625

+ 13 - 0
ems-ui-cloud/src/api/device/energyConsumption.js

@@ -7,6 +7,19 @@ import request from '@/utils/request'
  * @param {Object} query 查询参数
  * @returns {Promise} 区域用电统计列表
  */
+export function getElechourTypes(query) {
+  return request({
+    url: '/ems/consumption/area/elec/hourTypes',
+    method: 'get',
+    params: query
+  })
+}
+
+/**
+ * 查询区域用电统计列表
+ * @param {Object} query 查询参数
+ * @returns {Promise} 区域用电统计列表
+ */
 export function getAreaElecConsumptionList(query) {
   return request({
     url: '/ems/consumption/area/elec/list',

+ 235 - 110
ems-ui-cloud/src/views/analysis/report/statement-consume.vue

@@ -89,10 +89,10 @@
 
         <!-- 统计汇总卡片 - 用电 -->
         <div v-if="queryParams.energyType === 'elec'">
-          <el-row :gutter="20" style="margin-bottom: 20px">
+          <el-row :gutter="20" style="margin-bottom: 15px">
             <!-- 第一行:总用电量和总电费 -->
             <el-col :span="12">
-              <el-card class="summary-card">
+              <el-card class="summary-card compact-card">
                 <div slot="header">
                   <i class="el-icon-lightning summary-icon elec-icon"></i>
                   <span>总用电量</span>
@@ -103,7 +103,7 @@
               </el-card>
             </el-col>
             <el-col :span="12">
-              <el-card class="summary-card">
+              <el-card class="summary-card compact-card">
                 <div slot="header">
                   <i class="el-icon-money summary-icon cost-icon"></i>
                   <span>总电费</span>
@@ -115,64 +115,30 @@
             </el-col>
           </el-row>
 
-          <!-- 第二行:峰谷电统计 -->
-          <el-row :gutter="15" style="margin-bottom: 20px">
-            <el-col :span="6">
-              <el-card class="peak-valley-card">
-                <div slot="header" class="clearfix">
-                  <span>尖峰电</span>
-                  <span class="peak-type-tag peak-tag">尖峰</span>
-                </div>
-                <div class="peak-valley-content">
-                  <div class="quantity">{{ formatNumber(summary.sharpPeakQuantity) }} kWh</div>
-                  <div class="percentage">占比 {{ calculatePercentage(summary.sharpPeakQuantity, summary.totalElecQuantity) }}%</div>
-                </div>
-              </el-card>
-            </el-col>
-            <el-col :span="6">
-              <el-card class="peak-valley-card">
-                <div slot="header" class="clearfix">
-                  <span>高峰电</span>
-                  <span class="peak-type-tag high-peak-tag">高峰</span>
-                </div>
-                <div class="peak-valley-content">
-                  <div class="quantity">{{ formatNumber(summary.peakQuantity) }} kWh</div>
-                  <div class="percentage">占比 {{ calculatePercentage(summary.peakQuantity, summary.totalElecQuantity) }}%</div>
-                </div>
-              </el-card>
-            </el-col>
-            <el-col :span="6">
-              <el-card class="peak-valley-card">
-                <div slot="header" class="clearfix">
-                  <span>平峰电</span>
-                  <span class="peak-type-tag normal-tag">平峰</span>
-                </div>
-                <div class="peak-valley-content">
-                  <div class="quantity">{{ formatNumber(summary.normalQuantity) }} kWh</div>
-                  <div class="percentage">占比 {{ calculatePercentage(summary.normalQuantity, summary.totalElecQuantity) }}%</div>
-                </div>
-              </el-card>
-            </el-col>
-            <el-col :span="6">
-              <el-card class="peak-valley-card">
-                <div slot="header" class="clearfix">
-                  <span>低谷电</span>
-                  <span class="peak-type-tag valley-tag">低谷</span>
-                </div>
-                <div class="peak-valley-content">
-                  <div class="quantity">{{ formatNumber(summary.valleyQuantity) }} kWh</div>
-                  <div class="percentage">占比 {{ calculatePercentage(summary.valleyQuantity, summary.totalElecQuantity) }}%</div>
-                </div>
-              </el-card>
-            </el-col>
-          </el-row>
+          <!-- 第二行:动态峰谷电统计 -->
+          <div class="peak-valley-container">
+            <el-card
+              v-for="meterType in supportedMeterTypes"
+              :key="meterType.value"
+              class="peak-valley-card compact-card"
+            >
+              <div slot="header" class="clearfix">
+                <span>{{ meterType.name }}</span>
+                <span class="peak-type-tag" :class="meterType.tagClass">{{ meterType.tagName }}</span>
+              </div>
+              <div class="peak-valley-content">
+                <div class="quantity">{{ formatNumber(getMeterTypeQuantity(meterType.value)) }} kWh</div>
+                <div class="percentage">占比 {{ calculatePercentage(getMeterTypeQuantity(meterType.value), summary.totalElecQuantity) }}%</div>
+              </div>
+            </el-card>
+          </div>
         </div>
 
         <!-- 统计汇总卡片 - 用水 -->
         <div v-if="queryParams.energyType === 'water'">
-          <el-row :gutter="20" style="margin-bottom: 20px">
+          <el-row :gutter="20" style="margin-bottom: 15px">
             <el-col :span="12">
-              <el-card class="summary-card">
+              <el-card class="summary-card compact-card">
                 <div slot="header">
                   <i class="el-icon-set-up summary-icon water-icon"></i>
                   <span>总用水量</span>
@@ -183,7 +149,7 @@
               </el-card>
             </el-col>
             <el-col :span="12">
-              <el-card class="summary-card">
+              <el-card class="summary-card compact-card">
                 <div slot="header">
                   <i class="el-icon-money summary-icon cost-icon"></i>
                   <span>总水费</span>
@@ -214,33 +180,20 @@
             </template>
           </el-table-column>
 
-          <el-table-column label="总用电量(kWh)" align="center" prop="totalElecQuantity">
+          <el-table-column label="总用电量(kW·h)" align="center" prop="totalElecQuantity">
             <template slot-scope="scope">
               <span>{{ formatNumber(scope.row.totalElecQuantity) }}</span>
             </template>
           </el-table-column>
 
-          <el-table-column label="尖峰电(kWh)" align="center" prop="sharpPeakQuantity">
-            <template slot-scope="scope">
-              <span>{{ formatNumber(scope.row.sharpPeakQuantity) }}</span>
-            </template>
-          </el-table-column>
-
-          <el-table-column label="高峰电(kWh)" align="center" prop="peakQuantity">
+          <el-table-column
+            v-for="meterType in supportedMeterTypes"
+            :key="'col-' + meterType.value"
+            :label="meterType.name + '(kW·h)'"
+            align="center"
+          >
             <template slot-scope="scope">
-              <span>{{ formatNumber(scope.row.peakQuantity) }}</span>
-            </template>
-          </el-table-column>
-
-          <el-table-column label="平峰电(kWh)" align="center" prop="normalQuantity">
-            <template slot-scope="scope">
-              <span>{{ formatNumber(scope.row.normalQuantity) }}</span>
-            </template>
-          </el-table-column>
-
-          <el-table-column label="低谷电(kWh)" align="center" prop="valleyQuantity">
-            <template slot-scope="scope">
-              <span>{{ formatNumber(scope.row.valleyQuantity) }}</span>
+              <span>{{ formatNumber(getRowMeterTypeQuantity(scope.row, meterType.value)) }}</span>
             </template>
           </el-table-column>
 
@@ -299,6 +252,7 @@
 import { getFacsCategoryTree } from '@/api/basecfg/emsfacs'
 import { areaTreeSelect } from '@/api/basecfg/area'
 import {
+  getElechourTypes,
   getAreaElecConsumptionList,
   getAreaWaterConsumptionList,
   getFacsElecConsumptionList,
@@ -335,6 +289,43 @@ export default {
       summary: {},
       total: 0,
 
+      // 支持的电量类型
+      supportedMeterTypes: [],
+
+      // 电量类型映射
+      meterTypeMap: {
+        '2': {
+          name: '尖峰电量',
+          tagName: '尖峰',
+          tagClass: 'peak-tag',
+          field: 'sharpPeakQuantity'
+        },
+        '1': {
+          name: '峰段电量',
+          tagName: '峰段',
+          tagClass: 'high-peak-tag',
+          field: 'peakQuantity'
+        },
+        '0': {
+          name: '平段电量',
+          tagName: '平段',
+          tagClass: 'normal-tag',
+          field: 'normalQuantity'
+        },
+        '-1': {
+          name: '谷段电量',
+          tagName: '谷段',
+          tagClass: 'valley-tag',
+          field: 'valleyQuantity'
+        },
+        '-2': {
+          name: '深谷电量',
+          tagName: '深谷',
+          tagClass: 'deep-valley-tag',
+          field: 'deepValleyQuantity'
+        }
+      },
+
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -343,7 +334,7 @@ export default {
         objCode: null,
         objType: 1,
         facsCategory: 'Z',
-        energyType: 'elec', // 新增:能源类型
+        energyType: 'elec',
         timeDimension: 'month',
         startRecTime: this.getDefaultStartTime(),
         endRecTime: this.getDefaultEndTime(),
@@ -391,13 +382,72 @@ export default {
     // 初始化数据
     async initializeData() {
       await this.loadTreeData()
+      await this.loadSupportedMeterTypes()
       await this.getConsumptionList()
       await this.getConsumptionSummary()
     },
 
+    // 加载支持的电量类型
+    async loadSupportedMeterTypes() {
+      if (this.queryParams.energyType !== 'elec') {
+        this.supportedMeterTypes = []
+        return
+      }
+
+      try {
+        const query = formatQueryParams(this.queryParams)
+        const response = await getElechourTypes(query)
+
+        if (response.data && Array.isArray(response.data)) {
+          // 过滤并排序电量类型
+          const types = response.data
+            .filter(type => type !== null && type !== undefined && this.meterTypeMap[type])
+            .sort((a, b) => Number(b) - Number(a)) // 从大到小排序(尖峰到深谷)
+            .map(type => ({
+              value: type,
+              ...this.meterTypeMap[type]
+            }))
+
+          this.supportedMeterTypes = types
+        } else {
+          // 如果没有返回数据,使用默认全部类型
+          this.supportedMeterTypes = Object.keys(this.meterTypeMap)
+            .sort((a, b) => Number(b) - Number(a))
+            .map(type => ({
+              value: type,
+              ...this.meterTypeMap[type]
+            }))
+        }
+      } catch (error) {
+        console.error('加载电量类型失败:', error)
+        // 出错时使用默认全部类型
+        this.supportedMeterTypes = Object.keys(this.meterTypeMap)
+          .sort((a, b) => Number(b) - Number(a))
+          .map(type => ({
+            value: type,
+            ...this.meterTypeMap[type]
+          }))
+      }
+    },
+
+    // 获取指定类型的电量值
+    getMeterTypeQuantity(meterType) {
+      if (!this.summary) return 0
+      const fieldName = this.meterTypeMap[meterType]?.field
+      return fieldName ? (this.summary[fieldName] || 0) : 0
+    },
+
+    // 获取表格行中指定类型的电量值
+    getRowMeterTypeQuantity(row, meterType) {
+      if (!row) return 0
+      const fieldName = this.meterTypeMap[meterType]?.field
+      return fieldName ? (row[fieldName] || 0) : 0
+    },
+
     // 能源类型切换处理
     async handleEnergyTypeChange() {
       this.clearData()
+      await this.loadSupportedMeterTypes()
       await this.getConsumptionList()
       await this.getConsumptionSummary()
     },
@@ -414,6 +464,7 @@ export default {
         await this.loadFacsTreeData()
       }
 
+      await this.loadSupportedMeterTypes()
       await this.getConsumptionList()
       await this.getConsumptionSummary()
     },
@@ -532,7 +583,7 @@ export default {
     },
 
     // 节点点击处理
-    handleNodeClick(data, node) {
+    async handleNodeClick(data, node) {
       if (this.activeName === 'facsConsume') {
         const isTopLevelAreaNode = !node.parent || node.level === 1
 
@@ -549,8 +600,9 @@ export default {
       }
 
       this.queryParams.pageNum = 1
-      this.getConsumptionList()
-      this.getConsumptionSummary()
+      await this.loadSupportedMeterTypes()
+      await this.getConsumptionList()
+      await this.getConsumptionSummary()
     },
 
     // 获取顶级区域节点ID
@@ -572,11 +624,12 @@ export default {
     },
 
     // 时间维度变化处理
-    handleTimeDimensionChange() {
+    async handleTimeDimensionChange() {
       this.adjustTimeRange()
       this.queryParams.pageNum = 1
-      this.getConsumptionList()
-      this.getConsumptionSummary()
+      await this.loadSupportedMeterTypes()
+      await this.getConsumptionList()
+      await this.getConsumptionSummary()
     },
 
     // 调整时间范围
@@ -612,14 +665,15 @@ export default {
     },
 
     // 搜索处理
-    handleQuery() {
+    async handleQuery() {
       this.queryParams.pageNum = 1
-      this.getConsumptionList()
-      this.getConsumptionSummary()
+      await this.loadSupportedMeterTypes()
+      await this.getConsumptionList()
+      await this.getConsumptionSummary()
     },
 
     // 重置处理
-    resetQuery() {
+    async resetQuery() {
       this.resetForm('queryForm')
       this.queryParams = {
         ...this.queryParams,
@@ -629,7 +683,7 @@ export default {
         endRecTime: this.getDefaultEndTime(),
         pageNum: 1
       }
-      this.handleQuery()
+      await this.handleQuery()
     },
 
     // 导出处理
@@ -827,19 +881,27 @@ export default {
   overflow-y: auto;
 }
 
-.summary-card {
-  text-align: center;
-  min-height: 120px;
+/* 压缩卡片高度 */
+.compact-card {
+  min-height: auto !important;
 }
 
-.summary-card .el-card__header {
-  padding: 15px 20px;
+.compact-card .el-card__header {
+  padding: 10px 15px !important;
   border-bottom: 1px solid #ebeef5;
 }
 
+.compact-card .el-card__body {
+  padding: 15px !important;
+}
+
+.summary-card {
+  text-align: center;
+}
+
 .summary-icon {
-  font-size: 18px;
-  margin-right: 8px;
+  font-size: 16px;
+  margin-right: 6px;
   vertical-align: middle;
 }
 
@@ -856,14 +918,14 @@ export default {
 }
 
 .summary-value {
-  font-size: 28px;
+  font-size: 24px;
   font-weight: bold;
   color: #409EFF;
-  padding: 20px 0;
+  padding: 10px 0;
 }
 
 .unit {
-  font-size: 16px;
+  font-size: 14px;
   font-weight: normal;
   color: #909399;
   margin-left: 5px;
@@ -871,12 +933,10 @@ export default {
 
 .peak-valley-card {
   text-align: center;
-  min-height: 120px;
 }
 
 .peak-valley-card .el-card__header {
-  padding: 12px 15px;
-  border-bottom: 1px solid #ebeef5;
+  padding: 8px 12px !important;
 }
 
 .clearfix:after {
@@ -887,12 +947,13 @@ export default {
 
 .peak-type-tag {
   float: right;
-  padding: 3px 8px;
-  font-size: 12px;
-  border-radius: 4px;
+  padding: 2px 6px;
+  font-size: 11px;
+  border-radius: 3px;
   color: white;
 }
 
+/* 峰谷电类型标签样式 */
 .peak-tag {
   background-color: #F56C6C;
 }
@@ -909,19 +970,25 @@ export default {
   background-color: #67C23A;
 }
 
+/* 新增深谷标签样式 */
+.deep-valley-tag {
+  background-color: #409EFF;
+  background: linear-gradient(135deg, #409EFF 0%, #1976D2 100%);
+}
+
 .peak-valley-content {
-  padding: 15px 0;
+  padding: 10px 0;
 }
 
 .quantity {
-  font-size: 20px;
+  font-size: 18px;
   font-weight: bold;
   color: #303133;
-  margin-bottom: 8px;
+  margin-bottom: 6px;
 }
 
 .percentage {
-  font-size: 14px;
+  font-size: 13px;
   color: #909399;
 }
 
@@ -934,4 +1001,62 @@ export default {
   color: #909399;
   cursor: not-allowed;
 }
+
+/* 响应式布局调整 */
+@media (max-width: 1680px) {
+  .peak-valley-card .quantity {
+    font-size: 16px;
+  }
+
+  .peak-valley-card .percentage {
+    font-size: 12px;
+  }
+}
+
+@media (max-width: 1366px) {
+  .peak-valley-card .quantity {
+    font-size: 14px;
+  }
+
+  .peak-type-tag {
+    font-size: 10px;
+    padding: 1px 4px;
+  }
+}
+
+/* 峰谷电容器flex布局 */
+.peak-valley-container {
+  display: flex;
+  gap: 15px;
+  margin-bottom: 15px;
+}
+
+.peak-valley-container .peak-valley-card {
+  flex: 1;
+  min-width: 0; /* 防止内容溢出 */
+}
+
+/* 响应式调整 - 小屏幕时换行 */
+@media (max-width: 1366px) {
+  .peak-valley-container {
+    flex-wrap: wrap;
+  }
+
+  .peak-valley-container .peak-valley-card {
+    flex: 1 1 calc(33.333% - 10px); /* 一行显示3个 */
+    min-width: 200px;
+  }
+}
+
+@media (max-width: 768px) {
+  .peak-valley-container .peak-valley-card {
+    flex: 1 1 calc(50% - 7.5px); /* 一行显示2个 */
+  }
+}
+
+@media (max-width: 480px) {
+  .peak-valley-container .peak-valley-card {
+    flex: 1 1 100%; /* 一行显示1个 */
+  }
+}
 </style>

+ 81 - 74
ems-ui-cloud/src/views/basecfg/boundaryRel/index.vue

@@ -71,7 +71,7 @@
                 <template slot="label">
                   <span>
                     <i class="el-icon-lightning"></i> 电表
-                    <el-badge :value="boundDevices.length" :max="99" v-if="boundDevices.length > 0" />
+                    <el-badge :value="boundElectricMeterCount" :max="99" v-if="boundElectricMeterCount > 0" />
                   </span>
                 </template>
               </el-tab-pane>
@@ -79,7 +79,7 @@
                 <template slot="label">
                   <span>
                     <i class="el-icon-water"></i> 水表
-                    <el-badge :value="boundDevices.length" :max="99" v-if="boundDevices.length > 0" />
+                    <el-badge :value="boundWaterMeterCount" :max="99" v-if="boundWaterMeterCount > 0" />
                   </span>
                 </template>
               </el-tab-pane>
@@ -343,30 +343,6 @@
         </div>
       </el-col>
     </el-row>
-
-    <!-- 显示总数信息代替分页 -->
-    <div class="summary-info" v-if="selectedNode">
-      <el-card class="summary-card">
-        <div class="summary-content">
-          <div class="summary-item">
-            <span class="summary-label">当前区域:</span>
-            <span class="summary-value">{{ selectedNode.label }}</span>
-          </div>
-          <div class="summary-item">
-            <span class="summary-label">设备类型:</span>
-            <span class="summary-value">{{ activeDeviceTab === 'electricMeter' ? '电表' : '水表' }}</span>
-          </div>
-          <div class="summary-item">
-            <span class="summary-label">可绑定设备:</span>
-            <span class="summary-value">{{ unboundDevices.length }}个</span>
-          </div>
-          <div class="summary-item">
-            <span class="summary-label">已绑定设备:</span>
-            <span class="summary-value">{{ boundDevices.length }}个</span>
-          </div>
-        </div>
-      </el-card>
-    </div>
   </div>
 </template>
 
@@ -407,6 +383,10 @@ export default {
       selectedUnboundDevices: [],
       selectedBoundDevices: [],
 
+      // 添加分别存储电表和水表绑定数量
+      boundElectricMeterCount: 0,
+      boundWaterMeterCount: 0,
+
       // 初始查询参数(用于获取完整树结构)
       initialQueryParams: {
         pageNum: 1,
@@ -681,12 +661,16 @@ export default {
       this.MeterQueryParams.areaCode = null;
       this.activeDeviceTab = 'electricMeter';
 
+      // 重置绑定数量
+      this.boundElectricMeterCount = 0;
+      this.boundWaterMeterCount = 0;
+
       // 重新加载对应的树形数据
       await this.loadTreeData();
     },
 
     // 设备类型标签页切换
-    handleDeviceTabClick(tab) {
+    async handleDeviceTabClick(tab) {
       this.activeDeviceTab = tab.name;
       this.queryParams.meterCls = tab.name === 'electricMeter' ? 45 : 70;
       this.MeterQueryParams.meterCls = tab.name === 'electricMeter' ? 45 : 70;
@@ -697,10 +681,35 @@ export default {
       this.boundDevices = [];
 
       if (this.selectedNode) {
+        // 切换设备类型时只需要重新加载设备数据,不需要重新获取绑定数量
         this.loadDevices();
       }
     },
 
+    // 添加获取所有绑定数量的方法
+    async loadAllBindingCounts() {
+      if (!this.selectedNode) return;
+
+      try {
+        const objType = this.getObjType();
+        const selectedNodeId = this.selectedNode.areaCode || this.selectedNode.id;
+
+        // 并发获取电表和水表的绑定数量
+        const [electricResponse, waterResponse] = await Promise.all([
+          listByObj(objType, 45, selectedNodeId), // 45是电表
+          listByObj(objType, 70, selectedNodeId)  // 70是水表
+        ]);
+
+        this.boundElectricMeterCount = electricResponse.data ? electricResponse.data.length : 0;
+        this.boundWaterMeterCount = waterResponse.data ? waterResponse.data.length : 0;
+
+      } catch (error) {
+        console.error('获取绑定数量失败:', error);
+        this.boundElectricMeterCount = 0;
+        this.boundWaterMeterCount = 0;
+      }
+    },
+
     // 树节点搜索
     handleSearch(value) {
       this.$refs.tree.filter(value);
@@ -714,7 +723,7 @@ export default {
     },
 
     // 树节点点击 - 修复原始代码的查询逻辑
-    handleNodeClick(data) {
+    async handleNodeClick(data) {
       this.selectedNode = {
         ...data,
         // 统一使用id字段,处理不同数据结构
@@ -763,7 +772,8 @@ export default {
       this.unboundDevices = [];
       this.boundDevices = [];
 
-      // 重新加载设备数据
+      // 先获取所有绑定数量,再加载当前类型的设备数据
+      await this.loadAllBindingCounts();
       this.loadDevices();
     },
 
@@ -959,6 +969,13 @@ export default {
           this.selectedUnboundDevices.splice(selectedIndex, 1);
         }
 
+        // 更新对应的绑定数量
+        if (this.activeDeviceTab === 'electricMeter') {
+          this.boundElectricMeterCount++;
+        } else {
+          this.boundWaterMeterCount++;
+        }
+
         this.$message.success('绑定成功');
       } catch (error) {
         console.error('绑定失败:', error);
@@ -982,6 +999,13 @@ export default {
           this.selectedBoundDevices.splice(selectedIndex, 1);
         }
 
+        // 更新对应的绑定数量
+        if (this.activeDeviceTab === 'electricMeter') {
+          this.boundElectricMeterCount = Math.max(0, this.boundElectricMeterCount - 1);
+        } else {
+          this.boundWaterMeterCount = Math.max(0, this.boundWaterMeterCount - 1);
+        }
+
         this.$message.success('解绑成功');
       } catch (error) {
         console.error('解绑失败:', error);
@@ -1020,6 +1044,13 @@ export default {
           }
         });
 
+        // 更新对应的绑定数量
+        if (this.activeDeviceTab === 'electricMeter') {
+          this.boundElectricMeterCount += devices.length;
+        } else {
+          this.boundWaterMeterCount += devices.length;
+        }
+
         this.selectedUnboundDevices = [];
         this.$message.success(`成功绑定 ${devices.length} 个设备`);
       } catch (error) {
@@ -1051,6 +1082,13 @@ export default {
 
         await this.loadDevices();
 
+        // 更新对应的绑定数量
+        if (this.activeDeviceTab === 'electricMeter') {
+          this.boundElectricMeterCount = Math.max(0, this.boundElectricMeterCount - devices.length);
+        } else {
+          this.boundWaterMeterCount = Math.max(0, this.boundWaterMeterCount - devices.length);
+        }
+
         this.selectedBoundDevices = [];
         this.$message.success(`成功解绑 ${devices.length} 个设备`);
       } catch (error) {
@@ -1085,6 +1123,13 @@ export default {
             });
           });
 
+          // 更新对应的绑定数量
+          if (this.activeDeviceTab === 'electricMeter') {
+            this.boundElectricMeterCount += devicesToBind.length;
+          } else {
+            this.boundWaterMeterCount += devicesToBind.length;
+          }
+
           this.unboundDevices = [];
           this.selectedUnboundDevices = [];
 
@@ -1110,6 +1155,13 @@ export default {
           const devicesToUnbind = [...this.boundDevices];
           await this.performUnbinding(devicesToUnbind);
 
+          // 更新对应的绑定数量
+          if (this.activeDeviceTab === 'electricMeter') {
+            this.boundElectricMeterCount = 0;
+          } else {
+            this.boundWaterMeterCount = 0;
+          }
+
           this.boundDevices = [];
           this.selectedBoundDevices = [];
 
@@ -1534,42 +1586,6 @@ export default {
   box-shadow: 0 2px 8px rgba(0,0,0,0.1);
 }
 
-// 总结信息卡片
-.summary-info {
-  margin-top: 20px;
-}
-
-.summary-card {
-  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
-}
-
-.summary-content {
-  display: flex;
-  justify-content: space-around;
-  align-items: center;
-  flex-wrap: wrap;
-  gap: 16px;
-}
-
-.summary-item {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  text-align: center;
-
-  .summary-label {
-    font-size: 12px;
-    color: #999;
-    margin-bottom: 4px;
-  }
-
-  .summary-value {
-    font-size: 16px;
-    font-weight: 600;
-    color: #333;
-  }
-}
-
 // 响应式设计
 @media (max-width: 768px) {
   .binding-workspace {
@@ -1588,14 +1604,5 @@ export default {
     flex-direction: row;
     padding: 16px 0;
   }
-
-  .summary-content {
-    flex-direction: column;
-    gap: 8px;
-  }
-
-  .summary-item {
-    width: 100%;
-  }
 }
 </style>

+ 570 - 180
ems-ui-cloud/src/views/basecfg/price/index.vue

@@ -3,116 +3,116 @@
     <el-tabs v-model="activeTab">
       <el-tab-pane label="用电分类" name="first">
         <el-row :gutter="20">
-        <el-col :span="4" :xs="24">
-          <div class="head-container">
-            <el-input v-model="areaName" placeholder="请输入区域名称" clearable size="small" prefix-icon="el-icon-search"
-                      style="margin-bottom: 20px"
-            />
-          </div>
-          <div class="head-container" style="height: 100vh; overflow: hidden; position: relative;">
-            <el-tree :data="treeAreaOptions" :props="defaultProps" :expand-on-click-node="false"
-                     :filter-node-method="filterNode" ref="tree" node-key="id" default-expand-all highlight-current
-                     @node-click="handleNodeClick" style="height: calc(100vh - 50px); overflow-y: auto;"
-            />
-          </div>
-        </el-col>
-        <el-col :span="20" :xs="24">
-        <el-row :gutter="10" class="mb8">
-          <el-col :span="1.5">
-            <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAttrAdd" v-hasPermi="['basecfg:price:add']">新增
-            </el-button>
+          <el-col :span="4" :xs="24">
+            <div class="head-container">
+              <el-input v-model="areaName" placeholder="请输入区域名称" clearable size="small" prefix-icon="el-icon-search"
+                        style="margin-bottom: 20px"
+              />
+            </div>
+            <div class="head-container" style="height: 100vh; overflow: hidden; position: relative;">
+              <el-tree :data="treeAreaOptions" :props="defaultProps" :expand-on-click-node="false"
+                       :filter-node-method="filterNode" ref="tree" node-key="id" default-expand-all highlight-current
+                       @node-click="handleNodeClick" style="height: calc(100vh - 50px); overflow-y: auto;"
+              />
+            </div>
           </el-col>
-        </el-row>
-
-        <el-table v-loading="loading" :data="attrList">
-          <el-table-column label="区域" align="center" prop="areaName"/>
-          <el-table-column label="状态" align="center" width="100">
-            <template slot-scope="scope">
-              <el-tag :type="scope.$index === attrList.length - 1 ? 'success' : 'info'" disable-transitions>
-                {{ scope.$index === attrList.length - 1 ? '生效' : '继承' }}
-              </el-tag>
-            </template>
-          </el-table-column>
-          <el-table-column label="用电分类" align="center" prop="elecTypeName" />
-          <el-table-column label="电压等级" align="center" prop="voltageLevel" />
-          <el-table-column label="容(需)量策略" align="center">
-            <el-table-column label="容(需)量类型" align="center" prop="reqCapacityFlag" :formatter="matchReqCapacityFlag" />
-            <el-table-column label="变压器容量(千伏·安)" align="center" prop="transCapacity" />
-            <el-table-column label="最大需量(千瓦)" align="center" prop="reqQuantity" />
-          </el-table-column>
-          <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-            <template slot-scope="scope">
-              <!-- 修改按钮 -->
-              <el-tooltip
-                effect="dark"
-                :content="scope.row.areaCode !== currentAreaCode ? '请到上游节点编辑' : '修改'"
-                placement="top"
-                :open-delay="0"
-                :disabled="scope.row.areaCode === currentAreaCode">
-                <el-button
-                  size="mini"
-                  type="text"
-                  icon="el-icon-edit"
-                  :disabled="scope.row.areaCode !== currentAreaCode"
-                  @click="handleAttrUpdate(scope.row)"
-                  v-hasPermi="['basecfg:price:edit']">
-                  修改
+          <el-col :span="20" :xs="24">
+            <el-row :gutter="10" class="mb8">
+              <el-col :span="1.5">
+                <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAttrAdd" v-hasPermi="['basecfg:price:add']">新增
                 </el-button>
-              </el-tooltip>
-              <el-tooltip
-                effect="dark"
-                :content="scope.row.areaCode !== currentAreaCode ? '请到上游节点编辑' : '删除'"
-                placement="top"
-                :open-delay="0"
-                :disabled="scope.row.areaCode === currentAreaCode">
-                <el-button
-                  size="mini"
-                  type="text"
-                  icon="el-icon-delete"
-                  class="deleteBtn"
-                  :disabled="scope.row.areaCode !== currentAreaCode"
-                  @click="handleAttrDelete(scope.row)"
-                  v-hasPermi="['basecfg:price:remove']">
-                  删除
-                </el-button>
-              </el-tooltip>
-            </template>
-          </el-table-column>
-        </el-table>
+              </el-col>
+            </el-row>
 
-          <pagination v-show="total > 0 || total === 0" :total="total || 0" :page.sync="queryAttrParams.pageNum" :limit.sync="queryAttrParams.pageSize"
-                      @pagination="refreshCurrentAreaData" />
-        <!-- 添加或修改服务区用电属性对话框 -->
-        <el-dialog :title="title" :visible.sync="attrOpen" width="500px" append-to-body>
-          <el-form ref="attrForm" :model="attrForm" :rules="attrRules" label-width="150px">
-            <el-form-item label="园区" prop="areaCode">
-              <el-input v-model="currentAreaName" disabled placeholder="园区名称" />
-              <input type="hidden" v-model="attrForm.areaCode" />
-            </el-form-item>
-            <el-form-item label="价格策略" prop="priceCode">
-              <el-select v-model="attrForm.priceCode">
-                <el-option v-for="item in gwPriceOptions" :label="`${item.elecTypeName}&lt;${item.voltageLevel}&gt;`" :value="item.cfgCode"
-                  :key="item.cfgCode" />
-              </el-select>
-            </el-form-item>
-            <el-form-item label="容(需)量类型" prop="reqCapacityFlag">
-              <el-select v-model="attrForm.reqCapacityFlag">
-                <el-option v-for="item in reqCapacityOptions" :label="item.name" :value="item.code" :key="item.code" />
-              </el-select>
-            </el-form-item>
-            <el-form-item label="变压器容量(kVA/月)" prop="transCapacity" v-if="attrForm.reqCapacityFlag === 1">
-              <el-input v-model="attrForm.transCapacity" placeholder="请输入变压器容量" />
-            </el-form-item>
-            <el-form-item label="最大需量(kW·h/月)" prop="reqQuantity" v-if="attrForm.reqCapacityFlag === 2">
-              <el-input v-model="attrForm.reqQuantity" placeholder="请输入最大需量" />
-            </el-form-item>
-          </el-form>
-          <div slot="footer" class="dialog-footer">
-            <el-button type="primary" @click="submitAttrForm">确 定</el-button>
-            <el-button @click="attrCancel">取 消</el-button>
-          </div>
-        </el-dialog>
-        </el-col>
+            <el-table v-loading="loading" :data="attrList">
+              <el-table-column label="区域" align="center" prop="areaName"/>
+              <el-table-column label="状态" align="center" width="100">
+                <template slot-scope="scope">
+                  <el-tag :type="scope.$index === attrList.length - 1 ? 'success' : 'info'" disable-transitions>
+                    {{ scope.$index === attrList.length - 1 ? '生效' : '继承' }}
+                  </el-tag>
+                </template>
+              </el-table-column>
+              <el-table-column label="用电分类" align="center" prop="elecTypeName" />
+              <el-table-column label="电压等级" align="center" prop="voltageLevel" />
+              <el-table-column label="容(需)量策略" align="center">
+                <el-table-column label="容(需)量类型" align="center" prop="reqCapacityFlag" :formatter="matchReqCapacityFlag" />
+                <el-table-column label="变压器容量(千伏·安)" align="center" prop="transCapacity" />
+                <el-table-column label="最大需量(千瓦)" align="center" prop="reqQuantity" />
+              </el-table-column>
+              <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+                <template slot-scope="scope">
+                  <!-- 修改按钮 -->
+                  <el-tooltip
+                    effect="dark"
+                    :content="scope.row.areaCode !== currentAreaCode ? '请到上游节点编辑' : '修改'"
+                    placement="top"
+                    :open-delay="0"
+                    :disabled="scope.row.areaCode === currentAreaCode">
+                    <el-button
+                      size="mini"
+                      type="text"
+                      icon="el-icon-edit"
+                      :disabled="scope.row.areaCode !== currentAreaCode"
+                      @click="handleAttrUpdate(scope.row)"
+                      v-hasPermi="['basecfg:price:edit']">
+                      修改
+                    </el-button>
+                  </el-tooltip>
+                  <el-tooltip
+                    effect="dark"
+                    :content="scope.row.areaCode !== currentAreaCode ? '请到上游节点编辑' : '删除'"
+                    placement="top"
+                    :open-delay="0"
+                    :disabled="scope.row.areaCode === currentAreaCode">
+                    <el-button
+                      size="mini"
+                      type="text"
+                      icon="el-icon-delete"
+                      class="deleteBtn"
+                      :disabled="scope.row.areaCode !== currentAreaCode"
+                      @click="handleAttrDelete(scope.row)"
+                      v-hasPermi="['basecfg:price:remove']">
+                      删除
+                    </el-button>
+                  </el-tooltip>
+                </template>
+              </el-table-column>
+            </el-table>
+
+            <pagination v-show="total > 0 || total === 0" :total="total || 0" :page.sync="queryAttrParams.pageNum" :limit.sync="queryAttrParams.pageSize"
+                        @pagination="refreshCurrentAreaData" />
+            <!-- 添加或修改服务区用电属性对话框 -->
+            <el-dialog :title="title" :visible.sync="attrOpen" width="500px" append-to-body>
+              <el-form ref="attrForm" :model="attrForm" :rules="attrRules" label-width="150px">
+                <el-form-item label="园区" prop="areaCode">
+                  <el-input v-model="currentAreaName" disabled placeholder="园区名称" />
+                  <input type="hidden" v-model="attrForm.areaCode" />
+                </el-form-item>
+                <el-form-item label="价格策略" prop="priceCode">
+                  <el-select v-model="attrForm.priceCode">
+                    <el-option v-for="item in gwPriceOptions" :label="`${item.elecTypeName}<${item.voltageLevel}>`" :value="item.cfgCode"
+                               :key="item.cfgCode" />
+                  </el-select>
+                </el-form-item>
+                <el-form-item label="容(需)量类型" prop="reqCapacityFlag">
+                  <el-select v-model="attrForm.reqCapacityFlag">
+                    <el-option v-for="item in reqCapacityOptions" :label="item.name" :value="item.code" :key="item.code" />
+                  </el-select>
+                </el-form-item>
+                <el-form-item label="变压器容量(kVA/月)" prop="transCapacity" v-if="attrForm.reqCapacityFlag === 1">
+                  <el-input v-model="attrForm.transCapacity" placeholder="请输入变压器容量" />
+                </el-form-item>
+                <el-form-item label="最大需量(kW·h/月)" prop="reqQuantity" v-if="attrForm.reqCapacityFlag === 2">
+                  <el-input v-model="attrForm.reqQuantity" placeholder="请输入最大需量" />
+                </el-form-item>
+              </el-form>
+              <div slot="footer" class="dialog-footer">
+                <el-button type="primary" @click="submitAttrForm">确 定</el-button>
+                <el-button @click="attrCancel">取 消</el-button>
+              </div>
+            </el-dialog>
+          </el-col>
         </el-row>
       </el-tab-pane>
 
@@ -127,11 +127,12 @@
         <el-table v-loading="loading" :data="gwPriceList">
           <el-table-column label="用电分类" align="center" prop="elecTypeName" />
           <el-table-column label="电压等级" align="center" prop="voltageLevel" />
-          <el-table-column label="单位电价" align="center" prop="degreePrice" />
           <el-table-column label="峰谷电价" align="center">
-            <el-table-column label="低谷段" align="center" prop="fsLowDegreePrice" />
-            <el-table-column label="尖峰段" align="center" prop="fsPeakDegreePrice" />
-            <el-table-column label="高峰段" align="center" prop="fsHighDegreePrice" />
+            <el-table-column label="深谷" align="center" prop="dvPrice" />
+            <el-table-column label="谷段" align="center" prop="vPrice" />
+            <el-table-column label="平段" align="center" prop="opPrice" />
+            <el-table-column label="峰段" align="center" prop="pPrice" />
+            <el-table-column label="尖峰" align="center" prop="cpPrice" />
           </el-table-column>
           <el-table-column label="容(需)量用电价格" align="center">
             <el-table-column label="最大需量 (元/千瓦时·月)" align="center" prop="maxReqPrice" width="80px" />
@@ -148,7 +149,7 @@
         </el-table>
 
         <pagination v-show="total>0" :total="total" :page.sync="queryGwPriceParams.pageNum" :limit.sync="queryGwPriceParams.pageSize"
-          @pagination="getGwPriceList" />
+                    @pagination="getGwPriceList" />
 
         <!-- 添加或修改电价配置对话框 -->
         <el-dialog :title="title" :visible.sync="gwPriceCfgOpen" width="500px" append-to-body>
@@ -164,18 +165,22 @@
             <el-form-item label="电压等级" prop="voltageLevel">
               <el-input v-model="gwPriceForm.voltageLevel" placeholder="请输入电压等级" />
             </el-form-item>
-            <el-form-item label="单位电价(平段)" prop="degreePrice">
-              <el-input v-model="gwPriceForm.degreePrice" placeholder="请输入电度用电价格" />
+            <el-form-item label="深谷价格" prop="dvPrice">
+              <el-input v-model="gwPriceForm.dvPrice" placeholder="请输入深谷价格" />
             </el-form-item>
-            <el-form-item label="尖峰段价格" prop="fsPeakDegreePrice">
-              <el-input v-model="gwPriceForm.fsPeakDegreePrice" placeholder="请输入分时尖峰时段价格" />
+            <el-form-item label="谷段价格" prop="vPrice">
+              <el-input v-model="gwPriceForm.vPrice" placeholder="请输入谷段价格" />
             </el-form-item>
-            <el-form-item label="高峰段价格" prop="fsHighDegreePrice">
-              <el-input v-model="gwPriceForm.fsHighDegreePrice" placeholder="请输入分时高峰时段价格" />
+            <el-form-item label="平段价格" prop="opPrice">
+              <el-input v-model="gwPriceForm.opPrice" placeholder="请输入平段价格" />
             </el-form-item>
-            <el-form-item label="低谷段价格" prop="fsLowDegreePrice">
-              <el-input v-model="gwPriceForm.fsLowDegreePrice" placeholder="请输入分时低谷时段价格" />
+            <el-form-item label="峰段价格" prop="pPrice">
+              <el-input v-model="gwPriceForm.pPrice" placeholder="请输入分时峰段价格" />
             </el-form-item>
+            <el-form-item label="尖峰价格" prop="cpPrice">
+              <el-input v-model="gwPriceForm.cpPrice" placeholder="请输入分时尖时段价格" />
+            </el-form-item>
+
             <el-form-item label="最大需量用电价格" prop="maxReqPrice" v-if="gwPriceForm.elecType === 4">
               <el-input v-model="gwPriceForm.maxReqPrice" placeholder="请输入最大需量用电价格" />
             </el-form-item>
@@ -249,13 +254,22 @@
         <el-table v-loading="strategyParams.loading" :data="strategyList">
           <el-table-column label="策略编码" align="center" prop="strategyCode" />
           <el-table-column label="策略名称" align="center" prop="strategyName" />
-          <el-table-column label="执行日期" align="center" prop="repeatType">
+          <el-table-column label="执行月份" align="center" prop="execMonth" show-overflow-tooltip>
+            <template slot-scope="scope">
+              {{formatExecMonth(scope.row.execMonth)}}
+            </template>
+          </el-table-column>
+          <el-table-column label="执行日期" align="center" prop="execDateType">
             <template slot-scope="scope">
-              {{formatDict(scope.row.repeatType,'repeatTypeOptions')}}
+              {{formatDict(scope.row.execDateType,'execDateTypeOptions')}}
             </template>
           </el-table-column>
-          <el-table-column label="执行说明" align="center" prop="repeatParam" />
           <el-table-column label="策略描述" align="center" prop="strategyDesc" show-overflow-tooltip />
+          <el-table-column label="分时类型" align="center" prop="supportType" show-overflow-tooltip>
+            <template slot-scope="scope">
+              {{formatSupportType(scope.row.supportType)}}
+            </template>
+          </el-table-column>
           <el-table-column label="优先级" align="center" prop="priority" />
           <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
             <template slot-scope="scope">
@@ -270,37 +284,76 @@
         </el-table>
 
         <!-- 添加或修改峰谷电价策略配置对话框 -->
-        <el-dialog :title="title" :visible.sync="strategyDialog" width="750px" append-to-body>
+        <el-dialog :title="title" :visible.sync="strategyDialog" width="850px" append-to-body>
           <el-form ref="strategyForm" class="strategyForm" :model="strategyForm" :disabled="ifDisabled" label-width="100px">
             <el-form-item label="策略编码" prop="strategyCode" required :rules="[{required:true,message:'策略编码不能为空'}]">
               <el-input v-model="strategyForm.strategyCode" placeholder="请输入策略编码" />
             </el-form-item>
-            <el-form-item label="策略名称" prop="strategyName" required :rules="[{required:true,message:'策略编码不能为空'}]">
+            <el-form-item label="策略名称" prop="strategyName" required :rules="[{required:true,message:'策略名称不能为空'}]">
               <el-input v-model="strategyForm.strategyName" placeholder="请输入策略名称" />
             </el-form-item>
-            <el-form-item label="执行日期" prop="repeatType" required :rules="[{required:true,message:'请选择执行日期'}]">
-              <el-select v-model="strategyForm.repeatType" style="width:100%" placeholder="请选择执行日期" @change="repeatTypeChange">
-                <el-option v-for="item in repeatTypeOptions" :label="item.name" :value="item.value" :key="item.value" />
+            <el-form-item label="执行日期" prop="execDateType" required :rules="[{required:true,message:'请选择执行日期'}]">
+              <el-select v-model="strategyForm.execDateType" style="width:100%" placeholder="请选择执行日期" @change="execDateTypeChange">
+                <el-option v-for="item in execDateTypeOptions" :label="item.name" :value="item.value" :key="item.value" />
               </el-select>
             </el-form-item>
-            <el-form-item label="执行说明" required :rules="[{required:true,message:'请选择执行说明'}]" prop="repeatParam"
-                          v-if="[1,5,6].includes(strategyForm.repeatType)">
-              <el-time-picker v-if="strategyForm.repeatType==1" v-model="strategyForm.repeatParam" value-format="HH:mm:ss"
+            <el-form-item label="执行说明" required :rules="[{required:true,message:'请选择执行说明'}]" prop="execDate"
+                          v-if="[1,5,6].includes(strategyForm.execDateType)">
+              <el-time-picker v-if="strategyForm.execDateType==1" v-model="strategyForm.execDate" value-format="HH:mm:ss"
                               :picker-options="{selectableRange: '00:00:00 - 23:59:59'}" placeholder="选择时间">
               </el-time-picker>
-              <el-checkbox-group v-else-if="strategyForm.repeatType==5" v-model="strategyForm.repeatParam">
+              <el-checkbox-group v-else-if="strategyForm.execDateType==5" v-model="strategyForm.execDate">
                 <el-checkbox v-for="day in weeks.filter(item=>item.value<6)"  :label="day.value" :key="day.value">
                   {{day.name}}</el-checkbox>
               </el-checkbox-group>
-              <el-checkbox-group v-else-if="strategyForm.repeatType==6" v-model="strategyForm.repeatParam">
+              <el-checkbox-group v-else-if="strategyForm.execDateType==6" v-model="strategyForm.execDate">
                 <el-checkbox v-for="day in weeks" :label="day.value" :key="day.value">{{day.name}}</el-checkbox>
               </el-checkbox-group>
             </el-form-item>
             <el-form-item label="策略描述" prop="strategyDesc">
               <el-input v-model="strategyForm.strategyDesc" placeholder="请输入策略描述" />
             </el-form-item>
+            <el-form-item label="执行月份" prop="execMonth" required :rules="[{required:true,message:'请选择执行月份'}]">
+              <el-checkbox-group v-model="strategyForm.execMonth">
+                <el-tooltip
+                  v-for="month in availableMonths"
+                  :key="month.value"
+                  :content="month.disabled ? '已占用' : ''"
+                  :disabled="!month.disabled"
+                  placement="top"
+                  effect="dark">
+                  <el-checkbox
+                    :label="month.value"
+                    :disabled="month.disabled">
+                    <span :style="{color: month.disabled ? '#c0c4cc' : ''}">
+                      {{month.label}}
+                     </span>
+                  </el-checkbox>
+                </el-tooltip>
+              </el-checkbox-group>
+              <div v-if="monthConflictTip" style="color: #f56c6c; font-size: 12px; margin-top: 5px;">
+                {{ monthConflictTip }}
+              </div>
+            </el-form-item>
+            <el-form-item label="分时类型" prop="supportType" required :rules="[{required:true,message:'请选择分时类型'}]">
+              <el-checkbox-group v-model="strategyForm.supportType" @change="handleSupportTypeChange">
+                <el-checkbox v-for="type in timeTypeOptions"
+                             :label="type.value"
+                             :key="type.value"
+                             :disabled="type.value === 0">
+                  {{type.label}}
+                </el-checkbox>
+              </el-checkbox-group>
+            </el-form-item>
             <el-form-item label="优先级" prop="priority" required>
-              <el-input-number v-model="strategyForm.priority" :min="0" :max="100" label="描述文字"></el-input-number>
+              <el-input-number v-model="strategyForm.priority"
+                               :min="0"
+                               :max="100"
+                               @change="handlePriorityChange"
+                               label="描述文字"></el-input-number>
+              <span style="margin-left: 10px; color: #909399; font-size: 12px;">
+                相同优先级的策略月份不能重叠
+              </span>
             </el-form-item>
             <el-form-item label="小时电价">
               <el-table class="sub-table" :data="strategyForm.hourList" max-height="200px">
@@ -318,13 +371,13 @@
                     </el-time-picker>
                   </template>
                 </el-table-column>
-                <el-table-column label="计量类型" align="center" prop="type">
+                <el-table-column label="分时类型" align="center" prop="type">
                   <template slot-scope="scope">
                     <el-select v-model="scope.row.type" size="mini" style="width:100%" placeholder="请选择">
-                      <el-option label="低谷电" :value="-1" />
-                      <el-option label="平峰电" :value="0" />
-                      <el-option label="高峰电" :value="1" />
-                      <el-option label="尖峰电" :value="2" />
+                      <el-option v-for="type in filteredTimeTypes"
+                                 :label="type.label"
+                                 :value="type.value"
+                                 :key="type.value" />
                     </el-select>
                   </template>
                 </el-table-column>
@@ -581,7 +634,7 @@ export default {
       },
       // 当前选中的区域代码
       currentAreaCode: null,
-       // 当前选中的区域名称
+      // 当前选中的区域名称
       currentAreaName: '',
       // 是否显示弹出层
       attrOpen: false,
@@ -680,7 +733,8 @@ export default {
         { code: 1, name: '容量电价' },
         { code: 2, name: '需量电价' }
       ],
-      repeatTypeOptions: [
+      // 执行日期选项(原repeatTypeOptions)
+      execDateTypeOptions: [
         // { name: '执行1次', value: 1 },
         { name: '每天', value: 2 },
         // { name: '法定工作日(跳过节假日)', value: 3 },
@@ -697,12 +751,37 @@ export default {
         { name: '周六', value: '6' },
         { name: '周日', value: '7' }
       ],
+      // 新增月份选项
+      monthOptions: [
+        { value: '01', label: '一月' },
+        { value: '02', label: '二月' },
+        { value: '03', label: '三月' },
+        { value: '04', label: '四月' },
+        { value: '05', label: '五月' },
+        { value: '06', label: '六月' },
+        { value: '07', label: '七月' },
+        { value: '08', label: '八月' },
+        { value: '09', label: '九月' },
+        { value: '10', label: '十月' },
+        { value: '11', label: '十一月' },
+        { value: '12', label: '十二月' }
+      ],
+      // 新增分时类型选项
+      timeTypeOptions: [
+        { value: -2, label: '低谷' },
+        { value: -1, label: '谷段' },
+        { value: 0, label: '平段' }, // 默认选中且不可取消
+        { value: 1, label: '峰段' },
+        { value: 2, label: '尖峰' }
+      ],
       strategyForm: {
         strategyCode: '',
         strategyName: '',
         strategyDesc: '',
-        repeatType: '',
-        repeatParam: [],
+        execDateType: '',  // 原repeatType
+        execDate: [],      // 原repeatParam
+        execMonth: [],     // 新增执行月份
+        supportType: [0],  // 新增分时类型,默认包含平段
         priority: 0,
         hourList: []
       },
@@ -725,6 +804,52 @@ export default {
       ifDisabled: false
     }
   },
+  computed: {
+    // 根据选中的分时类型过滤小时电价表格中的选项
+    filteredTimeTypes() {
+      return this.timeTypeOptions.filter(type =>
+        this.strategyForm.supportType.includes(type.value)
+      );
+    },
+    // 获取可用月份(动态禁用已被占用的月份)
+    availableMonths() {
+      const currentPriority = this.strategyForm.priority
+      const samePriorityStrategies = this.strategyList.filter(strategy => {
+        return strategy.priority === currentPriority &&
+          strategy.id !== this.strategyForm.id &&
+          strategy.editFlag !== 0
+      })
+
+      const occupiedMonths = new Set()
+      samePriorityStrategies.forEach(strategy => {
+        if (strategy.execMonth) {
+          strategy.execMonth.split(',').forEach(month => {
+            occupiedMonths.add(month)
+          })
+        }
+      })
+
+      return this.monthOptions.map(month => ({
+        ...month,
+        disabled: occupiedMonths.has(month.value)
+      }))
+    },
+    // 月份冲突提示
+    monthConflictTip() {
+      const currentPriority = this.strategyForm.priority
+      const samePriorityStrategies = this.strategyList.filter(strategy => {
+        return strategy.priority === currentPriority &&
+          strategy.id !== this.strategyForm.id &&
+          strategy.editFlag !== 0
+      })
+
+      if (samePriorityStrategies.length > 0) {
+        const strategies = samePriorityStrategies.map(s => s.strategyName).join('、')
+        return `提示:优先级${currentPriority}下已存在策略:${strategies}`
+      }
+      return ''
+    }
+  },
   created() {
     this.getAreaList('0', 1)
     this.getAreaTree('0', 2)
@@ -784,6 +909,45 @@ export default {
       })
       return text
     },
+    // 新增分时类型格式化方法
+    formatSupportType(supportType) {
+      if (!supportType) return '';
+      const types = supportType.split(',').map(v => parseInt(v));
+      const labels = types.map(type => {
+        const found = this.timeTypeOptions.find(opt => opt.value === type);
+        return found ? found.label : '';
+      }).filter(label => label);
+      return labels.join('、');
+    },
+    // 新增执行月份格式化方法
+    formatExecMonth(execMonth) {
+      if (!execMonth) return '';
+      const months = execMonth.split(',');
+      const labels = months.map(month => {
+        const found = this.monthOptions.find(opt => opt.value === month);
+        return found ? found.label : '';
+      }).filter(label => label);
+      return labels.join('、');
+    },
+    // 处理分时类型变化
+    handleSupportTypeChange(values) {
+      // 确保平段始终被选中
+      if (!values.includes(0)) {
+        values.push(0);
+      }
+    },
+    // 处理优先级变化
+    handlePriorityChange(value) {
+      // 当优先级改变时,清空月份选择中的冲突月份
+      const availableMonthValues = this.availableMonths
+        .filter(m => !m.disabled)
+        .map(m => m.value)
+
+      // 过滤掉不可用的月份
+      this.strategyForm.execMonth = this.strategyForm.execMonth.filter(month =>
+        availableMonthValues.includes(month)
+      )
+    },
     /** 查询非电能源价格配置列表 */
     getFdPriceList() {
       this.fdPriceLoading = true;
@@ -903,10 +1067,11 @@ export default {
         cfgCode: null,
         elecType: null,
         voltageLevel: null,
-        degreePrice: null,
-        fsPeakDegreePrice: null,
-        fsHighDegreePrice: null,
-        fsLowDegreePrice: null,
+        dvPrice: null,
+        vPrice: null,
+        opPrice: null,
+        pPrice: null,
+        cpPrice: null,
         maxReqPrice: null,
         transCapacityPrice: null
       }
@@ -1163,13 +1328,14 @@ export default {
         this.gwPriceOptions = response.data
       })
     },
-    repeatTypeChange(val) {
+    // 修改执行日期变更方法(原repeatTypeChange)
+    execDateTypeChange(val) {
       if (val == 5) {
-        this.strategyForm.repeatParam = this.weeks.filter(item => item.value < 6).map(item => item.value)
+        this.strategyForm.execDate = this.weeks.filter(item => item.value < 6).map(item => item.value)
       } else if (val == 6) {
-        this.strategyForm.repeatParam = []
+        this.strategyForm.execDate = []
       } else {
-        this.strategyForm.repeatParam = ''
+        this.strategyForm.execDate = ''
       }
     },
     /** 查询峰谷电价列表 */
@@ -1184,26 +1350,59 @@ export default {
     handleStrategyDetail(row) {
       this.ifDisabled = true
       this.resetForm('strategyForm')
-      Object.assign(this.strategyForm, row)
-      if ([5, 6].includes(this.strategyForm.repeatType)) {
-        this.strategyForm.repeatParam = this.strategyForm.repeatParam.split(',')
+      // 深拷贝数据,避免直接修改原数据
+      this.strategyForm = JSON.parse(JSON.stringify(row))
+      // 处理执行日期
+      if ([5, 6].includes(this.strategyForm.execDateType)) {
+        this.strategyForm.execDate = this.strategyForm.execDate ?
+          this.strategyForm.execDate.split(',') : []
       }
+      // 处理执行月份
+      this.strategyForm.execMonth = this.strategyForm.execMonth ?
+        this.strategyForm.execMonth.split(',') : []
+      // 处理分时类型
+      this.strategyForm.supportType = this.strategyForm.supportType ?
+        this.strategyForm.supportType.split(',').map(v => parseInt(v)) : [0]
       this.strategyDialog = true
       this.title = '查看峰谷电价策略'
     },
     handleStrategyAdd() {
       this.ifDisabled = false
       this.resetForm('strategyForm')
-      this.strategyForm = this.$options.data().strategyForm
+      this.strategyForm = {
+        id: null, // 确保id为null
+        strategyCode: '',
+        strategyName: '',
+        strategyDesc: '',
+        execDateType: '',
+        execDate: [],
+        execMonth: [],
+        supportType: [0], // 默认选中平段
+        priority: 1, // 默认优先级为1
+        hourList: []
+      }
       this.strategyDialog = true
       this.title = '添加峰谷电价策略'
     },
     handleStrategyUpdate(row) {
       this.ifDisabled = false
       this.resetForm('strategyForm')
-      Object.assign(this.strategyForm, row)
-      if ([5, 6].includes(this.strategyForm.repeatType)) {
-        this.strategyForm.repeatParam = this.strategyForm.repeatParam.split(',')
+      // 深拷贝数据,避免直接修改原数据
+      this.strategyForm = JSON.parse(JSON.stringify(row))
+      // 处理执行日期
+      if ([5, 6].includes(this.strategyForm.execDateType)) {
+        this.strategyForm.execDate = this.strategyForm.execDate ?
+          this.strategyForm.execDate.split(',') : []
+      }
+      // 处理执行月份
+      this.strategyForm.execMonth = this.strategyForm.execMonth ?
+        this.strategyForm.execMonth.split(',') : []
+      // 处理分时类型
+      this.strategyForm.supportType = this.strategyForm.supportType ?
+        this.strategyForm.supportType.split(',').map(v => parseInt(v)) : [0]
+      // 确保平段始终被选中
+      if (!this.strategyForm.supportType.includes(0)) {
+        this.strategyForm.supportType.push(0)
       }
       this.strategyDialog = true
       this.title = '修改峰谷电价策略'
@@ -1219,7 +1418,25 @@ export default {
     strategyCancel() {
       this.strategyDialog = false
       this.resetForm('strategyForm')
-      this.strategyForm = this.$options.data().strategyForm
+      // 完全重置表单数据,确保不影响下次编辑
+      this.strategyForm = {
+        id: null,
+        strategyCode: '',
+        strategyName: '',
+        strategyDesc: '',
+        execDateType: '',
+        execDate: [],
+        execMonth: [],
+        supportType: [0], // 重置时也要默认选中平段
+        priority: 1,
+        hourList: []
+      }
+      // 清除可能的验证状态
+      this.$nextTick(() => {
+        if (this.$refs.strategyForm) {
+          this.$refs.strategyForm.clearValidate()
+        }
+      })
     },
     submitStrategyForm() {
       this.$refs['strategyForm'].validate(valid => {
@@ -1227,6 +1444,13 @@ export default {
           if (this.strategyForm.hourList.length === 0) {
             return this.$modal.msgError(`请添加小时电价数据`)
           }
+
+          // 检查相同优先级的月份冲突
+          const monthConflict = this.checkMonthConflict()
+          if (monthConflict) {
+            return this.$modal.msgError(`执行月份冲突:${monthConflict}月份已被其他相同优先级的策略使用`)
+          }
+
           let subFlag = false
           let dateFlag = false
           let validIndex = 0
@@ -1249,32 +1473,63 @@ export default {
           if (dateFlag) {
             return this.$modal.msgError(`小时电价第${validIndex}行开始时刻不能大于结束时刻`)
           }
-          if (this.checkTimeRangesOverlap()) {
-            return this.$modal.msgError(`小时电价存在时刻交叉,请调整`)
-          }
-          // 特殊处理
-          if ([5, 6].includes(this.strategyForm.repeatType)) {
-            this.strategyForm.repeatParam = this.strategyForm.repeatParam.join()
+
+          // 增强的时间段重叠检查
+          const overlapInfo = this.checkTimeRangesOverlapEnhanced()
+          if (overlapInfo) {
+            return this.$modal.msgError(`小时电价时间段冲突:${overlapInfo}`)
           }
-          this.strategyForm.hourList.forEach(item => {
-            item.strategyCode = this.strategyForm.strategyCode
-          })
-          if (this.strategyForm.id) {
-            updateStrategy(this.strategyForm).then(() => {
-              this.$modal.msgSuccess('修改成功')
-              this.strategyDialog = false
-              this.getStrategyList()
+
+          // 检查时间段完整性(改为可选的警告,不阻止提交)
+          const completenessCheck = this.checkTimeCompleteness()
+          if (completenessCheck) {
+            // 使用confirm让用户选择是否继续
+            this.$modal.confirm(`${completenessCheck},是否继续保存?`).then(() => {
+              this.saveStrategyForm()
+            }).catch(() => {
+              // 用户选择取消,不做任何操作
             })
           } else {
-            addStrategy(this.strategyForm).then(() => {
-              this.$modal.msgSuccess('新增成功')
-              this.strategyDialog = false
-              this.getStrategyList()
-            })
+            // 没有时间段问题,直接保存
+            this.saveStrategyForm()
           }
         }
       })
     },
+    // 新增方法:保存策略表单
+    saveStrategyForm() {
+      // 创建表单数据的副本以避免修改原数据
+      const formData = JSON.parse(JSON.stringify(this.strategyForm))
+
+      // 特殊处理执行日期 - 确保是字符串
+      if ([5, 6].includes(formData.execDateType)) {
+        formData.execDate = Array.isArray(formData.execDate) ? formData.execDate.join(',') : formData.execDate
+      }
+
+      // 处理执行月份 - 确保是字符串
+      formData.execMonth = Array.isArray(formData.execMonth) ? formData.execMonth.join(',') : formData.execMonth
+
+      // 处理分时类型 - 确保是字符串
+      formData.supportType = Array.isArray(formData.supportType) ? formData.supportType.join(',') : formData.supportType
+
+      formData.hourList.forEach(item => {
+        item.strategyCode = formData.strategyCode
+      })
+
+      if (formData.id) {
+        updateStrategy(formData).then(() => {
+          this.$modal.msgSuccess('修改成功')
+          this.strategyDialog = false
+          this.getStrategyList()
+        })
+      } else {
+        addStrategy(formData).then(() => {
+          this.$modal.msgSuccess('新增成功')
+          this.strategyDialog = false
+          this.getStrategyList()
+        })
+      }
+    },
     compareTime(t1, t2) {
       const d = new Date()
       const ft1 = d.setHours(t1.split(':')[0], t1.split(':')[1], t1.split(':')[2])
@@ -1299,6 +1554,142 @@ export default {
       // 所有时间段都没有重叠
       return false
     },
+    // 增强版时间段重叠检查,返回具体的冲突信息
+    checkTimeRangesOverlapEnhanced() {
+      const ranges = this.strategyForm.hourList.map((item, index) => {
+        const d = new Date()
+        const ft1 = d.setHours(item.startTime.split(':')[0], item.startTime.split(':')[1], item.startTime.split(':')[2])
+        const ft2 = d.setHours(item.endTime.split(':')[0], item.endTime.split(':')[1], item.endTime.split(':')[2])
+        return {
+          start: ft1,
+          end: ft2,
+          startStr: item.startTime,
+          endStr: item.endTime,
+          index: index + 1
+        }
+      })
+
+      // 按开始时间排序
+      const sortedRanges = ranges.slice().sort((a, b) => a.start - b.start)
+
+      // 检查重叠并返回详细信息
+      for (let i = 1; i < sortedRanges.length; i++) {
+        if (sortedRanges[i].start < sortedRanges[i - 1].end) {
+          return `第${sortedRanges[i - 1].index}行(${sortedRanges[i - 1].startStr}-${sortedRanges[i - 1].endStr})与第${sortedRanges[i].index}行(${sortedRanges[i].startStr}-${sortedRanges[i].endStr})存在时间重叠`
+        }
+      }
+      return null
+    },
+    // 检查时间完整性(24小时是否都被覆盖)
+    checkTimeCompleteness() {
+      if (this.strategyForm.hourList.length === 0) return null
+
+      const ranges = this.strategyForm.hourList.map(item => {
+        const startParts = item.startTime.split(':')
+        const endParts = item.endTime.split(':')
+        return {
+          start: parseInt(startParts[0]) * 3600 + parseInt(startParts[1]) * 60 + parseInt(startParts[2]),
+          end: parseInt(endParts[0]) * 3600 + parseInt(endParts[1]) * 60 + parseInt(endParts[2]),
+          startStr: item.startTime,
+          endStr: item.endTime
+        }
+      }).sort((a, b) => a.start - b.start)
+
+      const gaps = []
+      const dayInSeconds = 24 * 3600
+      const tolerance = 1 // 允许1秒的容差
+
+      // 检查开始是否从0点开始
+      if (ranges[0].start > tolerance) {
+        gaps.push(`00:00:00 - ${this.formatSeconds(ranges[0].start)}`)
+      }
+
+      // 检查中间的间隙(允许1秒的连续性)
+      for (let i = 1; i < ranges.length; i++) {
+        const gap = ranges[i].start - ranges[i - 1].end
+        // 如果间隙大于1秒,才认为是真正的间隙
+        if (gap > tolerance) {
+          gaps.push(`${this.formatSeconds(ranges[i - 1].end)} - ${this.formatSeconds(ranges[i].start)}`)
+        }
+      }
+
+      // 检查结束是否到24点(23:59:59)
+      if (ranges[ranges.length - 1].end < dayInSeconds - tolerance) {
+        gaps.push(`${this.formatSeconds(ranges[ranges.length - 1].end)} - 23:59:59`)
+      }
+
+      if (gaps.length > 0) {
+        return `以下时间段未配置:${gaps.join('、')}`
+      }
+      return null
+    },
+    // 辅助方法:将秒数转换为时间格式
+    formatSeconds(seconds) {
+      const h = Math.floor(seconds / 3600)
+      const m = Math.floor((seconds % 3600) / 60)
+      const s = seconds % 60
+      return `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`
+    },
+    // 检查相同优先级策略的月份冲突
+    checkMonthConflict() {
+      // 获取当前优先级
+      const currentPriority = this.strategyForm.priority
+
+      // 获取相同优先级的其他策略
+      const samePriorityStrategies = this.strategyList.filter(strategy => {
+        // 排除当前正在编辑的策略和默认策略
+        return strategy.priority === currentPriority &&
+          strategy.id !== this.strategyForm.id &&
+          strategy.editFlag !== 0
+      })
+
+      // 收集已被占用的月份
+      const occupiedMonths = new Set()
+      samePriorityStrategies.forEach(strategy => {
+        if (strategy.execMonth) {
+          strategy.execMonth.split(',').forEach(month => {
+            occupiedMonths.add(month)
+          })
+        }
+      })
+
+      // 检查当前选择的月份是否有冲突
+      const conflictMonths = []
+      this.strategyForm.execMonth.forEach(month => {
+        if (occupiedMonths.has(month)) {
+          const monthLabel = this.monthOptions.find(m => m.value === month)?.label || month
+          conflictMonths.push(monthLabel)
+        }
+      })
+
+      if (conflictMonths.length > 0) {
+        return conflictMonths.join('、')
+      }
+      return null
+    },
+    // 获取可用月份(用于动态禁用已被占用的月份)
+    getAvailableMonths() {
+      const currentPriority = this.strategyForm.priority
+      const samePriorityStrategies = this.strategyList.filter(strategy => {
+        return strategy.priority === currentPriority &&
+          strategy.id !== this.strategyForm.id &&
+          strategy.editFlag !== 0
+      })
+
+      const occupiedMonths = new Set()
+      samePriorityStrategies.forEach(strategy => {
+        if (strategy.execMonth) {
+          strategy.execMonth.split(',').forEach(month => {
+            occupiedMonths.add(month)
+          })
+        }
+      })
+
+      return this.monthOptions.map(month => ({
+        ...month,
+        disabled: occupiedMonths.has(month.value)
+      }))
+    },
     addSub() {
       this.strategyForm.hourList.push({
         startTime: '',
@@ -1406,7 +1797,7 @@ export default {
 }
 
 .app-container {
-   .el-button.deleteBtn:disabled {
+  .el-button.deleteBtn:disabled {
     color: #c0c4cc !important; /* 文字颜色 */
   }
   .el-button.deleteBtn:disabled:hover {
@@ -1415,4 +1806,3 @@ export default {
   }
 }
 </style>
-

+ 743 - 451
ems-ui-cloud/src/views/devmgr/meterData/index.vue

@@ -1,40 +1,52 @@
 <template>
   <div class="app-container">
     <el-row :gutter="20">
+      <!-- 左侧树形选择器 -->
       <el-col :span="4" :xs="24">
         <div class="head-container">
-          <el-input v-model="areaName" placeholder="请输入服务区名称" clearable size="small"
-                    prefix-icon="el-icon-search"
-                    style="margin-bottom: 20px"
-                    @input="filterTree"
+          <el-input
+            v-model="areaName"
+            placeholder="请输入区域名称"
+            clearable
+            size="small"
+            prefix-icon="el-icon-search"
+            style="margin-bottom: 20px"
+            @input="filterTree"
           />
         </div>
-        <div class="head-container">
-          <el-tree :data="areaOptions" :props="defaultProps" :expand-on-click-node="false"
-                   :filter-node-method="filterNode" ref="tree"
-                   node-key="id" default-expand-all highlight-current @node-click="handleNodeClick">
-            <!-- 自定义节点内容:字符标识+名称 -->
-            <template #default="{ data }">
-              <div class="tree-node">
-                <!-- 区域节点添加 ▶ 符号 -->
-                <span v-if="data.type === 'area'" class="node-symbol area-symbol">▶</span>
-                <!-- 设备节点添加 ◬ 符号 -->
-                <span v-if="data.type === 'device'" class="node-symbol device-symbol">◬</span>
+        <div class="head-container tree-container">
+          <el-tree
+            :data="areaOptions"
+            :props="defaultProps"
+            :expand-on-click-node="false"
+            :filter-node-method="filterNode"
+            ref="tree"
+            node-key="id"
+            default-expand-all
+            highlight-current
+            @node-click="handleNodeClick"
+          >
+            <template #default="{ node, data }">
+              <div class="tree-node" :class="{ 'device-node': data.type === 'device', 'area-node': data.type === 'area' }">
+                <i v-if="data.type === 'area'" class="el-icon-folder node-icon area-icon"></i>
+                <i v-if="data.type === 'device'" class="el-icon-monitor node-icon device-icon"></i>
                 <span class="node-label">{{ data.label }}</span>
               </div>
             </template>
           </el-tree>
         </div>
       </el-col>
+
+      <!-- 右侧内容区域 -->
       <el-col :span="20" :xs="24">
+        <!-- Tab切换 -->
         <el-tabs v-model="activeTab" @tab-click="handleTabChange">
-          <el-tab-pane label="电表读数" name="first">
-          </el-tab-pane>
-          <el-tab-pane label="水表读数" name="second">
-          </el-tab-pane>
+          <el-tab-pane label="电表读数" name="first"></el-tab-pane>
+          <el-tab-pane label="水表读数" name="second"></el-tab-pane>
         </el-tabs>
-        <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch"
-                 label-width="68px">
+
+        <!-- 查询表单 -->
+        <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
           <el-form-item label="抄表周期">
             <el-date-picker
               v-model="daterangeRecordTime"
@@ -44,127 +56,121 @@
               range-separator="-"
               start-placeholder="开始日期"
               end-placeholder="结束日期"
+              :picker-options="pickerOptions"
               @change="handleQuery"
-            ></el-date-picker>
+            />
           </el-form-item>
 
           <el-form-item>
             <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
             <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+            <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport">导出</el-button>
           </el-form-item>
         </el-form>
 
-        <!-- 用电统计数据表格 -->
-        <el-card class="box-card" v-if="activeTab==='first' && numElecMeterHData">
-          <div slot="header" class="clearfix">
-            <span>用电统计</span>
+        <!-- 用电统计卡片 -->
+        <div v-if="activeTab === 'first' && numElecMeterHData">
+          <!-- 汇总统计区域 -->
+          <div class="summary-container">
+            <!-- 总量统计卡片 -->
+            <div class="summary-row">
+              <el-card class="summary-inline-card">
+                <div class="inline-card-content">
+                  <div class="inline-card-left">
+                    <i class="el-icon-lightning inline-icon elec-icon"></i>
+                    <span class="inline-label">总用电量</span>
+                  </div>
+                  <div class="inline-card-right">
+                    <span class="inline-value">{{ formatNumber(numElecMeterHData.total.quantity) }}</span>
+                    <span class="inline-unit">kWh</span>
+                  </div>
+                </div>
+              </el-card>
+
+              <el-card class="summary-inline-card">
+                <div class="inline-card-content">
+                  <div class="inline-card-left">
+                    <i class="el-icon-money inline-icon cost-icon"></i>
+                    <span class="inline-label">总电费</span>
+                  </div>
+                  <div class="inline-card-right">
+                    <span class="inline-value">{{ formatNumber(numElecMeterHData.total.useCost, 2) }}</span>
+                    <span class="inline-unit">元</span>
+                  </div>
+                </div>
+              </el-card>
+            </div>
+
+            <!-- 动态峰谷电统计卡片 - 仅在有数据时显示 -->
+            <div v-if="supportedMeterTypes && supportedMeterTypes.length > 0" class="peak-valley-row">
+              <el-card
+                v-for="meterType in supportedMeterTypes"
+                :key="meterType.value"
+                class="peak-inline-card"
+              >
+                <div class="peak-inline-content">
+                  <div class="peak-inline-header">
+                    <span class="peak-type-badge" :class="meterType.tagClass">{{ meterType.tagName }}</span>
+                  </div>
+                  <div class="peak-inline-body">
+                    <div class="peak-inline-info">
+                      <span class="peak-label">电量</span>
+                      <span class="peak-value">{{ formatNumber(getMeterTypeData(meterType.value, 'quantity')) }}</span>
+                      <span class="peak-unit">kWh</span>
+                    </div>
+                    <div class="peak-inline-info">
+                      <span class="peak-label">费用</span>
+                      <span class="peak-value">{{ formatNumber(getMeterTypeData(meterType.value, 'useCost'), 2) }}</span>
+                      <span class="peak-unit">元</span>
+                    </div>
+                    <div class="peak-percentage">
+                      占比 {{ calculatePercentage(getMeterTypeData(meterType.value, 'quantity'), numElecMeterHData.total.quantity) }}%
+                    </div>
+                  </div>
+                </div>
+              </el-card>
+            </div>
           </div>
+        </div>
 
-          <el-table :data="[numElecMeterHData]" border style="width: 100%">
-            <!-- 第一行:用电量 -->
-            <el-table-column label="" align="center">
-              <template slot-scope="scope">
-                <span>{{ '电量(千瓦时)' }}</span>
-              </template>
-            </el-table-column>
-            <el-table-column label="合计" align="center" class-name="total-column">
-              <template slot-scope="scope">
-                <span class="total-value">{{ scope.row.total.quantity ? scope.row.total.quantity.toFixed(2) : '0.00' }}</span>
-              </template>
-            </el-table-column>
-            <el-table-column label="平段" align="center">
-              <template slot-scope="scope">
-                <span>{{ scope.row.normalElec.quantity ? scope.row.normalElec.quantity.toFixed(2) : '0.00' }}</span>
-              </template>
-            </el-table-column>
-            <el-table-column label="谷段" align="center">
-              <template slot-scope="scope">
-                <span>{{ scope.row.lowElec.quantity ? scope.row.lowElec.quantity.toFixed(2) : '0.00' }}</span>
-              </template>
-            </el-table-column>
-            <el-table-column label="峰段" align="center">
-              <template slot-scope="scope">
-                <span>{{ scope.row.highElec.quantity ? scope.row.highElec.quantity.toFixed(2) : '0.00' }}</span>
-              </template>
-            </el-table-column>
-            <el-table-column label="尖峰段" align="center">
-              <template slot-scope="scope">
-                <span>{{ scope.row.peakElec.quantity ? scope.row.peakElec.quantity.toFixed(2) : '0.00' }}</span>
-              </template>
-            </el-table-column>
-          </el-table>
-          <!-- 第二行:总金额 -->
-          <el-table :data="[numElecMeterHData]" border style="width: 100%; margin-top: 10px" :show-header="false">
-            <el-table-column label="" align="center" >
-              <template slot-scope="scope">
-                <span>{{ '金额(元)' }}</span>
-              </template>
-            </el-table-column>
-            <el-table-column label="合计" align="center" class-name="total-column">
-              <template slot-scope="scope">
-                <span class="total-value">{{ scope.row.total.useCost ? scope.row.total.useCost.toFixed(2) : '0.00' }}</span>
-              </template>
-            </el-table-column>
-            <el-table-column label="平峰-金额(元)" align="center">
-              <template slot-scope="scope">
-                <span>{{ scope.row.normalElec.useCost ? scope.row.normalElec.useCost.toFixed(2) : '0.00' }}</span>
-              </template>
-            </el-table-column>
-            <el-table-column label="低谷段" align="center">
-              <template slot-scope="scope">
-                <span>{{ scope.row.lowElec.useCost ? scope.row.lowElec.useCost.toFixed(2) : '0.00' }}</span>
-              </template>
-            </el-table-column>
-            <el-table-column label="高峰段" align="center">
-              <template slot-scope="scope">
-                <span>{{ scope.row.highElec.useCost ? scope.row.highElec.useCost.toFixed(2) : '0.00' }}</span>
-              </template>
-            </el-table-column>
-            <el-table-column label="尖峰段" align="center">
-              <template slot-scope="scope">
-                <span>{{ scope.row.peakElec.useCost ? scope.row.peakElec.useCost.toFixed(2) : '0.00' }}</span>
-              </template>
-            </el-table-column>
-          </el-table>
-        </el-card>
-
-        <!-- 用水统计数据表格 -->
-        <el-card class="box-card" v-if="activeTab==='second' && numWaterMeterHData">
-          <div slot="header" class="clearfix">
-            <span>用水统计</span>
+        <!-- 用水统计卡片 -->
+        <div v-if="activeTab === 'second'">
+          <!-- 汇总统计区域 -->
+          <div class="summary-container">
+            <div class="summary-row">
+              <el-card class="summary-inline-card">
+                <div class="inline-card-content">
+                  <div class="inline-card-left">
+                    <i class="el-icon-set-up inline-icon water-icon"></i>
+                    <span class="inline-label">总用水量</span>
+                  </div>
+                  <div class="inline-card-right">
+                    <span class="inline-value">{{ formatNumber(getWaterTotal('quantity')) }}</span>
+                    <span class="inline-unit">m³</span>
+                  </div>
+                </div>
+              </el-card>
+
+              <el-card class="summary-inline-card">
+                <div class="inline-card-content">
+                  <div class="inline-card-left">
+                    <i class="el-icon-money inline-icon cost-icon"></i>
+                    <span class="inline-label">总水费</span>
+                  </div>
+                  <div class="inline-card-right">
+                    <span class="inline-value">{{ formatNumber(getWaterTotal('useCost'), 2) }}</span>
+                    <span class="inline-unit">元</span>
+                  </div>
+                </div>
+              </el-card>
+            </div>
           </div>
+        </div>
 
-          <el-table :data="[numWaterMeterHData]" border style="width: 100%">
-            <!-- 第一行:用水量 -->
-            <el-table-column label="" align="center">
-              <template slot-scope="scope">
-                <span>{{ '水量(吨)' }}</span>
-              </template>
-            </el-table-column>
-            <el-table-column label="合计" align="center" class-name="total-column">
-              <template slot-scope="scope">
-                <span class="total-value">{{ scope.row.quantity ? scope.row.quantity.toFixed(2) : '0.00' }}</span>
-              </template>
-            </el-table-column>
-          </el-table>
-          <!-- 第二行:总金额 -->
-          <el-table :data="[numWaterMeterHData]" border style="width: 100%; margin-top: 10px" :show-header="false">
-            <el-table-column label="" align="center" >
-              <template slot-scope="scope">
-                <span>{{ '金额(元)' }}</span>
-              </template>
-            </el-table-column>
-            <el-table-column label="合计" align="center" class-name="total-column">
-              <template slot-scope="scope">
-                <span class="total-value">{{ scope.row.useCost ? scope.row.useCost.toFixed(2) : '0.00' }}</span>
-              </template>
-            </el-table-column>
-          </el-table>
-        </el-card>
-
-        <el-table v-if="activeTab === 'first'" v-loading="loading" :data="elecMeterHList">
-          <el-table-column label="表计名称" align="left" prop="deviceName" width="250px"/>
-          <el-table-column label="表计编号" align="left" prop="deviceCode"/>
+        <!-- 电表数据表格 -->
+        <el-table v-if="activeTab === 'first'" v-loading="loading" :data="elecMeterHList" style="margin-top: 20px">
+          <el-table-column label="表计名称" align="left" prop="deviceName" width="250px" />
+          <el-table-column label="表计编号" align="left" prop="deviceCode" />
           <el-table-column label="抄表时间" align="center" prop="recordTime" width="180">
             <template slot-scope="scope">
               <span>{{ formatDateTime(scope.row.recordTime) }}</span>
@@ -172,135 +178,127 @@
           </el-table-column>
           <el-table-column label="计量时段" align="center" prop="meterType">
             <template slot-scope="scope">
-              <span>{{ getElecMeterType(scope.row.meterType) + "( " + scope.row.meterUnitPrice + " )"}}</span>
+              <el-tag :type="getMeterTypeTagType(scope.row.meterType)" size="small">
+                {{ getElecMeterType(scope.row.meterType) }}
+              </el-tag>
+              <span style="margin-left: 5px; color: #909399;">{{ scope.row.meterUnitPrice }} 元/kWh</span>
             </template>
           </el-table-column>
-
-          <el-table-column label="用电量(kW·h)" align="center" prop="elecQuantity">
+          <el-table-column label="用电量(kWh)" align="center" prop="elecQuantity">
             <template slot-scope="scope">
-              <span>{{ scope.row.elecQuantity ? scope.row.elecQuantity.toFixed(2) : '0.00' }}</span>
+              <span>{{ formatNumber(scope.row.elecQuantity) }}</span>
             </template>
           </el-table-column>
-          <el-table-column label="小时电费" align="center" prop="useElecCost">
+          <el-table-column label="小时电费(元)" align="center" prop="useElecCost">
             <template slot-scope="scope">
-              <span>{{ scope.row.useElecCost ? scope.row.useElecCost.toFixed(2) : '0.00' }}</span>
+              <span>{{ formatNumber(scope.row.useElecCost, 2) }}</span>
             </template>
           </el-table-column>
         </el-table>
 
-        <el-table v-if="activeTab === 'second'" v-loading="loading" :data="waterMeterHList">
-          <el-table-column type="selection" width="55" align="center"/>
-          <el-table-column label="表计名称" align="left" prop="deviceName" width="250"/>
-          <el-table-column label="表计编号" align="left" prop="deviceCode"/>
+        <!-- 水表数据表格 -->
+        <el-table v-if="activeTab === 'second'" v-loading="loading" :data="waterMeterHList" style="margin-top: 20px">
+          <el-table-column label="表计名称" align="left" prop="deviceName" width="250" />
+          <el-table-column label="表计编号" align="left" prop="deviceCode" />
           <el-table-column label="抄表时间" align="center" prop="recordTime" width="180">
             <template slot-scope="scope">
               <span>{{ formatDateTime(scope.row.recordTime) }}</span>
             </template>
           </el-table-column>
-          <el-table-column label="时间序列" align="center" prop="timeIndex"/>
-          <el-table-column label="用水量(t)" align="center" prop="waterQuantity"/>
-          <el-table-column label="单位水价" align="center" prop="meterUnitPrice"/>
-          <el-table-column label="小时水费" align="center" prop="useWaterCost"/>
+          <el-table-column label="时间序列" align="center" prop="timeIndex" />
+          <el-table-column label="用水量(m³)" align="center" prop="waterQuantity">
+            <template slot-scope="scope">
+              <span>{{ formatNumber(scope.row.waterQuantity) }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="单位水价(元/m³)" align="center" prop="meterUnitPrice">
+            <template slot-scope="scope">
+              <span>{{ formatNumber(scope.row.meterUnitPrice, 2) }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="小时水费(元)" align="center" prop="useWaterCost">
+            <template slot-scope="scope">
+              <span>{{ formatNumber(scope.row.useWaterCost, 2) }}</span>
+            </template>
+          </el-table-column>
         </el-table>
+
+        <!-- 分页 -->
         <pagination
-          v-show="total>0"
+          v-show="total > 0"
           :total="total"
           :page.sync="queryParams.pageNum"
           :limit.sync="queryParams.pageSize"
-          @pagination="getElecList"
+          @pagination="getList"
         />
-
-        <!-- 添加或修改用电计量-小时对话框 -->
-        <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
-          <el-form ref="form" :model="form" :rules="rules" label-width="80px">
-            <el-form-item label="园区代码" prop="areaCode">
-              <el-input v-model="form.areaCode" placeholder="请输入园区代码"/>
-            </el-form-item>
-            <el-form-item label="计量设备" prop="deviceCode">
-              <el-input v-model="form.deviceCode" placeholder="请输入计量设备"/>
-            </el-form-item>
-            <el-form-item label="记录时间" prop="recordTime">
-              <el-input v-model="form.recordTime" placeholder="记录时间"/>
-            </el-form-item>
-            <el-form-item label="日期" prop="date">
-              <el-date-picker clearable
-                              v-model="form.date"
-                              type="date"
-                              value-format="yyyy-MM-dd"
-                              placeholder="请选择日期 yyyy-MM-dd"
-              >
-              </el-date-picker>
-            </el-form-item>
-            <el-form-item label="时间" prop="time">
-              <el-time-picker clearable
-                              v-model="form.time"
-                              type="date"
-                              value-format="HH:mm:ss"
-                              placeholder="请选择时间 HH:mm:ss"
-              >
-              </el-time-picker>
-            </el-form-item>
-            <el-form-item label="时间序列" prop="timeIndex">
-              <el-input v-model="form.timeIndex" placeholder="请输入时间序列"/>
-            </el-form-item>
-            <el-form-item label="用电量" prop="elecQuantity">
-              <el-input v-model="form.elecQuantity" placeholder="请输入用电量 单位:kW-h"/>
-            </el-form-item>
-            <el-form-item label="单位电价" prop="meterUnitPrice">
-              <el-input v-model="form.meterUnitPrice" placeholder="请输入单位电价"/>
-            </el-form-item>
-            <el-form-item label="小时电费" prop="useElecCost">
-              <el-input v-model="form.useElecCost" placeholder="请输入小时电费"/>
-            </el-form-item>
-          </el-form>
-          <div slot="footer" class="dialog-footer">
-            <el-button type="primary" @click="submitForm">确 定</el-button>
-            <el-button @click="cancel">取 消</el-button>
-          </div>
-        </el-dialog>
       </el-col>
     </el-row>
   </div>
 </template>
 
 <script>
-import { listElecMeterH, delElecMeterH, addElecMeterH, updateElecMeterH, getNumElecMeterH } from '@/api/device/elecMeterH'
+import { listElecMeterH, getNumElecMeterH, getElecDayAvg } from '@/api/device/elecMeterH'
 import { listWaterMeterH, getNumWaterMeterH } from '@/api/device/waterMeterH'
 import { getDeviceTree } from '@/api/device/meterDevice'
+import { getElechourTypes } from '@/api/device/energyConsumption'
 
 export default {
-  name: 'ElecMeterH',
+  name: 'MeterReading',
   data() {
     return {
       // 存储用电统计数据
       numElecMeterHData: null,
       // 存储用水统计数据
       numWaterMeterHData: null,
+      // 当前激活的标签页
       activeTab: 'first',
       // 遮罩层
       loading: true,
-      // 选中数组
-      ids: [],
-      // 非单个禁用
-      single: true,
-      // 非多个禁用
-      multiple: true,
       // 显示搜索条件
       showSearch: true,
       // 总条数
       total: 0,
-      eleCTotal:0,
-      waterTotal:0,
       // 用电计量-小时表格数据
       elecMeterHList: [],
       // 用水计量-小时表格数据
       waterMeterHList: [],
-      // 弹出层标题
-      title: '',
-      // 是否显示弹出层
-      open: false,
       // 小时电费时间范围
       daterangeRecordTime: [],
+      // 支持的电量类型
+      supportedMeterTypes: [],
+      // 电量类型映射
+      meterTypeMap: {
+        '-2': {
+          name: '深谷电量',
+          tagName: '深谷',
+          tagClass: 'deep-valley-tag',
+          field: 'deepValleyElec'
+        },
+        '-1': {
+          name: '谷段电量',
+          tagName: '谷段',
+          tagClass: 'valley-tag',
+          field: 'lowElec'
+        },
+        '0': {
+          name: '平段电量',
+          tagName: '平段',
+          tagClass: 'normal-tag',
+          field: 'normalElec'
+        },
+        '1': {
+          name: '峰段电量',
+          tagName: '峰段',
+          tagClass: 'high-peak-tag',
+          field: 'highElec'
+        },
+        '2': {
+          name: '尖峰电量',
+          tagName: '尖峰',
+          tagClass: 'peak-tag',
+          field: 'peakElec'
+        }
+      },
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -320,95 +318,141 @@ export default {
         children: 'children',
         label: 'label'
       },
-      // 表单参数
-      form: {},
-      // 表单校验
-      rules: {
-        areaCode: [
-          { required: true, message: '园区代码不能为空', trigger: 'blur' }
-        ],
-        deviceCode: [
-          { required: true, message: '计量设备不能为空', trigger: 'blur' }
-        ],
-        recordTime: [
-          { required: true, message: '记录时间不能为空', trigger: 'blur' }
-        ],
-        date: [
-          { required: true, message: '日期 yyyy-MM-dd不能为空', trigger: 'blur' }
-        ],
-        time: [
-          { required: true, message: '时间 HH:mm:ss不能为空', trigger: 'blur' }
-        ],
-        timeIndex: [
-          { required: true, message: '时间序列不能为空', trigger: 'blur' }
-        ]
+      // 日期选择器配置
+      pickerOptions: {
+        disabledDate(time) {
+          return time.getTime() > Date.now()
+        }
       }
     }
   },
   created() {
-    // 初始化默认查询时间范围
-    this.initDefaultDateRange();
-
+    this.initDefaultDateRange()
     this.getAreaTreeSelect().then(() => {
-      /** 获取第一个有效的设备节点 */
-      const firstValidNode = this.findFirstValidNode(this.areaOptions);
+      const firstValidNode = this.findFirstValidNode(this.areaOptions)
       if (firstValidNode) {
-        this.queryParams.deviceCode = firstValidNode.id;
-        this.handleQuery();
+        this.queryParams.deviceCode = firstValidNode.id
+        this.handleQuery()
       } else {
-        this.getElecList();
+        this.getList()
       }
-    });
+    })
   },
   methods: {
     // 初始化默认查询时间范围:当月1号到今天
     initDefaultDateRange() {
-      const today = new Date();
-      const currentYear = today.getFullYear();
-      const currentMonth = today.getMonth();
+      const today = new Date()
+      const currentYear = today.getFullYear()
+      const currentMonth = today.getMonth()
+      const startDate = new Date(currentYear, currentMonth, 1)
+      const endDate = new Date(today)
 
-      // 当月1号
-      const startDate = new Date(currentYear, currentMonth, 1);
+      const formatDate = (date) => {
+        const year = date.getFullYear()
+        const month = (date.getMonth() + 1).toString().padStart(2, '0')
+        const day = date.getDate().toString().padStart(2, '0')
+        return `${year}-${month}-${day}`
+      }
 
-      // 当天
-      const endDate = new Date(today);
+      this.daterangeRecordTime = [formatDate(startDate), formatDate(endDate)]
+    },
 
-      // 格式化为日期字符串 yyyy-MM-dd
-      const formatDate = (date) => {
-        const year = date.getFullYear();
-        const month = (date.getMonth() + 1).toString().padStart(2, '0');
-        const day = date.getDate().toString().padStart(2, '0');
-        return `${year}-${month}-${day}`;
-      };
+    // 加载支持的电量类型
+    async loadSupportedMeterTypes() {
+      if (this.activeTab !== 'first' || !this.queryParams.deviceCode) {
+        this.supportedMeterTypes = []
+        return
+      }
+
+      try {
+        const query = {
+          objCode: this.queryParams.deviceCode,
+          objType: 2, // 设备类型
+          startRecTime: this.queryParams.startRecTime,
+          endRecTime: this.queryParams.endRecTime
+        }
+
+        // 尝试获取支持的电量类型
+        const response = await getElechourTypes(query)
 
-      this.daterangeRecordTime = [formatDate(startDate), formatDate(endDate)];
+        if (response.data && Array.isArray(response.data)) {
+          const types = response.data
+            .filter(type => type !== null && type !== undefined && this.meterTypeMap[type])
+            .sort((a, b) => Number(b) - Number(a))
+            .map(type => ({
+              value: type,
+              ...this.meterTypeMap[type]
+            }))
+
+          this.supportedMeterTypes = types.length > 0 ? types : this.getDefaultMeterTypes()
+        } else {
+          this.supportedMeterTypes = this.getDefaultMeterTypes()
+        }
+      } catch (error) {
+        console.error('加载电量类型失败:', error)
+        this.supportedMeterTypes = this.getDefaultMeterTypes()
+      }
     },
 
+    // 获取默认的电量类型
+    getDefaultMeterTypes() {
+      // 根据已有数据判断支持的类型
+      const availableTypes = []
+      if (this.numElecMeterHData) {
+        if (this.numElecMeterHData.peakElec && this.numElecMeterHData.peakElec.quantity > 0) {
+          availableTypes.push('2')
+        }
+        if (this.numElecMeterHData.highElec && this.numElecMeterHData.highElec.quantity > 0) {
+          availableTypes.push('1')
+        }
+        if (this.numElecMeterHData.normalElec && this.numElecMeterHData.normalElec.quantity > 0) {
+          availableTypes.push('0')
+        }
+        if (this.numElecMeterHData.lowElec && this.numElecMeterHData.lowElec.quantity > 0) {
+          availableTypes.push('-1')
+        }
+        // 深谷电量暂不支持,需要后端提供
+      }
+
+      // 如果没有任何数据,返回空数组
+      return availableTypes.length > 0
+        ? availableTypes.map(type => ({ value: type, ...this.meterTypeMap[type] }))
+        : []
+    },
+
+    // 获取指定类型的电量数据
+    getMeterTypeData(meterType, field) {
+      if (!this.numElecMeterHData) return 0
+      const typeMapping = {
+        '-2': 'deepValleyElec',
+        '-1': 'lowElec',
+        '0': 'normalElec',
+        '1': 'highElec',
+        '2': 'peakElec'
+      }
+      const typeName = typeMapping[meterType]
+      return typeName && this.numElecMeterHData[typeName]
+        ? (this.numElecMeterHData[typeName][field] || 0)
+        : 0
+    },
+
+    // Tab切换处理
     handleTabChange() {
       if (this.activeTab === 'first') {
-        // 电表读数
-        this.queryParams.meterCls = '45';
+        this.queryParams.meterCls = '45'
       } else if (this.activeTab === 'second') {
-        // 水表读数
-        this.queryParams.meterCls = '70';
+        this.queryParams.meterCls = '70'
       }
 
-      // 重新加载树结构并重置设备选择
       this.getAreaTreeSelect().then(() => {
-        // 切换tab后重新选择第一个设备节点
-        const firstValidNode = this.findFirstValidNode(this.areaOptions);
+        const firstValidNode = this.findFirstValidNode(this.areaOptions)
         if (firstValidNode) {
-          this.queryParams.deviceCode = firstValidNode.id;
-          this.handleQuery();
+          this.queryParams.deviceCode = firstValidNode.id
+          this.handleQuery()
         } else {
-          // 如果没有找到设备节点,则清空数据
-          if (this.activeTab === 'first') {
-            this.getElecList();
-          } else {
-            this.getWaterList();
-          }
+          this.getList()
         }
-      });
+      })
     },
 
     // 筛选节点
@@ -416,63 +460,43 @@ export default {
       if (!value) return true
       return data.label.indexOf(value) !== -1
     },
+
     // 过滤树节点
     filterTree() {
-      this.$refs.tree.filter(this.areaName);
+      this.$refs.tree.filter(this.areaName)
     },
+
     // 节点单击事件
     handleNodeClick(data) {
       // 仅处理设备节点
       if (data.type === 'device') {
-        this.queryParams.deviceCode = data.id;
-        this.handleQuery();
+        this.queryParams.deviceCode = data.id
+        this.handleQuery()
       }
-      // 区域节点不做处理
     },
-    /** 查找第一个设备节点 */
+
+    // 查找第一个设备节点
     findFirstValidNode(nodes) {
       for (const node of nodes) {
         if (node.type === 'device') {
-          return node;
+          return node
         }
         if (node.children && node.children.length > 0) {
-          const foundNode = this.findFirstValidNode(node.children);
-          if (foundNode) return foundNode;
+          const foundNode = this.findFirstValidNode(node.children)
+          if (foundNode) return foundNode
         }
       }
-      return null;
+      return null
     },
-    /** 树结构加载 */
+
+    // 树结构加载
     async getAreaTreeSelect() {
       await getDeviceTree(0, this.queryParams.meterCls, 0).then(response => {
-        this.areaOptions = response.data;
-        // 为树节点添加类型标识以便样式控制
-        this.$nextTick(() => {
-          this.addTypeToNodeAttrs();
-        });
+        this.areaOptions = response.data
       })
     },
-    /** 为树节点DOM添加type属性用于样式控制 */
-    addTypeToNodeAttrs() {
-      if (!this.$refs.tree) return;
-
-      const addAttr = (nodes) => {
-        nodes.forEach(node => {
-          if (node.data && node.data.type) {
-            const el = this.$refs.tree.$el.querySelector(`[data-node-key="${node.key}"] .el-tree-node__content`);
-            if (el) {
-              el.setAttribute('data-type', node.data.type);
-            }
-          }
-          if (node.children && node.children.length > 0) {
-            addAttr(node.children);
-          }
-        });
-      };
-
-      addAttr(this.$refs.tree.store.root.children);
-    },
 
+    // 格式化日期时间
     formatDateTime(dateTime) {
       if (!dateTime) return ''
       const date = new Date(dateTime)
@@ -483,7 +507,17 @@ export default {
       const minutes = date.getMinutes().toString().padStart(2, '0')
       return `${year}-${month}-${day} ${hours}:${minutes}`
     },
-    /** 查询用电计量-小时列表 */
+
+    // 获取列表数据
+    getList() {
+      if (this.activeTab === 'first') {
+        this.getElecList()
+      } else {
+        this.getWaterList()
+      }
+    },
+
+    // 查询用电计量-小时列表
     getElecList() {
       this.loading = true
       listElecMeterH(this.queryParams).then(response => {
@@ -493,7 +527,7 @@ export default {
       })
     },
 
-    /** 查询用水计量-小时列表 */
+    // 查询用水计量-小时列表
     getWaterList() {
       this.loading = true
       listWaterMeterH(this.queryParams).then(response => {
@@ -503,51 +537,26 @@ export default {
       })
     },
 
-    // 取消按钮
-    cancel() {
-      this.open = false
-      this.Elecreset()
-    },
-    // 表单重置
-    Elecreset() {
-      this.form = {
-        id: null,
-        areaCode: null,
-        deviceCode: null,
-        recordTime: null,
-        date: null,
-        time: null,
-        timeIndex: null,
-        elecQuantity: null,
-        meterType: null,
-        meterUnitPrice: null,
-        useElecCost: null,
-        createTime: null
-      }
-      this.resetForm('form')
-    },
-
-    /** 搜索按钮操作 */
-    handleQuery() {
-      // 处理日期范围,自动拼接时分秒
+    // 搜索按钮操作
+    async handleQuery() {
+      // 处理日期范围
       if (this.daterangeRecordTime && this.daterangeRecordTime.length === 2) {
-        this.queryParams.startRecTime = this.daterangeRecordTime[0] + ' 00:00:00';
-        this.queryParams.endRecTime = this.daterangeRecordTime[1] + ' 23:59:59';
+        this.queryParams.startRecTime = this.daterangeRecordTime[0] + ' 00:00:00'
+        this.queryParams.endRecTime = this.daterangeRecordTime[1] + ' 23:59:59'
       } else {
-        this.queryParams.startRecTime = null;
-        this.queryParams.endRecTime = null;
+        this.queryParams.startRecTime = null
+        this.queryParams.endRecTime = null
       }
 
       if (this.activeTab === 'first') {
         this.queryParams.meterCls = '45'
+        await this.loadSupportedMeterTypes()
         this.getElecList()
-        // 获取用电统计数据
-        this.getNumElecMeterH();
+        this.getNumElecMeterH()
       } else if (this.activeTab === 'second') {
         this.queryParams.meterCls = '70'
         this.getWaterList()
-        // 获取用水统计数据
-        this.getNumWaterMeterH();
+        this.getNumWaterMeterH()
       }
     },
 
@@ -556,13 +565,15 @@ export default {
       const query = {
         deviceCode: this.queryParams.deviceCode,
         startRecTime: this.queryParams.startRecTime,
-        endRecTime: this.queryParams.endRecTime,
-      };
+        endRecTime: this.queryParams.endRecTime
+      }
       try {
-        const response = await getNumElecMeterH(query);
-        this.numElecMeterHData = response.data;
+        const response = await getNumElecMeterH(query)
+        this.numElecMeterHData = response.data
+        // 重新加载支持的电量类型
+        await this.loadSupportedMeterTypes()
       } catch (error) {
-        this.$message.error("获取用电统计数据失败");
+        this.$message.error('获取用电统计数据失败')
       }
     },
 
@@ -571,178 +582,459 @@ export default {
       const query = {
         deviceCode: this.queryParams.deviceCode,
         startRecTime: this.queryParams.startRecTime,
-        endRecTime: this.queryParams.endRecTime,
-      };
+        endRecTime: this.queryParams.endRecTime
+      }
       try {
-        const response = await getNumWaterMeterH(query);
-        this.numWaterMeterHData = response.data;
+        const response = await getNumWaterMeterH(query)
+        this.numWaterMeterHData = response.data
       } catch (error) {
-        this.$message.error("获取用水统计数据失败");
+        this.$message.error('获取用水统计数据失败')
       }
     },
 
-    /** 重置按钮操作 */
+    // 重置按钮操作
     resetQuery() {
       this.daterangeRecordTime = []
       this.resetForm('queryForm')
-      // 重置时重新初始化默认时间范围
-      this.initDefaultDateRange();
+      this.initDefaultDateRange()
       this.handleQuery()
     },
-    /** 新增按钮操作 */
-    handleAdd() {
-      this.Elecreset()
-      this.open = true
-      this.title = '添加用电计量-小时'
-    },
-    /** 提交按钮 */
-    submitForm() {
-      this.$refs['form'].validate(valid => {
-        if (valid) {
-          if (this.form.id != null) {
-            updateElecMeterH(this.form).then(response => {
-              this.$modal.msgSuccess('修改成功')
-              this.open = false
-              this.getElecList()
-            })
-          } else {
-            addElecMeterH(this.form).then(response => {
-              this.$modal.msgSuccess('新增成功')
-              this.open = false
-              this.getElecList()
-            })
-          }
-        }
-      })
-    },
-    /** 导出按钮操作 */
+
+    // 导出按钮操作
     handleExport() {
-      this.download('ems/elecMeterH/export', {
-        ...this.queryParams
-      }, `elecMeterH_${new Date().getTime()}.xlsx`)
+      const filename = this.activeTab === 'first'
+        ? `电表读数_${new Date().getTime()}.xlsx`
+        : `水表读数_${new Date().getTime()}.xlsx`
+
+      const url = this.activeTab === 'first'
+        ? 'ems/elecMeterH/export'
+        : 'ems/waterMeterH/export'
+
+      this.download(url, { ...this.queryParams }, filename)
     },
+
+    // 获取电表类型名称
     getElecMeterType(meterType) {
       const meterTypeMap = {
+        '-2': '深谷',
         '-1': '谷段',
         '0': '平段',
         '1': '峰段',
-        '2': '尖峰'
+        '2': '尖峰'
       }
       return meterTypeMap[meterType] || '未知'
+    },
+
+    // 获取电表类型标签颜色
+    getMeterTypeTagType(meterType) {
+      const typeMap = {
+        '-2': 'primary',
+        '-1': 'success',
+        '0': 'info',
+        '1': 'warning',
+        '2': 'danger'
+      }
+      return typeMap[meterType] || 'info'
+    },
+
+    // 计算百分比
+    calculatePercentage(value, total) {
+      if (!value || !total || total === 0) {
+        return '0.0'
+      }
+      const percentage = (value / total) * 100
+      return percentage.toFixed(1)
+    },
+
+    // 获取用水总计数据
+    getWaterTotal(field) {
+      if (this.numWaterMeterHData && this.numWaterMeterHData[field]) {
+        return this.numWaterMeterHData[field]
+      }
+      // 如果没有统计数据,尝试从列表数据计算
+      if (this.waterMeterHList && this.waterMeterHList.length > 0) {
+        if (field === 'quantity') {
+          return this.waterMeterHList.reduce((sum, item) => sum + (item.waterQuantity || 0), 0)
+        } else if (field === 'useCost') {
+          return this.waterMeterHList.reduce((sum, item) => sum + (item.useWaterCost || 0), 0)
+        }
+      }
+      return 0
+    },
+
+    // 格式化数字
+    formatNumber(num, decimals = 2) {
+      if (num === null || num === undefined || isNaN(num)) {
+        return '0.' + '0'.repeat(decimals)
+      }
+      return Number(num).toFixed(decimals)
     }
   }
 }
 </script>
 
 <style scoped>
+/* 树容器样式 */
+.tree-container {
+  height: calc(100vh - 200px);
+  overflow-y: auto;
+  border: 1px solid #e8e8e8;
+  border-radius: 4px;
+  padding: 10px;
+  background-color: #fafafa;
+}
+
 /* 树节点样式 */
 .tree-node {
   display: flex;
   align-items: center;
-  gap: 6px; /* 符号与文字之间的间距 */
-  height: 100%;
+  width: 100%;
+  padding: 2px 0;
+  transition: all 0.3s;
 }
 
-/* 字符标识样式 */
-.node-symbol {
-  display: inline-block;
-  width: 16px; /* 固定宽度确保对齐 */
-  text-align: center;
+.node-icon {
+  margin-right: 8px;
+  font-size: 16px;
+  transition: color 0.3s;
 }
 
-/* 区域节点符号样式 */
-.area-symbol {
-  color: #666; /* 深灰色 */
+.area-icon {
+  color: #909399;
 }
 
-/* 设备节点符号样式 */
-.device-symbol {
-  color: #337ab7; /* 蓝色 */
+.device-icon {
+  color: #409EFF;
 }
 
 .node-label {
-  vertical-align: middle;
+  flex: 1;
+  font-size: 14px;
 }
 
-/* 鼠标样式控制 */
-.el-tree-node__content[data-type="area"] {
+/* 区域节点样式 - 不可点击 */
+.area-node {
   cursor: not-allowed;
-  opacity: 0.9;
+  opacity: 0.7;
+}
+
+.area-node:hover {
+  background-color: transparent !important;
+}
+
+.area-node:hover .area-icon {
+  color: #909399;
 }
 
-.el-tree-node__content[data-type="device"] {
+/* 设备节点样式 - 可点击 */
+.device-node {
   cursor: pointer;
 }
 
-/* 优化树节点hover效果 */
-.el-tree-node__content:hover {
-  background-color: #f5f7fa;
+.device-node:hover {
+  background-color: #f0f7ff;
+  border-radius: 4px;
+  padding-left: 4px;
 }
 
-.el-tree-node__content[data-type="area"]:hover {
-  background-color: #f5f7fa;
+.device-node:hover .device-icon {
+  color: #2b7bff;
+  transform: scale(1.1);
 }
 
-/* 强调合计列的样式 - 若依框架适配 */
-/deep/ .total-column {
-  background-color: #f0f9ff !important;
+/* 高亮当前选中的节点 */
+/deep/ .el-tree-node.is-current > .el-tree-node__content .device-node {
+  background-color: #e6f7ff;
+  border-radius: 4px;
+  padding-left: 4px;
 }
 
-/deep/ .total-column .cell {
-  position: relative;
-  padding-left: 12px !important;
+/deep/ .el-tree-node.is-current > .el-tree-node__content .device-icon {
+  color: #1890ff;
 }
 
-/deep/ .total-column .cell::before {
-  content: '';
-  position: absolute;
-  left: 0;
-  top: 50%;
-  transform: translateY(-50%);
-  width: 4px;
-  height: 60%;
-  background-color: #409eff;
-  border-radius: 2px;
+/* 压缩卡片高度 */
+.compact-card {
+  min-height: auto !important;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
+  transition: all 0.3s;
 }
 
-.total-value {
-  font-weight: bold !important;
-  font-size: 16px !important;
-  color: #2c3e50 !important;
+.compact-card:hover {
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
+  transform: translateY(-2px);
+}
+
+.compact-card .el-card__header {
+  padding: 12px 15px !important;
+  border-bottom: 1px solid #f0f0f0;
+  background: linear-gradient(to right, #f7f8fa, #ffffff);
+}
+
+.compact-card .el-card__body {
+  padding: 20px 15px !important;
+}
+
+/* 新的汇总统计容器 */
+.summary-container {
+  margin-bottom: 20px;
+}
+
+.summary-row {
+  display: flex;
+  gap: 15px;
+  margin-bottom: 15px;
+}
+
+/* 横向紧凑卡片样式 */
+.summary-inline-card {
+  flex: 1;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+  transition: all 0.3s;
+}
+
+.summary-inline-card:hover {
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+  transform: translateY(-2px);
+}
+
+.summary-inline-card .el-card__body {
+  padding: 12px 20px !important;
+}
+
+.inline-card-content {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.inline-card-left {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+
+.inline-icon {
+  font-size: 24px;
+}
+
+.elec-icon {
+  color: #409EFF;
+}
+
+.water-icon {
+  color: #67C23A;
+}
+
+.cost-icon {
+  color: #E6A23C;
+}
+
+.inline-label {
+  font-size: 14px;
+  color: #606266;
+  font-weight: 500;
+}
+
+.inline-card-right {
+  display: flex;
+  align-items: baseline;
+  gap: 5px;
+}
+
+.inline-value {
+  font-size: 24px;
+  font-weight: bold;
+  background: linear-gradient(135deg, #409EFF 0%, #66b1ff 100%);
+  -webkit-background-clip: text;
+  -webkit-text-fill-color: transparent;
+}
+
+.inline-unit {
+  font-size: 12px;
+  color: #909399;
+}
+
+/* 峰谷电横向紧凑卡片 */
+.peak-valley-row {
+  display: flex;
+  gap: 12px;
+  flex-wrap: wrap;
+}
+
+.peak-inline-card {
+  flex: 1;
+  min-width: 200px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+  transition: all 0.3s;
+}
+
+.peak-inline-card:hover {
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+  transform: translateY(-2px);
+}
+
+.peak-inline-card .el-card__body {
+  padding: 10px 15px !important;
+}
+
+.peak-inline-content {
+  display: flex;
+  align-items: center;
+  gap: 15px;
+}
+
+.peak-inline-header {
+  flex-shrink: 0;
+}
+
+.peak-type-badge {
   display: inline-block;
+  padding: 4px 10px;
+  font-size: 12px;
+  border-radius: 4px;
+  color: white;
+  font-weight: 500;
+  min-width: 40px;
+  text-align: center;
 }
 
-.total-value::before {
-  content: '[';
-  margin-right: 2px;
-  color: #409eff !important;
-  font-weight: bold !important;
-  font-size: 16px;
+/* 峰谷电类型标签样式 */
+.deep-valley-tag {
+  background: linear-gradient(135deg, #409EFF 0%, #1976D2 100%);
 }
 
-.total-value::after {
-  content: ']';
-  margin-left: 2px;
-  color: #409eff !important;
-  font-weight: bold !important;
-  font-size: 16px;
+.valley-tag {
+  background: linear-gradient(135deg, #67C23A 0%, #4CAF50 100%);
+}
+
+.normal-tag {
+  background: linear-gradient(135deg, #909399 0%, #606266 100%);
+}
+
+.high-peak-tag {
+  background: linear-gradient(135deg, #E6A23C 0%, #FF9800 100%);
 }
 
-/* 若依框架下的表格样式增强 */
-/deep/ .el-table .total-column {
-  background-color: #f0f9ff !important;
+.peak-tag {
+  background: linear-gradient(135deg, #F56C6C 0%, #f44336 100%);
+}
+
+.peak-inline-body {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  gap: 20px;
 }
 
-/deep/ .el-table .total-column td {
-  background-color: #f0f9ff !important;
+.peak-inline-info {
+  display: flex;
+  align-items: baseline;
+  gap: 5px;
+}
+
+.peak-label {
+  font-size: 12px;
+  color: #909399;
+}
+
+.peak-value {
+  font-size: 16px;
   font-weight: bold;
+  color: #303133;
+}
+
+.peak-unit {
+  font-size: 11px;
+  color: #909399;
+}
+
+.peak-percentage {
+  margin-left: auto;
+  font-size: 12px;
+  color: #909399;
+  padding: 2px 8px;
+  background-color: #f4f4f5;
+  border-radius: 12px;
+  white-space: nowrap;
+}
+
+/* 汇总卡片样式 - 已删除 */
+
+/* 峰谷电卡片样式 - 已删除旧样式 */
+
+/* 响应式布局 */
+@media (max-width: 1680px) {
+  .inline-value {
+    font-size: 20px;
+  }
+
+  .peak-value {
+    font-size: 14px;
+  }
+}
+
+@media (max-width: 1366px) {
+  .peak-valley-row .peak-inline-card {
+    flex: 1 1 calc(50% - 6px);
+  }
+
+  .inline-value {
+    font-size: 18px;
+  }
+
+  .peak-inline-body {
+    gap: 15px;
+  }
+}
+
+@media (max-width: 768px) {
+  .summary-row {
+    flex-direction: column;
+  }
+
+  .peak-valley-row .peak-inline-card {
+    flex: 1 1 100%;
+  }
+
+  .peak-inline-body {
+    gap: 10px;
+  }
+}
+
+@media (max-width: 480px) {
+  .inline-card-content {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 10px;
+  }
+
+  .peak-inline-content {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 10px;
+  }
+
+  .peak-inline-body {
+    width: 100%;
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 5px;
+  }
+
+  .peak-percentage {
+    margin-left: 0;
+    margin-top: 5px;
+  }
 }
 
-/* 确保样式在若依主题下生效 */
-.app-container /deep/ .el-table .total-column {
-  background-color: #f0f9ff !important;
+/* 过渡动画 */
+.el-card {
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
 }
 
-.app-container /deep/ .el-table .total-column .cell {
-  font-weight: bold !important;
+/* 加载动画优化 */
+.el-loading-mask {
+  background-color: rgba(255, 255, 255, 0.9);
 }
+</style>