简介:这份《精益生产运行管理平台(EW-APS)项目建议书》面向制造业信息化从业者、生产管理岗位人员及ERP/APS方向的学习者,围绕传统生产管理中信息孤岛、人工决策低效、库存与排程失衡等痛点,提出一套以精益生产理念为核心的企业级生产运行管理方案。文档从行业特点、存在问题与车间情景切入,依次展开设计思路、平台定位、功能需求、逻辑架构、SOA技术架构、技术选型及部署对接等内容,并附有功能清单与实施进度安排,涵盖生产计划、资源分配、实时监控、预警机制与数据报表等模块,可作为项目立项参考或方案撰写模板。资源包共1个docx文件,约2.24MB,结构完整、目录清晰,便于按章节检索与二次编辑。目前已有127人学习下载,适合需要了解APS系统设计思路、撰写项目建议书或进行生产管理系统选型的技术与管理读者参考。
1. 精益生产运行管理平台(EW-APS)到底在解决哪类排产难题
很多工厂上 MES 之后发现一个尴尬事:报工数据实时了,设备状态可视了,但计划排产还是靠 Excel 加微信群吼。计划员早上八点排好的机台顺序,十点因为一个急单全部推翻,下午两点又因为某台注塑机模具异常再改一遍。MES 管的是“已经发生的事”,而精益生产运行管理平台(EW-APS)要管的是“接下来该发生什么”。EW-APS 里的 APS 指高级计划排程,EW 通常是企业级工作流或工程工作台的缩写,合起来就是一套把精益思想落到排产动作上的运行管理系统。它适合年产值三千万以上、多品种小批量、设备瓶颈明显、计划员超过两个还天天加班的离散制造工厂。如果你正被“插单插到计划表成废纸”折磨,这套东西值得花二十分钟看完。
2. EW-APS 的排程内核与 MES 的边界怎么划
2.1 APS 排程引擎的四个输入维度
APS 不是魔法,它本质是一个带约束的搜索器。输入维度只有四类:订单维度(交期、优先级、工艺路线)、资源维度(机台、模具、人员、班次)、物料维度(齐套率、在途、安全库存)、规则维度(换型时间矩阵、批量约束、日历例外)。很多项目翻车是因为只喂了订单和机台,忽略了模具和换型矩阵,排出来的计划看着漂亮,到现场发现换模要四小时,计划只给了四十分钟。
精益生产在这里的体现是:把“换型时间”当作一等公民。SMED 快速换模的数据必须进系统,否则 APS 排出来的顺序会频繁触发长换型,反而制造了新的浪费。我一般会要求客户先整理一张换型矩阵表,行和列都是产品族,交叉格填分钟数,这张表的质量直接决定 APS 输出能不能用。
2.2 EW-APS 与 MES 的职责切分
MES 管执行层的“人机料法环”,EW-APS 管计划层的“顺序、时间、数量”。两者通过工单状态和报工回传形成闭环。常见做法是:EW-APS 生成排程结果后,按班次下发工单到 MES;MES 报工后把实际开始/结束时间回传,EW-APS 用这些实际数据滚动重排。边界不清的典型症状是:MES 里也能手工调顺序,EW-APS 里也能报工,两边数据打架,计划员不知道该信谁。
提示:EW-APS 与 MES 的集成接口至少要有三个:工单下发、报工回传、异常事件通知。少一个,闭环就断了。
2.3 基于若依框架搭建 EW-APS 的工程结构
热搜里“基于若依框架的 mes”热度很高,若依(RuoYi)是一套 Java 后台快速开发脚手架,很多中小工厂的 MES 就是基于它改的。EW-APS 完全可以复用同一套技术栈,降低运维成本。典型模块划分如下:
| 模块 | 职责 | 关键表 |
|---|---|---|
| 基础数据 | 物料、BOM、工艺路线、机台、模具 | md_material, md_routing |
| 排程引擎 | 约束解析、搜索、结果输出 | aps_constraint, aps_schedule |
| 工单管理 | 工单拆分、下发、状态跟踪 | aps_workorder |
| 集成接口 | 与 MES/ERP 数据交换 | int_log, int_mapping |
| 看板报表 | 甘特图、负荷图、达成率 | 视图或物化表 |
若依框架自带的代码生成器可以快速生成基础数据的增删改查,省掉大量重复劳动。排程引擎部分建议独立成一个 Spring Boot 服务,通过 REST 或消息队列与主应用通信,避免排程计算阻塞 Web 线程。
3. 从零跑通一个最小排程闭环的操作步骤
3.1 环境准备与若依框架初始化
假设你已经有 Java 8+、MySQL 5.7+、Redis 和 Maven。先拉取若依单体版或前后端分离版,初始化数据库。以下命令以若依前后端分离版为例:
# 克隆若依框架(使用官方仓库地址) git clone https://gitee.com/y_project/RuoYi-Vue.git ew-aps cd ew-aps # 创建数据库并导入脚本 mysql -uroot -p -e "CREATE DATABASE ew_aps DEFAULT CHARSET utf8mb4;" mysql -uroot -p ew_aps < sql/ry_20xx.sql # 修改数据库连接配置 vim ruoyi-admin/src/main/resources/application-druid.yml # 将 url 改为 jdbc:mysql://localhost:3306/ew_aps?useUnicode=true&characterEncoding=utf8 # username/password 改为你的实际值 # 启动 Redis(若未运行) redis-server /etc/redis/redis.conf # 编译并启动后端 mvn clean package -DskipTests java -jar ruoyi-admin/target/ruoyi-admin.jar逻辑说明:若依框架默认使用 Druid 连接池,配置文件里要同时改主库和从库(如果不用从库可注释掉)。启动后访问 8080 端口,默认账号 admin/admin123。这一步的目的是先让基础平台跑起来,后面所有 APS 模块都作为若依的插件式模块加入。
参数说明:-DskipTests跳过测试加速编译;Redis 用于缓存字典和会话,生产环境必须设置密码;MySQL 连接串里的serverTimezone建议设为 Asia/Shanghai,否则排程时间会差八小时。
3.2 建立 APS 核心表与换型矩阵
在若依的代码生成器里建表,或者直接执行 SQL。最小闭环需要四张表:
-- 机台资源表 CREATE TABLE aps_machine ( machine_id BIGINT PRIMARY KEY AUTO_INCREMENT, machine_code VARCHAR(32) NOT NULL, machine_name VARCHAR(64), capacity_per_hour DECIMAL(10,2) COMMENT '每小时产能', status TINYINT DEFAULT 1 COMMENT '1可用 0停用' ); -- 换型矩阵表:从产品族 A 换到 B 的分钟数 CREATE TABLE aps_changeover ( id BIGINT PRIMARY KEY AUTO_INCREMENT, from_family VARCHAR(32), to_family VARCHAR(32), minutes INT COMMENT '换型耗时分钟', UNIQUE KEY uk_from_to (from_family, to_family) ); -- 工单表 CREATE TABLE aps_workorder ( wo_id BIGINT PRIMARY KEY AUTO_INCREMENT, wo_no VARCHAR(32) NOT NULL, material_code VARCHAR(32), qty DECIMAL(12,2), due_date DATETIME, priority INT DEFAULT 5 COMMENT '1最高 9最低', family VARCHAR(32) COMMENT '产品族', status TINYINT DEFAULT 0 COMMENT '0待排 1已排 2生产中 3完工' ); -- 排程结果表 CREATE TABLE aps_schedule ( schedule_id BIGINT PRIMARY KEY AUTO_INCREMENT, wo_id BIGINT, machine_id BIGINT, seq INT COMMENT '机台内顺序', plan_start DATETIME, plan_end DATETIME, changeover_minutes INT DEFAULT 0 );逻辑说明:换型矩阵是 APS 排程质量的生命线。from_family和to_family相同表示不换型,填 0。实际项目中这张表往往有几百行,需要工艺工程师和车间主任一起确认。工单表的family字段必须填,否则排程时无法查换型时间。
参数说明:capacity_per_hour用于计算工单占用时长,公式是qty / capacity_per_hour * 60分钟;priority影响排程顺序,数字越小越优先;due_date是硬约束还是软约束取决于业务,我一般先设为软约束,允许少量逾期,否则容易无解。
3.3 写一个贪心排程器跑通闭环
先不追求最优解,用贪心算法按交期和优先级排序,逐工单分配到最早可用的机台上。以下是一个简化版 Java 方法:
/** * 贪心排程:按优先级和交期排序,依次分配到最早空闲机台 * @param workorders 待排工单列表 * @param machines 可用机台列表 * @param changeoverMap 换型矩阵,key为"from_to" * @return 排程结果列表 */ public List<ApsSchedule> greedySchedule(List<ApsWorkorder> workorders, List<ApsMachine> machines, Map<String, Integer> changeoverMap) { // 按优先级升序、交期升序排列 workorders.sort(Comparator.comparingInt(ApsWorkorder::getPriority) .thenComparing(ApsWorkorder::getDueDate)); // 记录每台机台的可用时间点和上一个产品族 Map<Long, LocalDateTime> machineFreeTime = new HashMap<>(); Map<Long, String> machineLastFamily = new HashMap<>(); for (ApsMachine m : machines) { machineFreeTime.put(m.getMachineId(), LocalDateTime.now()); machineLastFamily.put(m.getMachineId(), null); } List<ApsSchedule> result = new ArrayList<>(); for (ApsWorkorder wo : workorders) { Long bestMachine = null; LocalDateTime bestStart = null; int bestChangeover = 0; for (ApsMachine m : machines) { LocalDateTime free = machineFreeTime.get(m.getMachineId()); String lastFamily = machineLastFamily.get(m.getMachineId()); int changeover = 0; if (lastFamily != null && !lastFamily.equals(wo.getFamily())) { changeover = changeoverMap.getOrDefault(lastFamily + "_" + wo.getFamily(), 60); } LocalDateTime start = free.plusMinutes(changeover); if (bestStart == null || start.isBefore(bestStart)) { bestStart = start; bestMachine = m.getMachineId(); bestChangeover = changeover; } } // 计算加工时长 ApsMachine machine = machines.stream() .filter(m -> m.getMachineId().equals(bestMachine)).findFirst().get(); long processMinutes = (long) Math.ceil(wo.getQty() / machine.getCapacityPerHour() * 60); LocalDateTime end = bestStart.plusMinutes(processMinutes); ApsSchedule schedule = new ApsSchedule(); schedule.setWoId(wo.getWoId()); schedule.setMachineId(bestMachine); schedule.setPlanStart(bestStart); schedule.setPlanEnd(end); schedule.setChangeoverMinutes(bestChangeover); result.add(schedule); machineFreeTime.put(bestMachine, end); machineLastFamily.put(bestMachine, wo.getFamily()); } return result; }逻辑说明:这段代码的核心是“为每个工单找最早能开工的机台”。换型时间通过from_to键查表,查不到默认 60 分钟,这个默认值要根据实际数据调整。加工时长用qty / capacity_per_hour * 60计算,向上取整。排完后更新机台的可用时间和最后产品族,供下一个工单判断换型。
参数说明:changeoverMap的键建议用from + "_" + to格式,避免歧义;capacity_per_hour如果不同产品在同一机台上产能不同,需要把产能放到工艺路线表里,而不是机台表。贪心算法不保证全局最优,但能在毫秒级给出可行解,适合作为第一版上线。
3.4 把排程结果推给 MES 并接收报工回传
排程结果写入aps_schedule后,通过定时任务按班次下发到 MES。常见做法是调用 MES 的 REST 接口,或者写中间表由 MES 轮询。以下是一个下发逻辑的伪代码:
// 每天早八点下发当天排程 @Scheduled(cron = "0 0 8 * * ?") public void pushScheduleToMes() { List<ApsSchedule> todaySchedules = scheduleMapper.selectByDate(LocalDate.now()); for (ApsSchedule s : todaySchedules) { MesWorkOrderDto dto = new MesWorkOrderDto(); dto.setWoNo(workorderMapper.selectById(s.getWoId()).getWoNo()); dto.setMachineCode(machineMapper.selectById(s.getMachineId()).getMachineCode()); dto.setPlanStart(s.getPlanStart()); dto.setPlanEnd(s.getPlanEnd()); // 调用 MES 接口,失败写入重试表 try { mesClient.createWorkOrder(dto); } catch (Exception e) { retryMapper.insert(new RetryLog(s.getScheduleId(), e.getMessage())); } } }逻辑说明:下发失败必须落重试表,不能只打日志。MES 报工回传后,更新工单实际开始/结束时间,EW-APS 每天夜班结束后用实际数据重排第二天计划。这个滚动重排的节奏是精益生产里“持续改善”的体现。
参数说明:cron表达式根据工厂班次调整;重试表建议加retry_count字段,超过三次告警人工介入。
4. EW-APS 落地时最容易翻车的五个坑
4.1 换型矩阵拍脑袋填,排程结果现场不认
现象:系统排出的顺序在甘特图上看换型很少,但车间执行时发现换模要两小时,计划只给了二十分钟。原因:换型矩阵是计划员在办公室估的,没有经过工艺和车间确认。解决:上线前用秒表实测至少二十组换型,取平均值加 20% 安全余量;矩阵表由工艺工程师签字确认,后续每月回顾一次。
4.2 工单拆分粒度过粗,APS 排不动
现象:一个工单数量五千,交期三天,系统排出来占用机台连续四十小时,但机台每天只能跑十六小时。原因:工单没有按班次或按日拆分成子工单,APS 把工单当作不可中断的整体。解决:在工单下发前按“日产能”或“班次产能”自动拆分,拆分工单之间保留衔接关系。若依框架里可以用定时任务做拆分,拆分规则写在配置文件里。
4.3 与 MES 的时间基准不一致
现象:EW-APS 显示工单八点开始,MES 显示八点零三分,报表对不上。原因:两台服务器时区不同,或者一个用数据库时间一个用应用服务器时间。解决:统一用 NTP 校时,所有时间字段用LocalDateTime并明确时区为 Asia/Shanghai;接口传输用 ISO 8601 格式带时区偏移。
4.4 排程引擎无解时直接报错,没有降级方案
现象:某天急单太多,APS 跑出来空结果,计划员只能手工排。原因:硬约束太多,比如所有工单都必须按期完成,导致搜索空间为空。解决:设置约束优先级,交期设为软约束允许逾期,逾期工单在报表里标红;排程引擎超时时间设为 30 秒,超时返回当前最优可行解而不是报错。
4.5 若依框架的权限模型没适配 APS 角色
现象:计划员能看到所有机台数据,车间主任只能看自己车间,但若依默认的角色菜单权限太粗。原因:APS 需要按“工厂-车间-产线-机台”四级数据权限,若依自带的部门数据权限不够用。解决:在若依的数据权限注解基础上扩展,用自定义注解加 AOP 实现机台级别的过滤;或者简单点,在 SQL 里拼machine_id in (select ...)子查询。
5. 用滚动重排和达成率看板验证 EW-APS 是否真的有用
上线 EW-APS 之后,别急着看“排程速度提升了多少倍”,那个指标没意义。真正要盯的是两个数:计划达成率和滚动重排频率。计划达成率低于 85%,说明排程输入有问题,要么换型矩阵不准,要么产能数据虚高。滚动重排频率如果每天超过三次,说明现场异常太多,APS 在给异常擦屁股,这时候要先做精益改善而不是调算法。
我一般会在若依框架里加一个定时任务,每天凌晨两点用过去 24 小时的实际报工数据重排未来 48 小时计划,生成一版“滚动计划”和原计划做对比。对比看板用 ECharts 画甘特图,差异部分用红色标出。这个看板给计划员和车间主任每天早上开短会用,十五分钟过完异常和调整。
-- 计划达成率统计视图 CREATE VIEW v_plan_achievement AS SELECT DATE(s.plan_start) AS plan_date, m.machine_code, COUNT(*) AS total_wo, SUM(CASE WHEN w.status = 3 AND w.actual_end <= s.plan_end THEN 1 ELSE 0 END) AS on_time_wo, ROUND(SUM(CASE WHEN w.status = 3 AND w.actual_end <= s.plan_end THEN 1 ELSE 0 END) / COUNT(*) * 100, 2) AS achievement_rate FROM aps_schedule s JOIN aps_workorder w ON s.wo_id = w.wo_id JOIN aps_machine m ON s.machine_id = m.machine_id GROUP BY DATE(s.plan_start), m.machine_code;这个视图按天和机台统计达成率,低于 80% 的机台在报表里自动标黄。注意actual_end字段需要 MES 报工回传后更新,如果 MES 没有这个字段,先用plan_end代替,但达成率会虚高。
还有一个技巧:把换型时间实际值和矩阵预估值做对比,每周出一张偏差表。偏差超过 30% 的换型组合,安排工艺工程师去现场跟一次,更新矩阵。这个习惯坚持三个月,APS 的排程准确率会有肉眼可见的提升。我自己踩过的坑是:一开始贪图省事,换型矩阵直接抄了同行的一份,结果产品族定义都不一样,排出来的计划车间根本不认,返工了两周才把基础数据理清楚。希望帮到你。
本文还有配套的精品资源,点击获取