huang
2025-05-22 16b32f4511aa90b95b13a15751850cf6db0829e2
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
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
package com.mes.md.service.impl;
 
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mes.md.entity.RotatingRack;
import com.mes.md.mapper.RotatingRackMapper;
import com.mes.md.service.RotatingRackService;
import com.mes.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
 
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import com.fasterxml.jackson.databind.ObjectMapper;
 
@Service
public  class RotatingRackServiceImpl extends ServiceImpl<RotatingRackMapper, RotatingRack> implements RotatingRackService {
 
    private static final Logger log = LoggerFactory.getLogger(RotatingRackServiceImpl.class);
    private static final String BASE_API_URL = "http://10.3.58.110/api/Robot";
 
    @Autowired
    private RotatingRackMapper rotatingRackMapper;
 
    @Autowired
    private RestTemplate restTemplate;
 
    @Override
    public Result queryRackData(Map<String, String> params) {
        try {
            // 构建查询条件
            LambdaQueryWrapper<RotatingRack> queryWrapper = new LambdaQueryWrapper<>();
            
            // 根据日期范围查询
            if (StringUtils.hasText(params.get("fromDate"))) {
                // 将字符串转换为Date对象
                try {
                    String dateStr = params.get("fromDate").trim();
                    Date fromDate;
                    if (dateStr.contains("T")) {
                        // 处理ISO 8601格式
                        SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                        isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
                        fromDate = isoFormat.parse(dateStr);
                    } else {
                        // 处理普通格式
                        fromDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateStr);
                    }
                    queryWrapper.ge(RotatingRack::getStartDate, fromDate);
                } catch (ParseException e) {
                    log.error("日期解析错误: {}", e.getMessage());
                }
            }
 
            if (StringUtils.hasText(params.get("toDate"))) {
                try {
                    String dateStr = params.get("toDate").trim();
                    Date toDate;
                    if (dateStr.contains("T")) {
                        // 处理ISO 8601格式
                        SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                        isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
                        toDate = isoFormat.parse(dateStr);
                    } else {
                        // 处理普通格式
                        toDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateStr);
                    }
                    queryWrapper.le(RotatingRack::getEndDate, toDate);
                } catch (ParseException e) {
                    log.error("日期解析错误: {}", e.getMessage());
                }
            }
            
            // 根据机器人编号查询
            if (StringUtils.hasText(params.get("Arm_No"))) {
                queryWrapper.eq(RotatingRack::getRobotNo, params.get("Arm_No").trim());
            }
            
            // 根据交付订单号查询
            if (StringUtils.hasText(params.get("DO_NO"))) {
                queryWrapper.like(RotatingRack::getDoCode, params.get("DO_NO").trim());
            }
            
            // 只查询已完成的任务
            queryWrapper.eq(RotatingRack::getTaskStatus, 2);
            
            // 执行查询
            List<RotatingRack> results = rotatingRackMapper.selectList(queryWrapper);
            
            // 将实体转换为前端需要的数据格式
            List<Map<String, Object>> data = new ArrayList<>();
            for (RotatingRack rack : results) {
                Map<String, Object> record = new HashMap<>();
                record.put("ROBOT_NO", rack.getRobotNo());
                //record.put("RACK_NAME", rack.getRackName());                    // 料架名称
                record.put("DO_Code", rack.getDoCode());                        // DO编号
                record.put("SKU_CODE", rack.getSkuCode());                      // SKU编号
                record.put("GlassWeight", rack.getGlassWeight() + "KG");
                record.put("PCS", rack.getTargetPcs());
                //record.put("GlassWidth", rack.getWidth());
                //record.put("GlassHeight", rack.getHeight());
                //record.put("GlassThickness", rack.getThickness());
                SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
                record.put("StartDateTime", isoFormat.format(rack.getStartDate()));
                record.put("EndDateTime", isoFormat.format(rack.getEndDate()));
                record.put("Broken", rack.getBroken());
                record.put("SucessfullyCompleted", rack.getCompletedPcs());     // 成功完成数量
                record.put("ElectricityConsume", rack.getElectricityConsume());
                record.put("DownTime", rack.getDownTime());
                record.put("Operator_Name", rack.getOperatorName());
                data.add(record);
            }
            
            return Result.build(200, "Success", data);
        } catch (Exception e) {
            log.error("查询料架数据失败: {}", e.getMessage(), e);
            return Result.build(500, "Error: " + e.getMessage(), null);
        }
    }
 
    @Override
    public Result searchDO(String searchKey) {
        try {
            if (!StringUtils.hasText(searchKey)) {
                return Result.build(200, "Success", Collections.emptyList());
            }
 
            String url = BASE_API_URL + "/DOSearch?prefix=" + searchKey;
 
            try {
                log.info("发送DO搜索请求...");
                ResponseEntity<List<Map<String, Object>>> response = restTemplate.exchange(
                    url,
                    HttpMethod.GET,
                    null,
                    new ParameterizedTypeReference<List<Map<String, Object>>>() {}
                );
                
                if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                    return Result.build(200, "Success", response.getBody());
                } else {
                    log.warn("搜索DO返回空结果或非200状态码: {}", response.getStatusCode());
                    return Result.build(200, "Success", Collections.emptyList());
                }
            } catch (Exception e) {
                log.error("调用DO搜索API失败: {}", e.getMessage(), e);
                return Result.build(500, "调用DO搜索API失败: " + e.getMessage(), null);
            }
        } catch (Exception e) {
            log.error("搜索DO失败: {}", e.getMessage(), e);
            return Result.build(500, "Error: " + e.getMessage(), null);
        }
    }
 
    @Override
    public Result searchSKU(String searchKey) {
        try {
            if (!StringUtils.hasText(searchKey)) {
                return Result.build(200, "Success", Collections.emptyList());
            }
 
            String url = BASE_API_URL + "/FGSearch?prefix=" + searchKey;
 
            try {
                log.info("发送SKU搜索请求...");
                ResponseEntity<List<Map<String, Object>>> response = restTemplate.exchange(
                    url,
                    HttpMethod.GET,
                    null,
                    new ParameterizedTypeReference<List<Map<String, Object>>>() {}
                );
 
                if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                    return Result.build(200, "Success", response.getBody());
                } else {
                    log.warn("搜索SKU返回空结果或非200状态码: {}", response.getStatusCode());
                    return Result.build(200, "Success", Collections.emptyList());
                }
            } catch (Exception e) {
                log.error("调用SKU搜索API失败: {}", e.getMessage(), e);
                return Result.build(500, "调用SKU搜索API失败: " + e.getMessage(), null);
            }
        } catch (Exception e) {
            log.error("搜索SKU失败: {}", e.getMessage(), e);
            return Result.build(500, "Error: " + e.getMessage(), null);
        }
    }
 
    @Override
    public Long startTask(RotatingRack rotatingRack) {
 
        
        // 直接返回,不保存到数据库
        return rotatingRack.getId();
    }
 
    @Override
    public boolean completeTask(RotatingRack rotatingRack) {
        try {
            // 获取原任务信息并更新完成信息
            rotatingRack.setEndDate(new Date());
            rotatingRack.setTaskStatus(2); // 已完成
            rotatingRack.setDownTime(0);
            
            // 计算电力消耗:功率(12kW) * 运行时间(小时)
            long durationMs = rotatingRack.getEndDate().getTime() - rotatingRack.getStartDate().getTime();
            double durationHours = durationMs / (1000.0 * 60 * 60); // 转换为小时
            double electricityConsume = 12.0 * durationHours; // 12kW * 运行时间(小时)
            // 保留两位小数
            electricityConsume = Math.round(electricityConsume * 100.0) / 100.0;
            rotatingRack.setElectricityConsume(electricityConsume);
            
            rotatingRack.setErpSentStatus(0); // 初始化为未发送状态
 
            // 计算破损数量 = 目标数量 - 完成数量
            if (rotatingRack.getTargetPcs() != null && rotatingRack.getCompletedPcs() != null) {
                rotatingRack.setBroken(rotatingRack.getTargetPcs() - rotatingRack.getCompletedPcs());
                if (rotatingRack.getBroken() < 0) {
                    rotatingRack.setBroken(0);
                }
            }
 
            // 计算玻璃重量(根据宽度、高度、厚度计算)
            if (rotatingRack.getWidth() != null && rotatingRack.getHeight() != null && rotatingRack.getThickness() != null) {
                // 玻璃密度约为2.5g/cm³
                // 宽(cm) * 高(cm) * 厚(mm) / 10 = 体积(cm³)
                double volume = rotatingRack.getWidth() * rotatingRack.getHeight() * rotatingRack.getThickness() / 10.0;
                // 重量(kg) = 体积(cm³) * 密度(g/cm³) / 1000
                double weight = volume * 2.5 / 1000.0;
                // 保留两位小数
                weight = Math.round(weight * 100.0) / 100.0;
                rotatingRack.setGlassWeight(weight);
                log.info("料架{}玻璃重量: {}kg", rotatingRack.getRobotNo(), weight);
            }
 
            log.info("完成目标数量: {}", rotatingRack.getCompletedPcs());
            // 设置是否成功完成
            rotatingRack.setSuccessfullyCompleted(
                (rotatingRack.getBroken() != null && rotatingRack.getBroken() == 0) ? 1 : 0
            );
 
            // 准备发送到ERP的数据
            Map<String, Object> erpData = new HashMap<>();
            erpData.put("ROBOT_NO", rotatingRack.getRobotNo());
            erpData.put("DO_Code", rotatingRack.getDoCode());
            erpData.put("SKU_CODE", rotatingRack.getSkuCode());
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
            dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
            erpData.put("StartDateTime", dateFormat.format(rotatingRack.getStartDate()));
            erpData.put("EndDateTime", dateFormat.format(rotatingRack.getEndDate()));
            erpData.put("PCS", String.valueOf(rotatingRack.getCompletedPcs()));  // 转换为字符串
            erpData.put("Broken", rotatingRack.getBroken() != null && rotatingRack.getBroken() > 0 ? "True" : "False");  
            erpData.put("SuccessfullyCompleted", rotatingRack.getSuccessfullyCompleted() == 1 ? "True" : "False");  
            erpData.put("GlassWeight", String.valueOf(rotatingRack.getGlassWeight()));  
            erpData.put("Oparator_Name", rotatingRack.getOperatorName()); 
            erpData.put("ElectricityConsume", String.valueOf(rotatingRack.getElectricityConsume()));  // 转为字符串
            erpData.put("DownTime", rotatingRack.getDownTime() != null ? rotatingRack.getDownTime() : 0);  // 保持整数类型
 
            // 确保数据字段有效性,防止空值
            if (erpData.get("Oparator_Name") == null) {
                erpData.put("Oparator_Name", "TEST");
            }
            if (erpData.get("GlassWeight") == null) {
                erpData.put("GlassWeight", "0");
            }
            if (erpData.get("ElectricityConsume") == null) {
                erpData.put("ElectricityConsume", "0");
            }
            if (erpData.get("DownTime") == null) {
                erpData.put("DownTime", 0);
            }
 
            // 记录发送的数据,帮助调试
            log.info("准备发送数据到ERP:{}", erpData);
 
            // 尝试发送数据到ERP
            boolean erpSendSuccess = sendToERP(erpData);
 
            if (!erpSendSuccess) {
                // ERP发送失败,保存到本地数据库,并标记为发送失败
                log.warn("发送数据到ERP失败,任务数据保存到数据库。任务ID: {}", rotatingRack.getId());
                rotatingRack.setErpSentStatus(2); // 标记为发送失败
                rotatingRackMapper.insert(rotatingRack);
                return false;
            }
 
            // 发送成功,直接返回true,不保存到数据库
            return true;
        } catch (Exception e) {
            log.error("完成任务处理失败: {}", e.getMessage(), e);
            // 发生异常时保存到本地数据库
            try {
                rotatingRack.setErpSentStatus(2); // 标记为发送失败
                rotatingRackMapper.insert(rotatingRack);
                log.info("任务数据已保存到本地数据库。任务ID: {}", rotatingRack.getId());
            } catch (Exception dbEx) {
                log.error("保存到本地数据库也失败: {}", dbEx.getMessage(), dbEx);
            }
            return false;
        }
    }
 
    /**
     * 发送数据到ERP系统
     * @param data 要发送的数据
     * @return 是否发送成功
     */
    private boolean sendToERP(Map<String, Object> data) {
        try {
            // 设置API地址
            String erpUrl = "http://10.3.58.110/api/Robot/Insert";
 
 
            // 使用ObjectMapper手动序列化JSON
            ObjectMapper objectMapper = new ObjectMapper();
            String jsonData = objectMapper.writeValueAsString(data);
 
            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
 
            // 创建请求实体 - 直接使用JSON字符串
            HttpEntity<String> requestEntity = new HttpEntity<>(jsonData, headers);
 
            // 记录发送的数据,帮助调试
            //log.info("准备发送数据到ERP: {}", jsonData);
 
            // 发送POST请求
            ResponseEntity<String> response = restTemplate.postForEntity(erpUrl, requestEntity, String.class);
 
            // 检查响应状态码
            if (response.getStatusCode() == HttpStatus.OK) {
                //log.info("数据成功发送到ERP,响应内容:{}", response.getBody());
                return true;
            } else {
                log.error("ERP接口返回非成功状态码:{}, 响应内容: {}", response.getStatusCode(), response.getBody());
                return false;
            }
        }catch (HttpClientErrorException e) {
            try {
                // 尝试按UTF-8解码响应体
                String responseBody = new String(e.getResponseBodyAsByteArray(), StandardCharsets.UTF_8);
                log.error("发送数据到ERP失败,HTTP错误: {}, 响应状态: {}, 响应内容: {}",
                        e.getMessage(), e.getStatusCode(), responseBody, e);
            } catch (Exception ex) {
                log.error("发送数据到ERP失败,HTTP错误: {}, 响应状态: {}",
                        e.getMessage(), e.getStatusCode(), e);
            }
            return false;
        } catch (Exception e) {
            log.error("发送数据到ERP失败,未知错误: {}", e.getMessage(), e);
            return false;
        }
    }
 
    /**
     * 定时任务:每分钟检查一次未成功发送到ERP的数据,并尝试重新发送
     */
    @Scheduled(fixedRate = 60000) // 1分钟
    public void retryFailedErpSending() {
        log.info("开始执行定时任务:重试发送失败的数据到ERP");
        try {
            // 查询所有发送失败的数据
            LambdaQueryWrapper<RotatingRack> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(RotatingRack::getErpSentStatus, 2); // 查询发送失败的数据
            
            List<RotatingRack> failedRecords = rotatingRackMapper.selectList(queryWrapper);
            
            if (failedRecords.isEmpty()) {
                //log.info("没有需要重试发送的数据");
                return;
            }
            
            log.info("找到{}条发送失败的数据,开始重试发送", failedRecords.size());
            
            int successCount = 0;
            int failCount = 0;
            
            for (RotatingRack record : failedRecords) {
                // 准备发送到ERP的数据
                Map<String, Object> erpData = new HashMap<>();
                erpData.put("ROBOT_NO", record.getRobotNo());
                erpData.put("DO_Code", record.getDoCode());
                erpData.put("SKU_CODE", record.getSkuCode());
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
                erpData.put("StartDateTime", dateFormat.format(record.getStartDate()));
                erpData.put("EndDateTime", dateFormat.format(record.getEndDate()));
                erpData.put("PCS", String.valueOf(record.getCompletedPcs()));  
                erpData.put("Broken", record.getBroken() != null && record.getBroken() > 0 ? "True" : "False");  
                erpData.put("SuccessfullyCompleted", record.getSuccessfullyCompleted() == 1 ? "True" : "False"); 
                erpData.put("GlassWeight", String.valueOf(record.getGlassWeight())); 
                erpData.put("Oparator_Name", record.getOperatorName());  
                erpData.put("ElectricityConsume", String.valueOf(record.getElectricityConsume()));  // 转为字符串
                erpData.put("DownTime", record.getDownTime() != null ? record.getDownTime() : 0);  // 保持整数类型
                
                // 确保数据字段有效性,防止空值
                if (erpData.get("Oparator_Name") == null) {
                    erpData.put("Oparator_Name", "TEST");
                }
                if (erpData.get("GlassWeight") == null) {
                    erpData.put("GlassWeight", "0");
                }
                if (erpData.get("ElectricityConsume") == null) {
                    erpData.put("ElectricityConsume", "0");
                }
                if (erpData.get("DownTime") == null) {
                    erpData.put("DownTime", 0);
                }
                
                // 记录发送的数据
                log.info("准备重试发送数据到ERP,任务ID: {}, 数据: {}", record.getId(), erpData);
                
                // 尝试重新发送
                boolean sendSuccess = sendToERP(erpData);
                
                if (sendSuccess) {
                    // 发送成功,更新状态
                    record.setErpSentStatus(1);
                    rotatingRackMapper.updateById(record);
                    successCount++;
                    log.info("成功重试发送数据到ERP,任务ID: {}", record.getId());
                } else {
                    failCount++;
                    log.warn("重试发送数据到ERP失败,任务ID: {}", record.getId());
                }
            }
            
            log.info("定时任务执行完成,成功发送: {}条,失败: {}条", successCount, failCount);
        } catch (Exception e) {
            log.error("定时任务执行异常: {}", e.getMessage(), e);
        }
    }