设备保养计划自动排程怎么实现?周期规则、浮动窗口与资源冲突的算法设计
2026/9/5 7:06:19 网站建设 项目流程

引言:为什么"每 30 天保养一次"做不对

很多团队觉得保养排程是个简单问题:每台设备一个周期,到日子生成工单,结束。

我们在第一个客户现场待了一周就发现这个认知有多天真:这家厂的注塑机保养计划里写着"每月 15 日保养",但 15 日可能是周日、可能是赶大货订单的产能高峰日、保养班组那天可能全部被派去支援另一车间。结果就是——纸面上的计划很整齐,实际执行一塌糊涂,没人觉得计划有问题,也没人按计划执行。

真实的保养排程是一个带日历约束和资源约束的调度问题。本文把它拆开讲清楚:怎么建模周期、怎么处理"法定节假日不保养"、怎么解决两个班组撞车。算法不复杂,但每一步都要贴着现场逻辑走。

一、问题抽象:排程 = 日历 × 周期 × 资源

先把整个问题形式化。一次排程要回答:

对设备集合 D 中的每台设备 d,按照它的保养周期规则 R,在未来 N 天的排产日历 C 上,找到执行时间点 t 和执行班组 g,满足:周期约束成立、t 不落在禁排日上、g 在 t 时刻有可用工时。

三个核心构件:

排产日历 C:工作日/节假日/客户自定义停机日(如月度盘点日) 周期规则 R:固定日历周期 | 累计量浮动周期 | 条件触发 资源池 G:班组(人员 × 技能 × 每日可用工时)

二、周期规则:两种模型,别混着用

2.1 固定日历周期

“每 30 天”“每月 15 日”“每季度首月第一周”——下一个保养日可以直接从日历推出来:

publicLocalDatenextDate(LocalDatelastDate,CycleRulerule,WorkCalendarcalendar){LocalDatecandidate=rule.advance(lastDate);// +30天 / 下月15日 / ...// 禁排日顺延:节假日、停机日往后找第一个可执行日while(calendar.isBlocked(candidate)){candidate=candidate.plusDays(rule.shiftPolicy()==SHIFT_NEXT?1:0);if(rule.shiftPolicy()==SHIFT_EARLIEST){/* 找窗口内最早可执行日 */}}returncandidate;}

顺延策略本身是个业务决策,必须在配置里显式化:**顺延(往后推)还是提前(往前挪)?最多顺延几天?**我们见过客户要求"最多顺延 3 天,超过 3 天视为本月放弃",也见过"只能提前不能推后"(药厂 GMP 场景)。没有唯一正确答案,只有可配置。

2.2 累计量浮动周期(容易被漏掉的模型)

“每运行 500 小时保养一次”——这才是旋转类设备的真实逻辑。它没法从日历直接推,需要用采集数据估算:

预计到达时点 = 今日 + (500 - 当前累计运行小时) / 日均运行小时

实现上有两个坑:

  1. 日均运行小时要用近期窗口算(如近 14 天),设备的开工强度是变的,用历史平均值会越排越歪。
  2. 估算到期日每天滚动更新,但工单只生成一次。用"首次进入触发窗口(如剩余 50 小时)"作为生成事件的触发条件,配合第一篇讲的bizKey幂等,保证估算漂移不会导致重复生成。

两类周期在系统里并存,设备台账上每个保养项绑定其中一种,绝不允许同一保养项同时配两种周期——我们真见过客户配了"每 30 天且每 500 小时",执行率统计直接乱套。

三、资源冲突:贪心 + 优先级,够用且可控

班组资源的约束是:每个班组每天有可执行工时上限,每个保养任务有预计工时。这是经典的装箱/调度问题,但B 端系统不需要最优解,需要"稳定、可解释、可人工微调"的解。我们用带优先级的贪心:

publicList<Assignment>schedule(List<Task>tasks,List<Crew>crews,WorkCalendarcal){// 1. 排序:逾期任务 > 即将逾期 > 重要度等级 > 设备价值List<Task>sorted=tasks.stream().sorted(Comparator.comparing(Task::urgencyRank).thenComparing(Comparator.comparing(Task::importance).reversed())).collect(Collectors.toList());List<Assignment>result=newArrayList<>();for(Taskt:sorted){// 2. 技能过滤 + 负载最轻优先(并列时选历史做过该设备的班组)Crewbest=crews.stream().filter(c->c.hasSkill(t.getRequiredSkill())).filter(c->cal.isWorkingDay(c,t.getTargetDate())).min(Comparator.comparingDouble(c->c.loadOn(t.getTargetDate())+c.familiarityPenalty(t))).orElse(null);if(best==null){t.markDeferred(findNextAvailableDay(t,cal));// 挤不进则顺延并标记}else{best.addLoad(t.getTargetDate(),t.getEstimatedHours());result.add(newAssignment(t,best,t.getTargetDate()));}}returnresult;}

两个必须交代的取舍:

  • 为什么不上运筹优化求解器?试过 OR-Tools,排出来的解确实更优,但客户调度员完全看不懂"为什么把我组的人排到隔壁车间",最后全被手工改掉。贪心的结果虽然次优,但每一单都符合人能理解的规则(技能匹配、负载均衡),被接受的概率高得多。排程算法在 B 端的价值在被接受,不在最优。
  • 人工微调是一等公民。系统排完只是"草案",调度员拖拽改派是常态,改派动作回写为下轮排程的固定约束。抢走调度员的控制权,系统就会被绕开。

四、排程结果的度量:达成率口径要先锁死

排程做得好不好,靠数据说话,但口径不统一,数据就是吵架工具。我们把三个口径写进了需求文档并让客户签字:

  1. 计划达成率= 按期完成工单 / 应执行计划(补录不计入);
  2. 准时率= 在周期窗口内完成的占比(顺延在允许天数内仍算准时);
  3. 工时利用率= 班组实际保养工时 / 可用工时。

上线后有个有意思的发现:某客户"计划达成率"从 68% 提到 93%,但设备故障率只降了一点。复盘发现原来的 68% 里包含大量"纸面完成",而 93% 是系统验证过的真实完成——数字变好的一部分其实是数据变真了,这个解释工作做在前面,客户对系统的信任会深得多。

五、踩坑记录

坑一:跨月周期边界。"每月 1 号"的保养在 12 月 31 日完成了,算 12 月的完成还是 1 月的?报表按"计划周期归属"统计,而不是按执行日期归属——这个决定需要在设计期明确。

**坑二:批量生成风暴。**2000 台设备同一天到期的计划在同一秒生成工单,把数据库写崩。方案:生成任务按设备 ID 分片错峰(与第一篇的军规三呼应),并在生成入口加限流。

**坑三:保养项之间的依赖。**某些保养项必须同时做(换油和换油滤),拆成两个独立工单后现场要跑两趟。后来支持"保养项组":组内项目打包成一张工单,排程时视为一个任务单元。

写在最后

保养排程的本质是把设备管理制度的节律翻译成可执行的日历和工单。算法上它不性感——贪心、顺延、装箱,没有一篇论文会写它;但工程上它极其敏感——一个边界条件没想清楚,客户现场的保养体系就会"系统性跑偏"。这类功能的正确投入方式是:多花时间在现场确认规则口径,少花时间在算法炫技。

下一篇回到数据层:设备台账、设备树与保养计划的数据库建模——所有这些业务逻辑的地基。

系列目录(持续更新)

  1. 设备保养工单系统开发实战:从计划自动生成到验收闭环的状态机设计
  2. 从 0 到 1 开发设备运维管理系统:整体架构设计与模块划分
  3. 设备数据采集协议怎么选?MQTT、Modbus、OPC UA 在运维场景的对比与落地
  4. 预测性维护不用深度学习?设备健康度评分的务实实现方案
  5. 用规则引擎实现可配置的设备告警策略:自研轻量引擎 vs Drools 落地对比
  6. 设备巡检系统开发实战:扫码打卡、离线缓存与防作弊的完整方案
  7. 设备保养计划自动排程怎么实现?周期规则、浮动窗口与资源冲突的算法设计(本文)

作者长期从事设备管理与售后运维方向的软件开发,主导过多个制造、物业机电现场的保养计划系统落地,欢迎在评论区交流排程算法与调度规则设计中的问题。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询