浏览代码

计费提交

luogang 11 月之前
父节点
当前提交
2ad3e9128d
共有 2 个文件被更改,包括 556 次插入86 次删除
  1. 18 0
      ems-ui/src/api/mgr/charging.js
  2. 538 86
      ems-ui/src/views/mgr/charging.vue

+ 18 - 0
ems-ui/src/api/mgr/charging.js

@@ -0,0 +1,18 @@
+import request from '@/utils/request'
+
+// 查询商户计费数据
+export function chargingList(query) {
+  return request({
+    url: '/ems/charging/bill/co',
+    method: 'get',
+    params: query
+  })
+}
+// 查询计费总览数据
+export function overviewInfo(query) {
+  return request({
+    url: '/ems/charging/bill/getByTag',
+    method: 'get',
+    params: query
+  })
+}

+ 538 - 86
ems-ui/src/views/mgr/charging.vue

@@ -4,20 +4,114 @@
       <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">
-          <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" />
+          <el-tree ref="tree" :data="areaOptions" :props="defaultProps" :expand-on-click-node="false" :filter-node-method="filterNode"
+            node-key="id" :default-expanded-keys="this.defalutArr" highlight-current @node-click="handleNodeClick" />
         </div>
       </el-col>
       <el-col :span="20" :xs="24">
         <el-tabs v-model="activeTab" @tab-click="handleTabChange">
           <el-tab-pane label="总览" name="first">
+            <div class="custom-form">
+              <el-select v-model="queryParams.meterCls" size="mini" @change="meterClsChange">
+                <el-option v-for="item in emsClsOptions" :key="item.code" :label="item.name" :value="item.code"></el-option>
+              </el-select>
+            </div>
+            <div class="panel">
+              <div class="panel-title">当月数据</div>
+              <div class="panel-body">
+                <BaseChart width="100%" height="300px" :option="pieOptions" />
+              </div>
+            </div>
+            <div class="panel">
+              <div class="panel-title">历史数据</div>
+              <div class="panel-body">
+                <div class="custom-form">
+                  <el-date-picker v-model="queryParams.historyRange" size="mini" type="monthrange" align="right" :clearable="false"
+                    range-separator="至" start-placeholder="开始月份" end-placeholder="结束月份" value-format="yyyyMM"
+                    :picker-options="pickerOptions" @change="getList">
+                  </el-date-picker>
+                </div>
+                <el-table :data="historyData" style="width: 100%;margin-bottom:20px" max-height="300px">
+                  <el-table-column prop="meteredTime" align="center" label="账单月份">
+                  </el-table-column>
+                  <el-table-column prop="meteredValue" align="center" label="用量">
+                  </el-table-column>
+                  <el-table-column prop="meteredPrice" align="center" label="金额">
+                  </el-table-column>
+                  <el-table-column prop="sharedValue" align="center" label="公摊用量">
+                  </el-table-column>
+                  <el-table-column prop="sharedPrice" align="center" label="公摊金额">
+                  </el-table-column>
+                  <el-table-column prop="totalValue" align="center" label="总用量">
+                  </el-table-column>
+                  <el-table-column prop="totalPrice" align="center" label="总金额">
+                  </el-table-column>
+                </el-table>
+                <BaseChart width="100%" height="300px" :option="overviewOptions" />
+              </div>
+            </div>
 
           </el-tab-pane>
           <el-tab-pane label="个户" name="second">
-
+            <div class="custom-form">
+              <el-select v-model="queryParams.meterCls" size="mini" @change="meterClsChange">
+                <el-option v-for="item in emsClsOptions" :key="item.code" :label="item.name" :value="item.code"></el-option>
+              </el-select>
+            </div>
+            <div class="panel">
+              <div class="panel-title">当月数据</div>
+              <div class="panel-body">
+                <el-table :data="currentData" style="width: 100%">
+                  <el-table-column prop="meteredTime" align="center" label="账单月份">
+                  </el-table-column>
+                  <el-table-column prop="meteredValue" align="center" label="用量">
+                  </el-table-column>
+                  <el-table-column prop="meteredPrice" align="center" label="金额">
+                  </el-table-column>
+                  <el-table-column prop="sharedPrice" align="center" label="公摊价格">
+                  </el-table-column>
+                  <el-table-column prop="sharedComputeType" align="center" label="公摊类型">
+                    <template slot-scope="scope">
+                      {{formatDict(scope.row.sharedComputeType,'computeTypeOptions')}}
+                    </template>
+                  </el-table-column>
+                  <el-table-column prop="totalPrice" align="center" label="总金额">
+                  </el-table-column>
+                </el-table>
+              </div>
+            </div>
+            <div class="panel">
+              <div class="panel-title">历史数据</div>
+              <div class="panel-body">
+                <div class="custom-form">
+                  <el-date-picker v-model="queryParams.historyRange" size="mini" type="monthrange" align="right" :clearable="false"
+                    range-separator="至" start-placeholder="开始月份" end-placeholder="结束月份" value-format="yyyyMM"
+                    :picker-options="pickerOptions" @change="getList">
+                  </el-date-picker>
+                </div>
+                <el-table :data="historyData" style="width: 100%;margin-bottom:20px" max-height="300px">
+                  <el-table-column prop="meteredTime" align="center" label="账单月份">
+                  </el-table-column>
+                  <el-table-column prop="meteredValue" align="center" label="用量">
+                  </el-table-column>
+                  <el-table-column prop="meteredPrice" align="center" label="金额">
+                  </el-table-column>
+                  <!-- <el-table-column prop="sharedPrice" align="center" label="公摊价格">
+                  </el-table-column>
+                  <el-table-column prop="sharedComputeType" align="center" label="公摊类型">
+                    <template slot-scope="scope">
+                      {{formatDict(scope.row.sharedComputeType,'computeTypeOptions')}}
+                    </template>
+                  </el-table-column> -->
+                  <el-table-column prop="totalPrice" align="center" label="总价">
+                  </el-table-column>
+                </el-table>
+                <BaseChart width="100%" height="300px" :option="elecOptions" />
+              </div>
+            </div>
           </el-tab-pane>
 
         </el-tabs>
@@ -30,35 +124,24 @@
 import { areaTreeSelect, areaTreeSelectByTag } from '@/api/basecfg/area'
 import Treeselect from '@riophae/vue-treeselect'
 import '@riophae/vue-treeselect/dist/vue-treeselect.css'
-
-
+import { chargingList, overviewInfo } from '@/api/mgr/charging.js'
+import { dateFormat } from '@/utils/index.js'
+import BaseChart from '@/components/BaseChart'
 export default {
   name: 'Device',
-  components: { Treeselect },
+  components: { Treeselect, BaseChart },
   data() {
     const nowDay = new Date()
+    const lastMonth = new Date(nowDay.getFullYear(), nowDay.getMonth() - 1)
     return {
       activeTab: 'first',
-      // 遮罩层
-      loading: true,
       // 总条数
-      total: 0,
-      // 计量设备表格数据
-      deviceList: [],
-      // 弹出层标题
-      title: '',
-      // 记录表单开启
-      recListOpen: false,
-      // 填报表单开启
-      fillFormOpen: false,
-      // 区域名称
       areaName: undefined,
       areaOptions: [],
       defaultProps: {
         children: 'children',
         label: 'label'
       },
-      // 能源分类树
       emsClsOptions: [
         { code: 45, name: '电表' },
         { code: 70, name: '水表' }
@@ -68,62 +151,420 @@ export default {
         pageNum: 1,
         pageSize: 10,
         areaCode: null,
-        deviceCode: null,
-        meterCls: 45
-      },
-      // 电表表单参数
-      recListForm: {
-        year: '',
-        deviceCode: '',
-        recList: []
+        meterCls: 45,
+        historyRange: []
       },
+      lastMonth: dateFormat(lastMonth, 'yyyyMM'),
+      currentData: [],
+      historyData: [],
+      defalutArr: [],
+      computeTypeOptions: [
+        { name: '不计入', code: 0 },
+        { name: '个户平摊', code: 1 },
+        { name: '面积公摊)', code: 2 }
+      ],
+      pickerOptions: {
+        disabledDate(time) {
+          const t = new Date().getDate()
+          return time.getTime() > Date.now() - 8.64e7 * t
+        }
+      }
     }
   },
   created() {
-    this.handleTabChange();
-    this.getList()
+    this.setDefaultMonthRange()
+    this.handleTabChange()
   },
-  methods: {
-    getList() {
+  computed: {
+    pieOptions() {
+      let options = {}
+      if (this.activeTab == 'first') {
+        const { meterCls } = this.queryParams
+        let pieData = []
+        let total = ''
+        if (this.currentData.length) {
+          const { meteredValue, sharedValue, totalValue, meteredPrice, sharedPrice, totalPrice } = this.currentData[0]
+          total = totalValue
+          pieData = [
+            {
+              value: meteredValue,
+              price: meteredPrice,
+              name: meterCls === 45 ? '电表用量' : '水表用量',
+              totalValue,
+              totalPrice,
+              itemStyle: {
+                color: '#8d7fec'
+              }
+            },
+            {
+              value: sharedValue,
+              price: sharedPrice,
+              name: '公摊用量',
+              totalValue,
+              totalPrice,
+              itemStyle: {
+                color: '#6BD9BC'
+              }
+            }
+          ]
+        }
+        options = {
+          title: [
+            {
+              text: '总用量',
+              subtext: total + `${meterCls === 45 ? '度' : '吨'}`,
+              textStyle: {
+                fontSize: 15,
+                color: 'black'
+              },
+              subtextStyle: {
+                fontSize: 20,
+                color: 'black'
+              },
+              textAlign: 'center',
+              x: '34.5%',
+              y: '40%'
+            }
+          ],
+          tooltip: {
+            trigger: 'item',
+            formatter: function(parms) {
+              var str =
+                parms.data.name +
+                '</br>' +
+                '用量:' +
+                parms.data.value +
+                `${meterCls === 45 ? '度' : '吨'}` +
+                '</br>' +
+                '金额:' +
+                parms.data.price +
+                '元'
+              return str
+            }
+          },
+          legend: {
+            type: 'scroll',
+            orient: 'vertical',
+            left: '65%',
+            align: 'left',
+            top: 'middle',
+            textStyle: {
+              color: '#8C8C8C'
+            }
+          },
+          series: [
+            {
+              type: 'pie',
+              center: ['35%', '50%'],
+              radius: ['40%', '65%'],
+              clockwise: false, // 饼图的扇区是否是顺时针排布
+              avoidLabelOverlap: false,
+              itemStyle: {
+                // 图形样式
+                normal: {
+                  borderColor: '#ffffff',
+                  borderWidth: 1
+                }
+              },
+              label: {
+                formatter: function(val) {
+                  const unit = meterCls === 45 ? '度' : '吨'
+                  return '{a|' + val.name + '}{b|\n' + val.value + unit + '}{b|\n' + val.data.price + '元}'
+                },
+                textStyle: {
+                  rich: {
+                    a: {
+                      color: '#333333',
+                      fontSize: '12'
+                    },
+                    b: {
+                      color: '#0086FF',
+                      fontSize: '12',
+                      padding: [4, 0, 0, 0]
+                    }
+                  }
+                }
+              },
+              labelLine: {
+                length: 10,
+                length2: 50
+              },
+              labelLayout: {
+                verticalAlign: 'bottom',
+              },
+              data: pieData
+            }
+          ]
+        }
+      }
 
+      return options
     },
-    handleTabChange() {
-      // 根据newTabName给someParam赋值
+    overviewOptions() {
+      let option = {}
       if (this.activeTab === 'first') {
-        this.getAreaTree('Area')
-      } else if (this.activeTab === 'second') {
-        this.getAreaTreeByTag('Zoning', 'Area_01')
+        const xData = this.historyData.map(item => item.meteredTime)
+        const quantity = this.historyData.map(item => item.meteredValue)
+        const shareQuantity = this.historyData.map(item => item.sharedValue)
+        const cost = this.historyData.map(item => item.meteredPrice)
+        const shareCost = this.historyData.map(item => item.sharedPrice)
+        const { meterCls } = this.queryParams
+        option = {
+          tooltip: {
+            trigger: 'axis',
+            axisPointer: {
+              type: 'cross',
+              crossStyle: {
+                color: '#999'
+              }
+            }
+          },
+          grid: {
+            left: '5%'
+          },
+          legend: {
+            data: meterCls === 45 ? ['电表用量', '电表金额', '公摊用量', '公摊金额'] : ['水表用量', '水表金额', '公摊用量', '公摊金额']
+          },
+          xAxis: {
+            type: 'category',
+            data: xData,
+            axisPointer: {
+              type: 'shadow'
+            }
+          },
+          yAxis: [
+            {
+              name: meterCls === 45 ? 'kW-h(千瓦时)' : '吨',
+              type: 'value'
+            },
+            {
+              name: '¥(元)',
+              type: 'value'
+            }
+          ],
+          series: [
+            {
+              name: meterCls === 45 ? '电表用量' : '水表用量',
+              type: 'bar',
+              data: quantity,
+              barWidth: 30,
+              itemStyle: {
+                normal: {
+                  color: '#6395FA'
+                }
+              }
+            },
+            {
+              name: '公摊用量',
+              type: 'bar',
+              data: shareQuantity,
+              barWidth: 30,
+              itemStyle: {
+                normal: {
+                  color: '#8CDF6C'
+                }
+              }
+            },
+            {
+              name: meterCls === 45 ? '电表金额' : '水表金额',
+              type: 'line',
+              yAxisIndex: 1,
+              data: cost,
+              showSymbol: true,
+              itemStyle: {
+                normal: {
+                  color: '#5BD9A5'
+                }
+              }
+            },
+            {
+              name: '公摊金额',
+              type: 'line',
+              yAxisIndex: 1,
+              data: shareCost,
+              showSymbol: true,
+            }
+          ]
+        }
       }
-      this.handleQuery()
+
+      return option
     },
-    /** 搜索按钮操作 */
-    handleQuery() {
-      this.queryParams.pageNum = 1
+    elecOptions() {
+      const xData = this.historyData.map(item => item.meteredTime)
+      const quantity = this.historyData.map(item => item.meteredValue)
+      const cost = this.historyData.map(item => item.meteredPrice)
+      const { meterCls } = this.queryParams
+      const option = {
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: {
+            type: 'cross',
+            crossStyle: {
+              color: '#999'
+            }
+          }
+        },
+        grid: {
+          left: '5%'
+        },
+        legend: {
+          data: ['用量', '金额']
+        },
+        xAxis: {
+          type: 'category',
+          data: xData,
+          axisPointer: {
+            type: 'shadow'
+          }
+        },
+        yAxis: [
+          {
+            name: meterCls === 45 ? 'kW-h(千瓦时)' : '吨',
+            type: 'value'
+          },
+          {
+            name: '¥(元)',
+            type: 'value'
+          }
+        ],
+        series: [
+          {
+            name: '用量',
+            type: 'bar',
+            data: quantity,
+            barWidth: 30,
+            itemStyle: {
+              normal: {
+                color: '#6395FA'
+              }
+            }
+          },
+          {
+            name: '金额',
+            type: 'line',
+            yAxisIndex: 1,
+            data: cost,
+            showSymbol: true,
+            itemStyle: {
+              normal: {
+                color: '#5BD9A5'
+              }
+            }
+          }
+        ]
+      }
+      return option
+    }
+  },
+  methods: {
+    meterClsChange() {
+      this.getList('current')
       this.getList()
     },
-    /** 重置按钮操作 */
-    resetQuery() {
-      this.resetForm('queryForm')
-      this.handleQuery()
+    setDefaultMonthRange() {
+      const nowDay = new Date()
+      const lastMonth = new Date(nowDay.getFullYear(), nowDay.getMonth() - 1)
+      const months = this.getPreviousFiveMonthsYearMonth(lastMonth)
+      const { year, month } = months[months.length - 1]
+      const lastFiveMonth = month < 10 ? `0${month}` : month
+      this.queryParams.historyRange = [`${year}${lastFiveMonth}`, this.lastMonth]
     },
-
-
-    getObjTagName(objTag) {
-      const tagMap = {
-        0: '公摊表',
-        1: '个户表'
+    getPreviousFiveMonthsYearMonth(date) {
+      const months = [...Array(5).keys()].map(i => {
+        const year = date.getFullYear()
+        const month = date.getMonth() - i
+        if (month < 0) {
+          return {
+            year: year - 1,
+            month: 12 + month
+          }
+        }
+        return { year, month: month + 1 }
+      })
+      return months
+    },
+    formatDict(val, options, key = 'code', text = 'name') {
+      let name = null
+      this[options].forEach(item => {
+        if (item[key] === val) {
+          name = item[text]
+        }
+      })
+      return name
+    },
+    getList(type) {
+      let startTime = null
+      let endTime = null
+      const { areaCode, meterCls, historyRange } = this.queryParams
+      if (type === 'current') {
+        startTime = this.lastMonth
+        endTime = this.lastMonth
+      } else {
+        startTime = historyRange[0]
+        endTime = historyRange[1]
+      }
+      // 个户
+      if (this.activeTab === 'second') {
+        chargingList({
+          areaPath: areaCode,
+          tier: 'Zoning',
+          meterCls,
+          startTime,
+          endTime
+        }).then(({ data }) => {
+          if (type === 'current') {
+            this.currentData = data || []
+          } else {
+            this.historyData = data || []
+          }
+        })
+      } else {
+        overviewInfo({
+          areaPath: areaCode,
+          tier: 'Area',
+          meterCls,
+          startTime,
+          endTime
+        }).then(({ data }) => {
+          if (type === 'current') {
+            this.currentData = data || []
+          } else {
+            this.historyData = data || []
+          }
+        })
+      }
+    },
+    async handleTabChange() {
+      // 根据newTabName给someParam赋值
+      if (this.activeTab === 'first') {
+        await this.getAreaTree('Area')
+        this.queryParams.areaCode = this.areaOptions[0].id
+        this.$refs['tree'].setCurrentKey(this.queryParams.areaCode)
+      } else if (this.activeTab === 'second') {
+        await this.getAreaTreeByTag('Zoning', 'Area_01')
+        this.defalutArr = []
+        this.recursion(this.areaOptions[0], this.defalutArr)
+        this.queryParams.areaCode = this.defalutArr.join('/')
+        this.$refs['tree'].setCurrentKey(this.defalutArr[this.defalutArr.length - 1])
+      }
+      this.meterClsChange()
+    },
+    recursion(data, defalutArr) {
+      defalutArr.push(data.id)
+      if (data.children && data.children.length) {
+        this.recursion(data.children[0], defalutArr)
       }
-      return tagMap[objTag] || '未知'
     },
     /** 查询区域树结构 */
-    getAreaTree(tier) {
-      areaTreeSelect(tier).then(response => {
+    async getAreaTree(tier) {
+      await areaTreeSelect(tier).then(response => {
         this.areaOptions = response.data
       })
     },
     /** 查询区域树结构 */
-    getAreaTreeByTag(tier, tagCode) {
-      areaTreeSelectByTag(tier, tagCode).then(response => {
+    async getAreaTreeByTag(tier, tagCode) {
+      await areaTreeSelectByTag(tier, tagCode).then(response => {
         this.areaOptions = response.data
       })
     },
@@ -132,10 +573,25 @@ export default {
       if (!value) return true
       return data.label.indexOf(value) !== -1
     },
-    // 节点单击事件
-    handleNodeClick(data) {
-      this.queryParams.areaCode = data.id
-      this.handleQuery()
+    handleNodeClick(data, node) {
+      // 商户树形结构只能点击最后一级
+      if (this.activeTab === 'second' && node.level < 3) return this.$refs['tree'].setCurrentKey(null)
+      const nodeArr = []
+      //  获取点击当节点的dom的信息
+      const selectNode = this.$refs.tree.getNode(data)
+      // 调用递归函数
+      this.platform(selectNode, nodeArr)
+      this.queryParams.areaCode = nodeArr.map(item => item.id).join('/')
+      this.meterClsChange()
+    },
+    // 递归函数
+    platform(node, array) {
+      if (!node.parent) {
+        return
+      }
+      array.unshift(node.data)
+      // 调用递归
+      this.platform(node.parent, array)
     }
   }
 }
@@ -146,36 +602,32 @@ export default {
     overflow: initial;
   }
 }
-.sub-table {
-  .el-icon-delete {
-    cursor: pointer;
-  }
-  .operateBtns {
-    cursor: pointer;
-    i {
-      color: #1990ff;
-      margin-left: 5px;
+.custom-form {
+  padding-bottom: 10px;
+}
+.panel {
+  display: flex;
+  flex-direction: column;
+  .panel-title {
+    display: flex;
+    align-items: center;
+    font-size: 14px;
+    font-weight: 500;
+    &::before {
+      content: '';
+      display: inline-block;
+      height: 14px;
+      width: 3px;
+      border-radius: 6px;
+      background: #409eff;
+      margin-right: 5px;
     }
   }
-  ::v-deep .el-date-editor {
-    width: 100% !important;
-  }
-}
-.custom-checkbox-group {
-  max-height: 120px;
-  overflow-y: auto;
-}
-.strategyForm {
-  ::v-deep .el-input.is-disabled .el-input__inner {
-    color: #606266;
+  .panel-body {
+    flex: 1;
     background: #fff;
+    padding: 10px 0;
   }
 }
 </style>
-<style lang="scss">
-.custom-dialog {
-  .el-dialog__body {
-    padding-bottom: 0;
-  }
-}
 </style>