feat:【mall 商城】商城首页的迁移【antd】50%:trade-trend-card 修复缺陷
This commit is contained in:
@@ -1,35 +1,30 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { EchartsUIType } from '@vben/plugins/echarts';
|
|
||||||
import type { Dayjs } from 'dayjs';
|
import type { Dayjs } from 'dayjs';
|
||||||
|
|
||||||
import { onMounted, ref } from 'vue';
|
import type { EchartsUIType } from '@vben/plugins/echarts';
|
||||||
|
|
||||||
import dayjs from 'dayjs';
|
import { onMounted, ref } from 'vue';
|
||||||
import { Card, Radio, RadioGroup, Spin } from 'ant-design-vue';
|
|
||||||
|
|
||||||
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
|
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
|
||||||
import { fenToYuan } from '@vben/utils';
|
import { fenToYuan } from '@vben/utils';
|
||||||
|
|
||||||
|
import { Card, Radio, RadioGroup, Spin } from 'ant-design-vue';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
import * as TradeStatisticsApi from '#/api/mall/statistics/trade';
|
import * as TradeStatisticsApi from '#/api/mall/statistics/trade';
|
||||||
|
|
||||||
import { getTradeTrendChartOptions } from './trade-trend-chart-options';
|
import {
|
||||||
|
getTradeTrendChartOptions,
|
||||||
|
TimeRangeTypeEnum,
|
||||||
|
} from './trade-trend-chart-options';
|
||||||
|
|
||||||
/** 交易量趋势 */
|
/** 交易量趋势 */
|
||||||
defineOptions({ name: 'TradeTrendCard' });
|
defineOptions({ name: 'TradeTrendCard' });
|
||||||
|
|
||||||
enum TimeRangeTypeEnum {
|
|
||||||
DAY30 = 1,
|
|
||||||
WEEK = 7,
|
|
||||||
MONTH = 30,
|
|
||||||
YEAR = 365,
|
|
||||||
}
|
|
||||||
|
|
||||||
const timeRangeType = ref(TimeRangeTypeEnum.DAY30); // 日期快捷选择按钮, 默认30天
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
|
||||||
// 时间范围 Map
|
|
||||||
const timeRangeConfig = {
|
const timeRangeConfig = {
|
||||||
[TimeRangeTypeEnum.DAY30]: {
|
[TimeRangeTypeEnum.DAY30]: {
|
||||||
name: '30 天',
|
name: '30 天',
|
||||||
@@ -47,7 +42,8 @@ const timeRangeConfig = {
|
|||||||
name: '年',
|
name: '年',
|
||||||
seriesCount: 4,
|
seriesCount: 4,
|
||||||
},
|
},
|
||||||
};
|
}; // 时间范围 Map
|
||||||
|
const timeRangeType = ref(TimeRangeTypeEnum.DAY30); // 日期快捷选择按钮, 默认 30 天
|
||||||
|
|
||||||
/** 时间范围类型单选按钮选中 */
|
/** 时间范围类型单选按钮选中 */
|
||||||
const handleTimeRangeTypeChange = async () => {
|
const handleTimeRangeTypeChange = async () => {
|
||||||
@@ -55,9 +51,9 @@ const handleTimeRangeTypeChange = async () => {
|
|||||||
let beginTime: Dayjs;
|
let beginTime: Dayjs;
|
||||||
let endTime: Dayjs;
|
let endTime: Dayjs;
|
||||||
switch (timeRangeType.value) {
|
switch (timeRangeType.value) {
|
||||||
case TimeRangeTypeEnum.WEEK: {
|
case TimeRangeTypeEnum.DAY30: {
|
||||||
beginTime = dayjs().startOf('week');
|
beginTime = dayjs().subtract(30, 'day').startOf('d');
|
||||||
endTime = dayjs().endOf('week');
|
endTime = dayjs().endOf('d');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TimeRangeTypeEnum.MONTH: {
|
case TimeRangeTypeEnum.MONTH: {
|
||||||
@@ -65,16 +61,18 @@ const handleTimeRangeTypeChange = async () => {
|
|||||||
endTime = dayjs().endOf('month');
|
endTime = dayjs().endOf('month');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case TimeRangeTypeEnum.WEEK: {
|
||||||
|
beginTime = dayjs().startOf('week');
|
||||||
|
endTime = dayjs().endOf('week');
|
||||||
|
break;
|
||||||
|
}
|
||||||
case TimeRangeTypeEnum.YEAR: {
|
case TimeRangeTypeEnum.YEAR: {
|
||||||
beginTime = dayjs().startOf('year');
|
beginTime = dayjs().startOf('year');
|
||||||
endTime = dayjs().endOf('year');
|
endTime = dayjs().endOf('year');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TimeRangeTypeEnum.DAY30:
|
|
||||||
default: {
|
default: {
|
||||||
beginTime = dayjs().subtract(30, 'day').startOf('d');
|
throw new Error(`未知的时间范围类型: ${timeRangeType.value}`);
|
||||||
endTime = dayjs().endOf('d');
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 发送时间范围选中事件
|
// 发送时间范围选中事件
|
||||||
@@ -82,25 +80,22 @@ const handleTimeRangeTypeChange = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** 查询订单数量趋势对照数据 */
|
/** 查询订单数量趋势对照数据 */
|
||||||
const getOrderCountTrendComparison = async (
|
async function getOrderCountTrendComparison(beginTime: Dayjs, endTime: Dayjs) {
|
||||||
beginTime: dayjs.ConfigType,
|
|
||||||
endTime: dayjs.ConfigType,
|
|
||||||
) => {
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
// 查询数据
|
// 1. 查询数据
|
||||||
const list = await TradeStatisticsApi.getOrderCountTrendComparison(
|
const list = await TradeStatisticsApi.getOrderCountTrendComparison(
|
||||||
timeRangeType.value,
|
timeRangeType.value,
|
||||||
beginTime,
|
beginTime.toDate(),
|
||||||
endTime,
|
endTime.toDate(),
|
||||||
);
|
);
|
||||||
// 处理数据
|
// 2. 处理数据
|
||||||
const dates: string[] = [];
|
const dates: string[] = [];
|
||||||
const series: any[] = [];
|
const series: any[] = [];
|
||||||
const config = timeRangeConfig[timeRangeType.value];
|
const config = timeRangeConfig[timeRangeType.value];
|
||||||
|
// 情况一:seriesCount 为 2(近 30 天)
|
||||||
if (config.seriesCount === 2) {
|
if (config.seriesCount === 2) {
|
||||||
const orderPayPriceData: number[] = [];
|
const orderPayPriceData: string[] = [];
|
||||||
const orderPayCountData: number[] = [];
|
const orderPayCountData: number[] = [];
|
||||||
for (const item of list) {
|
for (const item of list) {
|
||||||
dates.push(item.value.date);
|
dates.push(item.value.date);
|
||||||
@@ -108,7 +103,12 @@ const getOrderCountTrendComparison = async (
|
|||||||
orderPayCountData.push(item?.value?.orderPayCount || 0);
|
orderPayCountData.push(item?.value?.orderPayCount || 0);
|
||||||
}
|
}
|
||||||
series.push(
|
series.push(
|
||||||
{ name: '订单金额', type: 'bar', smooth: true, data: orderPayPriceData },
|
{
|
||||||
|
name: '订单金额',
|
||||||
|
type: 'bar',
|
||||||
|
smooth: true,
|
||||||
|
data: orderPayPriceData,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: '订单数量',
|
name: '订单数量',
|
||||||
type: 'line',
|
type: 'line',
|
||||||
@@ -117,11 +117,11 @@ const getOrderCountTrendComparison = async (
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const refPriceData: number[] = [];
|
// 情况二:seriesCount 为 4
|
||||||
const curPriceData: number[] = [];
|
const refPriceData: string[] = [];
|
||||||
|
const curPriceData: string[] = [];
|
||||||
const refCountData: number[] = [];
|
const refCountData: number[] = [];
|
||||||
const curCountData: number[] = [];
|
const curCountData: number[] = [];
|
||||||
|
|
||||||
for (const item of list) {
|
for (const item of list) {
|
||||||
dates.push(item.value.date);
|
dates.push(item.value.date);
|
||||||
refPriceData.push(fenToYuan(item?.reference?.orderPayPrice || 0));
|
refPriceData.push(fenToYuan(item?.reference?.orderPayPrice || 0));
|
||||||
@@ -129,14 +129,15 @@ const getOrderCountTrendComparison = async (
|
|||||||
refCountData.push(item?.reference?.orderPayCount || 0);
|
refCountData.push(item?.reference?.orderPayCount || 0);
|
||||||
curCountData.push(item?.value?.orderPayCount || 0);
|
curCountData.push(item?.value?.orderPayCount || 0);
|
||||||
}
|
}
|
||||||
|
// 根据时间范围类型确定对照数据的标签文本
|
||||||
const timeLabel =
|
let timeLabel: string[];
|
||||||
timeRangeType.value === TimeRangeTypeEnum.WEEK
|
if (timeRangeType.value === TimeRangeTypeEnum.WEEK) {
|
||||||
? ['上周', '本周']
|
timeLabel = ['上周', '本周'];
|
||||||
: timeRangeType.value === TimeRangeTypeEnum.MONTH
|
} else if (timeRangeType.value === TimeRangeTypeEnum.MONTH) {
|
||||||
? ['上月', '本月']
|
timeLabel = ['上月', '本月'];
|
||||||
: ['去年', '今年'];
|
} else {
|
||||||
|
timeLabel = ['去年', '今年'];
|
||||||
|
}
|
||||||
series.push(
|
series.push(
|
||||||
{
|
{
|
||||||
name: `${timeLabel[0]}金额`,
|
name: `${timeLabel[0]}金额`,
|
||||||
@@ -165,13 +166,14 @@ const getOrderCountTrendComparison = async (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3. 渲染 Echarts 界面
|
||||||
await renderEcharts(
|
await renderEcharts(
|
||||||
getTradeTrendChartOptions(dates, series, timeRangeType.value),
|
getTradeTrendChartOptions(dates, series, timeRangeType.value),
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/** 初始化 */
|
/** 初始化 */
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@@ -184,7 +186,10 @@ onMounted(() => {
|
|||||||
<template #title>
|
<template #title>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<span>交易量趋势</span>
|
<span>交易量趋势</span>
|
||||||
<RadioGroup v-model:value="timeRangeType" @change="handleTimeRangeTypeChange">
|
<RadioGroup
|
||||||
|
v-model:value="timeRangeType"
|
||||||
|
@change="handleTimeRangeTypeChange"
|
||||||
|
>
|
||||||
<Radio
|
<Radio
|
||||||
v-for="[key, value] in Object.entries(timeRangeConfig)"
|
v-for="[key, value] in Object.entries(timeRangeConfig)"
|
||||||
:key="key"
|
:key="key"
|
||||||
@@ -196,8 +201,7 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<Spin :spinning="loading">
|
<Spin :spinning="loading">
|
||||||
<EchartsUI ref="chartRef" class="h-[300px] w-full" />
|
<EchartsUI ref="chartRef" class="w-full" />
|
||||||
</Spin>
|
</Spin>
|
||||||
</Card>
|
</Card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
/**
|
/** 时间范围类型枚举 */
|
||||||
* 交易量趋势图表配置
|
export enum TimeRangeTypeEnum {
|
||||||
*/
|
DAY30 = 1,
|
||||||
|
MONTH = 30,
|
||||||
|
WEEK = 7,
|
||||||
|
YEAR = 365,
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 交易量趋势图表配置 */
|
||||||
export function getTradeTrendChartOptions(
|
export function getTradeTrendChartOptions(
|
||||||
dates: string[],
|
dates: string[],
|
||||||
series: any[],
|
series: any[],
|
||||||
timeRangeType: number,
|
timeRangeType: TimeRangeTypeEnum,
|
||||||
): any {
|
): any {
|
||||||
return {
|
return {
|
||||||
grid: {
|
grid: {
|
||||||
@@ -51,20 +57,23 @@ export function getTradeTrendChartOptions(
|
|||||||
axisLabel: {
|
axisLabel: {
|
||||||
formatter: (date: string) => {
|
formatter: (date: string) => {
|
||||||
switch (timeRangeType) {
|
switch (timeRangeType) {
|
||||||
case 1: // DAY30
|
case TimeRangeTypeEnum.DAY30: {
|
||||||
return dayjs(date).format('MM-DD');
|
return dayjs(date).format('MM-DD');
|
||||||
case 7: // WEEK
|
}
|
||||||
{
|
case TimeRangeTypeEnum.MONTH: {
|
||||||
|
return dayjs(date).format('D');
|
||||||
|
}
|
||||||
|
case TimeRangeTypeEnum.WEEK: {
|
||||||
const weekDay = dayjs(date).day();
|
const weekDay = dayjs(date).day();
|
||||||
return weekDay === 0 ? '周日' : `周${weekDay}`;
|
return weekDay === 0 ? '周日' : `周${weekDay}`;
|
||||||
}
|
}
|
||||||
case 30: // MONTH
|
case TimeRangeTypeEnum.YEAR: {
|
||||||
return dayjs(date).format('D');
|
return `${dayjs(date).format('M')}月`;
|
||||||
case 365: // YEAR
|
}
|
||||||
return dayjs(date).format('M') + '月';
|
default: {
|
||||||
default:
|
|
||||||
return date;
|
return date;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -75,4 +84,3 @@ export function getTradeTrendChartOptions(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user