refactor: 重构商场首页和统计页面组件

- 新等组件
- 优化 Work增 AnalysisOverview、AnalysisOverviewIconbenchQuickDataShow 组件的使用
- 更新图标使用方式,移除自定义 SVG 图标
-提升页面视觉效果 调整布局和样式,
This commit is contained in:
lrl
2025-07-23 10:51:13 +08:00
parent 27a7e84def
commit 992f0bd2f0
33 changed files with 726 additions and 367 deletions

View File

@@ -1,14 +1,14 @@
<script lang="ts" setup>
import type { AnalysisOverviewItem } from '@vben/common-ui';
import type { MallMemberStatisticsApi } from '#/api/mall/statistics/member'; // 会员统计数据
import type { AnalysisOverviewIconItem } from '#/views/mall/home/components/data';
import { onMounted, ref } from 'vue';
import { AnalysisOverview, DocAlert, Page } from '@vben/common-ui';
import { SvgCakeIcon, SvgCardIcon } from '@vben/icons';
import { DocAlert, Page } from '@vben/common-ui';
import { fenToYuan } from '@vben/utils';
import * as MemberStatisticsApi from '#/api/mall/statistics/member'; // 会员统计数据
import AnalysisOverviewIcon from '#/views/mall/home/components/analysis-overview-icon.vue';
import MemberFunnelCard from '#/views/mall/home/components/member-funnel-card.vue';
import MemberTerminalCard from '#/views/mall/home/components/member-terminal-card.vue';
@@ -17,29 +17,41 @@ import MemberSexCard from './components/member-sex-card.vue';
const summary = ref<MallMemberStatisticsApi.Summary>();
const overviewItems = ref<AnalysisOverviewItem[]>([]);
const overviewItems = ref<AnalysisOverviewIconItem[]>([]);
const loadOverview = async () => {
summary.value = await MemberStatisticsApi.getMemberSummary();
overviewItems.value = [
{
icon: SvgCakeIcon, // 自定义立体用户群组图标 - 累计会员数
icon: 'fa-solid:users', // 自定义立体用户群组图标 - 累计会员数
title: '累计会员数',
value: summary.value?.userCount || 0,
iconBgColor: 'text-blue-500',
iconColor: 'bg-blue-100',
},
{
icon: SvgCardIcon, // 自定义立体信用卡图标 - 累计充值人数
icon: 'fa-solid:user', // 自定义立体信用卡图标 - 累计充值人数
title: '累计充值人数',
value: summary.value?.rechargeUserCount || 0,
iconBgColor: 'text-purple-500',
iconColor: 'bg-purple-100',
},
{
icon: SvgCardIcon, // 自定义立体钞票图标 - 累计充值金额
icon: 'fa-solid:money-check-alt', // 自定义立体钞票图标 - 累计充值金额
title: '累计充值金额',
value: summary.value?.rechargePrice || 0,
value: Number(fenToYuan(summary.value?.rechargePrice || 0)),
iconBgColor: 'text-yellow-500',
iconColor: 'bg-yellow-100',
prefix: '¥',
decimals: 2,
},
{
icon: SvgCakeIcon, // 自定义立体用户添加图标 - 今日会员注册量
title: '今日会员注册量',
value: summary.value?.expensePrice || 0,
icon: 'fa-solid:yen-sign', // 自定义立体用户添加图标 - 今日会员注册量
title: '累计消费金额',
value: Number(fenToYuan(summary.value?.expensePrice || 0)),
iconBgColor: 'text-green-500',
iconColor: 'bg-green-100',
prefix: '¥',
decimals: 2,
},
];
};
@@ -56,7 +68,7 @@ onMounted(async () => {
url="https://doc.iocoder.cn/mall/statistics/"
/>
<div class="mt-5 w-full md:flex">
<AnalysisOverview
<AnalysisOverviewIcon
v-model:model-value="overviewItems"
class="mt-5 md:mr-4 md:mt-0 md:w-full"
/>

View File

@@ -1,16 +1,16 @@
<script lang="ts" setup>
import type { AnalysisOverviewItem } from '@vben/common-ui';
import type { EchartsUIType } from '@vben/plugins/echarts';
import type { MallDataComparisonResp } from '#/api/mall/statistics/common';
import type { MallProductStatisticsApi } from '#/api/mall/statistics/product';
import type { AnalysisOverviewIconItem } from '#/views/mall/home/components/data';
import { reactive, ref } from 'vue';
import { AnalysisChartCard, AnalysisOverview, confirm } from '@vben/common-ui';
import { SvgCakeIcon, SvgCardIcon, SvgEyeIcon } from '@vben/icons';
import { confirm } from '@vben/common-ui';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
import {
calculateRelativeRate,
downloadFileFromBlobPart,
fenToYuan,
formatDate,
@@ -20,6 +20,8 @@ import {
import dayjs from 'dayjs';
import * as ProductStatisticsApi from '#/api/mall/statistics/product';
import AnalysisChartCard from '#/views/mall/home/components/analysis-chart-card.vue';
import AnalysisOverviewIcon from '#/views/mall/home/components/analysis-overview-icon.vue';
import ShortcutDateRangePicker from '#/views/mall/home/components/shortcut-date-range-picker.vue';
/** 商品概况 */
@@ -210,64 +212,88 @@ const handleExport = async () => {
}
};
const overviewItems = ref<AnalysisOverviewItem[]>();
const overviewItems = ref<AnalysisOverviewIconItem[]>();
const loadOverview = () => {
overviewItems.value = [
{
icon: SvgEyeIcon,
icon: 'ep:view',
title: '商品浏览量',
totalTitle: '昨日数据',
totalValue: trendSummary.value?.reference?.browseCount || 0,
value: trendSummary.value?.value?.browseCount || 0,
iconColor: 'bg-blue-100',
iconBgColor: 'text-blue-500',
tooltip:
'在选定条件下,所有商品详情页被访问的次数,一个人在统计时间内访问多次记为多次',
showGrowthRate: true,
percent: calculateRelativeRate(
trendSummary?.value?.value?.browseCount,
trendSummary.value?.reference?.browseCount,
),
},
{
icon: SvgCakeIcon,
icon: 'ep:user-filled',
title: '商品访客数',
totalTitle: '昨日数据',
totalValue: trendSummary.value?.reference?.browseUserCount || 0,
value: trendSummary.value?.value?.browseUserCount || 0,
iconColor: 'bg-purple-100',
iconBgColor: 'text-purple-500',
tooltip:
'在选定条件下,访问任何商品详情页的人数,一个人在统计时间范围内访问多次只记为一个',
showGrowthRate: true,
percent: calculateRelativeRate(
trendSummary?.value?.value?.browseUserCount,
trendSummary.value?.reference?.browseUserCount,
),
},
{
icon: SvgCakeIcon,
icon: 'fa-solid:money-check-alt',
title: '支付件数',
totalTitle: '昨日数据',
totalValue: trendSummary.value?.reference?.orderPayCount || 0,
iconColor: 'bg-yellow-100',
iconBgColor: 'text-yellow-500',
value: trendSummary.value?.value?.orderPayCount || 0,
tooltip: '在选定条件下,成功付款订单的商品件数之和',
showGrowthRate: true,
percent: calculateRelativeRate(
trendSummary?.value?.value?.orderPayCount,
trendSummary.value?.reference?.orderPayCount,
),
},
{
icon: SvgCardIcon,
icon: 'ep:warning-filled',
title: '支付金额',
totalTitle: '昨日数据',
totalValue: trendSummary.value?.reference?.afterSaleCount || 0,
value: trendSummary.value?.value?.orderPayPrice || 0,
iconColor: 'bg-green-100',
iconBgColor: 'text-green-500',
prefix: '¥',
value: Number(fenToYuan(trendSummary.value?.value?.orderPayPrice || 0)),
tooltip: '在选定条件下,成功付款订单的商品金额之和',
showGrowthRate: true,
decimals: 2,
percent: calculateRelativeRate(
trendSummary?.value?.value?.orderPayPrice,
trendSummary.value?.reference?.orderPayPrice,
),
},
{
icon: SvgCakeIcon,
icon: 'fa-solid:wallet',
title: '退款件数',
totalTitle: '昨日数据',
totalValue: trendSummary.value?.reference?.afterSaleCount || 0,
iconColor: 'bg-cyan-100',
iconBgColor: 'text-cyan-500',
value: trendSummary.value?.value?.afterSaleCount || 0,
tooltip: '在选定条件下,成功退款的商品件数之和',
showGrowthRate: true,
percent: calculateRelativeRate(
trendSummary?.value?.value?.afterSaleCount,
trendSummary.value?.reference?.afterSaleCount,
),
},
{
icon: SvgCardIcon,
icon: 'fa-solid:award',
title: '退款金额',
totalTitle: '昨日数据',
totalValue: trendSummary.value?.reference?.afterSaleRefundPrice || 0,
value: trendSummary.value?.value?.afterSaleRefundPrice || 0,
iconColor: 'bg-yellow-100',
iconBgColor: 'text-yellow-500',
prefix: '¥',
decimals: 2,
value: Number(
fenToYuan(trendSummary.value?.value?.afterSaleRefundPrice || 0),
),
tooltip: '在选定条件下,成功退款的商品金额之和',
showGrowthRate: true,
percent: calculateRelativeRate(
trendSummary?.value?.value?.afterSaleRefundPrice,
trendSummary.value?.reference?.afterSaleRefundPrice,
),
},
];
};
@@ -291,7 +317,7 @@ const loadOverview = () => {
</ShortcutDateRangePicker>
</template>
<!-- 统计值 -->
<AnalysisOverview
<AnalysisOverviewIcon
v-model:model-value="overviewItems"
:columns-number="6"
class="mt-5 md:mr-4 md:mt-0 md:w-full"

View File

@@ -11,7 +11,11 @@ import ProductSummary from './components/product-summary.vue';
title="【统计】会员、商品、交易统计"
url="https://doc.iocoder.cn/mall/statistics/"
/>
<ProductSummary class="md:w-3/3 mt-5 md:mr-4 md:mt-0" />
<ProductRank class="md:w-3/3 mt-5 md:mr-4 md:mt-0" />
<div class="mt-5 w-full">
<ProductSummary class="mt-5 md:mr-4 md:mt-0" />
</div>
<div class="mt-5 w-full">
<ProductRank class="mt-5 md:mr-4 md:mt-0" />
</div>
</Page>
</template>

View File

@@ -1,16 +1,15 @@
<script lang="ts" setup>
import type { AnalysisOverviewItem } from '@vben/common-ui';
import type { EchartsUIType } from '@vben/plugins/echarts';
import type { MallDataComparisonResp } from '#/api/mall/statistics/common';
import type { MallTradeStatisticsApi } from '#/api/mall/statistics/trade';
import type { AnalysisOverviewIconItem } from '#/views/mall/home/components/data';
import { reactive, ref } from 'vue';
import { AnalysisChartCard, AnalysisOverview } from '@vben/common-ui';
import { SvgCakeIcon, SvgCardIcon } from '@vben/icons';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
import {
calculateRelativeRate,
downloadFileFromBlobPart,
fenToYuan,
formatDate,
@@ -21,11 +20,13 @@ import dayjs from 'dayjs';
import { ElMessageBox } from 'element-plus';
import * as TradeStatisticsApi from '#/api/mall/statistics/trade';
import AnalysisChartCard from '#/views/mall/home/components/analysis-chart-card.vue';
import AnalysisOverviewIcon from '#/views/mall/home/components/analysis-overview-icon.vue';
import ShortcutDateRangePicker from '#/views/mall/home/components/shortcut-date-range-picker.vue';
const chartRef = ref<EchartsUIType>();
const { renderEcharts } = useEcharts(chartRef);
const overviewItems = ref<AnalysisOverviewItem[]>();
const overviewItems = ref<AnalysisOverviewIconItem[]>();
const summary =
ref<MallDataComparisonResp<MallTradeStatisticsApi.TradeTrendSummary>>();
const shortcutDateRangePicker = ref();
@@ -34,61 +35,105 @@ const trendLoading = ref(true); // 交易状态加载中
const loadOverview = () => {
overviewItems.value = [
{
icon: SvgCakeIcon,
icon: 'fa-solid:yen-sign',
title: '营业额',
value: summary?.value?.value.turnoverPrice || 0,
value: Number(fenToYuan(summary?.value?.value.turnoverPrice || 0)),
tooltip: '商品支付金额、充值金额',
totalValue: summary?.value?.reference?.turnoverPrice || 0,
showGrowthRate: true,
iconColor: 'bg-blue-100',
iconBgColor: 'text-blue-500',
prefix: '¥',
decimals: 2,
percent: calculateRelativeRate(
summary?.value?.value?.turnoverPrice,
summary?.value?.reference?.turnoverPrice,
),
},
{
icon: SvgCakeIcon,
icon: 'fa-solid:shopping-cart',
title: '商品支付金额',
value: summary.value?.value?.orderPayPrice || 0,
value: Number(fenToYuan(summary.value?.value?.orderPayPrice || 0)),
tooltip:
'用户购买商品的实际支付金额,包括微信支付、余额支付、支付宝支付、线下支付金额(拼团商品在成团之后计入,线下支付订单在后台确认支付后计入)',
totalValue: summary?.value?.reference?.orderPayPrice || 0,
showGrowthRate: true,
iconColor: 'bg-purple-100',
iconBgColor: 'text-purple-500',
prefix: '¥',
decimals: 2,
percent: calculateRelativeRate(
summary?.value?.value?.orderPayPrice,
summary?.value?.reference?.orderPayPrice,
),
},
{
icon: SvgCardIcon,
icon: 'fa-solid:money-check-alt',
title: '充值金额',
value: summary.value?.value?.rechargePrice || 0,
value: Number(fenToYuan(summary.value?.value?.rechargePrice || 0)),
tooltip: '用户成功充值的金额',
totalValue: summary?.value?.reference?.rechargePrice || 0,
showGrowthRate: true,
iconColor: 'bg-yellow-100',
iconBgColor: 'text-yellow-500',
prefix: '¥',
decimals: 2,
percent: calculateRelativeRate(
summary?.value?.value?.rechargePrice,
summary?.value?.reference?.rechargePrice,
),
},
{
icon: SvgCardIcon,
icon: 'ep:warning-filled',
title: '支出金额',
value: summary.value?.value?.expensePrice || 0,
value: Number(fenToYuan(summary.value?.value?.expensePrice || 0)),
tooltip: '余额支付金额、支付佣金金额、商品退款金额',
totalValue: summary?.value?.reference?.expensePrice || 0,
showGrowthRate: true,
iconColor: 'bg-green-100',
iconBgColor: 'text-green-500',
prefix: '¥',
decimals: 2,
percent: calculateRelativeRate(
summary?.value?.value?.expensePrice,
summary?.value?.reference?.expensePrice,
),
},
{
icon: SvgCardIcon,
icon: 'fa-solid:wallet',
title: '余额支付金额',
value: summary.value?.value?.walletPayPrice || 0,
value: Number(fenToYuan(summary.value?.value?.walletPayPrice || 0)),
tooltip: '余额支付金额、支付佣金金额、商品退款金额',
totalValue: summary?.value?.reference?.walletPayPrice || 0,
showGrowthRate: true,
iconColor: 'bg-cyan-100',
iconBgColor: 'text-cyan-500',
prefix: '¥',
decimals: 2,
percent: calculateRelativeRate(
summary?.value?.value?.walletPayPrice,
summary?.value?.reference?.walletPayPrice,
),
},
{
icon: SvgCardIcon,
icon: 'fa-solid:award',
title: '支付佣金金额',
value: summary.value?.value?.brokerageSettlementPrice || 0,
value: Number(
fenToYuan(summary.value?.value?.brokerageSettlementPrice || 0),
),
tooltip: '后台给推广员支付的推广佣金,以实际支付为准',
totalValue: summary?.value?.reference?.brokerageSettlementPrice || 0,
showGrowthRate: true,
iconColor: 'bg-yellow-100',
iconBgColor: 'text-yellow-500',
prefix: '¥',
decimals: 2,
percent: calculateRelativeRate(
summary?.value?.value?.brokerageSettlementPrice,
summary?.value?.reference?.brokerageSettlementPrice,
),
},
{
icon: SvgCardIcon,
icon: 'fa-solid:times-circle',
title: '商品退款金额',
value: summary.value?.value?.afterSaleRefundPrice || 0,
value: Number(fenToYuan(summary.value?.value?.afterSaleRefundPrice || 0)),
tooltip: '用户成功退款的商品金额',
totalValue: summary?.value?.reference?.afterSaleRefundPrice || 0,
showGrowthRate: true,
iconColor: 'bg-blue-100',
iconBgColor: 'text-blue-500',
prefix: '¥',
decimals: 2,
percent: calculateRelativeRate(
summary?.value?.value?.afterSaleRefundPrice,
summary?.value?.reference?.afterSaleRefundPrice,
),
},
];
};
@@ -229,7 +274,7 @@ const lineChartOptions = reactive({
</el-button>
</ShortcutDateRangePicker>
</template>
<AnalysisOverview v-model:model-value="overviewItems" />
<AnalysisOverviewIcon v-model:model-value="overviewItems" />
<EchartsUI height="500px" ref="chartRef" />
</AnalysisChartCard>
</template>

View File

@@ -1,54 +1,62 @@
<script lang="ts" setup>
import type { AnalysisOverviewItem } from '@vben/common-ui';
import type { MallDataComparisonResp } from '#/api/mall/statistics/common';
import type { MallTradeStatisticsApi } from '#/api/mall/statistics/trade';
import type { AnalysisOverviewTradeItem } from '#/views/mall/home/components/data';
import { onMounted, ref } from 'vue';
import { AnalysisOverview, DocAlert, Page } from '@vben/common-ui';
import { SvgCakeIcon, SvgCardIcon } from '@vben/icons';
import { DocAlert, Page } from '@vben/common-ui';
import { calculateRelativeRate, fenToYuan } from '@vben/utils';
import * as TradeStatisticsApi from '#/api/mall/statistics/trade';
import analysisTradeOverview from '#/views/mall/home/components/analysis-trade-overview.vue';
import TradeTransactionCard from './components/trade-transaction-card.vue';
const overviewItems = ref<AnalysisOverviewItem[]>();
const overviewItems = ref<AnalysisOverviewTradeItem[]>();
const summary =
ref<MallDataComparisonResp<MallTradeStatisticsApi.TradeSummary>>();
const loadOverview = () => {
overviewItems.value = [
{
icon: SvgCakeIcon,
title: '昨日订单数量',
value: summary.value?.value?.yesterdayOrderCount || 0,
tooltip: '昨日订单数量',
totalValue: summary?.value?.reference?.yesterdayOrderCount,
showGrowthRate: true,
percent: calculateRelativeRate(
summary?.value?.value?.yesterdayOrderCount,
summary.value?.reference?.yesterdayOrderCount,
),
},
{
icon: SvgCakeIcon,
title: '本月订单数量',
value: summary.value?.value?.monthOrderCount || 0,
tooltip: '本月订单数量',
totalValue: summary?.value?.reference?.monthOrderCount,
showGrowthRate: true,
percent: calculateRelativeRate(
summary?.value?.value?.monthOrderCount,
summary.value?.reference?.monthOrderCount,
),
},
{
icon: SvgCardIcon,
title: '昨日支付金额',
value: summary.value?.value?.yesterdayPayPrice || 0,
value: Number(fenToYuan(summary.value?.value?.yesterdayPayPrice || 0)),
tooltip: '昨日支付金额',
totalValue: summary?.value?.reference?.yesterdayPayPrice,
showGrowthRate: true,
prefix: '¥',
decimals: 2,
percent: calculateRelativeRate(
summary?.value?.value?.yesterdayPayPrice,
summary.value?.reference?.yesterdayPayPrice,
),
},
{
icon: SvgCardIcon,
title: '本月支付金额',
value: summary.value?.value?.monthPayPrice || 0,
tooltip: '本月支付金额',
totalValue: summary?.value?.reference?.monthPayPrice,
showGrowthRate: true,
prefix: '¥',
decimals: 2,
percent: calculateRelativeRate(
summary?.value?.value?.monthPayPrice,
summary.value?.reference?.monthPayPrice,
),
},
];
};
@@ -73,7 +81,7 @@ onMounted(async () => {
/>
<!-- 统计值 -->
<div class="mb-4 mt-5 w-full md:flex">
<AnalysisOverview
<analysisTradeOverview
v-model:model-value="overviewItems"
class="mt-5 md:mr-4 md:mt-0 md:w-full"
/>