
这篇文章是《Web简易ERP进销存管理系统》系列的第 01 篇。系列目标是带着你从零搭建一个可用的 Web 进销存系统而不是只贴概念图。先聊一个很直接的问题市面上成熟的 ERP 系统非常多为什么还要自己写一个简易 ERP答案通常是三个场景。第一学习。Spring Boot、Vue、MySQL 这些技术单独学容易组合起来做一个完整业务系统很难进销存是最适合练手的业务模型。第二毕业设计。进销存几乎是计算机专业毕设里出现频率最高的题目之一选一套清晰的系统设计比堆功能更重要。第三小微企业轻量管理。很多小团队没有专门的 IT 人员大型 ERP 太重、太贵一个 Web 化的简易进销存系统能解决商品资料、采购、销售、库存和基础报表的核心诉求就够了。这篇文章是系列开篇不写具体代码实现先把整体规划讲清楚系统解决什么问题、包含哪些模块、用什么技术栈、数据库怎么设计、后续怎么一步步开发。读完你会对整个项目有完整认知后面每一期只需要照着路线图填充细节。1. 核心能力速览能力项说明项目类型基于 Web 的简易 ERP 进销存管理系统核心业务商品资料、供应商、客户、采购入库、销售出库、库存流水、库存结余、业务报表系统形态B/S 架构浏览器访问无需安装客户端常见角色管理员、采购员、销售员、仓库管理员技术栈方案轻量方案Flask Vue SQLite/MySQL企业级方案Spring Boot MyBatis-Plus MySQL Vue运行环境Windows / Linux 均可需安装对应运行时和数据库部署方式前后端分别部署或打包后由 Nginx 托管静态文件并反向代理后端是否支持 API后端按 RESTful 风格提供接口方便后续对接小程序、扫码枪等是否支持批量任务采购单、销售单支持批量导入或批量录入需后续实现适合场景技术学习、毕业设计、小微企业内部轻量管理从当前系列定位来看这是一个教学型项目。功能不会做成 SAP、Oracle ERP 那种大而全而是把进销存最核心的链路跑通商品档案 → 采购入库 → 库存增加 → 销售出库 → 库存减少 → 报表统计。这条链路清晰、完整也最容易验证业务逻辑是否正确。2. 适用场景与使用边界2.1 适合解决的业务问题进销存本质上管的是三件事进、销、存。进向供应商采购商品生成采购订单到货后入库。销向客户销售商品生成销售订单发货后出库。存实时记录每个商品在哪个仓库、剩余多少、出入库流水是否可追溯。系统还要解决三个基础资料的问题商品信息、供应商信息、客户信息。商品信息包括编码、名称、规格、单位、分类、价格等供应商信息用于采购业务客户信息用于销售业务。基础资料越规范后面的库存和报表越准确。2.2 不适合做什么在设计简易 ERP 时有几块复杂度很高不建议一上来就做生产制造 BOM、工单、工序排程这是专业 MES/ERP 的领域不是简易系统能覆盖的。财务总账、应收应付、固定资产、成本核算这些需要会计逻辑和严格的凭证体系适合对接专业财务软件。多公司、多组织架构、多币种涉及复杂的结算规则不适合在入门项目中实现。复杂审批流例如多级审批、自定义流程引擎会影响核心业务的建设优先级。因此这个系统的业务边界要提前划清楚只做进销存不做财务不做生产不做复杂审批。把核心链路做稳定再逐步扩展。2.3 数据安全与合规边界进销存系统里会存商品成本、销售价格、客户资料、库存数量等经营数据。开发和使用时需要注意系统上线前要设置强密码和访问控制不能把管理后台暴露到公网裸奔。涉及客户隐私信息电话、地址时必须获得对方授权并按相关法规做好隐私保护。数据要有定期备份机制防止服务器故障导致商业数据丢失。如果后续接入扫码枪、电子秤、小程序等设备接口调用要加鉴权不能开放任意写入。3. 系统整体架构设计简易 ERP 采用典型的前后端分离架构也可以根据技术栈不同选择服务端渲染模式。这里推荐前后端分离因为接口清晰、便于后续扩展。整体架构分为三层展示层Web 前端页面包括登录、首页看板、基础资料管理、业务单据、库存查询、报表图表。业务层后端服务处理权限、业务规则、事务控制、数据校验。数据层数据库存储核心是基础资料表、业务单据表、库存流水表和报表统计表。模块划分推荐如下模块主要功能系统管理用户管理、角色管理、菜单权限、操作日志基础资料商品分类、商品信息、供应商、客户、仓库采购管理采购订单、采购入库、采购退货可选销售管理销售订单、销售出库、销售退货可选库存管理库存查询、库存流水、库存盘点、预警报表统计采购报表、销售报表、库存报表、利润统计简化版这个模块划分适合第一版迭代。后续如果需要可以在报表模块增加图表展示也可以把采购和销售模块的订单与入库/出库流程分离。4. 技术选型建议进销存系统的技术选型主要看你当前的目的是什么。有两种路线比较常见。4.1 轻量快速路线Flask / FastAPI Vue SQLite该组合适合 Python 技术栈学习、课程设计或者快速做原型验证。后端使用 Flask 或 FastAPI前端使用 Vue 3 Element Plus数据库先用 SQLite 起步后期可以切换到 MySQL。优点环境准备简单Python 安装后即可启动。Flask 代码量少适合快速理解业务逻辑。SQLite 文件数据库无需额外安装服务方便本地开发和演示。缺点高并发能力一般适合小团队内部试用。SQLite 在多用户并发写入时会有锁竞争正式环境建议切换 MySQL。4.2 企业级学习路线Spring Boot MyBatis-Plus MySQL Vue该组合适合 Java 技术栈学习、毕业设计或者作为可扩展的系统底座。后端使用 Spring BootORM 使用 MyBatis-Plus 减少 SQL 编写前端使用 Vue 3 Vite Element Plus数据库使用 MySQL 8.x。优点生态成熟岗位需求量大学完直接能写企业级项目。Spring Boot 的事务管理可以很好地保证采购入库、销售出库的库存一致性。后续对接小程序、APP 或者第三方系统都比较方便。缺点环境安装和项目配置相对复杂需要 JDK、Maven、MySQL。做选择时不用太纠结。如果是 Java 方向选方案二如果是 Python 方向或快速验证选方案一。系列后续文章会以 Spring Boot Vue 为主路线讲解但核心设计思路两种方案通用。5. 数据库设计核心思路进销存系统的数据库设计最关键的是库存数据。不能只存一张“当前库存表”一定要有流水表来记录每一次出入库变化。否则一旦出现数据错误很难追溯。推荐的表结构设计思路如下5.1 核心表清单表名用途sys_user用户表sys_role角色表sys_user_role用户角色关联表biz_category商品分类表biz_product商品信息表biz_supplier供应商表biz_customer客户表biz_warehouse仓库表biz_purchase_order采购订单主表biz_purchase_order_item采购订单明细表biz_purchase_inbound采购入库单主表biz_purchase_inbound_item采购入库单明细表biz_sale_order销售订单主表biz_sale_order_item销售订单明细表biz_sale_outbound销售出库单主表biz_sale_outbound_item销售出库单明细表biz_stock_balance库存结余表biz_stock_flow库存流水表biz_stock_check盘点记录表可选5.2 商品信息表示例商品表不需要设计得太复杂但编码、名称、规格、单位、分类、默认进价、默认售价都属于常规必填项。CREATE TABLE biz_product ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 主键, product_code VARCHAR(50) NOT NULL UNIQUE COMMENT 商品编码, product_name VARCHAR(200) NOT NULL COMMENT 商品名称, category_id BIGINT COMMENT 分类ID, spec VARCHAR(100) COMMENT 规格型号, unit VARCHAR(20) COMMENT 计量单位, default_purchase_price DECIMAL(10,2) DEFAULT 0 COMMENT 默认进价, default_sale_price DECIMAL(10,2) DEFAULT 0 COMMENT 默认售价, status TINYINT DEFAULT 1 COMMENT 状态1启用 0停用, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, deleted TINYINT DEFAULT 0 COMMENT 逻辑删除 ) COMMENT 商品信息表;5.3 库存结余表与流水表库存结余表保存当前仓库、当前商品的实时库存用于查询。库存流水表记录每一次入库、出库、盘点、调整的操作用于追溯。结余表可以冗余“最后更新时间”但算法要统一。CREATE TABLE biz_stock_balance ( id BIGINT PRIMARY KEY AUTO_INCREMENT, product_id BIGINT NOT NULL COMMENT 商品ID, warehouse_id BIGINT NOT NULL COMMENT 仓库ID, quantity DECIMAL(12,2) DEFAULT 0 COMMENT 当前库存数量, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_product_warehouse (product_id, warehouse_id) ) COMMENT 库存结余表; CREATE TABLE biz_stock_flow ( id BIGINT PRIMARY KEY AUTO_INCREMENT, product_id BIGINT NOT NULL COMMENT 商品ID, warehouse_id BIGINT NOT NULL COMMENT 仓库ID, change_type VARCHAR(20) NOT NULL COMMENT 类型PURCHASE_IN SALE_OUT STOCK_IN STOCK_OUT CHECK, change_quantity DECIMAL(12,2) NOT NULL COMMENT 变动数量入库正出库负, before_quantity DECIMAL(12,2) COMMENT 变动前库存, after_quantity DECIMAL(12,2) COMMENT 变动后库存, biz_type VARCHAR(50) COMMENT 关联业务类型, biz_no VARCHAR(50) COMMENT 关联业务单号, remark VARCHAR(255) COMMENT 备注, create_by BIGINT COMMENT 操作人, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) COMMENT 库存流水表;在业务实现中采购入库、销售出库这些操作必须在同一个数据库事务里完成两件事更新库存结余表写入库存流水表。这样才能保证库存数据可追溯、不会凭空消失。6. 项目目录结构与启动流程不管是 Java 后端还是 Python 后端项目目录结构都应该遵循分层设计controller、service、mapper/repository、entity/model、dto、config 等。6.1 后端目录结构示例Spring Booterp-backend/ ├── src/main/java/com/example/erp/ │ ├── ErpApplication.java │ ├── controller/ │ │ ├── AuthController.java │ │ ├── ProductController.java │ │ ├── PurchaseController.java │ │ ├── SaleController.java │ │ └── StockController.java │ ├── service/ │ │ ├── impl/ │ │ └── ... │ ├── mapper/ │ ├── entity/ │ ├── dto/ │ ├── config/ │ └── common/ ├── src/main/resources/ │ ├── application.yml │ ├── mapper/ │ └── db/ │ └── init.sql └── pom.xml6.2 前端目录结构示例Vue 3 Viteerp-frontend/ ├── src/ │ ├── api/ │ │ ├── product.js │ │ ├── purchase.js │ │ ├── sale.js │ │ └── stock.js │ ├── assets/ │ ├── components/ │ ├── router/ │ ├── store/ │ ├── views/ │ │ ├── Login.vue │ │ ├── dashboard/ │ │ ├── product/ │ │ ├── purchase/ │ │ ├── sale/ │ │ └── stock/ │ ├── App.vue │ └── main.js ├── package.json └── vite.config.js6.3 通用启动命令模板实际启动命令需要按项目实际情况调整。下面给出通用模板# 后端启动Spring Boot cd erp-backend mvn spring-boot:run # 后端启动Flask cd erp-backend pip install -r requirements.txt python app.py # 前端启动 cd erp-frontend npm install npm run dev启动后前端开发服务器一般会占用一个端口例如 5173后端接口服务占用另一个端口例如 8080。如果出现端口被占用可以分别修改配置文件中的端口号。前后端联调时需要在前端设置 API 代理地址把/api请求转发到后端服务。7. 功能流程演示与验证计划虽然是系统整体介绍但也需要把核心业务流程和验证方式讲清楚。后续每个功能模块都会按下面的流程开发。7.1 主业务流一个完整的进销存主流程如下管理员登录系统。维护基础资料新增商品分类、商品信息、供应商、客户、仓库。采购员创建采购订单选择供应商和商品填写数量和进价。采购订单审核通过后仓库管理员执行入库操作。系统自动增加库存结余并记录一条采购入库流水。销售员创建销售订单选择客户和商品填写数量和售价。销售订单审核通过后仓库管理员执行出库操作。系统自动扣减库存并记录一条销售出库流水。库存报表和销售报表实时更新管理者可以查看毛利和库存情况。7.2 功能验证清单验证点输入 / 操作预期结果用户登录输入正确账号密码登录成功进入首页错误密码提示失败商品新增新增商品编码、名称、价格商品列表展示新商品重复编码被拦截采购入库创建采购单并入库库存结余增加库存流水生成销售出库创建销售单并出库库存结余减少库存流水生成库存防负出库数量大于当前库存系统提示库存不足或不允许负数可按业务开关控制权限控制普通用户访问用户管理菜单返回无权限提示数据一致性并发执行多笔出库库存最终结果正确无超卖或负数7.3 判断成功的标准一套进销存系统能不能用不只看页面是否好看关键看两点第一库存流水是否完整。每一次数量变动都能在流水表里找到对应的业务单号和时间。第二库存结余是否准确。在任意时间点库存结余等于所有入库流水数量减去所有出库流水数量。如果出现不一致说明事务控制或业务逻辑有问题。8. 接口 API 设计示例前后端分离模式下后端提供 RESTful API。以下是一组基础接口约定实际开发中需要根据项目模块调整。方法路径功能POST/api/auth/login用户登录GET/api/product/page商品分页查询POST/api/product新增商品PUT/api/product/{id}修改商品DELETE/api/product/{id}删除商品GET/api/stock/balance库存结余查询POST/api/purchase/inbound创建采购入库单POST/api/sale/outbound创建销售出库单GET/api/report/sale销售报表查询下面给出一个通用的 API 调用示例使用 Python requests 模拟创建采购入库单。实际接口路径和字段需要按你的项目定义来调整import requests url http://127.0.0.1:8080/api/purchase/inbound headers { Authorization: Bearer TOKEN, Content-Type: application/json } payload { supplierId: 1, warehouseId: 1, items: [ { productId: 10, quantity: 20, purchasePrice: 15.5 } ], remark: 第一批测试采购入库 } response requests.post(url, jsonpayload, headersheaders, timeout30) print(response.status_code) print(response.json())对应返回结果可以设计为{ code: 200, message: success, data: { inboundNo: RK202501010001, stockFlows: 1 } }接口设计要注意几点所有写操作都需要校验登录状态和操作权限采购入库、销售出库这类影响库存的接口必须有事务控制返回结果统一封装 code、message、data方便前端处理。9. 关键问题与排查思路开发 Web 进销存系统过程中遇到问题最多的集中在数据库、跨域、库存和部署几个方面。问题现象可能原因排查方式解决方案后端服务启动失败端口被占用或配置错误查看启动日志检查端口占用更换端口或关闭占用进程数据库连接失败MySQL 未启动、账号密码错误、库不存在检查 application.yml 配置确认数据库服务和账号权限前端请求接口跨域前后端域名或端口不一致打开浏览器控制台查看 CORS 报错后端配置跨域或前端配置代理库存出现负数未做库存校验或并发问题检查出库接口逻辑和事务出库前查询库存数量不足直接拦截必要时加锁采购入库后库存没变事务未提交或流程未执行完查看后端日志检查库存流水确认入库存方法事务生效异常时回滚页面刷新后 404前端路由是 history 模式检查 Nginx 部署配置Nginx 配置 try_files 指向 index.html数据异常但无日志日志级别太低或异常被吞调整日志级别为 DEBUG打印关键流水日志记录操作人和时间多人同时出库超卖高并发下单行更新竞争查看数据库锁和流水记录对库存扣减使用条件更新WHERE quantity ?9.1 库存扣减的常见实现库存扣减是进销存最容易出 Bug 的地方。推荐使用乐观更新加条件判断UPDATE biz_stock_balance SET quantity quantity - #{quantity}, update_time NOW() WHERE product_id #{productId} AND warehouse_id #{warehouseId} AND quantity #{quantity};如果更新影响行数为 0说明库存不足直接抛出业务异常回滚事务。同时无论成功失败都写入一条库存流水记录。10. 开发路线图与后续系列安排为了让整套系统可落地建议按下面的路线推进。每期解决一个明确问题做完一期就能跑通一个阶段。阶段主题产出01系统整体介绍需求分析、模块划分、技术选型、数据库设计思路本文02开发环境搭建JDK、MySQL、Vue 项目初始化前后端运行成功03数据库建库与基础代码建表 SQL、项目骨架、统一返回结果和异常处理04用户登录与权限管理登录接口、JWT、角色权限、前端路由守卫05基础资料模块产品分类、商品信息、供应商、客户、仓库管理06采购入库模块采购订单、采购入库、库存更新07销售出库模块销售订单、销售出库、库存扣减08库存查询与流水库存结余、库存流水、库存预警09报表统计与首页看板销售报表、采购报表、商品销售排行10部署上线与操作手册Linux 部署、Nginx 配置、数据备份、使用说明第一期的重点是把业务边界和技术方向定下来。不要急着写代码先把模块、表和流程想清楚后面开发会顺畅很多。最容易踩的坑有两个一是库存没有流水表出问题只能手工改数据库二是权限设计得过于复杂导致迟迟做不完核心业务。建议第一次开发时权限只做“管理员、采购员、销售员、仓库管理员”四种角色权限控制到菜单级别即可。核心优先先把采购入库、销售出库、库存流水跑通再优化权限和报表。下一期也就是系列第 02 篇会带你完整搭建开发环境安装 JDK、Maven、MySQL初始化 Spring Boot 后端项目和 Vue 3 前端项目并让一个最简单的“Hello World”接口在前端页面上显示出来。这是整个系统开发的第一步也是很多新手上手时最容易卡住的一步。到时候可以先把环境装好下一篇直接跟着操作。