惠州市网站建设_网站建设公司_动画效果_seo优化
2025/12/17 12:00:00 网站建设 项目流程

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

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库

核心代码实现

<!DOCTYPE html>

<html lang="zh-CN">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>中小商家库存智能预警系统</title>

<script src="lib/xlsx.full.min.js"></script>

<script src="lib/chart.min.js"></script>

<style>

: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>

</head>

<body>

<div class="container">

<header>

<div class="header-content">

<h1>📊 中小商家库存智能预警系统</h1>

<div class="user-info">

<span id="currentDate"></span>

</div>

</div>

</header>

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

</body>

</html>

使用说明

快速上手指南

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. 低成本部署:纯前端实现,无需服务器支持,本地即可运行

该系统适用于零售、批发等各类中小商家,帮助实现库存精细化管理,降低运营成本,提升资金周转效率。

关注我,有更多编程干货等着你!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询