销售数据分析平台

复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>销售数据可视化仪表盘</title>
    <!-- 引入Tailwind CSS -->
    <script src="https://cdn.tailwindcss.com"></script>
    <!-- 引入Font Awesome -->
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <!-- 引入Chart.js -->
    <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.8/dist/chart.umd.min.js"></script>

    <!-- 配置Tailwind自定义颜色和字体 -->
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#165DFF',
                        secondary: '#36CFC9',
                        accent: '#722ED1',
                        success: '#52C41A',
                        warning: '#FAAD14',
                        danger: '#F5222D',
                        info: '#1890FF',
                        dark: '#1D2129',
                        'gray-light': '#F2F3F5',
                        'gray-medium': '#C9CDD4'
                    },
                    fontFamily: {
                        inter: ['Inter', 'system-ui', 'sans-serif'],
                    },
                }
            }
        }
    </script>

    <!-- 自定义工具类 -->
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .card-shadow {
                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
            }
            .card-hover {
                transition: all 0.3s ease;
            }
            .card-hover:hover {
                transform: translateY(-5px);
                box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
            }
            .animate-fade-in {
                animation: fadeIn 0.5s ease-in-out;
            }
            .animate-slide-up {
                animation: slideUp 0.5s ease-out;
            }
        }

        @keyframes fadeIn {
            from { opacity: 0; }
            to { opacity: 1; }
        }

        @keyframes slideUp {
            from { transform: translateY(20px); opacity: 0; }
            to { transform: translateY(0); opacity: 1; }
        }
    </style>
</head>
<body class="bg-gray-50 font-inter text-dark">
    <!-- 顶部导航栏 -->
    <header class="bg-white shadow-sm fixed top-0 left-0 right-0 z-50 transition-all duration-300" id="navbar">
        <div class="container mx-auto px-4 py-3 flex items-center justify-between">
            <div class="flex items-center space-x-2">
                <i class="fa fa-line-chart text-primary text-2xl"></i>
                <h1 class="text-xl font-bold text-primary">销售数据分析平台</h1>
            </div>

            <div class="hidden md:flex items-center space-x-6">
                <a href="#" class="text-primary font-medium">仪表盘</a>
                <a href="#" class="text-gray-600 hover:text-primary transition-colors">报表</a>
                <a href="#" class="text-gray-600 hover:text-primary transition-colors">分析</a>
                <a href="#" class="text-gray-600 hover:text-primary transition-colors">设置</a>
            </div>

            <div class="flex items-center space-x-4">
                <button id="refreshBtn" class="p-2 rounded-full hover:bg-gray-light transition-colors text-gray-600">
                    <i class="fa fa-refresh"></i>
                </button>
                <div class="relative">
                    <button class="flex items-center space-x-2 focus:outline-none">
                        <img src="https://picsum.photos/id/1005/40/40" alt="用户头像" class="w-8 h-8 rounded-full object-cover border-2 border-primary">
                        <span class="hidden md:inline text-sm font-medium">管理员</span>
                        <i class="fa fa-angle-down text-gray-500"></i>
                    </button>
                </div>
            </div>
        </div>
    </header>

    <!-- 主内容区 -->
    <main class="container mx-auto px-4 pt-24 pb-16">
        <!-- 页面标题和过滤器 -->
        <div class="mb-8 animate-fade-in">
            <div class="flex flex-col md:flex-row md:items-center md:justify-between mb-6">
                <div>
                    <h2 class="text-[clamp(1.5rem,3vw,2.5rem)] font-bold mb-2">销售数据概览</h2>
                    <p class="text-gray-500">实时监控销售趋势和关键指标</p>
                </div>

                <div class="flex flex-wrap gap-3 mt-4 md:mt-0">
                    <div class="relative">
                        <select id="timeFilter" class="appearance-none bg-white border border-gray-300 rounded-lg py-2 pl-4 pr-10 text-sm focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary">
                            <option value="month">近30天</option>
                            <option value="quarter">近90天</option>
                            <option value="year">近一年</option>
                        </select>
                        <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-500">
                            <i class="fa fa-chevron-down text-xs"></i>
                        </div>
                    </div>

                    <div class="relative">
                        <select id="regionFilter" class="appearance-none bg-white border border-gray-300 rounded-lg py-2 pl-4 pr-10 text-sm focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary">
                            <option value="all">全部区域</option>
                            <option value="north">北区</option>
                            <option value="south">南区</option>
                            <option value="east">东区</option>
                            <option value="west">西区</option>
                        </select>
                        <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-500">
                            <i class="fa fa-chevron-down text-xs"></i>
                        </div>
                    </div>

                    <button class="bg-primary hover:bg-primary/90 text-white rounded-lg py-2 px-4 text-sm transition-colors flex items-center">
                        <i class="fa fa-download mr-2"></i>导出报表
                    </button>
                </div>
            </div>

            <!-- 日期显示 -->
            <div class="bg-white rounded-lg p-3 shadow-sm flex items-center justify-between">
                <div class="text-sm text-gray-500">
                    <i class="fa fa-calendar-o mr-2"></i>
                    <span id="dateRange">2023年5月15日 - 2023年6月14日</span>
                </div>
                <div class="text-sm text-gray-500 flex items-center">
                    <span class="mr-4"><i class="fa fa-refresh mr-1"></i> 上次更新: <span id="lastUpdate">今天 09:45</span></span>
                    <span class="text-success"><i class="fa fa-check-circle mr-1"></i> 数据已同步</span>
                </div>
            </div>
        </div>

        <!-- 关键指标卡片 -->
        <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
            <!-- 总销售额 -->
            <div class="bg-white rounded-xl p-6 card-shadow card-hover animate-slide-up" style="animation-delay: 0.1s">
                <div class="flex justify-between items-start mb-4">
                    <div>
                        <p class="text-gray-500 text-sm">总销售额</p>
                        <h3 class="text-2xl font-bold mt-1" id="totalSales">¥0</h3>
                    </div>
                    <div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center text-primary">
                        <i class="fa fa-rmb"></i>
                    </div>
                </div>
                <div class="flex items-center">
                    <span class="text-success text-sm flex items-center">
                        <i class="fa fa-arrow-up mr-1"></i>
                        <span id="salesGrowth">0%</span>
                    </span>
                    <span class="text-gray-400 text-xs ml-2">相比上期</span>
                </div>
            </div>

            <!-- 订单数量 -->
            <div class="bg-white rounded-xl p-6 card-shadow card-hover animate-slide-up" style="animation-delay: 0.2s">
                <div class="flex justify-between items-start mb-4">
                    <div>
                        <p class="text-gray-500 text-sm">订单数量</p>
                        <h3 class="text-2xl font-bold mt-1" id="orderCount">0</h3>
                    </div>
                    <div class="w-10 h-10 rounded-full bg-secondary/10 flex items-center justify-center text-secondary">
                        <i class="fa fa-shopping-cart"></i>
                    </div>
                </div>
                <div class="flex items-center">
                    <span class="text-success text-sm flex items-center">
                        <i class="fa fa-arrow-up mr-1"></i>
                        <span id="orderGrowth">0%</span>
                    </span>
                    <span class="text-gray-400 text-xs ml-2">相比上期</span>
                </div>
            </div>

            <!-- 平均客单价 -->
            <div class="bg-white rounded-xl p-6 card-shadow card-hover animate-slide-up" style="animation-delay: 0.3s">
                <div class="flex justify-between items-start mb-4">
                    <div>
                        <p class="text-gray-500 text-sm">平均客单价</p>
                        <h3 class="text-2xl font-bold mt-1" id="avgOrderValue">¥0</h3>
                    </div>
                    <div class="w-10 h-10 rounded-full bg-accent/10 flex items-center justify-center text-accent">
                        <i class="fa fa-usd"></i>
                    </div>
                </div>
                <div class="flex items-center">
                    <span class="text-danger text-sm flex items-center">
                        <i class="fa fa-arrow-down mr-1"></i>
                        <span id="avgValueGrowth">0%</span>
                    </span>
                    <span class="text-gray-400 text-xs ml-2">相比上期</span>
                </div>
            </div>

            <!-- 转化率 -->
            <div class="bg-white rounded-xl p-6 card-shadow card-hover animate-slide-up" style="animation-delay: 0.4s">
                <div class="flex justify-between items-start mb-4">
                    <div>
                        <p class="text-gray-500 text-sm">转化率</p>
                        <h3 class="text-2xl font-bold mt-1" id="conversionRate">0%</h3>
                    </div>
                    <div class="w-10 h-10 rounded-full bg-success/10 flex items-center justify-center text-success">
                        <i class="fa fa-exchange"></i>
                    </div>
                </div>
                <div class="flex items-center">
                    <span class="text-success text-sm flex items-center">
                        <i class="fa fa-arrow-up mr-1"></i>
                        <span id="conversionGrowth">0%</span>
                    </span>
                    <span class="text-gray-400 text-xs ml-2">相比上期</span>
                </div>
            </div>
        </div>

        <!-- 图表区域 -->
        <div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-8">
            <!-- 销售趋势图 -->
            <div class="bg-white rounded-xl p-6 card-shadow lg:col-span-2 animate-slide-up" style="animation-delay: 0.5s">
                <div class="flex justify-between items-center mb-6">
                    <h3 class="font-bold text-lg">销售趋势分析</h3>
                    <div class="flex space-x-2">
                        <button class="chart-filter-btn active px-3 py-1 text-xs rounded-full bg-primary text-white" data-period="day">按日</button>
                        <button class="chart-filter-btn px-3 py-1 text-xs rounded-full bg-gray-light text-gray-600 hover:bg-gray-200" data-period="week">按周</button>
                        <button class="chart-filter-btn px-3 py-1 text-xs rounded-full bg-gray-light text-gray-600 hover:bg-gray-200" data-period="month">按月</button>
                    </div>
                </div>
                <div class="h-[300px]">
                    <canvas id="salesTrendChart"></canvas>
                </div>
            </div>

            <!-- 销售分布 -->
            <div class="bg-white rounded-xl p-6 card-shadow animate-slide-up" style="animation-delay: 0.6s">
                <div class="flex justify-between items-center mb-6">
                    <h3 class="font-bold text-lg">销售区域分布</h3>
                    <button class="text-gray-400 hover:text-gray-600">
                        <i class="fa fa-ellipsis-v"></i>
                    </button>
                </div>
                <div class="h-[300px] flex items-center justify-center">
                    <canvas id="salesDistributionChart"></canvas>
                </div>
            </div>
        </div>

        <!-- 产品销售和区域表现 -->
        <div class="grid grid-cols-1 lg:grid-cols-5 gap-6">
            <!-- 产品销售排行 -->
            <div class="bg-white rounded-xl p-6 card-shadow lg:col-span-3 animate-slide-up" style="animation-delay: 0.7s">
                <div class="flex justify-between items-center mb-6">
                    <h3 class="font-bold text-lg">产品销售排行</h3>
                    <button class="text-primary text-sm hover:underline flex items-center">
                        查看全部 <i class="fa fa-angle-right ml-1"></i>
                    </button>
                </div>
                <div class="overflow-x-auto">
                    <table class="min-w-full">
                        <thead>
                            <tr class="border-b border-gray-100">
                                <th class="py-3 px-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">产品名称</th>
                                <th class="py-3 px-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">类别</th>
                                <th class="py-3 px-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">销售额</th>
                                <th class="py-3 px-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">销量</th>
                                <th class="py-3 px-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">同比增长</th>
                            </tr>
                        </thead>
                        <tbody id="productTableBody" class="divide-y divide-gray-100">
                            <!-- 产品数据将通过JavaScript动态生成 -->
                        </tbody>
                    </table>
                </div>
            </div>

            <!-- 区域销售表现 -->
            <div class="bg-white rounded-xl p-6 card-shadow lg:col-span-2 animate-slide-up" style="animation-delay: 0.8s">
                <div class="flex justify-between items-center mb-6">
                    <h3 class="font-bold text-lg">区域销售表现</h3>
                    <div class="relative">
                        <select id="regionMetricFilter" class="appearance-none bg-gray-light border-none rounded-lg py-1.5 pl-3 pr-8 text-xs focus:outline-none focus:ring-1 focus:ring-primary">
                            <option value="sales">按销售额</option>
                            <option value="orders">按订单数</option>
                            <option value="growth">按增长率</option>
                        </select>
                        <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-500">
                            <i class="fa fa-chevron-down text-xs"></i>
                        </div>
                    </div>
                </div>
                <div class="space-y-5" id="regionPerformance">
                    <!-- 区域数据将通过JavaScript动态生成 -->
                </div>
            </div>
        </div>
    </main>

    <!-- 页脚 -->
    <footer class="bg-white border-t border-gray-200 py-6">
        <div class="container mx-auto px-4">
            <div class="flex flex-col md:flex-row justify-between items-center">
                <div class="text-gray-500 text-sm mb-4 md:mb-0">
                    © 2023 销售数据分析平台. 保留所有权利.
                </div>
                <div class="flex space-x-6">
                    <a href="#" class="text-gray-400 hover:text-primary transition-colors">
                        <i class="fa fa-question-circle"></i>
                        <span class="ml-1 text-sm">帮助中心</span>
                    </a>
                    <a href="#" class="text-gray-400 hover:text-primary transition-colors">
                        <i class="fa fa-file-text-o"></i>
                        <span class="ml-1 text-sm">使用文档</span>
                    </a>
                    <a href="#" class="text-gray-400 hover:text-primary transition-colors">
                        <i class="fa fa-envelope-o"></i>
                        <span class="ml-1 text-sm">联系我们</span>
                    </a>
                </div>
            </div>
        </div>
    </footer>

    <script>
        // 页面加载完成后初始化
        document.addEventListener('DOMContentLoaded', function() {
            // 生成模拟数据(1万至100万区间)
            const salesData = generateSalesData();

            // 渲染数据到页面
            renderDashboard(salesData);

            // 初始化图表
            initCharts(salesData);

            // 添加事件监听器
            addEventListeners();

            // 导航栏滚动效果
            window.addEventListener('scroll', function() {
                const navbar = document.getElementById('navbar');
                if (window.scrollY > 10) {
                    navbar.classList.add('py-2', 'shadow');
                    navbar.classList.remove('py-3', 'shadow-sm');
                } else {
                    navbar.classList.add('py-3', 'shadow-sm');
                    navbar.classList.remove('py-2', 'shadow');
                }
            });
        });

        // 生成模拟数据(1万至100万区间)
        function generateSalesData() {
            // 生成30天的销售数据
            const days = 30;
            const dailySales = [];
            const dailyOrders = [];

            for (let i = 0; i < days; i++) {
                // 销售额:1万至100万之间的随机数
                const sales = Math.floor(Math.random() * 990000) + 10000;
                // 订单数:根据销售额估算,平均客单价约2万
                const orders = Math.max(1, Math.floor(sales / 20000));

                dailySales.push(sales);
                dailyOrders.push(orders);

                // 添加一些趋势,使数据更真实
                if (i > 0) {
                    const trend = Math.random() > 0.6 ? 1 : -1;
                    const variation = Math.floor(dailySales[i] * (0.05 + Math.random() * 0.15) * trend);
                    dailySales[i] = Math.max(10000, dailySales[i] + variation);
                }
            }

            // 计算总计
            const totalSales = dailySales.reduce((sum, val) => sum + val, 0);
            const totalOrders = dailyOrders.reduce((sum, val) => sum + val, 0);
            const avgOrderValue = Math.round(totalSales / totalOrders);

            // 模拟上期数据,用于计算增长率
            const lastPeriodSales = totalSales * (0.9 + Math.random() * 0.15);
            const lastPeriodOrders = totalOrders * (0.9 + Math.random() * 0.15);
            const lastPeriodAvgValue = Math.round(lastPeriodSales / lastPeriodOrders);

            // 计算增长率
            const salesGrowth = ((totalSales - lastPeriodSales) / lastPeriodSales * 100).toFixed(1);
            const orderGrowth = ((totalOrders - lastPeriodOrders) / lastPeriodOrders * 100).toFixed(1);
            const avgValueGrowth = ((avgOrderValue - lastPeriodAvgValue) / lastPeriodAvgValue * 100).toFixed(1);

            // 转化率(随机5%-15%)
            const conversionRate = (5 + Math.random() * 10).toFixed(1);
            const lastPeriodConversion = (5 + Math.random() * 10).toFixed(1);
            const conversionGrowth = ((conversionRate - lastPeriodConversion) / lastPeriodConversion * 100).toFixed(1);

            // 区域销售分布
            const regions = [
                { name: '北区', sales: Math.floor(totalSales * (0.2 + Math.random() * 0.15)), color: '#165DFF' },
                { name: '南区', sales: Math.floor(totalSales * (0.2 + Math.random() * 0.15)), color: '#36CFC9' },
                { name: '东区', sales: Math.floor(totalSales * (0.2 + Math.random() * 0.15)), color: '#722ED1' },
                { name: '西区', sales: Math.floor(totalSales * (0.2 + Math.random() * 0.15)), color: '#FAAD14' }
            ];

            // 确保区域销售总和接近总销售额
            const regionSalesTotal = regions.reduce((sum, r) => sum + r.sales, 0);
            const ratio = totalSales / regionSalesTotal;
            regions.forEach(r => r.sales = Math.floor(r.sales * ratio));

            // 为每个区域计算增长率
            regions.forEach(region => {
                region.growth = (5 - Math.random() * 10 + Math.random() * 10).toFixed(1);
                region.orders = Math.max(1, Math.floor(region.sales / (15000 + Math.random() * 15000)));
            });

            // 产品数据
            const productCategories = ['电子产品', '服装鞋帽', '家居用品', '食品饮料', '图书音像'];
            const products = [];

            for (let i = 0; i < 8; i++) {
                const category = productCategories[Math.floor(Math.random() * productCategories.length)];
                const sales = Math.floor(Math.random() * 990000) + 10000; // 1万至100万
                const volume = Math.max(1, Math.floor(sales / (5000 + Math.random() * 15000)));
                const growth = (5 - Math.random() * 10 + Math.random() * 10).toFixed(1);

                products.push({
                    id: i + 1,
                    name: `产品${String.fromCharCode(65 + i)}`,
                    category,
                    sales,
                    volume,
                    growth
                });
            }

            // 按销售额排序
            products.sort((a, b) => b.sales - a.sales);

            // 生成日期标签
            const labels = [];
            const today = new Date();

            for (let i = days - 1; i >= 0; i--) {
                const date = new Date();
                date.setDate(today.getDate() - i);
                labels.push(`${date.getMonth() + 1}/${date.getDate()}`);
            }

            return {
                dailySales,
                dailyOrders,
                labels,
                totalSales,
                totalOrders,
                avgOrderValue,
                conversionRate,
                salesGrowth,
                orderGrowth,
                avgValueGrowth,
                conversionGrowth,
                regions,
                products
            };
        }

        // 渲染仪表盘数据
        function renderDashboard(data) {
            // 格式化数字为带逗号的形式
            const formatNumber = (num) => {
                return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
            };

            // 渲染关键指标
            document.getElementById('totalSales').textContent = `¥${formatNumber(data.totalSales)}`;
            document.getElementById('orderCount').textContent = formatNumber(data.totalOrders);
            document.getElementById('avgOrderValue').textContent = `¥${formatNumber(data.avgOrderValue)}`;
            document.getElementById('conversionRate').textContent = `${data.conversionRate}%`;

            // 渲染增长率并设置颜色
            renderGrowthRate('salesGrowth', data.salesGrowth);
            renderGrowthRate('orderGrowth', data.orderGrowth);
            renderGrowthRate('avgValueGrowth', data.avgValueGrowth);
            renderGrowthRate('conversionGrowth', data.conversionGrowth);

            // 更新最后更新时间
            const now = new Date();
            document.getElementById('lastUpdate').textContent = `今天 ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`;

            // 渲染产品表格
            const productTableBody = document.getElementById('productTableBody');
            productTableBody.innerHTML = '';

            data.products.forEach(product => {
                const row = document.createElement('tr');
                row.className = 'hover:bg-gray-50 transition-colors';
                row.innerHTML = `
                    <td class="py-4 px-4 whitespace-nowrap">
                        <div class="flex items-center">
                            <div class="w-8 h-8 rounded-md bg-gray-100 flex items-center justify-center mr-3">
                                <i class="fa fa-cube text-gray-500"></i>
                            </div>
                            <div>
                                <div class="font-medium">${product.name}</div>
                            </div>
                        </div>
                    </td>
                    <td class="py-4 px-4 whitespace-nowrap">
                        <span class="px-2 py-1 text-xs rounded-full bg-gray-100 text-gray-600">${product.category}</span>
                    </td>
                    <td class="py-4 px-4 whitespace-nowrap font-medium">¥${formatNumber(product.sales)}</td>
                    <td class="py-4 px-4 whitespace-nowrap">${formatNumber(product.volume)}</td>
                    <td class="py-4 px-4 whitespace-nowrap">
                        <span class="${product.growth >= 0 ? 'text-success' : 'text-danger'} text-sm flex items-center">
                            <i class="fa fa-arrow-${product.growth >= 0 ? 'up' : 'down'} mr-1"></i>
                            ${Math.abs(product.growth)}%
                        </span>
                    </td>
                `;
                productTableBody.appendChild(row);
            });

            // 渲染区域表现
            renderRegionPerformance(data.regions, 'sales');
        }

        // 渲染增长率
        function renderGrowthRate(elementId, value) {
            const element = document.getElementById(elementId);
            element.textContent = `${Math.abs(value)}%`;

            if (parseFloat(value) >= 0) {
                element.parentElement.className = 'text-success text-sm flex items-center';
                element.parentElement.innerHTML = `<i class="fa fa-arrow-up mr-1"></i><span id="${elementId}">${Math.abs(value)}%</span>`;
            } else {
                element.parentElement.className = 'text-danger text-sm flex items-center';
                element.parentElement.innerHTML = `<i class="fa fa-arrow-down mr-1"></i><span id="${elementId}">${Math.abs(value)}%</span>`;
            }
        }

        // 渲染区域表现
        function renderRegionPerformance(regions, metric) {
            const container = document.getElementById('regionPerformance');
            container.innerHTML = '';

            // 根据所选指标排序
            let sortedRegions = [...regions];
            if (metric === 'sales') {
                sortedRegions.sort((a, b) => b.sales - a.sales);
            } else if (metric === 'orders') {
                sortedRegions.sort((a, b) => b.orders - a.orders);
            } else if (metric === 'growth') {
                sortedRegions.sort((a, b) => b.growth - a.growth);
            }

            sortedRegions.forEach(region => {
                let value, label;
                if (metric === 'sales') {
                    value = region.sales;
                    label = `¥${formatNumber(value)}`;
                } else if (metric === 'orders') {
                    value = region.orders;
                    label = formatNumber(value);
                } else {
                    value = Math.abs(region.growth);
                    label = `${region.growth}%`;
                }

                // 计算最大值用于进度条
                const maxValue = metric === 'sales'
                    ? Math.max(...regions.map(r => r.sales))
                    : metric === 'orders'
                        ? Math.max(...regions.map(r => r.orders))
                        : 20; // 增长率最大20%

                const percentage = Math.min(100, Math.round((value / maxValue) * 100));

                const regionElement = document.createElement('div');
                regionElement.className = 'region-item';
                regionElement.innerHTML = `
                    <div class="flex justify-between items-center mb-1">
                        <div class="flex items-center">
                            <div class="w-3 h-3 rounded-full mr-2" style="background-color: ${region.color}"></div>
                            <span class="text-sm font-medium">${region.name}</span>
                        </div>
                        <span class="text-sm font-semibold ${metric === 'growth' && region.growth < 0 ? 'text-danger' : metric === 'growth' ? 'text-success' : ''}">${label}</span>
                    </div>
                    <div class="w-full bg-gray-100 rounded-full h-2">
                        <div class="h-2 rounded-full" style="width: ${percentage}%; background-color: ${region.color}"></div>
                    </div>
                `;
                container.appendChild(regionElement);
            });
        }

        // 初始化图表
        function initCharts(data) {
            // 销售趋势图
            const trendCtx = document.getElementById('salesTrendChart').getContext('2d');

            // 图表样式配置
            const gridLineColor = 'rgba(0, 0, 0, 0.05)';
            const tooltipBackgroundColor = 'rgba(255, 255, 255, 0.95)';
            const tooltipBorderColor = 'rgba(0, 0, 0, 0.1)';

            window.salesTrendChart = new Chart(trendCtx, {
                type: 'line',
                data: {
                    labels: data.labels,
                    datasets: [
                        {
                            label: '销售额',
                            data: data.dailySales,
                            borderColor: '#165DFF',
                            backgroundColor: 'rgba(22, 93, 255, 0.1)',
                            borderWidth: 2,
                            pointBackgroundColor: '#FFFFFF',
                            pointBorderColor: '#165DFF',
                            pointBorderWidth: 2,
                            pointRadius: 4,
                            pointHoverRadius: 6,
                            tension: 0.3,
                            fill: true
                        },
                        {
                            label: '订单数',
                            data: data.dailyOrders,
                            borderColor: '#722ED1',
                            backgroundColor: 'transparent',
                            borderWidth: 2,
                            pointBackgroundColor: '#FFFFFF',
                            pointBorderColor: '#722ED1',
                            pointBorderWidth: 2,
                            pointRadius: 4,
                            pointHoverRadius: 6,
                            tension: 0.3,
                            fill: false,
                            yAxisID: 'y1'
                        }
                    ]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    interaction: {
                        mode: 'index',
                        intersect: false,
                    },
                    plugins: {
                        legend: {
                            position: 'top',
                            align: 'end',
                            labels: {
                                usePointStyle: true,
                                boxWidth: 6,
                                font: {
                                    size: 12
                                },
                                padding: 20
                            }
                        },
                        tooltip: {
                            backgroundColor: tooltipBackgroundColor,
                            titleColor: '#1D2129',
                            bodyColor: '#4E5969',
                            borderColor: tooltipBorderColor,
                            borderWidth: 1,
                            padding: 12,
                            boxPadding: 6,
                            usePointStyle: true,
                            callbacks: {
                                label: function(context) {
                                    let label = context.dataset.label || '';
                                    if (label) {
                                        label += ': ';
                                    }
                                    if (context.datasetIndex === 0) {
                                        label += '¥' + formatNumber(context.parsed.y);
                                    } else {
                                        label += formatNumber(context.parsed.y) + ' 单';
                                    }
                                    return label;
                                }
                            }
                        }
                    },
                    scales: {
                        x: {
                            grid: {
                                display: false
                            },
                            ticks: {
                                maxRotation: 0,
                                autoSkip: true,
                                maxTicksLimit: 8
                            }
                        },
                        y: {
                            beginAtZero: true,
                            grid: {
                                color: gridLineColor
                            },
                            ticks: {
                                callback: function(value) {
                                    if (value >= 1000000) {
                                        return '¥' + (value / 1000000).toFixed(1) + 'M';
                                    } else if (value >= 1000) {
                                        return '¥' + (value / 1000).toFixed(0) + 'K';
                                    }
                                    return '¥' + value;
                                }