ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

多用户多仓库进销存系统源码解析:基于uniapp的跨端库存管理方案

多用户多仓库进销存系统源码解析:基于uniapp的跨端库存管理方案 跑进销存这条路的人都知道真正的痛点从来不是“做一张入库单”或者“打一张出库单”而是当公司有多个门店、多个仓甚至多人同时操作时数据到底怎么算得清。前阵子我拿到一套基于uniapp的多用户多仓库进销存管理系统源码前后端全开源既能编译成微信小程序也能打包成H5页面和APP第一反应是这东西终于把“能用”和“好用”之间的坑填了一部分。这篇就围绕这套源码把我拆解系统时的设计思路、数据模型、部署细节和踩坑记录都摊开讲给想直接用或者打算二开的同学一份可抄的作业。这套系统本质上是一个标准的前后端分离项目前端用uniapp做跨端适配后端提供RESTful API数据库层处理多租户、多仓库的权限隔离和库存流水。它的核心价值不只是“能跑”而是把进销存里面最容易被做坏的两件事——多用户权限边界、多仓库库存一致性——用一套相对轻量的方案落地了。无论你是小团队想内部用还是接了个外包项目需要在短时间交付一套管理后台加移动端这份源码的参考价值都很高。1. 项目概述与核心价值拆解1.1 这个项目到底解决了什么痛点很多刚接触进销存的人会以为库存就是一张表、一个数字做完加减法就行。但真实生意场景里同样一款商品A仓有一百件B仓有二十件总库存不是单纯求和那么简单。因为不同仓库可能对应不同门店、不同销售渠道甚至同一仓库里还存在“待出库”“在途”“锁定”这些状态。这套系统把“多仓库”作为一等的业务概念来做而不是在商品表后面硬塞一个仓库字段这是它最值钱的地方。多用户的问题同样现实。一个老板不可能自己录所有单据采购员、销售员、仓库管理员各管一段。如果大家都用一个账号操作审计就是一笔糊涂账。这套系统在用户权限上做了角色划分每个用户归属到某个仓库或跨仓库操作单据上能追溯谁在什么时候做了什么这正是中小型企业从“人治”走向“系统治”的必经之路。1.2 多用户多仓库的设计亮点从源码的数据库脚本能看出它的核心思路是“用户—角色—仓库—商品”四张主表加一堆流水表。用户表并不直接绑死某个仓库而是中间挂了一层角色表角色再配置仓库权限。这样设计的好处很明显一个客户经理可以同时管A仓和B仓的销售数据而仓库管理员只能看他负责的那个仓的库存灵活性比“用户表加一个warehouse_id字段”的一锤子买卖高得多。库存表的设计也值得一提。它不是只存“当前数量”而是用“可用库存 锁定库存 在途库存”这种拆分方式来记录。我做进销存项目这些年凡是把库存做成单一字段的后期做订单预占、调拨在途的时候基本都要返工。这个项目的拆分方式虽然会增加写入复杂度但换来了业务上的严谨性值得借鉴。1.3 适合谁用、怎么落地这套源码最适合两类人一类是手里有真实业务、需要快速跑起来一套内部管理系统的中小企业主或IT负责人另一类是做外包或私活的后端开发拿它当基座改造成甲方的进销存项目。前端基于uniapp意味着你不需要维护三套代码一套代码同时输出微信小程序、H5网页和Android/iOS的APP壳对于“预算有限、场景又需要多渠道操作”的小团队来说太合适了。落地方式也很直白后端拉起来之后先初始化数据库前端在HBuilderX里配置好接口地址小程序端直接跑微信开发者工具H5和APP则是用uniapp的标准发布流程打包。后面我会把每一步的具体操作和参数列出来。2. 技术栈选型与架构拆解2.1 为什么是uniapp而不是原生小程序但凡做过原生微信小程序的人都知道那套语法跟Vue是完全不同的体系写起来倒不算太难但要同时维护小程序、支付宝小程序、H5、APP四套代码人力和维护成本直接翻倍。uniapp的好处是它本身基于Vue语法写完之后通过编译工具链转成不同平台的代码。语法层面90%是共通的平台特有的差异点再通过条件编译来处理。这套系统选择uniapp还有一个现实原因进销存这种工具类系统操作者不一定只在小程序里用。老板可能想在电脑浏览器上直接打开H5页面录入大批量采购单库管员拿着手机在仓库里扫条码业务员用APP在外面登录。一个前端工程覆盖这些场景说句实话省下的不光是开发时间还有后续每次改需求时同步改多个端的精神损耗。用uniapp也不是没有代价。它编译出来的微信小程序包体天然偏大因为框架运行时本身要有一坨体积另外如果你用了大量原生插件跨端兼容性就要逐个测。这套源码在插件使用上偏克制主要用uni-ui这类官方组件这对想快点上线的人是个友好信号。2.2 前后端分离的工程结构源码目录清楚分成了前端和后端两大部分。前端是标准的uniapp项目结构pages目录下面按业务模块分包登录、首页、商品管理、采购订单、销售订单、库存查询、报表统计这些。后端我看到的版本是常见的Spring Boot风格工程当然市面上也有ThinkPHP或Node.js版本不管哪种接口返回格式都遵循统一约定就是code message data的结构。这里有个细节值得单独提一下就是API的Auth鉴权方式。这套系统用的是JWTJSON Web Token方案用户在登录接口拿到token之后前端会把它缓存在本地存储里每次请求在请求头带上Authorization字段后端通过拦截器校验。全部请求都走HTTPS生产环境或者本地HTTP代理开发环境没有为了让“看起来复杂”而引入一堆微服务网关整体设计非常务实。一个小范围管理系统的后端最忌一堆中间件往死里堆。这套源码只用了数据库连接池、Redis缓存主要存验证码和部分热点数据比如商品类别、以及定时任务处理库存预警通知跟进销存业务的颗粒度是匹配的。复杂度留到需要的时候再加这才是小型项目应该有的态度。2.3 数据隔离方案用户、仓库、角色我见过不少项目在做“多用户”的时候只是简单在查询语句后头加一个where user_id ?这样做确实隔离了用户但只要两个用户对同一份数据有操作交集就很容易出权限漏洞。这套系统改成了基于角色的访问控制RBAC模型用户属于角色角色具备菜单权限和数据范围权限数据范围又细分为“全部仓库”“本仓库”“仅本人”三级。举一个实际例子销售总监的角色可以看到所有仓库的销售数据和库存数据但只能编辑自己负责的大区仓库仓管员角色可以看到本仓所有库存流水但新增采购单时只能选自己仓库老板角色什么都不限制但每笔操作最终都会落到人员上。从数据库层面来看核心业务表都带warehouse_id和create_by两个字段查询时通过SQL自动拼接权限条件比在业务代码里到处判断再过滤数据要稳妥得多。3. 核心功能模块与数据模型设计3.1 商品档案与库存流水商品档案是进销存的地基字段设计看着简单实际坑很多。这套系统的商品表核心字段包括商品编号、条码、名称、分类、规格、单位、成本价、销售价、预警库存、状态等。条码这块它不是强制唯一因为现实里同一个条码可能对应多规格所以它还留了“辅助条码”字段方便你用多个条码去搜同一个商品。库存表的设计才是真正的重点。我的建议是永远不要在商品表里直接放一个stock_quantity因为一旦并发写入这个字段就会变成数据地狱。这套系统的做法是库存流水表stock_flow记录每一笔入库、出库、调拨、盘点、报损的记录然后通过流水表聚合出实时库存。查询库存时走缓存或汇总表而写操作永远只插流水核心逻辑用数据库事务包起来。这套“流水驱动库存”的方式才是进销存系统的正确打开方式。计算库存时有个公式可以重点关注可用库存 期初库存 总入库量 - 总出库量 - 锁定库存。期初库存通过盘点单来做初始化锁定库存则来自销售订单创建时预占的数量。这个公式看起来简单但能保证你在开了很多订单还没发货的时候不会把还没到货或已经预定的商品卖超。3.2 采购、销售、退货的流程闭环采购模块从“采购申请”到“采购入库”再到“采购退货”形成了一个闭环。采购单审核通过后会自动生成一笔入库单草案仓管员确认收货时只改数量不重新填一堆重复信息。销售模块正好反过来从销售订单到出库单再到销售退货单每一环都串着关联单号。这种单据关联设计的好处是审计可追溯出了问题能顺着单号一路查回去。我做进销存外包时遇到过最常见的需求就是“统计一下这个月实际赚多少”但如果没有把采购退货和销售退货处理好毛利永远算不准。这套系统在退货流程里单独计了成本调整销售退货会把退回商品的成本重新回到库存成本里采购退货则减少应付账款同时扣减库存。每月毛利统计时只需要从销售明细减掉退货金额再从采购明细加上退货金额数字就能对上。3.3 多仓库调拨与盘点逻辑多仓库系统绕不开调拨单。这套系统的调拨方式是“调出仓出库 调入仓入库”的成对流水生成调拨单时自动创建两张单子一个扣减调出仓可用库存一个增加调入仓在途库存调入仓收货确认后在途转成实际库存。这种“在途”状态的引入让调拨过程中两边的库存数字都能反映出真实情况不会出现货还在路上、两边都看到货的尴尬。盘点则是另一块容易做崩的功能。这套系统用的是盘点单快照模式创建盘点单时锁定盘点范围内的库存仓库人员拿着清单去数实物然后录入实盘数量系统自动算出盘盈盘亏数。如果盘点数和账面数差异超过阈值必须填写原因说明才能提交这样能防止有人随便乱改数据。对于有多个仓库的公司盘点按仓库分批做不要所有仓库同时锁库存避免影响正常营业。4. 源码结构与部署实操4.1 前端uniapp目录解析拿到源码后前端目录结构一般是这样frontend/ ├── pages/ │ ├── login/ │ ├── index/ │ ├── goods/ │ ├── purchase/ │ ├── sale/ │ ├── stock/ │ └── report/ ├── components/ ├── store/ ├── utils/ │ ├── request.js │ └── auth.js ├── static/ ├── App.vue ├── main.js └── manifest.jsonutils/request.js是一个封装了uni.request的公共请求模块它的作用是把baseURL、请求头token、错误码统一处理都收敛在一个文件里。如果你要部署到自己的服务器第一个要改的就是这个文件里的baseURL改成你后端实际可达的地址。另一个要留意的是manifest.json这里面除了小程序AppID还配置了App打包的图标、启动图和权限声明。多端编译时的差异化逻辑通常在App.vue和各个页面的条件编译代码里体现例如// #ifdef MP-WEIXIN const token uni.getStorageSync(token) // #endif // #ifdef H5 const token localStorage.getItem(token) // #endif这种写法保证了同一套逻辑在不同平台都能正确拿到持久化数据。理解了这个你在改代码时就不会被跨端兼容问题卡住。4.2 后端接口与权限设计后端接口划分得比较清晰统一前缀/api然后按资源拆分比如/api/auth/login、/api/goods/list、/api/stock/query、/api/order/sale/create等。每个接口都遵循Restful风格GET用于查询POST用于新增或提交PUT用于修改状态DELETE用于逻辑删除。这里的逻辑删除指的是数据表里的deleted字段置1而不是物理删除记录因为进销存的单据都是有溯源价值的物理删单后期对账会非常难受。权限控制方面后端除了校验用户是否登录每个需要数据权限的接口都会带上当前用户可访问的仓库ID集合然后在SQL层面用IN条件过滤。这个仓库权限集合是在用户登录时加载进Redis里的接口调用时实时读取避免每次请求都查一遍数据库角色表。源码头里分为开发环境和生产环境的数据库配置切换环境时主要改数据源连接串。后端启动步骤一般分三步先建库并初始化SQL再改配置文件里的数据库账号密码最后启动应用。启动成功后Swagger或接口文档能直接看到全部接口列表方便前端联调。这套系统如果你在本地调试建议后端项目直接用IDE启动前端跑H5模式做联调这样调试效率最高。4.3 从源码到H5和APP的编译流程先从H5说起。在HBuilderX里打开前端工程点击菜单栏的“运行 - 运行到浏览器”它会自动启动一个本地服务打开就是能直接登录使用的H5页面。这个模式最适合开发调试因为你改完代码浏览器热更新不用重新编译。真要上线部署就选“发行 - 网站-H5手机版”它会在dist/build/h5目录生成静态文件把整个目录扔到Nginx的web根目录即可。编译成微信小程序的流程是“发行 - 小程序-微信”生成的文件在dist/build/mp-weixin。随后用微信开发者工具打开这个目录填入自己的AppID就能预览和上传。注意小程序要求所有请求域名必须是HTTPS且在后台配好合法域名这个步骤最容易漏一旦漏了就会出现“request:fail url not in domain list”报错。编译成APP则采用HBuilderX自带的云打包功能。在“发行 - 原生App-云打包”里选Android或iOS配置好包名和证书系统会发到云端打包完成后下载安装包。如果你用的是离线打包玩法又不一样需要Android Studio配合离线SDK这里不展开对大部分人来说云打包已经够用。5. 常见问题与坑位实录5.1 登录态与多端同步问题这套系统默认登录后把token存在本地但你会遇到一个很常见的尴尬同一个账号在小程序登录了再打开H5页面还要再登录一次两边数据又不能互通。这是正常的因为不同端的存储本来就不共享。要解决这个问题可以把登录态后移到后端保存一份“会话记录表”然后用一个短期二维码方式实现扫码登录比如H5页面生成二维码小程序扫码后确认登录。这样两个端就统一了。真要做这个功能后端要加两个接口一个申请登录二维码并轮询状态一个小程序扫码后写入登录确认。前端组件再包一层轮询逻辑。这个改动工作量不大但对用户体验提升非常明显我自己接手的几个项目都做了这个优化。5.2 库存并发与超卖问题多仓库系统上线后第一个容易爆的问题就是超卖。用户下单的瞬间系统先去查当前库存判断是否够卖然后再扣减库存。这两个动作之间如果有并发两个订单都查到剩余库存是1然后都扣成0实际就卖超了。解决方式有三种乐观锁、悲观锁、Redis原子扣减。这套系统源码里我看到的是数据库事务配合SELECT ... FOR UPDATE锁行的方式也就是悲观锁它能保证同一时间只有一个订单在操作同一商品的那行库存记录。如果想进一步优化性能可以在Redis里做库存预扣下单时用DECR命令原子减库存后端只做最终异步落库。但这样得处理订单取消或支付超时后回补库存的事复杂度会上一台阶。中小团队我建议直接用数据库锁数据量没到一天几十万单没必要提前优化。真到了流量大到缓存扛不住的时候你早就该上专门的库存中台了。5.3 小程序包体超限与优化uniapp项目编译成微信小程序时有个红线是主包不能超过2MB。一旦资源文件多起来很容易触发“source size exceed max limit”的报错。这根本不是什么玄学问题就是代码和图片体积超了。解决办法无非这几个方向第一图片全部走远程地址不放在本地static目录。一个几十KB的背景图就能吃掉很多空间本地只放图标类小文件。第二组件按需引入别在main.js里全局注册一整套UI库用哪个引哪个。第三以分包方式组织页面比如把“报表统计”“系统设置”这些不常用的页面丢进subpackages主包只放登录、首页、商品、库存这些核心页面。改完这些包体基本能压到1.5MB以内。我个人踩过的坑是某些云打包平台会对资源文件再次压缩但压缩后个别字体图标会显示异常。所以打完包上线前一定用真机把每个页面过一遍别只盯着模拟器。模拟器上好好的真机上不显示的案例我见过太多次。6. 二次开发与扩展建议6.1 如何快速改造成自己的项目拿到这套源码别急着改业务代码。第一步先把包跑起来把后端、前端、数据库全部接通走一遍登录、建商品、开采购单、开销售单、查库存这五个核心流程。确认主链路没问题后再去改品牌名称、Logo、颜色主题这些改动主要集中在uniapp的manifest.json里的应用名称和App.vue里的全局样式变量。如果你要改后端接口的地址前缀或者调整数据库表名前缀用全局替换工具统一处理就行。改数据库表名前缀是个细致的活必须把SQL脚本里的建表语句和后端实体类的注解全改了否则一启动就报“table not exist”。建议用IDE的重构能力去全局重命名不要手动一个个来省得漏。6.2 可以往哪些方向扩展从这套系统继续往外扩展我比较推荐三条线。第一条线是“多单位换算”比如商品按箱入库、按瓶出库箱和瓶的比例可以配置这一块在很多零售场景非常刚需。第二条线是“客户信用额度与账期”给长期合作客户设置赊账上限超了自动拦截销售单做贸易类业务的公司基本绕不开。第三条线是“多端消息通知”比如库存低于预警线时通过公众号模板消息或APP推送通知给对应仓管员让系统从“被查”变成“主动报”。做扩展的时候记住一个原则进销存这种带钱和货的系统任何改动先保证单据流和库存流水的一致性不要为了加功能把核心表结构写乱。每加一个扩展模块先画一遍数据流转图确认不会破坏原有闭环再动手。遇到需要变更数据表结构的场景别直接改原表优先加新表做关联扩展方便以后升级主线代码。这套源码给我的整体感觉是它把一个进销存系统该有的骨架完整立住了多用户、多仓库、多端输出这些硬骨头都啃了下来。实际动手的时候我建议你按“先跑通、再改造、后扩展”的顺序来别一上来就拆底层。把核心流程吃透之后它完全可以变成你自己手里一套拿得出手的进销存基座。做系统这种事最怕的不是没有源码而是拿到一堆代码却没有耐心梳理数据关系。耐心跑一遍流程你就会发现所谓进销存说到底就是让每一件货、每一笔钱都有据可查罢了。
返回列表