diff --git a/apps/web-antd/src/views/mall/statistics/product/index.vue b/apps/web-antd/src/views/mall/statistics/product/index.vue
index df8469a91..6e6001454 100644
--- a/apps/web-antd/src/views/mall/statistics/product/index.vue
+++ b/apps/web-antd/src/views/mall/statistics/product/index.vue
@@ -1,32 +1,27 @@
-
-
-
-
-
+
+
+
+
+
+
diff --git a/apps/web-antd/src/views/mall/statistics/product/modules/product-rank-card.vue b/apps/web-antd/src/views/mall/statistics/product/modules/product-rank-card.vue
new file mode 100644
index 000000000..cfb7b667a
--- /dev/null
+++ b/apps/web-antd/src/views/mall/statistics/product/modules/product-rank-card.vue
@@ -0,0 +1,231 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ record.spuName }}
+
+
+
+
+ ¥{{ formatPrice(record.orderPayPrice) }}
+
+
+
+
+ {{ formatConvertRate(record.browseConvertPercent) }}
+
+
+
+
+
+
+
+
diff --git a/apps/web-antd/src/views/mall/statistics/product/modules/product-summary-card.vue b/apps/web-antd/src/views/mall/statistics/product/modules/product-summary-card.vue
new file mode 100644
index 000000000..93ccc17af
--- /dev/null
+++ b/apps/web-antd/src/views/mall/statistics/product/modules/product-summary-card.vue
@@ -0,0 +1,296 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web-antd/src/views/mall/statistics/product/modules/product-summary-chart-options.ts b/apps/web-antd/src/views/mall/statistics/product/modules/product-summary-chart-options.ts
new file mode 100644
index 000000000..7e64c78e6
--- /dev/null
+++ b/apps/web-antd/src/views/mall/statistics/product/modules/product-summary-chart-options.ts
@@ -0,0 +1,124 @@
+import type { EChartsOption } from 'echarts';
+
+/** 商品统计折线图配置 */
+export function getProductSummaryChartOptions(data: any[]): EChartsOption {
+ return {
+ dataset: {
+ dimensions: [
+ 'time',
+ 'browseCount',
+ 'browseUserCount',
+ 'orderPayPrice',
+ 'afterSaleRefundPrice',
+ ],
+ source: data,
+ },
+ grid: {
+ left: 20,
+ right: 20,
+ bottom: 20,
+ top: 80,
+ containLabel: true,
+ },
+ legend: {
+ top: 50,
+ },
+ series: [
+ {
+ name: '商品浏览量',
+ type: 'line',
+ smooth: true,
+ itemStyle: { color: '#B37FEB' },
+ },
+ {
+ name: '商品访客数',
+ type: 'line',
+ smooth: true,
+ itemStyle: { color: '#FFAB2B' },
+ },
+ {
+ name: '支付金额',
+ type: 'bar',
+ smooth: true,
+ yAxisIndex: 1,
+ itemStyle: { color: '#1890FF' },
+ },
+ {
+ name: '退款金额',
+ type: 'bar',
+ smooth: true,
+ yAxisIndex: 1,
+ itemStyle: { color: '#00C050' },
+ },
+ ],
+ toolbox: {
+ feature: {
+ // 数据区域缩放
+ dataZoom: {
+ yAxisIndex: false, // Y轴不缩放
+ },
+ brush: {
+ type: ['lineX', 'clear'], // 区域缩放按钮、还原按钮
+ },
+ saveAsImage: {
+ show: true,
+ name: '商品状况',
+ }, // 保存为图片
+ },
+ },
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: {
+ type: 'cross',
+ },
+ padding: [5, 10],
+ },
+ xAxis: {
+ type: 'category',
+ boundaryGap: true,
+ axisTick: {
+ show: false,
+ },
+ },
+ yAxis: [
+ {
+ type: 'value',
+ name: '金额',
+ axisLine: {
+ show: false,
+ },
+ axisTick: {
+ show: false,
+ },
+ axisLabel: {
+ color: '#7F8B9C',
+ },
+ splitLine: {
+ show: true,
+ lineStyle: {
+ color: '#F5F7F9',
+ },
+ },
+ },
+ {
+ type: 'value',
+ name: '数量',
+ axisLine: {
+ show: false,
+ },
+ axisTick: {
+ show: false,
+ },
+ axisLabel: {
+ color: '#7F8B9C',
+ },
+ splitLine: {
+ show: true,
+ lineStyle: {
+ color: '#F5F7F9',
+ },
+ },
+ },
+ ],
+ };
+}
diff --git a/apps/web-antd/src/views/mall/statistics/trade/index.vue b/apps/web-antd/src/views/mall/statistics/trade/index.vue
index 46ceb7e65..d2261fe71 100644
--- a/apps/web-antd/src/views/mall/statistics/trade/index.vue
+++ b/apps/web-antd/src/views/mall/statistics/trade/index.vue
@@ -1,32 +1,119 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web-antd/src/views/mall/statistics/trade/modules/trade-statistic-card.vue b/apps/web-antd/src/views/mall/statistics/trade/modules/trade-statistic-card.vue
new file mode 100644
index 000000000..af775ac9c
--- /dev/null
+++ b/apps/web-antd/src/views/mall/statistics/trade/modules/trade-statistic-card.vue
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+
+ 环比
+
+ {{ Math.abs(percentValue).toFixed(2) }}%
+
+
+
+
+
+
diff --git a/apps/web-antd/src/views/mall/statistics/trade/modules/trade-trend-card.vue b/apps/web-antd/src/views/mall/statistics/trade/modules/trade-trend-card.vue
new file mode 100644
index 000000000..113ceabfc
--- /dev/null
+++ b/apps/web-antd/src/views/mall/statistics/trade/modules/trade-trend-card.vue
@@ -0,0 +1,314 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web-antd/src/views/mall/statistics/trade/modules/trade-trend-chart-options.ts b/apps/web-antd/src/views/mall/statistics/trade/modules/trade-trend-chart-options.ts
new file mode 100644
index 000000000..a9af51446
--- /dev/null
+++ b/apps/web-antd/src/views/mall/statistics/trade/modules/trade-trend-chart-options.ts
@@ -0,0 +1,111 @@
+import type { EChartsOption } from 'echarts';
+
+import type { MallTradeStatisticsApi } from '#/api/mall/statistics/trade';
+
+/** 交易趋势折线图配置 */
+export function getTradeTrendChartOptions(
+ data: MallTradeStatisticsApi.TradeTrendSummary[],
+): EChartsOption {
+ return {
+ dataset: {
+ dimensions: [
+ 'time',
+ 'turnoverPrice',
+ 'orderPayPrice',
+ 'rechargePrice',
+ 'expensePrice',
+ ],
+ source: data,
+ },
+ grid: {
+ left: 20,
+ right: 20,
+ bottom: 20,
+ top: 80,
+ containLabel: true,
+ },
+ legend: {
+ top: 50,
+ },
+ series: [
+ {
+ name: '营业额',
+ type: 'line',
+ smooth: true,
+ itemStyle: { color: '#1890FF' },
+ },
+ {
+ name: '商品支付金额',
+ type: 'line',
+ smooth: true,
+ itemStyle: { color: '#722ED1' },
+ },
+ {
+ name: '充值金额',
+ type: 'line',
+ smooth: true,
+ itemStyle: { color: '#FAAD14' },
+ },
+ {
+ name: '支出金额',
+ type: 'line',
+ smooth: true,
+ itemStyle: { color: '#52C41A' },
+ },
+ ],
+ toolbox: {
+ feature: {
+ // 数据区域缩放
+ dataZoom: {
+ yAxisIndex: false, // Y轴不缩放
+ },
+ brush: {
+ type: ['lineX', 'clear'], // 区域缩放按钮、还原按钮
+ },
+ saveAsImage: {
+ show: true,
+ name: '交易状况',
+ }, // 保存为图片
+ },
+ },
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: {
+ type: 'cross',
+ },
+ padding: [5, 10],
+ formatter(params: any) {
+ let result = `
${params[0].data.time}
`;
+ params.forEach((item: any) => {
+ result += `
+
+ ${item.seriesName}: ¥${item.data[item.dimensionNames[item.encode.y[0]]]}
+
`;
+ });
+ return result;
+ },
+ },
+ xAxis: {
+ type: 'category',
+ boundaryGap: false,
+ axisTick: {
+ show: false,
+ },
+ },
+ yAxis: {
+ type: 'value',
+ axisTick: {
+ show: false,
+ },
+ axisLabel: {
+ formatter: '¥{value}',
+ },
+ splitLine: {
+ show: true,
+ lineStyle: {
+ color: '#F5F7F9',
+ },
+ },
+ },
+ };
+}