123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633 |
- <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" />
- </div>
- <div class="head-container">
- <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>
- </el-col>
- </el-row>
- </div>
- </template>
- <script>
- 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, BaseChart },
- data() {
- const nowDay = new Date()
- const lastMonth = new Date(nowDay.getFullYear(), nowDay.getMonth() - 1)
- return {
- activeTab: 'first',
- // 总条数
- areaName: undefined,
- areaOptions: [],
- defaultProps: {
- children: 'children',
- label: 'label'
- },
- emsClsOptions: [
- { code: 45, name: '电表' },
- { code: 70, name: '水表' }
- ],
- // 查询参数
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- areaCode: null,
- 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.setDefaultMonthRange()
- this.handleTabChange()
- },
- 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: '商户用量',
- 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
- },
- overviewOptions() {
- let option = {}
- if (this.activeTab === 'first') {
- 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:['商户用量', '商户金额', '公摊用量', '公摊金额']
- },
- 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: 'bar',
- data: shareQuantity,
- barWidth: 30,
- itemStyle: {
- normal: {
- color: '#8CDF6C'
- }
- }
- },
- {
- name: '商户金额',
- type: 'line',
- yAxisIndex: 1,
- data: cost,
- showSymbol: true,
- itemStyle: {
- normal: {
- color: '#5BD9A5'
- }
- }
- },
- {
- name: '公摊金额',
- type: 'line',
- yAxisIndex: 1,
- data: shareCost,
- showSymbol: true,
- }
- ]
- }
- }
- return option
- },
- 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()
- },
- 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]
- },
- 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)
- }
- },
- /** 查询区域树结构 */
- async getAreaTree(tier) {
- await areaTreeSelect(tier).then(response => {
- this.areaOptions = response.data
- })
- },
- /** 查询区域树结构 */
- async getAreaTreeByTag(tier, tagCode) {
- await areaTreeSelectByTag(tier, tagCode).then(response => {
- this.areaOptions = response.data
- })
- },
- // 筛选节点
- filterNode(value, data) {
- if (!value) return true
- return data.label.indexOf(value) !== -1
- },
- 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)
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .app-container {
- ::v-deep .el-tabs__content {
- overflow: initial;
- }
- }
- .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;
- }
- }
- .panel-body {
- flex: 1;
- background: #fff;
- padding: 10px 0;
- }
- }
- </style>
- </style>
|