进销存ERP系统实战:Spring Boot+Vue3+小程序设计全解析
简介完整的进销存ERP管理系统源码基于VS2012 .NET与MsSQL开发适合中小企业、软件实施人员及.NET开发者快速搭建或二次开发进销存/仓库/电商订单管理平台。系统标准版功能简洁实用已有多家企业稳定运行包含销售订单、销售出库、采购订单、采购入库、生产管理等核心模块并支持与微信、小程序、公众号订单对接前后端齐全便于直接部署与扩展。压缩包共7267个文件大小46.71MB以cs、aspx、js、css等后端与前端源码为主含大量png/jpg/gif界面图与资源文件以及wxml/wxss小程序前端文件、ashx一般处理程序等目录结构清晰覆盖Web端和小程序端完整代码。目前已有9655人学习下载适合需要一套成熟可用的进销存ERP基线代码、用于业务定制或学习.NET企业级项目架构的开发者参考使用。1. 先想清楚再动手进销存ERP到底在管什么很多小团队的业务负责人跟我聊库存管理第一句话都是“我们商品才几百个Excel够用了”。等真做到上千个SKU、多个人同时开单问题就全冒出来了——销售不知道哪些货能卖采购不知道什么时候该补货月底盘完点差异能吵一晚上。进销存ERP管理系统就是为这个问题而生的把采购、销售、库存三条线串起来让每一笔货的来龙去脉都有据可查。我整理过一套带小程序端的完整源码后台用Vue3接口用Spring Boot小程序端覆盖仓管员扫码和老板看报表这些高频场景。这篇文章不打算给你贴一个“下载即跑”的幌子我想把真正决定项目成败的设计思路和踩坑过程讲透。适合要做这套系统的开发者、准备拿它做毕业设计的学生以及想给自家小团队选型或二次开发的负责人。1.1 三条业务主线不是各管各的进销存的核心不是“增删改查”而是“业务流程不乱、库存账实相符”。先理清三条主线采购线供应商 → 采购订单 → 收货质检 → 采购入库 → 生成应付账款销售线客户 → 销售订单 → 发货出库 → 生成应收账款库存线商品在仓库里的入库、出库、调拨、盘点、结存、安全库存预警这三条线不是各管各的它们通过“仓库里的商品数量”互相咬合。销售出库会减少库存采购入库会增加库存调拨会在仓库之间移动库存。你做的每一个功能本质上都是在为“库存结存”服务。用开超市打比方采购就是进货销售就是卖货库存就是货架上的数。货架上的数必须和实际摆放一致否则采购和销售都会做出错误决策。1.2 单据状态机一切库存变动必须依附单据这是进销存系统跟普通CRUD最大的区别。我见过有人把库存做成一个可编辑的表单结果月底一查全是手工改的数据对不上账只能干瞪眼。正确的做法是定义单据状态机草稿 → 已审核 → 已完成 → 已作废。只有已审核的单据才真正影响库存审核之前都只是“想法”不改变任何现有数据。审核之后允许“反审核”但反审核不能把记录物理删除而是要么生成一笔数量相反的调整记录要么把原单标记作废后重新做单。为什么这么麻烦因为要保证审计轨迹完整。哪天老板问“这批货为什么少了”你能顺着流水账一路查到具体是哪张单、哪个人、哪个时间点操作的而不是只看到一个被删掉的空洞。这一点在进销存系统里不是可选项是灵魂。1.3 第一版要主动砍掉的功能边界进销存ERP这几个字听起来很唬人但小团队的资源有限。我建议第一版老老实实砍掉这些东西不做BOM和工序级的车间管理那是MES或者专业ERP的领域不做财务总账和固定资产管理那不是进销存该管的事不做复杂的成本分摊成本核算先做到“移动加权平均”就够了。移动加权平均是什么意思就是每次采购入库时重新计算一次商品的平均成本销售出库时按这个平均成本结转毛利自然就能算出来。这套逻辑对小团队足够用而且实现简单。第一版的功能边界越清楚核心库存链路就越稳。功能少不是丢人数据乱才是真麻烦。2. 技术选型为什么是Spring Boot Vue3 uni-app三件套选型这件事我不喜欢追新讲究的是社区活跃、资料多、部署成本低。我最后定下来的技术栈是后端Spring Boot 3.x MyBatis-Plus MySQL 8管理后台用Vue3 Element Plus Vite Pinia小程序端用uni-app。下面把每一个选择背后的理由说透。2.1 后端的务实选择Spring Boot生态成熟打包出来一个java -jar就能跑对没有专职运维的小团队非常友好。MyBatis-Plus的BaseMapper把单表CRUD几乎写成了配置能把精力省给业务设计。数据库用MySQL 8InnoDB的事务和行锁是库存扣减的基本保障后面讲并发坑的时候你会明白为什么必须依赖它。权限框架我用的是Sa-Token而不是Spring Security。原因很直接Sa-Token轻量很多内置token自动续期、注解鉴权对接小程序登录比Security省心一个量级。我做进销存这种内部工具系统根本不需要Security那套复杂的过滤器链Sa-Token开箱即用文档也接地气。这里多说一句这套系统不要上微服务。进销存的数据量和并发在小团队场景下单体应用完全扛得住微服务只是徒增运维成本。把库存变动的核心逻辑收敛在单个事务里数据一致性反而更好保证。2.2 管理端和小程序端怎么选框架管理端选Vue3 Element Plus原因是Vue3的Composition API写这类强交互后台很顺手逻辑复用比Options API干净。Element Plus的表格、表单、弹窗、树形选择组件非常全做进销存这种表单密集的后台开发效率比从零写组件高太多。Vite冷启动秒开开发体验比Webpack时代好两个档次。状态管理用Pinia轻量且天然支持TypeScript适合存当前登录用户、仓库切换、权限列表这类全局状态。小程序端我选了uni-app而不是原生微信小程序。原因很现实很多项目跑着跑着就想要H5版本或者Android Appuni-app一套代码能编译到多个端仓库维护成本低很多。配套uView Plus这类组件库做表单和列表页速度很快。有人担心uni-app性能不如原生实际做进销存这种管理工具完全够用——真正的瓶颈在网络请求和数据量上不在框架本身。2.3 工程目录与一条重要设计原则这套系统的目录结构大致长这样backend: src/main/java/com/xxx/erp controller/ // 接口层只做参数校验和结果返回 service/ // 业务层库存变动统一走这里 mapper/ // MyBatis-Plus数据访问 entity/ // 数据库实体 common/ // 统一返回、异常处理、工具类 frontend-admin: // Vue3后台 src/views purchase/ // 采购模块 sale/ // 销售模块 stock/ // 库存模块 report/ // 报表模块 system/ // 系统管理 frontend-app: // uni-app小程序 pages login/ index/ stock/ purchase/ sale/ mine/整个工程里最重要的一条设计原则是库存变动不要分散在各业务Service里一定要收敛到一个独立的StockService。所有采购入库、销售出库、盘盈盘亏都调用这个统一入口并且事务边界就画在StockService上。这个设计在前期看着不起眼等出现并发问题、库存对不上问题的时候你会感谢当初这个决定。3. 数据模型里最关键的两件事库存流水账与单据状态机数据模型是进销存的灵魂这一章专门说两个容易被忽略但决定成败的设计库存表和流水账分离、单据状态机。很多人做进销存失败不是不会写代码是表结构设计有问题。3.1 基础档案表与主从单据结构先有商品、仓库、供应商、客户这些基础档案业务单据才有关联对象。商品表的核心字段是这几样sku_code唯一编码、barcode条码、name名称、category_id分类、unit单位、purchase_price采购价、sale_price销售价、safety_stock安全库存、status状态。其中barcode是为了小程序扫码准备的safety_stock用来做库存预警。仓库表、供应商表、客户表结构不展开但记住每个表都要有create_time、update_time、deleted三个公共字段。软删除在进销存里特别重要因为历史单据引用的档案不能真正消失否则单据详情页会显示一片空白。采购订单、采购入库、销售订单、销售出库、调拨单、盘点单这六类单据全部采用“主表明细表”的双层结构。主表放业务公共信息单据编号、单据日期、往来单位ID、仓库ID、经办人、总金额、状态、审核人、审核时间。明细表放商品级数据商品ID、数量、单价、金额、行备注。这样设计的好处是列表页查询只查主表详情页再关联明细数据不冗余状态流转只看主表一个字段。几乎是所有进销存系统的通用范式。采购入库单的主表SQL大概是这样的CREATE TABLE purchase_inbound ( id BIGINT PRIMARY KEY AUTO_INCREMENT, bill_no VARCHAR(32) NOT NULL UNIQUE COMMENT 单据编号, bill_date DATE NOT NULL COMMENT 单据日期, supplier_id BIGINT NOT NULL COMMENT 供应商ID, warehouse_id BIGINT NOT NULL COMMENT 仓库ID, total_amount DECIMAL(18,2) NOT NULL DEFAULT 0, status TINYINT NOT NULL DEFAULT 0 COMMENT 0草稿 1已审核 2已完成 -1已作废, audit_by BIGINT COMMENT 审核人ID, audit_time DATETIME COMMENT 审核时间, create_time DATETIME NOT NULL, update_time DATETIME NOT NULL, deleted TINYINT NOT NULL DEFAULT 0 );3.2 库存表与流水账为什么必须分离库存表存的是“当前结余”核心字段就是sku_id、warehouse_id、quantity三者做唯一索引。流水账存的是“每一笔变动”包括单据类型、单据号、变动前数量、变动数量、变动后数量、操作人、操作时间、关联明细ID。这两张表虽然都跟数量有关职责完全不同——库存表是快照流水账是审计轨迹。没有流水账的库存系统出了问题根本没法溯源这是新手最容易犯的错。任何业务代码都不能直接UPDATE库存表的quantity。必须调用StockService的统一入口在一个事务里先写流水、再更新库存。库存扣减要用原子更新防止并发超卖UPDATE stock SET quantity quantity - #{qty}, update_time NOW() WHERE sku_id #{skuId} AND warehouse_id #{warehouseId} AND quantity #{qty}受影响行数为0说明库存不足直接抛出业务异常。为什么不能先SELECT再UPDATE因为两个请求同时读到quantity1的时候都会判断“够”然后都执行扣减库存就变负了。原子更新把判断和扣减放在一条SQL里数据库的行锁保证了同一时刻只有一个请求能成功。3.3 索引和唯一约束别等数据量上来再补单据编号必须加唯一约束防止同一张单被重复提交明细表要建bill_id索引库存表要建sku_id warehouse_id的唯一索引商品表的barcode建议建普通索引小程序扫码模糊匹配时很有用。这些细节看着不起眼数据量到几十万条之后缺索引的查询能把接口拖到几秒报表页面直接打不开。我接手过一个慢SQL案例库存查询接口要3秒多EXPLAIN一看warehouse_id没有索引全表扫描十几万行。加上一个联合索引之后查询时间降到20毫秒。这个问题在开发阶段数据量小的时候完全看不出来上线三个月后才爆发。所以表结构设计阶段就把索引规划好比事后补要省太多事。4. 管理端与小程序端业务闭环怎么真正落地技术选型和数据模型定了接下来就是把业务功能落地。核心原则是后台管全流程小程序管高频移动场景。两边各管各的谁也不越界。4.1 后台四个模块与审核过账链路管理端分采购、销售、库存、报表四大模块。采购模块采购订单管理、采购入库、供应商管理、应付账款明细。销售模块销售订单管理、销售出库、客户管理、应收账款明细。库存模块库存查询、调拨单、盘点单、库存预警。报表模块进销存汇总表、商品销售排行、销售毛利、往来对账。操作链路要顺列表页新增单据 → 明细编辑 → 保存草稿 → 提交审核 → 审核通过后系统自动过账。所谓过账就是自动生成库存流水并更新库存表这一步必须放在审核动作的事务里。采购入库和采购订单之间做“引用关联”入库单只能引用已审核且未入库完成的订单数量避免重复入库。销售出库同理超卖往往就是出库环节没有和订单锁定库存导致的。审核这个动作是权限敏感点我建议单独分配审核角色不要让开单的人自己审自己的单。这不是不信任而是内控的基本要求。单据保存成草稿阶段可以随便改一旦提交审核就锁死编辑按钮审核通过后连删除入口都不给只能反审核。这套逻辑虽然严格但换来了数据的可信度。4.2 小程序端的三种身份与扫码作业小程序端不要做成PC端的完整迁移只做高频场景就能解决很大问题。仓管员最常用的是扫码出入库、库存查询、盘点录入调用wx.scanCode扫条码通过barcode查询商品带出名称和规格输入数量就能提交出入库单。业务员最常用的是新建销售订单、查客户欠款、跟进记录手边没有电脑时先把订单录进去业务流转不会卡住。老板最常用的是今日销售额、热销商品、库存预警、应收应付汇总一个看板式首页全搞定。登录流程用wx.login换取openid后端生成业务token并绑定员工账号后续请求带token即可。这里要提醒一句小程序的类目和功能必须和实际运营内容一致涉及电商交易的还要提前办好微信支付商户资质。微信支付v3对接前先确认主体和类目合规不然很容易出现“支付功能被限制”之类的提示处理起来非常麻烦。另外仓管员扫码作业经常在仓库现场网络不一定好。接口请求必须加上超时时间和错误提示提交单据失败时要把数据保留在本地网络恢复后给用户一个“重试”按钮而不是直接把这单数据丢掉。这个小细节直接影响仓库作业能不能顺畅跑起来。4.3 数据权限与多仓库多仓库场景下用户和仓库要建立关联关系接口层统一取当前用户的仓库权限而不是前端只做一个下拉框。用户在接口层面只能查到有权限的仓库数据别人登录后看不到不该看的内容。这既是数据安全要求也是为了避免误操作。实现方式不复杂用户表加一个warehouse_ids字段或者单独建关联表在SQL查询条件里动态拼接。后台管理端在菜单里配置角色权限小程序端根据角色显示不同的首页功能。权限这块别等到上线再补数据已经录进去之后再加权限成本会成倍增加。5. 上线前后最容易踩的坑从测试设计到库存对账最后这部分是真金白银换来的经验。我把上线前后踩过的坑整理出来按出现频率排序希望你不用再走一遍。5.1 期初库存导入和关键接口测试系统上线第一天没有历史数据要把原来Excel里的库存导进去。这里最容易犯的错是直接UPDATE库存表。正确的做法是生成一张“期初库存盘点调整单”走正常的库存变动流程这样流水账从头就是完整的后面所有对账都有依据。上线前的测试至少要覆盖两个核心用例用JUnit MockMvc写自动化用例第一审核采购入库单后库存增加且流水账新增记录第二反审核已入库单据后库存回滚且流水账留下负数记录。这两个用例能通过说明库存变动的核心链路是安全的。之后再补普通的增删改查测试基本就稳了。5.2 库存对不上80%都是这几个原因我接手过的项目里库存对不上的原因翻来覆去就那几种有人直接改了库存表这必须从制度和技术上双重杜绝反审核只改了单据状态没有回滚库存盘点差异直接改库存而没有生成调整单。另外还有跨天操作的问题——过了零点之后做反审核日期归属算前一天还是当天这会影响报表统计。解决原则就一条库存永远只能通过StockService变动盘点差异必须生成盘盈盘亏调整单走审核流程。加一个定时任务每天凌晨跑一次“库存快照对账”检测有没有库存记录被绕过流水直接修改。这个对账任务上线第一天就配好后面能省掉大量排查时间。5.3 并发扣库存和报表连不上的处理并发扣库存出现负数我前面已经说了用原子更新SQL解决。这里补充一点如果业务量大了原子更新也可能出现行锁等待可以考虑加乐观锁version字段更新时带上前一次查询的version等于告诉数据库“只有在我读取之后没有人改过的情况下才允许更新”失败就重试。小团队并发不高原子扣减SQL基本够用但绝不能用“先查再改”的方式。总有人说报表服务器连接不上十次里有八次是配置文件里的数据库地址写成了localhost。如果报表服务是独立部署的应该写数据库的内网IP这个问题排查起来特别隐蔽。还有的是连接池配置太小慢SQL把连接打满新请求全部排队。解决办法是报表页面不做实时大查询进销存汇总按天或按仓库维度异步生成汇总表页面查汇总表而不是实时join十几万行明细。商品表、单据明细表记得加索引不然卡死是迟早的事。最后说点实在的。进销存ERP这套系统功能列表可以做得很长但真正拉高评价的永远是“数据到底准不准”。我做过几套之后最大的感受是宁可把库存流水和单据状态这两个模型设计得严格一点也不要在后面为了图方便给系统开“直接改库存”的口子。拿到这套源码后建议先跑通采购入库和销售出库的完整闭环确认库存数字和手工账对得上再考虑做报表和扩展电子面单、财务对接这些功能。数据流转正确了后面的一切都顺。本文还有配套的精品资源点击获取

相关新闻

最新新闻

日新闻

周新闻

月新闻