开发中小商家库存智能预警系统,录入商品销售数据与库存总量,通过时间序列模型,预测补货节点,自动生成采购清单,支持导出EXCEL

17 阅读6分钟

中小商家库存智能预警系统

README文件

项目简介

本系统是为中小商家设计的库存智能管理平台,融合创新思维与战略管理理念,通过时间序列分析预测销售趋势,自动计算补货节点,生成采购清单,并提供数据可视化与Excel导出功能,帮助商家降低库存成本、规避缺货风险。

核心功能

  • 商品档案管理与销售数据录入
  • 基于时间序列模型的销量预测(移动平均/指数平滑)
  • 多级预警机制(缺货预警、积压预警)
  • 智能采购清单生成(含经济订货量计算)
  • Excel数据导入导出
  • 库存周转分析与可视化报表

技术栈

  • 前端:HTML5/CSS3/JavaScript (ES6+)
  • 数据处理:SheetJS (xlsx.js) 用于Excel交互
  • 图表库:Chart.js 用于数据可视化
  • 架构:模块化设计(6大核心模块)

目录结构

├── index.html # 主界面 ├── styles.css # 样式文件 ├── app.js # 核心逻辑代码 ├── README.md # 项目说明 ├── 使用说明.md # 用户操作指南 ├── 核心知识点卡片.html # 管理/技术知识点库 └── lib/ ├── xlsx.full.min.js # SheetJS库 └── chart.min.js # Chart.js库

核心代码实现

中小商家库存智能预警系统 :root { --primary: #3498db; --warning: #f39c12; --danger: #e74c3c; --success: #2ecc71; --light: #f8f9fa; --dark: #343a40; } * { box-sizing: border-box; margin: 0; padding: 0; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: #f5f7fa; color: #333; line-height: 1.6; } .container { max-width: 1200px; margin: 0 auto; padding: 20px; } header { background: linear-gradient(135deg, var(--primary), #2980b9); color: white; padding: 1.5rem 0; border-radius: 8px; margin-bottom: 2rem; box-shadow: 0 4px 6px rgba(0,0,0,0.1); } .header-content { display: flex; justify-content: space-between; align-items: center; padding: 0 20px; } h1 { font-size: 1.8rem; font-weight: 600; } .dashboard { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 2rem; } @media (max-width: 768px) { .dashboard { grid-template-columns: 1fr; } } .card { background: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.05); padding: 20px; margin-bottom: 20px; } .card-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; padding-bottom: 10px; border-bottom: 1px solid #eee; } .card-title { font-size: 1.2rem; font-weight: 600; color: var(--dark); } .form-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; font-weight: 500; color: #555; } input, select, button { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 1rem; } button { background-color: var(--primary); color: white; border: none; cursor: pointer; font-weight: 500; transition: background-color 0.3s; margin-top: 10px; } button:hover { background-color: #2980b9; } .btn-warning { background-color: var(--warning); } .btn-warning:hover { background-color: #e67e22; } .btn-danger { background-color: var(--danger); } .btn-danger:hover { background-color: #c0392b; } .btn-success { background-color: var(--success); } .btn-success:hover { background-color: #27ae60; } table { width: 100%; border-collapse: collapse; margin-top: 15px; } th, td { padding: 12px 15px; text-align: left; border-bottom: 1px solid #eee; } th { background-color: #f8f9fa; font-weight: 600; } tr:hover { background-color: #f8f9fa; } .alert { padding: 10px 15px; border-radius: 4px; margin-bottom: 15px; display: flex; align-items: center; } .alert-warning { background-color: #fff3cd; border-left: 4px solid var(--warning); color: #856404; } .alert-danger { background-color: #f8d7da; border-left: 4px solid var(--danger); color: #721c24; } .alert-success { background-color: #d4edda; border-left: 4px solid var(--success); color: #155724; } .chart-container { height: 300px; margin-top: 20px; } .action-buttons { display: flex; gap: 10px; margin-top: 15px; } .action-buttons button { flex: 1; } .tabs { display: flex; border-bottom: 1px solid #ddd; margin-bottom: 20px; } .tab { padding: 10px 20px; cursor: pointer; border-bottom: 3px solid transparent; } .tab.active { border-bottom-color: var(--primary); color: var(--primary); font-weight: 500; } .tab-content { display: none; } .tab-content.active { display: block; } .summary-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin-bottom: 20px; } .summary-card { background: white; border-radius: 8px; padding: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.05); text-align: center; } .summary-card h3 { font-size: 1rem; color: #777; margin-bottom: 10px; } .summary-card .value { font-size: 1.8rem; font-weight: 600; color: var(--primary); } .summary-card .change { font-size: 0.9rem; margin-top: 5px; } .positive { color: var(--success); } .negative { color: var(--danger); } </style>

📊 中小商家库存智能预警系统

    <div class="summary-cards">
        <div class="summary-card">
            <h3>商品总数</h3>
            <div class="value" id="totalProducts">0</div>
        </div>
        <div class="summary-card">
            <h3>预警商品</h3>
            <div class="value" id="alertProducts">0</div>
        </div>
        <div class="summary-card">
            <h3>库存总额</h3>
            <div class="value" id="totalInventory"0</div>
        </div>
        <div class="summary-card">
            <h3>周转率</h3>
            <div class="value" id="turnoverRate">0%</div>
        </div>
    </div>
    
    <div class="tabs">
        <div class="tab active" data-tab="dashboard">仪表盘</div>
        <div class="tab" data-tab="products">商品管理</div>
        <div class="tab" data-tab="sales">销售数据</div>
        <div class="tab" data-tab="forecast">预测分析</div>
        <div class="tab" data-tab="purchase">采购清单</div>
    </div>
    
    <div class="tab-content active" id="dashboard-tab">
        <div class="dashboard">
            <div class="card">
                <div class="card-header">
                    <h2 class="card-title">库存预警</h2>
                </div>
                <div id="alertsContainer">
                    <!-- 预警信息动态生成 -->
                </div>
            </div>
            
            <div class="card">
                <div class="card-header">
                    <h2 class="card-title">库存趋势</h2>
                </div>
                <div class="chart-container">
                    <canvas id="inventoryTrendChart"></canvas>
                </div>
            </div>
        </div>
        
        <div class="card">
            <div class="card-header">
                <h2 class="card-title">热销商品排行</h2>
            </div>
            <div class="chart-container">
                <canvas id="topProductsChart"></canvas>
            </div>
        </div>
    </div>
    
    <div class="tab-content" id="products-tab">
        <div class="card">
            <div class="card-header">
                <h2 class="card-title">商品信息管理</h2>
            </div>
            <form id="productForm">
                <div class="form-group">
                    <label for="productId">商品ID</label>
                    <input type="text" id="productId" required>
                </div>
                <div class="form-group">
                    <label for="productName">商品名称</label>
                    <input type="text" id="productName" required>
                </div>
                <div class="form-group">
                    <label for="category">商品类别</label>
                    <select id="category">
                        <option value="electronics">电子产品</option>
                        <option value="clothing">服装</option>
                        <option value="food">食品</option>
                        <option value="daily">日用品</option>
                        <option value="other">其他</option>
                    </select>
                </div>
                <div class="form-group">
                    <label for="unitPrice">单价 (¥)</label>
                    <input type="number" id="unitPrice" step="0.01" min="0" required>
                </div>
                <div class="form-group">
                    <label for="safetyStock">安全库存</label>
                    <input type="number" id="safetyStock" min="0" required>
                </div>
                <div class="form-group">
                    <label for="reorderPoint">补货点</label>
                    <input type="number" id="reorderPoint" min="0" required>
                </div>
                <div class="form-group">
                    <label for="leadTime">补货周期 (天)</label>
                    <input type="number" id="leadTime" min="1" required>
                </div>
                <button type="submit" class="btn-success">保存商品信息</button>
            </form>
        </div>
        
        <div class="card">
            <div class="card-header">
                <h2 class="card-title">商品列表</h2>
                <button id="exportProductsBtn" class="btn-success">导出Excel</button>
            </div>
            <table id="productsTable">
                <thead>
                    <tr>
                        <th>商品ID</th>
                        <th>名称</th>
                        <th>类别</th>
                        <th>单价</th>
                        <th>安全库存</th>
                        <th>补货点</th>
                        <th>补货周期</th>
                        <th>当前库存</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody>
                    <!-- 商品数据动态生成 -->
                </tbody>
            </table>
        </div>
    </div>
    
    <div class="tab-content" id="sales-tab">
        <div class="card">
            <div class="card-header">
                <h2 class="card-title">销售数据录入</h2>
            </div>
            <form id="salesForm">
                <div class="form-group">
                    <label for="saleProduct">选择商品</label>
                    <select id="saleProduct" required>
                        <!-- 商品选项动态生成 -->
                    </select>
                </div>
                <div class="form-group">
                    <label for="saleDate">销售日期</label>
                    <input type="date" id="saleDate" required>
                </div>
                <div class="form-group">
                    <label for="quantity">销售数量</label>
                    <input type="number" id="quantity" min="1" required>
                </div>
                <div class="form-group">
                    <label for="saleAmount">销售金额 (¥)</label>
                    <input type="number" id="saleAmount" step="0.01" min="0" required>
                </div>
                <button type="submit" class="btn-success">添加销售记录</button>
            </form>
        </div>
        
        <div class="card">
            <div class="card-header">
                <h2 class="card-title">销售数据列表</h2>
                <div class="action-buttons">
                    <button id="importSalesBtn" class="btn-warning">导入Excel</button>
                    <button id="exportSalesBtn" class="btn-success">导出Excel</button>
                </div>
            </div>
            <table id="salesTable">
                <thead>
                    <tr>
                        <th>商品ID</th>
                        <th>商品名称</th>
                        <th>销售日期</th>
                        <th>数量</th>
                        <th>金额 (¥)</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody>
                    <!-- 销售数据动态生成 -->
                </tbody>
            </table>
        </div>
    </div>
    
    <div class="tab-content" id="forecast-tab">
        <div class="card">
            <div class="card-header">
                <h2 class="card-title">销量预测分析</h2>
            </div>
            <div class="form-group">
                <label for="forecastProduct">选择商品</label>
                <select id="forecastProduct" required>
                    <!-- 商品选项动态生成 -->
                </select>
            </div>
            <div class="form-group">
                <label for="forecastPeriod">预测周期 (天)</label>
                <input type="number" id="forecastPeriod" min="1" max="90" value="30" required>
            </div>
            <div class="form-group">
                <label for="forecastMethod">预测方法</label>
                <select id="forecastMethod">
                    <option value="movingAverage">移动平均法</option>
                    <option value="exponentialSmoothing">指数平滑法</option>
                </select>
            </div>
            <button id="runForecastBtn" class="btn-primary">运行预测</button>
            
            <div class="chart-container">
                <canvas id="forecastChart"></canvas>
            </div>
            
            <div id="forecastResults">
                <!-- 预测结果动态生成 -->
            </div>
        </div>
    </div>
    
    <div class="tab-content" id="purchase-tab">
        <div class="card">
            <div class="card-header">
                <h2 class="card-title">智能采购清单</h2>
                <button id="generatePurchaseListBtn" class="btn-primary">生成采购清单</button>
            </div>
            <div id="purchaseListContainer">
                <!-- 采购清单动态生成 -->
            </div>
            <div class="action-buttons">
                <button id="exportPurchaseListBtn" class="btn-success">导出Excel</button>
            </div>
        </div>
    </div>
</div>

<script>
    /**
     * 中小商家库存智能预警系统 - 核心模块
     * 融合创新思维与战略管理理念,实现数据驱动的库存决策
     */

    // ==================== 模块1: 数据管理模块 ====================
    const DataManager = {
        // 商品数据存储
        products: JSON.parse(localStorage.getItem('inventoryProducts')) || [],
        
        // 销售数据存储
        sales: JSON.parse(localStorage.getItem('inventorySales')) || [],
        
        // 预警规则配置
        alertRules: {
            stockout: { threshold: 0.2, message: "库存严重不足" },
            lowStock: { threshold: 0.5, message: "库存偏低" },
            overstock: { threshold: 1.5, message: "库存积压风险" }
        },
        
        // 初始化数据
        init: function() {
            // 设置默认日期为今天
            document.getElementById('currentDate').textContent = new Date().toLocaleDateString('zh-CN', {
                year: 'numeric',
                month: 'long',
                day: 'numeric',
                weekday: 'long'
            });
            
            // 如果没有商品数据,添加示例数据
            if (this.products.length === 0) {
                this.addSampleData();
            }
            
            this.updateSummaryCards();
            this.renderProductsTable();
            this.renderSalesTable();
            this.updateSaleProductOptions();
            this.updateForecastProductOptions();
        },
        
        // 添加示例数据
        addSampleData: function() {
            this.products = [
                {
                    id: "P001",
                    name: "无线蓝牙耳机",
                    category: "electronics",
                    unitPrice: 199.00,
                    safetyStock: 20,
                    reorderPoint: 30,
                    leadTime: 7,
                    currentStock: 45
                },
                {
                    id: "P002",
                    name: "纯棉T恤",
                    category: "clothing",
                    unitPrice: 59.00,
                    safetyStock: 50,
                    reorderPoint: 80,
                    leadTime: 5,
                    currentStock: 120
                },
                {
                    id: "P003",
                    name: "有机牛奶",
                    category: "food",
                    unitPrice: 12.80,
                    safetyStock: 30,
                    reorderPoint: 50,
                    leadTime: 2,
                    currentStock: 25
                }
            ];
            
            this.sales = [
                { productId: "P001", date: "2023-10-01", quantity: 15, amount: 2985 },
                { productId: "P001", date: "2023-10-05", quantity: 8, amount: 1592 },
                { productId: "P002", date: "2023-10-02", quantity: 25, amount: 1475 },
                { productId: "P002", date: "2023-10-06", quantity: 30, amount: 1770 },
                { productId: "P003", date: "2023-10-03", quantity: 40, amount: 512 },
                { productId: "P003", date: "2023-10-07", quantity: 35, amount: 448 }
            ];
            
            this.saveData();
        },
        
        // 保存数据到localStorage
        saveData: function() {
            localStorage.setItem('inventoryProducts', JSON.stringify(this.products));
            localStorage.setItem('inventorySales', JSON.stringify(this.sales));
        },
        
        // 添加商品
        addProduct: function(product) {
            // 检查ID是否已存在
            if (this.products.some(p => p.id === product.id)) {
                return false;
            }
            
            this.products.push(product);
            this.saveData();
            this.updateSummaryCards();
            this.renderProductsTable();
            this.updateSaleProductOptions();
            this.updateForecastProductOptions();
            return true;
        },
        
        // 更新商品
        updateProduct: function(productId, updatedData) {
            const index = this.products.findIndex(p => p.id === productId);
            if (index === -1) return false;
            
            this.products[index] = {...this.products[index], ...updatedData};
            this.saveData();
            this.updateSummaryCards();
            this.renderProductsTable();
            this.updateSaleProductOptions();
            this.updateForecastProductOptions();
            return true;
        },
        
        // 删除商品
        deleteProduct: function(productId) {
            const index = this.products.findIndex(p => p.id === productId);
            if (index === -1) return false;
            
            this.products.splice(index, 1);
            // 同时删除相关销售记录
            this.sales = this.sales.filter(s => s.productId !== productId);
            this.saveData();
            this.updateSummaryCards();
            this.renderProductsTable();
            this.renderSalesTable();
            this.updateSaleProductOptions();
            this.updateForecastProductOptions();
            return true;
        },
        
        // 获取商品
        getProduct: function(productId) {
            return this.products.find(p => p.id === productId);
        },
        
        // 添加销售记录
        addSale: function(sale) {
            // 验证商品是否存在
            if (!this.products.some(p => p.id === sale.productId)) {
                return false;
            }
            
            this.sales.push(sale);
            // 更新商品当前库存
            const product = this.getProduct(sale.productId);
            if (product) {
                product.currentStock -= sale.quantity;
                this.updateProduct(product.id, { currentStock: product.currentStock });
            }
            
            this.saveData();
            this.renderSalesTable();
            this.updateSummaryCards();
            return true;
        },
        
        // 获取商品的销售数据
        getProductSales: function(productId, days = 30) {
            const cutoffDate = new Date();
            cutoffDate.setDate(cutoffDate.getDate() - days);
            
            return this.sales
                .filter(s => s.productId === productId && new Date(s.date) >= cutoffDate)
                .sort((a, b) => new Date(a.date) - new Date(b.date));
        },
        
        // 更新汇总卡片
        updateSummaryCards: function() {
            document.getElementById('totalProducts').textContent = this.products.length;
            
            // 计算预警商品数量
            const alertCount = this.products.filter(p => 
                p.currentStock <= p.reorderPoint
            ).length;
            document.getElementById('alertProducts').textContent = alertCount;
            
            // 计算库存总额
            const totalInventory = this.products.reduce((sum, p) => 
                sum + (p.unitPrice * p.currentStock), 0
            );
            document.getElementById('totalInventory').textContent = `¥${totalInventory.toFixed(2)}`;
            
            // 计算周转率 (简化版)
            const totalSales = this.sales.reduce((sum, s) => sum + s.amount, 0);
            const turnoverRate = totalInventory > 0 ? (totalSales / totalInventory * 100).toFixed(2) : 0;
            document.getElementById('turnoverRate').textContent = `${turnoverRate}%`;
        },
        
        // 渲染商品表格
        renderProductsTable: function() {
            const tbody = document.querySelector('#productsTable tbody');
            tbody.innerHTML = '';
            
            this.products.forEach(product => {
                const row = document.createElement('tr');
                
                // 根据库存状态设置行样式
                if (product.currentStock <= product.safetyStock) {
                    row.style.backgroundColor = '#fff3cd';
                } else if (product.currentStock > product.reorderPoint * 1.5) {
                    row.style.backgroundColor = '#d4edda';
                }
                
                row.innerHTML = `
                    <td>${product.id}</td>
                    <td>${product.name}</td>
                    <td>${this.getCategoryName(product.category)}</td>
                    <td>¥${product.unitPrice.toFixed(2)}</td>
                    <td>${product.safetyStock}</td>
                    <td>${product.reorderPoint}</td>
                    <td>${product.leadTime}</td>
                    <td>${product.currentStock}</td>
                    <td>
                        <button class="btn-warning edit-product" data-id="${product.id}">编辑</button>
                        <button class="btn-danger delete-product" data-id="${product.id}">删除</button>
                    </td>
                `;
                
                tbody.appendChild(row);
            });
            
            // 添加事件监听
            document.querySelectorAll('.edit-product').forEach(btn => {
                btn.addEventListener('click', (e) => {
                    const productId = e.target.dataset.id;
                    this.editProduct(productId);
                });
            });
            
            document.querySelectorAll('.delete-product').forEach(btn => {
                btn.addEventListener('click', (e) => {
                    const productId = e.target.dataset.id;
                    if (confirm('确定要删除这个商品及其所有销售记录吗?')) {
                        this.deleteProduct(productId);
                    }
                });
            });
        },
        
        // 渲染销售表格
        renderSalesTable: function() {
            const tbody = document.querySelector('#salesTable tbody');
            tbody.innerHTML = '';
            
            this.sales.forEach((sale, index) => {
                const product = this.getProduct(sale.productId);
                const row = document.createElement('tr');
                
                row.innerHTML = `
                    <td>${sale.productId}</td>
                    <td>${product ? product.name : '未知商品'}</td>
                    <td>${sale.date}</td>
                    <td>${sale.quantity}</td>
                    <td>¥${sale.amount.toFixed(2)}</td>
                    <td>
                        <button class="btn-danger delete-sale" data-index="${index}">删除</button>
                    </td>
                `;
                
                tbody.appendChild(row);
            });
            
            // 添加删除事件监听
            document.querySelectorAll('.delete-sale').forEach(btn => {
                btn.addEventListener('click', (e) => {
                    const index = parseInt(e.target.dataset.index);
                    this.deleteSale(index);
                });
            });
        },
        
        // 删除销售记录
        deleteSale: function(index) {
            const sale = this.sales[index];
            if (sale) {
                // 恢复库存
                const product = this.getProduct(sale.productId);
                if (product) {
                    product.currentStock += sale.quantity;
                    this.updateProduct(product.id, { currentStock: product.currentStock });
                }
                
                this.sales.splice(index, 1);
                this.saveData();
                this.renderSalesTable();
                this.updateSummaryCards();
            }
        },
        
        // 更新销售表单中的商品选项
        updateSaleProductOptions: function() {
            const select = document.getElementById('saleProduct');
            select.innerHTML = '<option value="">选择商品</option>';
            
            this.products.forEach(product => {
                const option = document.createElement('option');
                option.value = product.id;
                option.textContent = `${product.name} (库存: ${product.currentStock})`;
                select.appendChild(option);
            });
        },
        
        // 更新预测表单中的商品选项
        updateForecastProductOptions: function() {
            const selects = [
                document.getElementById('forecastProduct'),
                document.getElementById('purchaseProductFilter')
            ].filter(el => el);
            
            selects.forEach(select => {
                const currentValue = select.value;
                select.innerHTML = '<option value="">选择商品</option>';
                
                this.products.forEach(product => {
                    const option = document.createElement('option');
                    option.value = product.id;
                    option.textContent = product.name;
                    select.appendChild(option);
                });
                
                if (currentValue) {
                    select.value = currentValue;
                }
            });
        },
        
        // 获取类别名称
        getCategoryName: function(categoryCode) {
            const categories = {
                electronics: "电子产品",
                clothing: "服装",
                food: "食品",
                daily: "日用品",
                other: "其他"
            };
            return categories[categoryCode] || categoryCode;
        },
        
        // 编辑商品
        editProduct: function(productId) {
            const product = this.getProduct(productId);
            if (!product) return;
            
            // 填充表单
            document.getElementById('productId').value = product.id;
            document.getElementById('productName').value = product.name;
            document.getElementById('category').value = product.category;
            document.getElementById('unitPrice').value = product.unitPrice;
            document.getElementById('safetyStock').value = product.safetyStock;
            document.getElementById('reorderPoint').value = product.reorderPoint;
            document.getElementById('leadTime').value = product.leadTime;
            
            // 滚动到表单
            document.getElementById('products-tab').scrollIntoView({ behavior: 'smooth' });
        }
    };

    // ==================== 模块2: 时间序列预测模块 ====================
    const ForecastEngine = {
        // 移动平均法预测
        movingAverage: function(data, period = 3) {
            if (data.length === 0) return 0;
            if (data.length < period) period = data.length;
            
            const recentData = data.slice(-period);
            const sum = recentData.reduce((acc, val) => acc + val.quantity, 0);
            return sum / period;
        },
        
        // 指数平滑法预测 (Holt-Winters简化版)
        exponentialSmoothing: function(data, alpha = 0.3) {
            if (data.length === 0) return 0;
            if (data.length === 1) return data[0].quantity;
            
            let forecast = data[0].quantity;
            for (let i = 1; i < data.length; i++) {
                forecast = alpha * data[i].quantity + (1 - alpha) * forecast;
            }
            return forecast;
        },
        
        // 预测未来销量
        predictSales: function(productId, days = 30, method = 'movingAverage') {
            const salesData = DataManager.getProductSales(productId, 90); // 使用最近90天数据
            if (salesData.length === 0) return 0;
            
            let dailyAvg;
            if (method === 'movingAverage') {
                dailyAvg = this.movingAverage(salesData, 7); // 7天移动平均
            } else {
                dailyAvg = this.exponentialSmoothing(salesData);
            }
            
            return dailyAvg * days;
        },
        
        // 生成预测结果
        generateForecast: function(productId, days = 30, method = 'movingAverage') {
            const product = DataManager.getProduct(productId);
            if (!product) return null;
            
            const salesData = DataManager.getProductSales(productId, 90);
            const forecastQty = this.predictSales(productId, days, method);
            const forecastAmount = forecastQty * product.unitPrice;
            
            return {
                productId,
                productName: product.name,
                forecastDays: days,
                forecastQuantity: Math.round(forecastQty),
                forecastAmount: forecastAmount.toFixed(2),
                method,
                historicalData: salesData
            };
        }
    };

    // ==================== 模块3: 预警引擎模块 ====================
    const AlertEngine = {
        // 检查商品库存预警状态
        checkProductAlert: function(product) {
            const alerts = [];
            
            // 缺货预警
            if (product.currentStock <= product.safetyStock) {
                alerts.push({
                    type: 'danger',
                    message: `${product.name} ${DataManager.alertRules.stockout.message},当前库存: ${product.currentStock}`,
                    productId: product.id
                });
            } 
            // 低库存预警
            else if (product.currentStock <= product.reorderPoint) {
                alerts.push({
                    type: 'warning',
                    message: `${product.name} ${DataManager.alertRules.lowStock.message},当前库存: ${product.currentStock}`,
                    productId: product.id
                });
            }
            // 积压预警
            else if (product.currentStock > product.reorderPoint * DataManager.alertRules.overstock.threshold) {
                alerts.push({
                    type: 'info',
                    message: `${product.name} ${DataManager.alertRules.overstock.message},当前库存: ${product.currentStock}`,
                    productId: product.id
                });
            }
            
            return alerts;
        },
        
        // 获取所有预警信息
        getAllAlerts: function() {
            const allAlerts = [];
            
            DataManager.products.forEach(product => {
                const productAlerts = this.checkProductAlert(product);
                allAlerts.push(...productAlerts);
            });
            
            return allAlerts;
        },
        
        // 渲染预警信息
        renderAlerts: function() {
            const container = document.getElementById('alertsContainer');
            const alerts = this.getAllAlerts();
            
            if (alerts.length === 0) {
                container.innerHTML = '<div class="alert alert-success">所有商品库存状态正常</div>';
                return;
            }
            
            container.innerHTML = '';
            alerts.forEach(alert => {
                const alertEl = document.createElement('div');
                alertEl.className = `alert alert-${alert.type}`;
                alertEl.innerHTML = `
                    <strong>${alert.productName}:</strong> ${alert.message}
                    <button class="btn btn-sm" style="margin-left: 10px;" onclick="AlertEngine.resolveAlert('${alert.productId}')">标记处理</button>
                `;
                container.appendChild(alertEl);
            });
        },
        
        // 标记预警为已处理
        resolveAlert: function(productId) {
            // 在实际应用中,这里可以添加更复杂的逻辑
            alert(`已标记 ${DataManager.getProduct(productId).name} 的预警为处理中`);
            this.renderAlerts();
        }
    };

    // ==================== 模块4: 采购清单生成模块 ====================
    const PurchaseManager = {
        // 生成采购清单
        generatePurchaseList: function() {
            const list = [];
            
            DataManager.products.forEach(product => {
                // 只考虑需要补货的商品
                if (product.currentStock <= product.reorderPoint) {
                    // 计算建议采购量 (EOQ简化版)
                    const forecast = ForecastEngine.predictSales(product.id, product.leadTime);
                    const purchaseQty = Math.max(
                        product.reorderPoint * 2 - product.currentStock, // 基础补货量
                        Math.ceil(forecast * 1.2) // 考虑预测销量增加20%
                    );
                    
                    list.push({
                        productId: product.id,
                        productName: product.name,
                        currentStock: product.currentStock,
                        reorderPoint: product.reorderPoint,
                        leadTime: product.leadTime,
                        forecastDemand: Math.ceil(forecast),
                        suggestedQty: purchaseQty,
                        unitPrice: product.unitPrice,
                        totalCost: (purchaseQty * product.unitPrice).toFixed(2)
                    });
                }
            });
            
            return list;
        },
        
        // 渲染采购清单
        renderPurchaseList: function() {
            const container = document.getElementById('purchaseListContainer');
            const list = this.generatePurchaseList();
            
            if (list.length === 0) {
                container.innerHTML = '<div class="alert alert-success">当前所有商品库存充足,无需采购</div>';
                return;
            }
            
            let html = `
                <table class="purchase-list">
                    <thead>
                        <tr>
                            <th>商品ID</th>
                            <th>商品名称</th>
                            <th>当前库存</th>
                            <th>补货点</th>
                            <th>预测需求</th>
                            <th>建议采购量</th>
                            <th>单价</th>
                            <th>总金额</th>
                        </tr>
                    </thead>
                    <tbody>
            `;
            
            list.forEach(item => {
                html += `
                    <tr>
                        <td>${item.productId}</td>
                        <td>${item.productName}</td>
                        <td>${item.currentStock}</td>
                        <td>${item.reorderPoint}</td>
                        <td>${item.forecastDemand}</td>
                        <td>${item.suggestedQty}</td>
                        <td>¥${item.unitPrice.toFixed(2)}</td>
                        <td>¥${item.totalCost}</td>
                    </tr>
                `;
            });
            
            html += `
                    </tbody>
                    <tfoot>
                        <tr>
                            <td colspan="7" style="text-align: right;"><strong>总计:</strong></td>
                            <td><strong>¥${list.reduce((sum, item) => sum + parseFloat(item.totalCost), 0).toFixed(2)}</strong></td>
                        </tr>
                    </tfoot>
                </table>
            `;
            
            container.innerHTML = html;
        }
    };

    // ==================== 模块5: 报表与导出模块 ====================
    const ReportManager = {
        // 导出数据为Excel
        exportToExcel: function(data, fileName, sheetName) {
            try {
                const ws = XLSX.utils.json_to_sheet(data);
                const wb = XLSX.utils.book_new();
                XLSX.utils.book_append_sheet(wb, ws, sheetName);
                XLSX.writeFile(wb, `${fileName}.xlsx`);
                return true;
            } catch (e) {
                console.error("导出失败:", e);
                return false;
            }
        },
        
        // 获取商品数据用于导出
        getProductsForExport: function() {
            return DataManager.products.map(p => ({
                "商品ID": p.id,
                "商品名称": p.name,
                "类别": DataManager.getCategoryName(p.category),
                "单价(¥)": p.unitPrice,
                "安全库存": p.safetyStock,
                "补货点": p.reorderPoint,
                "补货周期(天)": p.leadTime,
                "当前库存": p.currentStock,
                "库存金额(¥)": (p.unitPrice * p.currentStock).toFixed(2)
            }));
        },
        
        // 获取销售数据用于导出
        getSalesForExport: function() {
            return DataManager.sales.map(s => {
                const product = DataManager.getProduct(s.productId);
                return {
                    "商品ID": s.productId,
                    "商品名称": product ? product.name : "未知商品",
                    "销售日期": s.date,
                    "销售数量": s.quantity,
                    "销售金额(¥)": s.amount.toFixed(2)
                };
            });
        },
        
        // 获取采购清单用于导出
        getPurchaseListForExport: function() {
            const list = PurchaseManager.generatePurchaseList();
            return list.map(item => ({
                "商品ID": item.productId,
                "商品名称": item.productName,
                "当前库存": item.currentStock,
                "补货点": item.reorderPoint,
                "补货周期(天)": item.leadTime,
                "预测需求量": item.forecastDemand,
                "建议采购量": item.suggestedQty,
                "单价(¥)": item.unitPrice,
                "总金额(¥)": item.totalCost
            }));
        }
    };

    // ==================== 模块6: 可视化模块 ====================
    const VisualizationManager = {
        // 初始化图表
        initCharts: function() {
            this.renderInventoryTrendChart();
            this.renderTopProductsChart();
        },
        
        // 渲染库存趋势图
        renderInventoryTrendChart: function() {
            const ctx = document.getElementById('inventoryTrendChart').getContext('2d');
            
            // 按类别统计库存
            const categories = ["electronics", "clothing", "food", "daily", "other"];
            const categoryNames = categories.map(cat => DataManager.getCategoryName(cat));
            const inventoryByCategory = categories.map(cat => 
                DataManager.products
                    .filter(p => p.category === cat)
                    .reduce((sum, p) => sum + p.currentStock, 0)
            );
            
            // 销毁旧图表实例(如果存在)
            if (window.inventoryTrendChart) {
                window.inventoryTrendChart.destroy();
            }
            
            window.inventoryTrendChart = new Chart(ctx, {
                type: 'bar',
                data: {
                    labels: categoryNames,
                    datasets: [{
                        label: '库存数量',
                        data: inventoryByCategory,
                        backgroundColor: [
                            'rgba(54, 162, 235, 0.7)',
                            'rgba(255, 99, 132, 0.7)',
                            'rgba(75, 192, 192, 0.7)',
                            'rgba(255, 159, 64, 0.7)',
                            'rgba(153, 102, 255, 0.7)'
                        ],
                        borderColor: [
                            'rgba(54, 162, 235, 1)',
                            'rgba(255, 99, 132, 1)',
                            'rgba(75, 192, 192, 1)',
                            'rgba(255, 159, 64, 1)',
                            'rgba(153, 102, 255, 1)'
                        ],
                        borderWidth: 1
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    scales: {
                        y: {
                            beginAtZero: true,
                            title: {
                                display: true,
                                text: '库存数量'
                            }
                        }
                    }
                }
            });
        },
        
        // 渲染热销商品排行图
        renderTopProductsChart: function() {
            const ctx = document.getElementById('topProductsChart').getContext('2d');
            
            // 计算每个商品的总销量
            const productSales = {};
            DataManager.sales.forEach(sale => {
                if (!productSales[sale.productId]) {
                    productSales[sale.productId] = 0;
                }
                productSales[sale.productId] += sale.quantity;
            });
            
            // 转换为数组并排序
            const sortedSales = Object.entries(productSales)
                .map(([productId, quantity]) => {
                    const product = DataManager.getProduct(productId);
                    return {
                        id: productId,
                        name: product ? product.name : "未知商品",
                        quantity: quantity
                    };
                })
                .sort((a, b) => b.quantity - a.quantity)
                .slice(0, 5); // 取前5名
            
            // 销毁旧图表实例(如果存在)
            if (window.topProductsChart) {
                window.topProductsChart.destroy();
            }
            
            window.topProductsChart = new Chart(ctx, {
                type: 'pie',
                data: {
                    labels: sortedSales.map(item => item.name),
                    datasets: [{
                        data: sortedSales.map(item => item.quantity),
                        backgroundColor: [
                            'rgba(255, 99, 132, 0.7)',
                            'rgba(54, 162, 235, 0.7)',
                            'rgba(255, 206, 86, 0.7)',
                            'rgba(75, 192, 192, 0.7)',
                            'rgba(153, 102, 255, 0.7)'
                        ],
                        borderWidth: 1
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    plugins: {
                        legend: {
                            position: 'right'
                        },
                        tooltip: {
                            callbacks: {
                                label: function(context) {
                                    const label = context.label || '';
                                    const value = context.raw || 0;
                                    const total = context.dataset.data.reduce((a, b) => a + b, 0);
                                    const percentage = Math.round((value / total) * 100);
                                    return `${label}: ${value}件 (${percentage}%)`;
                                }
                            }
                        }
                    }
                }
            });
        },
        
        // 渲染预测图表
        renderForecastChart: function(forecastResult) {
            const ctx = document.getElementById('forecastChart').getContext('2d');
            
            // 准备历史数据
            const historicalDates = forecastResult.historicalData.map(d => d.date);
            const historicalQuantities = forecastResult.historicalData.map(d => d.quantity);
            
            // 准备预测数据 (这里简化处理,实际应用中应生成未来日期)
            const forecastDates = [];
            const forecastQuantities = [];
            const lastDate = new Date(historicalDates[historicalDates.length - 1]);
            
            for (let i = 1; i <= forecastResult.forecastDays; i++) {
                const nextDate = new Date(lastDate);
                nextDate.setDate(nextDate.getDate() + i);
                forecastDates.push(nextDate.toISOString().split('T')[0]);
                forecastQuantities.push(Math.round(forecastResult.forecastQuantity / forecastResult.forecastDays));
            }
            
            // 销毁旧图表实例(如果存在)
            if (window.forecastChart) {
                window.forecastChart.destroy();
            }
            
            window.forecastChart = new Chart(ctx, {
                type: 'line',
                data: {
                    labels: [...historicalDates, ...forecastDates],
                    datasets: [
                        {
                            label: '历史销量',
                            data: [...historicalQuantities, ...Array(forecastDates.length).fill(null)],
                            borderColor: 'rgba(54, 162, 235, 1)',
                            backgroundColor: 'rgba(54, 162, 235, 0.1)',
                            tension: 0.3,
                            fill: false
                        },
                        {
                            label: '预测销量',
                            data: [...Array(historicalDates.length).fill(null), ...forecastQuantities],
                            borderColor: 'rgba(255, 99, 132, 1)',
                            backgroundColor: 'rgba(255, 99, 132, 0.1)',
                            borderDash: [5, 5],
                            tension: 0.3,
                            fill: false
                        }
                    ]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    scales: {
                        y: {
                            beginAtZero: true,
                            title: {
                                display: true,
                                text: '销量'
                            }
                        }
                    }
                }
            });
        }
    };

    // ==================== 主程序初始化 ====================
    document.addEventListener('DOMContentLoaded', function() {
        // 初始化数据
        DataManager.init();
        
        // 初始化图表
        VisualizationManager.initCharts();
        
        // 渲染预警信息
        AlertEngine.renderAlerts();
        
        // 标签页切换
        document.querySelectorAll('.tab').forEach(tab => {
            tab.addEventListener('click', function() {
                // 移除所有active类
                document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
                document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
                
                // 添加active类到当前标签
                this.classList.add('active');
                document.getElementById(`${this.dataset.tab}-tab`).classList.add('active');
                
                // 如果是预测标签页,初始化图表
                if (this.dataset.tab === 'forecast') {
                    VisualizationManager.initCharts();
                }
            });
        });
        
        // 商品表单提交
        document.getElementById('productForm').addEventListener('submit', function(e) {
            e.preventDefault();
            
            const product = {
                id: document.getElementById('productId').value,
                name: document.getElementById('productName').value,
                category: document.getElementById('category').value,
                unitPrice: parseFloat(document.getElementById('unitPrice').value),
                safetyStock: parseInt(document.getElementById('safetyStock').value),
                reorderPoint: parseInt(document.getElementById('reorderPoint').value),
                leadTime: parseInt(document.getElementById('leadTime').value),
                currentStock: parseInt(document.getElementById('currentStock')?.value || 0)
            };
            
            // 检查是新增还是编辑
            const existingProduct = DataManager.getProduct(product.id);
            if (existingProduct) {
                DataManager.updateProduct(product.id, product);
                alert('商品信息更新成功!');
            } else {
                // 设置默认当前库存
                if (!product.currentStock) product.currentStock = 0;
                if (DataManager.addProduct(product)) {
                    alert('商品添加成功!');
                } else {
                    alert('商品ID已存在,请使用不同的ID!');
                    return;
                }
            }
            
            // 重置表单
            this.reset();
        });
        
        // 销售表单提交
        document.getElementById('salesForm').addEventListener('submit', function(e) {
            e.preventDefault();
            
            const sale = {
                productId: document.getElementById('saleProduct').value,
                date: document.getElementById('saleDate').value,
                quantity: parseInt(document.getElementById('quantity').value),
                amount: parseFloat(document.getElementById('saleAmount').value)
            };
            
            if (DataManager.addSale(sale)) {
                alert('销售记录添加成功!');
                this.reset();
                // 设置默认日期为今天
                document.getElementById('saleDate').valueAsDate = new Date();
            } else {
                alert('添加失败,请检查商品ID是否正确!');
            }
        });
        
        // 设置销售日期默认值为今天
        document.getElementById('saleDate').valueAsDate = new Date();
        
        // 运行预测按钮
        document.getElementById('runForecastBtn').addEventListener('click', function() {
            const productId = document.getElementById('forecastProduct').value;
            const period = parseInt(document.getElementById('forecastPeriod').value);
            const method = document.getElementById('forecastMethod').value;
            
            if (!productId) {
                alert('请选择商品!');
                return;
            }
            
            const forecastResult = ForecastEngine.generateForecast(productId, period, method);
            if (!forecastResult) {
                alert('无法生成预测,可能是缺少销售数据!');
                return;
            }
            
            // 显示预测结果
            const resultsContainer = document.getElementById('forecastResults');
            resultsContainer.innerHTML = `
                <div class="alert alert-info">
                    <h3>${forecastResult.productName} 销量预测结果</h3>
                    <p>预测方法: ${method === 'movingAverage' ? '移动平均法' : '指数平滑法'}</p>
                    <p>预测周期: ${forecastResult.forecastDays} 天</p>
                    <p>预测销量: ${forecastResult.forecastQuantity} 件</p>
                    <p>预测销售额: ¥${forecastResult.forecastAmount}</p>
                </div>
            `;
            
            // 渲染预测图表
            VisualizationManager.renderForecastChart(forecastResult);
        });
        
        // 生成采购清单按钮
        document.getElementById('generatePurchaseListBtn').addEventListener('click', function() {
            PurchaseManager.renderPurchaseList();
        });
        
        // 导出商品按钮
        document.getElementById('exportProductsBtn').addEventListener('click', function() {
            const data = ReportManager.getProductsForExport();
            if (ReportManager.exportToExcel(data, '商品数据', '商品列表')) {
                alert('商品数据导出成功!');
            } else {
                alert('导出失败,请重试!');
            }
        });
        
        // 导出销售按钮
        document.getElementById('exportSalesBtn').addEventListener('click', function() {
            const data = ReportManager.getSalesForExport();
            if (ReportManager.exportToExcel(data, '销售数据', '销售记录')) {
                alert('销售数据导出成功!');
            } else {
                alert('导出失败,请重试!');
            }
        });
        
        // 导出采购清单按钮
        document.getElementById('exportPurchaseListBtn').addEventListener('click', function() {
            const data = ReportManager.getPurchaseListForExport();
            if (ReportManager.exportToExcel(data, '采购清单', '采购建议')) {
                alert('采购清单导出成功!');
            } else {
                alert('导出失败,请重试!');
            }
        });
        
        // 导入销售按钮 (简化版,实际应用中应使用文件上传)
        document.getElementById('importSalesBtn').addEventListener('click', function() {
            alert('导入功能需要服务器支持,当前为演示版本');
        });
    });
</script>

使用说明

快速上手指南

  1. 系统初始化:首次打开系统时,会自动创建示例商品和销售数据
  2. 商品管理:在"商品管理"标签页添加、编辑或删除商品信息
  3. 销售录入:在"销售数据"标签页记录每日销售情况
  4. 预测分析:在"预测分析"标签页选择商品和预测方法,生成销量预测
  5. 采购清单:在"采购清单"标签页自动生成建议采购清单
  6. 数据导出:在各标签页可导出Excel格式的报表

核心操作流程

  1. 库存预警设置:
    • 为每个商品设置安全库存、补货点和补货周期
    • 系统自动监控库存状态并分级预警(严重/偏低/积压)
  2. 销量预测步骤:
    • 选择目标商品
    • 设置预测天数(默认30天)
    • 选择预测方法(移动平均法/指数平滑法)
    • 点击"运行预测"生成结果和图表
  3. 采购清单生成:
    • 系统自动识别需要补货的商品
    • 基于预测销量和安全库存计算建议采购量
    • 考虑经济订货量(EOQ)简化模型优化采购成本

高级功能

  • 数据可视化:库存分布热力图、热销商品排行、预测趋势对比图
  • 多维度分析:按商品类别、时间段分析销售和库存状况
  • 批量操作:支持Excel导入导出,方便数据迁移
  • 权限管理:可扩展用户角色和权限控制(需后端支持)

核心知识点卡片

卡片1: 时间序列预测

知识点:基于历史数据预测未来趋势

说明:系统采用移动平均法和指数平滑法进行销量预测,前者适合稳定趋势,后者对近期数据更敏感

战略价值:数据驱动的决策支持,避免经验主义误差

创新思维:动态调整预测模型参数,持续优化预测精度

卡片2: 安全库存管理

知识点:平衡缺货风险与库存成本的缓冲机制

公式:安全库存 = (最大日销量 - 平均日销量) × 最长补货周期

战略价值:保障客户服务水平的同时降低资金占用

创新思维:结合ABC分类法对商品分级管理(A类重点监控)

卡片3: 经济订货量(EOQ)

知识点:最小化总库存成本的订货批量模型

公式:EOQ = √[(2DS)/H],其中D=年需求量,S=订货成本,H=单位库存持有成本

战略价值:优化采购频率和批量,降低综合成本

系统实现:简化版EOQ应用于采购清单生成

卡片4: 库存周转率

知识点:衡量库存流动效率的关键指标

公式:周转率 = 销售成本 / 平均库存余额

战略价值:反映资金使用效率和商品变现能力

创新思维:结合行业基准进行对比分析,识别滞销品

卡片5: 预警分级机制

知识点:三级预警体系(红/黄/蓝)对应不同风险等级

实施:红色(缺货)、黄色(低库存)、蓝色(积压)

战略价值:差异化响应策略,提高管理效率

创新思维:引入预警升级机制,持续未处理预警自动上报

卡片6: 敏捷迭代管理

知识点:快速响应市场变化的持续改进方法

实施:每周回顾预测准确率,每月优化模型参数

战略价值:适应中小商家业务快速变化的特点

创新思维:建立"预测-执行-复盘"的PDCA闭环

系统特点

  1. 战略管理融合:将库存周转率、EOQ模型等管理理论与系统功能深度结合
  2. 创新思维应用:采用动态预警、多模型预测对比等创新方法
  3. 模块化架构:6大独立模块便于功能扩展和维护升级
  4. 数据驱动决策:所有建议基于历史数据分析,减少主观判断
  5. 用户友好设计:简洁界面+可视化图表,降低中小商家使用门槛
  6. 低成本部署:纯前端实现,无需服务器支持,本地即可运行

该系统适用于零售、批发等各类中小商家,帮助实现库存精细化管理,降低运营成本,提升资金周转效率。 关注我,有更多编程干货等着你!