feat:【mall 商城】交易统计、商品统计【antd】20%:product-summary-card.vue 完善
This commit is contained in:
@@ -41,14 +41,14 @@ export namespace MallProductStatisticsApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 获得商品统计分析 */
|
/** 获得商品统计分析 */
|
||||||
export function getProductStatisticsAnalyse(params: PageParam) {
|
export function getProductStatisticsAnalyse(params: any) {
|
||||||
return requestClient.get<
|
return requestClient.get<
|
||||||
DataComparisonRespVO<MallProductStatisticsApi.ProductStatistics>
|
DataComparisonRespVO<MallProductStatisticsApi.ProductStatistics>
|
||||||
>('/statistics/product/analyse', { params });
|
>('/statistics/product/analyse', { params });
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 获得商品状况明细 */
|
/** 获得商品状况明细 */
|
||||||
export function getProductStatisticsList(params: PageParam) {
|
export function getProductStatisticsList(params: any) {
|
||||||
return requestClient.get<MallProductStatisticsApi.ProductStatistics[]>(
|
return requestClient.get<MallProductStatisticsApi.ProductStatistics[]>(
|
||||||
'/statistics/product/list',
|
'/statistics/product/list',
|
||||||
{ params },
|
{ params },
|
||||||
@@ -56,7 +56,7 @@ export function getProductStatisticsList(params: PageParam) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 导出获得商品状况明细 Excel */
|
/** 导出获得商品状况明细 Excel */
|
||||||
export function exportProductStatisticsExcel(params: PageParam) {
|
export function exportProductStatisticsExcel(params: any) {
|
||||||
return requestClient.download('/statistics/product/export-excel', { params });
|
return requestClient.download('/statistics/product/export-excel', { params });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ const times = ref<[Dayjs, Dayjs]>(); // 日期范围
|
|||||||
const rangePickerProps = getRangePickerDefaultProps();
|
const rangePickerProps = getRangePickerDefaultProps();
|
||||||
const timeRangeOptions = [
|
const timeRangeOptions = [
|
||||||
rangePickerProps.presets[3]!, // 昨天
|
rangePickerProps.presets[3]!, // 昨天
|
||||||
rangePickerProps.presets[4]!, // 最近 7 天
|
rangePickerProps.presets[1]!, // 最近 7 天
|
||||||
rangePickerProps.presets[5]!, // 最近 30 天
|
rangePickerProps.presets[2]!, // 最近 30 天
|
||||||
];
|
];
|
||||||
const timeRangeType = ref(timeRangeOptions[1]!.label); // 默认选中第一个选项
|
const timeRangeType = ref(timeRangeOptions[1]!.label); // 默认选中第一个选项
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ import { onMounted, ref } from 'vue';
|
|||||||
import { SummaryCard } from '@vben/common-ui';
|
import { SummaryCard } from '@vben/common-ui';
|
||||||
import { IconifyIcon } from '@vben/icons';
|
import { IconifyIcon } from '@vben/icons';
|
||||||
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
|
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
|
||||||
import { fenToYuan } from '@vben/utils';
|
import { fenToYuan, isSameDay } from '@vben/utils';
|
||||||
|
|
||||||
import { Button, Card, Col, message, Row, Skeleton } from 'ant-design-vue';
|
import { Button, Card, Col, message, Row, Spin } from 'ant-design-vue';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
import * as ProductStatisticsApi from '#/api/mall/statistics/product';
|
import * as ProductStatisticsApi from '#/api/mall/statistics/product';
|
||||||
@@ -24,12 +24,11 @@ import { getProductSummaryChartOptions } from './product-summary-chart-options';
|
|||||||
/** 商品概况 */
|
/** 商品概况 */
|
||||||
defineOptions({ name: 'ProductSummaryCard' });
|
defineOptions({ name: 'ProductSummaryCard' });
|
||||||
|
|
||||||
// 消息弹窗
|
|
||||||
|
|
||||||
const trendLoading = ref(true); // 商品状态加载中
|
const trendLoading = ref(true); // 商品状态加载中
|
||||||
const exportLoading = ref(false); // 导出的加载中
|
const exportLoading = ref(false); // 导出的加载中
|
||||||
const trendSummary =
|
const trendSummary =
|
||||||
ref<DataComparisonRespVO<MallProductStatisticsApi.ProductStatistics>>(); // 商品状况统计数据
|
ref<DataComparisonRespVO<MallProductStatisticsApi.ProductStatistics>>(); // 商品状况统计数据
|
||||||
|
// TODO @AI:searchTimes;参考 /Users/yunai/Java/yudao-ui-admin-vben-v5/apps/web-antd/src/views/mall/statistics/product/modules/rank-card.vue;这样,可以去掉 shortcutDateRangePicker
|
||||||
const shortcutDateRangePicker = ref();
|
const shortcutDateRangePicker = ref();
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
@@ -39,7 +38,9 @@ const { renderEcharts } = useEcharts(chartRef);
|
|||||||
const calculateRelativeRate = (value?: number, reference?: number): string => {
|
const calculateRelativeRate = (value?: number, reference?: number): string => {
|
||||||
const refValue = Number(reference || 0);
|
const refValue = Number(reference || 0);
|
||||||
const curValue = Number(value || 0);
|
const curValue = Number(value || 0);
|
||||||
if (!refValue || refValue === 0) return '0.00';
|
if (!refValue || refValue === 0) {
|
||||||
|
return '0.00';
|
||||||
|
}
|
||||||
return (((curValue - refValue) / refValue) * 100).toFixed(2);
|
return (((curValue - refValue) / refValue) * 100).toFixed(2);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -47,14 +48,12 @@ const calculateRelativeRate = (value?: number, reference?: number): string => {
|
|||||||
const getProductTrendData = async (times?: [Dayjs, Dayjs]) => {
|
const getProductTrendData = async (times?: [Dayjs, Dayjs]) => {
|
||||||
trendLoading.value = true;
|
trendLoading.value = true;
|
||||||
try {
|
try {
|
||||||
|
// 处理时间: 开始与截止在同一天的, 折线图出不来, 需要延长一天
|
||||||
let queryTimes = times;
|
let queryTimes = times;
|
||||||
if (!queryTimes && shortcutDateRangePicker.value?.times) {
|
if (!queryTimes && shortcutDateRangePicker.value?.times) {
|
||||||
queryTimes = shortcutDateRangePicker.value.times;
|
queryTimes = shortcutDateRangePicker.value.times;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. 处理时间: 开始与截止在同一天的, 折线图出不来, 需要延长一天
|
|
||||||
if (queryTimes && isSameDay(queryTimes[0], queryTimes[1])) {
|
if (queryTimes && isSameDay(queryTimes[0], queryTimes[1])) {
|
||||||
// 前天
|
|
||||||
queryTimes[0] = dayjs(queryTimes[0]).subtract(1, 'd');
|
queryTimes[0] = dayjs(queryTimes[0]).subtract(1, 'd');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,13 +67,9 @@ const getProductTrendData = async (times?: [Dayjs, Dayjs]) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 判断是否同一天 */
|
|
||||||
const isSameDay = (date1: Dayjs, date2: Dayjs): boolean => {
|
|
||||||
return date1.format('YYYY-MM-DD') === date2.format('YYYY-MM-DD');
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 查询商品状况数据统计 */
|
/** 查询商品状况数据统计 */
|
||||||
const getProductTrendSummary = async (times?: [Dayjs, Dayjs]) => {
|
const getProductTrendSummary = async (times?: [Dayjs, Dayjs]) => {
|
||||||
|
// TODO @AI:是不是 queryTimes 直接使用 searchTimes 完事?!
|
||||||
const queryTimes = times
|
const queryTimes = times
|
||||||
? [
|
? [
|
||||||
times[0].format('YYYY-MM-DD HH:mm:ss'),
|
times[0].format('YYYY-MM-DD HH:mm:ss'),
|
||||||
@@ -88,6 +83,7 @@ const getProductTrendSummary = async (times?: [Dayjs, Dayjs]) => {
|
|||||||
|
|
||||||
/** 查询商品状况数据列表 */
|
/** 查询商品状况数据列表 */
|
||||||
const getProductStatisticsList = async (times?: [Dayjs, Dayjs]) => {
|
const getProductStatisticsList = async (times?: [Dayjs, Dayjs]) => {
|
||||||
|
// TODO @AI:是不是 queryTimes 直接使用 searchTimes 完事?!
|
||||||
// 查询数据
|
// 查询数据
|
||||||
const queryTimes = times
|
const queryTimes = times
|
||||||
? [
|
? [
|
||||||
@@ -98,18 +94,12 @@ const getProductStatisticsList = async (times?: [Dayjs, Dayjs]) => {
|
|||||||
const list: MallProductStatisticsApi.ProductStatistics[] =
|
const list: MallProductStatisticsApi.ProductStatistics[] =
|
||||||
await ProductStatisticsApi.getProductStatisticsList({ times: queryTimes });
|
await ProductStatisticsApi.getProductStatisticsList({ times: queryTimes });
|
||||||
|
|
||||||
// 处理数据
|
// 更新 Echarts 数据,数据转换由图表配置处理
|
||||||
const processedList = list.map((item) => ({
|
await renderEcharts(getProductSummaryChartOptions(list));
|
||||||
...item,
|
|
||||||
orderPayPrice: Number(fenToYuan(item.orderPayPrice)),
|
|
||||||
afterSaleRefundPrice: Number(fenToYuan(item.afterSaleRefundPrice)),
|
|
||||||
}));
|
|
||||||
|
|
||||||
// 更新 Echarts 数据
|
|
||||||
await renderEcharts(getProductSummaryChartOptions(processedList));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
|
// TODO @AI:导出有问题,参考别的模块的 confirm 更好;
|
||||||
const handleExport = async () => {
|
const handleExport = async () => {
|
||||||
try {
|
try {
|
||||||
// 导出的二次确认
|
// 导出的二次确认
|
||||||
@@ -175,7 +165,7 @@ onMounted(async () => {
|
|||||||
|
|
||||||
<!-- 统计值 -->
|
<!-- 统计值 -->
|
||||||
<Row :gutter="16" class="mb-4">
|
<Row :gutter="16" class="mb-4">
|
||||||
<Col :xl="4" :md="8" :sm="24" class="mb-4">
|
<Col :xl="8" :md="8" :sm="24" class="mb-4">
|
||||||
<SummaryCard
|
<SummaryCard
|
||||||
title="商品浏览量"
|
title="商品浏览量"
|
||||||
tooltip="在选定条件下,所有商品详情页被访问的次数,一个人在统计时间内访问多次记为多次"
|
tooltip="在选定条件下,所有商品详情页被访问的次数,一个人在统计时间内访问多次记为多次"
|
||||||
@@ -192,8 +182,7 @@ onMounted(async () => {
|
|||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
|
<Col :xl="8" :md="8" :sm="24" class="mb-4">
|
||||||
<Col :xl="4" :md="8" :sm="24" class="mb-4">
|
|
||||||
<SummaryCard
|
<SummaryCard
|
||||||
title="商品访客数"
|
title="商品访客数"
|
||||||
tooltip="在选定条件下,访问任何商品详情页的人数,一个人在统计时间范围内访问多次只记为一个"
|
tooltip="在选定条件下,访问任何商品详情页的人数,一个人在统计时间范围内访问多次只记为一个"
|
||||||
@@ -211,7 +200,7 @@ onMounted(async () => {
|
|||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col :xl="4" :md="8" :sm="24" class="mb-4">
|
<Col :xl="8" :md="8" :sm="24" class="mb-4">
|
||||||
<SummaryCard
|
<SummaryCard
|
||||||
title="支付件数"
|
title="支付件数"
|
||||||
tooltip="在选定条件下,成功付款订单的商品件数之和"
|
tooltip="在选定条件下,成功付款订单的商品件数之和"
|
||||||
@@ -228,8 +217,7 @@ onMounted(async () => {
|
|||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
|
<Col :xl="8" :md="8" :sm="24" class="mb-4">
|
||||||
<Col :xl="4" :md="8" :sm="24" class="mb-4">
|
|
||||||
<SummaryCard
|
<SummaryCard
|
||||||
title="支付金额"
|
title="支付金额"
|
||||||
tooltip="在选定条件下,成功付款订单的商品金额之和"
|
tooltip="在选定条件下,成功付款订单的商品金额之和"
|
||||||
@@ -247,8 +235,7 @@ onMounted(async () => {
|
|||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
|
<Col :xl="8" :md="8" :sm="24" class="mb-4">
|
||||||
<Col :xl="4" :md="8" :sm="24" class="mb-4">
|
|
||||||
<SummaryCard
|
<SummaryCard
|
||||||
title="退款件数"
|
title="退款件数"
|
||||||
tooltip="在选定条件下,成功退款的商品件数之和"
|
tooltip="在选定条件下,成功退款的商品件数之和"
|
||||||
@@ -266,7 +253,7 @@ onMounted(async () => {
|
|||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col :xl="4" :md="8" :sm="24" class="mb-4">
|
<Col :xl="8" :md="8" :sm="24" class="mb-4">
|
||||||
<SummaryCard
|
<SummaryCard
|
||||||
title="退款金额"
|
title="退款金额"
|
||||||
tooltip="在选定条件下,成功退款的商品金额之和"
|
tooltip="在选定条件下,成功退款的商品金额之和"
|
||||||
@@ -289,8 +276,8 @@ onMounted(async () => {
|
|||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<!-- 折线图 -->
|
<!-- 折线图 -->
|
||||||
<Skeleton :loading="trendLoading" :active="true">
|
<Spin :spinning="trendLoading">
|
||||||
<EchartsUI ref="chartRef" class="h-[500px]" />
|
<EchartsUI ref="chartRef" />
|
||||||
</Skeleton>
|
</Spin>
|
||||||
</Card>
|
</Card>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
import type { EChartsOption } from 'echarts';
|
|
||||||
|
|
||||||
/** 商品统计折线图配置 */
|
/** 商品统计折线图配置 */
|
||||||
export function getProductSummaryChartOptions(data: any[]): EChartsOption {
|
export function getProductSummaryChartOptions(data: any[]): any {
|
||||||
|
// 处理数据:将金额从分转换为元
|
||||||
|
const processedData = data.map((item) => ({
|
||||||
|
...item,
|
||||||
|
orderPayPrice: Number((item.orderPayPrice / 100).toFixed(2)),
|
||||||
|
afterSaleRefundPrice: Number((item.afterSaleRefundPrice / 100).toFixed(2)),
|
||||||
|
}));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
dataset: {
|
dataset: {
|
||||||
dimensions: [
|
dimensions: [
|
||||||
@@ -11,7 +16,7 @@ export function getProductSummaryChartOptions(data: any[]): EChartsOption {
|
|||||||
'orderPayPrice',
|
'orderPayPrice',
|
||||||
'afterSaleRefundPrice',
|
'afterSaleRefundPrice',
|
||||||
],
|
],
|
||||||
source: data,
|
source: processedData,
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: 20,
|
left: 20,
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||||||
multiple: false,
|
multiple: false,
|
||||||
},
|
},
|
||||||
toolbarConfig: {
|
toolbarConfig: {
|
||||||
refresh: false,
|
enabled: false,
|
||||||
},
|
},
|
||||||
} as VxeTableGridOptions,
|
} as VxeTableGridOptions,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -23,4 +23,4 @@ export * from './window';
|
|||||||
export { default as cloneDeep } from 'lodash.clonedeep';
|
export { default as cloneDeep } from 'lodash.clonedeep';
|
||||||
export { default as get } from 'lodash.get';
|
export { default as get } from 'lodash.get';
|
||||||
export { default as isEqual } from 'lodash.isequal';
|
export { default as isEqual } from 'lodash.isequal';
|
||||||
export { default as set } from 'lodash.set';
|
export { default as set } from 'lodash.set';
|
||||||
|
|||||||
Reference in New Issue
Block a user