Ver Fonte

feat(statsAnalysis): add marketing analysis API and enhance marketing overview component

- Introduced new API functions for fetching marketing overview, payment trends, and activity statistics.
- Created a new `activity.js` file for utility functions related to marketing activities.
- Updated the `index.vue` component to utilize the new API for dynamic data loading and improved user interaction.
- Enhanced the `ActivityAnalysis` and `MarketingOverview` components to display fetched data with better formatting and responsiveness.
- Refactored funnel chart integration to include dynamic count labels based on activity type.
ylong há 3 dias atrás
pai
commit
8adcfe5e9c

+ 37 - 0
src/api/statsAnalysis/marketing.js

@@ -0,0 +1,37 @@
+import request from '@/utils/request';
+
+/**
+ * 营销分析-营销概要
+ */
+export async function getMarketingOverview(params) {
+    const res = await request.get('/shop/marketingStat/overview', { params });
+    if (res.data.code === 200) {
+        return res.data.data || {};
+    }
+    return Promise.reject(new Error(res.data.msg || '获取营销概要失败'));
+}
+
+/**
+ * 营销分析-支付金额趋势
+ */
+export async function getMarketingPayTrend(params) {
+    const res = await request.get('/shop/marketingStat/payTrend', { params });
+    if (res.data.code === 200) {
+        return res.data.data || [];
+    }
+    return Promise.reject(new Error(res.data.msg || '获取支付金额趋势失败'));
+}
+
+/**
+ * 营销分析-营销活动统计
+ * type:1-惊喜红包 2-分享降价 3-满减优惠 4-红包码活动
+ */
+export async function getMarketingActivityStat(params) {
+    const res = await request.get('/shop/marketingStat/activityStat', {
+        params
+    });
+    if (res.data.code === 200) {
+        return res.data.data || {};
+    }
+    return Promise.reject(new Error(res.data.msg || '获取营销活动统计失败'));
+}

+ 4 - 1
src/components/Chart/FunnelChart.vue

@@ -54,7 +54,9 @@
                 />
 
                 <!-- Text: Left -->
-                <text x="150" y="60" fill="#fff" font-size="20">领取人数</text>
+                <text x="150" y="60" fill="#fff" font-size="20">
+                    {{ countLabel }}
+                </text>
                 <text
                     x="150"
                     y="100"
@@ -141,6 +143,7 @@
     defineProps({
         visitorLabel: { type: String, default: '访客' },
         paymentLabel: { type: String, default: '支付' },
+        countLabel: { type: String, default: '领取人数' },
         visitorCount: { type: [Number, String], default: 0 },
         paymentCount: { type: [Number, String], default: 0 },
         unitPrice: { type: [Number, String], default: 0 },

+ 6 - 6
src/views/index/components/order-stat.vue

@@ -79,11 +79,11 @@
             cell('待退回订单', 'waitReturnOrderNum', 'is-orange'),
             cell('已到仓-收货超时', 'arriveReceiveTimeoutNum', 'is-green'),
             cell('已收货-审核超时', 'receiveCheckTimeoutNum', 'is-orange'),
-            cell('回收催审核', 'recycleUrgeCheckNum', 'is-orange')
+            cell('回收催审核', 'urgeCheckOrderNum', 'is-orange')
         ],
         [
-            cell('待处理复审', 'waitRecheckNum', 'is-orange'),
-            cell('待审核提醒', 'waitCheckRemindNum', 'is-green')
+            cell('待处理复审', 'waitReviewNum', 'is-orange'),
+            cell('待审核提现', 'waitAuditWithdrawNum', 'is-green')
         ]
     ]);
 
@@ -96,12 +96,12 @@
         ],
         [
             cell('投诉管理', 'complaintsNum', 'is-orange'),
-            cell('意见反馈', 'feedbackNum', 'is-green'),
-            cell('上报', 'reportNum', 'is-orange'),
+            cell('意见反馈', 'suggestionNum', 'is-green'),
+            cell('上报', 'reportOrderNum', 'is-orange'),
             cell('揽件超时', 'pickupTimeoutNum', 'is-orange')
         ],
         [
-            cell('待入库不良单', 'waitBadStockNum', 'is-orange'),
+            cell('待入库不良单', 'waitStockBadOrderNum', 'is-orange'),
             cell('待处理工单', 'waitHandleWorkOrderNum', 'is-green')
         ]
     ]);

+ 118 - 0
src/views/statsAnalysis/marketing/activity.js

@@ -0,0 +1,118 @@
+export function showValue(value) {
+    if (value == null || value === '') {
+        return 0;
+    }
+    return value;
+}
+
+export function toNumber(value) {
+    if (value == null || value === '') {
+        return 0;
+    }
+    const num = Number(value);
+    return Number.isFinite(num) ? num : 0;
+}
+
+export function formatPercent(value) {
+    if (value == null || value === '') {
+        return '0%';
+    }
+    const text = String(value);
+    return text.includes('%') ? text : `${text}%`;
+}
+
+function withUnit(value, unit) {
+    return `${showValue(value)} (${unit})`;
+}
+
+export const activityDefs = [
+    {
+        type: 1,
+        title: '惊喜红包活动',
+        countLabel: '领取人数',
+        buildStats(data) {
+            return [
+                {
+                    label: '红包拉动成交金额 (元)',
+                    value: showValue(data.payAmount)
+                },
+                {
+                    label: '参与人数 (人)',
+                    value: showValue(data.joinUserNum)
+                },
+                { label: '客单价(元)', value: showValue(data.unitPrice) },
+                {
+                    label: '订单覆盖率',
+                    value: formatPercent(data.orderCoverRate)
+                },
+                { label: '红包过期率', value: formatPercent(data.expireRate) },
+                { label: '红包使用数(张)', value: showValue(data.useNum) },
+                {
+                    label: '红包领取金额(元)',
+                    value: showValue(data.receiveAmount)
+                },
+                {
+                    label: '红包消耗金额 (元)',
+                    value: showValue(data.useAmount)
+                },
+                { label: '红包使用率', value: formatPercent(data.useRate) },
+                {
+                    label: '红包待使用金额(元)',
+                    value: showValue(data.waitUseAmount)
+                },
+                {
+                    label: '红包待使用量(张)',
+                    value: showValue(data.waitUseNum)
+                },
+                { label: '红包领取数(张)', value: showValue(data.receiveNum) }
+            ];
+        }
+    },
+    {
+        type: 2,
+        title: '分享降价活动',
+        countLabel: '参与人数',
+        buildStats(data) {
+            return [
+                {
+                    label: '营销支付金额',
+                    value: withUnit(data.payAmount, '元')
+                },
+                {
+                    label: '营销优惠金额',
+                    value: withUnit(data.discountAmount, '元')
+                },
+                { label: '参与人数', value: withUnit(data.joinUserNum, '人') },
+                {
+                    label: '支付订单数',
+                    value: withUnit(data.payOrderNum, '单')
+                },
+                { label: '客单价', value: withUnit(data.unitPrice, '元') },
+                { label: '助力人数', value: withUnit(data.helpUserNum, '人') }
+            ];
+        }
+    },
+    {
+        type: 3,
+        title: '满减优惠',
+        countLabel: '参与人数',
+        buildStats(data) {
+            return [
+                {
+                    label: '营销支付金额',
+                    value: withUnit(data.payAmount, '元')
+                },
+                {
+                    label: '营销优惠金额',
+                    value: withUnit(data.discountAmount, '元')
+                },
+                { label: '参与人数', value: withUnit(data.joinUserNum, '人') },
+                {
+                    label: '支付订单数',
+                    value: withUnit(data.payOrderNum, '单')
+                },
+                { label: '客单价', value: withUnit(data.unitPrice, '元') }
+            ];
+        }
+    }
+];

+ 17 - 8
src/views/statsAnalysis/marketing/components/ActivityAnalysis.vue

@@ -25,6 +25,7 @@
                 <div class="chart-title">流量转化</div>
                 <div class="chart-content">
                     <funnel-chart
+                        :count-label="countLabel"
                         :visitor-count="funnelData.visitorCount"
                         :payment-count="funnelData.paymentCount"
                         :unit-price="funnelData.unitPrice"
@@ -50,17 +51,25 @@
             type: Array,
             default: () => []
         },
-        newCustomerRatio: {
+        oldUserRate: {
             type: Number,
-            default: 0.6 // 60% new
+            default: 0
+        },
+        newUserRate: {
+            type: Number,
+            default: 0
+        },
+        countLabel: {
+            type: String,
+            default: '领取人数'
         },
         funnelData: {
             type: Object,
             default: () => ({
-                visitorCount: 32,
-                paymentCount: 32,
-                unitPrice: 32,
-                conversionRate: '65%'
+                visitorCount: 0,
+                paymentCount: 0,
+                unitPrice: 0,
+                conversionRate: '0%'
             })
         }
     });
@@ -101,12 +110,12 @@
                 },
                 data: [
                     {
-                        value: 1 - props.newCustomerRatio,
+                        value: props.oldUserRate,
                         name: '老客户成交占比',
                         itemStyle: { color: '#5b8ff9' }
                     },
                     {
-                        value: props.newCustomerRatio,
+                        value: props.newUserRate,
                         name: '新客户成交占比',
                         itemStyle: { color: '#5ebcb9' }
                     }

+ 137 - 110
src/views/statsAnalysis/marketing/components/MarketingOverview.vue

@@ -10,15 +10,21 @@
                 <div class="stats-row">
                     <div class="stat-item">
                         <div class="stat-label">有效活动数</div>
-                        <div class="stat-value">3</div>
+                        <div class="stat-value">{{
+                            showValue(overview.activityNum)
+                        }}</div>
                     </div>
                     <div class="stat-item">
                         <div class="stat-label">营销支付金额</div>
-                        <div class="stat-value">366994.6</div>
+                        <div class="stat-value">{{
+                            showValue(overview.marketingPayAmount)
+                        }}</div>
                     </div>
                     <div class="stat-item">
                         <div class="stat-label">营销支付金额占比</div>
-                        <div class="stat-value">15.6%</div>
+                        <div class="stat-value">{{
+                            formatPercent(overview.marketingPayRate)
+                        }}</div>
                     </div>
                 </div>
 
@@ -39,125 +45,146 @@
 </template>
 
 <script setup>
-    import { reactive } from 'vue';
+    import { computed } from 'vue';
+    import dayjs from 'dayjs';
     import BaseChart from '@/components/Chart/BaseChart.vue';
 
-    // Marketing Distribution Option (Horizontal Stacked Bar)
-    const marketingDistributionOption = reactive({
-        tooltip: {
-            trigger: 'axis',
-            axisPointer: { type: 'shadow' }
-        },
-        legend: {
-            bottom: 0,
-            data: ['惊喜红包', '分享降价', '满减优惠']
-        },
-        grid: {
-            left: '3%',
-            right: '4%',
-            bottom: '15%',
-            containLabel: true,
-            height: '60px', // Thin bar
-            top: 'center'
-        },
-        xAxis: {
-            type: 'value',
-            show: false,
-            splitLine: { show: false }
-        },
-        yAxis: {
-            type: 'category',
-            data: [''],
-            show: false,
-            splitLine: { show: false }
+    const TYPE_COLORS = {
+        1: '#d4ad5b',
+        2: '#5ebcb9',
+        3: '#4caf50',
+        4: '#5b8ff9'
+    };
+
+    const props = defineProps({
+        overview: {
+            type: Object,
+            default: () => ({})
         },
-        series: [
-            {
-                name: '惊喜红包',
-                type: 'bar',
-                stack: 'total',
-                label: { show: true, position: 'inside' },
-                emphasis: { focus: 'series' },
-                data: [100],
-                itemStyle: { color: '#d4ad5b' },
-                barWidth: 40
+        trendList: {
+            type: Array,
+            default: () => []
+        }
+    });
+
+    function showValue(value) {
+        if (value == null || value === '') {
+            return 0;
+        }
+        return value;
+    }
+
+    function formatPercent(value) {
+        if (value == null || value === '') {
+            return '0%';
+        }
+        const text = String(value);
+        return text.includes('%') ? text : `${text}%`;
+    }
+
+    function toNumber(value) {
+        if (value == null || value === '') {
+            return 0;
+        }
+        const num = Number(value);
+        return Number.isFinite(num) ? num : 0;
+    }
+
+    function formatStatDate(value) {
+        if (!value) {
+            return '';
+        }
+        const date = dayjs(value);
+        return date.isValid() ? date.format('M.D') : String(value);
+    }
+
+    const marketingDistributionOption = computed(() => {
+        const typeList = Array.isArray(props.overview.typeList)
+            ? props.overview.typeList
+            : [];
+        return {
+            tooltip: {
+                trigger: 'axis',
+                axisPointer: { type: 'shadow' }
             },
-            {
-                name: '分享降价',
-                type: 'bar',
-                stack: 'total',
-                label: { show: true, position: 'inside' },
-                emphasis: { focus: 'series' },
-                data: [300],
-                itemStyle: { color: '#5ebcb9' }
+            legend: {
+                bottom: 0,
+                data: typeList.map((item) => item.typeName || '')
+            },
+            grid: {
+                left: '3%',
+                right: '4%',
+                bottom: '15%',
+                containLabel: true,
+                height: '60px',
+                top: 'center'
             },
-            {
-                name: '满减优惠',
+            xAxis: {
+                type: 'value',
+                show: false,
+                splitLine: { show: false }
+            },
+            yAxis: {
+                type: 'category',
+                data: [''],
+                show: false,
+                splitLine: { show: false }
+            },
+            series: typeList.map((item) => ({
+                name: item.typeName || '',
                 type: 'bar',
                 stack: 'total',
                 label: { show: true, position: 'inside' },
                 emphasis: { focus: 'series' },
-                data: [100],
-                itemStyle: { color: '#4caf50' }
-            }
-        ]
+                data: [toNumber(item.payAmount)],
+                itemStyle: { color: TYPE_COLORS[item.type] || '#8c8c8c' },
+                barWidth: 40
+            }))
+        };
     });
 
-    // Payment Amount Option (Bar Chart)
-    const paymentAmountOption = reactive({
-        tooltip: {
-            trigger: 'axis',
-            axisPointer: { type: 'shadow' }
-        },
-        legend: {
-            top: 0,
-            right: 20,
-            data: ['营销金额', '非营销金额']
-        },
-        grid: {
-            left: '3%',
-            right: '4%',
-            bottom: '3%',
-            containLabel: true
-        },
-        xAxis: {
-            type: 'category',
-            data: [
-                '8.1',
-                '8.2',
-                '8.3',
-                '8.4',
-                '8.5',
-                '8.6',
-                '8.7',
-                '8.8',
-                '8.9',
-                '8.10',
-                '8.11',
-                '8.12'
-            ]
-        },
-        yAxis: {
-            type: 'value'
-        },
-        series: [
-            {
-                name: '营销金额',
-                type: 'bar',
-                data: [
-                    100, 140, 230, 100, 130, 210, 200, 180, 115, 150, 220, 120
-                ],
-                itemStyle: { color: '#5b8ff9' }
+    const paymentAmountOption = computed(() => {
+        const list = props.trendList || [];
+        return {
+            tooltip: {
+                trigger: 'axis',
+                axisPointer: { type: 'shadow' }
             },
-            {
-                name: '非营销金额',
-                type: 'bar',
-                data: [
-                    150, 100, 200, 140, 100, 230, 210, 150, 145, 210, 190, 130
-                ],
-                itemStyle: { color: '#5ebcb9' }
-            }
-        ]
+            legend: {
+                top: 0,
+                right: 20,
+                data: ['营销金额', '非营销金额']
+            },
+            grid: {
+                left: '3%',
+                right: '4%',
+                bottom: '3%',
+                containLabel: true
+            },
+            xAxis: {
+                type: 'category',
+                data: list.map((item) => formatStatDate(item.statDate))
+            },
+            yAxis: {
+                type: 'value'
+            },
+            series: [
+                {
+                    name: '营销金额',
+                    type: 'bar',
+                    data: list.map((item) => toNumber(item.marketingPayAmount)),
+                    itemStyle: { color: '#5b8ff9' }
+                },
+                {
+                    name: '非营销金额',
+                    type: 'bar',
+                    data: list.map((item) =>
+                        toNumber(item.nonMarketingPayAmount)
+                    ),
+                    itemStyle: { color: '#5ebcb9' }
+                }
+            ]
+        };
     });
 </script>
 

+ 135 - 75
src/views/statsAnalysis/marketing/index.vue

@@ -1,6 +1,6 @@
 <template>
     <ele-page>
-        <ele-card :body-style="{ padding: '20px' }">
+        <ele-card v-loading="loading" :body-style="{ padding: '20px' }">
             <!-- Header / Filters -->
             <div class="filter-container">
                 <div class="date-ranges">
@@ -8,7 +8,7 @@
                         v-for="range in dateRanges"
                         :key="range.value"
                         :type="activeRange === range.value ? 'primary' : ''"
-                        @click="activeRange = range.value"
+                        @click="handleRangeChange(range.value)"
                     >
                         {{ range.label }}
                     </el-button>
@@ -20,49 +20,57 @@
                         range-separator="到"
                         start-placeholder="开始时间"
                         end-placeholder="结束时间"
+                        value-format="YYYY-MM-DD"
+                        @change="handleDateChange"
                     />
                 </div>
                 <el-button type="primary" @click="handleSearch">搜索</el-button>
             </div>
 
-            <!-- Marketing Overview -->
-            <marketing-overview />
-
-            <!-- Surprise Red Packet Activity -->
-            <activity-analysis
-                title="惊喜红包活动"
-                :stats="redPacketStats"
-                :new-customer-ratio="0.6"
-                :funnel-data="funnelData1"
-            />
-
-            <!-- Share Price Reduction Activity -->
-            <activity-analysis
-                title="分享降价活动"
-                :stats="shareStats"
-                :new-customer-ratio="0.35"
-                :funnel-data="funnelData2"
+            <marketing-overview
+                :overview="overview"
+                :trend-list="trendList"
             />
 
-            <!-- Full Reduction Discount -->
             <activity-analysis
-                title="满减优惠"
-                :stats="fullReductionStats"
-                :new-customer-ratio="0.65"
-                :funnel-data="funnelData3"
+                v-for="item in activities"
+                :key="item.type"
+                :title="item.title"
+                :stats="item.stats"
+                :old-user-rate="item.oldUserRate"
+                :new-user-rate="item.newUserRate"
+                :count-label="item.countLabel"
+                :funnel-data="item.funnelData"
             />
         </ele-card>
     </ele-page>
 </template>
 
 <script setup>
-    import { ref } from 'vue';
+    import { computed, onMounted, ref } from 'vue';
+    import dayjs from 'dayjs';
+    import { EleMessage } from 'ele-admin-plus/es';
     import MarketingOverview from './components/MarketingOverview.vue';
     import ActivityAnalysis from './components/ActivityAnalysis.vue';
+    import {
+        getMarketingActivityStat,
+        getMarketingOverview,
+        getMarketingPayTrend
+    } from '@/api/statsAnalysis/marketing';
+    import {
+        activityDefs,
+        formatPercent,
+        showValue,
+        toNumber
+    } from './activity';
 
     // Filters
     const activeRange = ref('yesterday');
     const dateRange = ref([]);
+    const loading = ref(false);
+    const overview = ref({});
+    const trendList = ref([]);
+    const activityMap = ref({});
     const dateRanges = [
         { label: '昨日', value: 'yesterday' },
         { label: '7日', value: '7days' },
@@ -70,63 +78,115 @@
         { label: '30日', value: '30days' }
     ];
 
-    const handleSearch = () => {
-        console.log('Search clicked', activeRange.value, dateRange.value);
+    const rangeDays = {
+        '7days': 6,
+        '15days': 14,
+        '30days': 29
     };
 
-    // Mock Data
-    const redPacketStats = [
-        { label: '红包拉动成交金额 (元)', value: '1999.9' },
-        { label: '参与人数 (人)', value: '200' },
-        { label: '客单价(元)', value: '200' },
-        { label: '订单覆盖率', value: '20%' },
-        { label: '红包过期率', value: '20%' },
-        { label: '红包使用数(张)', value: '200' },
-        { label: '红包领取金额(元)', value: '200' },
-        { label: '红包消耗金额 (元)', value: '200.00' },
-        { label: '红包使用率', value: '0.10%' },
-        { label: '红包待使用金额(元)', value: '200' },
-        { label: '红包待使用量(张)', value: '200' },
-        { label: '红包领取数(张)', value: '200' }
-    ];
+    function handleSearch() {
+        if (!dateRange.value?.length) {
+            handleRangeChange('yesterday');
+            return;
+        }
+        loadData();
+    }
 
-    const shareStats = [
-        { label: '营销支付金额', value: '1999.99 (元)' },
-        { label: '营销优惠金额', value: '200.00 (元)' },
-        { label: '参与人数', value: '200.00 (人)' },
-        { label: '支付订单数', value: '200.00 (单)' },
-        { label: '客单价', value: '200.00 (元)' },
-        { label: '助力人数', value: '200.00 (人)' }
-    ];
+    const activities = computed(() =>
+        activityDefs.map((item) => {
+            const data = activityMap.value[item.type] || {};
+            return {
+                type: item.type,
+                title: item.title,
+                countLabel: item.countLabel,
+                stats: item.buildStats(data),
+                oldUserRate: toNumber(data.oldUserRate),
+                newUserRate: toNumber(data.newUserRate),
+                funnelData: {
+                    visitorCount: showValue(data.joinUserNum),
+                    paymentCount: showValue(data.payUserNum),
+                    unitPrice: showValue(data.unitPrice),
+                    conversionRate: formatPercent(data.conversionRate)
+                }
+            };
+        })
+    );
+
+    function buildDates(value) {
+        const today = dayjs();
+        if (value === 'yesterday') {
+            const day = today.subtract(1, 'day').format('YYYY-MM-DD');
+            return [day, day];
+        }
+        const offset = rangeDays[value] ?? 0;
+        return [
+            today.subtract(offset, 'day').format('YYYY-MM-DD'),
+            today.format('YYYY-MM-DD')
+        ];
+    }
 
-    const fullReductionStats = [
-        { label: '营销支付金额', value: '1999.99 (元)' },
-        { label: '营销优惠金额', value: '200.00 (元)' },
-        { label: '参与人数', value: '200.00 (人)' },
-        { label: '支付订单数', value: '200.00 (单)' },
-        { label: '客单价', value: '200.00 (元)' }
-    ];
+    function buildParams() {
+        const now = dayjs();
+        const [start, end] = dateRange.value || [];
+        const startDay = start ? dayjs(start) : now;
+        const endDay = end ? dayjs(end) : now;
+        return {
+            startTime: startDay.startOf('day').format('YYYY-MM-DD HH:mm:ss'),
+            endTime: endDay.endOf('day').format('YYYY-MM-DD HH:mm:ss')
+        };
+    }
 
-    const funnelData1 = {
-        visitorCount: 32,
-        paymentCount: 32,
-        unitPrice: 32,
-        conversionRate: '65%'
-    };
+    async function loadData() {
+        loading.value = true;
+        const params = buildParams();
+        const nextActivityMap = {};
+        await Promise.all([
+            getMarketingOverview(params)
+                .then((data) => {
+                    overview.value = data || {};
+                })
+                .catch((error) => {
+                    overview.value = {};
+                    EleMessage.error(error.message || '获取营销概要失败');
+                }),
+            getMarketingPayTrend(params)
+                .then((data) => {
+                    trendList.value = Array.isArray(data) ? data : [];
+                })
+                .catch((error) => {
+                    trendList.value = [];
+                    EleMessage.error(error.message || '获取支付金额趋势失败');
+                }),
+            ...activityDefs.map((item) =>
+                getMarketingActivityStat({ ...params, type: item.type })
+                    .then((data) => {
+                        nextActivityMap[item.type] = data || {};
+                    })
+                    .catch((error) => {
+                        nextActivityMap[item.type] = {};
+                        EleMessage.error(
+                            error.message || '获取营销活动统计失败'
+                        );
+                    })
+            )
+        ]);
+        activityMap.value = nextActivityMap;
+        loading.value = false;
+    }
 
-    const funnelData2 = {
-        visitorCount: 32,
-        paymentCount: 32,
-        unitPrice: 32,
-        conversionRate: '65%'
-    };
+    function handleRangeChange(value) {
+        activeRange.value = value;
+        dateRange.value = buildDates(value);
+        loadData();
+    }
 
-    const funnelData3 = {
-        visitorCount: 32,
-        paymentCount: 32,
-        unitPrice: 32,
-        conversionRate: '65%'
-    };
+    function handleDateChange() {
+        activeRange.value = '';
+    }
+
+    onMounted(() => {
+        handleRangeChange('yesterday');
+    });
 </script>
 
 <style scoped lang="scss">

+ 5 - 0
src/views/statsAnalysis/sellData/components/RefundStats.vue

@@ -55,6 +55,10 @@
                         <span class="label">子单退款率</span>
                         <span class="value">{{ card.refundRate }}</span>
                     </div>
+                    <div class="row">
+                        <span class="label">签收退款率</span>
+                        <span class="value">{{ card.signRefundRate }}</span>
+                    </div>
 
                     <div class="divider"></div>
 
@@ -133,6 +137,7 @@
                 refundUsers: showValue(data.refundUserNum),
                 subOrders: showValue(data.refundSubOrderNum),
                 refundRate: showRate(data.orderRefundRate),
+                signRefundRate: showRate(data.signRefundRate),
                 refundAmount: showValue(data.refundAmount),
                 amountRate: showRate(data.amountRefundRate)
             };