资讯动态

轻量级MES实战:基于若依框架的工单报工与设备联动

发布时间:2026/10/25 14:48:53 来源:尧图企业网站定制
简介本资源是一份面向制造业数字化转型从业者、MES系统实施工程师及工业信息化学习者的专业入门资料聚焦智能制造核心系统——制造执行系统MES的架构设计、功能模块与企业集成逻辑。文档系统梳理了MES在生产、质量、设备、监控、仓储五大领域的落地能力涵盖制程防错、实时进度追踪、OEE分析、SPC过程控制、正反向追溯及智能仓库联动等关键实践并详解其与ERP、PLM、WMS等系统的EAI集成路径与分层架构管理层/执行层/控制层/设备层。资源为单文件PDF格式大小2.83MB内容结构清晰、图文并茂含12页核心架构图、功能模块列表与典型业务流程说明便于快速建立MES全局认知与实施框架。目前已有495人学习下载适合初入智能制造领域者构建知识体系也适合作为项目方案汇报或内部培训的基础素材。1. MES不是ERP的简化版它专治车间里“人没看见、机没记下、料没对上”的实时断点你刚接手产线数字化改造领导甩来一份《智能制造系统MES简介.pdf》打开第一页就写着“制造执行系统MES是连接企业计划层与车间控制层的信息枢纽”——这句话没错但等于没说。真正让你头皮发紧的是排产计划下发后三号冲压线实际干了什么换模时间到底卡在哪个环节昨天那批不良品是A班操作员漏检还是B班设备参数漂移了2小时没人干预这些信息在ERP里查不到在PLC日志里又太碎片。MES要解决的从来不是“有没有系统”而是“有没有一个能在秒级粒度上把人、机、料、法、环五要素对齐”的现场操作系统。它不替代ERP做财务核算也不替代SCADA做毫秒级设备采集它的不可替代性就藏在“计划下达后第37分钟某工位报工延迟、同时温控曲线异常、辅料扫码失败”这种三重并发事件的归因能力里。适合正在推进精益生产落地、面临多品种小批量交付压力、或已部署IoT但数据沉在边缘没形成业务闭环的制造企业工程师与IT实施人员。本文不讲PPT里的架构图只拆解一个真实可跑通的轻量级MES核心模块从若依框架出发如何用最小改动实现工单下发、工序报工、设备状态联动这三件最常翻车的事。2. 为什么选若依框架打底不是因为它多先进而是它把MES最痛的“权限-流程-日志”三角踩实了MES系统落地最大的隐形成本从来不是代码而是业务规则与系统权限的咬合精度。比如质检员能修改检验结果但不能修改工艺参数班组长能强制报工但不能删除历史记录设备管理员能重启采集服务但看不到生产订单详情。若依框架RuoYi之所以成为国内MES二次开发高频选择并非因其前端炫酷而在于它用一套成熟RBAC模型动态数据权限操作日志审计把这三根骨头提前啃透了。我们不需要重写权限引擎只需在它的sys_role、sys_menu、sys_dept三层结构上叠加MES特有的业务维度——比如按“产线-班组-工位”三级组织树绑定角色再通过DataScope注解自动过滤用户可见的工单范围。这种设计让后续所有功能开发都避开“谁该看什么”的扯皮直接聚焦在业务逻辑本身。2.1 在若依V4.7.0上初始化MES基础数据表只加5张表不碰原框架任何核心表MES业务强依赖主数据一致性但若依默认不提供设备、工位、工艺路线等实体。我们采用“最小侵入”原则仅新增以下5张表MySQL建表语句严格遵循若依命名规范全部带mes_前缀-- mes_equipment: 设备主数据关联PLC采集点位 CREATE TABLE mes_equipment ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主键ID, equipment_code varchar(64) NOT NULL COMMENT 设备编码如CNC-001, equipment_name varchar(128) NOT NULL COMMENT 设备名称, line_id bigint NOT NULL COMMENT 所属产线ID关联sys_dept, status tinyint NOT NULL DEFAULT 1 COMMENT 状态0停用1启用, ip_address varchar(32) COMMENT PLC IP地址, modbus_slave_id int COMMENT Modbus从站ID, PRIMARY KEY (id), UNIQUE KEY uk_equipment_code (equipment_code) ) ENGINEInnoDB COMMENT设备主数据表; -- mes_workstation: 工位定义绑定物理位置与工艺能力 CREATE TABLE mes_workstation ( id bigint NOT NULL AUTO_INCREMENT, workstation_code varchar(64) NOT NULL COMMENT 工位编码如ASM-01-A, workstation_name varchar(128) NOT NULL, line_id bigint NOT NULL COMMENT 所属产线, process_capability varchar(255) COMMENT 支持的工艺类型JSON数组[焊接,点胶], operator_count int NOT NULL DEFAULT 1 COMMENT 标准作业人数, PRIMARY KEY (id) ) ENGINEInnoDB COMMENT工位定义表; -- mes_routing: 工艺路线定义工序顺序与标准工时 CREATE TABLE mes_routing ( id bigint NOT NULL AUTO_INCREMENT, routing_code varchar(64) NOT NULL COMMENT 工艺路线编码, product_code varchar(64) NOT NULL COMMENT 对应产品编码, version varchar(32) NOT NULL COMMENT 版本号如V1.0, is_default tinyint NOT NULL DEFAULT 0 COMMENT 是否默认版本, PRIMARY KEY (id) ) ENGINEInnoDB COMMENT工艺路线主表; -- mes_routing_step: 工序明细每条记录是一个工序节点 CREATE TABLE mes_routing_step ( id bigint NOT NULL AUTO_INCREMENT, routing_id bigint NOT NULL COMMENT 所属工艺路线ID, step_order int NOT NULL COMMENT 工序序号1,2,3..., workstation_id bigint NOT NULL COMMENT 要求工位ID, standard_time decimal(10,2) NOT NULL COMMENT 标准工时分钟, control_point varchar(255) COMMENT 关键控制点JSON{temperature:80±5℃,torque:12±0.5N·m}, PRIMARY KEY (id) ) ENGINEInnoDB COMMENT工艺路线工序明细表; -- mes_production_order: 生产工单MES核心业务单据 CREATE TABLE mes_production_order ( id bigint NOT NULL AUTO_INCREMENT, order_no varchar(64) NOT NULL COMMENT 工单号如PO20240520001, product_code varchar(64) NOT NULL COMMENT 产品编码, quantity int NOT NULL COMMENT 计划数量, start_time datetime COMMENT 计划开工时间, end_time datetime COMMENT 计划完工时间, status varchar(32) NOT NULL COMMENT 状态DRAFT/RELEASED/IN_PROGRESS/DONE/CLOSED, created_by bigint NOT NULL COMMENT 创建人ID关联sys_user, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no) ) ENGINEInnoDB COMMENT生产工单主表;提示所有表均未添加外键约束若依框架禁用外键通过MyBatis Plus的TableField注解在Java实体类中声明逻辑关联。mes_production_order.status字段值必须严格限定为枚举值避免前端传入非法字符串导致状态机混乱。2.2 基于若依代码生成器快速构建CRUD3步生成设备管理模块若依的ry-ui前端和ry-system后端已预置代码生成器我们利用它生成mes_equipment的增删改查全程无需手写一行Controller或Mapper XML进入若依后台 → 系统工具 → 代码生成点击“导入表”勾选mes_equipment修改生成配置业务名填equipment生成路径为/system/equipment模块名填system复用若依系统模块避免新建模块增加路由复杂度作者填你的名字生成代码会自动写入表前缀mes_→ 生成实体类名自动为MesEquipment点击“生成代码” → 下载ZIP → 解压后将java目录覆盖到ruoyi-system/src/main/java/com/ruoyi/system/将resources目录覆盖到ruoyi-system/src/main/resources/mapper/system/最后将vue目录合并到ruoyi-ui/src/views/system/生成后需手动补两处在MesEquipment.java中为TableField(line_id) private Long lineId;添加ApiModelProperty(所属产线)Swagger文档需要在EquipmentMapper.xml的select语句中将FROM mes_equipment改为FROM mes_equipment e LEFT JOIN sys_dept d ON e.line_id d.dept_id并在SELECT子句加入d.dept_name as lineName使列表页能显示产线名称而非ID。此时访问http://localhost:80用admin登录左侧菜单已出现“系统管理 设备管理”点击即可增删改查——这不是Demo而是可直接投入试运行的生产级模块因为若依生成的代码自带权限校验、分页、导出、批量删除等工业级功能。3. 工单下发与工序报工用状态机驱动业务拒绝if-else堆砌MES最核心的业务流是“工单→工序→报工→完工”但90%的翻车源于状态流转失控比如工单状态已是IN_PROGRESS但某工序仍允许重复报工或报工时未校验设备是否处于RUNNING状态导致停机期间的数据被计入有效产出。我们放弃用一堆if(status X userRole Y)硬编码而是用Spring State Machine定义清晰的状态转换规则。3.1 定义MES工单状态机5个状态 7种事件 严格守卫条件在ruoyi-system模块中新建包com.ruoyi.system.mes.statemachine创建状态机配置类Configuration EnableStateMachineFactory public class MesOrderStateMachineConfig extends StateMachineConfigurerAdapterString, String { Override public void configure(StateMachineConfigurationConfigurerString, String config) throws Exception { config .withConfiguration() .autoStartup(true) // 启动时自动初始化 .listener(stateMachineListener()); // 绑定监听器用于日志审计 } Override public void configure(StateMachineTransitionConfigurerString, String transitions) throws Exception { transitions .withExternal() .source(DRAFT).target(RELEASED).event(RELEASE) // 草稿→发布 .guard(releaseGuard()) // 守卫检查BOM完整性、工艺路线存在性 .and().withExternal() .source(RELEASED).target(IN_PROGRESS).event(START) // 发布→开工 .guard(startGuard()) // 守卫检查设备可用性、物料齐套性 .and().withExternal() .source(IN_PROGRESS).target(IN_PROGRESS).event(REPORT) // 开工中→报工自循环 .guard(reportGuard()) // 守卫当前工序未超时、设备状态正常、操作员有权限 .and().withExternal() .source(IN_PROGRESS).target(DONE).event(FINISH) // 开工中→完成 .guard(finishGuard()) // 守卫所有工序报工完成率100% .and().withExternal() .source(DONE).target(CLOSED).event(CLOSE) // 完成→关闭 .guard(closeGuard()); // 守卫质量检验已通过、工单差异已处理 } // 守卫逻辑示例reportGuard() 检查当前工序是否允许报工 Bean public GuardString, String reportGuard() { return context - { String orderNo context.getMessageHeader(orderNo); // 从消息头取工单号 MesProductionOrder order orderService.selectByOrderNo(orderNo); if (order null) return false; // 获取当前待报工工序按工序序号升序取第一个未报工的 MesRoutingStep nextStep routingStepService.selectNextUnreportedStep(order.getRoutingId()); if (nextStep null) return false; // 无待报工序禁止报工 // 检查设备状态必须为RUNNING且在线 MesEquipment equipment equipmentService.selectById(nextStep.getWorkstationId()); if (!RUNNING.equals(equipment.getStatus()) || !equipment.getIsOnline()) { throw new BusinessException(设备 equipment.getEquipmentCode() 未就绪无法报工); } return true; }; } }参数说明状态机事件RELEASE/START/REPORT等由前端按钮触发通过stateMachine.send(MessageBuilder.withPayload(REPORT).setHeader(orderNo, PO20240520001).build())发送。守卫函数Guard在状态转换前执行返回false则阻断转换并抛出明确异常前端可捕获提示用户具体原因——这比try-catch后笼统提示“操作失败”更符合车间操作习惯。3.2 报工接口的原子性保障用数据库行锁防并发超报当多个工位同时扫描同一工单二维码报工时极易发生“超报工”系统显示某工序完成10次但实际只干了9次。根本原因是报工逻辑未加锁两个请求同时读取mes_routing_step中completed_count字段各自1后写回导致丢失一次更新。解决方案用MySQL的SELECT ... FOR UPDATE锁定当前工序行。Service public class MesReportService { Transactional(rollbackFor Exception.class) public void reportStep(String orderNo, Long workstationId, Integer quantity) { // 1. 锁定该工单在该工位的工序记录注意WHERE条件必须命中索引 MesRoutingStep step routingStepMapper.selectOne( new LambdaQueryWrapperMesRoutingStep() .eq(MesRoutingStep::getRoutingId, getRoutingIdByOrderNo(orderNo)) .eq(MesRoutingStep::getWorkstationId, workstationId) .last(FOR UPDATE) // 关键加行锁 ); if (step null) { throw new BusinessException(未找到工单 orderNo 在工位 workstationId 的工序); } // 2. 校验是否可报工此处复用状态机守卫逻辑避免重复 if (!canReport(step)) { throw new BusinessException(当前工序不满足报工条件); } // 3. 原子更新completed_count completed_count quantity int updated routingStepMapper.update(null, new LambdaUpdateWrapperMesRoutingStep() .setSql(completed_count completed_count quantity) .eq(MesRoutingStep::getId, step.getId()) ); if (updated ! 1) { throw new BusinessException(报工更新失败请重试); } // 4. 记录报工日志含操作员、设备、时间戳 MesReportLog log new MesReportLog(); log.setOrderNo(orderNo); log.setWorkstationId(workstationId); log.setQuantity(quantity); log.setOperatorId(SecurityUtils.getUserId()); log.setReportTime(new Date()); reportLogMapper.insert(log); } }血泪经验SELECT ... FOR UPDATE的WHERE条件必须使用索引字段如本例中的routing_id和workstation_id否则会升级为表锁导致整个工艺路线表被阻塞。上线前务必用EXPLAIN验证执行计划。4. 设备状态与工艺参数联动用MQTT桥接PLC让“设备心跳”驱动MES决策MES的价值上限取决于它能否感知设备的真实状态。若依框架本身不处理设备通信我们必须在它之上架设一层轻量级设备接入层。这里不推荐重写通信协议栈而是用Eclipse Paho MQTT客户端将PLC采集的原始数据如运行状态、温度、电流发布到本地MQTT Broker再由MES订阅消费——解耦、低侵入、易扩展。4.1 部署Mosquitto作为本地MQTT Broker3行命令搞定# Ubuntu 22.04下安装其他系统请查官方文档 sudo apt update sudo apt install mosquitto mosquitto-clients -y # 修改配置启用WebSocket支持供前端实时图表使用 echo listener 9001 | sudo tee -a /etc/mosquitto/mosquitto.conf echo protocol websockets | sudo tee -a /etc/mosquitto/mosquitto.conf # 重启服务 sudo systemctl restart mosquitto验证用mosquitto_sub -h localhost -p 1883 -t device//status订阅所有设备状态主题再开新终端执行mosquitto_pub -h localhost -p 1883 -t device/CNC-001/status -m {status:RUNNING,temperature:78.5}确认第一条消息被收到——这是设备接入的最小可行验证。4.2 在MES中订阅设备状态用Spring Integration实现零配置MQTT消费在ruoyi-system的pom.xml中添加依赖dependency groupIdorg.springframework.integration/groupId artifactIdspring-integration-mqtt/artifactId /dependency创建MQTT配置类Configuration public class MqttConfig { Value(${mqtt.broker-url:tcp://localhost:1883}) private String brokerUrl; Bean public MqttPahoClientFactory mqttClientFactory() { DefaultMqttPahoClientFactory factory new DefaultMqttPahoClientFactory(); factory.setServerURIs(new String[]{brokerUrl}); return factory; } Bean ServiceActivator(inputChannel mqttInputChannel) public MessageHandler mqttOutbound() { MqttMessageHandler handler new MqttMessageHandler(mqttClientFactory()); handler.setAsync(false); // 同步处理确保状态更新不丢失 handler.setDefaultTopic(device//status); return handler; } Bean public MessageChannel mqttInputChannel() { return new PublishSubscribeChannel(); } Bean EventListener public ApplicationRunner mqttRunner(MqttPahoClientFactory factory) { return args - { // 启动时订阅设备状态主题 MqttPahoMessageDrivenChannelAdapter adapter new MqttPahoMessageDrivenChannelAdapter(mes-consumer, factory, device//status); adapter.setCompletionTimeout(5000); adapter.setConverter(new DefaultMQTTMessageConverter()); adapter.setOutputChannel(mqttInputChannel()); adapter.start(); }; } }创建设备状态处理器Component public class DeviceStatusHandler { ServiceActivator(inputChannel mqttInputChannel) public void handleDeviceStatus(Message? message) { try { // 解析MQTT payload为JSON String payload new String((byte[]) message.getPayload(), StandardCharsets.UTF_8); JSONObject json JSON.parseObject(payload); // 提取设备编码从topic中解析device/CNC-001/status → CNC-001 String topic (String) message.getHeaders().get(mqtt_receivedTopic); String equipmentCode topic.split(/)[1]; // 取第二个分段 // 更新设备状态表 MesEquipment equipment equipmentService.selectByCode(equipmentCode); if (equipment ! null) { equipment.setStatus(json.getString(status)); equipment.setTemperature(json.getDouble(temperature)); equipment.setLastHeartbeat(new Date()); equipmentService.updateById(equipment); // 关键联动若设备状态变更为STOPPED自动暂停其关联工单 if (STOPPED.equals(json.getString(status))) { pauseOrdersByEquipment(equipment.getId()); } } } catch (Exception e) { log.error(处理设备状态失败, e); } } private void pauseOrdersByEquipment(Long equipmentId) { // 查询该设备所在工位的所有进行中工单 ListMesProductionOrder orders orderService.selectOrdersByWorkstation(equipmentId, IN_PROGRESS); for (MesProductionOrder order : orders) { // 调用状态机发送PAUSE事件需先扩展状态机支持暂停 stateMachine.send(MessageBuilder.withPayload(PAUSE) .setHeader(orderNo, order.getOrderNo()).build()); } } }玄学调试技巧MQTT消息乱码90%是PLC侧发送时未指定UTF-8编码。在PLC程序中确保字符串字段以UTF-8字节流发送而非系统默认编码如GBK。用mosquitto_sub -v -t device/#开启详细模式观察原始字节流。5. 避坑指南MES落地中最常被忽略的5个“现场细节”MES项目失败往往死于对车间真实场景的误判。以下是我在3个汽车零部件厂、2个电子组装线踩过的坑每一条都附带现场照片级还原和可立即执行的修复方案。5.1 现象工单报工后系统显示“已完成”但车间主任说“那台设备还在修根本没干活”原因报工动作由操作员在平板点击触发但未与设备PLC的实际运行信号如M8000常开触点做双重校验。操作员为赶产量提前点击报工。解决在reportGuard()守卫函数中强制调用equipmentService.getPlcStatus(equipmentCode)方法通过Modbus TCP读取PLC寄存器如地址40001的值只有值为1运行中才允许报工。不要相信人的点击只相信PLC的触点。5.2 现象切换产品型号后同一台设备报工数据全乱A产品的参数被记到B产品工单上原因设备采集服务未按工单上下文隔离。PLC持续推送温度数据但MES服务端未将数据流与当前激活的工单绑定导致数据“串货”。解决在设备状态处理器中不直接更新mes_equipment表而是插入mes_equipment_data实时数据表并增加order_no字段。查询时按order_no timestamp范围聚合彻底切断跨工单污染。5.3 现象夜班交接时工单状态卡在IN_PROGRESS但早班没人能“继续报工”原因若依框架的SecurityUtils.getUserId()获取的是登录用户ID但夜班操作员用的是同一个账号为省事共享账号系统无法区分“谁在操作”导致状态机守卫认为“非本人操作”而拒绝。解决废除共享账号为每个班次配置独立账号并在mes_production_order表中增加current_operator_id字段。每次报工时用SecurityUtils.getUsername()匹配账号再更新该字段。交接班时由班组长在系统中执行“移交工单”操作更新current_operator_id。5.4 现象扫描枪扫工单二维码偶尔失败操作员猛按3次结果系统记录3次报工原因前端未做防抖网络延迟导致多次请求发出后端接口也未做幂等性校验。解决前端扫描后立即禁用按钮2秒后端在reportStep()方法开头用Redis存储report: orderNo : workstationId的唯一token过期时间30秒重复请求直接返回成功。车间操作没有F5刷新的概念只有“扫一下看绿灯亮没亮”。5.5 现象领导要看“设备综合效率OEE”系统算出来是35%但老师傅说“我们这线至少有70%”原因OEE计算公式中“可用率”分母用了24小时但车间实际每天只开工16小时8:00-24:00且包含1小时午餐休息。系统把休息时间也算作“计划停机”拉低了分母。解决在mes_production_order表中增加planned_working_hours字段如15.0OEE计算时可用率 实际运行时间 / planned_working_hours。这个字段必须由班组长在开工前填写系统不可自动生成——所有影响KPI的参数必须由现场责任人确认而不是由IT部门拍脑袋设定。6. 进阶技巧用若依的“定时任务”模块实现无人值守的工单自动释放与预警MES真正的价值不是让人天天盯着屏幕点鼠标而是让系统在无人干预时自动完成那些有明确规则的判断。若依框架内置的sys_job定时任务模块就是实现这一目标的完美杠杆——它比写Shell脚本更可靠比调度中间件更轻量且天然集成权限与日志。6.1 场景一每日8:00自动释放当日工单替代人工逐条点击很多工厂要求“前一天晚上把第二天的工单全部发布”但IT人员不可能凌晨来点鼠标。我们用若依定时任务在每天7:55执行工单释放Component public class DailyOrderReleaseJob { Autowired private MesOrderStateMachine stateMachine; Scheduled(cron 0 0 55 7 * ?) // 每天7:55:00执行 public void releaseTodaysOrders() { // 查询今日生效的工单计划开工时间在今天内且状态为DRAFT ListMesProductionOrder draftOrders orderService.selectList( new LambdaQueryWrapperMesProductionOrder() .eq(MesProductionOrder::getStatus, DRAFT) .ge(MesProductionOrder::getStartTime, DateUtils.beginOfDay(new Date())) .le(MesProductionOrder::getStartTime, DateUtils.endOfDay(new Date())) ); for (MesProductionOrder order : draftOrders) { try { // 调用状态机发布RELEASE事件 stateMachine.send(MessageBuilder.withPayload(RELEASE) .setHeader(orderNo, order.getOrderNo()).build()); log.info(自动释放工单{}, order.getOrderNo()); } catch (Exception e) { log.error(释放工单{}失败, order.getOrderNo(), e); // 失败时发企业微信告警此处省略告警代码 } } } }参数说明Scheduled(cron 0 0 55 7 * ?)中55是秒55秒7是小时7点即每天7:55:00触发。若需精确到分钟级如7:55:00必须用cron而非fixedDelay因为后者受上一次执行耗时影响。6.2 场景二每5分钟扫描一次对“开工超2小时未报工”的工单自动预警这是MES最实用的“数字巡检员”功能。我们配置一个每5分钟执行的任务扫描所有IN_PROGRESS状态且start_time超过2小时的工单Component public class OrderStuckWarningJob { Autowired private WeComAlertService weComAlertService; // 企业微信告警服务 Scheduled(fixedRate 300000) // 每5分钟执行一次300000毫秒 public void checkStuckOrders() { Date twoHoursAgo DateUtils.addHours(new Date(), -2); ListMesProductionOrder stuckOrders orderService.selectList( new LambdaQueryWrapperMesProductionOrder() .eq(MesProductionOrder::getStatus, IN_PROGRESS) .lt(MesProductionOrder::getStartTime, twoHoursAgo) ); for (MesProductionOrder order : stuckOrders) { // 查询该工单当前应报工的工序按工序序号取最小未报工的 MesRoutingStep nextStep routingStepService.selectNextUnreportedStep(order.getRoutingId()); if (nextStep ! null) { // 获取工位负责人从mes_workstation关联sys_user Long responsibleUserId workstationService.getResponsibleUserId(nextStep.getWorkstationId()); String alertMsg String.format( ⚠️ 工单预警\n工单号%s\n产品%s\n已开工超2小时未报工\n当前卡点工序%s\n请立即处理, order.getOrderNo(), order.getProductCode(), nextStep.getStepOrder() ); weComAlertService.sendToUser(alertMsg, responsibleUserId); } } } }6.3 场景三用若依的“系统监控”页面实时展示设备OEE看板若依后台自带/monitor/server服务器监控页我们将其魔改为MES设备看板。在ruoyi-admin模块中新建/monitor/mes页面后端提供以下接口RestController RequestMapping(/monitor/mes) public class MesMonitorController { GetMapping(/oee-summary) public AjaxResult getOeeSummary() { // 查询各产线OEE可用率×性能率×合格率 ListMapString, Object oeeList monitorService.selectOeeByLine(); return AjaxResult.success(oeeList); } GetMapping(/equipment-status) public AjaxResult getEquipmentStatus() { // 查询设备实时状态RUNNING/STOPPED/OFFLINE ListMesEquipment equipments equipmentService.selectList( new LambdaQueryWrapperMesEquipment().select( MesEquipment::getEquipmentCode, MesEquipment::getEquipmentName, MesEquipment::getStatus, MesEquipment::getLastHeartbeat ) ); return AjaxResult.success(equipments); } }前端Vue页面用ECharts绘制产线OEE趋势图并用不同颜色圆点表示设备状态绿色RUNNING红色STOPPED灰色OFFLINE。这个页面不追求炫酷3D只要求班组长走进IT办公室一眼看清哪条线掉队、哪台设备趴窝——这才是车间需要的“监控”。我坚持一个习惯每周五下午关掉所有开发环境穿上工装去车间站30分钟。看操作员怎么扫二维码、怎么查报工记录、怎么跟班组长解释“为什么这台设备没数据”。那些在键盘上敲不出的Bug永远在油污的工位上等着你。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑