From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目
---
src/views/mall/statistics/trade/index.vue | 363 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 363 insertions(+), 0 deletions(-)
diff --git a/src/views/mall/statistics/trade/index.vue b/src/views/mall/statistics/trade/index.vue
new file mode 100644
index 0000000..0a25fd7
--- /dev/null
+++ b/src/views/mall/statistics/trade/index.vue
@@ -0,0 +1,363 @@
+<template>
+ <doc-alert title="銆愮粺璁°�戜細鍛樸�佸晢鍝併�佷氦鏄撶粺璁�" url="https://doc.iocoder.cn/mall/statistics/" />
+
+ <div class="flex flex-col">
+ <el-row :gutter="16" class="summary">
+ <el-col :sm="6" :xs="12">
+ <TradeStatisticValue
+ tooltip="鏄ㄦ棩璁㈠崟鏁伴噺"
+ title="鏄ㄦ棩璁㈠崟鏁伴噺"
+ :value="summary?.value?.yesterdayOrderCount || 0"
+ :percent="
+ calculateRelativeRate(
+ summary?.value?.yesterdayOrderCount,
+ summary?.reference?.yesterdayOrderCount
+ )
+ "
+ />
+ </el-col>
+ <el-col :sm="6" :xs="12">
+ <TradeStatisticValue
+ tooltip="鏈湀璁㈠崟鏁伴噺"
+ title="鏈湀璁㈠崟鏁伴噺"
+ :value="summary?.value?.monthOrderCount || 0"
+ :percent="
+ calculateRelativeRate(
+ summary?.value?.monthOrderCount,
+ summary?.reference?.monthOrderCount
+ )
+ "
+ />
+ </el-col>
+ <el-col :sm="6" :xs="12">
+ <TradeStatisticValue
+ tooltip="鏄ㄦ棩鏀粯閲戦"
+ title="鏄ㄦ棩鏀粯閲戦"
+ prefix="锟�"
+ :decimals="2"
+ :value="fenToYuan(summary?.value?.yesterdayPayPrice || 0)"
+ :percent="
+ calculateRelativeRate(
+ summary?.value?.yesterdayPayPrice,
+ summary?.reference?.yesterdayPayPrice
+ )
+ "
+ />
+ </el-col>
+ <el-col :sm="6" :xs="12">
+ <TradeStatisticValue
+ tooltip="鏈湀鏀粯閲戦"
+ title="鏈湀鏀粯閲戦"
+ prefix="锟�"
+ ::decimals="2"
+ :value="fenToYuan(summary?.value?.monthPayPrice || 0)"
+ :percent="
+ calculateRelativeRate(summary?.value?.monthPayPrice, summary?.reference?.monthPayPrice)
+ "
+ />
+ </el-col>
+ </el-row>
+ <el-card shadow="never">
+ <template #header>
+ <!-- 鏍囬 -->
+ <div class="flex flex-row items-center justify-between">
+ <CardTitle title="浜ゆ槗鐘跺喌" />
+ <!-- 鏌ヨ鏉′欢 -->
+ <ShortcutDateRangePicker ref="shortcutDateRangePicker" @change="getTradeTrendData">
+ <el-button
+ class="ml-4"
+ @click="handleExport"
+ :loading="exportLoading"
+ v-hasPermi="['statistics:trade:export']"
+ >
+ <Icon icon="ep:download" class="mr-1" />瀵煎嚭
+ </el-button>
+ </ShortcutDateRangePicker>
+ </div>
+ </template>
+ <!-- 缁熻鍊� -->
+ <el-row :gutter="16">
+ <el-col :md="6" :sm="12" :xs="24">
+ <SummaryCard
+ title="钀ヤ笟棰�"
+ tooltip="鍟嗗搧鏀粯閲戦銆佸厖鍊奸噾棰�"
+ icon="fa-solid:yen-sign"
+ icon-color="bg-blue-100"
+ icon-bg-color="text-blue-500"
+ prefix="锟�"
+ :decimals="2"
+ :value="fenToYuan(trendSummary?.value?.turnoverPrice || 0)"
+ :percent="
+ calculateRelativeRate(
+ trendSummary?.value?.turnoverPrice,
+ trendSummary?.reference?.turnoverPrice
+ )
+ "
+ />
+ </el-col>
+ <el-col :md="6" :sm="12" :xs="24">
+ <SummaryCard
+ title="鍟嗗搧鏀粯閲戦"
+ tooltip="鐢ㄦ埛璐拱鍟嗗搧鐨勫疄闄呮敮浠橀噾棰濓紝鍖呮嫭寰俊鏀粯銆佷綑棰濇敮浠樸�佹敮浠樺疂鏀粯銆佺嚎涓嬫敮浠橀噾棰濓紙鎷煎洟鍟嗗搧鍦ㄦ垚鍥箣鍚庤鍏ワ紝绾夸笅鏀粯璁㈠崟鍦ㄥ悗鍙扮‘璁ゆ敮浠樺悗璁″叆锛�"
+ icon="fa-solid:shopping-cart"
+ icon-color="bg-purple-100"
+ icon-bg-color="text-purple-500"
+ prefix="锟�"
+ :decimals="2"
+ :value="fenToYuan(trendSummary?.value?.orderPayPrice || 0)"
+ :percent="
+ calculateRelativeRate(
+ trendSummary?.value?.orderPayPrice,
+ trendSummary?.reference?.orderPayPrice
+ )
+ "
+ />
+ </el-col>
+ <el-col :md="6" :sm="12" :xs="24">
+ <SummaryCard
+ title="鍏呭�奸噾棰�"
+ tooltip="鐢ㄦ埛鎴愬姛鍏呭�肩殑閲戦"
+ icon="fa-solid:money-check-alt"
+ icon-color="bg-yellow-100"
+ icon-bg-color="text-yellow-500"
+ prefix="锟�"
+ :decimals="2"
+ :value="fenToYuan(trendSummary?.value?.rechargePrice || 0)"
+ :percent="
+ calculateRelativeRate(
+ trendSummary?.value?.rechargePrice,
+ trendSummary?.reference?.rechargePrice
+ )
+ "
+ />
+ </el-col>
+ <el-col :md="6" :sm="12" :xs="24">
+ <SummaryCard
+ title="鏀嚭閲戦"
+ tooltip="浣欓鏀粯閲戦銆佹敮浠樹剑閲戦噾棰濄�佸晢鍝侀��娆鹃噾棰�"
+ icon="ep:warning-filled"
+ icon-color="bg-green-100"
+ icon-bg-color="text-green-500"
+ prefix="锟�"
+ :decimals="2"
+ :value="fenToYuan(trendSummary?.value?.expensePrice || 0)"
+ :percent="
+ calculateRelativeRate(
+ trendSummary?.value?.expensePrice,
+ trendSummary?.reference?.expensePrice
+ )
+ "
+ />
+ </el-col>
+ <el-col :md="6" :sm="12" :xs="24">
+ <SummaryCard
+ title="浣欓鏀粯閲戦"
+ tooltip="鐢ㄦ埛涓嬪崟鏃朵娇鐢ㄤ綑棰濆疄闄呮敮浠樼殑閲戦"
+ icon="fa-solid:wallet"
+ icon-color="bg-cyan-100"
+ icon-bg-color="text-cyan-500"
+ prefix="锟�"
+ :decimals="2"
+ :value="fenToYuan(trendSummary?.value?.walletPayPrice || 0)"
+ :percent="
+ calculateRelativeRate(
+ trendSummary?.value?.walletPayPrice,
+ trendSummary?.reference?.walletPayPrice
+ )
+ "
+ />
+ </el-col>
+ <el-col :md="6" :sm="12" :xs="24">
+ <SummaryCard
+ title="鏀粯浣i噾閲戦"
+ tooltip="鍚庡彴缁欐帹骞垮憳鏀粯鐨勬帹骞夸剑閲戯紝浠ュ疄闄呮敮浠樹负鍑�"
+ icon="fa-solid:award"
+ icon-color="bg-yellow-100"
+ icon-bg-color="text-yellow-500"
+ prefix="锟�"
+ :decimals="2"
+ :value="fenToYuan(trendSummary?.value?.brokerageSettlementPrice || 0)"
+ :percent="
+ calculateRelativeRate(
+ trendSummary?.value?.brokerageSettlementPrice,
+ trendSummary?.reference?.brokerageSettlementPrice
+ )
+ "
+ />
+ </el-col>
+ <el-col :md="6" :sm="12" :xs="24">
+ <SummaryCard
+ title="鍟嗗搧閫�娆鹃噾棰�"
+ tooltip="鐢ㄦ埛鎴愬姛閫�娆剧殑鍟嗗搧閲戦"
+ icon="fa-solid:times-circle"
+ icon-color="bg-blue-100"
+ icon-bg-color="text-blue-500"
+ prefix="锟�"
+ :decimals="2"
+ :value="fenToYuan(trendSummary?.value?.afterSaleRefundPrice || 0)"
+ :percent="
+ calculateRelativeRate(
+ trendSummary?.value?.afterSaleRefundPrice,
+ trendSummary?.reference?.afterSaleRefundPrice
+ )
+ "
+ />
+ </el-col>
+ </el-row>
+ <!-- 鎶樼嚎鍥� -->
+ <el-skeleton :loading="trendLoading" animated>
+ <Echart :height="500" :options="lineChartOptions" />
+ </el-skeleton>
+ </el-card>
+ </div>
+</template>
+<script lang="ts" setup>
+import * as TradeStatisticsApi from '@/api/mall/statistics/trade'
+import TradeStatisticValue from './components/TradeStatisticValue.vue'
+import SummaryCard from '@/components/SummaryCard/index.vue'
+import { EChartsOption } from 'echarts'
+import { DataComparisonRespVO } from '@/api/mall/statistics/common'
+import { TradeSummaryRespVO, TradeTrendSummaryRespVO } from '@/api/mall/statistics/trade'
+import { calculateRelativeRate, fenToYuan } from '@/utils'
+import download from '@/utils/download'
+import { CardTitle } from '@/components/Card'
+import * as DateUtil from '@/utils/formatTime'
+import dayjs from 'dayjs'
+
+/** 浜ゆ槗缁熻 */
+defineOptions({ name: 'TradeStatistics' })
+
+const message = useMessage() // 娑堟伅寮圭獥
+
+const trendLoading = ref(true) // 浜ゆ槗鐘舵�佸姞杞戒腑
+const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑
+const summary = ref<DataComparisonRespVO<TradeSummaryRespVO>>() // 浜ゆ槗缁熻鏁版嵁
+const trendSummary = ref<DataComparisonRespVO<TradeTrendSummaryRespVO>>() // 浜ゆ槗鐘跺喌缁熻鏁版嵁
+const shortcutDateRangePicker = ref()
+
+/** 鎶樼嚎鍥鹃厤缃� */
+const lineChartOptions = reactive<EChartsOption>({
+ dataset: {
+ dimensions: ['date', 'turnoverPrice', 'orderPayPrice', 'rechargePrice', 'expensePrice'],
+ source: []
+ },
+ grid: {
+ left: 20,
+ right: 20,
+ bottom: 20,
+ top: 80,
+ containLabel: true
+ },
+ legend: {
+ top: 50
+ },
+ series: [
+ { name: '钀ヤ笟棰�', type: 'line', smooth: true },
+ { name: '鍟嗗搧鏀粯閲戦', type: 'line', smooth: true },
+ { name: '鍏呭�奸噾棰�', type: 'line', smooth: true },
+ { name: '鏀嚭閲戦', type: 'line', smooth: true }
+ ],
+ 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: false,
+ axisTick: {
+ show: false
+ }
+ },
+ yAxis: {
+ axisTick: {
+ show: false
+ }
+ }
+}) as EChartsOption
+
+/** 澶勭悊浜ゆ槗鐘跺喌鏌ヨ */
+const getTradeTrendData = async () => {
+ trendLoading.value = true
+ // 1. 澶勭悊鏃堕棿: 寮�濮嬩笌鎴鍦ㄥ悓涓�澶╃殑, 鎶樼嚎鍥惧嚭涓嶆潵, 闇�瑕佸欢闀夸竴澶�
+ const times = shortcutDateRangePicker.value.times
+ if (DateUtil.isSameDay(times[0], times[1])) {
+ // 鍓嶅ぉ
+ times[0] = DateUtil.formatDate(dayjs(times[0]).subtract(1, 'd'))
+ }
+ // 鏌ヨ鏁版嵁
+ await Promise.all([getTradeStatisticsAnalyse(), getTradeStatisticsList()])
+ trendLoading.value = false
+}
+
+/** 鏌ヨ浜ゆ槗缁熻 */
+const getTradeStatisticsSummary = async () => {
+ summary.value = await TradeStatisticsApi.getTradeStatisticsSummary()
+}
+
+/** 鏌ヨ浜ゆ槗鐘跺喌鏁版嵁缁熻 */
+const getTradeStatisticsAnalyse = async () => {
+ const times = shortcutDateRangePicker.value.times
+ trendSummary.value = await TradeStatisticsApi.getTradeStatisticsAnalyse({ times })
+}
+
+/** 鏌ヨ浜ゆ槗鐘跺喌鏁版嵁鍒楄〃 */
+const getTradeStatisticsList = async () => {
+ // 鏌ヨ鏁版嵁
+ const times = shortcutDateRangePicker.value.times
+ const list = await TradeStatisticsApi.getTradeStatisticsList({ times })
+ // 澶勭悊鏁版嵁
+ for (let item of list) {
+ item.turnoverPrice = fenToYuan(item.turnoverPrice)
+ item.orderPayPrice = fenToYuan(item.orderPayPrice)
+ item.rechargePrice = fenToYuan(item.rechargePrice)
+ item.expensePrice = fenToYuan(item.expensePrice)
+ }
+ // 鏇存柊 Echarts 鏁版嵁
+ if (lineChartOptions.dataset && lineChartOptions.dataset['source']) {
+ lineChartOptions.dataset['source'] = list
+ }
+}
+
+/** 瀵煎嚭鎸夐挳鎿嶄綔 */
+const handleExport = async () => {
+ try {
+ // 瀵煎嚭鐨勪簩娆$‘璁�
+ await message.exportConfirm()
+ // 鍙戣捣瀵煎嚭
+ exportLoading.value = true
+ const times = shortcutDateRangePicker.value.times
+ const data = await TradeStatisticsApi.exportTradeStatisticsExcel({ times })
+ download.excel(data, '浜ゆ槗鐘跺喌.xls')
+ } catch {
+ } finally {
+ exportLoading.value = false
+ }
+}
+
+/** 鍒濆鍖� **/
+onMounted(async () => {
+ await getTradeStatisticsSummary()
+})
+</script>
+<style lang="scss" scoped>
+.summary {
+ .el-col {
+ margin-bottom: 1rem;
+ }
+}
+</style>
--
Gitblit v1.8.0