zss
6 天以前 b5d5cb947a194ceb34cd2797ab077f1484989305
Merge branch 'dev_New_pro' into dev_New_pro_财务

# Conflicts:
# src/main/java/com/ruoyi/home/controller/HomeController.java
# src/main/java/com/ruoyi/quality/controller/QualityInspectController.java
# src/main/java/com/ruoyi/quality/controller/QualityInspectParamController.java
# src/main/java/com/ruoyi/quality/controller/QualityTestStandardBindingController.java
# src/main/java/com/ruoyi/quality/controller/QualityTestStandardController.java
# src/main/java/com/ruoyi/quality/controller/QualityTestStandardParamController.java
# src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java
已添加2个文件
已修改10个文件
1022 ■■■■ 文件已修改
doc/20260520_首页生产看板前端联调文档.md 160 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/20260520_首页生产看板性能优化前端变更文档.md 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/controller/HomeController.java 491 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductionOrderMapper.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/controller/QualityInspectController.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/controller/QualityInspectParamController.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/controller/QualityTestStandardBindingController.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/controller/QualityTestStandardController.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/controller/QualityTestStandardParamController.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductionOrderMapper.xml 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/20260520_Ê×Ò³Éú²ú¿´°åǰ¶ËÁªµ÷Îĵµ.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,160 @@
# é¦–页生产看板前端联调文档
更新时间:2026-05-20
模块:`/home`(首页)
## 1. æŽ¥å£æ¸…单
1. `GET /home/productionOverview`:生产总览
2. `GET /home/productionRealtimeBoard`:生产实时看板
3. `GET /home/productionOrderProgress`:生产订单进度
4. `GET /home/todayProductionPlan`:今日生产计划
所有接口统一返回 `AjaxResult`:
```json
{
  "code": 200,
  "msg": "操作成功",
  "data": {}
}
```
## 2. ç”Ÿäº§æ€»è§ˆ
### 2.1 è¯·æ±‚
```http
GET /home/productionOverview
```
### 2.2 è¿”回 `data`
```json
{
  "totalOutput": 1280.00,
  "totalScrap": 25.00,
  "yieldRate": 98.08
}
```
字段说明:
- `totalOutput`:累计产出(件,合格数)
- `totalScrap`:累计报废(件)
- `yieldRate`:良率(0-100,前端展示时可拼接 `%`)
## 3. ç”Ÿäº§å®žæ—¶çœ‹æ¿
### 3.1 è¯·æ±‚
```http
GET /home/productionRealtimeBoard
```
### 3.2 è¿”回 `data`
```json
{
  "deviceOee": {
    "value": 74.00,
    "compareYesterday": 2.50
  },
  "orderAchievementRate": {
    "value": 81.30,
    "compareYesterday": -1.20
  },
  "defectRate": {
    "value": 1.40,
    "compareYesterday": 0.30
  }
}
```
字段说明:
- `value`:当日指标值(0-100)
- `compareYesterday`:较昨日变化值(可正可负;前端按正负决定箭头方向和颜色)
## 4. ç”Ÿäº§è®¢å•进度
### 4.1 è¯·æ±‚
```http
GET /home/productionOrderProgress?tab=all&pageNum=1&pageSize=10
```
参数:
- `tab`:`all` / `inProgress` / `completed` / `paused`
- `pageNum`:页码(默认 `1`)
- `pageSize`:每页条数(默认 `10`,最大 `50`)
### 4.2 è¿”回 `data`
```json
{
  "tab": "all",
  "total": 24,
  "pageNum": 1,
  "pageSize": 10,
  "inProgressCount": 6,
  "completedCount": 12,
  "pausedCount": 2,
  "records": [
    {
      "orderNo": "MO-20260518-001",
      "productName": "智能控制器",
      "plannedQuantity": 1000.00,
      "completedQuantity": 860.00,
      "completionRate": 86.00,
      "dueDate": "2026-05-20",
      "status": 2,
      "statusLabel": "进行中"
    }
  ]
}
```
字段说明:
- `completionRate`:完成率(0-100)
- `status`:后端状态码(`1`待开始,`2`进行中,`3`已完成,`4`已暂停)
- `statusLabel`:状态中文展示值
## 5. ä»Šæ—¥ç”Ÿäº§è®¡åˆ’
### 5.1 è¯·æ±‚
```http
GET /home/todayProductionPlan?limit=4
```
参数:
- `limit`:返回条数(默认 `4`,最大 `20`)
### 5.2 è¿”回 `data`
```json
{
  "total": 9,
  "records": [
    {
      "orderNo": "MO-20260518-004",
      "productName": "结构件A",
      "plannedQuantity": 1200.00,
      "dueDate": "2026-05-15",
      "status": 2,
      "statusLabel": "进行中"
    }
  ]
}
```
## 6. å‰ç«¯å±•示约定
- ç™¾åˆ†æ¯”字段统一是数值(如 `74.00`),前端自行拼接 `%`。
- æ‰€æœ‰æ•°å€¼ä¿ç•™ä¸¤ä½å°æ•°ã€‚
- `dueDate` å¯èƒ½ä¸º `null`,前端需兜底展示(如 `--`)。
- `compareYesterday` æ­£è´Ÿéƒ½å¯èƒ½å‡ºçŽ°ï¼Œå»ºè®®æŒ‰ `>0` ä¸Šå‡ã€`<0` ä¸‹é™ã€`=0` æŒå¹³å¤„理。
doc/20260520_Ê×Ò³Éú²ú¿´°åÐÔÄÜÓÅ»¯Ç°¶Ë±ä¸üÎĵµ.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,107 @@
# é¦–页生产看板性能优化前端变更文档
更新时间:2026-05-20
适用页面:首页
涉及区块:
1. ç”Ÿäº§è®¢å•进度
2. ä»Šæ—¥ç”Ÿäº§è®¡åˆ’
## 1. æœ¬æ¬¡ä¼˜åŒ–目标
针对大数据量场景(订单数量多、生产历史长)优化查询性能,降低首页接口响应时间和内存占用。
## 2. æ¶‰åŠæŽ¥å£
1. `GET /home/productionOrderProgress`
2. `GET /home/todayProductionPlan`
## 3. å‰ç«¯æ˜¯å¦éœ€è¦æ”¹ä»£ç 
结论:**无强制改动,接口入参与返回结构保持兼容**。
你现有页面可以直接联调,不需要改字段映射。
## 4. æŽ¥å£è¯´æ˜Žï¼ˆä¿æŒä¸å˜ï¼‰
### 4.1 ç”Ÿäº§è®¢å•进度
请求:
```http
GET /home/productionOrderProgress?tab=all&pageNum=1&pageSize=10
```
参数:
- `tab`:`all` / `inProgress` / `completed` / `paused`
- `pageNum`:页码,默认 `1`
- `pageSize`:每页条数,默认 `10`,最大 `50`
返回 `data`(结构不变):
```json
{
  "tab": "all",
  "total": 1200,
  "pageNum": 1,
  "pageSize": 10,
  "inProgressCount": 180,
  "completedCount": 900,
  "pausedCount": 20,
  "records": [
    {
      "orderNo": "MO-20260518-001",
      "productName": "智能控制器",
      "plannedQuantity": 1000.00,
      "completedQuantity": 860.00,
      "completionRate": 86.00,
      "dueDate": "2026-05-20",
      "status": 2,
      "statusLabel": "进行中"
    }
  ]
}
```
### 4.2 ä»Šæ—¥ç”Ÿäº§è®¡åˆ’
请求:
```http
GET /home/todayProductionPlan?limit=4
```
参数:
- `limit`:返回条数,默认 `4`,最大 `20`
返回 `data`(结构不变):
```json
{
  "total": 230,
  "records": [
    {
      "orderNo": "MO-20260518-004",
      "productName": "结构件A",
      "plannedQuantity": 1200.00,
      "dueDate": "2026-05-15",
      "status": 2,
      "statusLabel": "进行中"
    }
  ]
}
```
## 5. åŽç«¯ä¼˜åŒ–点(供前端知悉)
1. è®¢å•进度与今日计划改为轻量 SQL,仅查询首页必需字段。
2. åŽ»æŽ‰äº†é¦–é¡µæŸ¥è¯¢è·¯å¾„ä¸­ä¸å¿…è¦çš„å¤§å…³è”ã€å›¾ç‰‡å¡«å……å’Œå¯¹è±¡è£…é…ã€‚
3. çŠ¶æ€ç»Ÿè®¡æ”¹ä¸ºæ•°æ®åº“èšåˆè®¡æ•°ï¼Œä¸å†é€æ¡æ‹‰å–è®¡ç®—ã€‚
4. åˆ†é¡µä¸Žæ¡æ•°ä¸Šé™ä¿ç•™ï¼ˆ`pageSize <= 50`, `limit <= 20`)。
## 6. å‰ç«¯å»ºè®®
1. åˆ‡æ¢ `tab` æ—¶ä¿ç•™çŽ°æœ‰è°ƒç”¨æ–¹å¼å³å¯ã€‚
2. `dueDate` å¯èƒ½ä¸ºç©ºï¼Œç»§ç»­æŒ‰ `--` å…œåº•展示。
3. ç™¾åˆ†æ¯”字段仍为数值,前端继续追加 `%` å±•示。
src/main/java/com/ruoyi/home/controller/HomeController.java
@@ -1,6 +1,10 @@
package com.ruoyi.home.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.approve.pojo.ApproveProcess;
import com.ruoyi.device.mapper.DeviceLedgerMapper;
import com.ruoyi.device.mapper.DeviceRepairMapper;
import com.ruoyi.device.pojo.DeviceRepair;
import com.ruoyi.dto.MapDto;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
@@ -9,6 +13,9 @@
import com.ruoyi.home.annotation.DefaultType;
import com.ruoyi.home.dto.*;
import com.ruoyi.home.service.HomeService;
import com.ruoyi.production.mapper.ProductionOrderMapper;
import com.ruoyi.production.mapper.ProductionProductOutputMapper;
import com.ruoyi.production.pojo.ProductionOrder;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
@@ -17,9 +24,18 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
 * @author :yys
@@ -32,293 +48,608 @@
public class HomeController extends BaseController {
    private final HomeService homeService;
    private final ProductionOrderMapper productionOrderMapper;
    private final ProductionProductOutputMapper productionProductOutputMapper;
    private final DeviceLedgerMapper deviceLedgerMapper;
    private final DeviceRepairMapper deviceRepairMapper;
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final Integer ORDER_STATUS_WAIT = 1;
    private static final Integer ORDER_STATUS_RUNNING = 2;
    private static final Integer ORDER_STATUS_COMPLETED = 3;
    private static final Integer ORDER_STATUS_PAUSED = 4;
    /********************************************************基础类*****************************************************/
    @GetMapping("/todos")
    @Log(title = "待办事项", businessType = BusinessType.OTHER)
    @Operation(summary = "待办事项")
    public AjaxResult todos(ApproveProcess req) throws ParseException {
    public R todos(ApproveProcess req) throws ParseException {
        List<ApproveProcess> approveProcessList = homeService.todos();
        return AjaxResult.success(approveProcessList);
        return R.ok(approveProcessList);
    }
    @GetMapping("/approveAndDeviceTodos")
    @Operation(summary = "审批协同,设备报修待办事项")
    public AjaxResult approveAndDeviceTodos(){
    public R approveAndDeviceTodos(){
        Map<String, Object> map = homeService.approveAndDeviceTodos();
        return AjaxResult.success(map);
        return R.ok(map);
    }
    @GetMapping("/noticesCount")
    @Operation(summary = "未过期的公告数量")
    public AjaxResult noticesCount(){
    public R noticesCount(){
        Long count = homeService.noticesCount();
        return AjaxResult.success(count);
        return R.ok(count);
    }
    @GetMapping("/deptStaffDistribution")
    @Operation(summary = "各部门人员分布")
    public AjaxResult deptStaffDistribution() {
    public R deptStaffDistribution() {
        DeptStaffDistributionDto dto = homeService.deptStaffDistribution();
        return AjaxResult.success(dto);
        return R.ok(dto);
    }
    @GetMapping("/summaryStatistics")
    @Operation(summary = "员工-客户-供应商总数")
    public AjaxResult summaryStatistics() {
    public R summaryStatistics() {
        HomeSummaryDto homeSummaryDto = homeService.summaryStatistics();
        return AjaxResult.success(homeSummaryDto);
        return R.ok(homeSummaryDto);
    }
    /********************************************************营销采购类**************************************************/
    @GetMapping("/supplierPurchaseRanking")
    @Operation(summary = "供应商采购排名")
    public AjaxResult supplierPurchaseRanking(@DefaultType Integer type) {
    public R supplierPurchaseRanking(@DefaultType Integer type) {
        List<SupplierPurchaseRankingDto> list = homeService.supplierPurchaseRanking(type);
        return AjaxResult.success(list);
        return R.ok(list);
    }
    @GetMapping("/customerRevenueAnalysis")
    @Operation(summary = "客户营收贡献数值分析")
    public AjaxResult customerRevenueAnalysis(Long customerId, @DefaultType Integer type) {
    public R customerRevenueAnalysis(Long customerId, @DefaultType Integer type) {
        CustomerRevenueAnalysisDto dto = homeService.customerRevenueAnalysis(customerId, type);
        return AjaxResult.success(dto);
        return R.ok(dto);
    }
    @GetMapping("/customerContributionRanking")
    @Operation(summary = "客户金额贡献排名")
    public AjaxResult customerContributionRanking(@DefaultType Integer type) {
    public R customerContributionRanking(@DefaultType Integer type) {
        List<CustomerContributionRankingDto> list = homeService.customerContributionRanking(type);
        return AjaxResult.success(list);
        return R.ok(list);
    }
    @GetMapping("/productSalesAnalysis")
    @Operation(summary = "各产品销售金额分析")
    public AjaxResult productSalesAnalysis() {
    public R productSalesAnalysis() {
        List<MapDto> list = homeService.productSalesAnalysis();
        return AjaxResult.success(list);
        return R.ok(list);
    }
    @GetMapping("/rawMaterialPurchaseAmountRatio")
    @Operation(summary = "原材料采购金额占比")
    public AjaxResult rawMaterialPurchaseAmountRatio(){
    public R rawMaterialPurchaseAmountRatio(){
        List<MapDto> list = homeService.rawMaterialPurchaseAmountRatio();
        return AjaxResult.success(list);
        return R.ok(list);
    }
    @GetMapping("/business")
    @Log(title = "销售-采购-库存数据", businessType = BusinessType.OTHER)
    @Operation(summary = "销售-采购-库存数据")
    public AjaxResult business(HomeBusinessDto req) {
    public R business(HomeBusinessDto req) {
        HomeBusinessDto homeBusinessDto = homeService.business();
        return AjaxResult.success(homeBusinessDto);
        return R.ok(homeBusinessDto);
    }
    @GetMapping("/analysisCustomerContractAmounts")
    @Log(title = "客户合同金额分析", businessType = BusinessType.OTHER)
    @Operation(summary = "客户合同金额分析")
    public AjaxResult analysisCustomerContractAmounts(AnalysisCustomerContractAmountsDto req) {
    public R analysisCustomerContractAmounts(AnalysisCustomerContractAmountsDto req) {
        AnalysisCustomerContractAmountsDto analysisCustomerContractAmounts = homeService.analysisCustomerContractAmounts();
        return AjaxResult.success(analysisCustomerContractAmounts);
        return R.ok(analysisCustomerContractAmounts);
    }
    /********************************************************生产类*****************************************************/
    @GetMapping("/inputOutputAnalysis")
    @Operation(summary = "投入产出分析")
    public AjaxResult inputOutputAnalysis(@DefaultType Integer type){
    public R inputOutputAnalysis(@DefaultType Integer type){
      List<InputOutputAnalysisDto> list = homeService.inputOutputAnalysis(type);
        return AjaxResult.success(list);
        return R.ok(list);
    }
    @GetMapping("/processOutputAnalysis")
    @Operation(summary = "工序产出分析")
    public AjaxResult processOutputAnalysis(@DefaultType Integer type){
    public R processOutputAnalysis(@DefaultType Integer type){
        List<MapDto> list = homeService.processOutputAnalysis(type);
        return AjaxResult.success(list);
        return R.ok(list);
    }
    @GetMapping("/workOrderEfficiencyAnalysis")
    @Operation(summary = "工单执行效率分析")
    public AjaxResult workOrderEfficiencyAnalysis(@DefaultType Integer type){
    public R workOrderEfficiencyAnalysis(@DefaultType Integer type){
        List<WorkOrderEfficiencyDto> list = homeService.workOrderEfficiencyAnalysis(type);
        return AjaxResult.success(list);
        return R.ok(list);
    }
    @GetMapping("/productionAccountingAnalysis")
    @Operation(summary = "生产核算分析")
    public AjaxResult productionAccountingAnalysis(@DefaultType Integer type){
    public R productionAccountingAnalysis(@DefaultType Integer type){
        List<ProductionAccountingDto> list   = homeService.productionAccountingAnalysis(type);
        return AjaxResult.success(list);
        return R.ok(list);
    }
    @GetMapping("/orderCount")
    @Operation(summary = "订单数")
    public AjaxResult orderCount(){
        return AjaxResult.success(homeService.orderCount());
    public R orderCount(){
        return R.ok(homeService.orderCount());
    }
    @GetMapping("/progressStatistics")
    @Operation(summary = "各生产订单的完成进度统计")
    public AjaxResult progressStatistics(){
    public R progressStatistics(){
        ProductionProgressDto productionProgressDto = homeService.productionProgress();
        return AjaxResult.success(productionProgressDto);
        return R.ok(productionProgressDto);
    }
    @GetMapping("/workInProcessTurnover")
    @Operation(summary = "在制品周转情况")
    public AjaxResult workInProcessTurnover(){
    public R workInProcessTurnover(){
        ProductionTurnoverDto productionTurnoverDto = homeService.workInProcessTurnover();
        return AjaxResult.success(productionTurnoverDto);
        return R.ok(productionTurnoverDto);
    }
    @GetMapping("/processDataProductionStatistics")
    @Operation(summary = "工序数据生产统计数据")
    public AjaxResult processDataProductionStatistics(@DefaultType Integer type,@RequestParam(required = false) List<Long> processIds) {
    public R processDataProductionStatistics(@DefaultType Integer type,@RequestParam(required = false) List<Long> processIds) {
        List<processDataProductionStatisticsDto> list = homeService.processDataProductionStatistics(type, processIds);
        return AjaxResult.success(list);
        return R.ok(list);
    }
    /********************************************************质量类*****************************************************/
    @GetMapping("/productionOverview")
    @Operation(summary = "Production Overview")
    public R productionOverview() {
        LocalDate today = LocalDate.now();
        Map<String, BigDecimal> totalStats = loadOutputStats(LocalDate.of(2000, 1, 1), today.plusDays(1));
        BigDecimal totalOutput = totalStats.get("quantity");
        BigDecimal totalScrap = totalStats.get("scrapQty");
        BigDecimal yieldRate = calcRate(totalOutput, totalOutput.add(totalScrap));
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("totalOutput", scale(totalOutput));
        result.put("totalScrap", scale(totalScrap));
        result.put("yieldRate", scale(yieldRate));
        return R.ok(result);
    }
    @GetMapping("/productionRealtimeBoard")
    @Operation(summary = "Production Realtime Board")
    public R productionRealtimeBoard() {
        LocalDate today = LocalDate.now();
        LocalDate yesterday = today.minusDays(1);
        BigDecimal todayDeviceOee = calcDeviceOee(today);
        BigDecimal yesterdayDeviceOee = calcDeviceOee(yesterday);
        BigDecimal todayOrderAchievementRate = calcOrderAchievementRate(today);
        BigDecimal yesterdayOrderAchievementRate = calcOrderAchievementRate(yesterday);
        BigDecimal todayDefectRate = calcDefectRate(today);
        BigDecimal yesterdayDefectRate = calcDefectRate(yesterday);
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("deviceOee", buildRealtimeMetric(todayDeviceOee, todayDeviceOee.subtract(yesterdayDeviceOee)));
        result.put("orderAchievementRate", buildRealtimeMetric(todayOrderAchievementRate, todayOrderAchievementRate.subtract(yesterdayOrderAchievementRate)));
        result.put("defectRate", buildRealtimeMetric(todayDefectRate, todayDefectRate.subtract(yesterdayDefectRate)));
        return R.ok(result);
    }
    @GetMapping("/productionOrderProgress")
    @Operation(summary = "Production Order Progress")
    public R productionOrderProgress(@RequestParam(defaultValue = "all") String tab,
                                              @RequestParam(defaultValue = "1") Long pageNum,
                                              @RequestParam(defaultValue = "10") Long pageSize) {
        long safePageNum = pageNum == null || pageNum < 1 ? 1 : pageNum;
        long safePageSize = pageSize == null || pageSize < 1 ? 10 : Math.min(pageSize, 50);
        Integer status = resolveOrderStatus(tab);
        long offset = (safePageNum - 1) * safePageSize;
        List<Map<String, Object>> rawRows = productionOrderMapper.selectHomeOrderProgressPage(status, offset, safePageSize);
        List<Map<String, Object>> records = new ArrayList<>();
        if (rawRows != null) {
            for (Map<String, Object> rawRow : rawRows) {
                records.add(buildOrderProgressRow(rawRow));
            }
        }
        long inProgressCount = 0L;
        long completedCount = 0L;
        long pausedCount = 0L;
        List<Map<String, Object>> statusCountRows = productionOrderMapper.countHomeOrderProgressByStatus();
        if (statusCountRows != null) {
            for (Map<String, Object> countRow : statusCountRows) {
                Integer statusKey = toInteger(countRow.get("status"));
                long cnt = toLong(countRow.get("cnt"));
                if (Objects.equals(statusKey, ORDER_STATUS_RUNNING)) {
                    inProgressCount = cnt;
                } else if (Objects.equals(statusKey, ORDER_STATUS_COMPLETED)) {
                    completedCount = cnt;
                } else if (Objects.equals(statusKey, ORDER_STATUS_PAUSED)) {
                    pausedCount = cnt;
                }
            }
        }
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("tab", tab);
        result.put("total", toLong(productionOrderMapper.countHomeOrderProgress(status)));
        result.put("pageNum", safePageNum);
        result.put("pageSize", safePageSize);
        result.put("inProgressCount", inProgressCount);
        result.put("completedCount", completedCount);
        result.put("pausedCount", pausedCount);
        result.put("records", records);
        return R.ok(result);
    }
    @GetMapping("/todayProductionPlan")
    @Operation(summary = "Today Production Plan")
    public R todayProductionPlan(@RequestParam(defaultValue = "4") Long limit) {
        long safeLimit = limit == null || limit < 1 ? 4 : Math.min(limit, 20);
        List<Map<String, Object>> records = new ArrayList<>();
        List<Map<String, Object>> rawRows = productionOrderMapper.selectHomeTodayProductionPlan(safeLimit);
        if (rawRows != null) {
            for (Map<String, Object> rawRow : rawRows) {
                Map<String, Object> row = new LinkedHashMap<>();
                Integer rowStatus = toInteger(rawRow.get("status"));
                row.put("orderNo", rawRow.get("orderNo"));
                row.put("productName", rawRow.get("productName"));
                row.put("plannedQuantity", scale(toBigDecimal(rawRow.get("plannedQuantity"))));
                row.put("dueDate", rawRow.get("dueDate"));
                row.put("status", rowStatus);
                row.put("statusLabel", mapOrderStatusLabel(rowStatus));
                records.add(row);
            }
        }
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("total", toLong(productionOrderMapper.countHomeTodayProductionPlan()));
        result.put("records", records);
        return R.ok(result);
    }
    @GetMapping("/rawMaterialDetection")
    @Operation(summary = "原材料检测")
    public AjaxResult rawMaterialDetection(@DefaultType Integer type){
        return AjaxResult.success(homeService.rawMaterialDetection(type));
    public R rawMaterialDetection(@DefaultType Integer type){
        return R.ok(homeService.rawMaterialDetection(type));
    }
    @GetMapping("/processDetection")
    @Operation(summary = "过程检测")
    public AjaxResult processDetection(@DefaultType Integer type){
        return AjaxResult.success(homeService.processDetection(type));
    public R processDetection(@DefaultType Integer type){
        return R.ok(homeService.processDetection(type));
    }
    @GetMapping("/factoryDetection")
    @Operation(summary = "成品出厂检测")
    public AjaxResult factoryDetection(@DefaultType Integer type){
        return AjaxResult.success(homeService.factoryDetection(type));
    public R factoryDetection(@DefaultType Integer type){
        return R.ok(homeService.factoryDetection(type));
    }
    @GetMapping("/qualityInspectionCount")
    @Operation(summary = "质量检验数量")
    public AjaxResult qualityInspectionCount(){
    public R qualityInspectionCount(){
        QualityInspectionCountDto qualityInspectionCountDto = homeService.qualityInspectionCount();
        return AjaxResult.success(qualityInspectionCountDto);
        return R.ok(qualityInspectionCountDto);
    }
    @GetMapping("/nonComplianceWarning")
    @Operation(summary = "不合格预警")
    public AjaxResult nonComplianceWarning(){
    public R nonComplianceWarning(){
        NonComplianceWarningDto nonComplianceWarningDto = homeService.nonComplianceWarning();
        return AjaxResult.success(nonComplianceWarningDto);
        return R.ok(nonComplianceWarningDto);
    }
    @GetMapping("/completedInspectionCount")
    @Operation(summary = "完成检验数")
    public AjaxResult completedInspectionCount(){
    public R completedInspectionCount(){
        List<CompletedInspectionCountDto> list = homeService.completedInspectionCount();
        return AjaxResult.success(list);
        return R.ok(list);
    }
    @GetMapping("/unqualifiedProductRanking")
    @Operation(summary = "不合格产品排名")
    public AjaxResult unqualifiedProductRanking(){
    public R unqualifiedProductRanking(){
        List<UnqualifiedProductRankDto> list = homeService.unqualifiedProductRanking();
        return AjaxResult.success(list);
        return R.ok(list);
    }
    @GetMapping("/unqualifiedProductProcessingAnalysis")
    @Operation(summary = "不合格检品处理分析")
    public AjaxResult unqualifiedProductProcessingAnalysis(){
    public R unqualifiedProductProcessingAnalysis(){
        List<MapDto> list = homeService.unqualifiedProductProcessingAnalysis();
        return AjaxResult.success(list);
        return R.ok(list);
    }
    @GetMapping("/qualityStatistics")
    @Log(title = "质量分析", businessType = BusinessType.OTHER)
    @Operation(summary = "质量分析")
    public AjaxResult qualityStatistics(QualityStatisticsDto req) {
    public R qualityStatistics(QualityStatisticsDto req) {
        QualityStatisticsDto qualityStatisticsDto = homeService.qualityStatistics();
        return AjaxResult.success(qualityStatisticsDto);
        return R.ok(qualityStatisticsDto);
    }
    @GetMapping("/qualityInspectionStatistics")
    @Operation(summary = "质量统计")
    public AjaxResult qualityInspectionStatistics(@DefaultType Integer type) {
    public R qualityInspectionStatistics(@DefaultType Integer type) {
       QualityStatisticsDto  dto = homeService.qualityInspectionStatistics(type);
        return AjaxResult.success(dto);
        return R.ok(dto);
    }
    /********************************************************财务类*****************************************************/
    @GetMapping("/incomeExpenseAnalysis")
    @Operation(summary = "支收对比分析")
    public AjaxResult incomeExpenseAnalysis(@DefaultType Integer type) {
    public R incomeExpenseAnalysis(@DefaultType Integer type) {
        List<Map<String, Object>> result = homeService.incomeExpenseAnalysis(type);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @GetMapping("/profitTrendAnalysis")
    @Operation(summary = "利润趋势分析")
    public AjaxResult profitTrendAnalysis(){
    public R profitTrendAnalysis(){
        List<MapDto> list = homeService.profitTrendAnalysis();
        return AjaxResult.success(list);
        return R.ok(list);
    }
    @GetMapping("/expenseCompositionAnalysis")
    @Operation(summary = "构成分析")
    public AjaxResult expenseCompositionAnalysis(@DefaultType Integer type) {
    public R expenseCompositionAnalysis(@DefaultType Integer type) {
        List<MapDto> list = homeService.expenseCompositionAnalysis(type);
        return AjaxResult.success(list);
        return R.ok(list);
    }
    @GetMapping("/monthlyIncome")
    @Operation(summary = "月度收入")
    public AjaxResult monthlyIncome(){
    public R monthlyIncome(){
        MonthlyIncomeDto dto = homeService.monthlyIncome();
        return AjaxResult.success(dto);
        return R.ok(dto);
    }
    @GetMapping("/monthlyExpenditure")
    @Operation(summary = "月度支出")
    public AjaxResult monthlyExpenditure(){
    public R monthlyExpenditure(){
        MonthlyExpenditureDto dto = homeService.monthlyExpenditure();
        return AjaxResult.success(dto);
        return R.ok(dto);
    }
    @GetMapping("/statisticsReceivablePayable")
    @Log(title = "应收应付统计", businessType = BusinessType.OTHER)
    @Operation(summary = "应收应付统计")
    public AjaxResult statisticsReceivablePayable(StatisticsReceivablePayableDto req, @DefaultType Integer type ) {
    public R statisticsReceivablePayable(StatisticsReceivablePayableDto req, @DefaultType Integer type ) {
        StatisticsReceivablePayableDto statisticsReceivablePayable = homeService.statisticsReceivablePayable(type);
        return AjaxResult.success(statisticsReceivablePayable);
        return R.ok(statisticsReceivablePayable);
    }
    /********************************************************仓储类*****************************************************/
    @GetMapping("/productCategoryDistribution")
    @Operation(summary = "产品大类分布")
    public AjaxResult productCategoryDistribution() {
    public R productCategoryDistribution() {
        ProductCategoryDistributionDto dto = homeService.productCategoryDistribution();
        return AjaxResult.success(dto);
        return R.ok(dto);
    }
    @GetMapping("/salesPurchaseStorageProductCount")
    @Operation(summary = "销售-采购-储存产品数")
    public AjaxResult salesPurchaseStorageProductCount(){
    public R salesPurchaseStorageProductCount(){
        List<MapDto> list = homeService.salesPurchaseStorageProductCount();
        return AjaxResult.success(list);
        return R.ok(list);
    }
    @GetMapping("/productInOutAnalysis")
    @Operation(summary = "产品出入库分析")
    public AjaxResult productInOutAnalysis(@DefaultType Integer type){
    public R productInOutAnalysis(@DefaultType Integer type){
        List<Map<String, Object>> result = homeService.productInOutAnalysis(type);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @GetMapping("/productTurnoverDays")
    @Operation(summary = "产品周转天数")
    public AjaxResult productTurnoverDays(){
    public R productTurnoverDays(){
        List<MapDto> list = homeService.productTurnoverDays();
        return AjaxResult.success(list);
        return R.ok(list);
    }
    private Map<String, Object> buildOrderProgressRow(Map<String, Object> rawRow) {
        Map<String, Object> row = new LinkedHashMap<>();
        Integer rowStatus = toInteger(rawRow.get("status"));
        row.put("orderNo", rawRow.get("orderNo"));
        row.put("productName", rawRow.get("productName"));
        row.put("plannedQuantity", scale(toBigDecimal(rawRow.get("plannedQuantity"))));
        row.put("completedQuantity", scale(toBigDecimal(rawRow.get("completedQuantity"))));
        row.put("completionRate", scale(toBigDecimal(rawRow.get("completionRate"))));
        row.put("dueDate", rawRow.get("dueDate"));
        row.put("status", rowStatus);
        row.put("statusLabel", mapOrderStatusLabel(rowStatus));
        return row;
    }
    private Integer resolveOrderStatus(String tab) {
        if (tab == null) {
            return null;
        }
        String normalized = tab.trim().toLowerCase();
        if ("inprogress".equals(normalized)) {
            return ORDER_STATUS_RUNNING;
        }
        if ("completed".equals(normalized)) {
            return ORDER_STATUS_COMPLETED;
        }
        if ("paused".equals(normalized)) {
            return ORDER_STATUS_PAUSED;
        }
        return null;
    }
    private String mapOrderStatusLabel(Integer status) {
        if (Objects.equals(status, ORDER_STATUS_WAIT)) {
            return "待开始";
        }
        if (Objects.equals(status, ORDER_STATUS_RUNNING)) {
            return "进行中";
        }
        if (Objects.equals(status, ORDER_STATUS_COMPLETED)) {
            return "已完成";
        }
        if (Objects.equals(status, ORDER_STATUS_PAUSED)) {
            return "已暂停";
        }
        return "未知";
    }
    private Map<String, BigDecimal> loadOutputStats(LocalDate startDate, LocalDate endDateExclusive) {
        String start = startDate.atStartOfDay().format(DATE_TIME_FORMATTER);
        String end = endDateExclusive.atStartOfDay().format(DATE_TIME_FORMATTER);
        BigDecimal quantity = BigDecimal.ZERO;
        BigDecimal scrapQty = BigDecimal.ZERO;
        List<Map<String, Object>> rows = productionProductOutputMapper.selectDailyOutputStats(start, end);
        if (rows != null) {
            for (Map<String, Object> row : rows) {
                quantity = quantity.add(toBigDecimal(row.get("quantity")));
                scrapQty = scrapQty.add(toBigDecimal(row.get("scrapQty")));
            }
        }
        Map<String, BigDecimal> stats = new LinkedHashMap<>();
        stats.put("quantity", quantity);
        stats.put("scrapQty", scrapQty);
        return stats;
    }
    private BigDecimal calcDeviceOee(LocalDate day) {
        long totalDeviceCount = deviceLedgerMapper.selectCount(new LambdaQueryWrapper<>());
        if (totalDeviceCount <= 0) {
            return BigDecimal.ZERO;
        }
        Date start = Date.from(day.atStartOfDay(ZoneId.systemDefault()).toInstant());
        Date end = Date.from(day.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
        List<DeviceRepair> repairList = deviceRepairMapper.selectList(new LambdaQueryWrapper<DeviceRepair>()
                .select(DeviceRepair::getDeviceLedgerId)
                .ge(DeviceRepair::getRepairTime, start)
                .lt(DeviceRepair::getRepairTime, end)
                .in(DeviceRepair::getStatus, 0, 3));
        long repairingDeviceCount = repairList == null ? 0 : repairList.stream()
                .map(DeviceRepair::getDeviceLedgerId)
                .filter(Objects::nonNull)
                .distinct()
                .count();
        long availableDeviceCount = Math.max(totalDeviceCount - repairingDeviceCount, 0);
        return new BigDecimal(availableDeviceCount)
                .multiply(new BigDecimal("100"))
                .divide(new BigDecimal(totalDeviceCount), 2, RoundingMode.HALF_UP);
    }
    private BigDecimal calcOrderAchievementRate(LocalDate day) {
        List<ProductionOrder> orderList = productionOrderMapper.selectList(new LambdaQueryWrapper<ProductionOrder>()
                .select(ProductionOrder::getQuantity, ProductionOrder::getCompleteQuantity)
                .ge(ProductionOrder::getCreateTime, day.atStartOfDay())
                .lt(ProductionOrder::getCreateTime, day.plusDays(1).atStartOfDay())
                .ne(ProductionOrder::getStatus, ORDER_STATUS_PAUSED));
        BigDecimal totalQuantity = BigDecimal.ZERO;
        BigDecimal totalCompleteQuantity = BigDecimal.ZERO;
        if (orderList != null) {
            for (ProductionOrder order : orderList) {
                totalQuantity = totalQuantity.add(zeroIfNull(order.getQuantity()));
                totalCompleteQuantity = totalCompleteQuantity.add(zeroIfNull(order.getCompleteQuantity()));
            }
        }
        return calcRate(totalCompleteQuantity, totalQuantity);
    }
    private BigDecimal calcDefectRate(LocalDate day) {
        Map<String, BigDecimal> stats = loadOutputStats(day, day.plusDays(1));
        BigDecimal quantity = stats.get("quantity");
        BigDecimal scrapQty = stats.get("scrapQty");
        return calcRate(scrapQty, quantity.add(scrapQty));
    }
    private Map<String, Object> buildRealtimeMetric(BigDecimal value, BigDecimal change) {
        Map<String, Object> metric = new LinkedHashMap<>();
        metric.put("value", scale(value));
        metric.put("compareYesterday", scale(change));
        return metric;
    }
    private BigDecimal calcRate(BigDecimal numerator, BigDecimal denominator) {
        if (denominator == null || denominator.compareTo(BigDecimal.ZERO) <= 0) {
            return BigDecimal.ZERO;
        }
        return zeroIfNull(numerator)
                .multiply(new BigDecimal("100"))
                .divide(denominator, 2, RoundingMode.HALF_UP);
    }
    private BigDecimal toBigDecimal(Object value) {
        if (value == null) {
            return BigDecimal.ZERO;
        }
        if (value instanceof BigDecimal) {
            return (BigDecimal) value;
        }
        if (value instanceof Number) {
            return BigDecimal.valueOf(((Number) value).doubleValue());
        }
        try {
            return new BigDecimal(String.valueOf(value));
        } catch (Exception ex) {
            return BigDecimal.ZERO;
        }
    }
    private Integer toInteger(Object value) {
        if (value == null) {
            return null;
        }
        if (value instanceof Integer) {
            return (Integer) value;
        }
        if (value instanceof Number) {
            return ((Number) value).intValue();
        }
        try {
            return Integer.valueOf(String.valueOf(value));
        } catch (Exception ex) {
            return null;
        }
    }
    private long toLong(Object value) {
        if (value == null) {
            return 0L;
        }
        if (value instanceof Long) {
            return (Long) value;
        }
        if (value instanceof Number) {
            return ((Number) value).longValue();
        }
        try {
            return Long.parseLong(String.valueOf(value));
        } catch (Exception ex) {
            return 0L;
        }
    }
    private BigDecimal zeroIfNull(BigDecimal value) {
        return value == null ? BigDecimal.ZERO : value;
    }
    private BigDecimal scale(BigDecimal value) {
        return zeroIfNull(value).setScale(2, RoundingMode.HALF_UP);
    }
}
src/main/java/com/ruoyi/production/mapper/ProductionOrderMapper.java
@@ -12,6 +12,7 @@
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
 * <p>
@@ -39,4 +40,16 @@
    Integer countPending(@Param("startDate") String startDate, @Param("endDate") String endDate);
    List<Map<String, Object>> selectHomeOrderProgressPage(@Param("status") Integer status,
                                                          @Param("offset") Long offset,
                                                          @Param("size") Long size);
    Long countHomeOrderProgress(@Param("status") Integer status);
    List<Map<String, Object>> countHomeOrderProgressByStatus();
    List<Map<String, Object>> selectHomeTodayProductionPlan(@Param("size") Long size);
    Long countHomeTodayProductionPlan();
}
src/main/java/com/ruoyi/quality/controller/QualityInspectController.java
@@ -2,7 +2,7 @@
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.quality.dto.QualityInspectDto;
import com.ruoyi.quality.pojo.QualityInspect;
import com.ruoyi.quality.pojo.QualityInspectFile;
@@ -10,6 +10,7 @@
import com.ruoyi.quality.service.IQualityInspectFileService;
import com.ruoyi.quality.service.IQualityInspectParamService;
import com.ruoyi.quality.service.IQualityInspectService;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import org.springframework.util.CollectionUtils;
@@ -37,8 +38,9 @@
     * @return
     */
    @PostMapping("/add")
    public AjaxResult add(@RequestBody QualityInspectDto qualityInspectDto) {
        return AjaxResult.success(qualityInspectService.add(qualityInspectDto));
    @Operation(summary = "新增检验")
    public R<?> add(@RequestBody QualityInspectDto qualityInspectDto) {
        return R.ok(qualityInspectService.add(qualityInspectDto));
    }
    /**
@@ -48,9 +50,10 @@
     * @return
     */
    @DeleteMapping("/del")
    public AjaxResult delQualityInspect(@RequestBody List<Integer> ids) {
    @Operation(summary = "删除检验")
    public R<?> delQualityInspect(@RequestBody List<Integer> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return AjaxResult.error("请选择至少一条数据");
            return R.fail("请选择至少一条数据");
        }
        //如果已经提交就不允许删除
        List<QualityInspect> qualityInspects = qualityInspectService.listByIds(ids);
@@ -66,7 +69,7 @@
        qualityInspectFileService.remove(Wrappers.<QualityInspectFile>lambdaQuery()
                .in(QualityInspectFile::getInspectId, ids));
        //删除检验单
        return AjaxResult.success(qualityInspectService.removeBatchByIds(ids));
        return R.ok(qualityInspectService.removeBatchByIds(ids));
    }
    /**
@@ -76,8 +79,9 @@
     * @return
     */
    @GetMapping("/{id}")
    public AjaxResult QualityInspectDetail(@PathVariable("id") Integer id) {
        return AjaxResult.success(qualityInspectService.getDetailById(id));
    @Operation(summary = "检验详情")
    public R<?> QualityInspectDetail(@PathVariable("id") Integer id) {
        return R.ok(qualityInspectService.getDetailById(id));
    }
    /**
@@ -87,8 +91,9 @@
     * @return
     */
    @PostMapping("/update")
    public AjaxResult update(@RequestBody QualityInspectDto qualityInspectDto) {
        return AjaxResult.success(qualityInspectService.updateQualityInspect(qualityInspectDto));
    @Operation(summary = "修改检验")
    public R<?> update(@RequestBody QualityInspectDto qualityInspectDto) {
        return R.ok(qualityInspectService.updateQualityInspect(qualityInspectDto));
    }
    /**
@@ -99,8 +104,9 @@
     * @return
     */
    @GetMapping("/listPage")
    public AjaxResult qualityInspectListPage(Page page, QualityInspectDto qualityInspect) {
        return AjaxResult.success(qualityInspectService.qualityInspectListPage(page, qualityInspect));
    @Operation(summary = "分页查询检验")
    public R<?> qualityInspectListPage(Page page, QualityInspectDto qualityInspect) {
        return R.ok(qualityInspectService.qualityInspectListPage(page, qualityInspect));
    }
    /**
@@ -110,6 +116,7 @@
     * @param qualityInspect
     */
    @PostMapping("/export")
    @Operation(summary = "导出检验")
    public void qualityInspectExport(HttpServletResponse response, QualityInspect qualityInspect) {
        qualityInspectService.qualityInspectExport(response, qualityInspect);
    }
@@ -121,8 +128,9 @@
     * @return
     */
    @PostMapping("/submit")
    public AjaxResult submit(@RequestBody QualityInspect qualityInspect) {
        return AjaxResult.success(qualityInspectService.submit(qualityInspect));
    @Operation(summary = "提交检验")
    public R<?> submit(@RequestBody QualityInspect qualityInspect) {
        return R.ok(qualityInspectService.submit(qualityInspect));
    }
    /**
@@ -132,6 +140,7 @@
     * @param qualityInspect
     */
    @PostMapping("/down")
    @Operation(summary = "下载检验")
    public void down(HttpServletResponse response, @RequestBody QualityInspect qualityInspect) {
        qualityInspectService.down(response, qualityInspect);
    }
src/main/java/com/ruoyi/quality/controller/QualityInspectParamController.java
@@ -2,13 +2,14 @@
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.quality.pojo.QualityInspect;
import com.ruoyi.quality.pojo.QualityInspectFile;
import com.ruoyi.quality.pojo.QualityInspectParam;
import com.ruoyi.quality.service.IQualityInspectFileService;
import com.ruoyi.quality.service.IQualityInspectParamService;
import com.ruoyi.quality.service.IQualityInspectService;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
@@ -32,8 +33,9 @@
     * @return
     */
    @GetMapping("/{inspectId}")
    public AjaxResult QualityInspectParamDetail(@PathVariable("inspectId") Integer inspectId) {
        return AjaxResult.success(qualityInspectParamService.qualityInspectParamDetail(inspectId));
    @Operation(summary = "检验参数项详情")
    public R<?> QualityInspectParamDetail(@PathVariable("inspectId") Integer inspectId) {
        return R.ok(qualityInspectParamService.qualityInspectParamDetail(inspectId));
    }
@@ -43,8 +45,9 @@
     * @return
     */
    @PostMapping("/update")
    public AjaxResult update(@RequestBody List<QualityInspectParam> qualityInspectParams) {
        return AjaxResult.success(qualityInspectParamService.updateBatchById(qualityInspectParams));
    @Operation(summary = "修改检验参数项")
    public R<?> update(@RequestBody List<QualityInspectParam> qualityInspectParams) {
        return R.ok(qualityInspectParamService.updateBatchById(qualityInspectParams));
    }
    /**
@@ -53,11 +56,12 @@
     * @return
     */
    @DeleteMapping("/del")
    public AjaxResult delQualityUnqualified(@RequestBody List<Integer> ids) {
    @Operation(summary = "删除检验参数项")
    public R<?> delQualityUnqualified(@RequestBody List<Integer> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
            return R.fail("请选择至少一条数据");
        }
        return AjaxResult.success(qualityInspectParamService.removeBatchByIds(ids));
        return R.ok(qualityInspectParamService.removeBatchByIds(ids));
    }
src/main/java/com/ruoyi/quality/controller/QualityTestStandardBindingController.java
@@ -1,8 +1,10 @@
package com.ruoyi.quality.controller;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.quality.pojo.QualityTestStandardBinding;
import com.ruoyi.quality.service.QualityTestStandardBindingService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
@@ -20,6 +22,7 @@
@RestController
@RequestMapping("/qualityTestStandardBinding")
@AllArgsConstructor
@Tag(name = "检测标准主表与产品关联表")
public class QualityTestStandardBindingController {
    private QualityTestStandardBindingService qualityTestStandardBindingService;
@@ -31,8 +34,9 @@
     * @return
     */
    @PostMapping("/add")
    public AjaxResult add(@RequestBody List<QualityTestStandardBinding> qualityTestStandardBindings) {
        return AjaxResult.success(qualityTestStandardBindingService.add(qualityTestStandardBindings));
    @Operation(summary = "新增检测标准主表与产品关联表")
    public R<?> add(@RequestBody List<QualityTestStandardBinding> qualityTestStandardBindings) {
        return R.ok(qualityTestStandardBindingService.add(qualityTestStandardBindings));
    }
    /**
@@ -42,11 +46,12 @@
     * @return
     */
    @DeleteMapping("/del")
    public AjaxResult delQualityTestStandard(@RequestBody List<Integer> ids) {
    @Operation(summary = "删除检测标准主表与产品关联表")
    public R<?> delQualityTestStandard(@RequestBody List<Integer> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return AjaxResult.error("请选择至少一条数据");
            return R.fail("请选择至少一条数据");
        }
        return AjaxResult.success(qualityTestStandardBindingService.removeBatchByIds(ids));
        return R.ok(qualityTestStandardBindingService.removeBatchByIds(ids));
    }
    /**
@@ -55,8 +60,9 @@
     * @return
     */
    @GetMapping("/list")
    public AjaxResult listBinding(Long testStandardId) {
        return AjaxResult.success(qualityTestStandardBindingService.listBinding(testStandardId));
    @Operation(summary = "检测指标维护查询")
    public R<?> listBinding(Long testStandardId) {
        return R.ok(qualityTestStandardBindingService.listBinding(testStandardId));
    }
}
src/main/java/com/ruoyi/quality/controller/QualityTestStandardController.java
@@ -2,11 +2,13 @@
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.quality.pojo.QualityTestStandard;
import com.ruoyi.quality.pojo.QualityTestStandardParam;
import com.ruoyi.quality.service.IQualityTestStandardService;
import com.ruoyi.quality.service.QualityTestStandardParamService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
@@ -24,6 +26,7 @@
 */
@RestController
@RequestMapping("/qualityTestStandard")
@Tag(name = "检测标准主表")
public class QualityTestStandardController {
    @Resource
@@ -39,8 +42,9 @@
     * @return
     */
    @PostMapping("/add")
    public AjaxResult add(@RequestBody QualityTestStandard qualityTestStandard) {
        return AjaxResult.success(qualityTestStandardService.save(qualityTestStandard));
    @Operation(summary = "新增检测标准主表")
    public R<?> add(@RequestBody QualityTestStandard qualityTestStandard) {
        return R.ok(qualityTestStandardService.save(qualityTestStandard));
    }
    /**
@@ -49,11 +53,12 @@
     * @return
     */
    @DeleteMapping("/del")
    public AjaxResult delQualityTestStandard(@RequestBody List<Integer> ids) {
    @Operation(summary = "删除检测标准主表")
    public R<?> delQualityTestStandard(@RequestBody List<Integer> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
            return R.fail("请选择至少一条数据");
        }
        return AjaxResult.success(qualityTestStandardService.delQualityTestStandard(ids));
        return R.ok(qualityTestStandardService.delQualityTestStandard(ids));
    }
    /**
@@ -62,8 +67,9 @@
     * @return
     */
    @PostMapping("/update")
    public AjaxResult update(@RequestBody QualityTestStandard qualityTestStandard) {
        return AjaxResult.success(qualityTestStandardService.updateById(qualityTestStandard));
    @Operation(summary = "检测标准主表修改")
    public R<?> update(@RequestBody QualityTestStandard qualityTestStandard) {
        return R.ok(qualityTestStandardService.updateById(qualityTestStandard));
    }
    /**
@@ -73,8 +79,9 @@
     * @return
     */
    @GetMapping("/listPage")
    public AjaxResult qualityTestStandardListPage(Page page, QualityTestStandard qualityTestStandard) {
        return AjaxResult.success(qualityTestStandardService.qualityTestStandardListPage(page, qualityTestStandard));
    @Operation(summary = "检测标准主表分页查询")
    public R<?> qualityTestStandardListPage(Page page, QualityTestStandard qualityTestStandard) {
        return R.ok(qualityTestStandardService.qualityTestStandardListPage(page, qualityTestStandard));
    }
    /**
@@ -83,8 +90,9 @@
     * @return
     */
    @PostMapping("/copyParam")
    public AjaxResult copyParam(@RequestBody QualityTestStandard qualityTestStandard) {
        return AjaxResult.success(qualityTestStandardService.copyParam(qualityTestStandard));
    @Operation(summary = "检测标准复制参数")
    public R<?> copyParam(@RequestBody QualityTestStandard qualityTestStandard) {
        return R.ok(qualityTestStandardService.copyParam(qualityTestStandard));
    }
    /**
@@ -93,8 +101,9 @@
     * @return
     */
    @PostMapping("/qualityTestStandardAudit")
    public AjaxResult qualityTestStandardAudit(@RequestBody List<QualityTestStandard> qualityTestStandards) {
        return AjaxResult.success(qualityTestStandardService.updateBatchById(qualityTestStandards));
    @Operation(summary = "检测标准批量审核")
    public R<?> qualityTestStandardAudit(@RequestBody List<QualityTestStandard> qualityTestStandards) {
        return R.ok(qualityTestStandardService.updateBatchById(qualityTestStandards));
    }
    /**
@@ -102,8 +111,9 @@
     * @return
     */
    @GetMapping("/getQualityTestStandardByProductId")
    public AjaxResult getQualityTestStandardByProductId(@Nonnull Long productId, @Nonnull Integer inspectType, String process) {
        return AjaxResult.success(qualityTestStandardService.getQualityTestStandardByProductId(productId,inspectType,process));
    @Operation(summary = "根据产品id查询相关的检验标准")
    public R<?> getQualityTestStandardByProductId(@Nonnull Long productId, @Nonnull Integer inspectType, String process) {
        return R.ok(qualityTestStandardService.getQualityTestStandardByProductId(productId,inspectType,process));
    }
    /**
@@ -111,8 +121,9 @@
     * @return
     */
    @GetMapping("/getQualityTestStandardParamByTestStandardId")
    public AjaxResult getQualityTestStandardParamByTestStandardId(Long testStandardId) {
        return AjaxResult.success(qualityTestStandardParamService.list(Wrappers.<QualityTestStandardParam>lambdaQuery().eq(QualityTestStandardParam::getTestStandardId, testStandardId)));
    @Operation(summary = "根据检测标准id查询相关的检验标准参数")
    public R<?> getQualityTestStandardParamByTestStandardId(Long testStandardId) {
        return R.ok(qualityTestStandardParamService.list(Wrappers.<QualityTestStandardParam>lambdaQuery().eq(QualityTestStandardParam::getTestStandardId, testStandardId)));
    }
}
src/main/java/com/ruoyi/quality/controller/QualityTestStandardParamController.java
@@ -2,10 +2,12 @@
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.quality.pojo.QualityTestStandard;
import com.ruoyi.quality.pojo.QualityTestStandardParam;
import com.ruoyi.quality.service.QualityTestStandardParamService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
@@ -24,6 +26,7 @@
@RestController
@RequestMapping("/qualityTestStandardParam")
@AllArgsConstructor
@Tag(name = "检测标准参数")
public class QualityTestStandardParamController {
    private QualityTestStandardParamService qualityTestStandardParamService;
@@ -34,8 +37,9 @@
     * @return
     */
    @PostMapping("/add")
    public AjaxResult add(@RequestBody QualityTestStandardParam qualityTestStandardParam) {
        return AjaxResult.success(qualityTestStandardParamService.save(qualityTestStandardParam));
    @Operation(summary = "新增检测标准参数")
    public R<?> add(@RequestBody QualityTestStandardParam qualityTestStandardParam) {
        return R.ok(qualityTestStandardParamService.save(qualityTestStandardParam));
    }
    /**
@@ -44,11 +48,12 @@
     * @return
     */
    @DeleteMapping("/del")
    public AjaxResult delQualityTestStandard(@RequestBody List<Integer> ids) {
    @Operation(summary = "删除检测指标维护")
    public R<?> delQualityTestStandard(@RequestBody List<Integer> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
            return R.fail("请选择至少一条数据");
        }
        return AjaxResult.success(qualityTestStandardParamService.removeBatchByIds(ids));
        return R.ok(qualityTestStandardParamService.removeBatchByIds(ids));
    }
    /**
@@ -57,8 +62,9 @@
     * @return
     */
    @PostMapping("/update")
    public AjaxResult update(@RequestBody QualityTestStandardParam qualityTestStandardParam) {
        return AjaxResult.success(qualityTestStandardParamService.updateById(qualityTestStandardParam));
    @Operation(summary = "检测指标维护修改")
    public R<?> update(@RequestBody QualityTestStandardParam qualityTestStandardParam) {
        return R.ok(qualityTestStandardParamService.updateById(qualityTestStandardParam));
    }
    /**
@@ -66,8 +72,9 @@
     * @return
     */
    @GetMapping("/list")
    public AjaxResult list(Long testStandardId) {
        return AjaxResult.success(qualityTestStandardParamService.list(Wrappers.<QualityTestStandardParam>lambdaQuery().eq(QualityTestStandardParam::getTestStandardId,testStandardId)));
    @Operation(summary = "检测指标维护查询")
    public R<?> list(Long testStandardId) {
        return R.ok(qualityTestStandardParamService.list(Wrappers.<QualityTestStandardParam>lambdaQuery().eq(QualityTestStandardParam::getTestStandardId,testStandardId)));
    }
}
src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java
@@ -1,9 +1,11 @@
package com.ruoyi.quality.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.quality.pojo.QualityUnqualified;
import com.ruoyi.quality.service.IQualityUnqualifiedService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
@@ -16,6 +18,7 @@
 */
@RestController
@RequestMapping("/quality/qualityUnqualified")
@Tag(name = "不合格管理")
public class QualityUnqualifiedController {
    @Resource
@@ -28,9 +31,10 @@
     * @return
     */
    @PostMapping("/add")
    public AjaxResult add(@RequestBody QualityUnqualified qualityUnqualified) {
    @Operation(summary = "新增不合格管理")
    public R<?> add(@RequestBody QualityUnqualified qualityUnqualified) {
        qualityUnqualified.setInspectState(0);
        return AjaxResult.success(qualityUnqualifiedService.save(qualityUnqualified));
        return R.ok(qualityUnqualifiedService.save(qualityUnqualified));
    }
    /**
@@ -39,13 +43,14 @@
     * @return
     */
    @DeleteMapping("/del")
    public AjaxResult delQualityUnqualified(@RequestBody List<Integer> ids) {
    @Operation(summary = "删除不合格管理")
    public R<?> delQualityUnqualified(@RequestBody List<Integer> ids) {
       qualityUnqualifiedService.listByIds(ids).stream().forEach(qualityUnqualified -> {
           if (qualityUnqualified.getInspectState()==1){
               throw new RuntimeException("该不合格数据已经处理无法删除!");
           }
       });
        return AjaxResult.success(qualityUnqualifiedService.removeBatchByIds(ids));
        return R.ok(qualityUnqualifiedService.removeBatchByIds(ids));
    }
    /**
@@ -54,8 +59,9 @@
     * @return
     */
    @GetMapping("/{id}")
    public AjaxResult QualityUnqualifiedDetail(@PathVariable("id") Integer id) {
        return AjaxResult.success(qualityUnqualifiedService.getUnqualified(id));
    @Operation(summary = "不合格管理详情")
    public R<?> QualityUnqualifiedDetail(@PathVariable("id") Integer id) {
        return R.ok(qualityUnqualifiedService.getUnqualified(id));
    }
    /**
@@ -64,8 +70,9 @@
     * @return
     */
    @PostMapping("/update")
    public AjaxResult update(@RequestBody QualityUnqualified qualityUnqualified) {
        return AjaxResult.success(qualityUnqualifiedService.updateById(qualityUnqualified));
    @Operation(summary = "不合格管理修改")
    public R<?> update(@RequestBody QualityUnqualified qualityUnqualified) {
        return R.ok(qualityUnqualifiedService.updateById(qualityUnqualified));
    }
    /**
@@ -75,8 +82,9 @@
     * @return
     */
    @GetMapping("/listPage")
    public AjaxResult qualityUnqualifiedListPage(Page page, QualityUnqualified qualityUnqualified) {
        return AjaxResult.success(qualityUnqualifiedService.qualityUnqualifiedListPage(page, qualityUnqualified));
    @Operation(summary = "不合格管理分页查询")
    public R<?> qualityUnqualifiedListPage(Page page, QualityUnqualified qualityUnqualified) {
        return R.ok(qualityUnqualifiedService.qualityUnqualifiedListPage(page, qualityUnqualified));
    }
    /**
@@ -85,6 +93,7 @@
     * @param qualityUnqualified
     */
    @PostMapping("/export")
    @Operation(summary = "不合格管理导出")
    public void qualityUnqualifiedExport(HttpServletResponse response,QualityUnqualified qualityUnqualified) {
        qualityUnqualifiedService.qualityUnqualifiedExport(response, qualityUnqualified);
    }
@@ -95,8 +104,9 @@
     * @return
     */
    @PostMapping("/deal")
    public AjaxResult deal(@RequestBody QualityUnqualified qualityUnqualified) {
        return AjaxResult.success(qualityUnqualifiedService.deal(qualityUnqualified));
    @Operation(summary = "不合格管理处理")
    public R<?> deal(@RequestBody QualityUnqualified qualityUnqualified) {
        return R.ok(qualityUnqualifiedService.deal(qualityUnqualified));
    }
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -528,7 +528,10 @@
        salesLedger.setTenantId(customer.getTenantId());
        // 3. æ–°å¢žæˆ–更新主表
        if (salesLedger.getId() == null) {
            String contractNo = generateSalesContractNo();
            String contractNo = salesLedger.getSalesContractNo();
            if (StringUtils.isEmpty(contractNo)) {
                contractNo = generateSalesContractNo();
            }
            salesLedger.setSalesContractNo(contractNo);
            salesLedgerMapper.insert(salesLedger);
        } else {
src/main/resources/mapper/production/ProductionOrderMapper.xml
@@ -212,4 +212,61 @@
          and ifnull(complete_quantity, 0) &lt; quantity
    </select>
    <select id="selectHomeOrderProgressPage" resultType="java.util.Map">
        select po.nps_no as orderNo,
               p.product_name as productName,
               ifnull(po.quantity, 0) as plannedQuantity,
               ifnull(po.complete_quantity, 0) as completedQuantity,
               round(ifnull(po.complete_quantity, 0) / nullif(po.quantity, 0) * 100, 2) as completionRate,
               po.plan_complete_time as dueDate,
               po.status as status
        from production_order po
                 left join product_model pm on po.product_model_id = pm.id
                 left join product p on pm.product_id = p.id
        <where>
            <if test="status != null">
                and po.status = #{status}
            </if>
        </where>
        order by po.id desc
        limit #{offset}, #{size}
    </select>
    <select id="countHomeOrderProgress" resultType="java.lang.Long">
        select count(1)
        from production_order po
        <where>
            <if test="status != null">
                and po.status = #{status}
            </if>
        </where>
    </select>
    <select id="countHomeOrderProgressByStatus" resultType="java.util.Map">
        select po.status as status, count(1) as cnt
        from production_order po
        where po.status in (2, 3, 4)
        group by po.status
    </select>
    <select id="selectHomeTodayProductionPlan" resultType="java.util.Map">
        select po.nps_no as orderNo,
               p.product_name as productName,
               ifnull(po.quantity, 0) as plannedQuantity,
               po.plan_complete_time as dueDate,
               po.status as status
        from production_order po
                 left join product_model pm on po.product_model_id = pm.id
                 left join product p on pm.product_id = p.id
        where po.status in (1, 2)
        order by case when po.status = 2 then 0 else 1 end, po.id desc
        limit #{size}
    </select>
    <select id="countHomeTodayProductionPlan" resultType="java.lang.Long">
        select count(1)
        from production_order po
        where po.status in (1, 2)
    </select>
</mapper>