简介:本资源是一套完整的基于Java与Vue的前后端分离架构MES(制造执行系统)生产管理平台源码,面向工业软件开发工程师、企业信息化系统开发者及高校智能制造方向学习者,旨在解决制造业中生产计划、过程管控、质量追溯与设备协同等核心业务场景的数字化落地问题。压缩包共1473个文件,含496个Java后端业务与配置类、201个Vue组件与页面逻辑、164个JS工具与API调用脚本、141个SVG图标资源及75个XML配置文件,整体大小为20.36MB;其中bat脚本(如run.bat、package.bat)体现本地快速启停与构建流程,bcmap字体映射文件支持多语言报表导出,SQL与JasperReport模板支撑统计报表模块。目前已有1156人学习下载,读者可直接部署运行,深入理解Spring Boot+MyBatis RESTful接口设计、Vue+Vuex+Element UI前端工程化实践,以及MES典型功能模块(如生产排班、条码追踪、设备维保、大屏看板)的完整实现逻辑与前后端协作范式。 做了几年制造业相关的系统开发,MES(制造执行系统)这名字在圈子里越来越常见。但真要说清楚它是干嘛的、怎么搭、坑在哪里,很多人还是含糊的。尤其近几年Java + Vue的前后端分离方案几乎成了MES项目的主流标配,大大小小的制造企业都在往这个方向走。这套基于Java和Vue构建的前后端分离MES生产执行管理系统源码,就是围绕车间生产管理场景落地的一套完整实现。如果你正打算接手MES项目、在公司内部做数字化改造,或者想找一份能跑起来的开源代码做二次开发,这篇内容应该能省下你大量翻文档的时间。我会直接按项目实际开发的顺序,从选型、模块设计、数据建模到常见故障,把核心逻辑和踩坑记录都摊开讲清楚。
1. MES系统的核心价值与整体设计思路
1.1 为什么MES要选前后端分离架构
MES面向的角色比普通管理系统复杂得多。计划员要排产、调度员要派工、车间操作工要报工、质检员要录检验结果、设备管理员要看点检保养、老板要看实时产量。这么多人同时用,界面交互样式和业务变化频率都很高。过去那种把页面放进后端模板(JSP、Thymeleaf)的传统单体模式,前端小改一个按钮都要重启服务,而且随着业务增长,后端项目文件越来越臃肿,维护成本相当高。
前后端分离的核心价值在于:后端只专注提供稳定的API接口,前端单独打包部署,走HTTP/JSON通信。这样前后端团队可以并行开发,接口定义好了各做各的,前端体验迭代不影响后端稳定性。部署上也能分开做负载均衡,前端扔到Nginx上就行。最关键的是,MES经常要对接PDA手持终端、车间大屏看板、PAD平板工位终端,这些多端场景天然就适合把后端能力通过API开放出去,一套后端服务喂给多个前端应用。选这个架构不是赶时髦,是MES这类业务系统的实际诉求决定的。
1.2 MES系统的业务边界与模块规划
做MES之前必须先明确一件事:MES和ERP的区别。简单说,ERP管的是订单、物料、财务,偏计划层面;MES管的是车间现场执行,关注工单怎么下达到产线、每道工序干了多少、合格多少、设备状态如何。和ERP对接时,通常ERP下生产订单给MES,MES执行完成后再把报工数量、工时、不良数回传给ERP。这个业务边界如果不搞清楚,模块设计很容易做成四不像。
这套源码里,整体模块规划我建议按以下边界来划分:
- 系统管理:用户、角色、菜单、权限、字典、参数配置,属于所有系统的底座。
- 基础数据:产品档案、物料清单、工艺路线、工序定义、工位管理、产线管理、班次日历。这是MES的"数据原材料",没有基础数据,后面所有业务都跑不起来。
- 计划排产:接收ERP工单,拆分到产线和工序,排定生产顺序和交期,可手动调整和插单。
- 生产执行:工单下达、开工、领料、报工、完工、返工/退料等操作,记录每道工序的实际执行情况。
- 质量管理:来料检验、过程巡检、完工检、不合格品处理、质量追溯。
- 设备管理:设备台账、点检保养计划、维修工单、设备状态监控。
- 安灯与异常:呼叫异常、异常类型上报、响应时间跟踪、异常统计分析。
- 报表看板:产量统计、工时统计、质量报表、设备OEE、车间实时看板。
模块不是说一次全做完,但设计的时候要预留扩展点。比如基础数据里的工艺路线字段,如果一开始只想着应付简单流程,后期要增加多版本管理时就要动表结构,这才是最头疼的。
1.3 为什么是Java + Vue,而不是其他技术组合
Java在制造业软件里占有率极高,不是偶然。制造业IT团队普遍对Java生态熟悉,招聘成本低,而且Spring Boot全家桶让开发效率大幅提升。加上MES经常要对接各种ERP(SAP、用友、金蝶)和底层设备,Java有成熟的企业级中间件生态,处理WebService、MQ传输、PLC数据采集对接都有现成方案。
前端选Vue是权衡后的结果。Vue对国内开发者来说上手曲线比React平缓,中文文档全,Element UI这类组件库开箱即用,非常适合MES这种大量表单、表格、弹窗的管理界面。Vue的响应式数据绑定让车间报工、工单操作这类高频交互的页面写起来很顺手,而且Vue生态下做动态路由、权限控制、国际化都有成熟方案,不用自己造轮子。
相比之下,用C# WinForm或Java Swing做传统C/S架构MES的也不少,但这类桌面客户端最大的问题是部署。车间几十台电脑,每台都要装客户端、更新还要挨个推,而B/S架构只需要浏览器访问,维护压力小得多。低代码平台虽然也能搭MES,但遇到复杂工艺逻辑和性能要求高的报表场景,低代码往往不如代码灵活可控。所以这套源码选Java + Vue + MySQL + Redis这条技术路线,是"既要开发效率、又要部署方便、还要能长期维护"的综合结果。
2. 前后端技术选型与关键依赖解析
2.1 后端技术栈与版本选择
后端不能只看Spring Boot版本,整个技术栈是一套组合拳。拿我做过的项目来说,选型时要考虑团队的熟悉度、云上部署还是本地机房、并发量级以及后期的维护成本。下面是我推荐的一套组合:
| 技术组件 | 推荐选择 | 主要用途 |
|---|---|---|
| JDK | 1.8或11 | 稳定且生态兼容 |
| 框架 | Spring Boot 2.7.x | 集成开发、接口发布 |
| 安全认证 | Spring Security + JWT | 登录鉴权、接口权限控制 |
| ORM | MyBatis-Plus | 数据访问、分页、条件构造器 |
| 数据库 | MySQL 5.7+ 或 8.0 | 核心业务数据存储 |
| 缓存 | Redis | 登录会话、字典缓存、看板实时数据 |
| 任务调度 | Quartz或XXL-Job | 定时报表生成、设备保养提醒、工单自动关闭 |
| 消息队列 | RabbitMQ(可选) | 关键操作异步化、异常推送、与外部系统解耦 |
选JDK 8或11,不是保守,是现实需要。很多制造企业的服务器环境老旧,运维不一定愿意装太高版本的JDK,而且Spring Boot 2.x对JDK 8支持最好,部署包体积和启动速度也稳定。如果你的团队已经普遍用JDK 17,Spring Boot 3也可以选,但从我踩坑的经验看,Spring Boot 3在做老系统对接、第三方依赖兼容上要多花一些时间,没必要。
2.2 前端技术栈与依赖管理
前端部分,Vue 2 + Element UI的搭配在MES项目里非常常见,因为Element UI对中后台表单、表格、弹窗、级联选择器支持非常完善,几乎不用写复杂的自定义组件。如果是全新项目,上Vue 3 + Element Plus也是趋势,差异主要在于组合式API和TypeScript的加持,复杂度更高,但可维护性更好。如果团队没人用过Vue 3,直接开工容易卡在响应式API的理解上,建议稳妥起步:Vue 2 + Element UI。
前端另外几个配套依赖也很重要:
- Axios负责封装HTTP请求,统一拦截器处理token过期和错误信息提示。
- Vue Router负责路由管理,做权限控制时使用动态路由,根据后端返回的菜单权限生成可访问的路由表。
- Pinia(Vue3)/Vuex(Vue2)做全局状态管理,存用户信息、权限标识、系统配置。
- ECharts做生产看板的折线图、柱状图、饼图,以及设备OEE仪表盘。
- 其实还有一个容易忽略的点,就是表格大数据展示。MES的报表动辄上万条记录,配合Element UI的虚拟滚动或分页插件是必须考虑的,不然页面会卡到怀疑人生。
2.3 版本兼容性的坑,提前列出来
选型和版本部署里最烦的就是版本冲突。前端Node版本对Vue项目的构建影响巨大,Vue 2老项目用Node 16通常没问题,Vue 3项目如果用到Vite则推荐Node 18以上。后端Maven依赖之间的冲突也时有发生,比如netty、fastjson、hutool的版本问题,建议在parent pom里统一管理版本,而不是每个模块自己声明。
还有一件很实际的事:Spring Boot自带的Jackson处理日期格式化,默认对LocalDateTime的格式不友好,常常返回"2024-01-01T12:00:00"这种带T的格式。MES系统里时间字段极多,计划时间、开工时间、完工时间、检验时间,如果不全局配置toString直接把日期转为字符串或统一格式,前端拿到的数据会非常难解析。这个在项目启动前一定要在Jackson配置类里做好全局格式。
3. 核心功能板块与业务逻辑拆解
3.1 工单管理:从ERP下达到产线开工的完整链路
生产工单是MES的核心业务单据,几乎所有功能模块都是围绕工单转的。工单的来源有两种:一是和ERP对接自动同步,二是手工创建。无论哪种来源,工单字段都要覆盖:工单号、产品编码、产品名称、计划数量、工单类型(普通/返工/样品)、优先级、计划开始/结束时间、状态、关联的工艺路线版本、备注。
工单状态流转要设计严谨。常见状态我按这样设计:待下达 -> 已下达 -> 生产中 -> 已完成 -> 已关闭。简单场景下这个就够了,但实际车间操作会有很多分支,比如生产过程中发现物料不够需要挂起,或来料不良需要暂停;还会出现部分完工、部分不良需要返工的情况。所以建议在状态机里加上一个"暂停"状态,并记录暂停原因和操作人。状态流转尽量通过后端服务方法控制,不要散落在各业务代码里随便改状态,否则后期排查問題的时候会非常痛苦。
我在工单模块里遇到最多的需求,是"插单"。车间里计划永远赶不上变化,销售突然插进来的紧急订单,计划员要在已有排程里调整优先级。实现上要支持拖拽调整工单顺序,并允许操作人修改工单优先级,后台记录调整日志,方便后续追溯。
3.2 报工与工序执行:多场景下的灵活设置
报工是操作工每天重复最多的动作。常见报工方式有三种:按完成数量报工、按工时报工、按工序流转卡报工。具体选哪种,取决于车间的自动化程度和工位布局。这套源码里最好同时支持,由系统配置参数决定启用哪种。
报工操作背后的逻辑并不简单。首先判断工单状态是否为"生产中",再校验当前操作人和工位是否有权限,然后检查本次报工数量是否超过剩余未报数量,防止超量。数量必须区分为"合格品数量"和"不良品数量",不良品还要关联不良原因代码。报工完成后更新工单总进度,若总完工数量达到计划数量,则自动触发工单完工校验。
这里强烈建议加一道幂等校验。车间网络不稳定,操作工点一次报工,如果网络超时,很容易再点一次,导致同一数量被提交两次。我的做法是在前端提交按钮加loading状态,后端在事务里判断"上次报工时间+设备+操作人+数量+工单"是否有完全相同记录,几秒内重复的直接拒绝。虽然不能百分之百拦截,但能挡住绝大多数重复提交。
3.3 质量管理:不只是记一个合格率
很多第一次做MES的人,把质量管理做成"录入检验结果+统计合格率",这就完全低估了质量模块的复杂度。MES的质检至少要覆盖三个环节:来料检验、过程检验、完工检验。每个环节的检验项目、抽样方案、判定标准都不一样,所以数据模型要支持可配置的检验模板。
检验模板要设计成两级结构:模板头和明细行。模板头定义适用产品、工艺路线、检验类型;明细行定义检验项名称、规格下限、规格上限、单位、抽样数、是否必检。录入检验结果时,系统自动判定单项是否合格,再根据所有项目的判定结果得出整单合格与否。不合格时要触发不合格品处理流程,处理方式包括:返工、让步接收、报废、退回供应商,每种方式都带审批流。
质量追溯这块,靠的是批次号或序列号。产品在关键工序流转时记录SN(序列号)、操作工、设备、物料批次、检验记录。这样一旦终端客诉,能通过成品SN反查到是哪台设备、哪个操作工、哪个物料批次生产的,实现正向和反向追溯。一些简单的实现可以在数据库里用一个"生产履历表"来记录,字段包含SN、工序、操作人、检验结果、物料批次等,不用做得太复杂就能满足90%的追溯需求。
3.4 设备管理与安灯异常:车间实时状态的核心
设备模块在MES里不是锦上添花,而是生产进度和OEE计算的基础数据来源。设备台账要记录设备编码、名称、型号、所属产线、责任人、购置日期、状态。设备状态常见的包括运行、停机、故障、保养、维修。这些状态变化要形成时间轴记录,用于计算设备运行时长、故障时长、OEE指标。
设备点检和保养计划建议用定时任务来驱动。每天凌晨生成当天的点检任务,分配到对应责任人;保养计划按周期生成保养工单。点检结果异常时,自动生成设备维修工单,通知维修人员。这一套流程并不复杂,但对车间的设备规范化管理很有价值。
安灯模块解决的是车间异常呼叫的问题。操作工发现物料缺料、设备故障、质量异常时,按工位上的安灯按钮或直接在网页端上报异常。系统记录异常发生时间和类型,通知对应的处理人,并计时跟踪响应时间。报表统计每个异常类型的平均响应时长和处理时长,为车间管理改进提供数据支撑。实现上可以用WebSocket实时推送异常信息到看板和责任人电脑,这块用Redis做一下状态存储和防重复通知,能避免很多并发消息导致的问题。
4. 实操过程与核心环节实现
4.1 项目工程结构与数据库建模要点
项目骨架的搭建决定了团队的协作方式和后续扩展能力。后端我推荐用Maven多模块结构,而不是一个单体大项目。你可以按这样组织:
mes-system ├─ mes-common // 公共模块:工具类、统一返回、异常处理 ├─ mes-framework // 框架配置:安全、Redis、MVC配置 ├─ mes-system // 系统管理模块:用户、角色、菜单 ├─ mes-biz // 业务模块:工单、报工、质量、设备 │ ├─ mes-plan // 计划排产 │ ├─ mes-execute // 生产执行 │ ├─ mes-quality // 质量管理 │ └─ mes-device // 设备管理 └─ mes-api // 暴露给外部系统的API接口模块划分的主要目的是避免业务代码相互耦合。比如生产执行模块要引用质量管理模块的检验单号,但如果不加控制随便互相调用,时间久了模块就乱了。我的经验是:下层模块不能依赖上层模块,公共的数据模型放到common里,模块间通过API接口交互。
数据库建模这块挑几张核心表说。工单表、报工记录表、质检单表、工序表、用户表是必须的。设计时注意几个原则:每张业务表都带主键(建议雪花ID)、创建时间、更新时间、创建人、更新人、逻辑删除标识。料品编码、工单号、SN号等字段要加唯一索引,这在并发场景下能防止重复数据。
以下是工单表和报工记录表的字段设计参考:
| 表名 | 关键字段 | 说明 |
|---|---|---|
| mes_work_order | order_no, product_code, plan_qty, status, priority, plan_start_time, plan_end_time, process_route_code | 工单基础信息 |
| mes_production_record | record_no, order_id, process_code, workstation_code, operator_id, qualified_qty, defective_qty, report_time | 报工记录 |
| mes_quality_inspection | inspection_no, inspection_type, source_type, source_id, inspector_id, result, inspect_time | 检验单 |
| mes_workstation | workstation_code, workstation_name, line_code, is_active | 工位定义 |
| mes_process_route | route_code, product_code, process_seq, process_code, process_name | 工艺路线 |
多工序场景下,报工记录要关联到具体的工序编码和工位编码,这才能支撑后续的工序产量统计。也可以把产品工艺路线设计成一张「工序路由表」,一个产品有多个工序排序,每道工序有对应的工位和标准工时。车间执行时按工艺顺序流转,MES根据当前工序判断是否允许进入下道工序。
4.2 权限模型与安全设计:基于RBAC的动态权限控制
MES里的权限必须细分到操作级别和部门数据级别。比如车间主任能看到整个车间的数据,班组长只能看到本班组的数据,操作工只能操作自己工位的数据。这种区分只靠角色不够,还得在数据层做过滤。
我在这套项目里采用RBAC模型,即用户 -> 多角色 -> 多权限(菜单权限+操作权限+数据权限)。后端使用Spring Security做认证授权,登录成功后签发JWT,前端每次请求带上token。后端通过自定义注解+AOP校验操作权限,比如@RequiresPermission("mes:order:edit")。数据权限则通过MyBatis-Plus的拦截器,在执行SQL前根据当前用户的数据范围自动追加过滤条件,比如"dept_id = ?"或"line_code LIKE ?",这样不会漏加权限判断。
前端权限这块也要处理:用户登录后,后端返回该用户具有的菜单列表和按钮权限列表,前端根据这些数据动态生成路由和菜单。没有权限的按钮直接隐藏。这样做的好处是,车间里几百个用户,每个人打开系统的界面都不一样,操作工看到的就是报工页和工单列表,不会误操作到系统配置。
4.3 一个核心接口的完整实现示范:工单开工与报工
说再多理论,不如直接走一遍代码。拿生产执行里最核心的"工单开工报工"接口来演示。
先看后端Service层的核心代码。
@Service public class ProductionRecordServiceImpl implements ProductionRecordService { @Resource private WorkOrderMapper workOrderMapper; @Resource private ProductionRecordMapper productionRecordMapper; @Override @Transactional(rollbackFor = Exception.class) public Result createProductionRecord(ProductionRecordDTO dto) { // 1. 校验工单状态 WorkOrder order = workOrderMapper.selectById(dto.getOrderId()); if (order == null) { return Result.error("工单不存在"); } if (!WorkOrderStatus.PRODUCING.getCode().equals(order.getStatus())) { return Result.error("工单状态不允许报工"); } // 2. 校验报工数量 Integer reportedQty = productionRecordMapper.sumReportedQty(dto.getOrderId(), dto.getProcessCode()); int remainingQty = order.getPlanQty() - reportedQty - (dto.getQualifiedQty() + dto.getDefectiveQty()); if (remainingQty < 0) { return Result.error("本次报工数量超过剩余计划数量"); } // 3. 插入报工记录 ProductionRecord record = new ProductionRecord(); record.setOrderId(dto.getOrderId()); record.setProcessCode(dto.getProcessCode()); record.setWorkstationCode(dto.getWorkstationCode()); record.setOperatorId(SecurityUtils.getUserId()); record.setQualifiedQty(dto.getQualifiedQty()); record.setDefectiveQty(dto.getDefectiveQty()); record.setReportTime(LocalDateTime.now()); productionRecordMapper.insert(record); // 4. 更新工单状态(完工判断) int totalReported = productionRecordMapper.sumTotalReported(dto.getOrderId()); if (totalReported >= order.getPlanQty()) { order.setStatus(WorkOrderStatus.COMPLETED.getCode()); order.setFinishTime(LocalDateTime.now()); workOrderMapper.updateById(order); } return Result.success("报工成功"); } }这段代码的关键在于事务。报工这个动作涉及插入记录、更新工单状态,必须在一个事务里完成,否则会出现记录插入成功但工单状态没更新的情况。@Transactional注解加rollbackFor = Exception.class能保证遇到任何运行时异常都回滚。
再看前端对应的调用。
// 报工页面核心逻辑 submitReport() { if (!this.reportForm.qualifiedQty && !this.reportForm.defectiveQty) { this.$message.warning('合格数和不良数不能都为空') return } this.loading = true createProductionRecord(this.reportForm).then(res => { this.$message.success('报工成功') this.loading = false this.refreshOrderInfo() }).catch(err => { this.loading = false this.$message.error(err.message || '报工失败') }) }前端最重要的事就是提交按钮的loading状态。很多新手忘了加,结果网络慢的时候操作工反复点,后端收到一堆重复请求。加loading后虽然不能完全避免重复,但能大幅降低概率。另外报工页面的数量输入框建议做限制,合格数量不能为负数,不良数不能超过计划数,这些前端校验能减少后端不必要的异常请求。
4.4 看板与报表数据的实时刷新方案
MES的车间看板是老板和管理者最关心的功能。实时产量、设备状态、工单进度、质量状况都要以极高的频率刷新。传统做法是前端定时轮询,每30秒调一次接口,简单但浪费资源,而且看板数据量大时接口压力不小。
好一点的方案是WebSocket推送。后端在报工、质检、设备状态变化时,主动向指定客户端推送最新的看板数据。用Spring的WebSocket + STOMP协议,前端用stompjs订阅topic。推送的频率不用很高,每次业务操作后推送一次即可。如果团队对WebSocket不熟悉,也可以用SSE(Server-Sent Events)简单实现服务端单向推送,效果也够用。
报表查询性能则是另一个容易翻车的点。MES日报、月报、良率统计表,数据量一上来就是几万条,如果再随意做全表count,数据库直接扛不住。我的做法是:常规统计走MySQL的聚合查询,配合时间段索引和常用过滤条件的联合索引;复杂的月度综合报表放到凌晨通过定时任务预生成统计表,前端直接查结果表。这样报表打开速度能控制在1秒内,而不是让用户等半分钟。
5. 常见问题与排查技巧实录
5.1 前端跨域与路由刷新404问题
前端跨域是前后端分离项目里第一个遇到的坑。开发环境下,Vue的devServer可以通过proxy把请求转发到后端,解决跨域问题。生产环境下,把前端打包到Nginx,后端的接口地址通过Nginx反向代理转发,这样浏览器看到的都是同源的,不会有跨域问题。配置参考:
server { listen 80; server_name mes.example.com; location / { root /opt/mes-frontend/dist; index index.html; try_files $uri $uri/ /index.html; } location /prod-api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }try_files那行是解决Vue Router history模式刷新404的关键。不写这行,用户在页面里点路由没问题,一按F5刷新就404了。生产上踩过这个坑的人不少,在这里记一次。
5.2 后端时区与日期格式化问题
MES系统里到处是时间字段,计划时间、报工时间、检验时间、设备运行时长。数据库存的是DateTime,Java端用的是LocalDateTime,前端展示要把时间格式化。最容易出的问题有三个:
第一,服务器时区没设对,导致存入数据库的时间比实际时间早8小时或晚8小时。解决方法是MySQL连接串加上serverTimezone=Asia/Shanghai,JVM启动参数也加上-Duser.timezone=Asia/Shanghai。
第二,Jackson序列化LocalDateTime默认格式是"2024-01-01T12:00:00",前端如果不处理,直接展示带T的字符串很难看。统一在配置类里加上LocalDateTimeSerializer,格式化模式设为yyyy-MM-dd HH:mm:ss。
第三,前端Element UI的日期选择器返回的格式是Date对象,提交到后端时可能序列化成长时间戳格式,和字段类型对不上。用一个公共的axios拦截器处理日期字段,或者在Vue组件里直接绑定value-format="yyyy-MM-dd HH:mm:ss",能省很多麻烦。
5.3 并发报工与数据一致性问题
车间里几十个人同时报工,数据库并发写入很容易出现超卖问题(报工总数大于计划数)。单纯靠后端代码先查询再判断,在并发情况下会出现判断时剩余数量充足,但插入记录时已经被其他人抢先的情况。
解决思路有几种。第一种是数据库锁,在工单表上加乐观锁字段,更新前比较版本号,版本不一致就提示重试。第二种是唯一约束,在报工记录表里对"工单ID+工序编码+工位+操作人+报工时间"建联合唯一索引,重复插入直接报错。第三种是用Redis的分布式锁,同一工单同一工序同时只有一个人能报工。实际项目我用最多的还是乐观锁+前端防重结合,能覆盖99%的场景,代价又最小。
还有一类问题是事务失效。很多人写完加@Transactional的Service方法后,发现数据不一致。原因往往是在同一个类里A方法调用B方法,B的@Transactional没生效。这是因为Spring事务通过代理对象实现,内部方法调用不走代理。解决办法是把B方法拆到另一个Service里,或者通过AopContext.currentProxy()获取代理对象再调用。这个坑排查起来比较隐蔽,如果发现某段事务逻辑时不时不正常,可以优先检查这一点。
5.4 MyBatis-Plus的更新空字段问题
用MyBatis-Plus做更新操作时,默认策略是忽略实体里为null的字段,只更新非null字段。这个特性大多数时候很省心,但也会踩坑:需要把某个字段清空置null时,直接set null再updateById发现没效果。这时候要用UpdateWrapper的set(column, null)来强制更新空值。
还有一个常用习惯:逻辑删除字段。MyBatis-Plus配置了全局逻辑删除后,删除操作会变成update逻辑。这个一定要在项目初期就配好,不然后期加上去,历史SQL很多会受牵连。同时逻辑删除字段在联合唯一索引里要考虑清楚,比如工单号做了唯一索引,逻辑删除的旧记录如果还占着唯一索引,新建同号工单就会冲突,最好把逻辑删除字段也加入唯一索引。
5.5 业务上容易忽略的坑:换班切换和月末统计
MES系统的报表统计经常要按班次分组。白班从早上8点到晚上8点,夜班从晚上8点到第二天早上8点。这里有个容易忽略的问题:报工时间跨班次怎么办?比如操作工在晚上8点零5秒报的工,应该算夜班,但如果数据库按自然日存储,就会归到白班当天。
两个解决办法:一是表结构里加一个shift_code字段,前端报工时带入当前班次,后端根据班次日历自动判断;二是报表SQL计算时用CASE WHEN判断时间点归属于哪个班次。我推荐用第一种,数据在源头就定好,统计时不用费劲转换。
月末统计也有坑。财务要的产量数据是按自然月的,但车间的统计口径可能是从每月26号到次月25号。这种口径差异如果在系统里不配置,到时候导出报表两边对不上,会非常麻烦。基础数据里建议做一个"账期日历"配置,支持定义任意日期范围作为统计周期,报表模块统一读取这个配置,不用到处写死。
6. 这套源码后续的扩展方向建议
写完核心模块后,这套MES系统的开发并没有结束。对做实际项目的团队来说,源码能跑起来只是第一步,关键是怎么让它适配自己的业务。我的建议是先把基础数据和生产执行跑通,再逐步增加质量、设备、报表这些模块,不要一上来就想全功能覆盖。
后续如果要做IoT设备数据采集,可以考虑引入Modbus、OPC UA等工业协议,把设备数据实时采集到MES系统里。这时后端服务需要新增一个采集模块,缓存设备实时状态到Redis,再由看板模块拉取展示。这个过程不需要改动核心业务表,只需要新增采集表和接口,前期设计预留扩展点的优势就体现出来了。
另外AI质检、设备预测性维护这些技术方向的探索,也正在逐步融入MES行业。虽然现阶段传统制造企业更关心的是基础数字化,但你在做技术选型和数据建模时,给后续数据积累留一些余地是非常划算的。比如报表模块设计成可配置的图表数据源,未来接算法模型时不需要大改。
说回具体的干法,做MES项目最容易被忽略的不是技术,而是去车间蹲守。我做过几个MES项目,最大的体会就是:你不在车间看过操作工怎么干活,不理解他们为什么抱怨PMC派工不合理,不感受一下产线停线时候的紧张气氛,做出来的系统就永远是产品经理想象中的MES,而不是车间里真正能用的MES。别急着写代码,先去车间待两天,看看工人手里拿着的纸单记录了什么数据,看看班组长每天在表格里统计什么。技术方案从来不是难事,业务流程才是。
最后分享一个小技巧:MES项目从需求确认到上线,中间会经历无数轮变更。强烈建议在开发前就跟业务方确认好"变更记录表",每次需求变更都记录时间、提出人、变更内容、影响范围、是否影响上线时间。不然到项目后期,你会发现代码已经改得和最初设计完全不是一回事,而出问题的时候,没人说得清这个逻辑是什么时候加的、为什么加。这套Java + Vue的前后端分离MES源码是一个好的地基,但真正的价值,取决于你在这个地基上盖出什么样的车间。
本文还有配套的精品资源,点击获取