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/product/components/ProductSummary.vue | 304 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 304 insertions(+), 0 deletions(-)
diff --git a/src/views/mall/statistics/product/components/ProductSummary.vue b/src/views/mall/statistics/product/components/ProductSummary.vue
new file mode 100644
index 0000000..0669223
--- /dev/null
+++ b/src/views/mall/statistics/product/components/ProductSummary.vue
@@ -0,0 +1,304 @@
+<template>
+ <el-card shadow="never">
+ <template #header>
+ <!-- 鏍囬 -->
+ <div class="flex flex-row items-center justify-between">
+ <CardTitle title="鍟嗗搧姒傚喌" />
+ <!-- 鏌ヨ鏉′欢 -->
+ <ShortcutDateRangePicker ref="shortcutDateRangePicker" @change="getProductTrendData">
+ <el-button
+ class="ml-4"
+ @click="handleExport"
+ :loading="exportLoading"
+ v-hasPermi="['statistics:product:export']"
+ >
+ <Icon icon="ep:download" class="mr-1" />瀵煎嚭
+ </el-button>
+ </ShortcutDateRangePicker>
+ </div>
+ </template>
+ <!-- 缁熻鍊� -->
+ <el-row :gutter="16">
+ <el-col :xl="4" :md="8" :sm="24">
+ <SummaryCard
+ title="鍟嗗搧娴忚閲�"
+ tooltip="鍦ㄩ�夊畾鏉′欢涓嬶紝鎵�鏈夊晢鍝佽鎯呴〉琚闂殑娆℃暟锛屼竴涓汉鍦ㄧ粺璁℃椂闂村唴璁块棶澶氭璁颁负澶氭"
+ icon="ep:view"
+ icon-color="bg-blue-100"
+ icon-bg-color="text-blue-500"
+ prefix=""
+ :decimals="0"
+ :value="trendSummary?.value?.browseCount || 0"
+ :percent="
+ calculateRelativeRate(
+ trendSummary?.value?.browseCount,
+ trendSummary?.reference?.browseCount
+ )
+ "
+ />
+ </el-col>
+ <el-col :xl="4" :md="8" :sm="24">
+ <SummaryCard
+ title="鍟嗗搧璁垮鏁�"
+ tooltip="鍦ㄩ�夊畾鏉′欢涓嬶紝璁块棶浠讳綍鍟嗗搧璇︽儏椤电殑浜烘暟锛屼竴涓汉鍦ㄧ粺璁℃椂闂磋寖鍥村唴璁块棶澶氭鍙涓轰竴涓�"
+ icon="ep:user-filled"
+ icon-color="bg-purple-100"
+ icon-bg-color="text-purple-500"
+ prefix=""
+ :decimals="0"
+ :value="trendSummary?.value?.browseUserCount || 0"
+ :percent="
+ calculateRelativeRate(
+ trendSummary?.value?.browseUserCount,
+ trendSummary?.reference?.browseUserCount
+ )
+ "
+ />
+ </el-col>
+ <el-col :xl="4" :md="8" :sm="24">
+ <SummaryCard
+ title="鏀粯浠舵暟"
+ tooltip="鍦ㄩ�夊畾鏉′欢涓嬶紝鎴愬姛浠樻璁㈠崟鐨勫晢鍝佷欢鏁颁箣鍜�"
+ icon="fa-solid:money-check-alt"
+ icon-color="bg-yellow-100"
+ icon-bg-color="text-yellow-500"
+ prefix=""
+ :decimals="0"
+ :value="trendSummary?.value?.orderPayCount || 0"
+ :percent="
+ calculateRelativeRate(
+ trendSummary?.value?.orderPayCount,
+ trendSummary?.reference?.orderPayCount
+ )
+ "
+ />
+ </el-col>
+ <el-col :xl="4" :md="8" :sm="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?.orderPayPrice || 0)"
+ :percent="
+ calculateRelativeRate(
+ trendSummary?.value?.orderPayPrice,
+ trendSummary?.reference?.orderPayPrice
+ )
+ "
+ />
+ </el-col>
+ <el-col :xl="4" :md="8" :sm="24">
+ <SummaryCard
+ title="閫�娆句欢鏁�"
+ tooltip="鍦ㄩ�夊畾鏉′欢涓嬶紝鎴愬姛閫�娆剧殑鍟嗗搧浠舵暟涔嬪拰"
+ icon="fa-solid:wallet"
+ icon-color="bg-cyan-100"
+ icon-bg-color="text-cyan-500"
+ prefix=""
+ :decimals="0"
+ :value="trendSummary?.value?.afterSaleCount || 0"
+ :percent="
+ calculateRelativeRate(
+ trendSummary?.value?.afterSaleCount,
+ trendSummary?.reference?.afterSaleCount
+ )
+ "
+ />
+ </el-col>
+ <el-col :xl="4" :md="8" :sm="24">
+ <SummaryCard
+ title="閫�娆鹃噾棰�"
+ tooltip="鍦ㄩ�夊畾鏉′欢涓嬶紝鎴愬姛閫�娆剧殑鍟嗗搧閲戦涔嬪拰"
+ icon="fa-solid:award"
+ icon-color="bg-yellow-100"
+ icon-bg-color="text-yellow-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>
+</template>
+<script lang="ts" setup>
+import { ProductStatisticsApi, ProductStatisticsVO } from '@/api/mall/statistics/product'
+import SummaryCard from '@/components/SummaryCard/index.vue'
+import { EChartsOption } from 'echarts'
+import { DataComparisonRespVO } from '@/api/mall/statistics/common'
+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: 'ProductSummary' })
+
+const message = useMessage() // 娑堟伅寮圭獥
+
+const trendLoading = ref(true) // 鍟嗗搧鐘舵�佸姞杞戒腑
+const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑
+const trendSummary = ref<DataComparisonRespVO<ProductStatisticsVO>>() // 鍟嗗搧鐘跺喌缁熻鏁版嵁
+const shortcutDateRangePicker = ref()
+
+/** 鎶樼嚎鍥鹃厤缃� */
+const lineChartOptions = reactive<EChartsOption>({
+ dataset: {
+ dimensions: ['time', 'browseCount', 'browseUserCount', 'orderPayPrice', 'afterSaleRefundPrice'],
+ source: []
+ },
+ 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: {
+ textStyle: {
+ color: '#7F8B9C'
+ }
+ },
+ splitLine: {
+ show: true,
+ lineStyle: {
+ color: '#F5F7F9'
+ }
+ }
+ },
+ {
+ type: 'value',
+ name: '鏁伴噺',
+ axisLine: {
+ show: false
+ },
+ axisTick: {
+ show: false
+ },
+ axisLabel: {
+ textStyle: {
+ color: '#7F8B9C'
+ }
+ },
+ splitLine: {
+ show: true,
+ lineStyle: {
+ color: '#F5F7F9'
+ }
+ }
+ }
+ ]
+}) as EChartsOption
+
+/** 澶勭悊鍟嗗搧鐘跺喌鏌ヨ */
+const getProductTrendData = 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([getProductTrendSummary(), getProductStatisticsList()])
+ trendLoading.value = false
+}
+
+/** 鏌ヨ鍟嗗搧鐘跺喌鏁版嵁缁熻 */
+const getProductTrendSummary = async () => {
+ const times = shortcutDateRangePicker.value.times
+ trendSummary.value = await ProductStatisticsApi.getProductStatisticsAnalyse({ times })
+}
+
+/** 鏌ヨ鍟嗗搧鐘跺喌鏁版嵁鍒楄〃 */
+const getProductStatisticsList = async () => {
+ // 鏌ヨ鏁版嵁
+ const times = shortcutDateRangePicker.value.times
+ const list: ProductStatisticsVO[] = await ProductStatisticsApi.getProductStatisticsList({ times })
+ // 澶勭悊鏁版嵁
+ for (let item of list) {
+ item.orderPayPrice = fenToYuan(item.orderPayPrice)
+ item.afterSaleRefundPrice = fenToYuan(item.afterSaleRefundPrice)
+ }
+ // 鏇存柊 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 ProductStatisticsApi.exportProductStatisticsExcel({ times })
+ download.excel(data, '鍟嗗搧鐘跺喌.xls')
+ } catch {
+ } finally {
+ exportLoading.value = false
+ }
+}
+</script>
+<style lang="scss" scoped></style>
--
Gitblit v1.8.0