Browse Source

feat(分享降价): 裂变分析页对接降价营销统计接口

将 mock 数据替换为 /activity/activityReduceInfo/statistic,并映射 reduce* 字段与趋势图 chartList。

Co-authored-by: Cursor <cursoragent@cursor.com>
ylong 2 tuần trước cách đây
mục cha
commit
7c700bc1f0
1 tập tin đã thay đổi với 126 bổ sung134 xóa
  1. 126 134
      src/views/marketing/shareDiscount/fission/index.vue

+ 126 - 134
src/views/marketing/shareDiscount/fission/index.vue

@@ -1,6 +1,6 @@
 <template>
     <div class="fission-analysis-container p-4">
-        <el-card class="analysis-card" shadow="never">
+        <el-card class="analysis-card" shadow="never" v-loading="loading">
             <div class="date-selector-container mb-6">
                 <!-- Top Navigation Section -->
                 <div class="date-period-selector flex items-center gap-4">
@@ -39,6 +39,7 @@
                         value-format="YYYY-MM-DD"
                         :clearable="false"
                         @change="handleDateRangeChange"
+                        style="max-width: 400px"
                     />
                     <div class="date-action-buttons">
                         <el-button type="primary" @click="fetchData"
@@ -120,7 +121,7 @@
 </template>
 
 <script setup>
-    import { ref, onMounted, computed, watch, nextTick } from 'vue';
+    import { ref, onMounted, computed, nextTick, onBeforeUnmount } from 'vue';
     import * as echarts from 'echarts';
     import dayjs from 'dayjs';
     import { ElMessage } from 'element-plus';
@@ -132,130 +133,161 @@
     const activePeriod = ref('30d');
     const chartRef = ref(null);
     let chart = null;
-    const isCustomDateRange = ref(false);
     const dateRange = ref([
         dayjs().subtract(29, 'day').format('YYYY-MM-DD'),
         dayjs().format('YYYY-MM-DD')
     ]);
     const loading = ref(false);
+    const statisticData = ref(null);
 
-    // Data
-    const statisticData = ref({
-        data: {
-            upsellHelpNum: 0,
-            upsellHelpNumComparison: '0',
-            upsellOrderNum: 0,
-            upsellOrderNumComparison: '0',
-            upsellScanNum: 0,
-            upsellScanNumComparison: '0',
-            scanJoinRate: 0,
-            scanJoinRateComparison: '0',
-            newUserRate: 0,
-            newUserRateComparison: '0',
-            conversionRate: 0,
-            conversionRateComparison: '0',
+    const formatComparison = (value) => {
+        if (value === null || value === undefined) return '0';
+        return String(value).replace('%', '');
+    };
+
+    const formatPercent = (value) => {
+        if (value === null || value === undefined || value === '') return '0%';
+        const str = String(value);
+        return str.includes('%') ? str : `${str}%`;
+    };
 
-            upsellShareNum: 0,
-            upsellHelpTimes: 0,
-            orderBookNum: 0,
-            orderTotalMoney: 0,
-            upsellTotalMoney: 0,
-            upsellFinalTotalMoney: 0
+    const formatMoney = (value) => {
+        if (value === null || value === undefined || value === '') {
+            return '¥0';
         }
-    });
+        const num = Number(value);
+        if (Number.isNaN(num)) return '¥0';
+        return `¥${num.toLocaleString('zh-CN', {
+            minimumFractionDigits: 0,
+            maximumFractionDigits: 2
+        })}`;
+    };
 
-    const trendData = ref({
-        dates: [],
-        values: []
-    });
+    const resultData = computed(() => statisticData.value?.data || {});
 
     const displayDateRange = computed(() => {
-        if (!dateRange.value) return '';
+        if (!dateRange.value?.length) return '';
+        if (dateRange.value[0] === dateRange.value[1]) {
+            return dateRange.value[0];
+        }
         return `${dateRange.value[0]} ~ ${dateRange.value[1]}`;
     });
 
     const metricsCardsData = computed(() => {
-        const data = statisticData.value.data;
+        const data = resultData.value;
         return [
             {
                 title: '分享人数',
-                value: data.upsellHelpNum,
-                change: data.upsellHelpNumComparison
+                value: data.reduceHelpNum ?? 0,
+                change: formatComparison(data.reduceHelpNumComparison)
             },
             {
                 title: '成单数',
-                value: data.upsellOrderNum,
-                change: data.upsellOrderNumComparison
+                value: data.reduceOrderNum ?? 0,
+                change: formatComparison(data.reduceOrderNumComparison)
             },
             {
                 title: '扫码人数',
-                value: data.upsellScanNum,
-                change: data.upsellScanNumComparison
+                value: data.reduceCartNum ?? 0,
+                change: formatComparison(data.reduceCartNumComparison)
             },
             {
                 title: '扫码参与率',
-                value: data.scanJoinRate + '%',
-                change: data.scanJoinRateComparison
+                value: formatPercent(data.cartJoinRate),
+                change: formatComparison(data.cartJoinRateComparison)
             },
             {
                 title: '新用户占比',
-                value: data.newUserRate + '%',
-                change: data.newUserRateComparison
+                value: formatPercent(data.newUserRate),
+                change: formatComparison(data.newUserRateComparison)
             },
             {
                 title: '转化率',
-                value: data.conversionRate + '%',
-                change: data.conversionRateComparison
+                value: formatPercent(data.conversionRate),
+                change: formatComparison(data.conversionRateComparison)
             }
         ];
     });
 
     const numberMetricsData = computed(() => {
-        const data = statisticData.value.data;
+        const data = resultData.value;
         return [
-            { label: '分享发起人数', value: data.upsellShareNum },
-            { label: '助力次数', value: data.upsellHelpTimes },
-            { label: '成单本数', value: data.orderBookNum },
-            { label: '订单总金额', value: '¥' + data.orderTotalMoney },
-            { label: '累计优惠金额', value: '¥' + data.upsellTotalMoney },
-            { label: '累计实付金额', value: '¥' + data.upsellFinalTotalMoney }
+            { label: '分享发起人数', value: data.reduceShareNum ?? 0 },
+            { label: '助力次数', value: data.reduceHelpTimes ?? 0 },
+            { label: '成单本数', value: data.orderBookNum ?? 0 },
+            { label: '订单总金额', value: formatMoney(0) },
+            {
+                label: '累计优惠金额',
+                value: formatMoney(data.reduceTotalMoney)
+            },
+            { label: '累计实付金额', value: formatMoney(0) }
         ];
     });
 
+    const chartData = computed(() => {
+        const chartList = resultData.value.chartList;
+        if (!Array.isArray(chartList) || !chartList.length) {
+            return { dates: [], values: [] };
+        }
+        return {
+            dates: chartList.map((item) => item.date),
+            values: chartList.map((item) => item.shareNum ?? 0)
+        };
+    });
+
+    const getDateRangeForAPI = () => {
+        const [start, end] = dateRange.value || [];
+        return {
+            startDate: dayjs(start || undefined)
+                .startOf('day')
+                .format('YYYY-MM-DD HH:mm:ss'),
+            endDate: dayjs(end || undefined)
+                .endOf('day')
+                .format('YYYY-MM-DD HH:mm:ss')
+        };
+    };
+
     const changePeriod = (period) => {
         activePeriod.value = period;
-        isCustomDateRange.value = false;
-
         const end = dayjs();
         let start;
 
         switch (period) {
             case 'yesterday':
                 start = end.subtract(1, 'day');
+                dateRange.value = [
+                    start.format('YYYY-MM-DD'),
+                    start.format('YYYY-MM-DD')
+                ];
                 break;
             case '7d':
                 start = end.subtract(6, 'day');
+                dateRange.value = [
+                    start.format('YYYY-MM-DD'),
+                    end.format('YYYY-MM-DD')
+                ];
                 break;
             case '15d':
                 start = end.subtract(14, 'day');
+                dateRange.value = [
+                    start.format('YYYY-MM-DD'),
+                    end.format('YYYY-MM-DD')
+                ];
                 break;
             case '30d':
+            default:
                 start = end.subtract(29, 'day');
+                dateRange.value = [
+                    start.format('YYYY-MM-DD'),
+                    end.format('YYYY-MM-DD')
+                ];
                 break;
-            default:
-                start = end;
         }
-
-        dateRange.value = [
-            start.format('YYYY-MM-DD'),
-            end.format('YYYY-MM-DD')
-        ];
         fetchData();
     };
 
     const handleDateRangeChange = () => {
         activePeriod.value = '';
-        isCustomDateRange.value = true;
     };
 
     const resetFilters = () => {
@@ -263,84 +295,43 @@
     };
 
     const fetchData = async () => {
+        const { startDate, endDate } = getDateRangeForAPI();
         loading.value = true;
         try {
-            const res = await request.get(
-                '/marketing/shareDiscount/fission/analysis',
+            const { data } = await request.get(
+                '/activity/activityReduceInfo/statistic',
                 {
                     params: {
-                        startDate: dateRange.value[0],
-                        endDate: dateRange.value[1]
+                        startDate, endDate 
                     }
                 }
             );
 
-            if (res.data) {
-                statisticData.value.data =
-                    res.data.summary || statisticData.value.data;
-                trendData.value = res.data.trend || { dates: [], values: [] };
+            if (data?.code !== 200) {
+                ElMessage.error(data?.msg || '获取数据失败');
+                return;
             }
-            ElMessage.success('数据已更新');
-            initChart();
+
+            statisticData.value = data;
+            await nextTick();
+            updateChart();
         } catch (error) {
-            // Mock data fallback
-            mockData();
-            ElMessage.success('数据已更新 (Mock)');
-            initChart();
+            console.error('Failed to fetch reduce statistic data:', error);
+            ElMessage.error('获取数据失败');
         } finally {
             loading.value = false;
         }
     };
 
-    const mockData = () => {
-        statisticData.value.data = {
-            upsellHelpNum: 1234,
-            upsellHelpNumComparison: '12.5',
-            upsellOrderNum: 567,
-            upsellOrderNumComparison: '-5.2',
-            upsellScanNum: 8901,
-            upsellScanNumComparison: '8.9',
-            scanJoinRate: 15.5,
-            scanJoinRateComparison: '2.1',
-            newUserRate: 45.2,
-            newUserRateComparison: '1.5',
-            conversionRate: 8.9,
-            conversionRateComparison: '-0.5',
-            upsellShareNum: 2345,
-            upsellHelpTimes: 6789,
-            orderBookNum: 1200,
-            orderTotalMoney: 56000,
-            upsellTotalMoney: 12000,
-            upsellFinalTotalMoney: 44000
-        };
-
-        // Generate mock trend data
-        const dates = [];
-        const values = [];
-        const start = dayjs(dateRange.value[0]);
-        const end = dayjs(dateRange.value[1]);
-        const diff = end.diff(start, 'day');
-
-        for (let i = 0; i <= diff; i++) {
-            dates.push(start.add(i, 'day').format('MM-DD'));
-            values.push(Math.floor(Math.random() * 100) + 50);
-        }
-        trendData.value = { dates, values };
-    };
-
-    const initChart = () => {
+    const updateChart = () => {
         if (!chartRef.value) return;
 
-        if (chart) {
-            chart.dispose();
+        if (!chart) {
+            chart = echarts.init(chartRef.value);
         }
 
-        chart = echarts.init(chartRef.value);
-
-        const option = {
-            tooltip: {
-                trigger: 'axis'
-            },
+        chart.setOption({
+            tooltip: { trigger: 'axis' },
             grid: {
                 left: '3%',
                 right: '4%',
@@ -350,34 +341,35 @@
             xAxis: {
                 type: 'category',
                 boundaryGap: false,
-                data: trendData.value.dates
-            },
-            yAxis: {
-                type: 'value'
+                data: chartData.value.dates
             },
+            yAxis: { type: 'value', min: 0 },
             series: [
                 {
                     name: '分享人数',
                     type: 'line',
-                    stack: 'Total',
                     smooth: true,
-                    data: trendData.value.values,
-                    areaStyle: {
-                        opacity: 0.3
-                    },
-                    itemStyle: {
-                        color: '#409EFF'
-                    }
+                    data: chartData.value.values,
+                    areaStyle: { opacity: 0.3 },
+                    itemStyle: { color: '#409EFF' }
                 }
             ]
-        };
+        });
+    };
 
-        chart.setOption(option);
+    const handleResize = () => {
+        chart?.resize();
     };
 
     onMounted(() => {
         fetchData();
-        window.addEventListener('resize', () => chart && chart.resize());
+        window.addEventListener('resize', handleResize);
+    });
+
+    onBeforeUnmount(() => {
+        window.removeEventListener('resize', handleResize);
+        chart?.dispose();
+        chart = null;
     });
 </script>