|
|
@ -0,0 +1,343 @@
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
|
|
|
<el-card shadow="never">
|
|
|
|
|
|
|
|
<template #header>
|
|
|
|
|
|
|
|
<div class="flex flex-row items-center justify-between">
|
|
|
|
|
|
|
|
<CardTitle title="充换电站信息统计" />
|
|
|
|
|
|
|
|
<!-- 查询条件 -->
|
|
|
|
|
|
|
|
<div class="flex flex-row items-center gap-2">
|
|
|
|
|
|
|
|
<el-radio-group v-model="timeRangeType" @change="handleTimeRangeTypeChange">
|
|
|
|
|
|
|
|
<el-radio-button v-for="[key, value] in timeRange.entries()" :key="key" :label="key">
|
|
|
|
|
|
|
|
{{ value.name }}
|
|
|
|
|
|
|
|
</el-radio-button>
|
|
|
|
|
|
|
|
</el-radio-group>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<!-- 折线图 -->
|
|
|
|
|
|
|
|
<Echart :height="300" :options="eChartOptions" />
|
|
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
|
|
|
|
|
import dayjs, { Dayjs } from 'dayjs'
|
|
|
|
|
|
|
|
import { color, EChartsOption } from 'echarts'
|
|
|
|
|
|
|
|
import * as TradeStatisticsApi from '@/api/mall/statistics/trade'
|
|
|
|
|
|
|
|
import { fenToYuan } from '@/utils'
|
|
|
|
|
|
|
|
import { formatDate } from '@/utils/formatTime'
|
|
|
|
|
|
|
|
import { CardTitle } from '@/components/Card'
|
|
|
|
|
|
|
|
import * as MemberStatisticsApi from '@/api/mall/statistics/member'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** 交易量趋势 */
|
|
|
|
|
|
|
|
defineOptions({ name: 'TradeTrendCard' })
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum TimeRangeTypeEnum {
|
|
|
|
|
|
|
|
DAY30 = 1,
|
|
|
|
|
|
|
|
WEEK = 7,
|
|
|
|
|
|
|
|
MONTH = 30,
|
|
|
|
|
|
|
|
YEAR = 365
|
|
|
|
|
|
|
|
} // 日期类型
|
|
|
|
|
|
|
|
const timeRangeType = ref(TimeRangeTypeEnum.MONTH) // 日期快捷选择按钮, 默认30天
|
|
|
|
|
|
|
|
const loading = ref(true) // 加载中
|
|
|
|
|
|
|
|
// 时间范围 Map
|
|
|
|
|
|
|
|
const timeRange = new Map()
|
|
|
|
|
|
|
|
// .set(TimeRangeTypeEnum.DAY30, {
|
|
|
|
|
|
|
|
// name: '30天',
|
|
|
|
|
|
|
|
// series: [
|
|
|
|
|
|
|
|
// { name: '订单金额', type: 'bar', smooth: true, data: [] },
|
|
|
|
|
|
|
|
// { name: '订单数量', type: 'line', smooth: true, data: [] }
|
|
|
|
|
|
|
|
// ]
|
|
|
|
|
|
|
|
// })
|
|
|
|
|
|
|
|
.set(TimeRangeTypeEnum.WEEK, {
|
|
|
|
|
|
|
|
name: '周',
|
|
|
|
|
|
|
|
series: [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ]
|
|
|
|
|
|
|
|
{ name: '上周', type: 'bar', smooth: true, data: [] },
|
|
|
|
|
|
|
|
{ name: '本周', type: 'bar', smooth: true, data: [] },
|
|
|
|
|
|
|
|
{ name: '上周', type: 'line', smooth: true, data: [] },
|
|
|
|
|
|
|
|
{ name: '本周', type: 'line', smooth: true, data: [] }
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.set(TimeRangeTypeEnum.MONTH, {
|
|
|
|
|
|
|
|
name: '月',
|
|
|
|
|
|
|
|
series: [
|
|
|
|
|
|
|
|
{ name: '上月', type: 'bar', smooth: true, data: [] },
|
|
|
|
|
|
|
|
{ name: '本月', type: 'bar', smooth: true, data: [] },
|
|
|
|
|
|
|
|
{ name: '上月', type: 'line', smooth: true, data: [] },
|
|
|
|
|
|
|
|
{ name: '本月', type: 'line', smooth: true, data: [] }
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.set(TimeRangeTypeEnum.YEAR, {
|
|
|
|
|
|
|
|
name: '年',
|
|
|
|
|
|
|
|
series: [
|
|
|
|
|
|
|
|
{ name: '去年', type: 'bar', smooth: true, data: [] },
|
|
|
|
|
|
|
|
{ name: '今年', type: 'bar', smooth: true, data: [] },
|
|
|
|
|
|
|
|
{ name: '去年', type: 'line', smooth: true, data: [] },
|
|
|
|
|
|
|
|
{ name: '今年', type: 'line', smooth: true, data: [] }
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
/** 图表配置 */
|
|
|
|
|
|
|
|
const eChartOptions = reactive<EChartsOption>({
|
|
|
|
|
|
|
|
grid: {
|
|
|
|
|
|
|
|
left: 20,
|
|
|
|
|
|
|
|
right: 20,
|
|
|
|
|
|
|
|
bottom: 20,
|
|
|
|
|
|
|
|
top: 80,
|
|
|
|
|
|
|
|
containLabel: true
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
|
|
trigger: 'axis'
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
legend: {
|
|
|
|
|
|
|
|
// data: ['充换电营收', '充换电量', '换电次数']
|
|
|
|
|
|
|
|
data: ['充换电营收', '充换电量']
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
calculable: true,
|
|
|
|
|
|
|
|
xAxis: [
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
type: 'category',
|
|
|
|
|
|
|
|
// prettier-ignore
|
|
|
|
|
|
|
|
data: [ ]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
yAxis: [
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
type: 'value'
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
series: [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
name: '充换电营收',
|
|
|
|
|
|
|
|
type: 'bar',
|
|
|
|
|
|
|
|
label:{show:true,position:'top',textStyle:{color:'#000000'},formatter:function(data){
|
|
|
|
|
|
|
|
return data.value+'元'
|
|
|
|
|
|
|
|
}},
|
|
|
|
|
|
|
|
data: [ 29792.40, 18646.14, 15153.60,14488.05,7735.55,6667.58,7035.60],
|
|
|
|
|
|
|
|
markPoint: {
|
|
|
|
|
|
|
|
data: [
|
|
|
|
|
|
|
|
{ type: 'max', name: 'Max' },
|
|
|
|
|
|
|
|
{ type: 'min', name: 'Min' }
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
markLine: {
|
|
|
|
|
|
|
|
data: [{ type: 'average', name: 'Avg' }]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
name: '充换电量',
|
|
|
|
|
|
|
|
type: 'bar',
|
|
|
|
|
|
|
|
label:{show:true,position:'top',textStyle:{color:'#000000'},formatter:function(data){
|
|
|
|
|
|
|
|
return data.value+'kwh'}},
|
|
|
|
|
|
|
|
data: [],
|
|
|
|
|
|
|
|
markPoint: {
|
|
|
|
|
|
|
|
data: [
|
|
|
|
|
|
|
|
{ name: 'Max', value: 182.2, xAxis: 7, yAxis: 183 },
|
|
|
|
|
|
|
|
{ name: 'Min', value: 2.3, xAxis: 11, yAxis: 3 }
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
markLine: {
|
|
|
|
|
|
|
|
data: [{ type: 'average', name: 'Avg' }]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
name: '换电次数',
|
|
|
|
|
|
|
|
type: 'bar',
|
|
|
|
|
|
|
|
data: [],
|
|
|
|
|
|
|
|
markPoint: {
|
|
|
|
|
|
|
|
data: [
|
|
|
|
|
|
|
|
{ name: 'Max', value: 182.2, xAxis: 7, yAxis: 183 },
|
|
|
|
|
|
|
|
{ name: 'Min', value: 2.3, xAxis: 11, yAxis: 3 }
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
markLine: {
|
|
|
|
|
|
|
|
data: [{ type: 'average', name: 'Avg' }]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
}) as EChartsOption
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const queryparams = ref({
|
|
|
|
|
|
|
|
startTime: '',
|
|
|
|
|
|
|
|
endTime: ''
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
/** 时间范围类型单选按钮选中 */
|
|
|
|
|
|
|
|
const handleTimeRangeTypeChange = async () => {
|
|
|
|
|
|
|
|
// 设置时间范围
|
|
|
|
|
|
|
|
switch (timeRangeType.value) {
|
|
|
|
|
|
|
|
case TimeRangeTypeEnum.WEEK:
|
|
|
|
|
|
|
|
queryparams.value.startTime = getDatesFromStartOfWeekToToday(new Date())
|
|
|
|
|
|
|
|
queryparams.value.endTime = getCurrentDateTime()
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
case TimeRangeTypeEnum.MONTH:
|
|
|
|
|
|
|
|
queryparams.value.startTime = getDatesFromStartOfMonthToToday(new Date())
|
|
|
|
|
|
|
|
queryparams.value.endTime = getCurrentDateTime()
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
case TimeRangeTypeEnum.YEAR:
|
|
|
|
|
|
|
|
queryparams.value.startTime = getFirstDayOfYear(new Date())
|
|
|
|
|
|
|
|
queryparams.value.endTime = getCurrentDateTime()
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
getlist()
|
|
|
|
|
|
|
|
// 发送时间范围选中事件
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const convertToTimestamp = (timeString) => {
|
|
|
|
|
|
|
|
// 创建一个 Date 对象
|
|
|
|
|
|
|
|
const date = new Date(timeString)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 检查日期是否有效
|
|
|
|
|
|
|
|
if (isNaN(date.getTime())) {
|
|
|
|
|
|
|
|
throw new Error('无效的时间字符串')
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 返回时间戳
|
|
|
|
|
|
|
|
return date.getTime()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const getlist = async () => {
|
|
|
|
|
|
|
|
loading.value = true
|
|
|
|
|
|
|
|
queryparams.value.startTime = convertToTimestamp(queryparams.value.startTime)
|
|
|
|
|
|
|
|
queryparams.value.endTime = convertToTimestamp(queryparams.value.endTime)
|
|
|
|
|
|
|
|
// 查询数据
|
|
|
|
|
|
|
|
const response = await MemberStatisticsApi.getHomeSwapInfo(queryparams.value)
|
|
|
|
|
|
|
|
console.log(response,"shuju")
|
|
|
|
|
|
|
|
let x_data = []
|
|
|
|
|
|
|
|
// 充换电营收
|
|
|
|
|
|
|
|
let y_data_1 = []
|
|
|
|
|
|
|
|
// 充换电量
|
|
|
|
|
|
|
|
let y_data_2 = []
|
|
|
|
|
|
|
|
// 换电次数
|
|
|
|
|
|
|
|
// let y_data_3 = []
|
|
|
|
|
|
|
|
if (response.length == 0) {
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let item of response) {
|
|
|
|
|
|
|
|
// console.log(item,'item');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
x_data.push(item.stationName)
|
|
|
|
|
|
|
|
y_data_1.push(item.swapRevenue / 100)
|
|
|
|
|
|
|
|
y_data_2.push(item.swapElec)
|
|
|
|
|
|
|
|
// y_data_3.push(item.swapCount)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
eChartOptions.xAxis[0].data = x_data
|
|
|
|
|
|
|
|
eChartOptions.series[0].data = y_data_1
|
|
|
|
|
|
|
|
eChartOptions.series[1].data = y_data_2
|
|
|
|
|
|
|
|
// eChartOptions.series[2].data = y_data_3
|
|
|
|
|
|
|
|
// console.log(x_data, 'x_data')
|
|
|
|
|
|
|
|
// console.log(y_data_1, 'y_data_1')
|
|
|
|
|
|
|
|
// console.log(y_data_2, 'y_data_2')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
loading.value = false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取本周
|
|
|
|
|
|
|
|
const getDatesFromStartOfWeekToToday = (todayDate) => {
|
|
|
|
|
|
|
|
// 解析传入的日期字符串
|
|
|
|
|
|
|
|
const today = new Date(todayDate)
|
|
|
|
|
|
|
|
// 确保传入的日期是有效的
|
|
|
|
|
|
|
|
if (isNaN(today.getTime())) {
|
|
|
|
|
|
|
|
throw new Error('Invalid date')
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取今天是星期几(0表示星期日,6表示星期六)
|
|
|
|
|
|
|
|
const todayIndex = today.getDay()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算本周的开始日期(假设本周从星期一开始)
|
|
|
|
|
|
|
|
const startOfWeek = new Date(today)
|
|
|
|
|
|
|
|
const offset = todayIndex === 0 ? -6 : 1 - todayIndex // 处理周日和其他星期几
|
|
|
|
|
|
|
|
startOfWeek.setDate(today.getDate() + offset)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 创建一个数组来存储日期
|
|
|
|
|
|
|
|
const dates = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 遍历从本周开始到今天的所有日期
|
|
|
|
|
|
|
|
for (let date = startOfWeek; date <= today; date.setDate(date.getDate() + 1)) {
|
|
|
|
|
|
|
|
dates.push(new Date(date).toISOString().split('T')[0]) // 格式化为 YYYY-MM-DD
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return dates[0] + ' 00:00:00'
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取本月
|
|
|
|
|
|
|
|
const getDatesFromStartOfMonthToToday = (todayDate) => {
|
|
|
|
|
|
|
|
// 解析传入的日期字符串
|
|
|
|
|
|
|
|
const today = new Date(todayDate)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 确保传入的日期是有效的
|
|
|
|
|
|
|
|
if (isNaN(today.getTime())) {
|
|
|
|
|
|
|
|
throw new Error('Invalid date')
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取当前月份和年份
|
|
|
|
|
|
|
|
const year = today.getFullYear()
|
|
|
|
|
|
|
|
const month = today.getMonth() // 0表示一月,11表示十二月
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算本月的第一天
|
|
|
|
|
|
|
|
const startOfMonth = new Date(year, month, 1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 创建一个数组来存储日期
|
|
|
|
|
|
|
|
const dates = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 遍历从本月开始到今天的所有日期
|
|
|
|
|
|
|
|
for (let date = startOfMonth; date <= today; date.setDate(date.getDate() + 1)) {
|
|
|
|
|
|
|
|
dates.push(new Date(date).toISOString().split('T')[0]) // 格式化为 YYYY-MM-DD
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return dates[0] + ' 00:00:00'
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取今年第一天
|
|
|
|
|
|
|
|
const getFirstDayOfYear = (dateString) => {
|
|
|
|
|
|
|
|
// 解析传入的日期字符串
|
|
|
|
|
|
|
|
const date = new Date(dateString)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 确保传入的日期是有效的
|
|
|
|
|
|
|
|
if (isNaN(date.getTime())) {
|
|
|
|
|
|
|
|
throw new Error('Invalid date')
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取当前年份
|
|
|
|
|
|
|
|
const year = date.getFullYear()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算今年的第一天
|
|
|
|
|
|
|
|
const firstDayOfYear = new Date(year, 0, 1) // 0表示1月
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 格式化为 YYYY-MM-DD hh:mm:ss
|
|
|
|
|
|
|
|
const formatDate = (date) => {
|
|
|
|
|
|
|
|
const year = date.getFullYear()
|
|
|
|
|
|
|
|
const month = String(date.getMonth() + 1).padStart(2, '0') // 月份从0开始,所以+1
|
|
|
|
|
|
|
|
const day = String(date.getDate()).padStart(2, '0')
|
|
|
|
|
|
|
|
const hours = String(date.getHours()).padStart(2, '0')
|
|
|
|
|
|
|
|
const minutes = String(date.getMinutes()).padStart(2, '0')
|
|
|
|
|
|
|
|
const seconds = String(date.getSeconds()).padStart(2, '0')
|
|
|
|
|
|
|
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return formatDate(firstDayOfYear)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const getCurrentDateTime = () => {
|
|
|
|
|
|
|
|
const now = new Date()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 格式化为 YYYY-MM-DD hh:mm:ss
|
|
|
|
|
|
|
|
const formatDate = (date) => {
|
|
|
|
|
|
|
|
const year = date.getFullYear()
|
|
|
|
|
|
|
|
const month = String(date.getMonth() + 1).padStart(2, '0')
|
|
|
|
|
|
|
|
const day = String(date.getDate()).padStart(2, '0')
|
|
|
|
|
|
|
|
const hours = String(date.getHours()).padStart(2, '0')
|
|
|
|
|
|
|
|
const minutes = String(date.getMinutes()).padStart(2, '0')
|
|
|
|
|
|
|
|
const seconds = String(date.getSeconds()).padStart(2, '0')
|
|
|
|
|
|
|
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return formatDate(now)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** 初始化 **/
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
|
|
queryparams.value.startTime = getDatesFromStartOfMonthToToday(new Date())
|
|
|
|
|
|
|
|
queryparams.value.endTime = getCurrentDateTime()
|
|
|
|
|
|
|
|
getlist()
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|