learshaw 1 сар өмнө
parent
commit
c91f8130c0

+ 262 - 320
ems-ui-cloud/src/views/analysis/report/statement-consume.vue

@@ -1,117 +1,87 @@
 <template>
   <div class="app-container">
+    <el-tabs v-model="activeName" @tab-click="tabClick">
+      <el-tab-pane label="区域用能" name="areaConsume">
+      </el-tab-pane>
+      <el-tab-pane label="设施用能" name="facsConsume">
+      </el-tab-pane>
+    </el-tabs>
     <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" />
+                    style="margin-bottom: 20px"
+          />
         </div>
         <div class="head-container" style="height: 100vh; overflow: hidden; position: relative;">
-          <el-tree :data="areaOptions" :props="defaultProps" :expand-on-click-node="false"
+          <el-tree :data="objOptions" :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;" />
+                   @node-click="handleNodeClick" style="height: calc(100vh - 50px); overflow-y: auto;"
+          />
         </div>
       </el-col>
       <el-col :span="20" :xs="24">
-        <el-tabs v-model="queryParams.objType" @tab-click="objTypeChange">
-          <el-tab-pane label="区域用能" name="1">
-            <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
-              <!-- 开始时间选择器 -->
-              <el-form-item label="开始时间" prop="startRecTime">
-                <el-date-picker
-                    v-model="queryParams.startRecTime"
-                    type="datetime"
-                    value-format="yyyy-MM-dd HH:00:00"
-                    :picker-options="startPickerOptions"
-                    placeholder="请选择开始时间"
-                    @change="handleTimeChange('startRecTime')">
-                </el-date-picker>
-              </el-form-item>
+        <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="68px">
+          <!-- 开始时间选择器 -->
+          <el-form-item label="开始时间" prop="startRecTime">
+            <el-date-picker
+                v-model="queryParams.startRecTime"
+                type="datetime"
+                value-format="yyyy-MM-dd HH:00:00"
+                :picker-options="startPickerOptions"
+                placeholder="请选择开始时间"
+                @change="handleTimeChange('startRecTime')"
+            >
+            </el-date-picker>
+          </el-form-item>
 
-              <!-- 结束时间选择器 -->
-              <el-form-item label="结束时间" prop="endRecTime">
-                <el-date-picker
-                    v-model="queryParams.endRecTime"
-                    type="datetime"
-                    value-format="yyyy-MM-dd HH:00:00"
-                    :picker-options="endPickerOptions"
-                    placeholder="请选择结束时间"
-                    @change="handleTimeChange('endRecTime')">
-                </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" v-hasPermi="['ems:EmsEcoD:export']" @click="handleExport">导出</el-button>
-              </el-form-item>
-            </el-form>
-          </el-tab-pane>
-          <el-tab-pane label="设施用能" name="2">
-            <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
-              <el-form-item label="选择对象" prop="objCode">
-                <treeselect
-                    v-model="queryParams.objCode"
-                    :options="objOptions"
-                    :show-count="true"
-                    placeholder="请选择对象"
-                    class="fixed-width-treeselect"
-                />
-              </el-form-item>
-              <!-- 开始时间选择器 -->
-              <el-form-item label="开始时间" prop="startRecTime">
-                <el-date-picker
-                    v-model="queryParams.startRecTime"
-                    type="datetime"
-                    value-format="yyyy-MM-dd HH:00:00"
-                    :picker-options="startPickerOptions"
-                    placeholder="请选择开始时间"
-                    @change="handleTimeChange('startRecTime')">
-                </el-date-picker>
-              </el-form-item>
+          <!-- 结束时间选择器 -->
+          <el-form-item label="结束时间" prop="endRecTime">
+            <el-date-picker
+                v-model="queryParams.endRecTime"
+                type="datetime"
+                value-format="yyyy-MM-dd HH:00:00"
+                :picker-options="endPickerOptions"
+                placeholder="请选择结束时间"
+                @change="handleTimeChange('endRecTime')"
+            >
+            </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" v-hasPermi="['ems:EmsEcoD:export']"
+                       @click="handleExport"
+            >导出
+            </el-button>
+          </el-form-item>
 
-              <!-- 结束时间选择器 -->
-              <el-form-item label="结束时间" prop="endRecTime">
-                <el-date-picker
-                    v-model="queryParams.endRecTime"
-                    type="datetime"
-                    value-format="yyyy-MM-dd HH:00:00"
-                    :picker-options="endPickerOptions"
-                    placeholder="请选择结束时间"
-                    @change="handleTimeChange('endRecTime')">
-                </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" v-hasPermi="['ems:EmsEcoD:export']" @click="handleExport">导出</el-button>
-              </el-form-item>
-            </el-form>
-          </el-tab-pane>
-        </el-tabs>
+          <el-table v-loading="loading" :data="consumeList">
+            <el-table-column label="对象名称" align="center" prop="objName"/>
+            <el-table-column label="日期" align="center" prop="date" width="180">
+              <template slot-scope="scope">
+                <span>{{ parseTime(scope.row.date, '{y}-{m}-{d}') }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="时间" align="center" prop="time">
+              <template slot-scope="scope">
+                <span>{{ scope.row.time }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="用电量(kW·h)" align="center" prop="elecQuantity"/>
+            <el-table-column label="用电花费(元)" align="center" prop="useElecCost"/>
+          </el-table>
 
-        <el-table v-loading="loading" :data="forecastConsumeList" @selection-change="handleSelectionChange">
-          <el-table-column label="对象名称" align="center" prop="deviceName" />
-          <el-table-column label="日期" align="center" prop="date" width="180">
-            <template slot-scope="scope">
-              <span>{{ parseTime(scope.row.date, '{y}-{m}-{d}') }}</span>
-            </template>
-          </el-table-column>
-          <el-table-column label="时间" align="center" prop="time">
-            <template slot-scope="scope">
-              <span>{{ scope.row.time }}</span>
-            </template>
-          </el-table-column>
-          <el-table-column label="用电量(kW·h)" align="center" prop="elecQuantity" />
-          <el-table-column label="用电花费(元)" align="center" prop="useElecCost" />
-        </el-table>
-
-        <pagination
+          <pagination
             v-show="total>0"
             :total="total"
             :page.sync="queryParams.pageNum"
             :limit.sync="queryParams.pageSize"
-            @pagination="getList"
-        />
+            @pagination="getAreaConsumeList"
+          />
+
+        </el-form>
+
       </el-col>
     </el-row>
   </div>
@@ -119,230 +89,223 @@
 
 <script>
 
-import { listFacsMeter, listAreaMeter } from '@/api/device/elecMeterH';
-import { areaTreeByFacsCategory, areaTreeSelect } from '@/api/basecfg/area'
 import { getFacsCategoryTree } from '@/api/basecfg/emsfacs'
+import { areaTreeSelect } from '@/api/basecfg/area'
 import Treeselect from '@riophae/vue-treeselect'
 import '@riophae/vue-treeselect/dist/vue-treeselect.css'
+import { listAreaMeter } from '@/api/device/elecMeterH'
+
 
 export default {
-  name: 'ForecastConsume',
+  name: 'consume',
   components: { Treeselect },
   data() {
     return {
       // 遮罩层
       loading: true,
-      // 选中数组
-      ids: [],
-      // 非单个禁用
-      single: true,
-      // 非多个禁用
-      multiple: true,
-      // 显示搜索条件
-      showSearch: true,
-      // 总条数
-      total: 0,
-      // 电力消耗预测表格数据
-      forecastConsumeList: [],
-      // 弹出层标题
-      title: '',
-      // 是否显示弹出层
-      open: false,
+      activeName: 'areaConsume',
       // 表单参数
       areaOptions: [],
       objOptions: [],
       areaName: undefined,
-      facsCategory: 'Z',
-      facsSubCategory: '',
-      // 设施选项
-      facsOptions: undefined,
       defaultProps: {
-        children: "children",
-        label: "label"
-      },
-      dictObjType: [
-        { value: '1', label: '区域' },
-        { value: '2', label: '设施' }
-      ],
-      treeProps: {
-        label: 'name',
-        value: 'code',
-        children: 'children'
+        children: 'children',
+        label: 'label'
       },
+      // 总条数
+      total: 0,
+      consumeList: [],
       // 查询参数
       queryParams: {
         pageNum: 1,
         pageSize: 10,
         areaCode: -1,
+        objType: '1',
         objCode: null,
-        objType: '1', // 修正:初始值应该是字符串类型
         facsCategory: 'Z',
+        facsSubCategory: '',
         startRecTime: null,
-        endRecTime: null,
-        elecUseQuantity: null,
-      },
-      // 表单参数
-      form: {
-        id: null,
-        areaCode: null,
-        objCode: null,
-        objType: null,
-        date: null,
-        elecUseQuantity: null,
-      },
-      // 表单校验
-      rules: {
-        areaCode: [
-          {
-            required: true,
-            message: '园区代码不能为空',
-            trigger: 'blur',
-          },
-        ],
-        objCode: [
-          {
-            required: true,
-            message: '对象代码不能为空',
-            trigger: 'blur',
-          },
-        ],
-        objType: [
-          {
-            required: true,
-            message: '对象类型不能为空',
-            trigger: 'change',
-          },
-        ],
+        endRecTime: null
       },
       // 时间选择器配置
       startPickerOptions: {
-        disabledDate(time) {
-          return time.getTime() > Date.now();
-        }
+        disabledDate: (time) => {
+          return time.getTime() > Date.now() - 8.64e7 // 禁用未来时间
+        },
+        selectableRange: this.generateHourRanges()
       },
       endPickerOptions: {
-        disabledDate(time) {
-          return time.getTime() < this.queryParams.startRecTime || time.getTime() > Date.now();
-        }
-      },
-    };
+        disabledDate: (time) => {
+          if (this.queryParams.startRecTime) {
+            return time.getTime() < new Date(this.queryParams.startRecTime).getTime() ||
+                time.getTime() > Date.now() - 8.64e7
+          }
+          return time.getTime() > Date.now() - 8.64e7
+        },
+        selectableRange: this.generateHourRanges()
+      }
+    }
   },
   created() {
-    this.getAreaList();
-    this.loadAreaData();
-    // 根据初始objType决定执行哪个查询
-    this.initQuery();
-  },
-  watch: {
-    'queryParams.objType': {
-      handler(newVal) {
-        // 标签页切换时执行对应查询
-        this.executeQueryByObjType(newVal);
-      },
-      immediate: true // 立即执行一次handler,处理初始化时的objType
-    }
+    this.getAreaList()
+    this.getConsumeList()
   },
+  watch: {},
   methods: {
-    // 加载设施数据
-    loadFacilityData() {
-      getFacsCategoryTree(0, "Z").then(response => {
-        // 获取原始数据
-        const originalData = response.data;
-
-        // 根据 areaCode 进行过滤
-        if (this.queryParams.areaCode === '-1') {
-          // areaCode=-1 时,展示全部数据
-          this.objOptions = originalData;
-        } else {
-          // 否则,只展示匹配 areaCode 的数据
-          const filteredData = originalData.filter(item =>
-              item.id === this.queryParams.areaCode
-          );
-          // 如果找到匹配项,则使用过滤后的数据;否则使用空数组
-          this.objOptions = filteredData.length > 0 ? filteredData : [];
-        }
-      }).catch(error => {
-        console.error('加载设施数据失败:', error);
-        this.$message.error('加载设施数据失败');
-      });
-    },
-    /** 初始化查询 */
-    initQuery() {
-      this.executeQueryByObjType(this.queryParams.objType);
-    },
-
-    /** 根据对象类型执行对应查询 */
-    executeQueryByObjType(objType) {
-      this.loading = true;
-      switch (objType) {
-        case '1': // 区域用能
-          listAreaMeter(this.queryParams).then(response => {
-            this.forecastConsumeList = response.rows;
-            this.total = response.total;
-            this.loading = false;
-          }).catch(error => {
-            console.error('区域用能查询失败:', error);
-            this.loading = false;
-            this.$message.error('区域用能查询失败');
-          });
-          break;
-        case '2': // 设施用能
-          listFacsMeter(this.queryParams).then(response => {
-            this.forecastConsumeList = response.rows;
-            this.total = response.total;
-            this.loading = false;
-          }).catch(error => {
-            console.error('设施用能查询失败:', error);
-            this.loading = false;
-            this.$message.error('设施用能查询失败');
-          });
-          break;
-        default:
-          this.loading = false;
-          this.$message.warning('未知的对象类型');
+    tabClick() {
+      this.clear()
+      if (this.activeName === 'areaConsume') {
+        this.queryParams.objType = 1
+        this.getAreaList()
+        this.getConsumeList() // 初始化区域用能数据
+      } else if (this.activeName === 'facsConsume') {
+        this.queryParams.objType = 2
+        this.getFacsList()
+        this.getConsumeList() // 初始化设施用能数据
       }
     },
 
-    /** 原getList方法修改为根据objType执行查询 */
-    getList() {
-      this.executeQueryByObjType(this.queryParams.objType);
+    // 表单重置
+    clear() {
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        areaCode: -1,
+        objCode: null,
+        facsCategory: 'Z',
+        facsSubCategory: '',
+        startRecTime: null,
+        endRecTime: null
+      }
+      this.consumeList = []
     },
-    // 查询区域列表
-    async getAreaList () {
-      try {
-        const response = await areaTreeByFacsCategory(this.facsCategory, this.facsSubCategory, false);
-        this.areaOptions = [{
+    /** 查询能源区域树列表 */
+    getAreaList() {
+      areaTreeSelect(0, 3).then(response => {
+        this.objOptions = [{
           id: '-1',
           label: '全部',
           children: []
-        }].concat(response.data);
-        this.selectedLabel = '全部';
-        this.queryParams.areaCode = '-1';
-      } catch (error) {
-        console.error('获取区域列表失败:', error);
-        this.$message.error('获取区域列表失败');
-      }
+        }].concat(response.data)
+      })
+    },
+    /** 查询能源设施树列表 */
+    getFacsList() {
+      getFacsCategoryTree().then(response => {
+        this.objOptions = this.flattenTreeData(response.data)
+      })
+    },
+    // 核心处理函数:压缩层级并扁平化树形结构
+    flattenTreeData(regions) {
+      if (!Array.isArray(regions)) return []
+
+      return regions.map(region => {
+        // 防御性处理children
+        const children = region.children || []
+        if (!Array.isArray(children)) return null
+
+        // 查找Z用能设施节点
+        const zFacility = children.find(child => child.id === 'Z')
+
+        // 仅当存在Z节点时处理该区域
+        if (zFacility) {
+          return {
+            ...region,
+            // 直接使用Z节点的子节点作为区域的子节点
+            children: (zFacility.children || []).map(child => ({ ...child }))
+          }
+        }
+        return null
+      }).filter(Boolean)
     },
-    objTypeChange() {
-      switch (this.queryParams.objType) {
-        case '1': // 区域
-          break;
-        case '2': // 设施
-          this.loadFacilityData();
-          break;
+    getConsumeList() {
+      if (this.activeName === 'areaConsume') {
+        this.getAreaConsumeList();
+      } else if (this.activeName === 'facsConsume') {
+        this.getFacsConsumeList(); // 调用设施用能数据获取方法
       }
     },
-    // 生成整点时间范围
-    generateHourRanges() {
-      const ranges = []
-      for (let i = 0; i < 24; i++) {
-        const start = `${i.toString().padStart(2, '0')}:00:00`
-        const end = `${i.toString().padStart(2, '0')}:59:59`
-        ranges.push(`${start} - ${end}`)
+    getAreaConsumeList() {
+      this.loading = true
+      listAreaMeter(this.queryParams).then(response => {
+        this.consumeList = response.rows
+        this.total = response.total
+        this.loading = false
+      })
+    },
+    // 新增:获取设施用能数据
+    getFacsConsumeList() {
+      this.loading = true
+      // 假设这里有对应的API
+      listFacsMeter(this.queryParams).then(response => {
+        this.consumeList = response.rows
+        this.total = response.total
+        this.loading = false
+      })
+    },
+
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1
+      this.getConsumeList()
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm('queryForm')
+      this.handleQuery()
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('ems/prod/pv/hour/export', {
+        ...this.queryParams
+      }, `用能报表_${new Date().getTime()}.xlsx`)
+    },
+    // 筛选节点
+    filterNode(value, data) {
+      if (!value) return true
+      return data.label.indexOf(value) !== -1
+    },
+    // 节点点击事件处理
+    handleNodeClick(data, node) {
+      console.log('##data:', data)
+      console.log('##node:', node)
+
+      if (this.activeName === 'areaConsume') {
+        this.queryParams.areaCode = data.id
+        this.getAreaConsumeList()
+
+      } else if (this.activeName === 'facsConsume') {
+        // 检查是否为叶子节点(通过ID判断或通过children长度判断)
+        if (this.isLeafNode(node)) {
+          // 获取顶级区域ID
+          const topLevelId = this.getTopLevelId(node)
+
+          // 设置查询参数
+          this.queryParams.areaCode = topLevelId
+          this.queryParams.facsSubCategory = data.id
+          this.queryParams.pageNum = 1 // 重置为第一页
+
+          // 获取设施用能数据
+          this.getFacsConsumeList()
+        } else {
+          console.log('父节点不可点击,请选择具体设施')
+        }
       }
-      return ranges
     },
+    isLeafNode(node) {
+      // 方式1:通过children长度判断
+      return node.parent.data.id !== undefined
+    },
+    // 追溯顶级节点ID的辅助函数
+    getTopLevelId(node) {
+      let id = node.parent.data.id
 
+      if (id === undefined || id === null) {
+        id = node.data.id
+      }
+
+      return id
+    },
     // 时间选择处理
     handleTimeChange(field) {
       if (this.queryParams[field]) {
@@ -350,7 +313,7 @@ export default {
         // 手动格式化日期(替代moment.js)
         const formatDate = (d) => {
           const pad = (n) => String(n).padStart(2, '0')
-          return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())} ${pad(d.getHours())}:00:00`
+          return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:00:00`
         }
         this.queryParams[field] = formatDate(date)
       }
@@ -362,51 +325,30 @@ export default {
         })
       }
     },
+    // 生成整点时间范围
+    generateHourRanges() {
+      const ranges = []
+      for (let i = 0; i < 24; i++) {
+        const start = `${i.toString().padStart(2, '0')}:00:00`
+        const end = `${i.toString().padStart(2, '0')}:59:59`
+        ranges.push(`${start} - ${end}`)
+      }
+      return ranges
+    }
+  }
+}
+</script>
+<style scoped>
 
 
-    // 取消按钮
-    cancel() {
-      this.open = false;
-      this.reset();
-    },
-    // 表单重置
-    reset() {
-      this.form = {
-        id: null,
-        areaCode: null,
-        objCode: null,
-        objType: null,
-        date: null,
-        elecUseQuantity: null,
-      };
-      this.resetForm('form');
-    },
-    /** 搜索按钮操作 */
-    handleQuery() {
-      this.queryParams.pageNum = 1;
-      this.getList();
-    },
-    /** 重置按钮操作 */
-    resetQuery() {
-      this.resetForm('queryForm');
-      this.handleQuery();
-    },
-    // 多选框选中数据
-    handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.id);
-      this.single = selection.length !== 1;
-      this.multiple = !selection.length;
-    },
-    // 筛选节点
-    filterNode (value, data) {
-      if (!value) return true
-      return data.label.indexOf(value) !== -1
-    },
-    // 节点单击事件
-    handleNodeClick (data) {
-      this.queryParams.areaCode = data.id
-      this.getList()
-    },
-  },
-};
-</script>
+/* 自定义样式:父节点文字变灰,提示不可点击 */
+.el-tree .el-tree-node.is-leaf > .el-tree-node__content {
+  color: #333;
+  cursor: pointer;
+}
+
+.el-tree .el-tree-node:not(.is-leaf) > .el-tree-node__content {
+  color: #909399;
+  cursor: not-allowed;
+}
+</style>

+ 1 - 1
ems-ui-cloud/src/views/analysis/report/statement-prod.vue

@@ -44,7 +44,7 @@
           </el-form-item>
         </el-form>
 
-        <el-table v-loading="loading" :data="pvSupplyHList" @selection-change="handleSelectionChange">
+        <el-table v-loading="loading" :data="pvSupplyHList">
           <el-table-column label="日期" align="center" prop="date" width="180">
             <template slot-scope="scope">
               <span>{{ parseTime(scope.row.date, '{y}-{m}-{d}') }}</span>

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

@@ -315,11 +315,11 @@ import { areaTreeSelect, listDetailArea } from '@/api/basecfg/area'
 import SubTitle from '@/components/SubTitle/index.vue'
 import { getDevProcess, getEmsTag } from '@/api/commonApi'
 import { listDevice } from '@/api/device/meterDevice'
-import { addAllByObj, listByObj ,getBoundaryTreeByArea } from '@/api/basecfg/meterBoundary'
+import { addAllByObj, listByObj, getBoundaryTreeByArea } from '@/api/basecfg/meterBoundary'
 import { listDept } from '@/api/system/dept'
 import { getFacsCategoryTree, listAllFacs } from '@/api/basecfg/emsfacs'
 import { listSubsystemAll } from '@/api/adapter/subsystem'
-import {getTreeByFacs} from '@/api/device/device.js'
+import { getTreeByFacs } from '@/api/device/device.js'
 
 
 export default {

+ 1 - 1
ems-ui-cloud/src/views/basecfg/meterdevc/index.vue

@@ -283,7 +283,7 @@ export default {
         meterCls = 70;
       }
       const params = {
-        locationRef: this.$refs.tree.getCurrentNode()?.id,
+        locationRef: this.queryParams.locationRef,
         meterCls,
         objTag: this.queryParams.objTag,
         colMode: this.queryParams.colMode,