自动化立体仓库 - WMS系统
chen.llin
1 天以前 d7020a8f1ec6f55167b4ad14941de0e28ce3d8c1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
package com.zy.asrs.task;
 
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.core.common.Cools;
import com.zy.asrs.entity.Task;
import com.zy.asrs.entity.WrkMast;
import com.zy.asrs.mapper.WrkMastMapper;
import com.zy.asrs.entity.WrkMastLog;
import com.zy.asrs.service.TaskService;
import com.zy.asrs.service.WrkMastLogService;
import com.zy.asrs.service.WrkMastService;
import com.zy.asrs.task.handler.AgvHandler;
import com.zy.common.properties.SchedulerProperties;
import com.zy.system.entity.Config;
import com.zy.system.service.ConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
 
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
 
/**
 * @author pang.jiabao
 * @description AGV交互相关定时任务
 * @createDate 2025/11/18 14:18
 */
@Slf4j
@Component
public class AgvScheduler {
 
    @Resource
    private ConfigService configService;
 
    @Resource
    private AgvHandler agvHandler;
 
    @Resource
    private TaskService taskService;
 
    @Resource
    private WrkMastMapper wrkMastMapper;
 
    @Resource
    private WrkMastService wrkMastService;
 
    @Resource
    private WrkMastLogService wrkMastLogService;
 
    @Resource
    private SchedulerProperties schedulerProperties;
 
    /**
     * 呼叫agv搬运
     */
    @Scheduled(cron = "0/5 * * * * ? ")
    private void callAgv() {
        if (!schedulerProperties.isEnabled()) {
            return;
        }
        // 查询待呼叫agv任务,按id升序排序(id最小的优先呼叫)
        List<Task> taskList = taskService.selectList(
            new EntityWrapper<Task>()
                .eq("wrk_sts", 7)
                .orderBy("id", true) // 按id升序,id最小的优先
        );
        if(taskList.isEmpty()) {
            return;
        }
        agvHandler.callAgv(taskList);
    }
 
    /**
     * 货物到达出库口,生成agv任务
     */
    @Scheduled(cron = "0/3 * * * * ? ")
    private void createAgvOutTasks() {
        if (!schedulerProperties.isEnabled()) {
            return;
        }
 
        // 获取呼叫agv配置
        List<Config> configs = configService.selectList(new EntityWrapper<Config>().in("code", "eastCallAgvControl", "westCallAgvControl").eq("status", 1));
        if(configs.isEmpty()) {
            return;
        }
 
        // 获取agv出库可用站点
        List<String> sites = new ArrayList<>();
        for(Config config: configs) {
            String value = config.getValue();
            if(Cools.isEmpty(value)) {
                continue;
            }
            String[] split = value.split(";");
            sites.addAll(Arrays.asList(split));
        }
 
        if(sites.isEmpty()) {
            return;
        }
 
        agvHandler.createAgvOutTasks(sites);
    }
 
    /**
     * 任务完成转历史
     */
    @Scheduled(cron = "0/10 * * * * ? ")
    private void moveTaskToHistory() {
        if (!schedulerProperties.isEnabled()) {
            return;
        }
        List<Task> taskList = taskService.selectList(new EntityWrapper<Task>().eq("wrk_sts", 9));
        if(taskList.isEmpty()) {
            return;
        }
        agvHandler.moveTaskToHistory(taskList);
    }
 
    /**
     * 检查入库成功的任务,完结对应的AGV呼叫单
     * 如果入库任务呼叫AGV后没有收到回调,但工作档已经入库成功,则完结AGV呼叫单
     */
    @Scheduled(cron = "0/10 * * * * ? ")
    private void checkInboundCompletedTasks() {
        if (!schedulerProperties.isEnabled()) {
            return;
        }
        try {
            // 查询入库成功的工作档(状态4:入库完成,入库类型:1,10,53,57)
            List<WrkMast> completedWrkMasts = wrkMastService.selectList(
                new EntityWrapper<WrkMast>()
                    .eq("wrk_sts", 4L)  // 入库完成
                    .in("io_type", 1, 10, 53, 57)  // 入库类型
                    .isNotNull("wrk_no")
            );
            
            if (completedWrkMasts.isEmpty()) {
                return;
            }
            
            Date now = new Date();
            int completedCount = 0;
            
            for (WrkMast wrkMast : completedWrkMasts) {
                // 查找对应的AGV任务(优先通过wrk_no查询)
                Wrapper<Task> taskWrapper1 = new EntityWrapper<Task>()
                    .eq("task_type", "agv")
                    .eq("wrk_sts", 8L)  // 已呼叫AGV状态
                    .eq("wrk_no", wrkMast.getWrkNo());
                List<Task> agvTasks = taskService.selectList(taskWrapper1);
                
                // 如果通过wrk_no没找到,且有条码,则通过条码查询
                if (agvTasks.isEmpty() && !Cools.isEmpty(wrkMast.getBarcode())) {
                    Wrapper<Task> taskWrapper2 = new EntityWrapper<Task>()
                        .eq("task_type", "agv")
                        .eq("wrk_sts", 8L)
                        .eq("barcode", wrkMast.getBarcode());
                    agvTasks = taskService.selectList(taskWrapper2);
                }
                
                for (Task agvTask : agvTasks) {
                    // 确保是入库任务
                    if (agvTask.getIoType() != null && 
                        (agvTask.getIoType() == 1 || agvTask.getIoType() == 10 || 
                         agvTask.getIoType() == 53 || agvTask.getIoType() == 57)) {
                        // 更新AGV任务状态为完成
                        agvTask.setWrkSts(9L);
                        agvTask.setModiTime(now);
                        if (taskService.updateById(agvTask)) {
                            completedCount++;
                            log.info("入库任务工作档已入库成功,完结AGV呼叫单,taskId:{},wrkNo:{},barcode:{}", 
                                agvTask.getId(), wrkMast.getWrkNo(), wrkMast.getBarcode());
                        }
                    }
                }
            }
            
            if (completedCount > 0) {
                log.info("本次检查完结了{}个入库AGV呼叫单", completedCount);
            }
        } catch (Exception e) {
            log.error("检查入库成功任务并完结AGV呼叫单异常", e);
        }
    }
 
    /**
     * 检查AGV任务对应的工作档是否已完成或已转历史档并完结
     * 处理被跳过的AGV任务:如果工作档已完成(wrk_sts=4,5,14,15)或已转历史档并完结,则完结AGV任务
     */
    @Scheduled(cron = "0/10 * * * * ? ")
    private void checkCompletedTasksInHistory() {
        if (!schedulerProperties.isEnabled()) {
            return;
        }
        try {
            // 查询状态为8(已呼叫AGV)的AGV任务
            List<Task> agvTasks = taskService.selectList(
                new EntityWrapper<Task>()
                    .eq("task_type", "agv")
                    .eq("wrk_sts", 8L)  // 已呼叫AGV状态
                    .isNotNull("wrk_no")
            );
            
            if (agvTasks.isEmpty()) {
                return;
            }
            
            Date now = new Date();
            int completedCount = 0;
            
            for (Task agvTask : agvTasks) {
                boolean isCompleted = false;
                String reason = "";
                
                // 检查工作档是否存在
                WrkMast wrkMast = null;
                if (agvTask.getWrkNo() != null) {
                    wrkMast = wrkMastService.selectOne(
                        new EntityWrapper<WrkMast>().eq("wrk_no", agvTask.getWrkNo())
                    );
                }
                
                // 如果工作档存在,检查是否已完成
                if (wrkMast != null) {
                    Long wrkSts = wrkMast.getWrkSts();
                    Integer ioType = agvTask.getIoType();
                    
                    if (wrkSts != null && ioType != null) {
                        // 入库任务:状态4(入库完成)或5(库存更新完成)
                        if ((ioType == 1 || ioType == 10 || ioType == 53 || ioType == 57) &&
                            (wrkSts == 4L || wrkSts == 5L)) {
                            isCompleted = true;
                            reason = String.format("工作档已完成,状态:%d", wrkSts);
                        }
                        // 出库任务:状态14(已出库未确认)或15(出库更新完成)
                        else if ((ioType == 101 || ioType == 110 || ioType == 103 || ioType == 107) &&
                                 (wrkSts == 14L || wrkSts == 15L)) {
                            isCompleted = true;
                            reason = String.format("工作档已完成,状态:%d", wrkSts);
                        }
                    }
                } else {
                    // 如果工作档不存在,检查历史档
                    WrkMastLog wrkMastLog = null;
                    
                    // 优先通过wrk_no查询历史档
                    if (agvTask.getWrkNo() != null) {
                        wrkMastLog = wrkMastLogService.selectOne(
                            new EntityWrapper<WrkMastLog>().eq("wrk_no", agvTask.getWrkNo())
                        );
                    }
                    
                    // 如果通过wrk_no没找到,且有条码,则通过条码查询
                    if (wrkMastLog == null && !Cools.isEmpty(agvTask.getBarcode())) {
                        List<WrkMastLog> logList = wrkMastLogService.selectList(
                            new EntityWrapper<WrkMastLog>().eq("barcode", agvTask.getBarcode())
                        );
                        if (!logList.isEmpty()) {
                            wrkMastLog = logList.get(0); // 取第一个
                        }
                    }
                    
                    // 如果历史档存在且已完结,则完结AGV任务
                    if (wrkMastLog != null) {
                        Integer ioType = agvTask.getIoType();
                        long logWrkSts = wrkMastLog.getWrkSts();
                        
                        if (ioType != null) {
                            // 入库任务:状态5(库存更新完成)
                            if ((ioType == 1 || ioType == 10 || ioType == 53 || ioType == 57) &&
                                logWrkSts == 5L) {
                                isCompleted = true;
                                reason = String.format("工作档已转历史档并完结,历史档状态:%d", logWrkSts);
                            }
                            // 出库任务:状态15(出库更新完成)
                            else if ((ioType == 101 || ioType == 110 || ioType == 103 || ioType == 107) &&
                                     logWrkSts == 15L) {
                                isCompleted = true;
                                reason = String.format("工作档已转历史档并完结,历史档状态:%d", logWrkSts);
                            }
                        }
                    }
                }
                
                // 如果已完成,更新AGV任务状态
                if (isCompleted) {
                    agvTask.setWrkSts(9L);
                    agvTask.setModiTime(now);
                    if (taskService.updateById(agvTask)) {
                        completedCount++;
                        log.info("{},完结AGV呼叫单,taskId:{},wrkNo:{},barcode:{},站点:{}", 
                            reason, agvTask.getId(), agvTask.getWrkNo(), agvTask.getBarcode(), agvTask.getStaNo());
                    }
                }
            }
            
            if (completedCount > 0) {
                log.info("本次检查完结了{}个AGV呼叫单(工作档已完成或已转历史档)", completedCount);
            }
        } catch (Exception e) {
            log.error("检查工作档已完成或历史档完结任务并完结AGV呼叫单异常", e);
        }
    }
 
}