electripper-v2-ui/src/views/bst/index/components/OrderDailyStat.vue
2025-05-06 18:42:44 +08:00

281 lines
7.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div v-loading="loading">
<el-date-picker
v-model="queryParams.dateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="yyyy-MM-dd"
@change="getDailyAmount"
size="mini"
:clearable="false"
:picker-options="DatePickerOptions.DEFAULT"
/>
<div ref="chart" :style="{width: width, height: height}"></div>
</div>
</template>
<script>
import { getDailyAmount } from '@/api/dashboard/dashboard';
import { getLastDateStr } from '@/utils';
import { DatePickerOptions } from '@/utils/constants';
import $resize from '@/views/dashboard/mixins/resize';
import * as echarts from 'echarts';
export default {
name: "OrderDailyStat",
mixins: [$resize],
props: {
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '300px'
},
query: {
type: Object,
default: () => ({})
}
},
data() {
return {
DatePickerOptions,
loading: false,
dailyAmount: [],
queryParams: {
dateRange: [
getLastDateStr(7),
getLastDateStr(0)
]
},
chart: null
}
},
created() {
this.getDailyAmount();
},
mounted() {
this.initChart();
},
beforeDestroy() {
if (this.chart) {
this.chart.dispose();
this.chart = null;
}
},
methods: {
getDailyAmount() {
this.loading = true;
Object.assign(this.queryParams, this.query);
getDailyAmount(this.queryParams).then(res => {
this.dailyAmount = res.data;
this.updateChart();
}).finally(() => {
this.loading = false;
})
},
initChart() {
this.chart = echarts.init(this.$refs.chart);
this.updateChart();
},
resizeChart() {
if (this.chart) {
this.chart.resize();
}
},
updateChart() {
if (!this.chart || !this.dailyAmount.length) return;
const dates = this.dailyAmount.map(item => item.date);
const orderCounts = this.dailyAmount.map(item => item.order?.count || 0)
const orderAmounts = this.dailyAmount.map(item => item.order?.payAmount || 0);
const bonusAmounts = this.dailyAmount.map(item => item.bonus?.amount || 0);
const orderRefunds = this.dailyAmount.map(item => item.orderRefund?.amount || 0);
const bonusRefunds = this.dailyAmount.map(item => item.bonusRefund?.amount || 0);
const orderNetAmounts = this.dailyAmount.map((item, index) =>
(item.order?.payAmount || 0) - (item.orderRefund?.amount || 0)
);
const bonusNetAmounts = this.dailyAmount.map((item, index) =>
(item.bonus?.amount || 0) - (item.bonusRefund?.amount || 0)
);
const option = {
color: [
'#5B8FF9', // 柔和蓝 - 订单数量
'#61DDAA', // 柔和绿 - 订单金额
'#F6BD16', // 柔和黄 - 订单退款
'#6DC8EC', // 淡青 - 订单实收
'#9270CA', // 淡紫 - 分成金额
'#E8684A', // 柔和橙 - 分成退款
'#FF9D4D' // 柔和橙红 - 分成实收
],
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: function(params) {
let result = params[0].axisValueLabel + '<br/>';
params.forEach(param => {
const value = param.value;
const marker = param.marker;
const seriesName = param.seriesName;
if (seriesName === '订单数量') {
result += marker + seriesName + '<span style="float: right; margin-left: 20px;">' + value + ' 单</span><br/>';
} else {
result += marker + seriesName + '<span style="float: right; margin-left: 20px;">' + value.toFixed(2) + ' </span><br/>';
}
});
return result;
}
},
legend: {
data: ['订单数量', '支付金额', '支付退款', '支付实收', '分成金额', '分成退款', '分成实收'],
top: 8,
selected: {
'订单数量': true,
'支付金额': false,
'支付退款': false,
'支付实收': true,
'分成金额': false,
'分成退款': false,
'分成实收': true
}
},
grid: {
left: '3%',
right: '3%',
bottom: '2%',
top: '15%',
containLabel: true
},
xAxis: {
type: 'category',
data: dates,
axisLabel: {
interval: 'auto',
fontSize: 12,
},
boundaryGap: true
},
yAxis: [
{
type: 'value',
name: '金额',
position: 'left',
axisLabel: {
formatter: value => {
return value.toFixed(2) + ' '
}
}
},
{
type: 'value',
name: '订单数量',
position: 'right',
axisLabel: {
formatter: '{value}'
}
}
],
series: [
{
name: '订单数量',
type: 'bar',
yAxisIndex: 1,
data: orderCounts,
itemStyle: {
opacity: 0.6
},
barWidth: '20%'
},
{
name: '支付金额',
type: 'line',
yAxisIndex: 0,
data: orderAmounts,
smooth: true,
symbol: 'circle',
symbolSize: 5,
lineStyle: {
width: 2
}
},
{
name: '支付退款',
type: 'line',
yAxisIndex: 0,
data: orderRefunds,
smooth: true,
symbol: 'circle',
symbolSize: 5,
lineStyle: {
width: 2
}
},
{
name: '支付实收',
type: 'line',
yAxisIndex: 0,
data: orderNetAmounts,
smooth: true,
symbol: 'circle',
symbolSize: 6,
lineStyle: {
width: 2
}
},
{
name: '分成金额',
type: 'line',
yAxisIndex: 0,
data: bonusAmounts,
smooth: true,
symbol: 'circle',
symbolSize: 5,
lineStyle: {
width: 2
}
},
{
name: '分成退款',
type: 'line',
yAxisIndex: 0,
data: bonusRefunds,
smooth: true,
symbol: 'circle',
symbolSize: 5,
lineStyle: {
width: 2
}
},
{
name: '分成实收',
type: 'line',
yAxisIndex: 0,
data: bonusNetAmounts,
smooth: true,
symbol: 'circle',
symbolSize: 6,
lineStyle: {
width: 2
}
}
]
};
this.chart.setOption(option);
}
}
}
</script>
<style lang="scss" scoped>
.el-date-picker {
margin-bottom: 20px;
}
</style>