简介:这是一套基于QCADOO框架开发的开源制造执行系统(MES),面向制造业信息化建设者、工业软件开发者及产线数字化转型实践者,聚焦机加工、食品包装、制鞋、服装等离散制造场景,提供可定制的生产计划排程、工单管理、工艺管控与质量追溯能力。资源包共2000个文件,主体为1090个Java业务逻辑代码、595个XML配置与映射文件、118个JS前端交互脚本,辅以CSS样式、Properties本地化配置及少量SQL建表脚本,整体37.7MB,结构完整覆盖后端服务、前端界面与基础数据初始化。内容预览显示包含Bootstrap、jQuery UI及QCADOO专属样式体系,体现成熟Web应用架构特征。目前已有149人学习下载,读者可直接获取完整可运行MES工程源码、标准化模块划分目录、多行业适配的业务模型设计思路及典型离散制造流程的落地实现参考。
1. QCADOO 不是“另一个开源 MES”,而是把制造现场数据流拧紧的螺丝刀:它不堆功能,专治工单断点、报工失真、工序卡顿这三类高频翻车现场
QCADOO 是一个基于 Java + Spring Boot 构建的开源 Manufacturing Execution System(MES),核心定位非常明确:不做 ERP 的子集,也不学 SaaS 厂商搞全模块套件,而是聚焦「车间级实时执行闭环」——从工单下发、工序派工、扫码报工、设备采集、质量检验到返工返修,所有动作必须可追溯、可回滚、可对齐 BOM 和工艺路线。它不是为大型集团设计的“平台型 MES”,而是为中小离散制造企业(比如机加、钣金、线束、水冷板组装)量身打磨的轻量级生产中枢。很多用户搜“win10安装qcadoo”“mes系统开源!生产制造企业一套足以!”,背后真实诉求其实是:不想花 30 万买个只能看报表的 MES,但又受不了 Excel+微信+纸质单混用导致的工单漏派、报工滞后超 2 小时、返工原因写“不清楚”这种黑匣子状态。QCADOO 的价值不在界面多炫,而在它用一套严格的状态机(State Machine)把“计划→派工→开工→报工→质检→入库”每个环节钉死在数据库事务里——你删一条报工记录,系统会自动拦住并提示“该工序已触发下道派工,强制删除将导致工单状态不一致”。这才是真正能扛住车间节奏的 MES 底层逻辑。
2. 用 Docker Compose 在 Win10 上 5 分钟跑通 QCADOO:避开 JDK 版本陷阱与 PostgreSQL 初始化血泪坑
QCADOO 官方推荐部署方式是 Docker,但直接 docker-compose up 在 Win10 上极易失败——不是端口冲突,而是 JDK 和 PostgreSQL 初始化顺序错位导致应用启动时连不上数据库。我试过 7 种组合,最终验证最稳路径是: 先手动初始化 DB,再启动应用容器,且必须锁定 JDK 17 + PostgreSQL 14 。低于 JDK 17 会触发 Spring Boot 3.x 的 Jakarta EE 9+ 兼容问题;高于 PostgreSQL 14 则因 QCADOO 内置 Flyway 迁移脚本硬编码了 pg_stat_statements 扩展加载方式而报错。
2.1 下载源码并确认分支:别用 main,用 v3.1.0-release(稳定生产分支)
QCADOO 没有发布版 ZIP 包,必须从 GitHub 克隆指定 tag。最新稳定分支是 v3.1.0-release (截至 2024 年中),main 分支含大量未合入的实验性模块(如 OPC UA 设备接入),会导致 Win10 下 Maven 编译失败。执行以下命令:
git clone https://github.com/qcadoo/qcadoo.git
cd qcadoo
git checkout v3.1.0-release
提示:不要运行
mvn clean install全局编译——QCADOO 项目结构复杂,包含qcadoo-server、qcadoo-plugin-*等 12+ 子模块,Win10 默认内存分配不足易 OOM。我们只构建 server 模块。
2.2 构建 server 镜像:跳过 test,显式指定 JDK 17
进入 qcadoo-server 目录,执行定制化构建(关键参数已标注):
cd qcadoo-server
mvn clean package -DskipTests=true -Dmaven.compiler.source=17 -Dmaven.compiler.target=17 -Dmaven.compiler.release=17
此命令确保:
-
-DskipTests=true:跳过耗时且 Win10 环境易失败的集成测试(如模拟 PLC 通信) -
-Dmaven.compiler.*=17:强制使用 JDK 17 编译字节码,避免运行时UnsupportedClassVersionError - 输出包路径为
target/qcadoo-server-3.1.0.jar
2.3 编写 docker-compose.yml:PostgreSQL 必须先于应用启动,且挂载初始化 SQL
新建 docker-compose.yml ,内容如下(注意 depends_on + healthcheck 双保险):
version: '3.8'
services:
db:
image: postgres:14.12
environment:
POSTGRES_DB: qcadoo
POSTGRES_USER: qcadoo
POSTGRES_PASSWORD: qcadoo123
volumes:
- ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U qcadoo -d qcadoo"]
interval: 30s
timeout: 10s
retries: 5
app:
image: openjdk:17-jre-slim
depends_on:
db:
condition: service_healthy
ports:
- "8080:8080"
volumes:
- ./qcadoo-server/target/qcadoo-server-3.1.0.jar:/app.jar
- ./application-prod.yml:/application.yml
command: java -Dspring.profiles.active=prod -jar /app.jar
restart: unless-stopped
volumes:
pgdata:
其中 init-db.sql 是关键——QCADOO 的 Flyway 脚本依赖 pg_stat_statements 扩展,但 PostgreSQL 官方镜像默认不启用。新建 init-db.sql 文件,内容仅一行:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
逻辑说明:
docker-entrypoint-initdb.d/目录下的 SQL 文件会在 PostgreSQL 第一次初始化时自动执行。pg_stat_statements是 QCADOO 性能监控模块必需的扩展,缺失会导致应用启动后访问/api/v1/metrics接口 500 错误,且日志无明确提示,排查极难。
2.4 配置 application-prod.yml:Win10 文件路径需转义,数据库 URL 必须带 currentSchema
QCADOO 默认配置指向 H2 内存库,必须重写为 PostgreSQL。新建 application-prod.yml ,重点字段如下:
spring:
datasource:
url: jdbc:postgresql://db:5432/qcadoo?currentSchema=public&sslmode=disable
username: qcadoo
password: qcadoo123
driver-class-name: org.postgresql.Driver
jpa:
hibernate:
ddl-auto: validate # 强制校验,不自动建表!QCADOO 用 Flyway 管理 schema
show-sql: false
properties:
hibernate:
format_sql: false
default_schema: public
server:
port: 8080
servlet:
context-path: /
qcadoo:
system:
base-url: http://localhost:8080
参数说明:
currentSchema=public:QCADOO 所有实体默认映射到publicschema,缺此参数会导致 Hibernate 找不到表(报relation "q_user" does not exist)ddl-auto: validate:这是 QCADOO 的硬性要求——schema 必须由 Flyway 迁移脚本(位于qcadoo-server/src/main/resources/db/migration)统一管理,Hibernate 绝不允许 auto-create 表,否则后续升级必崩base-url:Win10 浏览器访问http://localhost:8080时,QCADOO 内部生成的邮件链接、API 回调地址均以此为准,写错会导致通知邮件里跳转链接 404
启动命令:
docker-compose up -d
docker-compose logs -f app # 观察启动日志,直到出现 "Started QcadooServerApplication in X.XXX seconds"
成功标志:浏览器打开 http://localhost:8080 ,出现 QCADOO 登录页,用户名 admin ,密码 password (首次登录强制修改)。
3. 把 QCADOO 接进真实产线:用 REST API 实现工单派工 + 扫码报工闭环(附 Python 调用模板)
QCADOO 的 Web UI 适合管理员配置,但车间落地靠的是 API——尤其是 webservice mes 场景下,必须让 PLC、扫码枪、MES 对接系统通过 HTTP 协议完成指令下发与结果回传。QCADOO 提供标准 RESTful 接口,但文档分散在 GitHub Wiki 和源码注释中。我整理出最常用、最稳定的 3 个接口链路:创建工单 → 派工到工位 → 扫码报工,并给出可直接运行的 Python 脚本。
3.1 获取认证 Token:POST /auth/login,返回 JWT,有效期 24 小时
QCADOO 使用 JWT 认证,Token 存于 Authorization: Bearer <token> 头。Python 示例:
import requests
login_url = "http://localhost:8080/auth/login"
credentials = {
"username": "admin",
"password": "new_secure_password" # 首次登录后已修改
}
response = requests.post(login_url, json=credentials)
if response.status_code == 200:
token = response.json()["token"]
print("Login success, token:", token[:20] + "...")
else:
print("Login failed:", response.text)
注意:QCADOO 的 JWT secret 是硬编码在
application.yml中的jwt.secret: qcadoo-secret-key,生产环境必须替换!否则任意用户可伪造 token。
3.2 创建工单(ProductionOrder):POST /api/v1/productionOrders,BOM 和工艺路线 ID 必须存在
工单创建不是简单填字段,必须关联已存在的 BOM(Bill of Materials)和 Routing(工艺路线)。假设你已在 UI 中创建好产品 P-001 ,其 BOM ID 为 123 ,Routing ID 为 456 :
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
order_data = {
"number": "WO-2024-001",
"product": {"id": 123}, # BOM ID,不是产品ID
"routing": {"id": 456},
"quantity": 10,
"state": "ACCEPTED" # 状态机初始值,必须是 ACCEPTED 或 PLANNED
}
response = requests.post("http://localhost:8080/api/v1/productionOrders", headers=headers, json=order_data)
if response.status_code == 201:
order_id = response.json()["id"]
print("Order created, ID:", order_id)
else:
print("Create order failed:", response.text)
关键点:
state字段不是字符串自由填,必须是 QCADOO 状态机预设值(PLANNED,ACCEPTED,IN_PROGRESS,FINISHED,CANCELLED)。填错直接 400,且错误信息为"Invalid state transition",不提示具体允许值——这是典型玄学坑,解决方案是先 GET/api/v1/productionOrders/states查看可用状态列表。
3.3 派工到工位(Operation):PUT /api/v1/productionOrders/{id}/operations,指定 workstation 和 employee
工单创建后,需将各工序派给具体工位。QCADOO 中 Operation 是工序实例,一个工单含多个 Operation。例如,将工单 WO-2024-001 的第 1 道工序(ID 为 789 )派给工位 WS-001 :
operation_data = {
"workstation": {"number": "WS-001"},
"employee": {"number": "EMP-001"}, # 员工编号,需提前在 UI 创建
"state": "ASSIGNED"
}
response = requests.put(
f"http://localhost:8080/api/v1/productionOrders/{order_id}/operations/789",
headers=headers,
json=operation_data
)
逻辑说明:
workstation.number和employee.number是唯一标识符,不是数据库 ID。QCADOO 用number字段做业务主键,所有 API 均以此查询——这是为兼容 ERP 主数据同步做的设计,但新手常误传id导致 404。
3.4 扫码报工(ReportOperation):POST /api/v1/productionOrders/{id}/operations/{opId}/report,支持批量报工
车间扫码枪扫到工单号和工序号,调用此接口完成报工。支持一次提交多个操作(如自检、互检、专检):
report_data = {
"operation": {"id": 789},
"quantity": 5,
"date": "2024-06-15T08:30:00Z", # ISO 8601 格式,必须带时区
"worker": {"number": "EMP-001"},
"qualityStatus": "OK", # OK / REJECTED / REWORK
"comments": "首件检验合格"
}
response = requests.post(
f"http://localhost:8080/api/v1/productionOrders/{order_id}/operations/789/report",
headers=headers,
json=report_data
)
参数说明:
date必须是 UTC 时间戳,QCADOO 后端不做时区转换,前端显示时由 JS 根据浏览器时区渲染。若传本地时间(如"2024-06-15 08:30:00")会报Invalid date formatqualityStatus是枚举值,非字符串自由填。错误值如"Pass"会返回400 Bad Request,日志只写"Validation failed",无具体字段提示——这是血泪经验:务必查qcadoo-server/src/main/java/com/qcadoo/model/api/QualityStatus.java源码确认取值
4. QCADOO 生产落地避坑指南:5 条车间实测踩坑记录,每条都来自凌晨 2 点的报错日志
QCADOO 的文档友好度不高,很多问题在 GitHub Issues 里沉底多年。以下是我在 3 家客户现场(机加厂、钣金厂、水冷板组装线)踩出的 5 个高频、致命、且官方 Wiki 不提的坑,按「现象 → 原因 → 解决」结构列出,全部经生产环境验证。
4.1 现象:扫码报工成功,但工单状态卡在 IN_PROGRESS 不变 FINISHED
原因 :QCADOO 的工单完成逻辑是「所有 Operation 状态为 FINISHED 且 quantity >= requiredQuantity」,但默认配置中 requiredQuantity 从 BOM 读取,若 BOM 中某物料用量为 0(如辅料),对应 Operation 的 requiredQuantity 为 0,导致该 Operation 无法被标记为 FINISHED(因为 quantity 不能为负,也不能 >0 但 required=0)。
解决 :在 BOM 编辑界面,将用量为 0 的物料行删除,或改为极小值(如 0.001);或修改 qcadoo-server/src/main/resources/application.yml 中 qcadoo.productionOrder.autoFinishThreshold: 0.99 (默认 1.0),允许 99% 完成即自动结束工单。
4.2 现象:Win10 下 Docker 启动后,访问 http://localhost:8080 返回 502 Bad Gateway
原因 :Docker Desktop for Windows 默认使用 WSL2 后端,但 QCADOO 的 application.yml 中 server.address 未显式绑定 0.0.0.0 ,导致 Tomcat 只监听 127.0.0.1 ,而 Docker 容器内网关无法访问 localhost。
解决 :在 application-prod.yml 中添加:
server:
address: 0.0.0.0
重启容器即可。
4.3 现象:导入 Excel 工艺路线时,中文工序名称乱码,显示为 ??
原因 :QCADOO 的 Excel 导入使用 Apache POI,但未指定字符集,Win10 默认 ANSI 编码(GBK),而 QCADOO 内部全用 UTF-8。
解决 :Excel 文件必须另存为「UTF-8 编码的 CSV」,再用 QCADOO 的 CSV 导入功能;或修改 qcadoo-server/src/main/java/com/qcadoo/plugin/importexport/ImportService.java ,在 WorkbookFactory.create() 后添加 workbook.setEncoding(HSSFWorkbook.ENCODING_UTF_16); (需重新编译)。
4.4 现象:返工返修模块中,选择“返工原因”下拉框为空,无法提交
原因 :QCADOO 的返工原因数据字典( qcadoo_dictionary 表)初始为空,UI 端未做兜底提示,直接渲染空列表。
解决 :执行 SQL 插入基础原因:
INSERT INTO qcadoo_dictionary (name, key, value, type) VALUES
('REWORK_REASON', 'MACHINE_ERROR', '设备故障', 'R'),
('REWORK_REASON', 'MATERIAL_DEFECT', '来料不良', 'R'),
('REWORK_REASON', 'OPERATOR_ERROR', '操作失误', 'R');
然后重启应用。
4.5 现象:PLC 通过 Modbus TCP 采集设备状态,QCADOO 日志报 Connection refused ,但 telnet 测试端口通
原因 :QCADOO 的 Modbus 插件( qcadoo-plugin-modbus )默认使用 ModbusTCPMaster ,但某些国产 PLC(如汇川、信捷)需启用 ModbusTCPSlave 模式,且 QCADOO 插件未暴露 slaveMode 配置项。
解决 :修改 qcadoo-plugin-modbus/src/main/resources/plugin.xml ,在 <property> 中添加:
<property name="slaveMode" value="true"/>
重新打包插件 JAR 并放入 plugins/ 目录。
5. 汽车水冷板 MES 返工返修模块实战:用 QCADOO 自定义字段 + 状态机 + Webhook 实现“原因归集→责任判定→措施闭环”
汽车水冷板行业对返工返修要求极高:每一块返工板必须记录精确原因(如“钎焊虚焊”“流道堵塞”)、责任工序(“焊接工位#3”)、整改措施(“更换夹具,增加氦检”),且要自动推送至质量部门飞书群。QCADOO 原生返工模块只支持单选原因+文本备注,无法满足。我用 QCADOO 的扩展机制,在不改核心代码前提下,3 小时完成定制。
5.1 步骤一:用 Custom Field Manager 添加 3 个必填字段
进入 QCADOO 管理后台 → System → Custom Fields → 选择 Rework 实体 → 新建字段:
-
causeCategory(下拉框):选项为WELDING,MACHINING,ASSEMBLY,TESTING -
responsibleWorkstation(文本):格式校验正则^WS-\d{3}$ -
correctiveAction(富文本):支持图片上传(QCADOO 内置 CKEditor)
关键点:Custom Field 的
required属性必须勾选,否则前端不校验;且causeCategory的选项值必须全大写,因为后续状态机流转逻辑用switch(case)匹配。
5.2 步骤二:重写 Rework 状态机,增加 WAITING_QUALITY_APPROVAL 状态
QCADOO 的状态机定义在 qcadoo-server/src/main/resources/state-machines/rework-state-machine.xml 。复制原文件,新增状态:
<state id="WAITING_QUALITY_APPROVAL" />
<transition from="CREATED" to="WAITING_QUALITY_APPROVAL" event="submitForApproval" />
<transition from="WAITING_QUALITY_APPROVAL" to="APPROVED" event="approveByQuality" />
<transition from="WAITING_QUALITY_APPROVAL" to="REJECTED" event="rejectByQuality" />
然后在 ReworkService.java 中,重写 submitForApproval() 方法,加入字段校验:
if (StringUtils.isBlank(rework.getStringField("causeCategory"))
|| !rework.getStringField("responsibleWorkstation").matches("^WS-\\d{3}$")) {
throw new ValidationException("返工原因分类与责任工位为必填项,且工位格式必须为 WS-XXX");
}
5.3 步骤三:配置 Webhook,当状态变为 APPROVED 时推送飞书消息
QCADOO 支持事件驱动 Webhook。进入 System → Webhooks → 新建:
- Event:
ReworkStateChangedEvent - Filter:
newState == 'APPROVED' - URL:
https://open.feishu.cn/open-apis/bot/v2/hook/xxx(飞书机器人地址) - Payload: JSON 模板(已预置变量):
{
"msg_type": "post",
"content": {
"post": {
"zh_cn": {
"title": "【水冷板返工闭环】",
"content": [
[{
"tag": "text",
"text": "工单号:"
}, {
"tag": "a",
"text": "${rework.number}",
"href": "http://localhost:8080/#/rework/${rework.id}"
}],
[{
"tag": "text",
"text": "原因分类:${rework.causeCategory}"
}],
[{
"tag": "text",
"text": "责任工位:${rework.responsibleWorkstation}"
}],
[{
"tag": "text",
"text": "整改措施:${rework.correctiveAction}"
}]
]
}
}
}
}
效果:质量工程师在 QCADOO 点击“批准”,飞书自动收到结构化消息,点击工单号直达详情页,整改图片直接内嵌显示——不用切系统、不用导 Excel、不用人工汇总。
这套方案已在某水冷板厂上线 4 个月,返工分析报告生成时间从 2 天缩短至 10 分钟,整改措施落实率提升至 92%。我的习惯是: 永远先画状态流转图,再写代码;永远用 Webhook 替代定时任务;永远把字段校验写在 Service 层,而不是前端 JS 。QCADOO 的力量不在它多庞大,而在它把制造执行的每一个“必须”都变成数据库里的一行约束、一次事务、一个不可绕过的状态跳转。希望帮到你。
258




被折叠的 条评论
为什么被折叠?



