huminmin
3 天以前 cc9e229da3a5d06be13e9ade5b5254d403f47c57
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
446
447
448
449
450
451
452
453
454
455
456
457
458
package com.ruoyi.production.service.impl;
 
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.basic.mapper.ProductMapper;
import com.ruoyi.basic.mapper.ProductModelMapper;
import com.ruoyi.basic.mapper.SupplierManageMapper;
import com.ruoyi.basic.pojo.Product;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.basic.pojo.SupplierManage;
import com.ruoyi.home.dto.processDataProductionStatisticsDto;
import com.ruoyi.production.dto.ProductionStatisticDto;
import com.ruoyi.production.mapper.ProductProcessMapper;
import com.ruoyi.production.mapper.ProductWorkOrderMapper;
import com.ruoyi.production.mapper.ProductionProductInputMapper;
import com.ruoyi.production.mapper.ProductionProductOutputMapper;
import com.ruoyi.production.pojo.ProductProcess;
import com.ruoyi.production.pojo.ProductWorkOrder;
import com.ruoyi.production.pojo.ProductionProductInput;
import com.ruoyi.production.pojo.ProductionProductOutput;
import com.ruoyi.production.service.ProductionStatisticService;
import com.ruoyi.quality.mapper.QualityInspectMapper;
import com.ruoyi.quality.pojo.QualityInspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.YearMonth;
import java.time.ZoneId;
import java.util.Date;
import java.util.Set;
import java.util.TreeSet;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
/**
 * 生产统计服务实现类
 */
@Service
public class ProductionStatisticServiceImpl implements ProductionStatisticService {
 
    @Autowired
    private ProductProcessMapper productProcessMapper;
 
    @Autowired
    private ProductWorkOrderMapper productWorkOrderMapper;
 
    @Autowired
    private ProductionProductOutputMapper productionProductOutputMapper;
 
    @Autowired
    private ProductionProductInputMapper productionProductInputMapper;
 
    @Autowired
    private QualityInspectMapper qualityInspectMapper;
 
    @Autowired
    private SupplierManageMapper supplierManageMapper;
 
    @Autowired
    private ProductModelMapper productModelMapper;
 
    @Autowired
    private ProductMapper productMapper;
 
    @Override
    public ProductionStatisticDto getWorkOrderCount() {
        ProductionStatisticDto dto = new ProductionStatisticDto();
 
        // 查询工单总数
        Long totalCount = productWorkOrderMapper.selectCount(null);
        dto.setTotalCount(totalCount);
 
        // 查询进行中工单(完成数量小于需求数量)
        Long inProgressCount = productWorkOrderMapper.selectCount(
                new LambdaQueryWrapper<ProductWorkOrder>()
                        .apply("complete_quantity < plan_quantity and complete_quantity > 0")
        );
        dto.setInProgressCount(inProgressCount);
 
        // 查询已完成工单(完成数量大于等于需求数量)
        Long completedCount = productWorkOrderMapper.selectCount(
                new LambdaQueryWrapper<ProductWorkOrder>()
                        .apply("complete_quantity >= plan_quantity and complete_quantity > 0")
        );
        dto.setCompletedCount(completedCount);
 
        // 查询待完成工单(完成数量为0)
        Long pendingCount = productWorkOrderMapper.selectCount(
                new LambdaQueryWrapper<ProductWorkOrder>()
                        .eq(ProductWorkOrder::getCompleteQuantity, 0)
        );
        dto.setPendingCount(pendingCount);
 
        return dto;
    }
 
    @Override
    public Map<String, Object> getQualityStatistics() {
        Map<String, Object> result = new HashMap<>();
        
        // 查询所有报工记录
        List<ProductionProductOutput> outputList = productionProductOutputMapper.selectList(null);
        
        // 计算报工总数、报废总数和不良总数
        BigDecimal totalOutput = BigDecimal.ZERO;
        BigDecimal totalScrap = BigDecimal.ZERO;
        BigDecimal totalDefect = BigDecimal.ZERO;
        
        for (ProductionProductOutput output : outputList) {
            // 报工总数
            if (output.getQuantity() != null) {
                totalOutput = totalOutput.add(output.getQuantity());
            }
            // 报废数量
            if (output.getScrapQty() != null) {
                totalScrap = totalScrap.add(output.getScrapQty());
            }
            // 不良数量(从QualityInspect表查询)
            List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(
                    new LambdaQueryWrapper<QualityInspect>()
                            .eq(QualityInspect::getProductMainId, output.getProductMainId())
            );
            for (QualityInspect inspect : qualityInspects) {
                if (inspect.getDefectiveQuantity() != null) {
                    totalDefect = totalDefect.add(inspect.getDefectiveQuantity());
                }
            }
        }
        
        // 计算合格数量
        BigDecimal qualifiedQuantity = totalOutput.subtract(totalScrap).subtract(totalDefect);
        
        // 计算合格率和不良率
        double qualifiedRate = 0.0;
        double defectRate = 0.0;
        if (totalOutput.compareTo(BigDecimal.ZERO) > 0) {
            // 使用BigDecimal确保精度
            BigDecimal qualifiedRateBD = qualifiedQuantity.divide(totalOutput, 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
            BigDecimal defectRateBD = totalDefect.divide(totalOutput, 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
            // 保留两位小数
            qualifiedRate = qualifiedRateBD.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            defectRate = defectRateBD.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        }
        
        result.put("qualifiedRate", qualifiedRate); // 合格率
        result.put("defectRate", defectRate); // 不良率
        result.put("scrapCount", totalScrap.intValue()); // 报废总数
 
        return result;
    }
 
    @Override
    public Map<String, Object> getProductionStatistics() {
        Map<String, Object> result = new HashMap<>();
        
        // 获取当前月份和上一个月份的开始和结束时间
        LocalDateTime now = LocalDateTime.now();
        YearMonth currentMonth = YearMonth.from(now);
        LocalDateTime currentMonthStart = now.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
        LocalDateTime currentMonthEnd =  currentMonth.atEndOfMonth().atTime(23, 59, 59);
        LocalDateTime lastMonth = now.minusMonths(1);
        LocalDateTime lastMonthStart = lastMonth.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
        LocalDateTime lastMonthEnd = currentMonthStart.minusDays(1).withHour(23).withMinute(59).withSecond(59);
 
        // 计算生产总产出(当前月)
        List<ProductionProductOutput> currentOutputList = productionProductOutputMapper.selectList(
                new LambdaQueryWrapper<ProductionProductOutput>()
                        .ge(ProductionProductOutput::getCreateTime, currentMonthStart)
                        .le(ProductionProductOutput::getCreateTime, currentMonthEnd)
        );
        BigDecimal currentProductionOutput = BigDecimal.ZERO;
        for (ProductionProductOutput output : currentOutputList) {
            if (output.getQuantity() != null) {
                currentProductionOutput = currentProductionOutput.add(output.getQuantity());
            }
        }
        
        // 计算生产总产出(上月)
        List<ProductionProductOutput> lastOutputList = productionProductOutputMapper.selectList(
                new LambdaQueryWrapper<ProductionProductOutput>()
                        .ge(ProductionProductOutput::getCreateTime, lastMonthStart)
                        .le(ProductionProductOutput::getCreateTime, lastMonthEnd)
        );
        BigDecimal lastProductionOutput = BigDecimal.ZERO;
        for (ProductionProductOutput output : lastOutputList) {
            if (output.getQuantity() != null) {
                lastProductionOutput = lastProductionOutput.add(output.getQuantity());
            }
        }
        
        // 计算生产总消耗(当前月)
        List<ProductionProductInput> currentInputList = productionProductInputMapper.selectList(
                new LambdaQueryWrapper<ProductionProductInput>()
                        .ge(ProductionProductInput::getCreateTime, currentMonthStart)
                        .le(ProductionProductInput::getCreateTime, currentMonthEnd)
        );
        BigDecimal currentProductionConsumption = BigDecimal.ZERO;
        for (ProductionProductInput input : currentInputList) {
            if (input.getQuantity() != null) {
                currentProductionConsumption = currentProductionConsumption.add(input.getQuantity());
            }
        }
        
        // 计算生产总消耗(上月)
        List<ProductionProductInput> lastInputList = productionProductInputMapper.selectList(
                new LambdaQueryWrapper<ProductionProductInput>()
                        .ge(ProductionProductInput::getCreateTime, lastMonthStart)
                        .le(ProductionProductInput::getCreateTime, lastMonthEnd)
        );
        BigDecimal lastProductionConsumption = BigDecimal.ZERO;
        for (ProductionProductInput input : lastInputList) {
            if (input.getQuantity() != null) {
                lastProductionConsumption = lastProductionConsumption.add(input.getQuantity());
            }
        }
        
        // 计算供应商数量(当前月)
        List<SupplierManage> currentSuppliers = supplierManageMapper.selectList(
                new LambdaQueryWrapper<SupplierManage>()
                        .ge(SupplierManage::getCreateTime, currentMonthStart)
                        .le(SupplierManage::getCreateTime, currentMonthEnd)
        );
        int currentSupplierCount = currentSuppliers != null ? currentSuppliers.size() : 0;
        
        // 计算供应商数量(上月)
        List<SupplierManage> lastSuppliers = supplierManageMapper.selectList(
                new LambdaQueryWrapper<SupplierManage>()
                        .ge(SupplierManage::getCreateTime, lastMonthStart)
                        .le(SupplierManage::getCreateTime, lastMonthEnd)
        );
        int lastSupplierCount = lastSuppliers != null ? lastSuppliers.size() : 0;
        
        // 计算趋势
        double productionOutputMonthlyChange = 0.0;
        if (lastProductionOutput.compareTo(BigDecimal.ZERO) > 0) {
            productionOutputMonthlyChange = (currentProductionOutput.subtract(lastProductionOutput)
                    .divide(lastProductionOutput, 4, BigDecimal.ROUND_HALF_UP).doubleValue()) * 100;
        }
        
        double productionConsumptionMonthlyChange = 0.0;
        if (lastProductionConsumption.compareTo(BigDecimal.ZERO) > 0) {
            productionConsumptionMonthlyChange = (currentProductionConsumption.subtract(lastProductionConsumption)
                    .divide(lastProductionConsumption, 4, BigDecimal.ROUND_HALF_UP).doubleValue()) * 100;
        }
        
        double supplierCountMonthlyChange = 0.0;
        if (lastSupplierCount > 0) {
            supplierCountMonthlyChange = ((currentSupplierCount - lastSupplierCount) * 100.0) / lastSupplierCount;
        }
        
        result.put("productionOutput", currentProductionOutput.doubleValue()); // 生产总产
        result.put("productionConsumption", currentProductionConsumption.doubleValue()); // 生产总消耗
        result.put("productionOutputMonthlyChange", productionOutputMonthlyChange); // 生产总产月度变化
        result.put("productionConsumptionMonthlyChange", productionConsumptionMonthlyChange); // 生产总消耗月度变化
        result.put("supplierCount", currentSupplierCount); // 产品总供应公司
        result.put("supplierCountMonthlyChange", supplierCountMonthlyChange); // 供应商数量月度变化
        
        return result;
    }
 
    @Override
    public List<Map<String, Object>> getProductOutputCategoryPieData() {
        List<Map<String, Object>> result = new ArrayList<>();
        // 按产品大类
        // 查询所有报工记录
        List<ProductionProductOutput> outputList = productionProductOutputMapper.selectList(null);
 
        // 按产品分组计算产出数量
        Map<Long, BigDecimal> productOutputMap = new HashMap<>();
 
        for (ProductionProductOutput output : outputList) {
            if (output.getProductModelId() != null && output.getQuantity() != null) {
                // 根据productModelId查询ProductModel
                ProductModel productModel = productModelMapper.selectById(output.getProductModelId());
                if (productModel != null && productModel.getProductId() != null) {
                    // 根据productId查询Product
                    Product product = productMapper.selectById(productModel.getProductId());
                    if (product != null) {
                        // 按产品ID分组计算产出数量
                        productOutputMap.put(product.getId(),
                            productOutputMap.getOrDefault(product.getId(), BigDecimal.ZERO).add(output.getQuantity()));
                    }
                }
            }
        }
 
        // 转换为结果格式
        for (Map.Entry<Long, BigDecimal> entry : productOutputMap.entrySet()) {
            Product product = productMapper.selectById(entry.getKey());
            if (product != null) {
                Map<String, Object> item = new HashMap<>();
                item.put("name", product.getProductName());
                item.put("value", entry.getValue().intValue());
                result.add(item);
            }
        }
 
        return result;
    }
 
    @Override
    public List<Map<String, Object>> getDefectReasonAnalysis() {
        List<Map<String, Object>> result = new ArrayList<>();
        
        // 查询所有质量检验记录
        List<QualityInspect> qualityInspectList = qualityInspectMapper.selectList(null);
        
        // 按不良原因分组统计数量
        Map<String, Integer> reasonCountMap = new HashMap<>();
        
        for (QualityInspect inspect : qualityInspectList) {
            if (inspect.getDefectiveReason() != null && !inspect.getDefectiveReason().isEmpty()) {
                String reason = inspect.getDefectiveReason();
                reasonCountMap.put(reason, reasonCountMap.getOrDefault(reason, 0) + 1);
            }
        }
        
        // 转换为结果格式
        for (Map.Entry<String, Integer> entry : reasonCountMap.entrySet()) {
            Map<String, Object> item = new HashMap<>();
            item.put("name", entry.getKey());
            item.put("value", entry.getValue());
            result.add(item);
        }
        
        return result;
    }
 
    @Override
    public List<Map<String, Object>> getProcessDefectRateAnalysis(String startDate, String endDate) {
        List<Map<String, Object>> result = new ArrayList<>();
        
        // 默认查询近一个月数据
        if (startDate == null || endDate == null) {
            LocalDate now = LocalDate.now();
            startDate = now.minusMonths(1).toString();
            endDate = now.toString();
        }
        
        // 解析日期
        LocalDate startLocalDate = LocalDate.parse(startDate);
        LocalDate endLocalDate = LocalDate.parse(endDate);
        Date start = Date.from(startLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
        Date end = Date.from(endLocalDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
 
        // 查询所有工序
        List<ProductProcess> processList = productProcessMapper.selectList(null);
        
        // 收集所有日期
        Set<LocalDate> dateSet = new TreeSet<>();
        LocalDate currentDate = startLocalDate;
        while (!currentDate.isAfter(endLocalDate)) {
            dateSet.add(currentDate);
            currentDate = currentDate.plusDays(1);
        }
        
        // 一次性查询所有日期范围内的质量检验记录
        List<QualityInspect> allQualityInspects = qualityInspectMapper.selectList(
                new LambdaQueryWrapper<QualityInspect>()
                        .ge(QualityInspect::getCheckTime, start)
                        .lt(QualityInspect::getCheckTime, end)
        );
        
        // 按日期和工序分组处理数据
        Map<LocalDate, Map<String, BigDecimal[]>> dateProcessMap = new HashMap<>();
        
        for (QualityInspect inspect : allQualityInspects) {
            if (inspect.getCheckTime() != null && inspect.getProcess() != null) {
                // 转换检查时间为LocalDate
                LocalDate inspectDate = inspect.getCheckTime().toInstant()
                        .atZone(ZoneId.systemDefault()).toLocalDate();
                
                // 确保日期在查询范围内
                if (dateSet.contains(inspectDate)) {
                    String processName = inspect.getProcess();
                    
                    // 初始化日期和工序数据
                    dateProcessMap.computeIfAbsent(inspectDate, k -> new HashMap<>());
                    BigDecimal[] quantities = dateProcessMap.get(inspectDate)
                            .computeIfAbsent(processName, k -> new BigDecimal[]{BigDecimal.ZERO, BigDecimal.ZERO});
                    
                    // 累加数量
                    if (inspect.getQuantity() != null) {
                        quantities[0] = quantities[0].add(inspect.getQuantity());
                    }
                    if (inspect.getDefectiveQuantity() != null) {
                        quantities[1] = quantities[1].add(inspect.getDefectiveQuantity());
                    }
                }
            }
        }
        
        // 构建结果数据
        for (LocalDate date : dateSet) {
            Map<String, Object> item = new HashMap<>();
            item.put("date", date.toString());
            
            // 初始化每日总数量和不良数量
            BigDecimal dailyTotalQuantity = BigDecimal.ZERO;
            BigDecimal dailyDefectiveQuantity = BigDecimal.ZERO;
            
            // 初始化工序数据列表
            List<Map<String, Object>> processesList = new ArrayList<>();
            
            // 获取该日期的工序数据
            Map<String, BigDecimal[]> processData = dateProcessMap.getOrDefault(date, new HashMap<>());
            
            for (ProductProcess process : processList) {
                if (process.getName() != null) {
                    String processName = process.getName();
                    BigDecimal[] quantities = processData.getOrDefault(processName, new BigDecimal[]{BigDecimal.ZERO, BigDecimal.ZERO});
                    
                    BigDecimal processTotalQuantity = quantities[0];
                    BigDecimal processDefectiveQuantity = quantities[1];
                    
                    // 累加每日总数量
                    dailyTotalQuantity = dailyTotalQuantity.add(processTotalQuantity);
                    dailyDefectiveQuantity = dailyDefectiveQuantity.add(processDefectiveQuantity);
                    
                    // 计算该工序的不良率
                    double processDefectRate = 0.0;
                    if (processTotalQuantity.compareTo(BigDecimal.ZERO) > 0) {
                        // 计算不良率,保留两位小数
                        BigDecimal defectRateDecimal = processDefectiveQuantity.divide(processTotalQuantity, 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
                        processDefectRate = defectRateDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                    }
                    
                    // 构建工序数据对象
                    Map<String, Object> processMap = new HashMap<>();
                    processMap.put(process.getName(), processDefectRate);
                    processesList.add(processMap);
                }
            }
            
            // 计算每日平均不良率
            double dailyAverageDefectRate = 0.0;
            if (dailyTotalQuantity.compareTo(BigDecimal.ZERO) > 0) {
                // 计算不良率,保留两位小数
                BigDecimal defectRateDecimal = dailyDefectiveQuantity.divide(dailyTotalQuantity, 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
                dailyAverageDefectRate = defectRateDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            }
            
            // 添加平均不良率和工序数据到结果项
            item.put("averageDefectRate", dailyAverageDefectRate);
            item.put("processes", processesList);
            
            result.add(item);
        }
        
        return result;
    }
}