Browse Source

fleat: warning

igb 3 weeks ago
parent
commit
62535c3f0c
1 changed files with 1138 additions and 0 deletions
  1. 1138 0
      statistics_order_warnings.php

+ 1138 - 0
statistics_order_warnings.php

@@ -0,0 +1,1138 @@
+<?php
+/**
+ * 订单预警系统 - 监控订单异常情况
+ */
+require_once 'conn.php';
+require_once 'statistics_utils.php';
+
+// 检查登录状态
+if (!isset($_SESSION['employee_id'])) {
+    checkLogin();
+}
+
+// 获取日期范围参数
+$date_params = getDateRangeParams();
+$current_start_date = $date_params['start_date_sql'];
+$current_end_date = $date_params['end_date_sql'];
+$date_range = $date_params['date_range'];
+
+// 获取选中的业务员ID
+$selected_employee = isset($_GET['employee_id']) ? intval($_GET['employee_id']) : 0;
+
+// 获取所有业务员列表
+$sql_employees = "SELECT id, em_user FROM employee ORDER BY em_user";
+$employees_result = $conn->query($sql_employees);
+
+// 计算上一个时间段范围(用于比较)
+$previous_start_date = '';
+$previous_end_date = '';
+
+// 根据当前选择的日期范围,计算上一个对比时段
+if ($date_range == 'current_month') {
+    // 上个月
+    $previous_start_date = date('Y-m-01', strtotime('-1 month', strtotime($current_start_date)));
+    $previous_end_date = date('Y-m-t', strtotime('-1 month', strtotime($current_end_date)));
+} elseif ($date_range == 'last_month') {
+    // 上上个月
+    $previous_start_date = date('Y-m-01', strtotime('-2 month', strtotime($current_start_date)));
+    $previous_end_date = date('Y-m-t', strtotime('-2 month', strtotime($current_end_date)));
+} elseif ($date_range == 'current_year') {
+    // 去年同期
+    $previous_start_date = date('Y-01-01', strtotime('-1 year', strtotime($current_start_date)));
+    $previous_end_date = date('Y-12-31', strtotime('-1 year', strtotime($current_end_date)));
+} elseif ($date_range == 'last_30_days' || $date_range == 'last_90_days' || $date_range == 'custom') {
+    // 上一个同长度周期
+    $date_diff = (strtotime($current_end_date) - strtotime($current_start_date)) / (60 * 60 * 24);
+    $previous_end_date = date('Y-m-d', strtotime('-1 day', strtotime($current_start_date)));
+    $previous_start_date = date('Y-m-d', strtotime("-{$date_diff} day", strtotime($previous_end_date)));
+}
+
+// 阈值设置(可以移到数据库或配置文件中)
+$order_amount_decrease_threshold = -15; // 订单金额下降超过15%触发预警
+$repurchase_cycle_max_threshold = 90; // 复购周期超过90天触发预警
+$repurchase_cycle_min_threshold = 0.5; // 复购周期小于正常值的50%触发预警(异常频繁购买)
+$inactive_threshold = 60; // 60天未购买视为不活跃客户
+$normal_repurchase_days = 30; // 正常复购周期参考值(天)
+
+// 页面头部
+include('statistics_header.php');
+?>
+
+<div class="container">
+    <div class="page-header">
+        <h1 class="page-title">订单预警系统</h1>
+        <p class="page-description">监控订单异常情况,提前预警潜在问题</p>
+    </div>
+    
+    <!-- 日期筛选 -->
+    <div class="filter-form">
+        <form method="get" class="filter-form-inline">
+            <div class="form-group">
+                <label for="date_range">分析周期</label>
+                <select class="form-control" id="date_range" name="date_range" onchange="toggleCustomDates()">
+                    <option value="current_month" <?php echo $date_range == 'current_month' ? 'selected' : ''; ?>>本月</option>
+                    <option value="last_month" <?php echo $date_range == 'last_month' ? 'selected' : ''; ?>>上月</option>
+                    <option value="current_year" <?php echo $date_range == 'current_year' ? 'selected' : ''; ?>>今年</option>
+                    <option value="last_30_days" <?php echo $date_range == 'last_30_days' ? 'selected' : ''; ?>>最近30天</option>
+                    <option value="last_90_days" <?php echo $date_range == 'last_90_days' ? 'selected' : ''; ?>>最近90天</option>
+                    <option value="custom" <?php echo $date_range == 'custom' ? 'selected' : ''; ?>>自定义日期范围</option>
+                </select>
+            </div>
+            <div class="form-group custom-date-inputs" id="custom_start_date" style="display: <?php echo $date_range == 'custom' ? 'inline-block' : 'none'; ?>">
+                <label for="start_date">开始日期</label>
+                <input type="date" class="form-control" id="start_date" name="start_date" value="<?php echo $date_params['custom_start']; ?>">
+            </div>
+            <div class="form-group custom-date-inputs" id="custom_end_date" style="display: <?php echo $date_range == 'custom' ? 'inline-block' : 'none'; ?>">
+                <label for="end_date">结束日期</label>
+                <input type="date" class="form-control" id="end_date" name="end_date" value="<?php echo $date_params['custom_end']; ?>">
+            </div>
+            <div class="form-group">
+                <label for="employee_id">业务员</label>
+                <select class="form-control" id="employee_id" name="employee_id">
+                    <option value="0">全部业务员</option>
+                    <?php while ($emp = $employees_result->fetch_assoc()): ?>
+                    <option value="<?php echo $emp['id']; ?>" <?php echo $selected_employee == $emp['id'] ? 'selected' : ''; ?>><?php echo htmlspecialchars($emp['em_user']); ?></option>
+                    <?php endwhile; ?>
+                </select>
+            </div>
+            <div class="form-group">
+                <button type="submit" class="form-btn form-btn-primary">应用筛选</button>
+            </div>
+        </form>
+    </div>
+    
+    <!-- 预警概览 -->
+    <div class="warnings-overview">
+        <div class="row">
+            <?php
+            // 获取总预警数
+            $sql_total_warnings = "SELECT 
+                (SELECT COUNT(*) FROM customer WHERE cs_deal = 3) as total_customers,
+                (SELECT COUNT(DISTINCT customer_id) FROM orders WHERE order_date BETWEEN ? AND ?) as active_customers";
+            
+            $stmt = $conn->prepare($sql_total_warnings);
+            $stmt->bind_param("ss", $current_start_date, $current_end_date);
+            $stmt->execute();
+            $result = $stmt->get_result();
+            $warning_count = $result->fetch_assoc();
+            
+            // 获取订单金额下降的客户数
+            $decreasing_amount_count = getDecreasingOrderAmountCustomers($conn, $current_start_date, $current_end_date, $previous_start_date, $previous_end_date, $order_amount_decrease_threshold, true, $selected_employee);
+            
+            // 获取复购周期异常的客户数
+            $abnormal_cycle_count = getAbnormalRepurchaseCycleCustomers($conn, $current_start_date, $current_end_date, $repurchase_cycle_max_threshold, $repurchase_cycle_min_threshold, $normal_repurchase_days, true, $selected_employee);
+            
+            // 获取长期不活跃客户数
+            $inactive_customers_count = getInactiveCustomers($conn, $current_end_date, $inactive_threshold, true, 1, 10, $selected_employee);
+            ?>
+            
+            <div class="col-md-3">
+                <div class="stat-card warning">
+                    <h3>订单金额下降客户</h3>
+                    <div class="stat-value"><?php echo $decreasing_amount_count; ?></div>
+                    <div class="stat-desc">金额下降超过<?php echo abs($order_amount_decrease_threshold); ?>%</div>
+                </div>
+            </div>
+            
+            <div class="col-md-3">
+                <div class="stat-card warning">
+                    <h3>复购周期异常客户</h3>
+                    <div class="stat-value"><?php echo $abnormal_cycle_count; ?></div>
+                    <div class="stat-desc">周期异常或不规律</div>
+                </div>
+            </div>
+            
+            <div class="col-md-3">
+                <div class="stat-card danger">
+                    <h3>长期不活跃客户</h3>
+                    <div class="stat-value"><?php echo $inactive_customers_count; ?></div>
+                    <div class="stat-desc"><?php echo $inactive_threshold; ?>天以上未下单</div>
+                </div>
+            </div>
+            
+            <div class="col-md-3">
+                <div class="stat-card info">
+                    <h3>客户活跃率</h3>
+                    <div class="stat-value">
+                        <?php 
+                        $active_rate = ($warning_count['total_customers'] > 0) ? 
+                            round(($warning_count['active_customers'] / $warning_count['total_customers']) * 100, 1) : 0;
+                        echo $active_rate . '%'; 
+                        ?>
+                    </div>
+                    <div class="stat-desc">选定周期内下单客户占比</div>
+                </div>
+            </div>
+        </div>
+    </div>
+    
+    <!-- 订单金额下降客户列表 -->
+    <div class="warning-section">
+        <div class="section-header">
+            <h2>订单金额下降客户</h2>
+            <p>与上一周期相比,订单金额显著下降的客户</p>
+        </div>
+        
+        <table class="data-table">
+            <thead>
+                <tr>
+                    <th>客户名称</th>
+                    <th>本期订单金额</th>
+                    <th>上期订单金额</th>
+                    <th>变化百分比</th>
+                    <th>最近订单日期</th>
+                    <th>业务员</th>
+                    <th>操作</th>
+                </tr>
+            </thead>
+            <tbody>
+                <?php
+                $decreasing_customers = getDecreasingOrderAmountCustomers(
+                    $conn, 
+                    $current_start_date, 
+                    $current_end_date, 
+                    $previous_start_date, 
+                    $previous_end_date, 
+                    $order_amount_decrease_threshold,
+                    false,
+                    $selected_employee
+                );
+                
+                while ($customer = $decreasing_customers->fetch_assoc()) {
+                    $change_percent = round((($customer['current_amount'] - $customer['previous_amount']) / $customer['previous_amount']) * 100, 1);
+                    $change_class = $change_percent < -20 ? 'text-danger' : 'text-warning';
+                    
+                    echo "<tr>";
+                    echo "<td>" . htmlspecialchars($customer['cs_company']) . "</td>";
+                    echo "<td>¥" . number_format($customer['current_amount'], 2) . "</td>";
+                    echo "<td>¥" . number_format($customer['previous_amount'], 2) . "</td>";
+                    echo "<td class='{$change_class}'>" . $change_percent . "%</td>";
+                    echo "<td>" . $customer['last_order_date'] . "</td>";
+                    echo "<td>" . htmlspecialchars($customer['em_user']) . "</td>";
+                    echo "<td><a href='customer_detail.php?id=" . $customer['id'] . "' class='action-btn action-btn-view'>查看</a></td>";
+                    echo "</tr>";
+                }
+                
+                if ($decreasing_customers->num_rows == 0) {
+                    echo "<tr><td colspan='7' class='text-center'>没有发现订单金额下降的客户</td></tr>";
+                }
+                ?>
+            </tbody>
+        </table>
+    </div>
+    
+    <!-- 复购周期异常客户列表 -->
+    <div class="warning-section">
+        <div class="section-header">
+            <h2>复购周期异常客户</h2>
+            <p>复购周期异常延长或缩短的客户</p>
+        </div>
+        
+        <table class="data-table">
+            <thead>
+                <tr>
+                    <th>客户名称</th>
+                    <th>平均复购周期(天)</th>
+                    <th>最近复购周期(天)</th>
+                    <th>偏离正常值</th>
+                    <th>最近订单日期</th>
+                    <th>订单总数</th>
+                    <th>业务员</th>
+                    <th>操作</th>
+                </tr>
+            </thead>
+            <tbody>
+                <?php
+                $abnormal_customers = getAbnormalRepurchaseCycleCustomers(
+                    $conn, 
+                    $current_start_date, 
+                    $current_end_date, 
+                    $repurchase_cycle_max_threshold, 
+                    $repurchase_cycle_min_threshold,
+                    $normal_repurchase_days,
+                    false,
+                    $selected_employee
+                );
+                
+                while ($customer = $abnormal_customers->fetch_assoc()) {
+                    $deviation = round((($customer['recent_cycle'] - $normal_repurchase_days) / $normal_repurchase_days) * 100, 1);
+                    $deviation_text = $deviation > 0 ? "+{$deviation}%" : "{$deviation}%";
+                    $deviation_class = $deviation > 50 ? 'text-danger' : ($deviation < -30 ? 'text-warning' : 'text-info');
+                    
+                    echo "<tr>";
+                    echo "<td>" . htmlspecialchars($customer['cs_company']) . "</td>";
+                    echo "<td>" . round($customer['avg_cycle'], 1) . "</td>";
+                    echo "<td>" . round($customer['recent_cycle'], 1) . "</td>";
+                    echo "<td class='{$deviation_class}'>" . $deviation_text . "</td>";
+                    echo "<td>" . $customer['last_order_date'] . "</td>";
+                    echo "<td>" . $customer['order_count'] . "</td>";
+                    echo "<td>" . htmlspecialchars($customer['em_user']) . "</td>";
+                    echo "<td><a href='customer_detail.php?id=" . $customer['id'] . "' class='action-btn action-btn-view'>查看</a></td>";
+                    echo "</tr>";
+                }
+                
+                if ($abnormal_customers->num_rows == 0) {
+                    echo "<tr><td colspan='8' class='text-center'>没有发现复购周期异常的客户</td></tr>";
+                }
+                ?>
+            </tbody>
+        </table>
+    </div>
+    
+    <!-- 长期不活跃客户列表 -->
+    <div class="warning-section" id="inactive-customers">
+        <div class="section-header">
+            <h2>长期不活跃客户</h2>
+            <p>超过<?php echo $inactive_threshold; ?>天未下单的客户</p>
+        </div>
+        
+        <table class="data-table">
+            <thead>
+                <tr>
+                    <th>客户编码</th>
+                    <th>客户名称</th>
+                    <th>最后订单日期</th>
+                    <th>不活跃天数</th>
+                    <th>历史订单数</th>
+                    <th>历史订单总额</th>
+                    <th>业务员</th>
+                    <th>操作</th>
+                </tr>
+            </thead>
+            <tbody>
+                <?php
+                // 获取分页参数
+                $page = isset($_GET['inactive_page']) ? intval($_GET['inactive_page']) : 1;
+                $page_size = 10; // 每页显示10条记录
+                
+                // 获取总记录数
+                $total_inactive = getInactiveCustomers($conn, $current_end_date, $inactive_threshold, true, 1, 10, $selected_employee);
+                
+                // 计算总页数
+                $total_pages = ceil($total_inactive / $page_size);
+                
+                // 确保页码合法
+                if ($page < 1) $page = 1;
+                if ($page > $total_pages && $total_pages > 0) $page = $total_pages;
+                
+                // 获取当页数据
+                $inactive_customers = getInactiveCustomers($conn, $current_end_date, $inactive_threshold, false, $page, $page_size, $selected_employee);
+                
+                while ($customer = $inactive_customers->fetch_assoc()) {
+                    $inactive_days = $customer['inactive_days'];
+                    $inactive_class = $inactive_days > 90 ? 'text-danger' : 'text-warning';
+                    
+                    echo "<tr>";
+                    echo "<td title='{$customer['cs_code']}'>" . htmlspecialchars($customer['cs_code']) . "</td>";
+                    echo "<td>" . htmlspecialchars($customer['cs_company'] ?: '未填写') . "</td>";
+                    echo "<td>" . ($customer['last_order_date'] ? $customer['last_order_date'] : '从未下单') . "</td>";
+                    echo "<td class='{$inactive_class}'>" . $inactive_days . "</td>";
+                    echo "<td>" . $customer['order_count'] . "</td>";
+                    echo "<td>¥" . number_format($customer['total_amount'], 2) . "</td>";
+                    echo "<td>" . htmlspecialchars($customer['em_user']) . "</td>";
+                    echo "<td><a href='customer_detail.php?id=" . $customer['id'] . "' class='action-btn action-btn-view'>查看</a></td>";
+                    echo "</tr>";
+                }
+                
+                if ($inactive_customers->num_rows == 0) {
+                    echo "<tr><td colspan='8' class='text-center'>没有发现长期不活跃的客户</td></tr>";
+                }
+                ?>
+            </tbody>
+        </table>
+        
+        <!-- 分页控件 -->
+        <?php if ($total_pages > 1): ?>
+        <div class="pagination-container">
+            <ul class="pagination">
+                <?php
+                // 生成分页链接的基础URL
+                $base_url = '?';
+                foreach ($_GET as $key => $value) {
+                    if ($key != 'inactive_page') {
+                        $base_url .= $key . '=' . urlencode($value) . '&';
+                    }
+                }
+                
+                // 上一页链接
+                if ($page > 1) {
+                    echo "<li class='pager-item'><a class='pager-link' href='{$base_url}inactive_page=" . ($page - 1) . "#inactive-customers'>上一页</a></li>";
+                } else {
+                    echo "<li class='pager-item disabled'><a class='pager-link' href='#inactive-customers'>上一页</a></li>";
+                }
+                
+                // 页码链接
+                $start_page = max(1, $page - 2);
+                $end_page = min($total_pages, $page + 2);
+                
+                if ($start_page > 1) {
+                    echo "<li class='pager-item'><a class='pager-link' href='{$base_url}inactive_page=1#inactive-customers'>1</a></li>";
+                    if ($start_page > 2) {
+                        echo "<li class='pager-item disabled'><a class='pager-link' href='#inactive-customers'>...</a></li>";
+                    }
+                }
+                
+                for ($i = $start_page; $i <= $end_page; $i++) {
+                    if ($i == $page) {
+                        echo "<li class='pager-item active'><a class='pager-link' href='#inactive-customers'>{$i}</a></li>";
+                    } else {
+                        echo "<li class='pager-item'><a class='pager-link' href='{$base_url}inactive_page={$i}#inactive-customers'>{$i}</a></li>";
+                    }
+                }
+                
+                if ($end_page < $total_pages) {
+                    if ($end_page < $total_pages - 1) {
+                        echo "<li class='pager-item disabled'><a class='pager-link' href='#inactive-customers'>...</a></li>";
+                    }
+                    echo "<li class='pager-item'><a class='pager-link' href='{$base_url}inactive_page={$total_pages}#inactive-customers'>{$total_pages}</a></li>";
+                }
+                
+                // 下一页链接
+                if ($page < $total_pages) {
+                    echo "<li class='pager-item'><a class='pager-link' href='{$base_url}inactive_page=" . ($page + 1) . "#inactive-customers'>下一页</a></li>";
+                } else {
+                    echo "<li class='pager-item disabled'><a class='pager-link' href='#inactive-customers'>下一页</a></li>";
+                }
+                ?>
+            </ul>
+            <div class="pagination-info">
+                共 <?php echo $total_inactive; ?> 条记录,当前显示第 <?php echo $page; ?> 页,共 <?php echo $total_pages; ?> 页
+            </div>
+        </div>
+        <?php endif; ?>
+    </div>
+    
+    <!-- 总体订单趋势图 -->
+    <div class="chart-section">
+        <div class="section-header">
+            <h2>总体订单趋势</h2>
+            <p>最近12个月的订单数量和金额趋势</p>
+        </div>
+        
+        <div class="chart-container">
+            <canvas id="orderTrendChart"></canvas>
+        </div>
+        
+        <?php
+        // 获取最近12个月的订单趋势数据
+        $sql_trend = "SELECT 
+            DATE_FORMAT(order_date, '%Y-%m') as month,
+            COUNT(*) as order_count,
+            SUM(total_amount) as total_amount
+        FROM orders
+        WHERE order_date >= DATE_SUB(?, INTERVAL 11 MONTH)
+        GROUP BY DATE_FORMAT(order_date, '%Y-%m')
+        ORDER BY month";
+        
+        $stmt = $conn->prepare($sql_trend);
+        $stmt->bind_param("s", $current_end_date);
+        $stmt->execute();
+        $trend_result = $stmt->get_result();
+        
+        $months = [];
+        $order_counts = [];
+        $order_amounts = [];
+        
+        while ($row = $trend_result->fetch_assoc()) {
+            $months[] = $row['month'];
+            $order_counts[] = $row['order_count'];
+            $order_amounts[] = $row['total_amount'];
+        }
+        
+        // 转为JSON格式,用于JavaScript图表
+        $months_json = json_encode($months);
+        $order_counts_json = json_encode($order_counts);
+        $order_amounts_json = json_encode($order_amounts);
+        ?>
+    </div>
+</div>
+
+<style>
+.container {
+    padding: 20px;
+    max-width: 1280px; /* 稍微扩大容器宽度 */
+    margin: 0 auto;
+}
+
+.page-header {
+    margin-bottom: 30px;
+}
+
+.page-title {
+    font-size: 24px;
+    margin-top: 0;
+    margin-bottom: 5px;
+}
+
+.page-description {
+    color: #666;
+    margin-bottom: 0;
+}
+
+.filter-form {
+    background-color: #f8f9fa;
+    border-radius: 4px;
+    padding: 20px;
+    margin-bottom: 30px;
+    box-shadow: 0 1px 2px rgba(0,0,0,0.05);
+}
+
+.filter-form-inline {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 15px;
+    align-items: end;
+}
+
+.warnings-overview {
+    margin-bottom: 30px;
+}
+
+.warnings-overview .row {
+    display: flex;
+    flex-wrap: wrap;
+    margin: 0 -10px;
+}
+
+.warnings-overview .col-md-3 {
+    padding: 0 10px;
+    width: 25%;
+    flex: 0 0 25%;
+    box-sizing: border-box;
+}
+
+@media (max-width: 992px) {
+    .warnings-overview .col-md-3 {
+        width: 50%;
+        flex: 0 0 50%;
+    }
+}
+
+@media (max-width: 576px) {
+    .warnings-overview .col-md-3 {
+        width: 100%;
+        flex: 0 0 100%;
+    }
+}
+
+.stat-card {
+    border-radius: 8px;
+    padding: 20px;
+    color: #fff;
+    height: 100%;
+    margin-bottom: 20px;
+    box-shadow: 0 3px 6px rgba(0,0,0,0.16);
+    text-align: center;
+    transition: transform 0.3s ease;
+}
+
+.stat-card:hover {
+    transform: translateY(-5px);
+}
+
+.stat-card h3 {
+    margin-top: 0;
+    font-size: 16px;
+    font-weight: 500;
+    margin-bottom: 10px;
+}
+
+.stat-value {
+    font-size: 32px;
+    font-weight: 600;
+    margin-bottom: 10px;
+}
+
+.stat-desc {
+    font-size: 15px;
+    opacity: 0.8;
+}
+
+.stat-card.warning {
+    background-color: #ff9800;
+}
+
+.stat-card.danger {
+    background-color: #f44336;
+}
+
+.stat-card.info {
+    background-color: #2196f3;
+}
+
+.stat-card.success {
+    background-color: #4caf50;
+}
+
+.warning-section {
+    background-color: white;
+    border-radius: 8px;
+    padding: 25px;
+    margin-bottom: 35px;
+    box-shadow: 0 2px 8px rgba(0,0,0,0.08);
+}
+
+.section-header {
+    margin-bottom: 20px;
+}
+
+.section-header h2 {
+    font-size: 20px;
+    margin-top: 0;
+    margin-bottom: 5px;
+}
+
+.section-header p {
+    color: #666;
+    font-size: 15px;
+    margin-bottom: 15px;
+}
+
+.chart-section {
+    background-color: white;
+    border-radius: 4px;
+    padding: 20px;
+    margin-bottom: 30px;
+    box-shadow: 0 1px 2px rgba(0,0,0,0.05);
+}
+
+.chart-container {
+    height: 350px;
+}
+
+.text-danger {
+    color: #f44336;
+}
+
+.text-warning {
+    color: #ff9800;
+}
+
+.text-info {
+    color: #2196f3;
+}
+
+/* 调整表格和内容样式 */
+.data-table {
+    margin-bottom: 20px;
+    width: 100%;
+    font-size: 14px; /* 增加表格字体大小 */
+    border-collapse: separate;
+    border-spacing: 0;
+    table-layout: fixed; /* 固定表格布局 */
+}
+
+.data-table th {
+    font-size: 15px; /* 表头字体大小 */
+    padding: 12px 15px;
+    background-color: #f5f5f5;
+    font-weight: 600;
+}
+
+.data-table td {
+    padding: 12px 15px;
+    vertical-align: middle;
+    white-space: nowrap; /* 防止文本换行 */
+    overflow: hidden; /* 溢出隐藏 */
+    text-overflow: ellipsis; /* 文本溢出显示省略号 */
+}
+
+/* 为长期不活跃客户表格设置列宽 */
+#inactive-customers .data-table th:nth-child(1), /* 客户编码 */
+#inactive-customers .data-table td:nth-child(1) {
+    width: 12%;
+}
+
+#inactive-customers .data-table th:nth-child(2), /* 客户名称 */
+#inactive-customers .data-table td:nth-child(2) {
+    width: 20%;
+}
+
+#inactive-customers .data-table th:nth-child(3), /* 最后订单日期 */
+#inactive-customers .data-table td:nth-child(3) {
+    width: 12%;
+}
+
+#inactive-customers .data-table th:nth-child(4), /* 不活跃天数 */
+#inactive-customers .data-table td:nth-child(4) {
+    width: 10%;
+}
+
+#inactive-customers .data-table th:nth-child(5), /* 历史订单数 */
+#inactive-customers .data-table td:nth-child(5) {
+    width: 10%;
+}
+
+#inactive-customers .data-table th:nth-child(6), /* 历史订单总额 */
+#inactive-customers .data-table td:nth-child(6) {
+    width: 12%;
+}
+
+#inactive-customers .data-table th:nth-child(7), /* 业务员 */
+#inactive-customers .data-table td:nth-child(7) {
+    width: 12%;
+}
+
+#inactive-customers .data-table th:nth-child(8), /* 操作 */
+#inactive-customers .data-table td:nth-child(8) {
+    width: 12%;
+}
+
+.data-table td:last-child {
+    min-width: 80px; /* 确保操作列有足够宽度 */
+    text-align: center;
+}
+
+.data-table tr:hover {
+    background-color: #f9f9f9;
+}
+
+.action-btn {
+    padding: 5px 10px;
+    margin: 0 3px;
+    min-width: 60px;
+    display: inline-block;
+    text-align: center;
+    border-radius: 4px;
+    font-size: 13px;
+    transition: all 0.3s ease;
+}
+
+.action-btn-view {
+    background-color: #2196f3;
+    color: white;
+    border: none;
+}
+
+.action-btn-view:hover {
+    background-color: #0d8aee;
+    box-shadow: 0 2px 5px rgba(0,0,0,0.2);
+}
+
+/* 为所有客户列表表格添加共同样式 */
+.warning-section .data-table {
+    border: 1px solid #eee;
+    border-radius: 4px;
+    box-shadow: 0 1px 3px rgba(0,0,0,0.05);
+}
+
+.warning-section .data-table th:first-child,
+.warning-section .data-table td:first-child {
+    padding-left: 20px; /* 左侧留出更多间距 */
+}
+
+/* 表格内数字列的对齐方式 */
+.warning-section .data-table td:nth-child(3),
+.warning-section .data-table td:nth-child(4),
+.warning-section .data-table td:nth-child(5) {
+    text-align: left;
+}
+
+/* 调整整体字体大小 */
+body {
+    font-size: 14px;
+}
+
+/* 分页样式 */
+.pagination-container {
+    margin-top: 25px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+}
+
+.pagination {
+    display: flex;
+    list-style: none;
+    padding: 0;
+    margin-bottom: 15px;
+}
+
+.pagination .pager-item {
+    margin: 0 2px;
+}
+
+.pagination .pager-link {
+    padding: 8px 16px;
+    border-radius: 4px;
+    margin: 0 3px;
+    font-weight: 500;
+    border: 1px solid #ddd;
+    background-color: #fff;
+    color: #2196f3;
+    text-decoration: none;
+    display: inline-block;
+}
+
+.pagination .pager-item.active .pager-link {
+    background-color: #2196f3;
+    color: white;
+    border-color: #2196f3;
+}
+
+.pagination .pager-item.disabled .pager-link {
+    color: #999;
+    cursor: not-allowed;
+    background-color: #f5f5f5;
+}
+
+.pagination-info {
+    margin-top: 10px;
+    font-size: 14px;
+    color: #666;
+}
+
+.form-btn {
+    padding: 8px 15px;
+    border-radius: 4px;
+    cursor: pointer;
+    font-size: 14px;
+    border: none;
+    transition: all 0.3s ease;
+}
+
+.form-btn-primary {
+    background-color: #2196f3;
+    color: white;
+}
+
+.form-btn-primary:hover {
+    background-color: #0d8aee;
+    box-shadow: 0 2px 5px rgba(0,0,0,0.2);
+}
+
+/* 添加斑马纹和悬停效果 */
+.data-table tr:nth-child(even) {
+    background-color: #f8f8f8;
+}
+
+.data-table tbody tr:hover {
+    background-color: #f0f7ff;
+}
+</style>
+
+<script>
+function toggleCustomDates() {
+    const dateRange = document.getElementById('date_range').value;
+    const customDateInputs = document.querySelectorAll('.custom-date-inputs');
+    
+    if (dateRange === 'custom') {
+        customDateInputs.forEach(el => el.style.display = 'inline-block');
+    } else {
+        customDateInputs.forEach(el => el.style.display = 'none');
+    }
+}
+
+// 订单趋势图
+document.addEventListener('DOMContentLoaded', function() {
+    const ctx = document.getElementById('orderTrendChart').getContext('2d');
+    
+    const months = <?php echo $months_json; ?>;
+    const orderCounts = <?php echo $order_counts_json; ?>;
+    const orderAmounts = <?php echo $order_amounts_json; ?>;
+    
+    const chart = new Chart(ctx, {
+        type: 'line',
+        data: {
+            labels: months,
+            datasets: [
+                {
+                    label: '订单数量',
+                    data: orderCounts,
+                    backgroundColor: 'rgba(54, 162, 235, 0.2)',
+                    borderColor: 'rgba(54, 162, 235, 1)',
+                    borderWidth: 2,
+                    yAxisID: 'y-axis-1'
+                },
+                {
+                    label: '订单金额',
+                    data: orderAmounts,
+                    backgroundColor: 'rgba(255, 99, 132, 0.2)',
+                    borderColor: 'rgba(255, 99, 132, 1)',
+                    borderWidth: 2,
+                    yAxisID: 'y-axis-2'
+                }
+            ]
+        },
+        options: {
+            responsive: true,
+            maintainAspectRatio: false,
+            scales: {
+                'y-axis-1': {
+                    type: 'linear',
+                    position: 'left',
+                    title: {
+                        display: true,
+                        text: '订单数量'
+                    }
+                },
+                'y-axis-2': {
+                    type: 'linear',
+                    position: 'right',
+                    title: {
+                        display: true,
+                        text: '订单金额'
+                    },
+                    grid: {
+                        drawOnChartArea: false
+                    }
+                }
+            }
+        }
+    });
+});
+</script>
+
+<?php
+/**
+ * 获取订单金额下降的客户
+ */
+function getDecreasingOrderAmountCustomers($conn, $current_start, $current_end, $previous_start, $previous_end, $threshold, $count_only = false, $selected_employee = 0) {
+    // 构建业务员筛选条件
+    $employee_filter = $selected_employee > 0 ? " AND c.cs_belong = ?" : "";
+    
+    // 如果只需要计数
+    if ($count_only) {
+        $sql = "SELECT COUNT(DISTINCT c.id) as count
+        FROM customer c
+        LEFT JOIN (
+            SELECT customer_id, SUM(total_amount) as amount
+            FROM orders
+            WHERE order_date BETWEEN ? AND ?
+            GROUP BY customer_id
+        ) current_period ON c.id = current_period.customer_id
+        LEFT JOIN (
+            SELECT customer_id, SUM(total_amount) as amount
+            FROM orders
+            WHERE order_date BETWEEN ? AND ?
+            GROUP BY customer_id
+        ) previous_period ON c.id = previous_period.customer_id
+        JOIN employee e ON c.cs_belong = e.id
+        WHERE previous_period.amount > 0
+        AND (current_period.amount IS NULL OR (current_period.amount / previous_period.amount - 1) * 100 <= ?)
+        AND c.cs_deal = 3" . $employee_filter;
+        
+        $stmt = $conn->prepare($sql);
+        
+        if ($selected_employee > 0) {
+            $stmt->bind_param("ssssdi", $current_start, $current_end, $previous_start, $previous_end, $threshold, $selected_employee);
+        } else {
+            $stmt->bind_param("ssssd", $current_start, $current_end, $previous_start, $previous_end, $threshold);
+        }
+        
+        $stmt->execute();
+        $result = $stmt->get_result();
+        $row = $result->fetch_assoc();
+        return $row['count'];
+    }
+    
+    // 如果需要详细数据
+    $sql = "SELECT 
+        c.id,
+        c.cs_company,
+        IFNULL(current_period.amount, 0) as current_amount,
+        previous_period.amount as previous_amount,
+        e.em_user,
+        IFNULL((SELECT MAX(order_date) FROM orders WHERE customer_id = c.id), '') as last_order_date
+    FROM customer c
+    LEFT JOIN (
+        SELECT customer_id, SUM(total_amount) as amount
+        FROM orders
+        WHERE order_date BETWEEN ? AND ?
+        GROUP BY customer_id
+    ) current_period ON c.id = current_period.customer_id
+    LEFT JOIN (
+        SELECT customer_id, SUM(total_amount) as amount
+        FROM orders
+        WHERE order_date BETWEEN ? AND ?
+        GROUP BY customer_id
+    ) previous_period ON c.id = previous_period.customer_id
+    JOIN employee e ON c.cs_belong = e.id
+    WHERE previous_period.amount > 0
+    AND (current_period.amount IS NULL OR (current_period.amount / previous_period.amount - 1) * 100 <= ?)
+    AND c.cs_deal = 3" . $employee_filter . "
+    ORDER BY (current_period.amount / previous_period.amount) ASC";
+    
+    $stmt = $conn->prepare($sql);
+    
+    if ($selected_employee > 0) {
+        $stmt->bind_param("ssssdi", $current_start, $current_end, $previous_start, $previous_end, $threshold, $selected_employee);
+    } else {
+        $stmt->bind_param("ssssd", $current_start, $current_end, $previous_start, $previous_end, $threshold);
+    }
+    
+    $stmt->execute();
+    return $stmt->get_result();
+}
+
+/**
+ * 获取复购周期异常的客户
+ */
+function getAbnormalRepurchaseCycleCustomers($conn, $current_start, $current_end, $max_threshold, $min_threshold, $normal_cycle, $count_only = false, $selected_employee = 0) {
+    // 构建业务员筛选条件
+    $employee_filter = $selected_employee > 0 ? " AND c.cs_belong = ?" : "";
+    
+    if ($count_only) {
+        $sql = "SELECT COUNT(DISTINCT t.customer_id) as count
+        FROM (
+            SELECT 
+                o.customer_id,
+                COUNT(o.id) as order_count,
+                AVG(DATEDIFF(o.order_date, prev_order.order_date)) as avg_cycle,
+                MAX(DATEDIFF(o.order_date, prev_order.order_date)) as recent_cycle
+            FROM orders o
+            JOIN customer c ON o.customer_id = c.id
+            JOIN orders prev_order ON o.customer_id = prev_order.customer_id AND prev_order.order_date < o.order_date
+            WHERE o.order_date BETWEEN ? AND ?" . $employee_filter . "
+            GROUP BY o.customer_id
+            HAVING order_count > 1
+            AND (recent_cycle > ? OR recent_cycle < (? * ?))
+        ) t";
+        
+        $stmt = $conn->prepare($sql);
+        
+        if ($selected_employee > 0) {
+            $stmt->bind_param("ssiddd", $current_start, $current_end, $selected_employee, $max_threshold, $normal_cycle, $min_threshold);
+        } else {
+            $stmt->bind_param("ssddd", $current_start, $current_end, $max_threshold, $normal_cycle, $min_threshold);
+        }
+        
+        $stmt->execute();
+        $result = $stmt->get_result();
+        $row = $result->fetch_assoc();
+        return $row['count'];
+    }
+    
+    // 使用子查询方式,先获取所有符合条件的客户及其复购周期数据
+    $sql = "SELECT 
+        abnormal.customer_id as id,
+        c.cs_company,
+        abnormal.order_count,
+        abnormal.avg_cycle,
+        abnormal.recent_cycle,
+        abnormal.last_order_date,
+        e.em_user,
+        CASE 
+            WHEN abnormal.recent_cycle > ? THEN 1 /* 周期过长 */
+            ELSE 2 /* 周期过短 */
+        END as cycle_type,
+        CASE 
+            WHEN abnormal.recent_cycle > ? THEN abnormal.recent_cycle
+            ELSE (? * ?) - abnormal.recent_cycle
+        END as sort_value
+    FROM (
+        SELECT 
+            o.customer_id,
+            COUNT(o.id) as order_count,
+            AVG(DATEDIFF(o.order_date, prev_order.order_date)) as avg_cycle,
+            MAX(DATEDIFF(o.order_date, prev_order.order_date)) as recent_cycle,
+            (SELECT MAX(order_date) FROM orders WHERE customer_id = o.customer_id) as last_order_date
+        FROM orders o
+        JOIN customer c ON o.customer_id = c.id
+        JOIN orders prev_order ON o.customer_id = prev_order.customer_id AND prev_order.order_date < o.order_date
+        WHERE o.order_date BETWEEN ? AND ?" . $employee_filter . "
+        GROUP BY o.customer_id
+        HAVING order_count > 1
+        AND (recent_cycle > ? OR recent_cycle < (? * ?))
+    ) as abnormal
+    JOIN customer c ON abnormal.customer_id = c.id
+    JOIN employee e ON c.cs_belong = e.id
+    ORDER BY sort_value DESC";
+    
+    $stmt = $conn->prepare($sql);
+    
+    if ($selected_employee > 0) {
+        $stmt->bind_param("ddddssiddd", $max_threshold, $max_threshold, $normal_cycle, $min_threshold, $current_start, $current_end, $selected_employee, $max_threshold, $normal_cycle, $min_threshold);
+    } else {
+        $stmt->bind_param("ddddssddd", $max_threshold, $max_threshold, $normal_cycle, $min_threshold, $current_start, $current_end, $max_threshold, $normal_cycle, $min_threshold);
+    }
+    
+    $stmt->execute();
+    return $stmt->get_result();
+}
+
+/**
+ * 获取长期不活跃的客户
+ */
+function getInactiveCustomers($conn, $end_date, $inactive_days, $count_only = false, $page = 1, $page_size = 10, $selected_employee = 0) {
+    // 构建业务员筛选条件
+    $employee_filter = $selected_employee > 0 ? " AND c.cs_belong = ?" : "";
+    
+    if ($count_only) {
+        $sql = "SELECT COUNT(*) as count
+        FROM customer c
+        LEFT JOIN (
+            SELECT customer_id, MAX(order_date) as last_order_date
+            FROM orders
+            GROUP BY customer_id
+        ) last_orders ON c.id = last_orders.customer_id
+        JOIN employee e ON c.cs_belong = e.id
+        WHERE c.cs_deal = 3
+        AND (
+            last_orders.last_order_date IS NULL 
+            OR DATEDIFF(?, last_orders.last_order_date) > ?
+        )" . $employee_filter;
+        
+        $stmt = $conn->prepare($sql);
+        
+        if ($selected_employee > 0) {
+            $stmt->bind_param("sii", $end_date, $inactive_days, $selected_employee);
+        } else {
+            $stmt->bind_param("si", $end_date, $inactive_days);
+        }
+        
+        $stmt->execute();
+        $result = $stmt->get_result();
+        $row = $result->fetch_assoc();
+        return $row['count'];
+    }
+    
+    $sql = "SELECT 
+        c.id,
+        c.cs_company,
+        c.cs_code,
+        last_orders.last_order_date,
+        CASE 
+            WHEN last_orders.last_order_date IS NULL THEN DATEDIFF(?, c.cs_addtime)
+            ELSE DATEDIFF(?, last_orders.last_order_date)
+        END as inactive_days,
+        IFNULL(order_stats.order_count, 0) as order_count,
+        IFNULL(order_stats.total_amount, 0) as total_amount,
+        e.em_user
+    FROM customer c
+    LEFT JOIN (
+        SELECT customer_id, MAX(order_date) as last_order_date
+        FROM orders
+        GROUP BY customer_id
+    ) last_orders ON c.id = last_orders.customer_id
+    LEFT JOIN (
+        SELECT customer_id, COUNT(*) as order_count, SUM(total_amount) as total_amount
+        FROM orders
+        GROUP BY customer_id
+    ) order_stats ON c.id = order_stats.customer_id
+    JOIN employee e ON c.cs_belong = e.id
+    WHERE c.cs_deal = 3
+    AND (
+        last_orders.last_order_date IS NULL 
+        OR DATEDIFF(?, last_orders.last_order_date) > ?
+    )" . $employee_filter . "
+    ORDER BY inactive_days DESC
+    LIMIT ?, ?";
+    
+    $offset = ($page - 1) * $page_size;
+    
+    $stmt = $conn->prepare($sql);
+    
+    if ($selected_employee > 0) {
+        $stmt->bind_param("sssiiii", $end_date, $end_date, $end_date, $inactive_days, $selected_employee, $offset, $page_size);
+    } else {
+        $stmt->bind_param("sssiii", $end_date, $end_date, $end_date, $inactive_days, $offset, $page_size);
+    }
+    
+    $stmt->execute();
+    return $stmt->get_result();
+}
+
+// 页面底部
+include('statistics_footer.php');
+?> ?>