<template>
|
|
<TableLayout :permissions="['business:ywconditionerreport:query']">
|
|
<el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
|
|
<el-form-item label="报表类型" prop="reportType">
|
<el-select v-model="searchForm.reportType" style="min-width: 140px" @change="onReportTypeChange">
|
<el-option label="日报表" value="day" />
|
<el-option label="月报表" value="month" />
|
</el-select>
|
</el-form-item>
|
<el-form-item v-if="searchForm.reportType === 'month'" label="月份" prop="month">
|
|
<el-date-picker
|
|
v-model="searchForm.month"
|
|
type="month"
|
|
value-format="yyyy-MM"
|
|
placeholder="选择月份"
|
|
style="width: 160px"
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item v-if="searchForm.reportType === 'day'" label="时间段" prop="dateRange">
|
|
<el-date-picker
|
|
v-model="searchForm.dateRange"
|
|
type="daterange"
|
|
value-format="yyyy-MM-dd"
|
|
range-separator="至"
|
|
start-placeholder="开始日期"
|
|
end-placeholder="结束日期"
|
|
:picker-options="datePickerOptions"
|
|
style="width: 280px"
|
|
@change="onDateRangeChange"
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item label="商户" prop="gsId">
|
|
<el-select v-model="searchForm.gsId" clearable filterable placeholder="全部" style="min-width: 200px">
|
|
<el-option v-for="item in merchantOptions" :key="item.gsId" :label="item.gsName" :value="item.gsId" />
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item label="设备信息" prop="devKeyword">
|
|
<el-input v-model="searchForm.devKeyword" placeholder="设备名称/ID" clearable @keypress.enter.native="search" />
|
|
</el-form-item>
|
|
<section>
|
|
<el-button type="primary" icon="el-icon-search" @click="search">查询</el-button>
|
|
<el-button icon="el-icon-refresh" @click="reset">重置</el-button>
|
|
</section>
|
|
</el-form>
|
|
<template v-slot:table-wrap>
|
|
<ul class="toolbar">
|
|
<li>
|
|
<el-button
|
|
type="primary"
|
|
:loading="isSyncing"
|
|
v-permissions="['business:ywconditionerreport:sync']"
|
|
@click="handleSyncUsage"
|
|
>同步用量</el-button>
|
|
</li>
|
|
<li>
|
|
<el-button
|
|
@click="handleExport"
|
|
:loading="isWorking.export"
|
|
v-permissions="['business:ywconditionerreport:exportExcel']"
|
|
>导出</el-button>
|
|
</li>
|
|
</ul>
|
|
<div class="report-scroll-wrap">
|
|
<el-table v-loading="isWorking.search" :data="tableData.list" stripe border size="small">
|
|
<el-table-column label="设备名称" min-width="160" fixed align="center" show-overflow-tooltip>
|
<template slot-scope="{ row }">{{ formatDevName(row) }}</template>
|
</el-table-column>
|
|
<el-table-column prop="devId" label="设备ID" width="90" fixed align="center" />
|
|
<el-table-column label="总时长(h)" min-width="100" align="center">
|
<template slot-scope="{ row }">{{ formatNum(row.totalTime) }}</template>
|
</el-table-column>
|
<el-table-column label="总电量(kWh)" min-width="110" align="center">
|
<template slot-scope="{ row }">{{ formatNum(row.totalDl) }}</template>
|
</el-table-column>
|
<el-table-column label="总电费(元)" min-width="100" align="center">
|
<template slot-scope="{ row }">{{ formatNum(row.totalDf) }}</template>
|
</el-table-column>
|
<el-table-column
|
v-for="col in dateColumns"
|
:key="col"
|
:label="col"
|
align="center"
|
>
|
<el-table-column label="电量(kWh)" min-width="88" align="center">
|
<template slot-scope="{ row }">{{ dailyVal(row, col, 'dl') }}</template>
|
</el-table-column>
|
<el-table-column label="时长(h)" min-width="80" align="center">
|
<template slot-scope="{ row }">{{ dailyVal(row, col, 'time') }}</template>
|
</el-table-column>
|
<el-table-column label="电费(元)" min-width="88" align="center">
|
<template slot-scope="{ row }">{{ dailyVal(row, col, 'df') }}</template>
|
</el-table-column>
|
</el-table-column>
|
|
</el-table>
|
|
</div>
|
|
<pagination
|
|
@size-change="handleSizeChange"
|
|
@current-change="handlePageChange"
|
|
:pagination="tableData.pagination"
|
|
/>
|
|
</template>
|
|
</TableLayout>
|
|
</template>
|
|
|
|
<script>
|
|
import BaseTable from '@/components/base/BaseTable'
|
|
import TableLayout from '@/layouts/TableLayout'
|
|
import Pagination from '@/components/common/Pagination'
|
|
import * as reportApi from '@/api/business/ywconditionerreport'
|
|
import dayjs from 'dayjs'
|
|
|
|
function lastMonthStr () {
|
|
return dayjs().subtract(1, 'month').format('YYYY-MM')
|
|
}
|
|
|
|
function defaultDayRange () {
|
|
const end = dayjs().subtract(1, 'day')
|
|
const start = end.subtract(6, 'day')
|
|
return [start.format('YYYY-MM-DD'), end.format('YYYY-MM-DD')]
|
|
}
|
|
|
|
export default {
|
|
name: 'YwConditionerReport',
|
|
extends: BaseTable,
|
|
components: { TableLayout, Pagination },
|
|
data () {
|
|
return {
|
|
searchForm: {
|
|
reportType: 'day',
|
|
month: lastMonthStr(),
|
|
dateRange: defaultDayRange(),
|
|
gsId: null,
|
|
devKeyword: ''
|
|
},
|
|
dateColumns: [],
|
|
merchantOptions: [],
|
|
isSyncing: false,
|
|
rangePickAnchor: null,
|
|
datePickerOptions: {
|
|
onPick: ({ minDate, maxDate }) => {
|
|
this.rangePickAnchor = maxDate ? null : minDate
|
|
},
|
|
disabledDate: (time) => {
|
|
if (!this.rangePickAnchor) return false
|
|
const anchor = dayjs(this.rangePickAnchor)
|
|
const t = dayjs(time)
|
|
return t.isBefore(anchor.subtract(30, 'day'), 'day') || t.isAfter(anchor.add(30, 'day'), 'day')
|
|
}
|
|
}
|
|
}
|
|
},
|
|
created () {
|
|
this.api = reportApi
|
|
this.module = '空调用量报表'
|
|
this.configData['field.id'] = 'devId'
|
|
this.configData['field.main'] = 'devName'
|
|
this.loadMerchants()
|
|
this.search()
|
|
},
|
|
methods: {
|
|
loadMerchants () {
|
|
reportApi.merchantOptions()
|
|
.then(list => { this.merchantOptions = list || [] })
|
|
.catch(() => {})
|
|
},
|
|
onReportTypeChange (val) {
|
if (val === 'month') {
|
if (!this.searchForm.month) {
|
this.searchForm.month = lastMonthStr()
|
}
|
} else if (val === 'day') {
|
|
if (!this.searchForm.dateRange || this.searchForm.dateRange.length !== 2) {
|
|
this.searchForm.dateRange = defaultDayRange()
|
|
}
|
|
}
|
|
},
|
|
onDateRangeChange (val) {
|
|
this.rangePickAnchor = null
|
|
if (!val || val.length !== 2) return
|
|
const days = dayjs(val[1]).diff(dayjs(val[0]), 'day') + 1
|
|
if (days > 31) {
|
|
this.$tip.error('时间段最多不超过31天')
|
|
this.searchForm.dateRange = [
|
|
dayjs(val[1]).subtract(30, 'day').format('YYYY-MM-DD'),
|
|
val[1]
|
|
]
|
|
}
|
|
},
|
|
validateDayRange () {
|
|
if (this.searchForm.reportType !== 'day') return null
|
|
const range = this.searchForm.dateRange
|
|
if (!range || range.length !== 2) {
|
|
return '请选择时间段'
|
|
}
|
|
const days = dayjs(range[1]).diff(dayjs(range[0]), 'day') + 1
|
|
if (days > 31) {
|
|
return '时间段最多不超过31天'
|
|
}
|
|
return null
|
|
},
|
|
search () {
|
|
const err = this.validateDayRange()
|
|
if (err) {
|
|
this.$tip.error(err)
|
|
return
|
|
}
|
|
this.handlePageChange(1)
|
|
},
|
|
buildQuery () {
|
|
const q = {
|
|
reportType: this.searchForm.reportType,
|
|
gsId: this.searchForm.gsId || undefined,
|
|
devKeyword: this.searchForm.devKeyword || undefined,
|
|
page: this.tableData.pagination.pageIndex,
|
|
capacity: this.tableData.pagination.pageSize
|
|
}
|
|
if (this.searchForm.reportType === 'day') {
|
|
const range = this.searchForm.dateRange || []
|
|
q.startTime = range[0]
|
|
q.endTime = range[1]
|
|
} else {
|
|
q.month = this.searchForm.month || lastMonthStr()
|
|
}
|
|
return q
|
|
},
|
|
handlePageChange (pageIndex) {
|
|
const err = this.validateDayRange()
|
|
if (err) {
|
|
this.$tip.error(err)
|
|
return
|
|
}
|
|
this.tableData.pagination.pageIndex = pageIndex || this.tableData.pagination.pageIndex
|
|
this.isWorking.search = true
|
|
reportApi.fetchPage(this.buildQuery())
|
|
.then(data => {
|
|
this.tableData.list = data.records || []
|
|
this.tableData.pagination.total = data.total || 0
|
|
this.dateColumns = data.dateColumns || []
|
|
if (data.page) this.tableData.pagination.pageIndex = data.page
|
|
if (data.capacity) this.tableData.pagination.pageSize = data.capacity
|
|
})
|
|
.catch(() => {})
|
|
.finally(() => { this.isWorking.search = false })
|
|
},
|
|
reset () {
|
|
this.searchForm = {
|
|
reportType: 'day',
|
|
month: lastMonthStr(),
|
|
dateRange: defaultDayRange(),
|
|
gsId: null,
|
|
devKeyword: ''
|
|
}
|
|
this.search()
|
|
},
|
|
columnToDateKey (col) {
|
|
if (this.searchForm.reportType === 'day') {
|
|
return col
|
|
}
|
|
const month = this.searchForm.month || lastMonthStr()
|
|
const parts = String(col).split('.')
|
|
if (parts.length !== 2) return null
|
|
const m = parseInt(parts[0], 10)
|
|
const d = parseInt(parts[1], 10)
|
|
if (isNaN(m) || isNaN(d)) return null
|
|
const year = parseInt(month.split('-')[0], 10)
|
|
const pad = n => (n < 10 ? '0' + n : '' + n)
|
|
return `${year}-${pad(m)}-${pad(d)}`
|
|
},
|
|
dailyVal (row, col, field) {
|
|
if (!row.daily) return '-'
|
|
const key = this.columnToDateKey(col)
|
|
if (!key || !row.daily[key]) return '-'
|
|
const v = row.daily[key][field]
|
|
return v != null && v !== '' ? v : '-'
|
|
},
|
|
formatNum (val) {
|
|
if (val === null || val === undefined || val === '') return '-'
|
|
return val
|
|
},
|
|
formatDevName (row) {
|
const parts = [row.floorName, row.roomName, row.devName]
|
.filter(p => p != null && String(p).trim() !== '')
|
return parts.length ? parts.join('/') : '-'
|
},
|
|
handleSyncUsage () {
|
|
const err = this.validateDayRange()
|
|
if (err) {
|
|
this.$tip.error(err)
|
|
return
|
|
}
|
|
const q = this.buildQuery()
|
|
const msg = q.reportType === 'day'
|
|
? `确认同步 ${q.startTime} 至 ${q.endTime} 用量数据吗?`
|
|
: `确认同步 ${q.month} 用量数据吗?`
|
|
this.$dialog.actionConfirm(msg, '同步用量')
|
|
.then(() => {
|
|
this.isSyncing = true
|
|
reportApi.syncUsage(q)
|
|
.then(res => {
|
|
this.$tip.apiSuccess(res || '同步成功')
|
|
this.search()
|
|
})
|
|
.catch(e => this.$tip.apiFailed(e))
|
|
.finally(() => { this.isSyncing = false })
|
|
})
|
|
.catch(() => {})
|
|
},
|
|
handleExport () {
|
|
const err = this.validateDayRange()
|
|
if (err) {
|
|
this.$tip.error(err)
|
|
return
|
|
}
|
|
this.$dialog.exportConfirm('确认导出吗?')
|
|
.then(() => {
|
|
this.isWorking.export = true
|
|
reportApi.exportExcel({
|
|
...this.buildQuery(),
|
|
page: 1,
|
|
capacity: 1000000
|
|
})
|
|
.then(response => {
|
|
this.download(response)
|
|
})
|
|
.catch(e => this.$tip.apiFailed(e))
|
|
.finally(() => { this.isWorking.export = false })
|
|
})
|
|
.catch(() => {})
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
.report-scroll-wrap {
|
width: 100%;
|
overflow-x: auto;
|
}
|
</style>
|