Browse Source

fleat: status

igb 3 weeks ago
parent
commit
b4f7aee5c0
3 changed files with 315 additions and 1 deletions
  1. 31 1
      customers_stats.php
  2. 219 0
      statistics_customers.php
  3. 65 0
      statistics_header.php

+ 31 - 1
customers_stats.php

@@ -26,6 +26,7 @@ include('statistics_header.php');
     <div class="page-header">
         <h1 class="page-title">客户统计分析</h1>
     </div>
+
     
     <!-- 日期筛选 -->
     <div class="filter-form">
@@ -54,7 +55,36 @@ include('statistics_header.php');
             </div>
         </form>
     </div>
-    
+
+    <!-- 关键指标 -->
+    <div class="key-metrics-section">
+        <div class="section-title">
+            <h2>关键指标</h2>
+        </div>
+        <?php
+        // 获取关键指标数据
+        $total_customers = getTotalCustomers($conn);
+        $new_customers = getNewCustomers($conn, $start_date, $end_date);
+        $avg_customer_value = getAverageCustomerValue($conn, $start_date, $end_date);
+        $retention_data = getCustomerRetentionRate($conn, $start_date, $end_date);
+        $conversion_data = getOrderConversionRate($conn, $start_date, $end_date);
+
+        // 组合所有指标数据
+        $kpi_data = [
+            'total_customers' => $total_customers,
+            'new_customers' => $new_customers,
+            'avg_customer_value' => $avg_customer_value,
+            'retention_rate' => $retention_data['retention_rate'],
+            'retained_count' => $retention_data['retained_count'],
+            'total_previous' => $retention_data['total_previous'],
+            'conversion_rate' => $conversion_data['conversion_rate'],
+            'customers_with_orders' => $conversion_data['customers_with_orders']
+        ];
+
+        // 渲染关键指标卡片
+        renderKeyMetricsCard($kpi_data);
+        ?>
+    </div>
     <div class="stats-grid">
         <!-- 客户类型分布 -->
         <div class="stat-card">

+ 219 - 0
statistics_customers.php

@@ -434,4 +434,223 @@ function renderNewVsReturningCustomersChart($new_vs_returning) {
         });
     </script>
     <?php
+}
+
+/**
+ * 获取客户总数
+ * 
+ * @param mysqli $conn 数据库连接
+ * @return int 客户总数
+ */
+function getTotalCustomers($conn) {
+    $sql = "SELECT COUNT(id) as total FROM customer";
+    $result = $conn->query($sql);
+    $row = $result->fetch_assoc();
+    return $row['total'];
+}
+
+/**
+ * 获取指定时间段内新增客户数
+ * 
+ * @param mysqli $conn 数据库连接
+ * @param string $start_date 开始日期
+ * @param string $end_date 结束日期
+ * @return int 新增客户数
+ */
+function getNewCustomers($conn, $start_date, $end_date) {
+    $sql = "SELECT COUNT(id) as new_count 
+            FROM customer 
+            WHERE cs_addtime BETWEEN ? AND ?";
+    
+    $stmt = $conn->prepare($sql);
+    $stmt->bind_param("ss", $start_date, $end_date);
+    $stmt->execute();
+    $result = $stmt->get_result();
+    $row = $result->fetch_assoc();
+    return $row['new_count'];
+}
+
+/**
+ * 计算平均客户价值(客户平均订单金额)
+ * 
+ * @param mysqli $conn 数据库连接
+ * @param string $start_date 开始日期
+ * @param string $end_date 结束日期
+ * @return float 平均客户价值
+ */
+function getAverageCustomerValue($conn, $start_date, $end_date) {
+    $sql = "SELECT AVG(customer_value) as avg_value FROM (
+                SELECT 
+                    o.customer_id,
+                    SUM(o.total_amount) as customer_value
+                FROM orders o
+                WHERE o.order_date BETWEEN ? AND ?
+                GROUP BY o.customer_id
+            ) as customer_values";
+    
+    $stmt = $conn->prepare($sql);
+    $stmt->bind_param("ss", $start_date, $end_date);
+    $stmt->execute();
+    $result = $stmt->get_result();
+    $row = $result->fetch_assoc();
+    return $row['avg_value'] ? $row['avg_value'] : 0;
+}
+
+/**
+ * 计算客户留存率
+ * 
+ * @param mysqli $conn 数据库连接
+ * @param string $start_date 开始日期
+ * @param string $end_date 结束日期
+ * @return array 客户留存率数据
+ */
+function getCustomerRetentionRate($conn, $start_date, $end_date) {
+    // 获取之前时间段的客户
+    $previous_start = date('Y-m-d', strtotime('-1 year', strtotime($start_date)));
+    $previous_end = date('Y-m-d', strtotime('-1 day', strtotime($start_date)));
+    
+    // 之前时间段的客户ID
+    $prev_sql = "SELECT DISTINCT customer_id 
+                FROM orders 
+                WHERE order_date BETWEEN ? AND ?";
+    
+    $prev_stmt = $conn->prepare($prev_sql);
+    $prev_stmt->bind_param("ss", $previous_start, $previous_end);
+    $prev_stmt->execute();
+    $prev_result = $prev_stmt->get_result();
+    
+    $previous_customers = [];
+    while ($row = $prev_result->fetch_assoc()) {
+        $previous_customers[] = $row['customer_id'];
+    }
+    
+    $previous_count = count($previous_customers);
+    
+    // 如果没有之前的客户,返回0
+    if ($previous_count == 0) {
+        return [
+            'retained_count' => 0,
+            'total_previous' => 0,
+            'retention_rate' => 0
+        ];
+    }
+    
+    // 查询当前时间段内,之前客户中再次购买的客户数
+    $current_sql = "SELECT COUNT(DISTINCT customer_id) as retained_count
+                   FROM orders
+                   WHERE order_date BETWEEN ? AND ?
+                   AND customer_id IN (" . implode(',', $previous_customers) . ")";
+    
+    $current_stmt = $conn->prepare($current_sql);
+    $current_stmt->bind_param("ss", $start_date, $end_date);
+    $current_stmt->execute();
+    $current_result = $current_stmt->get_result();
+    $row = $current_result->fetch_assoc();
+    
+    $retained_count = $row['retained_count'];
+    $retention_rate = ($retained_count / $previous_count) * 100;
+    
+    return [
+        'retained_count' => $retained_count,
+        'total_previous' => $previous_count,
+        'retention_rate' => $retention_rate
+    ];
+}
+
+/**
+ * 计算下单转换率
+ * 
+ * @param mysqli $conn 数据库连接
+ * @param string $start_date 开始日期
+ * @param string $end_date 结束日期
+ * @return array 下单转换率数据
+ */
+function getOrderConversionRate($conn, $start_date, $end_date) {
+    // 获取指定时间段内总客户数
+    $total_sql = "SELECT COUNT(DISTINCT id) as total_count FROM customer WHERE cs_addtime <= ?";
+    $total_stmt = $conn->prepare($total_sql);
+    $total_stmt->bind_param("s", $end_date);
+    $total_stmt->execute();
+    $total_result = $total_stmt->get_result();
+    $total_row = $total_result->fetch_assoc();
+    $total_customers = $total_row['total_count'];
+    
+    // 获取有订单的客户数
+    $order_sql = "SELECT COUNT(DISTINCT customer_id) as order_count 
+                 FROM orders 
+                 WHERE order_date BETWEEN ? AND ?";
+    $order_stmt = $conn->prepare($order_sql);
+    $order_stmt->bind_param("ss", $start_date, $end_date);
+    $order_stmt->execute();
+    $order_result = $order_stmt->get_result();
+    $order_row = $order_result->fetch_assoc();
+    $customers_with_orders = $order_row['order_count'];
+    
+    // 计算转换率
+    $conversion_rate = ($total_customers > 0) ? ($customers_with_orders / $total_customers) * 100 : 0;
+    
+    return [
+        'total_customers' => $total_customers,
+        'customers_with_orders' => $customers_with_orders,
+        'conversion_rate' => $conversion_rate
+    ];
+}
+
+/**
+ * 渲染关键指标仪表板
+ * 
+ * @param array $kpi_data 关键指标数据
+ * @return void
+ */
+function renderKeyMetricsCard($kpi_data) {
+    ?>
+    <div class="stats-card-container">
+        <div class="stats-card">
+            <div class="stats-card-header">
+                <h3>客户总数</h3>
+            </div>
+            <div class="stats-card-body">
+                <div class="stats-card-value"><?php echo number_format($kpi_data['total_customers']); ?></div>
+            </div>
+        </div>
+        
+        <div class="stats-card">
+            <div class="stats-card-header">
+                <h3>新增客户</h3>
+            </div>
+            <div class="stats-card-body">
+                <div class="stats-card-value"><?php echo number_format($kpi_data['new_customers']); ?></div>
+            </div>
+        </div>
+        
+        <div class="stats-card">
+            <div class="stats-card-header">
+                <h3>平均客户价值</h3>
+            </div>
+            <div class="stats-card-body">
+                <div class="stats-card-value">¥<?php echo number_format($kpi_data['avg_customer_value'], 2); ?></div>
+            </div>
+        </div>
+        
+        <div class="stats-card">
+            <div class="stats-card-header">
+                <h3>客户留存率</h3>
+            </div>
+            <div class="stats-card-body">
+                <div class="stats-card-value"><?php echo number_format($kpi_data['retention_rate'], 1); ?>%</div>
+                <div class="stats-card-subtitle"><?php echo number_format($kpi_data['retained_count']); ?> / <?php echo number_format($kpi_data['total_previous']); ?></div>
+            </div>
+        </div>
+        
+        <div class="stats-card">
+            <div class="stats-card-header">
+                <h3>下单转换率</h3>
+            </div>
+            <div class="stats-card-body">
+                <div class="stats-card-value"><?php echo number_format($kpi_data['conversion_rate'], 1); ?>%</div>
+                <div class="stats-card-subtitle"><?php echo number_format($kpi_data['customers_with_orders']); ?> / <?php echo number_format($kpi_data['total_customers']); ?></div>
+            </div>
+        </div>
+    </div>
+    <?php
 } 

+ 65 - 0
statistics_header.php

@@ -209,6 +209,71 @@
         .download-btn:hover {
             background: #45a049;
         }
+        
+        /* 关键指标样式 */
+        .key-metrics-section {
+            margin-bottom: 30px;
+        }
+        
+        .section-title {
+            margin-bottom: 15px;
+        }
+        
+        .section-title h2 {
+            font-size: 20px;
+            font-weight: bold;
+            color: #333;
+            margin: 0;
+        }
+        
+        .stats-card-container {
+            display: flex;
+            flex-wrap: wrap;
+            gap: 20px;
+            justify-content: space-between;
+        }
+        
+        .stats-card {
+            background: white;
+            border-radius: 5px;
+            box-shadow: 0 2px 6px rgba(0,0,0,0.1);
+            padding: 15px;
+            min-width: 180px;
+            flex: 1;
+            transition: all 0.3s ease;
+        }
+        
+        .stats-card:hover {
+            transform: translateY(-3px);
+            box-shadow: 0 4px 8px rgba(0,0,0,0.15);
+        }
+        
+        .stats-card-header {
+            margin-bottom: 10px;
+        }
+        
+        .stats-card-header h3 {
+            font-size: 16px;
+            font-weight: bold;
+            color: #555;
+            margin: 0;
+        }
+        
+        .stats-card-body {
+            text-align: center;
+        }
+        
+        .stats-card-value {
+            font-size: 28px;
+            font-weight: bold;
+            color: #2196F3;
+        }
+        
+        .stats-card-subtitle {
+            font-size: 14px;
+            color: #777;
+            margin-top: 5px;
+        }
     </style>
 </head>
 <body>