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