重构
This commit is contained in:
@ -129,6 +129,15 @@ export function getAmmeterRevenueData(params) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 电表报表
|
||||||
|
export function getAmmeterData(params) {
|
||||||
|
return request({
|
||||||
|
url: `/ems/statsReport/getAmmeterData`,
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 一周冲放曲线
|
// 一周冲放曲线
|
||||||
export function getSevenChargeData(data) {
|
export function getSevenChargeData(data) {
|
||||||
return request({
|
return request({
|
||||||
|
|||||||
@ -1,15 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="site-switch-header">
|
<view class="site-switch-header">
|
||||||
<uni-data-picker
|
<view class="selector-row">
|
||||||
placeholder="请选择"
|
<uni-data-picker
|
||||||
popup-title="业态选择"
|
placeholder="请选择"
|
||||||
:step-searh="true"
|
popup-title="业态选择"
|
||||||
:value="siteId"
|
:step-searh="true"
|
||||||
:clear-icon="false"
|
:value="siteId"
|
||||||
:localdata="siteTypeOptions"
|
:clear-icon="false"
|
||||||
:ellipsis="false"
|
:localdata="siteTypeOptions"
|
||||||
@change="handleChange"
|
:ellipsis="false"
|
||||||
/>
|
@change="handleChange"
|
||||||
|
/>
|
||||||
|
<view class="site-count-badge">{{ displaySiteCount }}</view>
|
||||||
|
</view>
|
||||||
<view class="info">
|
<view class="info">
|
||||||
<view class="list">
|
<view class="list">
|
||||||
<uni-icons type="location" color="#fff" size="20"></uni-icons>
|
<uni-icons type="location" color="#fff" size="20"></uni-icons>
|
||||||
@ -41,6 +44,19 @@
|
|||||||
runningTime: {
|
runningTime: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '-'
|
default: '-'
|
||||||
|
},
|
||||||
|
siteCount: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
displaySiteCount() {
|
||||||
|
const count = Number(this.siteCount || 0)
|
||||||
|
if (!Number.isFinite(count) || count <= 0) {
|
||||||
|
return '0'
|
||||||
|
}
|
||||||
|
return count > 99 ? '99+' : String(count)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -58,6 +74,30 @@
|
|||||||
padding-bottom: 100rpx;
|
padding-bottom: 100rpx;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
|
||||||
|
.selector-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-count-badge {
|
||||||
|
min-width: 48rpx;
|
||||||
|
height: 48rpx;
|
||||||
|
padding: 0 12rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
background: #ff4d4f;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 24rpx;
|
||||||
|
line-height: 1;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #fff;
|
||||||
|
box-sizing: border-box;
|
||||||
|
flex-shrink: 0;
|
||||||
|
box-shadow: 0 6rpx 14rpx rgba(255, 77, 79, 0.28);
|
||||||
|
}
|
||||||
|
|
||||||
.info {
|
.info {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 26rpx;
|
font-size: 26rpx;
|
||||||
|
|||||||
@ -3,9 +3,11 @@ module.exports = {
|
|||||||
// todo 打包项目时切换baseUrl
|
// todo 打包项目时切换baseUrl
|
||||||
// baseUrl: 'http://localhost:8089',
|
// baseUrl: 'http://localhost:8089',
|
||||||
// 测试环境
|
// 测试环境
|
||||||
baseUrl: 'http://110.40.171.179:8089',
|
// baseUrl: 'http://110.40.171.179:8089',
|
||||||
// 生产环境
|
// 生产环境
|
||||||
// baseUrl: 'http://1.15.120.242:8089',
|
//baseUrl: 'http://1.15.120.242:8089',
|
||||||
|
baseUrl: 'http://111.229.210.50:8089',
|
||||||
|
|
||||||
// 应用信息
|
// 应用信息
|
||||||
appInfo: {
|
appInfo: {
|
||||||
// 应用名称
|
// 应用名称
|
||||||
|
|||||||
14
pages.json
14
pages.json
@ -119,10 +119,16 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "单体电池",
|
"navigationBarTitleText": "单体电池",
|
||||||
"onReachBottomDistance": 100
|
"onReachBottomDistance": 100
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
{
|
||||||
],
|
"path": "pages/work/report/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "报表"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
],
|
||||||
"tabBar": {
|
"tabBar": {
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"selectedColor": "#000000",
|
"selectedColor": "#000000",
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="home-container">
|
<view class="home-container">
|
||||||
<site-switch-header :site-id="siteId" :site-type-options="siteTypeOptions" :site-address="baseInfo.siteAddress"
|
<site-switch-header :site-id="siteId" :site-type-options="siteTypeOptions" :site-address="baseInfo.siteAddress"
|
||||||
:running-time="baseInfo.runningTime" @change="selectedSite" />
|
:running-time="baseInfo.runningTime" :site-count="siteOptions.length" @change="selectedSite" />
|
||||||
|
|
||||||
<view class="base-info">
|
<view class="base-info">
|
||||||
<view class="map-card">
|
<view class="map-card">
|
||||||
|
|||||||
@ -55,8 +55,8 @@
|
|||||||
register: false,
|
register: false,
|
||||||
globalConfig: getApp().globalData.config,
|
globalConfig: getApp().globalData.config,
|
||||||
loginForm: {
|
loginForm: {
|
||||||
username: "admin",
|
username: "",
|
||||||
password: "admin123",
|
password: "",
|
||||||
code: "",
|
code: "",
|
||||||
uuid: ""
|
uuid: ""
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="work-container">
|
<view class="work-container">
|
||||||
<site-switch-header :site-id="siteId" :site-type-options="siteTypeOptions" :site-address="baseInfo.siteAddress"
|
<site-switch-header :site-id="siteId" :site-type-options="siteTypeOptions" :site-address="baseInfo.siteAddress"
|
||||||
:running-time="baseInfo.runningTime" @change="selectedSite" />
|
:running-time="baseInfo.runningTime" :site-count="siteCount" @change="selectedSite" />
|
||||||
<!-- 静态信息 -->
|
<!-- 静态信息 -->
|
||||||
<view class="base-info">
|
<view class="base-info">
|
||||||
<uni-group mode="card" class="install-data">
|
<uni-group mode="card" class="install-data">
|
||||||
@ -21,19 +21,20 @@
|
|||||||
</uni-grid>
|
</uni-grid>
|
||||||
</uni-group>
|
</uni-group>
|
||||||
<!-- 工作台 -->
|
<!-- 工作台 -->
|
||||||
<uni-section title="工作台" type="line" class="sections-list">
|
<uni-section title="工作台" type="line" class="sections-list">
|
||||||
<view class="grid-body">
|
<view class="grid-body">
|
||||||
<uni-grid :column="4" :showBorder="false" @change="toDetail">
|
<uni-grid :column="4" :showBorder="false" @change="toDetail">
|
||||||
<uni-grid-item v-for="(item,index) in siteGirdList" :index="index" :key="index+'work'">
|
<uni-grid-item v-for="(item,index) in siteGirdList" :index="index" :key="index+'work'">
|
||||||
<view class="grid-item-box work-box">
|
<view class="grid-item-box work-box">
|
||||||
<view class="icon iconfont" :class="item.icon" size="30"></view>
|
<image v-if="item.image" :src="item.image" class="icon icon-image" mode="aspectFit" />
|
||||||
<text class="text">{{item.text}}</text>
|
<view v-else class="icon iconfont" :class="item.icon" size="30"></view>
|
||||||
</view>
|
<text class="text">{{item.text}}</text>
|
||||||
</uni-grid-item>
|
</view>
|
||||||
</uni-grid>
|
</uni-grid-item>
|
||||||
</view>
|
</uni-grid>
|
||||||
</uni-section>
|
</view>
|
||||||
<!-- 一周充放曲线 uchart的组件最好放在同级-->
|
</uni-section>
|
||||||
|
<!-- 一周充放曲线 uchart的组件最好放在同级-->
|
||||||
<uni-section title="一周充放曲线" type="line" class="sections-list">
|
<uni-section title="一周充放曲线" type="line" class="sections-list">
|
||||||
<date-range-select ref="weekChartDateRangeSelect" @updateDate="updateWeekChartDate" />
|
<date-range-select ref="weekChartDateRangeSelect" @updateDate="updateWeekChartDate" />
|
||||||
<view style="width:100%;height: 250px;">
|
<view style="width:100%;height: 250px;">
|
||||||
@ -53,7 +54,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {
|
import {
|
||||||
mapGetters
|
mapGetters
|
||||||
} from 'vuex'
|
} from 'vuex'
|
||||||
@ -90,9 +91,9 @@
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
// 图表数据
|
// 图表数据
|
||||||
weekChartTimeRange: [],
|
weekChartTimeRange: [],
|
||||||
activeChartTimeRange: [],
|
activeChartTimeRange: [],
|
||||||
weekChartData: {},
|
weekChartData: {},
|
||||||
activeChartData: {},
|
activeChartData: {},
|
||||||
curveDisplayData: [],
|
curveDisplayData: [],
|
||||||
curveDisplayLoadingPromise: null,
|
curveDisplayLoadingPromise: null,
|
||||||
@ -186,15 +187,27 @@
|
|||||||
page: 'dtdc',
|
page: 'dtdc',
|
||||||
icon: 'icon-dantidianchi',
|
icon: 'icon-dantidianchi',
|
||||||
text: '单体电池',
|
text: '单体电池',
|
||||||
categoryName: 'BATTERY'
|
categoryName: 'BATTERY'
|
||||||
}
|
},
|
||||||
]
|
{
|
||||||
}
|
page: 'report',
|
||||||
|
icon: 'icon-service',
|
||||||
|
image: '/static/images/work/report.svg',
|
||||||
|
text: '报表',
|
||||||
|
categoryName: ''
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['belongSite', 'currentSiteId']),
|
...mapGetters(['belongSite', 'currentSiteId']),
|
||||||
|
siteCount() {
|
||||||
|
return (this.siteTypeOptions || []).reduce((count, typeItem) => {
|
||||||
|
return count + ((typeItem.children || []).length)
|
||||||
|
}, 0)
|
||||||
|
},
|
||||||
siteGirdList() {
|
siteGirdList() {
|
||||||
return this.gridList.filter(i => this.deviceCategoryOptions.includes(i.categoryName))
|
return this.gridList.filter(i => !i.categoryName || this.deviceCategoryOptions.includes(i.categoryName))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -464,8 +477,8 @@
|
|||||||
onLoad() {
|
onLoad() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.getSiteList()
|
this.getSiteList()
|
||||||
this.$refs.weekChartDateRangeSelect.init()
|
this.$refs.weekChartDateRangeSelect.init()
|
||||||
this.$refs.activeChartDateRangeSelect.init(true)
|
this.$refs.activeChartDateRangeSelect.init(true)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
// 页面滚动 设置pageScrollTop chart显示需要
|
// 页面滚动 设置pageScrollTop chart显示需要
|
||||||
@ -564,23 +577,28 @@
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
.work-box {
|
.work-box {
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
font-size: 52rpx;
|
font-size: 52rpx;
|
||||||
color: #547ef4;
|
color: #547ef4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.icon-image {
|
||||||
font-size: 26rpx;
|
width: 56rpx;
|
||||||
|
height: 56rpx;
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
font-size: 26rpx;
|
||||||
padding-top: 10rpx;
|
padding-top: 10rpx;
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.base-lists {
|
||||||
|
|
||||||
.base-lists {
|
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
line-height: 40rpx;
|
line-height: 40rpx;
|
||||||
padding: 10rpx 20rpx;
|
padding: 10rpx 20rpx;
|
||||||
|
|||||||
580
pages/work/report/index.vue
Normal file
580
pages/work/report/index.vue
Normal file
@ -0,0 +1,580 @@
|
|||||||
|
<template>
|
||||||
|
<view class="report-page">
|
||||||
|
<view class="toolbar">
|
||||||
|
<uni-datetime-picker v-model="dateRange" type="daterange" :end="defaultDateRange[1]" :clear-icon="false"
|
||||||
|
rangeSeparator="至" @change="changeDateRange" />
|
||||||
|
<view class="button-group">
|
||||||
|
<button size="mini" class="small" :disabled="loading" @click="resetDateRange">重置</button>
|
||||||
|
<button type="primary" size="mini" class="large" :disabled="loading" @click="getReportData">查询</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="loading" class="report-state">报表数据加载中...</view>
|
||||||
|
<view v-else-if="reportList.length === 0" class="report-state">暂无报表数据</view>
|
||||||
|
<view v-else class="report-list">
|
||||||
|
<uni-collapse class="report-collapse">
|
||||||
|
<uni-collapse-item v-for="item in reportList" :key="item.dataTime" class="report-card">
|
||||||
|
<template v-slot:title>
|
||||||
|
<view class="report-card__header">
|
||||||
|
<view class="report-card__title-main">
|
||||||
|
<view class="report-card__date">{{item.dataTime}}</view>
|
||||||
|
<view class="report-card__tags">
|
||||||
|
<text v-if="item.dayType" class="report-tag">{{item.dayType}}</text>
|
||||||
|
<text v-if="item.weatherDesc" class="report-tag weather">{{item.weatherDesc}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="report-summary report-summary--compact">
|
||||||
|
<view class="summary-item emphasis">
|
||||||
|
<text class="label">实际收益</text>
|
||||||
|
<text class="value">{{formatReportValue(item.actualRevenue)}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="summary-item">
|
||||||
|
<text class="label">效率(%)</text>
|
||||||
|
<text class="value">{{formatReportValue(item.effect)}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="summary-item">
|
||||||
|
<text class="label">充电总量(kWh)</text>
|
||||||
|
<text class="value">{{formatReportValue(item.activeTotalKwh)}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="summary-item">
|
||||||
|
<text class="label">放电总量(kWh)</text>
|
||||||
|
<text class="value">{{formatReportValue(item.reActiveTotalKwh)}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<view class="report-card__content">
|
||||||
|
<view class="report-group">
|
||||||
|
<view class="report-group__title">电量数据</view>
|
||||||
|
<view class="report-metric-row">
|
||||||
|
<view class="report-metric-row__label">充电量</view>
|
||||||
|
<view class="report-metric-grid">
|
||||||
|
<view v-for="metric in buildMetricItems(item, 'chargeKwh')" :key="item.dataTime + metric.key"
|
||||||
|
class="report-metric">
|
||||||
|
<text class="metric-label">{{metric.label}}</text>
|
||||||
|
<text class="metric-value">{{formatReportValue(metric.value)}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="report-metric-row">
|
||||||
|
<view class="report-metric-row__label">放电量</view>
|
||||||
|
<view class="report-metric-grid">
|
||||||
|
<view v-for="metric in buildMetricItems(item, 'dischargeKwh')"
|
||||||
|
:key="item.dataTime + metric.key" class="report-metric">
|
||||||
|
<text class="metric-label">{{metric.label}}</text>
|
||||||
|
<text class="metric-value">{{formatReportValue(metric.value)}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="report-group">
|
||||||
|
<view class="report-group__title">收益数据</view>
|
||||||
|
<view class="report-metric-row">
|
||||||
|
<view class="report-metric-row__label">充电价格</view>
|
||||||
|
<view class="report-metric-grid">
|
||||||
|
<view v-for="metric in buildMetricItems(item, 'chargePrice')"
|
||||||
|
:key="item.dataTime + metric.key + 'price'" class="report-metric">
|
||||||
|
<text class="metric-label">{{metric.label}}</text>
|
||||||
|
<text class="metric-value">{{formatReportValue(metric.value)}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="report-metric-row">
|
||||||
|
<view class="report-metric-row__label">放电价格</view>
|
||||||
|
<view class="report-metric-grid">
|
||||||
|
<view v-for="metric in buildMetricItems(item, 'dischargePrice')"
|
||||||
|
:key="item.dataTime + metric.key + 'rePrice'" class="report-metric">
|
||||||
|
<text class="metric-label">{{metric.label}}</text>
|
||||||
|
<text class="metric-value">{{formatReportValue(metric.value)}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</uni-collapse-item>
|
||||||
|
</uni-collapse>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
formatDate
|
||||||
|
} from '@/utils/filters'
|
||||||
|
import {
|
||||||
|
getAmmeterData,
|
||||||
|
getAmmeterRevenueData
|
||||||
|
} from '@/api/ems/site.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
siteId: '',
|
||||||
|
dateRange: [],
|
||||||
|
defaultDateRange: [],
|
||||||
|
reportList: [],
|
||||||
|
loading: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initDateRange() {
|
||||||
|
const now = new Date()
|
||||||
|
const firstDay = new Date(now.getFullYear(), now.getMonth(), 1)
|
||||||
|
this.defaultDateRange = [formatDate(firstDay), formatDate(now)]
|
||||||
|
this.dateRange = [...this.defaultDateRange]
|
||||||
|
},
|
||||||
|
changeDateRange(value) {
|
||||||
|
this.dateRange = value || []
|
||||||
|
},
|
||||||
|
resetDateRange() {
|
||||||
|
this.dateRange = [...this.defaultDateRange]
|
||||||
|
this.getReportData()
|
||||||
|
},
|
||||||
|
createEmptyReportRow(dataTime) {
|
||||||
|
return {
|
||||||
|
dataTime,
|
||||||
|
dayType: '',
|
||||||
|
weatherDesc: '',
|
||||||
|
activePeakKwh: null,
|
||||||
|
activeHighKwh: null,
|
||||||
|
activeFlatKwh: null,
|
||||||
|
activeValleyKwh: null,
|
||||||
|
activeTotalKwh: null,
|
||||||
|
reActivePeakKwh: null,
|
||||||
|
reActiveHighKwh: null,
|
||||||
|
reActiveFlatKwh: null,
|
||||||
|
reActiveValleyKwh: null,
|
||||||
|
reActiveTotalKwh: null,
|
||||||
|
effect: null,
|
||||||
|
activePeakPrice: null,
|
||||||
|
activeHighPrice: null,
|
||||||
|
activeFlatPrice: null,
|
||||||
|
activeValleyPrice: null,
|
||||||
|
activeTotalPrice: null,
|
||||||
|
reActivePeakPrice: null,
|
||||||
|
reActiveHighPrice: null,
|
||||||
|
reActiveFlatPrice: null,
|
||||||
|
reActiveValleyPrice: null,
|
||||||
|
reActiveTotalPrice: null,
|
||||||
|
actualRevenue: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mergeReportRows(ammeterRows = [], revenueRows = []) {
|
||||||
|
const reportMap = {}
|
||||||
|
const ensureRow = (date) => {
|
||||||
|
const key = String(date || '').trim()
|
||||||
|
if (!key) return null
|
||||||
|
if (!reportMap[key]) {
|
||||||
|
reportMap[key] = this.createEmptyReportRow(key)
|
||||||
|
}
|
||||||
|
return reportMap[key]
|
||||||
|
}
|
||||||
|
;(ammeterRows || []).forEach(item => {
|
||||||
|
const row = ensureRow(item.dataTime)
|
||||||
|
if (!row) return
|
||||||
|
Object.assign(row, {
|
||||||
|
activePeakKwh: item.activePeakKwh,
|
||||||
|
activeHighKwh: item.activeHighKwh,
|
||||||
|
activeFlatKwh: item.activeFlatKwh,
|
||||||
|
activeValleyKwh: item.activeValleyKwh,
|
||||||
|
activeTotalKwh: item.activeTotalKwh,
|
||||||
|
reActivePeakKwh: item.reActivePeakKwh,
|
||||||
|
reActiveHighKwh: item.reActiveHighKwh,
|
||||||
|
reActiveFlatKwh: item.reActiveFlatKwh,
|
||||||
|
reActiveValleyKwh: item.reActiveValleyKwh,
|
||||||
|
reActiveTotalKwh: item.reActiveTotalKwh,
|
||||||
|
effect: item.effect
|
||||||
|
})
|
||||||
|
})
|
||||||
|
;(revenueRows || []).forEach(item => {
|
||||||
|
const row = ensureRow(item.dataTime)
|
||||||
|
if (!row) return
|
||||||
|
Object.assign(row, {
|
||||||
|
dayType: item.dayType,
|
||||||
|
weatherDesc: item.weatherDesc,
|
||||||
|
activePeakPrice: item.activePeakPrice,
|
||||||
|
activeHighPrice: item.activeHighPrice,
|
||||||
|
activeFlatPrice: item.activeFlatPrice,
|
||||||
|
activeValleyPrice: item.activeValleyPrice,
|
||||||
|
activeTotalPrice: item.activeTotalPrice,
|
||||||
|
reActivePeakPrice: item.reActivePeakPrice,
|
||||||
|
reActiveHighPrice: item.reActiveHighPrice,
|
||||||
|
reActiveFlatPrice: item.reActiveFlatPrice,
|
||||||
|
reActiveValleyPrice: item.reActiveValleyPrice,
|
||||||
|
reActiveTotalPrice: item.reActiveTotalPrice,
|
||||||
|
actualRevenue: item.actualRevenue
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return Object.values(reportMap).sort((a, b) => String(b.dataTime).localeCompare(String(a.dataTime)))
|
||||||
|
},
|
||||||
|
buildMetricItems(item, type) {
|
||||||
|
const configMap = {
|
||||||
|
chargeKwh: [{
|
||||||
|
key: 'activePeakKwh',
|
||||||
|
label: '尖',
|
||||||
|
value: item.activePeakKwh
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'activeHighKwh',
|
||||||
|
label: '峰',
|
||||||
|
value: item.activeHighKwh
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'activeFlatKwh',
|
||||||
|
label: '平',
|
||||||
|
value: item.activeFlatKwh
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'activeValleyKwh',
|
||||||
|
label: '谷',
|
||||||
|
value: item.activeValleyKwh
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'activeTotalKwh',
|
||||||
|
label: '总',
|
||||||
|
value: item.activeTotalKwh
|
||||||
|
}
|
||||||
|
],
|
||||||
|
dischargeKwh: [{
|
||||||
|
key: 'reActivePeakKwh',
|
||||||
|
label: '尖',
|
||||||
|
value: item.reActivePeakKwh
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'reActiveHighKwh',
|
||||||
|
label: '峰',
|
||||||
|
value: item.reActiveHighKwh
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'reActiveFlatKwh',
|
||||||
|
label: '平',
|
||||||
|
value: item.reActiveFlatKwh
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'reActiveValleyKwh',
|
||||||
|
label: '谷',
|
||||||
|
value: item.reActiveValleyKwh
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'reActiveTotalKwh',
|
||||||
|
label: '总',
|
||||||
|
value: item.reActiveTotalKwh
|
||||||
|
}
|
||||||
|
],
|
||||||
|
chargePrice: [{
|
||||||
|
key: 'activePeakPrice',
|
||||||
|
label: '尖',
|
||||||
|
value: item.activePeakPrice
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'activeHighPrice',
|
||||||
|
label: '峰',
|
||||||
|
value: item.activeHighPrice
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'activeFlatPrice',
|
||||||
|
label: '平',
|
||||||
|
value: item.activeFlatPrice
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'activeValleyPrice',
|
||||||
|
label: '谷',
|
||||||
|
value: item.activeValleyPrice
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'activeTotalPrice',
|
||||||
|
label: '总',
|
||||||
|
value: item.activeTotalPrice
|
||||||
|
}
|
||||||
|
],
|
||||||
|
dischargePrice: [{
|
||||||
|
key: 'reActivePeakPrice',
|
||||||
|
label: '尖',
|
||||||
|
value: item.reActivePeakPrice
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'reActiveHighPrice',
|
||||||
|
label: '峰',
|
||||||
|
value: item.reActiveHighPrice
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'reActiveFlatPrice',
|
||||||
|
label: '平',
|
||||||
|
value: item.reActiveFlatPrice
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'reActiveValleyPrice',
|
||||||
|
label: '谷',
|
||||||
|
value: item.reActiveValleyPrice
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'reActiveTotalPrice',
|
||||||
|
label: '总',
|
||||||
|
value: item.reActiveTotalPrice
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return configMap[type] || []
|
||||||
|
},
|
||||||
|
formatReportValue(value) {
|
||||||
|
if (!(value || value === 0 || value === '0')) return '-'
|
||||||
|
const num = Number(value)
|
||||||
|
if (!Number.isFinite(num)) return value
|
||||||
|
return num.toFixed(3).replace(/\.?0+$/, '')
|
||||||
|
},
|
||||||
|
getReportData() {
|
||||||
|
if (!this.siteId || !this.dateRange.length) return
|
||||||
|
const [startTime = '', endTime = ''] = this.dateRange || []
|
||||||
|
this.loading = true
|
||||||
|
Promise.all([
|
||||||
|
getAmmeterData({
|
||||||
|
siteId: this.siteId,
|
||||||
|
startTime,
|
||||||
|
endTime,
|
||||||
|
pageSize: 200,
|
||||||
|
pageNum: 1
|
||||||
|
}),
|
||||||
|
getAmmeterRevenueData({
|
||||||
|
siteId: this.siteId,
|
||||||
|
startTime,
|
||||||
|
endTime,
|
||||||
|
pageSize: 200,
|
||||||
|
pageNum: 1
|
||||||
|
})
|
||||||
|
]).then(([ammeterResponse, revenueResponse]) => {
|
||||||
|
const ammeterRows = ammeterResponse?.rows || []
|
||||||
|
const revenueRows = revenueResponse?.rows || []
|
||||||
|
this.reportList = this.mergeReportRows(ammeterRows, revenueRows)
|
||||||
|
}).catch(() => {
|
||||||
|
this.reportList = []
|
||||||
|
}).finally(() => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad(options) {
|
||||||
|
this.siteId = options.siteId || ''
|
||||||
|
this.initDateRange()
|
||||||
|
this.getReportData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.report-page {
|
||||||
|
min-height: 100%;
|
||||||
|
padding: 24rpx;
|
||||||
|
background: #f5f6f8;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
|
padding: 24rpx;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
background: #fff;
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-group {
|
||||||
|
margin-top: 20rpx;
|
||||||
|
|
||||||
|
uni-button {
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 26rpx;
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-right: 20rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.small {
|
||||||
|
width: 120rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.large {
|
||||||
|
width: 160rpx;
|
||||||
|
background-color: #547ef4;
|
||||||
|
|
||||||
|
&[disabled][type=primary] {
|
||||||
|
background-color: #89a8ffe6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-state {
|
||||||
|
padding: 80rpx 0;
|
||||||
|
text-align: center;
|
||||||
|
color: #999;
|
||||||
|
font-size: 24rpx;
|
||||||
|
line-height: 36rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-card {
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-collapse {
|
||||||
|
:deep(.uni-collapse) {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.uni-collapse-item) {
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.uni-collapse-item__title-wrap) {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.uni-collapse-item__title-box) {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.uni-collapse-item__content) {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-card__header {
|
||||||
|
padding: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-card__title-main {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 20rpx;
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-card__date {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1f2329;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-card__tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-tag {
|
||||||
|
padding: 8rpx 18rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
background: #eef3ff;
|
||||||
|
color: #547ef4;
|
||||||
|
font-size: 22rpx;
|
||||||
|
line-height: 1;
|
||||||
|
|
||||||
|
&.weather {
|
||||||
|
background: #f5f7fa;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-summary {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 18rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-summary--compact {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-item {
|
||||||
|
padding: 18rpx 20rpx;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
background: #f7f8fa;
|
||||||
|
|
||||||
|
&.emphasis {
|
||||||
|
background: linear-gradient(135deg, #547ef4, #6ea1ff);
|
||||||
|
|
||||||
|
.label,
|
||||||
|
.value {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
display: block;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #8a919f;
|
||||||
|
margin-bottom: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1f2329;
|
||||||
|
line-height: 1.2;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-group:not(:last-child) {
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-card__content {
|
||||||
|
padding: 0 24rpx 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-group__title {
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1f2329;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-metric-row:not(:last-child) {
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-metric-row__label {
|
||||||
|
margin-bottom: 12rpx;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #8a919f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-metric-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||||
|
gap: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-metric {
|
||||||
|
padding: 14rpx 10rpx;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
background: #f7f8fa;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8rpx;
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: #8a919f;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-value {
|
||||||
|
display: block;
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1f2329;
|
||||||
|
line-height: 1.3;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
12
static/images/work/report.svg
Normal file
12
static/images/work/report.svg
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="20" y="12" width="88" height="104" rx="16" fill="#EEF4FF"/>
|
||||||
|
<path d="M44 12H88L108 32V40H44V12Z" fill="#DCE8FF"/>
|
||||||
|
<path d="M88 12V28C88 30.2091 89.7909 32 92 32H108" fill="#C8DAFF"/>
|
||||||
|
<rect x="36" y="52" width="56" height="8" rx="4" fill="#9FB9FF"/>
|
||||||
|
<rect x="36" y="68" width="40" height="8" rx="4" fill="#C5D6FF"/>
|
||||||
|
<rect x="38" y="88" width="10" height="16" rx="5" fill="#7AA2FF"/>
|
||||||
|
<rect x="56" y="78" width="10" height="26" rx="5" fill="#5B87F7"/>
|
||||||
|
<rect x="74" y="70" width="10" height="34" rx="5" fill="#2F67E8"/>
|
||||||
|
<rect x="92" y="82" width="10" height="22" rx="5" fill="#89ACFF"/>
|
||||||
|
<rect x="20" y="12" width="88" height="104" rx="16" stroke="#5B87F7" stroke-width="4"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 807 B |
Reference in New Issue
Block a user