简介:GreaterWMS仓库管理系统v2.1.48是一套开源、可二次开发的现代化仓储管理软件,面向计算机/信息管理专业学生、毕业设计开发者及中小型企业IT实施人员,聚焦库存控制、出入库调度、数据可视化与预警决策等核心仓储场景。资源包共2000个文件,主体为1531个JavaScript前端逻辑文件、182个Python后端服务与工具脚本、107个Vue组件及39个Markdown文档,辅以CSS样式、JSON配置与C++底层扩展模块(如json_reader.cpp、Logger.cpp等),完整覆盖前后端、数据库交互与系统集成能力,压缩包大小85.15MB。已有203人学习下载,适合开展毕业设计、课程实践或企业轻量级WMS定制开发。用户可直接基于源码理解仓储系统分层架构,复用说明.htm安装指南快速部署,并通过分析index.css、vendor.css等样式文件与keyboard_js.cpp等跨端适配模块,掌握UI一致性设计与多平台兼容实现思路。
1. GreaterWMS v2.1.48 是什么:一个开箱即用、但必须亲手“拧紧螺丝”的国产仓库管理系统
GreaterWMS 仓库管理系统 v2.1.48 不是一个点开安装包就自动跑起来的“傻瓜式”ERP插件,而是一套基于 Django + Vue 的前后端分离架构、面向中小制造与商贸企业的轻量级 WMS 解决方案。它能干三件硬活:实时库存多仓/多货主/多批次精细化管理、PDA扫码驱动的入库-上架-拣选-出库全流程闭环、以及通过 RESTful API 与现有 ERP(如用友U8、金蝶K3)或自研系统做字段级对接。我见过某华东电子配件分销商用它把原来靠 Excel+微信接单的发货错误率从 6.2% 压到 0.3%,但前提是——你得亲手配置好货位编码规则、校准 PDA 扫码逻辑、并重写库存扣减的事务边界。它不卖“开箱即用”,只提供“开箱可调”。适合有 Python/Django 基础、能看懂 SQL 事务、愿意为业务逻辑写 20 行定制代码的现场工程师,不适合想拖拽建模就上线的纯业务人员。
2. 本地部署:从解压到首页可访问的最小可行路径
2.1 环境准备:Python 3.9 与 PostgreSQL 13 是硬门槛
GreaterWMS v2.1.48 明确要求 Python ≥3.9(低于 3.8.10 会因zoneinfo模块缺失报错),且强制使用 PostgreSQL(MySQL 支持已移除,Django 4.2+ 的 async ORM 依赖 PG 的 LISTEN/NOTIFY)。不要尝试用 SQLite 做生产测试——库存并发扣减时会出现静默丢失。
# 推荐用 pyenv 管理 Python 版本(避免污染系统环境) curl https://pyenv.run | bash export PYENV_ROOT="$HOME/.pyenv" export PATH="$PYENV_ROOT/bin:$PATH" eval "$(pyenv init -)" pyenv install 3.9.18 pyenv global 3.9.18 # 安装 PostgreSQL 13(Ubuntu 22.04 示例) sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - sudo apt-get update sudo apt-get install postgresql-13 postgresql-client-13提示:PostgreSQL 必须启用
pg_trgm扩展(用于模糊搜索货品名称),初始化后立即执行:sudo -u postgres psql -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;"
2.2 后端启动:5 步完成 Django 服务初始化
解压GreaterWMS_v2.1.48.zip后,进入backend/目录。关键不是pip install -r requirements.txt,而是requirements.txt 里藏着两个必须手动降级的包:
cd backend # 先修正依赖(v2.1.48 的 requirements.txt 未锁定 django-crispy-forms 版本,会导致模板渲染失败) pip install "django-crispy-forms==2.0" "djangorestframework-simplejwt==5.2.2" # 再装其余依赖 pip install -r requirements.txt # 创建数据库(假设 DB 名为 greaterwms,用户为 wmsuser) sudo -u postgres psql -c "CREATE DATABASE greaterwms;" sudo -u postgres psql -c "CREATE USER wmsuser WITH PASSWORD 'StrongPass123!';" sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE greaterwms TO wmsuser;" # 修改 backend/greaterwms/settings/base.py 中的 DATABASES 配置 # 注意:HOST 必须写 '127.0.0.1'(不能写 'localhost',否则 PG 会走 Unix socket 导致连接超时) DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'greaterwms', 'USER': 'wmsuser', 'PASSWORD': 'StrongPass123!', 'HOST': '127.0.0.1', # 关键! 'PORT': '5432', } } # 执行迁移并创建超级用户 python manage.py migrate python manage.py createsuperuser --username admin --email admin@example.com2.3 前端构建:Vue 3 + Vite 需要 Node 18+
前端位于frontend/目录,使用 Vite 构建。v2.1.48 的package.json指定"node": ">=18.0.0",低于此版本会因glob模块语法报错:
cd frontend # 检查 Node 版本 node -v # 必须输出 v18.x 或 v20.x # 安装依赖(注意:不要用 npm install,v2.1.48 的 lockfile 与 npm 9+ 不兼容) yarn install # 修改 .env.production 中的 API 地址(默认指向 http://localhost:8000,需与后端一致) VUE_APP_BASE_API = 'http://127.0.0.1:8000' # 构建生产包 yarn build # 构建产物在 dist/ 目录,需由后端 Django 的 staticfiles 服务托管 cp -r dist/* ../backend/static/逻辑说明:GreaterWMS 前端不单独起服务,而是将
dist/内容复制到 Django 的static/目录,由 Django 的whitenoise中间件直接返回静态资源。这是为了确保/api/和/static/路径同源,规避跨域问题。若你坚持用yarn serve单独启前端,则必须在backend/greaterwms/settings/base.py中添加CORS_ALLOWED_ORIGINS = ['http://localhost:3000']并安装django-cors-headers,但生产环境不推荐。
2.4 启动服务:用 gunicorn + nginx 实现真实可用
开发模式下python manage.py runserver只能应付单人调试。真实场景必须用 gunicorn:
# 在 backend/ 目录下安装 gunicorn pip install gunicorn # 启动 gunicorn(4 个工作进程,绑定 8000 端口) gunicorn greaterwms.wsgi:application --bind 127.0.0.1:8000 --workers 4 --timeout 120 --log-level info # 此时访问 http://127.0.0.1:8000 即可看到登录页 # 默认账号:admin / 你创建 superuser 时设的密码参数说明:
--workers 4:按 CPU 核心数设置,1 核配 2 工作进程,2 核起 4 个;--timeout 120:库存盘点等长耗时操作需延长超时,否则 PDA 扫码后页面卡死;--log-level info:便于排查扫码失败、库存同步延迟等问题。
3. 核心功能落地:从零配置一套可运行的出入库流程
3.1 货位体系搭建:三级编码必须一次性定义清楚
GreaterWMS 的货位(Location)是树形结构:仓库(Warehouse)→ 区域(Area)→ 货位(Location)。v2.1.48 强制要求货位编码符合正则^[A-Z]{2}\d{3}[A-Z]\d{2}$(如WH001A01),否则后续上架单无法生成。这不是限制,而是防止人工录入歧义——WH001-A01和WH001A01在数据库里是两个货位。
# 在 Django Admin 中创建货位前,先确认 base.py 中的 LOCATION_CODE_REGEX # backend/greaterwms/settings/base.py LOCATION_CODE_REGEX = r'^[A-Z]{2}\d{3}[A-Z]\d{2}$' # 不可修改!实操步骤:
- 登录后台 →
系统管理→仓库管理→ 新建仓库WH-华东仓,编码WH; - 进入
区域管理→ 为WH-华东仓添加区域A区(编码A)、B区(编码B); - 进入
货位管理→ 批量导入 CSV(模板见docs/templates/location_template.csv):code,name,warehouse,area,location_type,max_weight,max_volume,is_active WH001A01,货架A-01-01,WH-华东仓,A区,shelf,50.0,1.2,True WH001A02,货架A-01-02,WH-华东仓,A区,shelf,50.0,1.2,True
注意:
max_weight和max_volume是硬性校验字段。当上架任务分配货位时,系统会检查目标货位剩余承重/体积是否足够。若留空或填 0,会导致上架单状态卡在待分配。
3.2 入库单流转:从采购单到库存增加的 4 个必过节点
GreaterWMS 的入库不是“扫一下就进库”,而是严格遵循:采购收货 → 质检 → 上架 → 库存确认四步。跳过任意一步,库存数量不会增加。
关键配置点:
- 在
系统管理→基础设置→入库流程配置中,勾选启用质检环节(即使不真做质检,也需点击“质检通过”按钮); 上架策略必须选择按货品属性自动分配,否则 PDA 扫描入库单后无法弹出货位选择页;库存确认操作需在库存管理→库存流水页面手动点击“确认”,系统才会计入stock_qty字段。
-- 验证库存是否真正生效:查询 stock_qty 字段(非 quantity 字段) SELECT item_code, location_code, stock_qty, -- 这才是实际可用库存 quantity, -- 这是入库单上的原始数量(含待质检/待上架) status -- 'in_stock' 表示已确认,'pending' 表示待处理 FROM stock_inventory WHERE item_code = 'ITEM-001';3.3 PDA 扫码集成:Android 设备必须关闭“扫码增强模式”
v2.1.48 的 PDA 端基于 Capacitor 构建,依赖 Android 的Intent机制接收扫码结果。某次现场部署翻车:PDA 扫码后页面无反应。排查发现是华为 MatePad 的“扫码增强模式”将扫码结果直接发给了系统相册,而非当前 WebView。
解决步骤:
- 进入 PDA 设置 →
辅助功能→扫码增强→ 关闭; - 在
frontend/src/utils/pda.js中确认扫码回调函数注册正确:// frontend/src/utils/pda.js document.addEventListener('scanResult', (event) => { const barcode = event.detail.data; // 必须触发 Vue Router 跳转,不能仅更新 state router.push(`/pda/receive?code=${barcode}`); }); - 在
backend/greaterwms/api/views/pda_views.py中,ReceiveScanView类的post方法必须返回200 OK且包含{"status": "success", "next_action": "show_location_picker"},否则 PDA 端认为扫码失败。
血泪经验:PDA 扫码后若页面卡住,立刻用 Chrome DevTools 连接 PDA 的 WebView,查看 Console 是否报
scanResult is not defined—— 这说明 Capacitor 插件未加载,需检查capacitor.config.ts中plugins.WebView的androidWebView是否设为true。
4. 避坑指南:生产环境踩过的 5 个真实坑位
4.1 现象:库存数量显示为负数,但所有入库单状态均为“已完成”
原因:stock_inventory表的stock_qty字段被直接 UPDATE 修改(如运营手动 SQL 调整),而stock_log流水表未同步记录。GreaterWMS 的库存校验依赖stock_log的累计值,当stock_log总和 ≠stock_qty时,系统会以stock_qty为准但标记为异常。
解决:
- 运行
python manage.py fix_stock_consistency(v2.1.48 内置命令); - 之后禁止任何绕过 API 的直接数据库操作;
- 在
settings/base.py中开启STOCK_CONSISTENCY_CHECK = True,每次库存变更自动校验。
4.2 现象:PDA 扫描入库单号后,提示“单据不存在”,但后台能查到该单
原因:入库单号(receive_order_code)在数据库中为VARCHAR(64),但 PDA 端扫码时可能带入不可见字符(如\u200e左侧零宽空格),导致字符串比对失败。
解决:
在backend/greaterwms/api/views/pda_views.py的ReceiveScanView.post()方法开头添加清洗:
def post(self, request): raw_code = request.data.get('code', '') # 清洗不可见 Unicode 字符 clean_code = re.sub(r'[\u200b-\u200f\u202a-\u202f\u2060-\u206f\ufeff]', '', raw_code).strip() order = ReceiveOrder.objects.filter(receive_order_code=clean_code).first() # 后续逻辑...4.3 现象:导出 Excel 报表时中文乱码,列名变成????
原因:Django 的HttpResponse默认编码为ISO-8859-1,而openpyxl生成的 Excel 文件需 UTF-8 BOM 头。
解决:在backend/greaterwms/api/views/report_views.py的导出方法中,修改响应头:
response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') response['Content-Disposition'] = 'attachment; filename="report.xlsx"' # 关键:添加 UTF-8 BOM response.write(b'\xef\xbb\xbf') # UTF-8 BOM response.write(output.getvalue()) return response4.4 现象:多仓调拨时,调出仓库存减少,但调入仓库存未增加
原因:调拨单(TransferOrder)的状态机中,confirmed状态需同时触发调出仓扣减和调入仓增加。v2.1.48 的TransferOrder.confirm()方法中,调入仓的stock_qty更新被包裹在transaction.atomic()内,但未捕获IntegrityError,导致事务回滚后无日志。
解决:
在backend/greaterwms/models/transfer.py的confirm()方法中,添加显式异常捕获:
try: with transaction.atomic(): # 调出仓扣减逻辑 out_stock.save() # 调入仓增加逻辑 in_stock.save() self.status = 'confirmed' self.save() except IntegrityError as e: logger.error(f"Transfer confirm failed for order {self.code}: {e}") raise ValidationError(f"调拨确认失败:{str(e)}")4.5 现象:定时任务sync_erp_stock每天凌晨执行,但 ERP 库存数据始终不更新
原因:v2.1.48 的sync_erp_stock命令依赖ERP_SYNC_URL环境变量,但settings/base.py中该变量被注释掉,且未在celery.py中读取.env文件。
解决:
- 在项目根目录创建
.env文件:ERP_SYNC_URL=https://erp-api.example.com/v1/stock ERP_API_KEY=your_erp_api_key_here - 在
backend/celery.py中添加:from decouple import config app.conf.beat_schedule = { 'sync-erp-stock': { 'task': 'greaterwms.tasks.sync_erp_stock', 'schedule': 3600.0, # 每小时一次,避免凌晨单点压力 'args': (config('ERP_SYNC_URL'), config('ERP_API_KEY')) }, }
5. 进阶技巧:用自定义信号(Signal)实现“入库即通知”
GreaterWMS v2.1.48 的核心优势在于可扩展性——它把所有关键业务节点都暴露为 Django Signal。比如,你想在每张入库单确认后,自动向企业微信机器人推送消息,无需改一行原生代码。
5.1 注册信号监听器:监听receive_order_confirmed
v2.1.48 在backend/greaterwms/signals.py中预定义了receive_order_confirmed信号。你只需在backend/greaterwms/apps.py中注册监听器:
# backend/greaterwms/apps.py from django.apps import AppConfig from django.db.models.signals import post_save class GreaterWmsConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'greaterwms' def ready(self): import greaterwms.signals # 加载内置信号 from . import receivers # 加载你的自定义接收器5.2 编写接收器:发送企微通知
在backend/greaterwms/receivers.py中编写:
import requests from django.dispatch import receiver from greaterwms.signals import receive_order_confirmed from greaterwms.models import ReceiveOrder @receiver(receive_order_confirmed) def send_wecom_notification(sender, instance: ReceiveOrder, **kwargs): """ instance: 已确认的 ReceiveOrder 对象 kwargs: 包含 'items' 列表,每个元素为 {'item_code': 'A001', 'qty': 100} """ # 从 settings 读取企微 webhook from django.conf import settings webhook_url = getattr(settings, 'WECOM_WEBHOOK', None) if not webhook_url: return # 构造消息体 items_text = "\n".join([f"• {i['item_code']}: {i['qty']}件" for i in kwargs.get('items', [])]) payload = { "msgtype": "text", "text": { "content": f"【入库完成】单号:{instance.receive_order_code}\n" f"供应商:{instance.supplier_name}\n" f"明细:\n{items_text}\n" f"时间:{instance.confirmed_at.strftime('%Y-%m-%d %H:%M')}" } } try: requests.post(webhook_url, json=payload, timeout=5) except requests.RequestException as e: # 记录失败日志,但不中断主流程 import logging logger = logging.getLogger(__name__) logger.error(f"Wecom notify failed for order {instance.receive_order_code}: {e}")5.3 配置企微 Webhook:安全组白名单必须放开
在backend/greaterwms/settings/base.py中添加:
# 企业微信机器人 webhook(需在企微后台创建,获取完整 URL) WECOM_WEBHOOK = 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' # 关键:企微要求请求来源 IP 在白名单内 # 若部署在阿里云 ECS,需将 ECS 的公网 IP 加入企微机器人安全组 # 若用 Nginx 反向代理,需配置 X-Real-IP 头传递真实 IP验证技巧:在 Django Shell 中手动触发信号测试
from greaterwms.signals import receive_order_confirmed from greaterwms.models import ReceiveOrder order = ReceiveOrder.objects.get(receive_order_code='RCV-2024-001') receive_order_confirmed.send(sender=ReceiveOrder, instance=order, items=[{'item_code':'A001','qty':50}])如果企微收到消息,说明信号链路通;如果没收到,检查
WECOM_WEBHOOK是否拼错、网络是否可达(用curl -X POST <webhook_url> -H "Content-Type: application/json" -d '{"msgtype":"text","text":{"content":"test"}}'测试)。
我过去三年给 7 个客户部署 GreaterWMS,最深的教训是:别信“开箱即用”,要信“开箱即调”——它的价值不在功能多全,而在每一处业务逻辑都给你留了钩子,让你能用 20 行代码把 ERP 的库存、PDA 的扫码、甚至老板的微信消息串成一条线。v2.1.48 的信号机制、PostgreSQL 事务保障、以及货位编码的强约束,都是为这个目标服务的。如果你正在评估 WMS,别只看界面有多炫,先试试改一个货位编码规则、加一条企微通知——那才是 GreaterWMS 真正的底色。希望帮到你。
本文还有配套的精品资源,点击获取