|
@@ -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
|
|
|
}
|